深度学习——遗传算法和粒子群算法

本文介绍了遗传算法的基本原理,包括其模仿生物进化的过程,通过交叉和变异操作优化问题解。同时,详细阐述了粒子群算法,强调了群体协作和随机优化在寻找最优解中的作用。两者都是非线性优化的重要工具,被广泛应用于解决复杂问题。
摘要由CSDN通过智能技术生成

遗传算法

原理

遗传算法是一种仿生优化算法,其灵感源于生物进化和基因传的机制。通过模拟生物进化过程中的交叉、变异等操作,逐步优化一个问题的解,以实现最优解的搜索。在遗传算法中,每个解被编码成一个个体,交叉相当于两个个体基因交换,变则是在个体基础上进行随机修改。遗传算法的主要优点是可以处理多变量、多峰和非线性等问题,同时搜索范围较大。

简单来说,遗传算法是模拟自然选择和遗传机制的寻优方法。通过基因杂交,变异可能产生适应性强的后代,通过优胜劣汰的自然选择,适应能力强的基因结构就保存下来。一句话概括就是:优胜劣汰,胜者生存。

基本步骤:

1.初始化群:在优化问题的可行解空间中随机生成一个初始种群。
2.评价个体适应度:对于每个个体,计算其适应度,即问题目标函数的值。
3.选择操作:利用轮盘赌算法或其他选择策略,从当前种群中选择潜在优秀的个体,生成下一代种群。
4.基因操作:包括交叉和变异,对已选个体,在一定概率范围内进行基因的交叉、变异,并生成新的个体。
5.·替换操作:新生个体代替部分原来的个体,生成新的种群。
6.结束判断:根据预设的终止条件,判断是否满足结束条件,收敛或超过限制则结束,否则重复执行上述步骤。

代码示例

import numpy as np

a=-np.pi   #变量下界
b=np.pi    #变量上界
NP=100     #种群大小
NG=1000    #迭代次数
Pc=0.9     #交叉概率
Pm=0.1     #变异概率
eps=0.1    #离散精度,用于确定二进制码所需码长


def initial(length):             # 生成二进制编码的初始种群,大小为(length, )
    res=np.zeros(length)
    for ii in range(length):
        r = np.random.rand()
        res[ii]=np.round(r)
    return res


def fitness(x):                  # 计算函数的适应值
    return np.sin(x)


def dec(a,b,x,L):                # 将二进制编码的数值转换为实际数值
    L2 = list(range(L-1,-1,-1))
    Ji = []
    for m in range(len(L2)):
         Ji.append(x[m]*pow(2,L2[m]))
    y1 = sum(Ji)
    y = a + y1 * (b-a)/(pow(2,L)-1)
    return y


L=int( np.ceil(np.log2((b - a)/eps+1)))  # 根据离散精度,确定二进制编码需要的码长
x = np.zeros((NP,int(L)))                # 当前种群的二进制编码矩阵
fx= np.zeros(NP)                         # 每个个体的适应值
nx = np.zeros((NP,int(L)))               # 存储产生的新种群的矩阵,大小和x相同
PPx=np.zeros(NP,)                        # 种群的选择概率,与种群中个体的适应度成正比
rr2 = np.zeros(NP, )                     # 存储产的随机数的数组,用于调试和测试

for i0 in range(NP):
    x[i0,:]= initial(L)                  # 种群初始化
    fx[i0] = fitness(dec(a,b,x[i0,:],L)) # 个体适应值
