莫神视频:https://mofanpy.com/tutorials/machine-learning/evolutionary-algorithm/evolution-strategy-1plus1-ES/
第一部分比较容易理解,就是字面上代码的意思
"""
(1+1)-ES with 1/5th success rule with visualization.
Visit my tutorial website for more: https://mofanpy.com/tutorials/
统一来说都是 (μ/ρ +, λ)-ES, (1+1)-ES 只是一种特殊形式. 这里的 μ 是 population 的数量,
ρ 是从 population 中选取的个数, 用来生成宝宝的. λ 是生成的宝宝数,
如果采用的是 + 形式的, 就是使用将 ρ + λ 混合起来进行适者生存, 如果是 , 形式, 那么就是只使用 λ 进行适者生存.
"""
# 形式多种多样有些头疼. 不过在这一节中, 我们考虑的只是一个爸爸, 生成一个宝宝,
# 然后在爸爸和宝宝中进行适者生存的游戏, 选择爸爸和宝宝中比较好的那个当做下一代的爸爸. (1+1)-ES 总结如下:
# 有一个爸爸;
# 根据爸爸变异出一个宝宝;
# 在爸爸和宝宝中选好的那个变成下一代爸爸.
import numpy as np
import matplotlib.pyplot as plt
DNA_SIZE = 1 # DNA (real number)
DNA_BOUND = [0, 5] # solution upper and lower bounds
N_GENERATIONS = 200
MUT_STRENGTH = 5. # initial step size (dynamic mutation strength)
def F(x): return np.sin(10*x)*x + np.cos(2*x)*x # to find the maximum of this function
# find non-zero fitness for selection
def get_fitness(pred): return pred.flatten()
make_kid这部分是相当重要的。为什么此时代码简便了这么多?
最主要的原因是此算法不需要父辈进行杂交培育后代
那他是怎么进行的呢?
举个例子:
红点是父辈,当我比子代优秀的时候,我就一直在,子代受不了就自杀,当子代优于父辈的时候,父辈觉得很欣慰,便自己消失了,循环往复,直到某一代达到武林巅峰,在这个过程中,是什么决定了子代?实际上只有变异,因为我们的DNA实际上也只有横坐标。
def make_kid(parent):
# no crossover, only mutation
# 不用选父辈,因此简化了,只有变异
k = parent + MUT_STRENGTH * np.random.randn(DNA_SIZE)
# 限制在(0,5)
k = np.clip(k, *DNA_BOUND)
return k
kill_bad,莫神就已经说得很明白了
def kill_bad(parent, kid):
global MUT_STRENGTH
# 参考文献:Rechenberg, I. 1973. Evolutionsstrategie – Optimierung technischer Systeme nach Prinzipien
# der biologischen Evolution, Frommann-Holzboog.
# 计算父亲和孩子的fitness
fp = get_fitness(F(parent))[0]
fk = get_fitness(F(kid))[0]
# 网上有个课件Tutorial: CMA-ES — Evolution Strategies and Covariance Matrix Adaptation里面一张图, 让你秒懂这个1/5的意思.
p_target = 1/5
if fp < fk: # kid better than parent
parent = kid
ps = 1. # kid win -> ps = 1 (successful offspring)
else:
ps = 0.
# adjust global mutation strength
MUT_STRENGTH *= np.exp(1/np.sqrt(DNA_SIZE+1) * (ps - p_target)/(1 - p_target))
return parent
parent = 5 * np.random.rand(DNA_SIZE) # parent DNA
plt.ion() # something about plotting
x = np.linspace(*DNA_BOUND, 200)
for _ in range(N_GENERATIONS):
# ES part
kid = make_kid(parent)
py, ky = F(parent), F(kid) # for later plot
parent = kill_bad(parent, kid)
# something about plotting
plt.cla()
plt.scatter(parent, py, s=200, lw=0, c='red', alpha=0.5,)
plt.scatter(kid, ky, s=200, lw=0, c='blue', alpha=0.5)
plt.text(0, -7, 'Mutation strength=%.2f' % MUT_STRENGTH)
plt.plot(x, F(x))
plt.pause(0.05)
plt.ioff()
plt.show()