过了半年多了,现在也到下学期,想起来还有这个事,就来填填坑
话不多说,直接上一个遗传算法的python代码(根据老师的PlatEMO框架里面的GA代码复现,具体matlab代码请看PlatEMO
我这里用到了cupy,CUPY相当于是numpy的升级版,会加快两个ndarray之间的运算,具体用法请看官方文档,本质上与numpy不尽相同,就只有一些数据类型上不一样。
from math import floor
import cupy as cp
import time
class GA:
def __init__(self,population,epochs): # 输入许多个体即种群
self.population = population
self.epochs = epochs
def solve(self):
rank = []
idx = 0
for i in range(self.epochs):
matingPool = self.TournamentSelection(2,self.population.objs())
print("--------------第{}代交配池---------------".format(i+1))
print(matingPool)
pop = []
for j in matingPool:
pop.append(self.population.idvs[j])
offSpring = self.operator(pop)
popu = self.population.idvs + offSpring
rank.append(self.sort(popu))
self.population.idvs = rank[idx]
idx += 1
print("第{}代最优网络的loss为{:.4f}".format(i+1,self.population.idvs[0].obj))
return rank
def sort(self,pop):
res = []
while len(res)<self.population.num:
min = 100000000
idx = 0
for j in range(len(pop)):
if pop[j].obj<min:
min = pop[j].obj
idx = j
res.append(pop[idx])
pop.remove(pop[idx])
return res
def TournamentSelection(self,K,objs): # k元联赛选择算法,返回最佳的下标数组
l = objs[:]
l.sort()
p = [[np.random.randint(0,len(l)).tolist() for m in range(K)] for n in range(len(l))]
best = []
for i in p:
min = i[0]
for j in i:
if j==min:
continue
if l[j] < l[min]:
min = j
best.append(min)
return best
def operator(self,pop):
a = time.time()
p1 = pop[0:floor(len(pop)/2)]
p2 = pop[floor(len(pop)/2):floor(len(pop)/2)*2]
for i in range(len(p1)):
if p1[i]==p2[i]:
continue
if np.random.rand()<0.6: # 交叉率0.6
k = np.random.permutation(len(p1[0].w))[:floor(len(p1[0].w)*0.6)]
t1 = p1[i]
t2 = p2[i]
t1.w[k],t2.w[k] = t2.w[k].copy(),t1.w[k].copy()
p1[i],p2[i] = t1.copy(),t2.copy()
b = time.time()
print("CrossUseTime:{:.2f}s".format(b-a))
off = p1+p2
for i in range(len(off)):
if np.random.rand()<0.2: # 变异率0.2
# print("BeforMute obj:{:.4f}".format(off[i].obj))
m = np.random.permutation(len(off[0].w))[:floor(len(off[0].w)*0.02)]
tmp = off[i]
tmp.w[m] = -tmp.w[m].copy()
off[i] = tmp.copy()
# print("AfterMute obj:{:.4f}".format(off[i].obj))
print("MuteUseTime:{:.2f}s".format(time.time()-b))
return off
我这里用的交叉是模拟二进制交叉SBX,变异的话是针对二值(-1,1)做的。整个代码较为简单,没有PlatEMO里面写的那么全。
什么?你问我Population和Individual怎么写的?
这个要根据具体问题来写了,算法毕竟是基本上没有什么变化的,变的只有数据。
那我给一个简单的Population和Individual的代码
Population
from Individual import Individual
class population:
def __init__(self,N):
self.num = N
self.idvs = []
for i in range(N):
x = 随机生成的参数
idv = Individual()
self.idvs.append(idv)
print('个体{}的目标值为:{:.4f}'.format(i,idv.obj))
def objs(self):
res = []
for i in self.idvs:
res.append(i.obj)
return res
Individual
import cupy as cp
def LossF(**args):
obj = args[0]+args[1]+...
return obj
class Individual:
def __init__(self,**args):
self.x = args
self.obj = LossF(self.x)
def copy(self):
new = Individual(self.x)
return new
应该还算好理解吧,我简化了很多复杂的结构,直接把最本质的框架提取出来。
题外话:
虽然到目前为止看了数十篇论文了,但还是没什么创新的想法,感觉能想到的都有人做过了,别人没做过的也想不到。现在搞科研真的是越来越难了,如果不开发新领域的话真的就无法脱出内卷的大坑了。
说句实话,计算机方向所剩的能开发的领域越来越少,越晚读研越难创新,甚至发论文毕业都是问题。每年数十万研究生毕业,每年都有数十万篇论文要发表,越晚入局就意味着越难出成果。
不过嘛,人一定要有梦想,毕竟没有梦想支撑的生活就是一片空白,只会越活越乏味。说不定哪天能突发奇想,思路来了呢?