1

i am new to programming and especialy at programming ai. I am sorry if the problem is stupid or easy to fix. I have created a primitive flappy bird game with neural network to controll it. Every thing goes ok until all the birds die. After all birds die i am choosing the best bird, create Array of new population , set the new birds "brain" to equal to the best bird "brain", and finally i am mutate all the new population birds brain a tiny so they are not be the same. I tried to mutate using probability, mutate all the weights of new birds brain, set if statement so weights doesnt go below 1.0 or under -1.0. The result is the same , all the birds at the next generation (second) act like they are having the same "brain". Here are some code that i think is worth to check. I can place all the code but it is big.

Repopulation

        for (int i = 0; i < population; i++) {
            birds.add(new Bird());
            birds.get(i).brain=lastbird.brain;
            birds.get(i).brain.mutate(0.1);
        }

Mutation function

        public void mutate(double eta) {
        Random dice = new Random();
        for (int layer = 1; layer < NETWORK_SIZE; layer++) {
            for (int neuron = 0; neuron < NETWORK_LAYER_SIZES[layer]; neuron++) {
                if (dice.nextDouble() < eta) {
                    bias[layer][neuron] += dice.nextGaussian()/2;
                }
                for (int prevNeuron = 0; prevNeuron < NETWORK_LAYER_SIZES[layer - 1]; prevNeuron++) {
                    if (dice.nextDouble() < eta) {
                        weights[layer][neuron][prevNeuron] += dice.nextGaussian()/2;
                    }
                }
        }
        }
        }

Network(brain) veriables and constructor

public class Network  {

private double[][] output;
private double[][][] weights;
private double[][] bias;

private double[][] error_signal;
private double[][] output_derivative;

public final int[] NETWORK_LAYER_SIZES;
public final int INPUT_SIZE;
public final int OUTPUT_SIZE;
public final int NETWORK_SIZE;

public Network(int... NETWORK_LAYER_SIZES) {
    this.NETWORK_LAYER_SIZES = NETWORK_LAYER_SIZES;
    this.INPUT_SIZE = NETWORK_LAYER_SIZES[0];
    this.NETWORK_SIZE = NETWORK_LAYER_SIZES.length;
    this.OUTPUT_SIZE = NETWORK_LAYER_SIZES[NETWORK_SIZE - 1];

    this.output = new double[NETWORK_SIZE][];
    this.weights = new double[NETWORK_SIZE][][];
    this.bias = new double[NETWORK_SIZE][];

    this.error_signal = new double[NETWORK_SIZE][];
    this.output_derivative = new double[NETWORK_SIZE][];

    for (int i = 0; i < NETWORK_SIZE; i++) {
        this.output[i] = new double[NETWORK_LAYER_SIZES[i]];
        this.error_signal[i] = new double[NETWORK_LAYER_SIZES[i]];
        this.output_derivative[i] = new double[NETWORK_LAYER_SIZES[i]];

        this.bias[i] = NetworkTools.createRandomArray(NETWORK_LAYER_SIZES[i], -0.5, 0.7);

        if (i > 0) {
            weights[i] = NetworkTools.createRandomArray(NETWORK_LAYER_SIZES[i], NETWORK_LAYER_SIZES[i - 1], -1, 1);
        }
    }
}
john2994
  • 393
  • 1
  • 3
  • 15
  • What do you do in your if statement when you check that the new weight is below -1 or above 1? My guess is that whatever you're doing there, it is happening to all your population. Try to reduce the mutation (instead of `dice.nextGaussian()/2;` mutate it with a lower value like `dice.nextGaussian()/10;`). See if it helps. – ihavenoidea May 11 '20 at 19:10

1 Answers1

1

When you assign the brain of the i th bird to the lastbird.brain in all of the new generation birds at birds.get(i).brain=lastbird.brain, you are setting the references of all the brains of all the new birds to the same brain object. ie. any bird.brain reference points to the same brain object. So when you change (ie. mutate) one bird's brain, it is done on the common object pointed by all the references and it is reflected on all the birds at the same time.

You need to copy the contents of the brain object instead of pointing to the same object. You can do this by cloning or using copy constructors. Copy constructors are preferred over cloning. You need to replace birds.get(i).brain=lastbird.brain with

birds.get(i).brain = new Brain(lastbird.brain);

Since you have not given the code of the Brain object, I cannot give the implementation of the copy constructor. You can assign the primitives (int, String etc) using = sign within the constructor. But for all custom objects, you need to create a copy constructor for those as well.

You can find more information here How do I copy an object in Java?.

Edit: Adding the implementation after the Network class was provided.

 public Network( Network other )
    {
        this.output = copy2d( other.output );
        this.weights = copy3d( other.weights );
        this.bias = copy2d( other.bias );
        this.error_signal = copy2d( other.error_signal );
        this.output_derivative = copy2d( other.output_derivative );

        this.NETWORK_LAYER_SIZES = copy1dInt(other.NETWORK_LAYER_SIZES);
        this.INPUT_SIZE = other.INPUT_SIZE;
        this.OUTPUT_SIZE = other.OUTPUT_SIZE;
        this.NETWORK_SIZE = other.NETWORK_SIZE;
    }

    private static double[][][] copy3d( double[][][] original )
    {
        double[][][] copy = new double[original.length][][];
        for( int i = 0; i < original.length; i++ )
        {
            copy[i] = copy2d( original[i] );
        }
        return copy;
    }

    private  static double[][] copy2d( double[][] original )
    {
        double[][] copy = new double[original.length][];
        for( int i = 0; i < original.length; i++ )
        {
            copy[i] = copy1d( original[i] );
        }
        return copy;
    }

    private static double[] copy1d( double[] original )
    {
        int length = original.length;
        double[] copy = new double[length];
        System.arraycopy( original, 0, copy, 0, length );
        return copy;
    }

    private static int[] copy1dInt( int[] original )
    {
        int length = original.length;
        int[] copy = new int[length];
        System.arraycopy( original, 0, copy, 0, length );
        return copy;
    }
saki
  • 36
  • 3
  • I' ve read the post that you shared, also i watched some videos on youtube about shallow and deep copy. I am now understanding where i have problem , but i still didnt understand how to fix it. In the examples it is easy because of small amout of code and veriables , but how to do this on this code? I have edited the post and added the constructor of the Network class (here i named it "brain"). Thanks in advance. – john2994 May 11 '20 at 20:29
  • I've edited my answer with the implementation. You can copy the new constructor and the other methods into your code and replace birds.get(i).brain=lastbird.brain with birds.get(i).brain = new Brain(lastbird.brain); and it should work fine. More info on copying arrays https://stackoverflow.com/questions/1686425/copy-a-2d-array-in-java – saki May 12 '20 at 06:45
  • 1
    Thanks Saki ,it worked . I just tweaked a little bit your code at copy3d( double[][][] original ) cause of the specification of my neural network – john2994 May 12 '20 at 09:47