【优化算法】Python实现面向对象的遗传算法

遗传算法

遗传算法(Genetic Algorithm)属于智能优化算法的一种,本质上是模拟自然界中种群的演化来寻求问题的最优解。与之相似的还有模拟退火、粒子群、蚁群等算法。

在具体介绍遗传算法之前,我们先来了解一些知识🧀

DNA: 携带有合成RNA和蛋白质所必需的遗传信息的生物大分子,是生物体发育和正常运作必不可少的生物大分子。一般情况下,是以双螺旋结构存在。

现实中的DNA由碱基、脱氧核糖和磷酸双分子层组成,两条脱氧核苷酸链通过碱基间的氢键形成的碱基对相连,形成稳定的结构。碱基由四种,腺嘌呤,鸟嘌呤,胸腺嘧啶,胞嘧啶。

那么如何在计算机中对DNA进行编码?也不需要想的过于复杂,我们只需要表达每个位置上的碱基就行啦!譬如,一条DNA链可以写作:012332100123;每个数字对应一个碱基的映射。为了提高运行速度,我们将其以二进制的形式进行简化表达,即一条DNA链可以看做一串二进制文本:01011101010

个体与种群

我们将每条DNA链看做一个个体,实际上,也就是问题的一个解。譬如,我们寻找映射 F ( X , Y ) F(X,Y) F(X,Y)的最优解,其中一个可能的值 X = 6 X=6 X=6,便是一个个体。

种群就是个体的集合。注意,同一种群内部发生信息交换,不同种群之间不会发生信息交换。例如, X X X的全集不会与 Y Y Y的全集发生交换,DNA交换只会发生在 X X X集合或 Y Y Y集合内部。

遗传: 生物的DNA来自于父母,一般情况下由父亲提供X或Y染色体,母亲提供X染色体

假设现在有两个个体:

1001 0001 1001\ 0001 1001 0001 00011001 0001 1001 00011001 分别作为父亲和母亲,生下了一个新的个体,那么该个体的DNA将由父亲和母亲来决定,例如前四位由父亲提供,后四位由母亲提供,那么该子代个体就是:

1001 1001 1001\ 1001 1001 1001

变异: 在DNA的某个位置发生了变化

因为是二进制表达的DNA,那么所谓的变化就是某一位由0到1,或是由1到0

自然选择: 优胜劣汰,将会选择更加适宜的个体

个体的适宜度,实际上也就是满足函数最优解的值。适宜度越高,该个体在下一轮的自然选择中越容易存活,从而保留自身的DNA。


下面我们将来说一下如何实现一个GA算法~

一、创建属于我们的种群

在一切的开始,我们为种群制定一个规则,比方说这个种群的大小,DNA链的长度~

Population_Nums=200 # 种群有200个个体
DNA_Size=16 # DNA链的长度
Range=[[-3,3],[-3,3]] # 自变量的值域范围# 初始化
import numpy as np 
# pop维度为(n,Population_Nums,DNA_Size)
# 其中n表示有几个种群,也就是自变量
pop=np.random.randint(0,2,size=(len(Range),Population_Nums,DNA_Size))

种群的数量呢决定了收敛的速度,但是也有可能因此陷入局部最优解,并降低运行速度(注意跟收敛速度的区别)

DNA链的长度实际上决定了精度。这句话如何理解呢?我们要来看如何将一串DNA转译成我们需要的信息~

假设有一串DNA链: 10101 10101 10101,我们的映射函数为 F ( X , Y ) F(X,Y) F(X,Y),其中 X X X的值域为 [ − 5 , 5 ] [-5,5] [5,5],想一想如何进行转译呢?

为了方便计算和模拟遗传变异,我们采用了二进制作为个体DNA。而我们想要的结果是十进制,那就需要先将二进制转为十进制! 1 ∗ 2 4 + 0 ∗ 2 3 + 1 ∗ 2 2 + 0 ∗ 2 1 + 1 ∗ 2 0 = 21 1*2^{4}+0*2^3+1*2^2+0*2^1+1*2^0=21 124+023+122+021+120=21,这样就来到了十进制。对于种群的基因,只需要除以一个最大值,即 11111 11111 11111,或者说 2 n 2^n 2n,就可以压缩到区间 [ 0 , 1 ] [0,1] [0,1],然后再通过区间匹配到实际值域区间中。

这段写成代码的话,可以是这样:

def decoding(pop):deList=[]for idx,i in enumerate(pop):deList.append(i.dot(2**np.arange(DNA_Size))/float(2**DNA_Size)*(Range[idx][1]-Range[idx][0])+Range[idx][0])return deList

