AI Flappy Bird 无法正确变异
AI Flappy Bird doesnt mutate corectly
我是编程新手,尤其擅长人工智能编程。如果问题很愚蠢或很容易解决,我很抱歉。
我用神经网络创建了一个原始的飞扬的小鸟游戏来控制它。一切顺利,直到所有的鸟都死了。在所有鸟死后,我选择最好的鸟,创建新种群数组,将新鸟 "brain" 设置为等于最好的鸟 "brain",最后我将所有新种群鸟的大脑变异为很小,所以它们不一样。我尝试使用概率进行变异,改变新鸟类大脑的所有权重,设置 if 语句,以便权重不会低于 1.0 或低于 -1.0。结果是一样的,所有下一代(第二代)的鸟都表现得像它们一样 "brain"。
这里有一些我认为值得检查的代码。我可以放置所有代码,但它很大。
再人口
for (int i = 0; i < population; i++) {
birds.add(new Bird());
birds.get(i).brain=lastbird.brain;
birds.get(i).brain.mutate(0.1);
}
变异函数
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;
}
}
}
}
}
网络(大脑)变量和构造函数
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);
}
}
}
当您将第 i 只鸟的大脑分配给 birds.get(i).brain=lastbird.brain
处所有新生代鸟中的 lastbird.brain
时,您正在设置所有新生鸟的所有大脑的参考到同一个大脑对象。 IE。任何 bird.brain 引用指向同一个大脑对象。所以当你改变(即变异)一只鸟的大脑时,它是在所有参考指向的共同对象上完成的,并且同时反映在所有鸟身上。
您需要复制大脑对象的内容,而不是指向同一个对象。您可以通过克隆或使用复制构造函数来做到这一点。复制构造函数优于克隆。您需要将 birds.get(i).brain=lastbird.brain
替换为
birds.get(i).brain = new Brain(lastbird.brain);
由于你没有给出Brain对象的代码,我无法给出拷贝构造函数的实现。您可以在构造函数中使用 = 符号分配原语(int、String 等)。但是对于所有自定义对象,您还需要为它们创建一个复制构造函数。
您可以在此处找到更多信息 How do I copy an object in Java?。
编辑: 在提供网络 class 后添加实施。
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;
}
我是编程新手,尤其擅长人工智能编程。如果问题很愚蠢或很容易解决,我很抱歉。 我用神经网络创建了一个原始的飞扬的小鸟游戏来控制它。一切顺利,直到所有的鸟都死了。在所有鸟死后,我选择最好的鸟,创建新种群数组,将新鸟 "brain" 设置为等于最好的鸟 "brain",最后我将所有新种群鸟的大脑变异为很小,所以它们不一样。我尝试使用概率进行变异,改变新鸟类大脑的所有权重,设置 if 语句,以便权重不会低于 1.0 或低于 -1.0。结果是一样的,所有下一代(第二代)的鸟都表现得像它们一样 "brain"。 这里有一些我认为值得检查的代码。我可以放置所有代码,但它很大。
再人口
for (int i = 0; i < population; i++) {
birds.add(new Bird());
birds.get(i).brain=lastbird.brain;
birds.get(i).brain.mutate(0.1);
}
变异函数
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;
}
}
}
}
}
网络(大脑)变量和构造函数
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);
}
}
}
当您将第 i 只鸟的大脑分配给 birds.get(i).brain=lastbird.brain
处所有新生代鸟中的 lastbird.brain
时,您正在设置所有新生鸟的所有大脑的参考到同一个大脑对象。 IE。任何 bird.brain 引用指向同一个大脑对象。所以当你改变(即变异)一只鸟的大脑时,它是在所有参考指向的共同对象上完成的,并且同时反映在所有鸟身上。
您需要复制大脑对象的内容,而不是指向同一个对象。您可以通过克隆或使用复制构造函数来做到这一点。复制构造函数优于克隆。您需要将 birds.get(i).brain=lastbird.brain
替换为
birds.get(i).brain = new Brain(lastbird.brain);
由于你没有给出Brain对象的代码,我无法给出拷贝构造函数的实现。您可以在构造函数中使用 = 符号分配原语(int、String 等)。但是对于所有自定义对象,您还需要为它们创建一个复制构造函数。
您可以在此处找到更多信息 How do I copy an object in Java?。
编辑: 在提供网络 class 后添加实施。
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;
}