大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。
Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺
一、遗传算法简介:
遗传算法是进化算法的一部分,是一种通过模拟自然进化过程搜索最优解的方法。
二、遗传算法思想:
遗传算法组成:
1.编码
2.适应度函数
3.遗传算子:选择、交叉、变异
4.运行参数
借鉴生物进化论,遗传算法将要解决的问题模拟成一个生物进化的过程,通过复制、交叉、突变等操作产生下一代的解,并逐步淘汰掉适应度函数值低的解,增加适应度函数值高的解。这样进化N代后就很有可能会进化出适应度函数值很高的个体。
2.1.编码
将问题的解编码称字符串形式才能使用遗传算法。最简单的一种编码是二进制编码,即将问题的解编码成二进制位数组的形式。
基因在一定能够意义上包含了它所代表的问题的解。基因的编码方式很多,取决于要解决的问题本身。常见的编码方式有:
二进制编码,基因用0或1表示,常用于解决0-1背包问题
互换编码,用于解决排序问题
树形编码,用于遗传规划中的演化变成或者表示
2.2.适应度函数:
用于评价某个染色体的适应度,用f(x)表示。有时需要区分染色体的适应度函数与问题的目标函数。
2.3.遗传算子:
遗传算子有3个最基本的操作:选择、交叉、变异
选择:选择一些染色体来产生下一代。一种常用的选择策略是比例选择,也就是个体被选中的概率与其适应度函数值成正比。
交叉:两个相互配对的染色体依据交叉概率按某种方法(染色体交换部分基因、双交叉点法、基于“与/或”交叉法)相互交换其部分基因,从而形成两个新的个体。交叉运算在GA中起关键作用,是产生新个体的主要方法。
变异:依据变异概率将个体编码串中的某些基因值用其他基因值来替换,从而形成一个新的个体。GA中的变异运算是产生新个体的辅助方法,它决定了GA的局部搜索能力,同时保持种群的多样性。交叉运算和变异运算的相互配合,共同完成对搜索空间的全局搜索和局部搜索。
2.4.运行参数:
GA运行时选择的参数应该根据解决的具体问题而定,到目前为止,还没有一个适用于GA所有应用领域的关于算法参数的理论。使用GA时推荐的参数:交叉率、变异率、种群的规模、终止进化代数。
三、遗传算法特点:
遗传算法是一类可用于复杂系统优化的具有鲁棒性的搜索算法,与传统的优化算法相比,具有以下特点:
群体搜索,易于并行化处理
不是盲目穷举,而是启发式搜索
适应度函数不受连续、可微等条件的约束,适用范围很广
容易实现。一旦有了一个遗传算法的程序,如果想解决一个新的问题,只需针对新的问题重新进行基因编码就行,如果编码方法也相同,那只需要改变一下适应度函数
但是全局搜索能力不强,很容易陷入局部最优解跳不出来
将遗传算法用于解决各种实际问题后,遗传算法有时会由于各种原因过早向目标函数的局部最优解收敛,从而很难找到全局最优解。
四、遗传算法实例:
利用遗传算法求解二元函数的最大值
1.种群和个体:
首先生成了200个随机的(x,y)对,将(x,y)坐标对带入要求解的函数F(x,y)中,根据适者生存,我们定义使得函数值F(x,y)越大的(x,y)对越适合环境,从而这些适应环境党的(x,y)对更有可能被保留下来,而那些不适应环境的(x,y)则有很大胆几率被淘汰,保留下来的点经过繁殖产生新的点,如此进化下去最后留下的大部分点都是适应环境的点,即在最高点附近。执行结果将与结果相近x≈0,y≈1.5。每个(x,y)为一个个体,可能的解的集合为种群。
2.编码解码:
每个个体都将被编码成一个向量表示。这里将不同的实数表示成不同的二进制串表示,称编码后的二进制串为染色体。随机生成整个种群个体的染色体。需要找到一个逆映射将这个随机的二进制串映射到求解范围内。
3.适应度和选择:
需要在种群中根据适者生存保存优秀的个体,淘汰掉不适应环境的个体。在本例求最大值的问题中可以直接用每个个体对应的函数值来评估,函数值越大越有可能被保留。选择则是根据新个体的适应度进行,但同时不意味着完全以适应度高低为导向,单纯选择适应度高低为导向可能会导致算法快速收敛到局部最优解而非全局最优解。作为折中,可以根据原则:适应度越高,被选择的机会越高,适应度低,被选择的机会就低。
4.交叉、变异:
选择得到了适应度高的基因,需要通过繁殖后代来产生比当前更好的基因,但是繁殖过程不能保证每个后代个体的基因都比上一代优秀,需要继续通过选择让适应环境的个体保留下来,完成进化,不断迭代这个过程种群中的个体就会不断进化。交叉中子代个体随机产生染色体的任意位置获得父亲和母亲各一半染色体,变异通常在某个位置上改变二进制位。交叉和变异都是有一定概率发生的,避免了向优化的反方向运行,也避免了局部最优解。
代码:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
from mpl_toolkits.mplot3d import Axes3D
DNA_SIZE = 24
POP_SIZE = 200
CROSSOVER_RATE = 0.8
MUTATION_RATE = 0.005
N_GENERATIONS = 50
X_BOUND = [-3, 3]
Y_BOUND = [-3, 3]
def F(x, y):
return 3*(1-x)**2*np.exp(-(x**2)-(y+1)**2)- 10*(x/5 - x**3 - y**5)*np.exp(-x**2-y**2)- 1/3**np.exp(-(x+1)**2 - y**2)
def plot_3d(ax):
X = np.linspace(*X_BOUND, 100)
Y = np.linspace(*Y_BOUND, 100)
X,Y = np.meshgrid(X, Y)
Z = F(X, Y)
ax.plot_surface(X,Y,Z,rstride=1,cstride=1,cmap=cm.coolwarm)
ax.set_zlim(-10,10)
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')
plt.pause(3)
plt.show()
def get_fitness(pop):
x,y = translateDNA(pop)
pred = F(x, y)
return (pred - np.min(pred)) + 1e-3 #减去最小的适应度是为了防止适应度出现负数,通过这一步fitness的范围为[0, np.max(pred)-np.min(pred)],最后在加上一个很小的数防止出现为0的适应度
def translateDNA(pop): #pop表示种群矩阵,一行表示一个二进制编码表示的DNA,矩阵的行数为种群数目
x_pop = pop[:,1::2]#奇数列表示X
y_pop = pop[:,::2] #偶数列表示y
#pop:(POP_SIZE,DNA_SIZE)*(DNA_SIZE,1) --> (POP_SIZE,1)
x = x_pop.dot(2**np.arange(DNA_SIZE)[::-1])/float(2**DNA_SIZE-1)*(X_BOUND[1]-X_BOUND[0])+X_BOUND[0]
y = y_pop.dot(2**np.arange(DNA_SIZE)[::-1])/float(2**DNA_SIZE-1)*(Y_BOUND[1]-Y_BOUND[0])+Y_BOUND[0]
return x,y
def crossover_and_mutation(pop, CROSSOVER_RATE = 0.8):
new_pop = []
for father in pop: #遍历种群中的每一个个体,将该个体作为父亲
child = father #孩子先得到父亲的全部基因(这里我把一串二进制串的那些0,1称为基因)
if np.random.rand() < CROSSOVER_RATE: #产生子代时不是必然发生交叉,而是以一定的概率发生交叉
mother = pop[np.random.randint(POP_SIZE)] #再种群中选择另一个个体,并将该个体作为母亲
cross_points = np.random.randint(low=0, high=DNA_SIZE*2) #随机产生交叉的点
child[cross_points:] = mother[cross_points:] #孩子得到位于交叉点后的母亲的基因
mutation(child) #每个后代有一定的机率发生变异
new_pop.append(child)
return new_pop
def mutation(child, MUTATION_RATE=0.003):
if np.random.rand() < MUTATION_RATE: #以MUTATION_RATE的概率进行变异
mutate_point = np.random.randint(0, DNA_SIZE) #随机产生一个实数,代表要变异基因的位置
child[mutate_point] = child[mutate_point]^1 #将变异点的二进制为反转
def select(pop, fitness): # nature selection wrt pop's fitness
idx = np.random.choice(np.arange(POP_SIZE), size=POP_SIZE, replace=True,
p=(fitness)/(fitness.sum()) )
return pop[idx]
def print_info(pop):
fitness = get_fitness(pop)
max_fitness_index = np.argmax(fitness)
print("max_fitness:", fitness[max_fitness_index])
x,y = translateDNA(pop)
print("最优的基因型:", pop[max_fitness_index])
print("(x, y):", (x[max_fitness_index], y[max_fitness_index]))
if __name__ == "__main__":
fig = plt.figure()
ax = Axes3D(fig)
plt.ion()#将画图模式改为交互模式,程序遇到plt.show不会暂停,而是继续执行
plot_3d(ax)
pop = np.random.randint(2, size=(POP_SIZE, DNA_SIZE*2)) #matrix (POP_SIZE, DNA_SIZE)
for _ in range(N_GENERATIONS):#迭代N代
x,y = translateDNA(pop)
if 'sca' in locals():
sca.remove()
sca = ax.scatter(x, y, F(x,y), c='black', marker='o');plt.show();plt.pause(0.1)
pop = np.array(crossover_and_mutation(pop, CROSSOVER_RATE))
#F_values = F(translateDNA(pop)[0], translateDNA(pop)[1])#x, y --> Z matrix
fitness = get_fitness(pop)
pop = select(pop, fitness) #选择生成新的种群
print_info(pop)
plt.ioff()
plot_3d(ax)
结果:
运行结果最大点与正确最大值坐标相近。
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/197816.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...