diff --git a/CSharp/.vscode/launch.json b/CSharp/.vscode/launch.json new file mode 100644 index 0000000..05b9e80 --- /dev/null +++ b/CSharp/.vscode/launch.json @@ -0,0 +1,26 @@ +{ + "version": "0.2.0", + "configurations": [ + { + // Use IntelliSense to find out which attributes exist for C# debugging + // Use hover for the description of the existing attributes + // For further information visit https://github.com/dotnet/vscode-csharp/blob/main/debugger-launchjson.md + "name": ".NET Core Launch (console)", + "type": "coreclr", + "request": "launch", + "preLaunchTask": "build", + // If you have changed target frameworks, make sure to update the program path. + "program": "${workspaceFolder}/bin/Debug/net7.0/CSharp.dll", + "args": [], + "cwd": "${workspaceFolder}", + // For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console + "console": "internalConsole", + "stopAtEntry": false + }, + { + "name": ".NET Core Attach", + "type": "coreclr", + "request": "attach" + } + ] +} \ No newline at end of file diff --git a/CSharp/.vscode/tasks.json b/CSharp/.vscode/tasks.json new file mode 100644 index 0000000..21dbb79 --- /dev/null +++ b/CSharp/.vscode/tasks.json @@ -0,0 +1,41 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "build", + "command": "dotnet", + "type": "process", + "args": [ + "build", + "${workspaceFolder}/CSharp.csproj", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary;ForceNoAlign" + ], + "problemMatcher": "$msCompile" + }, + { + "label": "publish", + "command": "dotnet", + "type": "process", + "args": [ + "publish", + "${workspaceFolder}/CSharp.csproj", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary;ForceNoAlign" + ], + "problemMatcher": "$msCompile" + }, + { + "label": "watch", + "command": "dotnet", + "type": "process", + "args": [ + "watch", + "run", + "--project", + "${workspaceFolder}/CSharp.csproj" + ], + "problemMatcher": "$msCompile" + } + ] +} \ No newline at end of file diff --git a/CSharp/Neural.cs b/CSharp/Neural.cs index 720d11e..afaba74 100644 --- a/CSharp/Neural.cs +++ b/CSharp/Neural.cs @@ -33,11 +33,12 @@ public static double SigmoidPrim(double f) } public record Network( + int InputCount, int HiddenCount, int OutputCount, - double[][] WeightsHidden, + double[] WeightsHidden, double[] BiasesHidden, - double[][] WeightsOutput, + double[] WeightsOutput, double[] BiasesOutput) { public double[] Predict(double[] input) @@ -49,22 +50,23 @@ public double[] Predict(double[] input) public double[] Predict(double[] input, double[] y_hidden, double[] y_output) { - for (int c = 0; c < WeightsHidden[0].Length; c++) + for (int c = 0; c < HiddenCount; c++) { double sum = 0.0; - for (int r = 0; r < WeightsHidden.Length; r++) + for (int r = 0; r < InputCount; r++) { - sum += input[r] * WeightsHidden[r][c]; - y_hidden[c] = ActivationFunctions.Sigmoid(sum + BiasesHidden[c]); + sum += input[r] * WeightsHidden[r * HiddenCount + c]; } + + y_hidden[c] = ActivationFunctions.Sigmoid(sum + BiasesHidden[c]); } - for (int c = 0; c < WeightsOutput[0].Length; c++) + for (int c = 0; c < OutputCount; c++) { double sum = 0.0; - for (int r = 0; r < WeightsOutput.Length; r++) + for (int r = 0; r < HiddenCount; r++) { - sum += y_hidden[r] * WeightsOutput[r][c]; + sum += y_hidden[r] * WeightsOutput[r * OutputCount + c]; } y_output[c] = ActivationFunctions.Sigmoid(sum + BiasesOutput[c]); @@ -96,52 +98,46 @@ public static Trainer Create(int inputCount, int hiddenCount, int outputCount, F double[] output = new double[outputCount]; double[] gradHidden = new double[hiddenCount]; double[] gradOutput = new double[outputCount]; - double[][] weightsHidden = Enumerable - .Range(1, inputCount) - .Select(_ => Array.ConvertAll(new double[hiddenCount], v => rand.Invoke() - 0.5)) - .ToArray(); + double[] weightsHidden = Array.ConvertAll(new double[inputCount * hiddenCount], v => rand.Invoke() - 0.5); double[] biasesHidden = new double[hiddenCount]; - double[][] weightsOutput = Enumerable - .Range(1, hiddenCount) - .Select(_ => Array.ConvertAll(new double[outputCount], v => rand.Invoke() - 0.5)) - .ToArray(); + double[] weightsOutput = Array.ConvertAll(new double[hiddenCount * outputCount], v => rand.Invoke() - 0.5); double[] biasesOutput = new double[outputCount]; - Network network = new(hiddenCount, outputCount, weightsHidden, biasesHidden, weightsOutput, biasesOutput); + Network network = new(inputCount, hiddenCount, outputCount, weightsHidden, biasesHidden, weightsOutput, biasesOutput); return new Trainer(network, hidden, output, gradHidden, gradOutput); } public void Train (double[] input, double[] y, double lr) { _ = Network.Predict(input, Hidden, Output); - for (int c = 0; c < Output.Length; c++) + for (int c = 0; c < Network.OutputCount; c++) { GradOutput[c] = (Output[c] - y[c]) * ActivationFunctions.SigmoidPrim(Output[c]); } - for (int r = 0; r < Network.WeightsOutput.Length; r++) + for (int r = 0; r < Network.HiddenCount; r++) { double sum = 0.0; - for (int c = 0; c < Network.WeightsOutput[0].Length; c++) + for (int c = 0; c < Network.OutputCount; c++) { - sum += GradOutput[c] * Network.WeightsOutput[r][c]; + sum += GradOutput[c] * Network.WeightsOutput[r * Network.OutputCount + c]; } GradHidden[r] = sum * ActivationFunctions.SigmoidPrim(Hidden[r]); } - for (int r = 0; r < Network.WeightsOutput.Length; r++) + for (int r = 0; r < Network.HiddenCount; r++) { - for (int c = 0; c < Network.WeightsOutput[0].Length; c++) + for (int c = 0; c < Network.OutputCount; c++) { - Network.WeightsOutput[r][c] -= lr * GradOutput[c] * Hidden[r]; + Network.WeightsOutput[r * Network.OutputCount + c] -= lr * GradOutput[c] * Hidden[r]; } } - for (int r = 0; r < Network.WeightsHidden.Length; r++) + for (int r = 0; r < Network.InputCount; r++) { - for (int c = 0; c < Network.WeightsHidden[0].Length; c++) + for (int c = 0; c < Network.HiddenCount; c++) { - Network.WeightsHidden[r][c] -= lr * GradHidden[c] * input[r]; + Network.WeightsHidden[r * Network.HiddenCount + c] -= lr * GradHidden[c] * input[r]; } } diff --git a/CSharp/test.bats b/CSharp/test.bats index 84708c6..dca0ea1 100644 --- a/CSharp/test.bats +++ b/CSharp/test.bats @@ -10,33 +10,33 @@ [ "${lines[4]}" = "1,0 = 0.961 0.039 0.970 0.026 0.030 0.974" ] [ "${lines[5]}" = "1,1 = 0.049 0.952 0.994 0.956 0.006 0.044" ] [[ "${lines[7]}" =~ WeightsHidden ]] - [[ "${lines[9]}" =~ -5.94253266329493 ]] - [[ "${lines[10]}" =~ -7.053489763483629 ]] - [[ "${lines[13]}" =~ -5.93849179349689 ]] - [[ "${lines[14]}" =~ -7.080670057743411 ]] - [[ "${lines[17]}" =~ BiasesHidden ]] - [[ "${lines[18]}" =~ 8.66080005088484 ]] - [[ "${lines[19]}" =~ 3.18102806812189 ]] - [[ "${lines[21]}" =~ WeightsOutput ]] - [[ "${lines[23]}" =~ 7.02847492235002 ]] - [[ "${lines[24]}" =~ -7.0385257683402696 ]] - [[ "${lines[25]}" =~ -1.730833624456504 ]] - [[ "${lines[26]}" =~ -7.40327103830852 ]] - [[ "${lines[27]}" =~ 1.55892562488877 ]] - [[ "${lines[28]}" =~ 7.390186687736159 ]] - [[ "${lines[31]}" =~ -7.31042627730994 ]] - [[ "${lines[32]}" =~ 7.32111860535136 ]] - [[ "${lines[33]}" =~ -7.03879901708655 ]] - [[ "${lines[34]}" =~ -2.80022046282448 ]] - [[ "${lines[35]}" =~ 7.071517018377268 ]] - [[ "${lines[36]}" =~ 3.21919221700788 ]] - [[ "${lines[39]}" =~ BiasesOutput ]] - [[ "${lines[40]}" =~ -3.245795100480243 ]] - [[ "${lines[41]}" =~ 3.250424023612059 ]] - [[ "${lines[42]}" =~ 5.2467380115760 ]] - [[ "${lines[43]}" =~ 3.36378125079356 ]] - [[ "${lines[44]}" =~ -5.097046597754945 ]] - [[ "${lines[45]}" =~ -3.361940360109141 ]] + [[ "${lines[8]}" =~ -5.94253266329493 ]] + [[ "${lines[9]}" =~ -7.053489763483629 ]] + [[ "${lines[10]}" =~ -5.93849179349689 ]] + [[ "${lines[11]}" =~ -7.080670057743411 ]] + [[ "${lines[13]}" =~ BiasesHidden ]] + [[ "${lines[14]}" =~ 8.66080005088484 ]] + [[ "${lines[15]}" =~ 3.18102806812189 ]] + [[ "${lines[17]}" =~ WeightsOutput ]] + [[ "${lines[18]}" =~ 7.02847492235002 ]] + [[ "${lines[19]}" =~ -7.0385257683402696 ]] + [[ "${lines[20]}" =~ -1.730833624456504 ]] + [[ "${lines[21]}" =~ -7.40327103830852 ]] + [[ "${lines[22]}" =~ 1.55892562488877 ]] + [[ "${lines[23]}" =~ 7.390186687736159 ]] + [[ "${lines[24]}" =~ -7.31042627730994 ]] + [[ "${lines[25]}" =~ 7.32111860535136 ]] + [[ "${lines[26]}" =~ -7.03879901708655 ]] + [[ "${lines[27]}" =~ -2.80022046282448 ]] + [[ "${lines[28]}" =~ 7.071517018377268 ]] + [[ "${lines[29]}" =~ 3.21919221700788 ]] + [[ "${lines[31]}" =~ BiasesOutput ]] + [[ "${lines[32]}" =~ -3.245795100480243 ]] + [[ "${lines[33]}" =~ 3.250424023612059 ]] + [[ "${lines[34]}" =~ 5.2467380115760 ]] + [[ "${lines[35]}" =~ 3.36378125079356 ]] + [[ "${lines[36]}" =~ -5.097046597754945 ]] + [[ "${lines[37]}" =~ -3.361940360109141 ]] } @test "digits" {