ES算法模型
- 个体表示
- 适应度评价
- 变异
- 交叉
- 选择
个体的表示方法
-
个体是一个2n维向量,由实数解 x 和标准差sigma组成:
X = { x, sigma }
其中:x = [ x1, x2, ···,xn]表示个体特征,即基因。 -
向量x是搜索空间中的一个点,即实数解;向量sigma是正态分布的标准差,它用于变异进化。
适应度评价
-
取目标函数 f (x) 为适应度函数 F (x):
f ( x ) = F ( x )
-
目标函数 f (x) 取值可取值为正或负,对其值只进行大小比较,决定优劣。适应度评价只和选择操作相关,其结果用于某种选择操作。
变异
对sigma进行变异:
sigma_temp = theta * sigma[:, pos[0]] + (1 - theta) * sigma[:, pos[1]]
再对Xi个体进行变异:
son_temp = out + sigma_temp * np.random.normal([2, 1])
选择
可以选择以下列出的方法:
- ( 1+1 ) — ES:爬山法
- ( 1, 1 ) — ES:随机搜索法
- ( µ + 1 ) — ES:邻接搜索法
- ( µ , 1 ) — ES:邻接搜索法
- ( µ + λ ) — ES:保留最优个体的多点搜索法
- ( µ , λ ) — ES:多点搜索法
本文使用了 ( µ , λ )
-
先从父代 个个体中产生子代 个个体。
-
再从子代 个个体中选出 个适应度最好的个体,作为新的父代个体。
-
( µ , λ )选择只在λ个子代个体中进行,则父代中某个个体的适应度即使大大高于其他个体,也不能存活到下一代作为子代,造成搜索可能发散,因此只用于适应值函数是时变的情形和多处理机并行计算。
结果
计算多峰值函数的最大值:
import numpy as np
"""
ES-进化策略
(μ,λ) - ES算法从子代λ个个体中选择μ个个体作为新的父代
计算多峰值函数的最大值
"""
# ratio
ratio = 7
# 迭代代数
step = 0
# 期望最大值
E_MAX = 38.80
# 种群规模
N = 80
# x1、x2
res_x_y = []
# 范围
bound_x1 = [-0.3, 12.1]
bound_x2 = [4.1, 5.8]
# 初始化x1、x2
# 计算sigma 初始化种群
# 初始化可以修改为先生成[2,N]的正态分布 再给每一个计算具体的值
X = np.random.random([2, N]) # 生成初始种群矩阵,一列表示一个可行解
X[0] = (bound_x1[1] - bound_x1[0]) * X[0] + bound_x1[0]
X[1] = (bound_x2[1] - bound_x2[0]) * X[1] + bound_x2[0]
# 最大的适应度值
MAX_FITNESS = 0
# 迭代的代数 作为程序终止的条件
GEN = 200
# sigma
sigma = np.random.randn(2, N)
# theta
theta = 0.5
# out
out = np.zeros([2])
# son
son = np.zeros([2, ratio * N])
# fits
fits = np.zeros(son.shape[1])
# 计算适应度的函数
def F(x1, x2):
return 21.5 + x1 * np.sin(4 * np.pi * x1) + x2 * np.sin(20 * np.pi * x2)
if __name__ == '__main__':
while True:
lamda = 1
while lamda < ratio * N:
# 随机生成两个位置 即找X中的两个种子进行变异
pos = np.random.randint(0, N - 1, [1, 2])[0]
# 找出两个种子
index1 = X[:, pos[0]]
index2 = X[:, pos[1]]
# 再度随机交叉
# random 0-1
if np.random.random() < 0.5:
out[0] = index1[0]
else:
out[0] = index2[0]
if np.random.random() < 0.5:
out[1] = index1[1]
else:
out[1] = index2[1]
# 对sigma矩阵中对应列的变异强度进行加权平均
sigma_temp = theta * sigma[:, pos[0]] + (1 - theta) * sigma[:, pos[1]]
# 对被选中的种子对应的sigma变异
# 生成一个子代
son_temp = out + sigma_temp * np.random.normal([2, 1])
# 判断越界
if bound_x1[0] <= son_temp[0] <= bound_x1[1] and bound_x2[0] <= son_temp[1] <= bound_x2[1]:
# 保存子代
son[:, lamda] = son_temp
lamda += 1
# 进行选择
for j in range(son.shape[1]):
x1 = son[:, j][0]
x2 = son[:, j][1]
fits[j] = F(x1, x2)
# 排序 返回由小到大的索引 即下标
arg = np.argsort(fits)
# 找出最大fitness的N个种子 作为下一次的父代
X = son[:, arg[(ratio - 1) * N:ratio * N]]
# 最大适应值对应的x、y
res_x_y = X[:, -1]
MAX_FITNESS_TEMP = F(res_x_y[0], res_x_y[1])
# 更新最大值
if MAX_FITNESS < MAX_FITNESS_TEMP:
MAX_FITNESS = MAX_FITNESS_TEMP
if MAX_FITNESS > E_MAX:
break
print(MAX_FITNESS)
step += 1
print("结果:")
print("step:" + str(step))
print("x:" + str(res_x_y[0]))
print("y:" + str(res_x_y[1]))
print(MAX_FITNESS)
有问题希望可以提出,多多交流~
已经更新其他相关的进化算法(GA、ES、CMA-ES、EP等)~