好啦,那么现在我们就需要评估一个个体的适宜度,这也是自然选择中最重要的部分。适宜度越大的个体,越容易在下一轮的选择中存活。

假设函数为:

def F(x,y):return 3*(1-x)**2*np.exp(-(x**2)-(y+1)**2)-10*(x/5-x**3-y**5)*np.exp(-x**2-y**2)-1/3**np.exp(-(x+1)**2-y**2)

假设优化目标是求这个函数的极大值,那么我们的适宜度就应该是个体DNA转为十进制编码后,带入函数的结果,这个结果越大,说明适宜度越高。

def fitnetss(pop):deList=decoding(pop)pred=F(*deList)return (pred-pred.min())+1e-3

后面这个1e-3的实际含义是,让每一个个体都有机会,而不是绝对肯定或绝对否定哪个个体。


二、遗传和变异

在遗传部分,我们设置了一个参数,用来控制遗传发生的比例。毕竟有些个体并没有后代~

在变异部分,我们同样也有一个较小的参数,用来控制变异发生的可能性。

def mutation(pop,rate=1e-3):# 变异将随机发生for i in pop:if np.random.rand()<rate:# 随机一个个体发生变异i[np.random.randint(0,DNA_Size)]^=1

变异的作用是跳出局部最优解,下面是进行变异的三次结果:

(x,y):  -0.03668099860435703 1.499994903802568
(x,y):  -0.013274610833800438 1.6933678801875045
(x,y):  0.05119961805341333 1.4999723732455

而下面是不进行变异的三次结果:

(x,y):  -0.027307929236169315 1.5981612562037268
(x,y):  0.18948037561657305 1.4062327388663727
(x,y):  -0.0962074456338553 1.4998157322296937

可以发现,发生了变异后,结果稳定在[0,1.5],而不是陷入部分最优解。

遗传过程的算法可以描述如下:

  • 遍历种群中的每个个体,并将该个体A作为父母个体
  • 有一定概率该个体可以随机跟种群中的其他个体B发生基因交换(甚至包括它自己,但这对结果并没有影响,只是降低了遗传概率)
  • 发生基因交换时,随机选择DNA的断点,断点前半部分由个体A提供,后半段由个体B提供
def crossover(pop,rate=0.7):# 注意这里只与自身种群发生变化new_pop=[]for idx in pop.shape[0]:children=[]for father in pop[idx]:if np.random.rand()<rate:child=fathermother=pop[idx][np.random.randn(0,Population_Nums)]# 随机选择发生互换的碱基对choicePoint=np.random.randn(0,DNA_Size)child[choicePoint:]=mother[choicePoint:]# 发生变异children.append(mutation(child))return chidren

三、自然选择

这部分将会根据个体的适宜度分配权值,决定该个体基因出现在下一轮概率。

def select(pop,fitness):pop_s=[]for i in pop:pop_s.append(i[np.random.choice(np.array(Population_Nums),size=Population_Nums,replace=True,p=(fitness)/(fitness.sum()))])return pop_s

四、基于面向对象的遗传算法

现在,我们就要将这些东西封装成一个类啦,提高复用性和稳定性。

首先是构造函数,就是先写入一些常量。

class GA(object):def __init__(self,popN=2000,DNA_Size=16,Epochs=500,crossRate=0.8,mutationRate=0.005):self.popN=popN # 种群数量self.DNA_Size=DNA_Size # DNA长度self.Epochs=Epochs # 迭代次数self.crossRate=crossRate # 交叉遗传概率self.mutationRate=mutationRate  # 变异概率self.Range=None # 输入数据的值域# 例如:[[-3,3],[2,5],[1,9]] 这表示第一个变量的值域是[-3,3],第二个是[2,5]self.plot_=[] # 保留每轮的最优值self.bestScore=None # 最佳得分self.best=None # 最佳个体

然后,需要提供一个输入函数的接口:

   def fit_function(self,f,range):self.f=fself.Range=range# 初始化种群self.pop=np.random.randint(0,2,size=(len(range),self.popN,self.DNA_Size))self.plot_=[]

解码方法:

   def decoding(self):deList = []for idx, i in enumerate(self.pop):deList.append(i.dot(2 ** np.arange(self.DNA_Size)) / float(2 ** self.DNA_Size) * (self.Range[idx][1] - self.Range[idx][0]) + self.Range[idx][0])return deList

适应值:

    def fitness(self):deList=self.decoding()pred=self.f(*deList)return (pred-pred.min())+1e-3

变异:

    def mutation(self,pop):if np.random.rand()<self.mutationRate:pop[np.random.randint(0,self.DNA_Size)]^=1return pop