nx =x
for k in range(NG):                      # 遗传迭代主循环
    sumfx = sum(fx) # 计算所有个体的适应值之和
    Px= fx/sumfx    # 计算每个个体的选择概率
    PPx[0]=Px[0]    # 计算选择概率的累加和于轮盘赌算法
    for i2 in range(1,NP):
        PPx[i2] = PPx[i2-1]+Px[i2]

    for i in range(NP): # 对于每个种群个体,进行选择、交叉和变异操作
        sita = np.random.rand() # 随机生成一个选择概率,根据轮盘赌算法获取一个父代个体
        for n in range(NP):
            if sita <= PPx[n]:
                SelFather=n         # 选择的父代个体的索引,根据轮盘赌算法随机抽取
                break

        Selmother = int((np.random.rand() * (NP - 1)))#选择的母代个体的索引,随机选择一个体
        posCut = int((np.random.rand() * (L - 1)))#交叉点位置,随机选择两个个体进行交叉操作
        r1 = np.random.rand() # 随机生成交叉和变异的随机数,存储到rr2中
        rr2[i]=r1
        if r1<=Pc: # 判断是否进行交叉操作
            nx[i,1:posCut] = x[SelFather,1:posCut]
            nx[i,(posCut+1):L] = x[Selmother,(posCut+1):L]
        else:
            nx[i, :] = x[SelFather, :] #进行交叉操作否则不进行交叉操作直接将父代个体的基因复制到下一代个体

            r2 = np.random.rand()
            if r2 <= Pm: # 在一定概率下进行变异操作
                posMut = round(np.random.rand()*(L-1))# 变异点位置随机选择一个体进行变异操作
                if nx[i,posMut]==1.0:
                    nx[i,posMut]=0.0
                else:
                    nx[i, posMut] = 1.0

    x = nx
    for j in range(NP):
        fx[j] = fitness(dec(a,b,x[j,:],L))


fv =float('-inf')
for i3 in range(NP):
    fitx = fitness(dec(a, b, x[i3,:], L))
    if fitx > fv:
        fv = fitx                  
        xv = dec(a, b, x[i3,:], L)

print(xv) #最优解和最优函数值
print(fv)

粒子群算法

概述

粒子群算法(Particle Swarm Optimization,简称PSO)是1995年Eberhart博士和Kennedy博士一起提出的一种基于群体协作的搜索算法,它通过模拟鸟群捕食行为来寻找最优解。

在粒子群算法中,每个优化问题的解都被视为搜索空间中的一个粒子。每个粒子都保存有自己的历史最优位置和全局最优位置,通过在搜索空间中追踪这些最优位置,粒子们可以找到最优解。

在算法的每一轮迭代中,每个粒子都会向全局最优位置和自身历史最优位置进行一定的“飞行动”,这个飞行由两部分组成:一部分是粒子对全局最优位置的追踪,另一部分是粒子对自身历史最优位置的追踪。

粒子群算法的特点是在于其群体协作性质。当一个粒子找到一个好的解时,它会通过“飞行动”将这个信息传递给其他粒子,帮助整个群体找到最优解。因此,粒子群算法是一种基于种群的随机优化技术,它具有快速、简单、全局搜索能力强的优点。同时,它也适用于解决复杂和非线性问题,被广泛应用于各种优化问题中。

一般步骤

1.初始化粒子群(速度和位置)、惯性因子、加速常数、最大迭代次数和算法终止的最小允许误差。
2.计算每个粒子的初始适应值。
3.找出个体和群体最优值和对应的位置。
4.根据公式更新每个粒子的速度和位置。
5.比较当前各粒子的适应值是否比历史局部最优值好,如果好,就更新粒子的局部最优值和对应位置。
6.找出当前粒子群众的全局最优值和对应的位置。
7.重复步骤4~6,直到满足设定的最小误差或达到最大迭代次数。
8.输出粒子群全局最优值和对应位置,以及各粒子的局部最优值和对应位置。

代码示例

import numpy as np
import random
import matplotlib.pyplot as plt

