Не могу решить прболему вторую неделю... Юнити, нейросети, неточности. Код прилагается

Генерирую поколение особей. Выставляю мутацию на ноль и вижу следующий треш:

  1. Все особи при нулевой мутации хоть и имеют одинаковую расстановку весов в нейросети, выдают немного разное поведение от поколения к поколению, что сильно влияет на результаты.
  2. На протяжении текущего поколения никакого рассинхрона не наблюдается. Результаты и поведение одинаковы для всех особей.
  3. Самое интересное. Отбор лучшей особи осуществляется пузырьковой сортировкой по значению "фитнесс". "Фитнесс" = координата Х. Значение присваивается каждое обновление физики. При этом!!! В логах наблюдаю примерно следующее:

Дебаг лог: фитнесс лучшего типочка = -0.5

Дебаг лог: фитнесс лучшего типочка = 1.2

Дебаг лог: фитнесс лучшего типочка = -0.5

и далее по кругу... То есть обращаю ваше внимание, нейросеть в каждом поколении ОДНА И ТА ЖЕ, при этом результаты РАЗНЫЕ и они еще и повторяются циклично.

Короче вот код, поставлю свечку в храме за того кто сможет помочь...

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Assets.Brakodel;

public class ArenaManager : MonoBehaviour
{
    public GameObject referenceObj;
    public GameObject Arena;
    public GameObject spawn;
    public int populationSize;

    public int inputs;
    public int[] layers;
    public int outputs;
    public float powerOfMutation;
    public float genTime;

    private Brakodel dubolom;

    private List<GameObject> duboloms;
    private List<GameObject> obolduys;

    // Start is called before the first frame update
    void Start()
    {
        // walls
        for (int i = 0; i < populationSize; i++)
        {
            //Instantiate(Arena, new Vector3(i * 22, 0), Quaternion.identity);
        }

        duboloms = new List<GameObject>();

        for (int i = 0; i < populationSize; i++)
        {
            duboloms.Add(Instantiate(referenceObj, new Vector3(0, 0), Quaternion.identity));
            duboloms[i].name = "Drone " + i;
            duboloms[i].GetComponent<Spider>().bungler = new Brakodel(inputs, outputs, layers);
            duboloms[i].GetComponent<Spider>().bungler.RandomizeWeights();
        }

        Invoke("Generate", genTime);
    }
    
    void Generate()
    {
        //Brakodel AlphaBB = BubbleSort(obolduys);
        Brakodel BetaBB = BubbleSort(duboloms);
       // Debug.Log(BetaBB.axons[0][0][0]);
        // KILL THEM ALL
        for (int dr = 0; dr < populationSize; dr++)
        {
            Destroy(duboloms[dr]);
            //Destroy(obolduys[dr]);
        }


        duboloms[0] = Instantiate(referenceObj, new Vector3(0, 0), Quaternion.identity);
        duboloms[0].name = "Beta " + 0;
        duboloms[0].GetComponent<Spider>().bungler = new Brakodel(inputs, outputs, layers);
        duboloms[0].GetComponent<Spider>().bungler.CopyNetwork(BetaBB);
        Debug.Log(duboloms[0].GetComponent<Spider>().bungler.axons[0][0][0]);

        // Создание мужиков с мутациями
        for (int i = 1; i < populationSize; i++)
        {

            duboloms[i] = Instantiate(referenceObj, new Vector3(0, 0), Quaternion.identity);
            duboloms[i].name = "Beta " + i;
            duboloms[i].GetComponent<Spider>().bungler = new Brakodel(inputs, outputs, layers);
            duboloms[i].GetComponent<Spider>().bungler.CopyNetwork(BetaBB);
            duboloms[i].GetComponent<Spider>().bungler.Mutate(powerOfMutation);

        }

        Invoke("Generate", genTime);
    }


    Brakodel BubbleSort(List<GameObject> Drones)
    {
        GameObject booferObj;
        Brakodel bestBrakodel;
        
        // Fitness calc
        for (int i = 0; i < Drones.Count; i++)
        {
            //Debug.Log(Drones[i].GetComponent<Spider>().fitness);
        }

        float booferFit1;
        float booferFit2;
        for (int i = 0; i < Drones.Count; i++)
        {
            for (int j = 0; j < Drones.Count - 1; j++)
            {
                booferFit1 = Drones[j].GetComponent<Spider>().fitness;
                booferFit2 = Drones[j + 1].GetComponent<Spider>().fitness;
                if (booferFit1 < booferFit2)
                {
                    booferObj = Drones[j + 1];
                    Drones[j + 1] = Drones[j];
                    Drones[j] = booferObj;
                }
            }
        }
        bestBrakodel = new Brakodel(inputs, outputs, layers);
        bestBrakodel.CopyNetwork(Drones[0].GetComponent<Spider>().bungler);
        Debug.Log("Best fit = " + Drones[0].GetComponent<Spider>().fitness);
        //Debug.Log("Bestax = " + Drones[0].GetComponent<Spider>().bungler.axons[0][0][0]);
        return bestBrakodel;
    }


}