交叉遗传:

    def crossover(self):for idx in range(self.pop.shape[0]):for _,father in enumerate(self.pop[idx]):child = fatherif np.random.rand()<self.crossRate:mother=self.pop[idx][np.random.randint(0,self.popN)]crossPoint=np.random.randint(0,self.DNA_Size)child[crossPoint:]=mother[crossPoint:]self.pop[idx][_]=self.mutation(child)

自然选择:

    def select(self,fitness):pops=[]for i in self.pop:pops.append(i[np.random.choice(self.popN,size=self.popN,replace=True,p=fitness/(fitness.sum()))])return pops

打印信息:

    def getInfo(self):print('最优参数为: ',[i for i in self.best])print("最优结果为: ",self.bestScore)

提供一个训练接口和绘图接口供使用者调用:

    def train(self,plot=False):for _ in range(self.Epochs):self.crossover() # 交叉变异f=self.fitness() # 计算适宜度max_fit = np.argmax(f) # 获取最大适宜度下标k=[(i[max_fit].dot(2**np.arange(self.DNA_Size))/float(2**self.DNA_Size))*(self.Range[idx][1]-self.Range[idx][0])+self.Range[idx][0] for idx,i in enumerate(self.pop)] # 获取最佳个体的十进制值bs=self.f(*k) # 计算该值的适宜度# 请注意,适宜度并不代表函数结果,适宜度是一个相对的值# 记录全局最优结果if self.bestScore==None or bs>self.bestScore:self.bestScore=bsself.best=kself.pop = np.array(self.select(f)) # 自然选择if plot:self.plot_.append(bs)self.getInfo()def plot(self):if self.plot_==[]:passplt.plot([i for i in range(self.Epochs)],self.plot_)plt.xlabel("Epochs")plt.ylabel("BestValue")plt.show()

最终的结果如下:

在这里插入图片描述

可以看到在25个Epoch左右就开始收敛了。


完整代码

import numpy as np
import matplotlib.pyplot as pltclass GA(object):def __init__(self,popN=2000,DNA_Size=16,Epochs=500,crossRate=0.8,mutationRate=0.005):self.popN=popNself.DNA_Size=DNA_Sizeself.Epochs=Epochsself.crossRate=crossRateself.mutationRate=mutationRateself.Range=Noneself.plot_=[]self.bestScore=Noneself.best=Nonedef fit_function(self,f,range):self.f=fself.Range=rangeself.pop=np.random.randint(0,2,size=(len(range),self.popN,self.DNA_Size))self.plot_=[]def decoding(self):deList = []for idx, i in enumerate(self.pop):deList.append(i.dot(2 ** np.arange(self.DNA_Size)) / float(2 ** self.DNA_Size) * (self.Range[idx][1] - self.Range[idx][0]) + self.Range[idx][0])return deListdef fitness(self):deList=self.decoding()pred=self.f(*deList)return (pred-pred.min())+1e-3def mutation(self,pop):if np.random.rand()<self.mutationRate:pop[np.random.randint(0,self.DNA_Size)]^=1return popdef crossover(self):for idx in range(self.pop.shape[0]):for _,father in enumerate(self.pop[idx]):child = fatherif np.random.rand()<self.crossRate:mother=self.pop[idx][np.random.randint(0,self.popN)]crossPoint=np.random.randint(0,self.DNA_Size)child[crossPoint:]=mother[crossPoint:]self.pop[idx][_]=self.mutation(child)def select(self,fitness):pops=[]for i in self.pop:pops.append(i[np.random.choice(self.popN,size=self.popN,replace=True,p=fitness/(fitness.sum()))])return popsdef getInfo(self):print('最优参数为: ',[i for i in self.best])print("最优结果为: ",self.bestScore)def train(self,plot=False):for _ in range(self.Epochs):self.crossover()f=self.fitness()max_fit = np.argmax(f)k=[(i[max_fit].dot(2**np.arange(self.DNA_Size))/float(2**self.DNA_Size))*(self.Range[idx][1]-self.Range[idx][0])+self.Range[idx][0] for idx,i in enumerate(self.pop)]bs=self.f(*k)if self.bestScore==None or bs>self.bestScore:self.bestScore=bsself.best=kself.pop = np.array(self.select(f))if plot:self.plot_.append(bs)self.getInfo()return self.bestdef plot(self):if self.plot_==[]:passplt.plot([i for i in range(self.Epochs)],self.plot_)plt.xlabel("Epochs")plt.ylabel("BestValue")plt.show()if __name__ == '__main__':ga=GA(popN=200,DNA_Size=16,Epochs=200)def F(x, y):return 3 * (1 - x) ** 2 * np.exp(-(x ** 2) - (y + 1) ** 2) - 10 * (x / 5 - x ** 3 - y ** 5) * np.exp(-x ** 2 - y ** 2) - 1 / 3 ** np.exp(-(x + 1) ** 2 - y ** 2)Range = [[-3, 3], [-3, 3]]ga.fit_function(F,Range)ga.train(True)ga.plot()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/57387.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[FPGA IP系列] BRAM IP参数配置与使用示例

