public static DeltasFor2LayersOfNet DeltasFor(NeuralNet3LayerSigmoid net, IEnumerable <double> inputs, IEnumerable <ZeroToOne> targets) { var outputs = net.OutputFor(inputs).ToArray(); var outputDeltas = outputs .Zip(targets, (o, target) => (target - o) * o * (1 - o)) /* see e.g. wikipedia https://en.wikipedia.org/wiki/Backpropagation#Derivation */ .ToArray(); var outputWeightDeltas = new MatrixD(net.HiddenToOutput.RowCount, net.HiddenToOutput.ColumnCount); var hiddenDeltaParts = new MatrixD(net.HiddenToOutput.RowCount, net.HiddenToOutput.ColumnCount); for (int i = 0; i < outputWeightDeltas.RowCount; i++) { for (int j = 0; j < outputWeightDeltas.ColumnCount; j++) { outputWeightDeltas[i, j] = net.HiddenLayer[i].FiringRate * outputDeltas[j]; hiddenDeltaParts[i, j] = outputDeltas[j] * (net.HiddenToOutput[i, j] + outputWeightDeltas[i, j]) * outputs[j] * (1 - outputs[j]); } } var hiddenDeltas = hiddenDeltaParts.ByRows().Select(row => row.Sum()).ToArray(); var hiddenWeightDeltas = new MatrixD(net.InputToHidden.RowCount, net.InputToHidden.ColumnCount); for (int i = 0; i < hiddenWeightDeltas.RowCount; i++) { for (int j = 0; j < hiddenWeightDeltas.ColumnCount; j++) { hiddenWeightDeltas[i, j] = net.InputLayer[i].FiringRate * hiddenDeltas[j]; } } return(new DeltasFor2LayersOfNet { OutputBiases = net.OutputLayer.Zip(outputDeltas, (neuron, delta) => neuron.Bias * delta).ToArray(), OutputWeights = outputWeightDeltas, HiddenBiases = net.HiddenLayer.Zip(hiddenDeltas, (neuron, delta) => neuron.Bias * delta).ToArray(), HiddenWeights = hiddenWeightDeltas }); }