static void Main(string[] args) { String name; Bitmap img; int resizedWidth = 1000; int resizedHeight = 1000; double[] expected = { 0, 0, 0, 0, 0, 0, 1 }; do { Console.WriteLine("Enter an image:"); //get image filepath name = Console.ReadLine(); } while (!ImageUtil.VerifyImage(name)); //make sure image is actually image and not large img = Bitmap.FromFile(name) as Bitmap; //do this again here so we have it but know it's legit Bitmap resizedImg = ImageUtil.ResizeImage(img, resizedWidth, resizedHeight); //resize the image so it doesn't take multiple millenia resizedImg.Save("resized.png", System.Drawing.Imaging.ImageFormat.Png); int[] rgb = new int[resizedWidth * resizedHeight]; //holds int rgb values ImageUtil.getRGB(resizedImg, 0, 0, resizedWidth, resizedHeight, rgb, 0, resizedWidth); double[] input = new double[resizedWidth * resizedHeight]; //since we need doubles for compression to not have floating point errors for (int i = 0; i < rgb.Length; i++) { input[i] = Compressions.rgbcomp(rgb[i]); //compress int rgb values and put them into input } Layer initial = new Layer(input); //create initial layer with compressed activation values Console.WriteLine("How many hidden layers?"); int numhidden = Convert.ToInt16(Console.ReadLine()); int[] hidden = new int[numhidden]; for (int i = 0; i < numhidden; i++) { Console.WriteLine("How many neurons in hidden layer " + i + "?"); hidden[i] = Convert.ToInt16(Console.ReadLine()); } Network neural = new Network(resizedWidth * resizedHeight, hidden, 7); neural.randomizeAll(); for (int i = 0; i < 100; i++) { int errorCode = runNetwork(neural, input, expected); if (errorCode == -1) { Console.WriteLine("Intended output is a dead neuron, killing network."); Console.ReadKey(); return; } else if (errorCode == -2) { Console.WriteLine("Every output is a dead neuron, killing network."); Console.ReadKey(); return; } } Console.ReadKey(); }
public GradStep[] backpropogate(double[] expected) { double[][] errorPerActivation = new double[hiddenLayers.Count() + 1][]; //change in error per change in activation, multiplied by change in activation per change in weight/bias to give gradient GradStep[] steps = new GradStep[hiddenLayers.Count() + 1]; //the changes in weights and biases for each hidden layer, plus the output //Calculate changes for final layer errorPerActivation[hiddenLayers.Count()] = new double[output.weights.RowCount]; //have to initialize each array because it's jagged and c# is the dicks steps[steps.Count() - 1] = new GradStep(output.weights.RowCount, output.weights.ColumnCount, output.neurons.Count); //initialize gradstep for the output for (int i = 0; i < output.weights.RowCount; i++) { errorPerActivation[hiddenLayers.Count()][i] = 2 * (expected[i] - output.neurons[i]) * Compressions.derReLU(output.neurons[i]); //change in error per change in activation for the final layer for (int j = 0; j < output.weights.ColumnCount; j++) { steps[steps.Count() - 1].weightStep[i, j] = errorPerActivation[hiddenLayers.Count()][i] * hiddenLayers[hiddenLayers.Count() - 1].neurons[j]; //the change in weight is the error/activation times activation/weight } steps[steps.Count() - 1].biasStep[i] = errorPerActivation[hiddenLayers.Count()][i]; //change in error with respect to bias is just error/activation, since activation/bias is 1 (bias is constant) } for (int i = hiddenLayers.Count() - 1; i >= 0; i--) //for every hidden layer, iterating backwards since we need the next layer's error { DerivedLayer nextLayer; Layer previousLayer; errorPerActivation[i] = new double[hiddenLayers[i].weights.RowCount]; //have to initialize each array because it's jagged and c# is the balls steps[i] = new GradStep(hiddenLayers[i].weights.RowCount, hiddenLayers[i].weights.ColumnCount, hiddenLayers[i].biases.Count); //holds suggested changes to weights and biases in this layer if (i < hiddenLayers.Count() - 1) { nextLayer = hiddenLayers[i + 1]; //use values from next hidden layer } else { nextLayer = output; //unless it's the final hidden layer, in which case we need values of output } if (i > 0) { previousLayer = hiddenLayers[i - 1]; //use values from previous hidden layer } else { previousLayer = input; //unless it's the final hidden layer, in which case we need values of input } for (int j = 0; j < hiddenLayers[i].weights.RowCount; j++) //in every row { double activation = Compressions.derReLU(hiddenLayers[i].neurons[j]); //find the change in error per change in activation errorPerActivation[i][j] = 0; for (int k = 0; k < nextLayer.neurons.Count(); k++) //since this activation affects every neuron in next layer, we need changes for all of them { errorPerActivation[i][j] += nextLayer.weights[k, j] * errorPerActivation[i + 1][k]; //change in activation per weight times change in error per activation steps[i].biasStep[j] += errorPerActivation[i + 1][k]; //change in error with respect to bias is just error/activation, since activation/bias is 1 (bias is constant) } errorPerActivation[i][j] *= activation; //multiply error in activation by derivative of compression to complete the gradient for (int k = 0; k < hiddenLayers[i].weights.ColumnCount; k++) //adjust every weight { steps[i].weightStep[j, k] = errorPerActivation[i][j] * previousLayer.neurons[k]; } } } return(steps); }