//Unused method which would grab a real image and apply static to it for generator input List <double[]> GenerateNoisyImages(Random r, int latentsize, int num) { var output = new List <double[]>(); for (int i = 0; i < latentsize; i++) { var img = IO.FindNextNumber(num); var latentspace = Maths.RandomGaussian(r, latentsize); output.Add(new double[latentsize]); for (int j = 0; j < latentsize; j++) { output[i][j] = img[j] * latentspace[j]; } } return(output); }
/// <summary> /// Trains the GAN /// </summary> /// <param name="Critic">The network which criticises real and fake images</param> /// <param name="Generator">The network which generates fake images</param> /// <param name="LatentSize">How large the random noise input of the generator is</param> /// <param name="ctg">The Critic To Generator training ratio</param> /// <param name="num">The numerical digit to be learned (0-9)</param> /// <param name="activeform">The form running this method</param> /// <param name="imgspeed">How often generated images are pushed to the front-end</param> public static void Train(NN Critic, NN Generator, int LatentSize, int ctg, Form1 activeform, int imgspeed) { int formupdateiterator = 0; //The generator of the latentspace Random r = new Random(); while (Training) { //Train critic x times per 1 of generator for (int i = 0; i < ctg; i++) { //Batch norm stuff double realmean = 0; double realstddev = 0; double AvgRealScore = 0; double AvgFakeScore = 0; //Generate samples var realsamples = new List <double[]>(); var latentspaces = new List <double[]>(); for (int ii = 0; ii < BatchSize; ii++) { //Find next image realsamples.Add(IO.FindNextNumber(NN.Number)); //Generate latent space for fake image latentspaces.Add(Maths.RandomGaussian(r, LatentSize)); //Calculate values to help scale the fakes var mean = Maths.CalcMean(realsamples[ii]); realmean += mean; realstddev += Maths.CalcStdDev(realsamples[ii], mean); } realmean /= BatchSize; realstddev /= BatchSize; //Batchnorm the samples realsamples = Maths.BatchNormalize(realsamples, realmean, realstddev); var fakesamples = Maths.BatchNormalize(Generator.GenerateSamples(latentspaces), realmean, realstddev); //The RMSE of each network double CError = 0; double GError = 0; //Critic's scores of each type of sample List <double> rscores = new List <double>(); List <double> fscores = new List <double>(); //Real image calculations double RealPercCorrect = 0; Critic.Calculate(realsamples); for (int j = 0; j < BatchSize; j++) { //The score is the value of the output (last) neuron of the critic rscores.Add(Critic.Layers[Critic.NumLayers - 1].Values[j][0]); AvgRealScore += rscores[j]; //Add the squared error CError += Math.Pow(1d - Critic.Layers[Critic.NumLayers - 1].Values[j][0], 2); GError += Math.Pow(-Critic.Layers[Critic.NumLayers - 1].Values[j][0], 2); //Add whether it was correct or not to the total RealPercCorrect += Critic.Layers[Critic.NumLayers - 1].Values[j][0] > 0 ? 1d : 0d; } AvgRealScore /= BatchSize; RealPercCorrect /= BatchSize; //Loss on real images = how accurate the critic is Critic.CalcGradients(realsamples, null, RealPercCorrect, true); //Fake image calculations double FakePercIncorrect = 0; Critic.Calculate(fakesamples); for (int j = 0; j < BatchSize; j++) { //The score is the value of the output (last) neuron of the critic fscores.Add(Critic.Layers[Critic.NumLayers - 1].Values[j][0]); AvgFakeScore += fscores[j]; //Add the squared error CError += Math.Pow(-Critic.Layers[Critic.NumLayers - 1].Values[j][0], 2); GError += Math.Pow(1d - Critic.Layers[Critic.NumLayers - 1].Values[j][0], 2); //Add whether it was correct or not to the total FakePercIncorrect += Critic.Layers[Critic.NumLayers - 1].Values[j][0] > 0 ? 1d : 0d; } AvgFakeScore /= BatchSize; FakePercIncorrect /= BatchSize; //Wasserstein loss on fake images = real % correct - fake % correct Critic.CalcGradients(fakesamples, null, RealPercCorrect - (1 - FakePercIncorrect), true); //Update weights and biases Critic.Update(); //Reset trial number if desired if (Clear) { Critic.Trials = 0; Generator.Trials = 0; Clear = false; } //Critic processes 2 images per 1 the generator does CError = Math.Sqrt(CError / (2 * BatchSize)); GError = Math.Sqrt(GError / BatchSize); //Update errors and % correct values Critic.Error = (Critic.Error * ((Critic.Trials) / (Critic.Trials + 1d))) + (CError * (1d / (Critic.Trials + 1d))); Critic.PercCorrect = (Critic.PercCorrect * ((Critic.Trials) / (Critic.Trials + 1d))) + (RealPercCorrect * (1d / (Critic.Trials + 1d))); Generator.Error = (Generator.Error * ((Generator.Trials) / (Generator.Trials + 1d))) + (GError * (1d / (Generator.Trials + 1))); Generator.PercCorrect = (Generator.PercCorrect * ((Generator.Trials) / (Generator.Trials + 1d))) + (FakePercIncorrect * (1d / (Generator.Trials + 1d))); //Iterate trial count Critic.Trials++; Generator.Trials++; } //Generate samples List <double[]> testlatents = new List <double[]>(); for (int i = 0; i < BatchSize; i++) { testlatents.Add(Maths.RandomGaussian(r, LatentSize)); } var tests = Generator.GenerateSamples(testlatents); //Criticize generated samples Critic.Calculate(tests); //Compute generator's error on the critic's scores double Score = 0; for (int j = 0; j < BatchSize; j++) { Score += Critic.Layers[Critic.NumLayers - 1].Values[j][0] > 0 ? 1 : 0; } //Backprop through the critic to the generator Critic.CalcGradients(tests, null, Score, false); Generator.CalcGradients(testlatents, Critic.Layers[0], Score, true); //Update the generator's weights and biases Generator.Update(); //Update image (if applicable) if (formupdateiterator >= imgspeed) { //Code that converts normalized generator outputs into an image //Changes distribution of output values to 0-255 (brightness) var values = Form1.Rescale(Maths.Convert(tests[0])); var image = new int[28, 28]; //Convert values to a 2d int array for (int i = 0; i < 28; i++) { for (int ii = 0; ii < 28; ii++) { image[ii, i] = (int)values[i, ii]; } } //Report values and image to the front end activeform.Invoke((Action) delegate { activeform.image = image; activeform.CScore = Critic.Error.ToString(); activeform.CPerc = Critic.PercCorrect.ToString(); activeform.GScore = Generator.Error.ToString(); activeform.GPerc = Generator.PercCorrect.ToString(); if (Critic.Error > Form1.Cutoff) { Training = false; } if (IO.Reset) { IO.Reset = false; activeform.Epoch++; } }); formupdateiterator = 0; } formupdateiterator++; } if (Save) { //Save nns IO.Write(Generator, false); IO.Write(Critic, true); } activeform.Invoke((Action) delegate { //Notify of being done training activeform.DoneTraining = true; //Reset errors activeform.CScore = null; activeform.CPerc = null; activeform.GScore = null; activeform.GPerc = null; }); }