Улучшение популяции генетического алгоритма Flappy Bird

Я пытаюсь создать генетический алгоритм, который учится играть в дрянную птицу. У меня игра работает, это мой класс Bird:

public class Bird extends Player {

public NNetwork network;

public Bird(float x, float y, float velX, float velY, float width, float height) {
    super(x, y, velX, velY, width, height);
    NTopology topo = new NTopology(3,5,1);
    network = new NNetwork(topo, 0.1f, 0.1f, true);
}

public void reset() {
    setAlive(true);
    setX(0f);
    setY(1000f);
    setVelY(0f);
}

/**
 * Feeds the parameters into the neural net
 * @param dyTop height difference to the top edge
 * @param dyBot height difference to the bottom edge
 * @param dx distance to the obstacles
 * @return true if the bird thinks it would be good to jump
 */
public void jump(float dyTop, float dyBot,float dx) {
    network.feed(dyTop, dyBot, dx);
    if(network.getOutputs()[0]>0f) super.flap();
}

public void update(float dyTop, float dyBot, float dx) {
    super.update();
    jump(dyTop, dyBot, dx);
}

public Bird mutate() {
    Bird ret = this;
    ret.network.mutate();
    ret.setAlive(true);
    ret.setScore(0f);
    ret.setX(0);
    ret.setY(1000);
    return ret;
}

}

и это функции мутации населения

public ArrayList<Bird> sortBirds(ArrayList<Bird> birds) {
    ArrayList<Bird> ret = birds;
    Collections.sort(ret, new Comparator<Bird>() {
        @Override
        public int compare(Bird bird, Bird t1) {
            return bird.getScore() < t1.getScore() ? 1 : -1;
        }
    });
    lastBestScore = ret.get(0).getScore();
    return ret;
}


public ArrayList<Bird> repopulate(ArrayList<Bird> birds) {
    birds = sortBirds(birds);
    Bird bestBird = this.birds.get(0);
    Bird[] retA = new Bird[birds.size()];
    birds.toArray(retA);
    retA[0] = bestBird;
    for(int i = 0; i < 3; i++) {   //replace the 3 worst birds with mutations of the best one (there are always at least 5 birds)
        retA[retA.length-1-i] = bestBird.mutate();
    }
    ArrayList<Bird> ret = new ArrayList<>(Arrays.asList(retA));
    for(Bird b : ret) {b.reset();}
    generation++;
    return ret;
}

функция Bird.reset() просто оживляет птицу и возвращает ее к началу. Когда каждая птица мертва, вызывается repopulate(). Теоретически, эти функции должны улучшать мою популяцию с течением времени, но когда птица лучше других, следующее поколение снова становится плохим.

Я неправильно понял, как работают генетические алгоритмы, или в коде есть ошибка? (Если вам нужно больше кода, я могу опубликовать его)

1 ответ

Во-первых, в вашем коде нет кроссовера, что довольно плохо. Обычно это дает лучшие результаты.

Во-вторых, сохраняете ли вы только лучший геном и 3 его мутации, а остальная часть населения просто восстанавливается с нуля? - это не очень хорошо работает, потому что вам нужно больше разнообразия.

Если вы хотите использовать только мутацию, я бы предложил клонировать лучшую половину в новое поколение, а другую половину - мутации лучшей половины. Но я уверен, что и в этом случае вы застрянете в локальном максимуме, но это будет намного лучше, чем то, как вы это делаете.

Исходя из моего опыта работы с Flappy Bird, вам лучше начать с постоянных столбцов, потому что птицам легче учиться, а вам легче отлаживать.

Другие вопросы по тегам