我试图根据我从“用于游戏程序员的AI技术”一书中选择的技术编写遗传算法,该技术使用二进制编码和健身比例选择(也称为轮盘赌选择)对基因进行编写。在程序中以二维数组随机生成的总体。
我最近遇到过a piece of pseudocode并试图实施它,但是我遇到了一些问题,我需要做些什么。我检查过一些书籍和一些开源代码,但仍在努力取得进展。 我明白我必须得到总人口的总体适应度的总和,在总和与零之间选择一个随机数,然后如果数字大于父母要覆盖它,但我正在努力实施这些想法
由于我的Java生锈了,所以对实施这些想法的任何帮助都会非常感激。
答案 0 :(得分:50)
以下是GA的完整概述。我确保非常详细,因此可以很容易地编码为C / Java / Python /.../ p>
/* 1. Init population */
POP_SIZE = number of individuals in the population
pop = newPop = []
for i=1 to POP_SIZE {
pop.add( getRandomIndividual() )
}
/* 2. evaluate current population */
totalFitness = 0
for i=1 to POP_SIZE {
fitness = pop[i].evaluate()
totalFitness += fitness
}
while not end_condition (best fitness, #iterations, no improvement...)
{
// build new population
// optional: Elitism: copy best K from current pop to newPop
while newPop.size()<POP_SIZE
{
/* 3. roulette wheel selection */
// select 1st individual
rnd = getRandomDouble([0,1]) * totalFitness
for(idx=0; idx<POP_SIZE && rnd>0; idx++) {
rnd -= pop[idx].fitness
}
indiv1 = pop[idx-1]
// select 2nd individual
rnd = getRandomDouble([0,1]) * totalFitness
for(idx=0; idx<POP_SIZE && rnd>0; idx++) {
rnd -= pop[idx].fitness
}
indiv2 = pop[idx-1]
/* 4. crossover */
indiv1, indiv2 = crossover(indiv1, indiv2)
/* 5. mutation */
indiv1.mutate()
indiv2.mutate()
// add to new population
newPop.add(indiv1)
newPop.add(indiv2)
}
pop = newPop
newPop = []
/* re-evaluate current population */
totalFitness = 0
for i=1 to POP_SIZE {
fitness = pop[i].evaluate()
totalFitness += fitness
}
}
// return best genome
bestIndividual = pop.bestIndiv() // max/min fitness indiv
请注意,目前您缺少健身功能(取决于域名)。交叉将是一个简单的单点交叉(因为您使用的是二进制表示)。突变可以是一个随意的简单翻转。
修改强>: 考虑到你当前的代码结构和符号,我已经在Java中实现了上面的伪代码(请记住,我更像是一个c / c ++人而不是java)。请注意,这绝不是最有效或最完整的实现,我承认我写得很快:
<强> Individual.java 强>
import java.util.Random;
public class Individual
{
public static final int SIZE = 500;
private int[] genes = new int[SIZE];
private int fitnessValue;
public Individual() {}
public int getFitnessValue() {
return fitnessValue;
}
public void setFitnessValue(int fitnessValue) {
this.fitnessValue = fitnessValue;
}
public int getGene(int index) {
return genes[index];
}
public void setGene(int index, int gene) {
this.genes[index] = gene;
}
public void randGenes() {
Random rand = new Random();
for(int i=0; i<SIZE; ++i) {
this.setGene(i, rand.nextInt(2));
}
}
public void mutate() {
Random rand = new Random();
int index = rand.nextInt(SIZE);
this.setGene(index, 1-this.getGene(index)); // flip
}
public int evaluate() {
int fitness = 0;
for(int i=0; i<SIZE; ++i) {
fitness += this.getGene(i);
}
this.setFitnessValue(fitness);
return fitness;
}
}
<强> Population.java 强>
import java.util.Random;
public class Population
{
final static int ELITISM_K = 5;
final static int POP_SIZE = 200 + ELITISM_K; // population size
final static int MAX_ITER = 2000; // max number of iterations
final static double MUTATION_RATE = 0.05; // probability of mutation
final static double CROSSOVER_RATE = 0.7; // probability of crossover
private static Random m_rand = new Random(); // random-number generator
private Individual[] m_population;
private double totalFitness;
public Population() {
m_population = new Individual[POP_SIZE];
// init population
for (int i = 0; i < POP_SIZE; i++) {
m_population[i] = new Individual();
m_population[i].randGenes();
}
// evaluate current population
this.evaluate();
}
public void setPopulation(Individual[] newPop) {
// this.m_population = newPop;
System.arraycopy(newPop, 0, this.m_population, 0, POP_SIZE);
}
public Individual[] getPopulation() {
return this.m_population;
}
public double evaluate() {
this.totalFitness = 0.0;
for (int i = 0; i < POP_SIZE; i++) {
this.totalFitness += m_population[i].evaluate();
}
return this.totalFitness;
}
public Individual rouletteWheelSelection() {
double randNum = m_rand.nextDouble() * this.totalFitness;
int idx;
for (idx=0; idx<POP_SIZE && randNum>0; ++idx) {
randNum -= m_population[idx].getFitnessValue();
}
return m_population[idx-1];
}
public Individual findBestIndividual() {
int idxMax = 0, idxMin = 0;
double currentMax = 0.0;
double currentMin = 1.0;
double currentVal;
for (int idx=0; idx<POP_SIZE; ++idx) {
currentVal = m_population[idx].getFitnessValue();
if (currentMax < currentMin) {
currentMax = currentMin = currentVal;
idxMax = idxMin = idx;
}
if (currentVal > currentMax) {
currentMax = currentVal;
idxMax = idx;
}
if (currentVal < currentMin) {
currentMin = currentVal;
idxMin = idx;
}
}
//return m_population[idxMin]; // minimization
return m_population[idxMax]; // maximization
}
public static Individual[] crossover(Individual indiv1,Individual indiv2) {
Individual[] newIndiv = new Individual[2];
newIndiv[0] = new Individual();
newIndiv[1] = new Individual();
int randPoint = m_rand.nextInt(Individual.SIZE);
int i;
for (i=0; i<randPoint; ++i) {
newIndiv[0].setGene(i, indiv1.getGene(i));
newIndiv[1].setGene(i, indiv2.getGene(i));
}
for (; i<Individual.SIZE; ++i) {
newIndiv[0].setGene(i, indiv2.getGene(i));
newIndiv[1].setGene(i, indiv1.getGene(i));
}
return newIndiv;
}
public static void main(String[] args) {
Population pop = new Population();
Individual[] newPop = new Individual[POP_SIZE];
Individual[] indiv = new Individual[2];
// current population
System.out.print("Total Fitness = " + pop.totalFitness);
System.out.println(" ; Best Fitness = " +
pop.findBestIndividual().getFitnessValue());
// main loop
int count;
for (int iter = 0; iter < MAX_ITER; iter++) {
count = 0;
// Elitism
for (int i=0; i<ELITISM_K; ++i) {
newPop[count] = pop.findBestIndividual();
count++;
}
// build new Population
while (count < POP_SIZE) {
// Selection
indiv[0] = pop.rouletteWheelSelection();
indiv[1] = pop.rouletteWheelSelection();
// Crossover
if ( m_rand.nextDouble() < CROSSOVER_RATE ) {
indiv = crossover(indiv[0], indiv[1]);
}
// Mutation
if ( m_rand.nextDouble() < MUTATION_RATE ) {
indiv[0].mutate();
}
if ( m_rand.nextDouble() < MUTATION_RATE ) {
indiv[1].mutate();
}
// add to new population
newPop[count] = indiv[0];
newPop[count+1] = indiv[1];
count += 2;
}
pop.setPopulation(newPop);
// reevaluate current population
pop.evaluate();
System.out.print("Total Fitness = " + pop.totalFitness);
System.out.println(" ; Best Fitness = " +
pop.findBestIndividual().getFitnessValue());
}
// best indiv
Individual bestIndiv = pop.findBestIndividual();
}
}
答案 1 :(得分:4)
为什么不使用像JGAP这样的开源框架:http://jgap.sf.net
答案 2 :(得分:3)
我通过创建“累积适应度数组”和二进制搜索来实现此算法,因此在选择期间减少了遍历数组中每个元素的需要:
请注意,您只需要在复制阶段开始时创建适应度数组,然后可以多次重复使用它以在 O(log N)时间内执行选择。
另外,请注意比赛选择更容易实现!
答案 3 :(得分:1)
您正在寻找的概念称为“轮盘赌轮选择”。你还没有已建立的适应度函数(你可能暗示每个人的适应度是其染色体的整数值),但是当你做一般计划时:
还有其他等效实现,但总体思路是选择概率与其适应度成比例的成员。
编辑: 关于健身功能的一些注意事项。染色体的表示(在您的情况下为32位整数)与用于评估染色体的适应度函数无关。例如,二进制编码通常将染色体视为一组打包成适当大小的整数值的位域。然后可以通过适当的位掩码操作来完成交叉和变异。如果你有兴趣,我可以发布一些简单的GA代码(在C和Python中),它使用按位运算来实现这些功能。我不确定你对这些语言有多舒服。
答案 4 :(得分:1)
我在java中实现了一个可扩展的实现,其中运算符和单个结构由一起工作的接口很好地定义。 Github回复https://github.com/juanmf/ga
它为每个运营商提供了标准实施,并且具有特定的个人/人口结构和健身计量表的示例问题实施。实例问题的实施是找到一支优秀的足球队,其中包括20支队伍中的球员和预算限制。
要使其适应您当前的问题,您需要提供这些接口的实现:
juanmf.ga.structure.Gen;
juanmf.ga.structure.Individual;
juanmf.ga.structure.IndividualFactory;
juanmf.ga.structure.Population; // Has a basic implementation already
juanmf.ga.structure.PopulationFactory;
在pkg juanmf.grandt
中,您有示例问题实现类以及如何发布它们,如下面的代码段所示。
要发布实现,您只需从此Spring bean返回正确的类:
/**
* Make sure @ComponentScan("pkg") in juanmf.ga.App.java includes this class' pkg
* so that these beans get registered.
*/
@Configuration
public class Config {
@Bean(name="individualFactory")
public IndividualFactory getIndividualFactory() {
return new Team.TeamFactory();
}
@Bean(name="populationFactory")
public PopulationFactory getPopulationFactory() {
return new Team.TeamPopulationFactory();
}
@Bean(name="fitnessMeter")
public FitnessMeter getFitnessMeter() {
return new TeamAptitudeMeter();
}
}
Crosser运算符有两个相同技术的实现,一个顺序和一个并发,远远超过顺序。
可以指定停止条件。如果没有给出,它有一个默认停止条件,在100代之后停止而没有任何改进(这里你必须小心精英,不要放松每一代的最佳状态,以便有效地触发这个停止条件)。
所以,如果有人愿意试一试,我很乐意提供帮助。 欢迎任何人提供建议,以及更好的运营商实施:D或任何改进拉动请求。
答案 5 :(得分:0)
关于轮盘赌选择的其他问题应该有所帮助:
在第一个中,I've tried to explain轮盘赌轮是如何工作的。在第二个,Jarod Elliott has provided some pseudocode。结合Adamski's description of an efficient implementation,这些就足以让某些东西发挥作用。
答案 6 :(得分:0)
值得一提的是。轮盘赌选择(如伪代码所示)不适用于最小化问题 - 但它对最大化问题有效。
由于选择最适合的个体的方式,最小化情况将不成立。详情请参阅:Computational Intelligence: 2nd edition