public class Spider : MonoBehaviour
{
    BoxCollider2D[] colliders;
    HingeJoint2D[] joints;
    public Transform head;
    Raycasting rc;
    float[] sens;
    float[] mot;
    private ContactFilter2D filter;
    public Brakodel bungler;
    public Rigidbody2D eye;
    public float fitness;
    int zaebalo;

    // Start is called before the first frame update
    void Start()
    {
        colliders = GetComponentsInChildren<BoxCollider2D>();
        joints = GetComponentsInChildren<HingeJoint2D>();
        filter = new ContactFilter2D();
        filter.SetLayerMask(LayerMask.GetMask("Default")) ;
        rc = eye.gameObject.AddComponent<Raycasting>();
        rc.Initializer(5, 120);
        sens = new float[29];
        mot = new float[5];
        Debug.Log("Heuta" + bungler.axons[0][0][0]);
    }

    // Update is called once per frame
    void FixedUpdate()
    {
        float[] dists = rc.CastRays(5f);
        for (int i = 0; i < dists.Length; i++)
        {
            sens[i] = dists[i];
        }

        for (int i = 0; i < colliders.Length; i++)
        {
            sens[i + dists.Length] = IsOnGround(i);
        }

        sens[dists.Length + colliders.Length] = 1f;//eye.angularVelocity;

        //sens[dists.Length + colliders.Length + 1]
        mot = bungler.Podumat(sens);
        //.Log(mot[0]);
        
        for (int i = 0; i < joints.Length; i++)
        {
            JointMotor2D jm = new JointMotor2D();
            jm.motorSpeed = mot[i] * 100;
            jm.maxMotorTorque = 100f;
            joints[i].motor = jm;
        }
        
        fitness = head.position.x;
        //Debug.Log(zaebalo + " " + fitness);
        zaebalo += 1;
    }

