├── Evolution Strategy.py ├── Genetic_algorithm.py ├── PSO-Example.py ├── README.md └── Sentence_Pair_Matching.py /Evolution Strategy.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | 4 | # 每个个体的长度 5 | GENE_SIZE = 1 6 | # 每个基因的范围 7 | GENE_BOUND = [0, 5] 8 | # 200代 9 | N_GENERATIONS = 200 10 | # 种群的大小 11 | POP_SIZE = 100 12 | # 每一代生成50个孩子 13 | N_KID = 50 14 | 15 | # 寻找函数的最大值 16 | def F(x): 17 | return np.sin(10*x)*x + np.cos(2*x)*x 18 | 19 | class ES(): 20 | def __init__(self,gene_size,pop_size,n_kid): 21 | # 基因长度代表字符串的长度 22 | self.gene_size = gene_size 23 | # 种群的大小代表种群中有几个个体 24 | self.pop_size = pop_size 25 | self.n_kid = n_kid 26 | self.init_pop() 27 | print(self.pop) 28 | # 降到一维 29 | def get_fitness(self): 30 | return self.pred.flatten() 31 | 32 | # 初始化种群 33 | def init_pop(self): 34 | self.pop = dict(DNA=5 * np.random.rand(1, self.gene_size).repeat(POP_SIZE, axis=0), 35 | mut_strength=np.random.rand(POP_SIZE, self.gene_size)) 36 | 37 | # 更新后代 38 | def make_kid(self): 39 | # DNA指的是当前孩子的基因 40 | # mut_strength指的是变异强度 41 | self.kids = {'DNA': np.empty((self.n_kid, self.gene_size)), 42 | 'mut_strength': np.empty((self.n_kid, self.gene_size))} 43 | 44 | for kv, ks in zip(self.kids['DNA'], self.kids['mut_strength']): 45 | # 杂交,随机选择父母 46 | p1, p2 = np.random.choice(self.pop_size, size=2, replace=False) 47 | # 选择杂交点 48 | cp = np.random.randint(0, 2, self.gene_size, dtype=np.bool) 49 | # 当前孩子基因的杂交结果 50 | kv[cp] = self.pop['DNA'][p1, cp] 51 | kv[~cp] = self.pop['DNA'][p2, ~cp] 52 | # 当前孩子变异强度的杂交结果 53 | ks[cp] = self.pop['mut_strength'][p1, cp] 54 | ks[~cp] = self.pop['mut_strength'][p2, ~cp] 55 | 56 | # 变异强度要大于0,并且不断缩小 57 | ks[:] = np.maximum(ks + (np.random.rand()-0.5), 0.) 58 | kv += ks * np.random.randn() 59 | # 截断 60 | kv[:] = np.clip(kv,GENE_BOUND[0],GENE_BOUND[1]) 61 | 62 | # 淘汰低适应度后代 63 | def kill_bad(self): 64 | # 进行vertical垂直叠加 65 | for key in ['DNA', 'mut_strength']: 66 | self.pop[key] = np.vstack((self.pop[key], self.kids[key])) 67 | 68 | # 计算fitness 69 | self.pred = F(self.pop['DNA']) 70 | fitness = self.get_fitness() 71 | 72 | # 读出按照降序排列fitness的索引 73 | max_index = np.argsort(-fitness) 74 | # 选择适应度最大的50个个体 75 | good_idx = max_index[:POP_SIZE] 76 | for key in ['DNA', 'mut_strength']: 77 | self.pop[key] = self.pop[key][good_idx] 78 | 79 | 80 | test1 = ES(gene_size = GENE_SIZE,pop_size = POP_SIZE,n_kid = N_KID) 81 | 82 | plt.ion() 83 | x = np.linspace(*GENE_BOUND, 200) 84 | plt.plot(x, F(x)) 85 | 86 | for _ in range(N_GENERATIONS): 87 | # 画图部分 88 | if 'sca' in globals(): sca.remove() 89 | sca = plt.scatter(test1.pop['DNA'], F(test1.pop['DNA']), s=200, lw=0, c='red', alpha=0.5) 90 | plt.pause(0.05) 91 | 92 | # ES更新 93 | kids = test1.make_kid() 94 | pop = test1.kill_bad() 95 | 96 | plt.ioff(); plt.show() 97 | -------------------------------------------------------------------------------- /Genetic_algorithm.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import math 3 | import random 4 | 5 | 6 | def binarytodecimal(binary): # 将二进制转化为十进制,x的范围是[0,10] 7 | total = 0 8 | for j in range(len(binary)): 9 | total += binary[j] * (2**j) 10 | total = total * 10 / 1023 11 | return total 12 | 13 | def pop_b2d(pop): # 将整个种群转化成十进制 14 | temppop = [] 15 | for i in range(len(pop)): 16 | t = binarytodecimal(pop[i]) 17 | temppop.append(t) 18 | return temppop 19 | 20 | def calobjvalue(pop): # 计算目标函数值 21 | x = np.array(pop_b2d(pop)) 22 | return count_function(x) 23 | 24 | def count_function(x): 25 | y = np.sin(x) + np.cos(5 * x) - x**2 + 2*x 26 | return y 27 | 28 | def calfitvalue(objvalue): 29 | # 转化为适应值,目标函数值越大越好 30 | # 在本例子中可以直接使用函数运算结果为fit值,因为我们求的是最大值 31 | # 在实际应用中需要处理 32 | for i in range(len(objvalue)): 33 | if objvalue[i] < 0: 34 | objvalue[i] = 0 35 | return objvalue 36 | 37 | def best(pop, fitvalue): 38 | #找出适应函数值中最大值,和对应的个体 39 | bestindividual = pop[0] 40 | bestfit = fitvalue[0] 41 | for i in range(1,len(pop)): 42 | if(fitvalue[i] > bestfit): 43 | bestfit = fitvalue[i] 44 | bestindividual = pop[i] 45 | return [bestindividual, bestfit] 46 | 47 | def selection(pop, fit_value): 48 | probability_fit_value = [] 49 | # 适应度总和 50 | total_fit = sum(fit_value) 51 | # 求每个被选择的概率 52 | probability_fit_value = np.array(fit_value) / total_fit 53 | 54 | # 概率求和排序 55 | cum_sum_table = cum_sum(probability_fit_value) 56 | 57 | # 获取与pop大小相同的一个概率矩阵,其每一个内容均为一个概率 58 | # 当概率处于不同范围时,选择不同的个体。 59 | choose_probability = np.sort([np.random.rand() for i in range(len(pop))]) 60 | 61 | fitin = 0 62 | newin = 0 63 | newpop = pop[:] 64 | # 轮盘赌法 65 | while newin < len(pop): 66 | # 当概率处于不同范围时,选择不同的个体。 67 | # 如个体适应度分别为1,2,3,4,5的种群 68 | # 利用np.random.rand()生成一个随机数,当其处于0-0.07时 69 | # 选择个体1,当其属于0.07-0.2时选择个体2,以此类推。 70 | if (choose_probability[newin] < cum_sum_table[fitin]): 71 | newpop[newin] = pop[fitin] 72 | newin = newin + 1 73 | else: 74 | fitin = fitin + 1 75 | # pop里存在重复的个体 76 | pop = newpop[:] 77 | 78 | def cum_sum(fit_value): 79 | # 输入[1, 2, 3, 4, 5],返回[1,3,6,10,15] 80 | temp = fit_value[:] 81 | temp2 = fit_value[:] 82 | for i in range(len(temp)): 83 | temp2[i] = (sum(temp[:i + 1])) 84 | return temp2 85 | 86 | def crossover(pop, pc): 87 | # 按照一定概率杂交 88 | pop_len = len(pop) 89 | for i in range(pop_len - 1): 90 | # 判断是否达到杂交几率 91 | if (np.random.rand() < pc): 92 | # 随机选取杂交点,然后交换结点的基因 93 | individual_size = len(pop[0]) 94 | # 随机选择另一个个体进行杂交 95 | destination = np.random.randint(0,pop_len) 96 | # 生成每个基因进行交换的结点 97 | crosspoint = np.random.randint(0,2,size = individual_size) 98 | # 找到这些结点的索引 99 | index = np.argwhere(crosspoint==1) 100 | # 进行赋值 101 | pop[i,index] = pop[destination,index] 102 | 103 | def mutation(pop, pm): 104 | pop_len = len(pop) 105 | individual_size = len(pop[0]) 106 | # 每条染色体随便选一个杂交 107 | for i in range(pop_len): 108 | for j in range(individual_size): 109 | if (np.random.rand() < pm): 110 | if (pop[i][j] == 1): 111 | pop[i][j] = 0 112 | else: 113 | pop[i][j] = 1 114 | 115 | 116 | # 用遗传算法求函数最大值,组合交叉的概率时0.6,突变的概率为0.001 117 | # y = np.sin(x) + np.cos(5 * x) - x**2 + 2*x 118 | 119 | 120 | popsize = 50 # 种群的大小 121 | pc = 0.6 # 两个个体交叉的概率 122 | pm = 0.001 # 基因突变的概率 123 | gene_size = 10 # 基因长度为10 124 | generation = 100 # 繁殖100代 125 | 126 | results = [] 127 | bestindividual = [] 128 | bestfit = 0 129 | fitvalue = [] 130 | 131 | pop = np.array([np.random.randint(0,2,size = gene_size) for i in range(popsize)]) 132 | 133 | for i in range(generation): # 繁殖100代 134 | objvalue = calobjvalue(pop) # 计算种群中目标函数的值 135 | fitvalue = calfitvalue(objvalue) # 计算个体的适应值 136 | [bestindividual, bestfit] = best(pop, fitvalue) # 选出最好的个体和最好的适应值 137 | results.append([bestfit,binarytodecimal(bestindividual)]) # 每次繁殖,将最好的结果记录下来 138 | selection(pop, fitvalue) # 自然选择,淘汰掉一部分适应性低的个体 139 | crossover(pop, pc) # 交叉繁殖 140 | mutation(pop, pc) # 基因突变 141 | 142 | results.sort() 143 | print(results[-1]) #打印使得函数取得最大的个体,和其对应的适应度 144 | -------------------------------------------------------------------------------- /PSO-Example.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | class PSO(): 4 | def __init__(self,pN,dim,max_iter,func): 5 | self.w = 0.8 #惯性因子 6 | self.c1 = 2 #自身认知因子 7 | self.c2 = 2 #社会认知因子 8 | self.r1 = 0.6 #自身认知学习率 9 | self.r2 = 0.3 #社会认知学习率 10 | self.pN = pN #粒子数量 11 | self.dim = dim #搜索维度 12 | self.max_iter = max_iter #最大迭代次数 13 | self.X = np.zeros((self.pN,self.dim)) #初始粒子的位置和速度 14 | self.V = np.zeros((self.pN,self.dim)) 15 | self.pbest = np.zeros((self.pN,self.dim),dtype = float) #粒子历史最佳位置 16 | self.gbest = np.zeros((1,self.dim),dtype = float) #全局最佳位置 17 | self.p_bestfit = np.zeros(self.pN) #每个个体的历史最佳适应值 18 | self.fit = -1e15 #全局最佳适应值 19 | self.func = func 20 | 21 | def function(self,x): 22 | return self.func(x) 23 | 24 | def init_pop(self,): #初始化种群 25 | for i in range(self.pN): 26 | #初始化每一个粒子的位置和速度 27 | self.X[i] = np.random.uniform(0,5,[1,self.dim]) 28 | self.V[i] = np.random.uniform(0,5,[1,self.dim]) 29 | 30 | self.pbest[i] = self.X[i] #初始化历史最佳位置 31 | self.p_bestfit[i] = self.function(self.X[i]) #得到对应的fit值 32 | if(self.p_bestfit[i] > self.fit): 33 | self.fit = self.p_bestfit[i] 34 | self.gbest = self.X[i] #得到全局最佳 35 | 36 | def update(self): 37 | fitness = [] 38 | 39 | for _ in range(self.max_iter): 40 | for i in range(self.pN): #更新gbest\pbest 41 | temp = self.function(self.X[i]) #获得当前位置的适应值 42 | if( temp > self.p_bestfit[i] ): #更新个体最优 43 | self.p_bestfit[i] = temp 44 | self.pbest[i] = self.X[i] 45 | if(self.p_bestfit[i] > self.fit): #更新全局最优 46 | self.gbest = self.X[i] 47 | self.fit = self.p_bestfit[i] 48 | 49 | for i in range(self.pN): #更新权重 50 | self.V[i] = self.w*self.V[i] + self.c1*self.r1*(self.pbest[i] - self.X[i]) + \ 51 | self.c2*self.r2*(self.gbest - self.X[i]) 52 | self.X[i] = self.X[i] + self.V[i] 53 | 54 | fitness.append(self.fit) 55 | 56 | return self.gbest,self.fit 57 | 58 | def count_func(x): 59 | y = -x**2 + 20*x + 10 60 | return y 61 | 62 | pso_example = PSO(pN = 50,dim = 1,max_iter = 300, func = count_func) 63 | pso_example.init_pop() 64 | x_best,fit_best= pso_example.update() 65 | print(x_best,fit_best) 66 | 67 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Optimization_Algorithm 2 | Let's study optimization algorithm together! 3 | -------------------------------------------------------------------------------- /Sentence_Pair_Matching.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import math 3 | import random 4 | 5 | TARGET_PHRASE = 'XJQ2WX' # 目标字符串 6 | POP_SIZE = 300 # 种群数量 7 | CROSS_RATE = 0.4 # 杂交几率 8 | MUTATION_RATE = 0.01 # 突变几率 9 | N_GENERATIONS = 1000 # 繁殖代数 10 | 11 | GENE_SIZE = len(TARGET_PHRASE) # 获取字符串长度 12 | TARGET_ASCII = np.fromstring(TARGET_PHRASE, dtype=np.uint8) # 从字符串转换到数字 13 | 14 | class GA(): 15 | def __init__(self,gene_size,unit_length,cross_rate,mutation_rate,pop_size): 16 | # 基因长度代表字符串的长度 17 | self.gene_size = gene_size 18 | # 种群的大小代表种群中有几个个体 19 | self.pop_size = pop_size 20 | # 单位长度代表字符串每个字符所对应的编码长度 21 | self.unit_length = unit_length 22 | # 杂交几率 23 | self.cross_rate = cross_rate 24 | self.mutation_rate = mutation_rate 25 | self.pop = self.init_pop() 26 | 27 | # 初始化种群 28 | def init_pop(self): 29 | pop = [] 30 | for _ in range(self.pop_size): 31 | pop.append(np.random.randint(0,2,size = self.gene_size*self.unit_length)) 32 | return np.array(pop) 33 | 34 | # 将种群从[1,0,1....,1,0]编码转化成对应的数字 35 | def pop_translate(self): 36 | pop_translate = [] 37 | for i in range(self.pop_size): 38 | unit = [] 39 | # 读出一个个体基因中每一段对应的数字 40 | for j in range(self.gene_size): 41 | low,high = j*self.unit_length,(j+1)*self.unit_length 42 | after = self.binarytodecimal(self.pop[i,low:high]) 43 | unit.append(after) 44 | # 存入到转换后的种群中 45 | pop_translate.append(unit) 46 | return np.array(pop_translate,dtype = np.int8) 47 | 48 | # 该部分用于将字符对应的编码[1,0,1....,1,0]转换成对应的数字 49 | def binarytodecimal(self,binary): 50 | total = 0 51 | for j in range(len(binary)): 52 | total += binary[j] * (2**j) 53 | total = np.int8(total * 94 / 255 + 32) 54 | return total 55 | 56 | # 计算适应度 57 | def count_fitness(self): 58 | # 首先获取转换后的种群 59 | self.pop_t = self.pop_translate() 60 | # 将转换后的种群与目标字符串对应的ASCII码比较,计算出适应度 61 | fitness = (self.pop_t == TARGET_ASCII).sum(axis=1) 62 | return np.array(fitness) 63 | 64 | # 自然选择 65 | def selection(self): 66 | self.fit_value = self.count_fitness() 67 | [bestindividual, bestfit] = self.best() 68 | # 利用np.random.choice实现轮盘赌 69 | idx = np.random.choice(np.arange(self.pop_size), size=self.pop_size, replace=True, p=self.fit_value/self.fit_value.sum()) 70 | self.pop = self.pop[idx] 71 | return [bestindividual, bestfit] 72 | 73 | # 选出最大value对应的索引,取出个体与对应的适应度 74 | def best(self): 75 | index = np.argmax(self.fit_value) 76 | bestfit = self.fit_value[index] 77 | print(self.pop[index]) 78 | bestindividual = self.pop_t[index].tostring().decode('ascii') 79 | return [bestindividual, bestfit] 80 | 81 | # 杂交 82 | def crossover(self): 83 | # 按照一定概率杂交 84 | for i in range(self.pop_size): 85 | # 判断是否达到杂交几率 86 | if (np.random.rand() < self.cross_rate): 87 | # 随机选取杂交点,然后交换结点的基因 88 | individual_size = self.gene_size*self.unit_length 89 | # 随机选择另一个个体进行杂交 90 | destination = np.random.randint(0,self.pop_size) 91 | # 生成每个基因进行交换的结点 92 | crosspoint = np.random.randint(0,2,size = individual_size).astype(np.bool) 93 | # 进行赋值 94 | self.pop[i,crosspoint] = self.pop[destination,crosspoint] 95 | 96 | # 基因突变 97 | def mutation(self): 98 | # 判断每一条染色体是否需要突变 99 | for i in range(self.pop_size): 100 | for j in range(self.gene_size): 101 | if (np.random.rand() < self.mutation_rate): 102 | low,high = j*self.unit_length,(j+1)*self.unit_length 103 | self.pop[i,low:high] = np.random.randint(0,2,size=self.unit_length) 104 | 105 | def evolve(self): 106 | [bestindividual, bestfit] =self.selection() 107 | self.mutation() 108 | self.crossover() 109 | return [bestindividual, bestfit] 110 | 111 | # 初始化类 112 | test1 = GA(gene_size = GENE_SIZE,unit_length = 8,cross_rate = CROSS_RATE, 113 | mutation_rate = MUTATION_RATE,pop_size = POP_SIZE) 114 | 115 | results = [] 116 | 117 | for i in range(N_GENERATIONS): 118 | [bestindividual, bestfit] = test1.evolve() 119 | results.append([bestfit,bestindividual]) 120 | print("century:",i,"get:",bestindividual) 121 | if(bestindividual == TARGET_PHRASE): 122 | break 123 | results.sort() 124 | print(results[-1]) #打印使得函数取得最大的个体,和其对应的适应度 125 | --------------------------------------------------------------------------------