FPGA开发中使用频率非常高的两个IP就是FIFO和BRAM&#xff0c;上一篇文章中已经详细介绍了Vivado FIFO IP&#xff0c;今天我们来聊一聊BRAM IP。 本文将详细介绍Vivado中BRAM IP的配置方式和使用技巧。 一、BRAM IP核的配置 1、打开BRAM IP核 在Vivado的IP Catalog中找到B…

【腾讯云 TDSQL-C Serverless 产品测评】- 云原生时代的TDSQL-C MySQL数据库技术实践

一、活动介绍&#xff1a; “腾讯云 TDSQL-C 产品测评活动”是由腾讯云联合 CSDN 推出的针对数据库产品测评及产品体验活动&#xff0c;本次活动主要面向 TDSQL-C Serverless版本&#xff0c;初步的产品体验或针对TDSQL-C产品的自动弹性能力、自动启停能力、兼容性、安全、并发…

【uniapp】this有时为啥打印的是undefined?(箭头函数修改this)

&#x1f609;博主&#xff1a;初映CY的前说(前端领域) ,&#x1f4d2;本文核心&#xff1a;uniapp中this指向问题 前言&#xff1a;this大家知道是我们当前项目的实例&#xff0c;我们可以在这个this上面拿到我们原型上的全部数据。这个常用在我们在方法中调用其他方法使用。 …

STM32 无法烧录

1. 一直显示芯片没连接上&#xff0c;检查连线也没问题&#xff0c;换了个ST-Link 烧录器还是连不上&#xff0c;然后又拿这个烧录器去其它板子上试下&#xff0c;就可以连接上&#xff0c;说明我连线没问题&#xff0c;烧录器也没问题&#xff0c;驱动什么的更是没问题&#x…

LLM - Baichuan-13B 多卡加载与推理测试

目录 ​编辑 一.引言 二.模型加载 1.量化加载 ◆ 基础配置 ◆ 8_bit 加载 ◆ 4_bit 加载 2.多卡加载 ◆ API 加载 ◆ accelerate 加载 三.模型推理 1.显存查看 ◆ Nvidia 显卡监控 ◆ Python subprocess 调用 2.双卡推理 ◆ 双卡 divice 分配 ◆ 双卡推理 GPU…

网络直播源码UDP协议搭建:为平台注入一份力量

网络直播源码中的UDP协议的定义&#xff1a; UDP协议又名用户数据报协议&#xff0c;是一种轻量级、无连接的协议。在网络直播源码平台中&#xff0c;UDP协议有着高速传输与实时性的能力&#xff0c;尤其是在网络直播源码实时性要求较高的场景&#xff0c;UDP协议的应用有着重要…

【Flutter】Flutter 使用 flutter_timezone 获取当前操作系统的时区

【Flutter】Flutter 使用 flutter_timezone 获取当前操作系统的时区 文章目录 一、前言二、flutter_timezone 包的背景三、安装和基本使用四、深入理解时区五、实际业务中的用法六、完整示例七、总结 一、前言 大家好&#xff01;我是小雨青年&#xff0c;今天我想和大家分享一…

NeRFMeshing - 精确提取NeRF中的3D网格

准确的 3D 场景和对象重建对于机器人、摄影测量和 AR/VR 等各种应用至关重要。 NeRF 在合成新颖视图方面取得了成功&#xff0c;但在准确表示底层几何方面存在不足。 推荐&#xff1a;用 NSDT编辑器 快速搭建可编程3D场景 我们已经看到了最新的进展&#xff0c;例如 NVIDIA 的 …

软件工程(二十) 系统运行与软件维护

1、系统转换计划 1.1、遗留系统的演化策略 时至今日,你想去开发一个系统,想完全不涉及到已有的系统,基本是不可能的事情。但是对于已有系统我们有一个策略。 比如我们是淘汰掉已有系统,还是继承已有系统,或者集成已有系统,或者改造遗留的系统呢,都是不同的策略。 技术…

WPF基础入门-Class4-WPF绑定