class PSO():

    def __init__(self, pN, dim, max_iter):
        self.w = 0.8       #衰减因子,用于减小粒子群的速度,防止超出搜索空间
        self.c1 = 2        #c1, c2: 加速常数,控制速度的改变,用于调整粒子的方向
        self.c2 = 2        #随子,用于随机调整粒子的方向
        self.r1 = 0.6
        self.r2 = 0.3
        self.pN = pN       #粒子群大小
        self.dim = dim     #解向量维度
        self.max_iter = max_iter #最大迭代数 
        self.X = np.zeros((self.pN, self.dim))       #粒子的位置向量。
        self.V = np.zeros((self.pN, self.dim))       #粒子的速度向量
        self.pbest = np.zeros((self.pN, self.dim))   #粒子历史上最好的位置向量,即粒子在过去 
                                                                          经历过最优的位置
        self.gbest = np.zeros((1, self.dim))         #群体最好的位置向量,即所有粒子历史上最 
                                                                              优的位置向量
        self.p_fit = np.zeros(self.pN)               #每个粒子的历史最优适应度
        self.fit = 1e10                              #群体历史最优适应度


    def function(self, X):
        return X ** 4 - 2 * X + 3


    def init_Population(self):     #用于初始化粒子群,并找到群体中历史最优粒子
        for i in range(self.pN):  
            for j in range(self.dim): 
                self.X[i][j] = random.uniform(0, 1)
                self.V[i][j] = random.uniform(0, 1)
            self.pbest[i] = self.X[i]  
            tmp = self.function(self.X[i]) 
            self.p_fit[i] = tmp
               if tmp < self.fit: 
                self.fit = tmp
                self.gbest = self.X[i]

    def iterator(self):          #每次迭代更新每个粒子的速度,并重新更新位置向量
        fitness = []
        for t in range(self.max_iter):  
            for i in range(self.pN): 
                temp = self.function(self.X[i])
                if temp < self.p_fit[i]:  
                    self.p_fit[i] = temp
                    self.pbest[i] = self.X[i]
                    if self.p_fit[i] < self.fit: 
                        self.gbest = self.X[i]
                        self.fit = self.p_fit[i]
            for i in range(self.pN):
                self.V[i] = self.w * self.V[i] + self.c1 * self.r1 * (self.pbest[i] - self.X[i]) + \
                            self.c2 * self.r2 * (self.gbest - self.X[i])
                self.X[i] = self.X[i] + self.V[i]
            fitness.append(self.fit)
            print(self.X[0], end=" ")
            print(self.fit)  
        return fitness

my_pso = PSO(pN=30, dim=1, max_iter=100)
my_pso.init_Population()
fitness = my_pso.iterator()

