フレームワークを使わずに、UnityのC#で直接深層学習をしてみようということで、ChatGPTにソースを教えてくれと頼んで、XORの学習をやってみた。
しかし、動かしてみると配列のindexがrange超えてるエラーが出て、バグがあるので、それを伝えると、修正プログラムをくれたんだけど、エラーは出なくなったが、たかがXORをどうも学習できてない感じ
0 XOR 0 = 0.470043207691545, 0 XOR 1 = 0.469955608642673, 1 XOR 0 = 0.474689566887439, 1 XOR 1 = 0.474601967838568,
複雑な多重ループなんで、どこにバグがあるかよくわからない。・゚・(ノ∀`)・゚・。
以前にC言語で普通のニューラルネットワークでXOR学習してみたのあったけど、あれと比べてみるか?
そもそも昔は複数層のNNがうまく学習できなかったけど、それって活性関数がシグモイドだったからで、LeRUならできてたのかな?
とか思って、やってみたいのだけど
0 XOR 0 = 2.06501482580279E-14, 0 XOR 1 = 0.999999999999997, 1 XOR 0 = 0.999999999999979, 1 XOR 1 = 6.88338275267597E-15,
学習できたっぽい!!!
ReLUのmath.maxがおかしかった。普通に3項演算子に変えたらうまくいった。
下記のソースの活性化関数のところを
return Math.Max(0, x); //ReLU ↓ return x > 0f ? x : 0f;
と変えると学習がうまく行く
いや、試しに ANDやORで学習してみると、うまく学習出来てない。どこかにバグがある
using System.Collections; using System.Collections.Generic; using UnityEngine; using System; namespace NeuralNetwork { public class main : MonoBehaviour { double[][] inputs = { new double[] { 0, 0 }, new double[] { 0, 1 }, new double[] { 1, 0 }, new double[] { 1, 1 } }; double[][] outputs = { new double[] { 0 }, new double[] { 1 }, new double[] { 1 }, new double[] { 0 } }; NeuralNetwork network; private void Awake() { Debug.Log("Awake"); /* このプログラムは、2つの入力ノード、4つの隠れ層ノード、および1つの出力ノードを持つニューラルネットワークを定義し、 Sigmoid活性化関数を使用しています。また、学習率は0.1として設定されています。 XORの入力パターンを与え、ニューラルネットワークによって生成された出力を表示しています。 */ } void Start() { Debug.Log("Start"); network = new NeuralNetwork(2, 2, 1); for (int i = 0; i < 500000; i++) { int index = UnityEngine.Random.Range(0,4); network.Train(inputs[index], outputs[index]); } String str = ""; for (int i = 0; i < 4; i++) { double[] result = network.FeedForward(inputs[i]); str += inputs[i][0]+" XOR "+inputs[i][1]+" = "+result[0]+", "; } Debug.Log(str); } void Update() { } class NeuralNetwork { private int[] layerSizes; private double[][][] weights; private double[][] biases; private double learningRate = 0.1f; public NeuralNetwork(params int[] layerSizes) { this.layerSizes = layerSizes;//3 this.weights = new double[layerSizes.Length - 1][][];//[2][][] this.biases = new double[layerSizes.Length - 1][];//[3][] for (int i = 0; i < layerSizes.Length - 1; i++) { weights[i] = new double[layerSizes[i + 1]][]; biases[i] = new double[layerSizes[i + 1]]; for (int j = 0; j < layerSizes[i + 1]; j++) { weights[i][j] = new double[layerSizes[i]]; } } InitializeWeights(); } public double sigmoid(double x) { return Math.Max(0f, x); } public double dSigmoid(double x) { return x > 0f ? 1f : 0f; } public void Train(double[] input, double[] targetOutput) { // Debug.Log("input.Length=" + input.Length); // Debug.Log("output.Length=" + targetOutput.Length); double[][] activations = new double[layerSizes.Length][]; double[][] derivatives = new double[layerSizes.Length][]; double[] error = new double[layerSizes[layerSizes.Length - 1]]; for (int i = 0; i < layerSizes.Length; i++) { activations[i] = new double[layerSizes[i]]; derivatives[i] = new double[layerSizes[i]]; } Array.Copy(input, activations[0], input.Length); for (int i = 1; i < layerSizes.Length; i++) { for (int j = 0; j < layerSizes[i]; j++) { double sum = 0; for (int k = 0; k < layerSizes[i - 1]; k++) { sum += weights[i - 1][j][k] * activations[i - 1][k]; } sum += biases[i - 1][j]; activations[i][j] = sigmoid(sum); derivatives[i][j] = dSigmoid(activations[i][j]); } } for (int i = 0; i < error.Length; i++) { error[i] = targetOutput[i] - activations[layerSizes.Length - 1][i]; } for (int i = layerSizes.Length - 2; i >= 1; i--) { double[] nextError = new double[layerSizes[i]]; for (int j = 0; j < layerSizes[i]; j++) { double errorSum = 0; for (int k = 0; k < layerSizes[i + 1]; k++) { errorSum += error[k] * weights[i][k][j]; } nextError[j] = errorSum; } error = nextError; for (int j = 0; j < layerSizes[i + 1]; j++) { for (int k = 0; k < layerSizes[i]; k++) { weights[i][j][k] += learningRate * error[j] * activations[i][k]; } biases[i][j] += learningRate * error[j]; } } } public double[] FeedForward(double[] input) { double[][] activations = new double[layerSizes.Length][]; //Debug.Log("output.length="+ layerSizes[layerSizes.Length - 1]); for (int i = 0; i < layerSizes.Length; i++) { activations[i] = new double[layerSizes[i]]; } Array.Copy(input, activations[0], input.Length); for (int i = 1; i < layerSizes.Length; i++) { for (int j = 0; j < layerSizes[i]; j++) { double sum = 0; for (int k = 0; k < layerSizes[i - 1]; k++) { sum += weights[i - 1][j][k] * activations[i - 1][k]; } sum += biases[i - 1][j]; activations[i][j] = sigmoid(sum); } } return activations[layerSizes.Length - 1]; } private void InitializeWeights() { for (int i = 0; i < layerSizes.Length - 1; i++) { for (int j = 0; j < layerSizes[i + 1]; j++) { for (int k = 0; k < layerSizes[i]; k++) { weights[i][j][k] = UnityEngine.Random.Range(0f, 1f) * 2f - 1f; } biases[i][j] = UnityEngine.Random.Range(0f, 1f) * 2f - 1f; } } } } } }