遗传算法:收敛问题
Genetic algorithm: problem of convergence
我试图用遗传算法找到一个最大问题的解决方案,但它没有收敛,相反最大适应度越来越低。我不明白为什么它不起作用;我尝试自己执行这些函数并且它们起作用了,我不确定主函数中的调用 though.the 一个最大的问题是当你有一个长度为 m 的二进制个体 (1/0) 的人口 N ,并且您想优化种群,以便生成至少一个仅包含 1 的个体(在我的例子中为 0)
这是我的代码:
import random
def fitness(individual):
i = 0
for m in individual:
if m == 0:
i += 1
return i
def selection(pop):
chosen = []
for i in range(len(pop)):
aspirants = []
macs = []
for j in range(3):
aspirants.append(random.choice(pop))
if fitness(aspirants[0]) > fitness(aspirants[1]):
if fitness(aspirants[0]) > fitness(aspirants[2]):
macs = aspirants[0]
else: macs = aspirants[2]
else:
if fitness(aspirants[1]) > fitness(aspirants[2]):
macs = aspirants[1]
else: macs = aspirants[2]
chosen.append(macs)
return chosen
def crossover(offspring):
for child1, child2 in zip(offspring[::2], offspring[1::2]):
if random.random() < 0.7:
child1[50:100], child2[50:100]=child2[50:100], child1[50:100]
def mutate(offspring):
for mut in offspring:
if random.random() < 0.3:
for i in range(len(mut)):
if random.random() < 0.05:
mut[i] = type(mut[i])(not mut[i])
def gen_individ():
ind = []
for s in range(100):
ind.append(random.randint(0, 1))
return ind
def gen_pop():
pop = []
for s in range(300):
pop.append(gen_individ())
return pop
g = 0
popul = gen_pop()
print("length of pop = %i "% len(popul))
fits = []
for k in popul:
fits.append(fitness(k))
print("best fitness before = %i"% max(fits))
while(max(fits) < 100 and g < 100):
g += 1
offspring = []
offspring = selection(popul)
crossover(offspring)
mutate(offspring)
popul.clear()
popul[:] = offspring
fits.clear()
for k in popul:
fits.append(fitness(k))
print("lenght of pop = %i "% len(popul))
print("best fitness after = %i"% max(fits))
print("generation : %i"%g)
问题似乎是在您的所有功能中,您总是只修改相同的个体而不是创建副本。例如,在 selection
函数中,您重复 select 三者中最好的(以一种相当复杂的方式),然后插入多个 references 到相同的列表进入 chosen
列表。稍后,当你 mutate
其中任何一个时,你会改变所有引用。最后你甚至可能只得到 N
对同一个列表的引用,此时显然没有更多实际的 selection 可以发生。
相反,您应该创建列表的副本。这可能发生在不同的地方:在您的主要方法中,在 mutate
和 recombine
中,或者在下一次迭代的 selection
中。我把它放到selection
里,主要是因为这个功能也可以通过其他方式改进:
def selection(pop):
chosen = []
for i in range(len(pop)):
# a lot shorter
aspirants = random.sample(pop, 3)
macs = max(aspirants, key=fitness)
# create COPIES of the individual, not multiple references
chosen.append(macs[:])
return chosen
有了这个,你应该每次都获得 100 的质量。
我试图用遗传算法找到一个最大问题的解决方案,但它没有收敛,相反最大适应度越来越低。我不明白为什么它不起作用;我尝试自己执行这些函数并且它们起作用了,我不确定主函数中的调用 though.the 一个最大的问题是当你有一个长度为 m 的二进制个体 (1/0) 的人口 N ,并且您想优化种群,以便生成至少一个仅包含 1 的个体(在我的例子中为 0)
这是我的代码:
import random
def fitness(individual):
i = 0
for m in individual:
if m == 0:
i += 1
return i
def selection(pop):
chosen = []
for i in range(len(pop)):
aspirants = []
macs = []
for j in range(3):
aspirants.append(random.choice(pop))
if fitness(aspirants[0]) > fitness(aspirants[1]):
if fitness(aspirants[0]) > fitness(aspirants[2]):
macs = aspirants[0]
else: macs = aspirants[2]
else:
if fitness(aspirants[1]) > fitness(aspirants[2]):
macs = aspirants[1]
else: macs = aspirants[2]
chosen.append(macs)
return chosen
def crossover(offspring):
for child1, child2 in zip(offspring[::2], offspring[1::2]):
if random.random() < 0.7:
child1[50:100], child2[50:100]=child2[50:100], child1[50:100]
def mutate(offspring):
for mut in offspring:
if random.random() < 0.3:
for i in range(len(mut)):
if random.random() < 0.05:
mut[i] = type(mut[i])(not mut[i])
def gen_individ():
ind = []
for s in range(100):
ind.append(random.randint(0, 1))
return ind
def gen_pop():
pop = []
for s in range(300):
pop.append(gen_individ())
return pop
g = 0
popul = gen_pop()
print("length of pop = %i "% len(popul))
fits = []
for k in popul:
fits.append(fitness(k))
print("best fitness before = %i"% max(fits))
while(max(fits) < 100 and g < 100):
g += 1
offspring = []
offspring = selection(popul)
crossover(offspring)
mutate(offspring)
popul.clear()
popul[:] = offspring
fits.clear()
for k in popul:
fits.append(fitness(k))
print("lenght of pop = %i "% len(popul))
print("best fitness after = %i"% max(fits))
print("generation : %i"%g)
问题似乎是在您的所有功能中,您总是只修改相同的个体而不是创建副本。例如,在 selection
函数中,您重复 select 三者中最好的(以一种相当复杂的方式),然后插入多个 references 到相同的列表进入 chosen
列表。稍后,当你 mutate
其中任何一个时,你会改变所有引用。最后你甚至可能只得到 N
对同一个列表的引用,此时显然没有更多实际的 selection 可以发生。
相反,您应该创建列表的副本。这可能发生在不同的地方:在您的主要方法中,在 mutate
和 recombine
中,或者在下一次迭代的 selection
中。我把它放到selection
里,主要是因为这个功能也可以通过其他方式改进:
def selection(pop):
chosen = []
for i in range(len(pop)):
# a lot shorter
aspirants = random.sample(pop, 3)
macs = max(aspirants, key=fitness)
# create COPIES of the individual, not multiple references
chosen.append(macs[:])
return chosen
有了这个,你应该每次都获得 100 的质量。