private void TrainMinibatch() { UnityEngine.Profiling.Profiler.BeginSample("TrainMiniBatch"); const int numClasses = 10; const int batchSize = 10; var target = new float[numClasses]; var dCdO = new float[numClasses]; float avgTrainCost = 0f; int correctTrainLabels = 0; ZeroGradients(_gradientBucket); var trainBatch = DataManager.GetBatch(batchSize, DataManager.Train, ref _rng); for (int i = 0; i < trainBatch.Indices.Length; i++) { int lbl = DataManager.Train.Labels[trainBatch.Indices[i]]; // Copy image to input layer (Todo: this is a waste of time/memory) UnityEngine.Profiling.Profiler.BeginSample("CopyInputs"); for (int p = 0; p < DataManager.Train.ImgDims; p++) { _net.Input[p] = DataManager.Train.Images[trainBatch.Indices[i], p]; } UnityEngine.Profiling.Profiler.EndSample(); NetUtils.Forward(_net); int predictedLbl = NetUtils.GetMaxOutput(_net); NetUtils.LabelToOneHot(lbl, target); if (predictedLbl == lbl) { correctTrainLabels++; } //Debug.Log(outputClass + ", " + batch.Labels[i]); // Calculate error between output layer and target NetUtils.Subtract(target, _net.Output, dCdO); float cost = NetUtils.Cost(dCdO); avgTrainCost += cost; // Propagate error back // Calculate per-parameter gradient, store it NetUtils.Backward(_net, target); AddGradients(_net, _gradientBucket); } avgTrainCost /= (float)batchSize; // Update weights and biases according to averaged gradient and learning rate _rate = 3.0f / (float)batchSize; NetUtils.UpdateParameters(_net, _gradientBucket, _rate); _batch++; _trainingLoss = (float)Math.Round(avgTrainCost, 6); // Debug.Log( // "Batch: " + _batchesTrained + // ", TrainLoss: " + Math.Round(avgTrainCost, 6) + // ", Rate: " + Math.Round(rate, 6)); // Mnist.ToTexture(batch, batch.Labels.Length-1, _tex); // _label = batch.Labels[batch.Labels.Length-1]; UnityEngine.Profiling.Profiler.EndSample(); }