作者:金良([email protected]) csdn博客:http://blog.csdn.net/u012176591
这是基于 进化论 而启发出来的一种很特别的 机器学习 技巧。 我最近渐渐明白到它可能是破解 strong AI 的关键。 Ben Goertzel 和我见面的谈话中也特别注重这一方向。 原来 Alan Turing 很早就看到 进化 和 machine learning 之间有明显关系,而现时机器学习的一个很有名的研究者 Leslie Valiant 也在新书 (English version) 中谈论这课题。
机器学习的目的就是要在浩瀚的 假设空间 (hypothesis space) 中寻找那些能正确地解释现实的语句。 例如婴孩可能用「有胡子就是爸爸」 来解释身边出现的人。
问题是假设空间太大,我们如同「在禾秆推里找一只针」,单靠 brute force 不是办法。
进化算法就是在很大的空间里 寻找某个 最佳答案 (optimal solution) 的一个很强的技巧。 它把需要寻找的 candidates 模拟成一个「人口」population,任由这些 candidates 在某个人工的环境下竞争, 然后,每次选取得分最高的一小撮样本,让它们「交配」,即 基因重组 (genetic recombination),那样产生新一批的 candidates, 如此逐步推向越来越优秀的 solutions。
举个例子,研究者用进化算法进化出一些电子电路,例如用于音响的滤波器 (filter) ,其 performance 甚至比人手设计的还要优越。 而且,那电路很不规则而且难理解,人们不知道它是如何运作的,有些部分甚至有多馀的组件存在。 那是因为进化的过程中,有时一些表面上没用的「器官」在组合之后或许变有用,所以进化的结果也常保留很多「废物 junk」。
具体的算法怎样?
寻找最优解的函数表达式为
该函数的最小值为
其函数图像
作图源码
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
fig = figure()
ax = Axes3D(fig)
X = np.arange(-3.0, 12.1, 0.08)
Y = np.arange(-4.1, 5.8, 0.08)
X, Y = np.meshgrid(X, Y)
Z = -20*np.exp(-0.2*np.sqrt(np.sqrt((X**2+Y**2)/2)))+20+np.e-np.exp((np.cos(2*np.pi*X)+np.sin(2*np.pi*Y))/2)
ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap='cool')
包括断点的区间 [a,b] ,精度 p ,共有 N 个数,则 N=⌈a−bp⌉+1 。用 m 表示二进制位数,分析:
当 N=4 时, m=2 ,
当 N=5 时, m=3 。
观察得 2m−1<N≤2m ,故有 log2N≤m<log2(N+1) ,
在程序中可表示为
import numpy as np
import matplotlib.pyplot as plt
# 函数定义
def func(x):
y = -20*np.exp(-0.2*np.sqrt(np.sqrt((x[0]**2+x[1]**2)/2)))-np.exp((np.cos(2*np.pi*x[0])+np.cos(2*np.pi*x[1]))/2)+20+np.e
return y
#适应度计算
def getfitness(pop2):
pop = trans2to10(pop2)
fitness = 20*np.exp(-0.2*np.sqrt(np.sqrt((pop[:,0]**2+pop[:,1]**2)/2)))+np.exp((np.cos(2*np.pi*pop[:,0])+np.cos(2*np.pi*pop[:,1]))/2)
return fitness
def getcumsumrate(fitness):
cumsumrate = fitness.cumsum()/sum(fitness)
return cumsumrate
#根据参数(本例有两个参数)的取值范围和精度要求获得基因的个数
def getbitlength(range =((-3,12.1,0.0001),(-4.1,5.8,0.0001))):
N1 = np.ceil((range[0][1]-range[0][0])/range[0][2])+1
bitlength1 = np.int(np.ceil(np.log2(N1)))
N2 = np.ceil((range[1][1]-range[1][0])/range[1][2])+1
bitlength2 = np.int(np.ceil(np.log2(N2)))
return bitlength1,bitlength2
def getpop2(bitlength=(18,17),sizepop=20):
pop2 = np.random.rand(sizepop,sum(bitlength))
pop2[pop2>0.5] = 1
pop2[pop2<=0.5] = 0
return pop2
# 解码
def to2_10(binlist):
val = 0
pow = 1
for i in range(len(binlist))[::-1]:
val += binlist[i]*pow
pow *= 2
return val
def trans2to10(pop2,leninfo = (18,17),rang = ((-3,12.1,0.0001),(-4.1,5.8,0.0001))):
row,column = pop2.shape
pop10 = np.zeros((row,2))
for i in range(row):
pop10[i][0] = rang[0][2]*to2_10(pop2[i][:leninfo[0]])+rang[0][0]
pop10[i][1] = rang[1][2]*to2_10(pop2[i][leninfo[0]:])+rang[1][0]
return pop10
def getselectpair(cumsumrate):#用转盘算法根据累积概率选择两个个体
while True:
flag = cumsumrate-np.random.rand() #rand() [0,1)
sel0 = 0
while flag[sel0]<0 :
sel0 += 1
flag = cumsumrate-np.random.rand() #rand() [0,1)
sel1 = 0
while flag[sel1]<0 :
sel1 += 1
if sel0 != sel1:
break
return [sel0,sel1]
sizepop = 50 #种群规模
genermax = 100 #迭代次数
ratecross = 0.70 #染色体交配率
ratemutation = 0.12 #基因突变率
leninfo = getbitlength()
pop2 = getpop2(sizepop=sizepop)
fitnesslog = []
while genermax > 0:
genermax -= 1
pop2new = np.zeros(pop2.shape)
fitness = getfitness(pop2)
fitnesslog.append([max(fitness),mean(fitness)])
cumsumrate = getcumsumrate(fitness)
for i in range(0,sizepop,2):
selectpair = getselectpair(cumsumrate)
pop2new[i,:] = pop2[selectpair[0]].copy()
pop2new[i+1,:] = pop2[selectpair[1]].copy()
rand2 = np.random.rand(2)
if rand2[0]<=ratecross:#交叉操作,对应变量1
crossbit0 = np.int(np.random.rand()*leninfo[0])
pop2new[i,crossbit0:leninfo[0]],pop2new[i+1,crossbit0:leninfo[0]]=pop2new[i+1,crossbit0:leninfo[0]],pop2new[i,crossbit0:leninfo[0]]
if rand2[1]<=ratecross:#交叉操作,对应变量2
crossbit1 = np.int(np.random.rand()*leninfo[1])+leninfo[0]
pop2new[i,crossbit1:],pop2new[i+1,crossbit1:]=pop2new[i+1,crossbit1:],pop2new[i,crossbit1:]
rand4 = np.random.rand(4)
if rand4[0] < ratemutation:
mutationbit = np.int(rand4[1]*sum(leninfo))
pop2new[i,mutationbit] = np.abs(pop2new[i,mutationbit]-1)
if rand4[2] < ratemutation:
mutationbit = np.int(rand4[3]*sum(leninfo))
pop2new[i+1,mutationbit] = np.abs(pop2new[i+1,mutationbit]-1)
pop2 = pop2new
fitnesslog = np.array(fitnesslog)
bestlog = np.zeros(fitnesslog.shape[0])
bestlog[0] = fitnesslog[0,0]
for i in range(1,fitnesslog.shape[0]):
if(fitnesslog[i,0])>bestlog[i-1]:
bestlog[i]=fitnesslog[i,0]
else:
bestlog[i]=bestlog[i-1]
plt.plot(fitnesslog[:,0])
plt.plot(fitnesslog[:,1])
plt.plot(bestlog)
plt.legend(('max','mean','best'),loc='best')