WPF基础入门 Class4&#xff1a;WPF绑定 一、简单绑定数据 1、cs文件中设置需要绑定的数据&#xff1a; public partial class Class_4 : Window{public Class_4(){InitializeComponent();List<Color> test new List<Color>();test.Add(new Color() { Code &q…

Java并发编程第6讲——线程池(万字详解)

Java中的线程池是运用场景最多的并发框架&#xff0c;几乎所有需要异步或并发执行任务的程序都可以使用线程池&#xff0c;本篇文章就详细介绍一下。 一、什么是线程池 定义&#xff1a;线程池是一种用于管理和重用线程的技术&#xff08;池化技术&#xff09;&#xff0c;它主…

微服务中间件--分布式搜索ES

分布式搜索ES 11.分布式搜索 ESa.介绍ESb.IK分词器c.索引库操作 (类似于MYSQL的Table)d.查看、删除、修改 索引库e.文档操作 (类似MYSQL的数据)1) 添加文档2) 查看文档3) 删除文档4) 修改文档 f.RestClient操作索引库1) 创建索引库2) 删除索引库/判断索引库 g.RestClient操作文…

http协议与apache

http概念&#xff1a; 互联网&#xff1a;是网络的网络&#xff0c;是所有类型网络的母集 因特网&#xff1a;世界上最大的互联网网络。即因特网概念从属于互联网概念 万维网&#xff1a;万维网并非某种特殊的计算机网络&#xff0c;是一个大规模的、联机式的信息贮藏库&…

长胜证券:沪指探底回升涨0.47%,券商、酿酒板块拉升,传媒板块活跃

24日早盘&#xff0c;沪指盘中震动回落&#xff0c;接近午盘快速拉升走高&#xff1b;深成指、创业板指强势上扬&#xff1b;北向资金今天转向&#xff0c;早盘积极出场&#xff0c;半日净买入近30亿元。 到午间收盘&#xff0c;沪指涨0.47%报3092.88点&#xff0c;深成指涨1.1…

最新AI创作系统ChatGPT源码+详细图文部署教程/支持GPT-4/AI绘画/H5端/Prompt知识库/思维导图生成

一、AI系统 如何搭建部署AI创作ChatGPT系统呢&#xff1f;小编这里写一个详细图文教程吧&#xff01;SparkAi使用Nestjs和Vue3框架技术&#xff0c;持续集成AI能力到AIGC系统&#xff01; 1.1 程序核心功能 程序已支持ChatGPT3.5/GPT-4提问、AI绘画、Midjourney绘画&#xf…

Django(8)-静态资源引用CSS和图片

除了服务端生成的 HTML 以外&#xff0c;网络应用通常需要一些额外的文件——比如图片&#xff0c;脚本和样式表——来帮助渲染网络页面。在 Django 中&#xff0c;我们把这些文件统称为“静态文件”。 我们使用static文件来存放静态资源&#xff0c;django会在每个 INSTALLED…

LiveGBS伴侣

【1】LiveGBS 简介 LiveGBS是一套支持国标(GB28181)流媒体服务软件。 国标无插件;提供用户管理及Web可视化页面管理&#xff1b; 提供设备状态管理&#xff0c;可实时查看设备是否掉线等信息&#xff1b; 实时流媒体处理&#xff0c;PS&#xff08;TS&#xff09;转ES&…

GFPGAN 集成Flask 接口化改造

GFPGAN是一款腾讯开源的人脸高清修复模型&#xff0c;基于github上提供的demo&#xff0c;可以简单的集成Flask以实现功能接口化。 GFPGAN的安装&#xff0c;Flask的安装请参见其他文章。 如若使用POSTMAN进行测试&#xff0c;需使用POST方式&#xff0c;form-data的请求体&am…

5G 数字乡村数字农业农村大数据中心项目农业大数据建设方案PPT

导读&#xff1a;原文《5G 数字乡村数字农业农村大数据中心项目农业大数据建设方案PPT》&#xff08;获取来源见文尾&#xff09;&#xff0c;本文精选其中精华及架构部分&#xff0c;逻辑清晰、内容完整&#xff0c;为快速形成售前方案提供参考。以下是部分内容&#xff0c; 喜…

TCP协议的重点知识点

TCP协议的重点知识点 TCP(传输控制协议)是一种面向连接、可靠的数据传输协议,工作在传输层,提供可靠的字节流服务。它是互联网协议栈中最重要、最复杂的协议之一,也是面试中常被问到的知识点。本文将详细介绍TCP协议的各个重要概念。 TCP基本特性 TCP主要具有以下基本特性: …