AIプログラムとかUnityゲーム開発について

探索や学習などを活用したAI系ゲームを作りたいと思います。

ChatGPTにC#の深層学習のソースを作ってもらう

フレームワークを使わずに、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;
                    }
                }
            }
        }
    }
}