    float IsOnGround(int index)
    {
        if (colliders[index].IsTouchingLayers(0))
        {
            return (1);
        }
        else
        {
            return 0;
        }
    }
}

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace Assets.Brakodel
{ 
    public class Brakodel
    {
        public List<List<float[]>> axons;
        public List<float[]> neurons;
        public float[] inputs;
        public float[] outputs;


        public Brakodel(int inps, int outs, int[] neurs)
        {
            // Neuro Initialize
            neurons = new List<float[]>();
            for (int i = 0; i < neurs.Length; i++)
            {
                neurons.Add(new float[neurs[i]]);
            }

            /*
             * debug cycle for neurons
            for (int layer = 0; layer < neurons.Count; layer++)
            {
                Debug.Log("neurons layer is " + layer);
                for (int neuron = 0; neuron < neurons[layer].Length; neuron++)
                {
                    Debug.Log("neurons count in this layer is " + neurons[layer][neuron]);
                }
            }

            */

            // inputs
            inputs = new float[inps];
            //outputs
            outputs = new float[outs];



            axons = new List<List<float[]>>();
            for (int layer = 0; layer < 1 + neurs.Length; layer++)
            {
                axons.Add(new List<float[]>());
            }

            // First axons layer
            for (int neuron = 0; neuron < neurs[0]; neuron++)
            {
                axons[0].Add(new float[inps]);
            }

            // For hidden axon layers
            for (int neuronLayer = 1; neuronLayer < neurs.Length; neuronLayer++)
            {
                for (int neuron = 0; neuron < neurs[neuronLayer]; neuron++)
                {
                    axons[neuronLayer].Add(new float[neurs[neuronLayer - 1]]);
                }
            }

            // For outputs axon;
            for (int neuron = 0; neuron < outs; neuron++)
            {
                axons[axons.Count - 1].Add(new float[neurs[neurs.Length - 1]]);
            }

            /*
            // Debug cycle
            Debug.Log("Axon layers:" + axons.Count);
            //Debug.Log()
            for (int layer = 0; layer < axons.Count; layer++)
            {
                Debug.Log("kolvo puchkov na sloe " + layer + " ravno " + axons[layer].Count);
                for (int puchok = 0; puchok < axons[layer].Count; puchok++)
                {
                    Debug.Log("kolvo axonov v pucke = " + axons[layer][puchok].Length);
                } 
            }
            */

        }

        public void RandomizeWeights()
        {   
            //Debug.Log(axons.Count);
            for (int layer = 0; layer < axons.Count; layer++)
            {
                //Debug.Log("Layer n " + layer);
                for (int puchok = 0; puchok < axons[layer].Count; puchok++)
                {
                    //Debug.Log("puchok n " + puchok);
                    for (int axon = 0; axon < axons[layer][puchok].Length; axon++)
                    {
                        axons[layer][puchok][axon] = Random.Range(-1f, 1f);
                        //Debug.Log(axons[layer][puchok][axon]);
                    }
                }
            }
        }

        // Используй ЭТО, чтобы подумать. (Много думать вредно)
        public float[] Podumat(float[] sensorsInfo)
        {
            // Активация входных данных
            for(int neuron = 0; neuron < sensorsInfo.Length; neuron++)
            {
                inputs[neuron] = Tg(sensorsInfo[neuron]);
            }


            // First HL
            for(int neuron = 0; neuron < neurons[0].Length; neuron++)
            {
                neurons[0][neuron] = 0;
                for (int axon = 0; axon < axons[0][neuron].Length; axon++)
                {
                    neurons[0][neuron] += axons[0][neuron][axon] * inputs[axon];
                }
                neurons[0][neuron] = Tg(neurons[0][neuron]);
            }

            // Other HL
            for (int layer = 1; layer < neurons.Count; layer++)
            {
                for (int neuron = 0; neuron < neurons[layer].Length; neuron++)
                {
                    neurons[layer][neuron] = 0;
                    for (int axon = 0; axon < axons[layer][neuron].Length; axon++)
                    {
                        neurons[layer][neuron] += axons[layer][neuron][axon] * neurons[layer-1][axon];
                    }
                    neurons[layer][neuron] = Tg(neurons[layer][neuron]);
                }
            }

            // Outputs
            for (int neuron = 0; neuron < outputs.Length; neuron++)
            {
                outputs[neuron] = 0;
                for (int axon = 0; axon < axons[axons.Count - 1][neuron].Length; axon++)
                {
                    outputs[neuron] += axons[axons.Count - 1][neuron][axon] * neurons[neurons.Count - 1][axon];
                }
                outputs[neuron] = Tg(outputs[neuron]);
            }

            return outputs;
        }


        public static float Tg(float value)
        {
            //return (Mathf.Exp(value) - Mathf.Exp(-value)) / (Mathf.Exp(value) + Mathf.Exp(-value));
            //return (1 / (1 + Mathf.Exp(-value)));
            //return value / (1 + Mathf.Abs(value));
            return 2 / (1 + Mathf.Exp(-2 * value)) - 1; //TG
            /*
            if (value < -1f)
            {
                return (-1f);
            }
            else if (value > 1f)
            {
                return (1f);
            }
            else
            {
                return (value);
            }
            */
        }

        public void Mutate(float power)
        {
            for (int layer = 0; layer < axons.Count; layer++)
            {
                for (int puchok = 0; puchok < axons[layer].Count; puchok++)
                {
                    for(int axon = 0; axon < axons[layer][puchok].Length; axon++)
                    {
                        axons[layer][puchok][axon] = axons[layer][puchok][axon] + Random.Range(-1f, 1f) * power;
                    }
                }
            }
        }

        public void ChunkMutation(float power, float blockChance, float puchokChance)
        {
            for (int layer = 0; layer < axons.Count; layer++)
            {
                if (blockChance > Random.Range(0, 100))
                {
                    for (int puchok = 0; puchok < axons[layer].Count; puchok++)
                    {
                        if (puchokChance > Random.Range(0, 100))
                        {
                            for (int axon = 0; axon < axons[layer][puchok].Length; axon++)
                            {
                                axons[layer][puchok][axon] = axons[layer][puchok][axon] + Random.Range(-1f, 1f) * power;
                            }
                        }
                    }
                }
            }
        }

        public void CopyNetwork(Brakodel obolduy)
        {
            for (int layer = 0; layer < obolduy.axons.Count; layer++)
            {
                for (int puchok = 0; puchok < obolduy.axons[layer].Count; puchok++)
                {
                    for (int axon = 0; axon < obolduy.axons[layer][puchok].Length; axon++)
                    {
                        //Debug.Log("before"+axons[layer][puchok][axon]);
                        this.axons[layer][puchok][axon] = obolduy.axons[layer][puchok][axon];
                        //Debug.Log("after" + axons[layer][puchok][axon]+"index:"+layer+"."+puchok+"."+axon);
                    }
                }
            }
        }

        public float Lst()
        {
            return axons[0][0][0];
        }


    }
}

Ответы (0 шт):