本框架提供了有关粒子群算法(PSO)和遗传算法(GA)的完整实现,以及一套关于改进、应用、测试、结果输出的完整框架。 本框架对粒子群算法遗传算法进行逻辑解耦,对其中的改进点予以封装,进行模块化,使用者可以采取自己对该模块的改进替换默认实现组成新的改进算法与已有算法进行对比试验。试验结果基于Excel文件输出,并可通过设定不同的迭代结束方式选择试验数据的输出方式,包括: 1. 输出随迭代次数变化的平均达优率数据(设定终止条件区间大于0)。 2. 输出随迭代次数变化的平均最优值数据(设定终止条件区间等于0)。 本框架了包含了常用基准函数的实现以及遗传算法粒子群算法对其的求解方案实现和对比,如TSP,01背包,Banana函数,Griewank函数等。并提供大量工具方法,如KMeans,随机序列生成与无效序列修补方法等等。 对遗传算法的二进制编码,整数编码,实数编码,整数序列编码(用于求解TSP等),粒子群算法的各种拓扑结构,以及两种算法的参数各种更新方式均有实现,并提供接口供使用者实现新的改进方式并整合入框架进行试验。 其中还包括对PSO进行离散化的支持接口,和自己的设计一种离散PSO方法及其用以求解01背包问题的实现样例。 欢迎参考并提出宝贵意见,特别欢迎愿意协同更新修补代码的朋友(邮箱starffly@foxmail.com)。 代码已作为lakeast项目托管在Google Code: http://code.google.com/p/lakeast http://code.google.com/p/lakeast/downloads/list 某些类的功能说明: org.lakest.common中: BoundaryType定义了一个枚举,表示变量超出约束范围时为恢复到约束范围所采用的处理方式,分别是NONE(不处理),WRAP(加减若干整数个区间长度),BOUNCE(超出部分向区间内部折叠),STICK(取超出方向的最大限定值)。 Constraint定义了一个代表变量约束范围的类。 Functions定义了一系列基准函数的具体实现以供其他类统一调用。 InitializeException定义了一个代表程序初始化出现错误的异常类。 Randoms类的各个静态方法用以产生各种类型的随机数以及随机序列的快速产生。 Range类的实现了用以判断变量是否超出约束范围以及将超出约束范围的变量根据一定原则修补到约束范围的方法。 ToStringBuffer是一个将数组转换为其字符串表示的类。 org.lakeast.ga.skeleton中: AbstractChromosome定义了染色体的公共方法。 AbstractDomain是定义问题域有关的计算与参数的抽象类。 AbstractFactorGenerator定义产生交叉概率和变异概率的共同方法。 BinaryChromosome是采用二进制编码的染色体的具体实现类。 ConstantFactorGenerator是一个把交叉概率和变异概率定义为常量的参数产生器。 ConstraintSet用于在计算过程中保存和获取应用问题的各个维度的约束。 Domain是遗传算法求解中所有问题域必须实现的接口。 EncodingType是一个表明染色体编码类型的枚举,包括BINARY(二进制),REAL(实数),INTEGER(整型)。 Factor是交叉概率和变异概率的封装。 IFactorGenerator参数产生器的公共接口。 Population定义了染色体种群的行为,包括种群的迭代,轮盘赌选择和交叉以及最优个体的保存。 org.lakeast.ga.chromosome中: BinaryChromosome二进制编码染色体实现。 IntegerChromosome整数编码染色体实现。 RealChromosome实数编码染色体实现。 SequenceIntegerChromosome整数序列染色体实现。 org.lakeast.pso.skeleton中: AbstractDomain提供一个接口,将粒子的位置向量解释到离散空间,同时不干扰粒子的更新方式。 AbstractFactorGenerator是PSO中参数产生器的公共抽象类。 AbstractParticle定义了PSO种群中粒子的基本行为,最主要是实现了如何根据现有位置计算得到下一代粒子的位置的合法值。 ConstraintSet用于在粒子迭代过程中保存和获取应用问题的各个维度的约束。 AbstractSwarm.java各种拓扑结构的PSO种群的抽象父类,主要实现了种群迭代过程中计算流程的定义以及中间数据被如何输出到测试工具类。 Domain是PSO算法求解中所有问题域必须实现的接口。 DynamicFatorGenerator若种群在迭代过程中,w,c1,c2随迭代次数发生变化,那么它们的产生器需要继承这个抽象类。 Factor封装了w,c1,c2三个参数的字面值。 Location用于保存和获取迭代中粒子的位置和速度向量的数值。 NeighborhoodBestParticle定义了采用邻域版本的PSO算法的具体实现。主要是实现了如何根据邻域版本的PSO算法计算下一迭代中的粒子速度。 RingTopoSwarm定义环拓扑结构的具体实现,主要是定义了如何获取粒子的邻域粒子的方法。 StaticTopoSwarm静态拓扑结构的PSO算法的抽象父类。 org.lakeast.pso.swarm中包含粒子群拓扑结构的各种实现,基本见名知意。 对各种问题的求解样例位于org.lakeast.main包中,以...TaskTest结尾,基本见名知意。 以ShafferF6DomainTaskTes对ShafferF6函数进行求解(采用的是PSO,遗传算法样例参见TSPValueTaskTest)为例说明求解过程如下: 1. 入口函数位于org.lakeast.main.ShafferF6DomainTaskTest中,go函数执行。 2. 在go函数中,首先指定迭代次数(numberOfIterations),测试多少轮(testCount,多次运行以得到平均达优值),种群大小(popSize),邻域大小(neighborhoodSize),迭代结束条件(exitCondition,由于制定了迭代次数,所以设定为[0,0],也就是只有达到指定迭代次数才退出)。 3. 以testCount,numberOfIterations以及迭代结束条件exitCondition为参数构建TestBatch类的实例batch。这个类用来进行管理参与测试的各种具体算法,且把数据结果按指定的格式输出为Excel文件。 4. 指定PSO中的因子产生方法,采用ExponentFactorGenerator和ConstrictFactorGenerator两种方式(实现位于org.lakeast.pso.gen包)。 5. Y表示参与测试的算法数目。 6. Testable是所有可以被TestBatch测试的类需要实现的接口,以提供TestBatch生成结果Excel文件所需要的数据。 7. Domain接口是所有可以被算法解决的问题所需要实现的接口,比如说明该问题所需要的粒子位置约束范围,速度约束范围,以及适值评估的公司等。这里的Domain被实例化为ShafferF6Domain,也就是按照ShafferF6函数评估适值。 8. RingTopoSwarm是用来封装环拓扑邻域结构的类,NeighboordBestParticle是配合该类来实现按邻域最优更新速度而不是全局最优来更新。 9. 各个测试算法都被加入到TestBatch以后,batch.run()开始执行算法比较过程并输出结果Excel文件到C盘根目录(输出路径可在Testable接口中配置,除了生成Excel文件外,还可以通过修改log4j.properties在制定的位置产生运行结果日志)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值