当前位置:   article > 正文

QA函数寻优,遗传算法实现寻找函数极大值和极小值_非线性函数寻优 最大值函数

非线性函数寻优 最大值函数

先看这里!!!

只想要源码的可以直接到我的github上下载,文件为jupyter形式,相应的包下载上可以直接运行,代码中仍有不足的地方,欢迎指正,由于只是课程的作业,所以实现的比较简单,只可以二元函数运行,否则会报错,源码有自定义函数的案例,其他问题可以联系我。

本文不讲解原理,只给出代码和其逻辑。

代码用到的自带函数不懂得可以进行查阅,网上的信息非常全。

函数讲解

初始化,设置种群大小,染色体长度,函数范围等

def __init__(self,NP=100,L=20,G=10,Pc=0.8,Pm=0.1,Xs=7,Xx=0,Ys=7,Yx=0,is_max=False) -> None:
    self.NP = NP # 种群数目
    self.L = L # 染色体编码长度
    self.G = G # 最大进化代数
    self.Pc= Pc # 交叉概率
    self.Pm = Pm # 变异概率 
    self.Xs = Xs # x边界
    self.Xx = Xx
    self.Ys = Ys # y边界
    self.Yx = Yx
    self.is_max = is_max # 是否求最大值 True为最大值
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

目标函数

# 定义目标函数
def f(self,x,y):
    return x**2+y**2
  • 1
  • 2
  • 3

自定义函数可以直接替换即可这里目标函数为
f ( x , y ) = x 2 + y 2 f(x,y) = {x^2} + {y^2} f(x,y)=x2+y2

产生种群&编码

def generate_population(self):
    l = 2
    '''产生种群 已经编码好 0 1编码长度 L'''
    x = np.random.randint(2, size=(self.NP, self.L))
    y = np.random.randint(2, size=(self.NP, self.L))
    return x,y

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

产生NP数量的染色体长度为L编码为0 1的种群

解码函数


def decode(self,x,y):
    # 进行解码
    X = x.dot(2**np.arange(self.L)[::-1])/(2**self.L-1)*(self.Xs-self.Xx)+self.Xx
    Y = y.dot(2**np.arange(self.L)[::-1])/(2**self.L-1)*(self.Ys-self.Yx)+self.Yx
    return X,Y
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 由于编码使用的0 1编码,这里解码要把二进制转为十进制数
  • 具体过程就是先将整个染色体映射到0~1之间,再通过函数定义域放大
  • 映射过程可以自定义,这里采用的是2的i次幂/(2的染色体长度次幂-1)之后求和,i为染色体的下标
  • 至于为什么这样解码不再赘述,解码方式有很多,本文只是采用其中一种,只要知道染色体长度越长,越精确即可

适应度函数

def fitness(self,x,y):
    re = self.f(x,y)
    # 由于结果可能为负值 但是再下面的选择阶段不允许出现负值,需要进行处理
    # 0值相当于概率0,所以需要加个非常小的正数
    if self.is_max: # 选最大值
        re = re - np.min(re) + 1e-5
    else:
        re = np.max(re) - re + 1e-5
    return re
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 对于函数求最值过程中,以求最小值为例,肯定是f(x,y)的值越小越好,所以这里用目标函数为适应度函数
  • 但由于种群的需要选择,所以为了避免后续数值为0的出现,需要进行变换,加上一个很小的正数,防止概率为0
  • 逻辑分支的代码以if为例,当寻找最大值时,为了避免负值出现影响挑选,所以减去了最小值,避免0加上极小的正数,else同理

挑选操作

def select_population(self,x,y):
    x_ ,y_ =self.decode(x,y)
    result = self.fitness(x_,y_)
    # 挑选适应度高的个体 
    index = np.random.choice(np.arange(self.NP),replace=True,size=self.NP,p=result/result.sum())

    selected_x = x[index]
    selected_y = y[index]

    return selected_x,selected_y
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 挑选过程将解码与适应度函数连接了起来,先解码后通过f得到适应度,再通过numpy模拟轮盘赌法进行不放回挑选个体,最后返回挑选过的个体

交叉变异

def cross_mutation(self,x,y):
    father = []

    father.extend(x)
    father.extend(y)
    children = []
    for i in father:
        child = i
        # 交叉操作
        if np.random.rand() < self.Pc:
            
            # 产生随机交叉点
            point = np.random.randint(self.L)
            # 选取母节点
            # print(point)
            child[point:] = father[np.random.randint(self.NP)][point:]
        # 变异操作
        if np.random.rand() < self.Pm:
            point = np.random.randint(self.L)
            child[point]^=1 # 取反
        children.append(child)
    return np.array(children[:len(children)//2]),np.array(children[len(children)//2:])

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 先将x和y全取出便于交叉操作即为father列表
  • 交叉操作在迭代总个体过程中,自己作为父亲,随机抽一个作为母亲,采用单点交叉
  • 变异直接取反即可

种群进化

def population_iteration(self):
    self.process = []
    x,y = self.generate_population()

    for i in range(self.G):
        x,y = self.select_population(x,y)
        x,y = self.cross_mutation(x,y)
        
        a,b =self.decode(x,y)
        self.process.append(self.f(a,b).sum())

    self.x ,self.y= self.decode(x,y)
    self.plot_3d()
    self.plot_coss()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • process列表记录了种群总体的函数和,每次迭代可以看到是否朝向有利方向进化
  • 先生成种群,随后挑选,交叉变异。继续重复知道迭代完成
  • 注意,进化过程中,全部操作x,y均为染色体形式进行
  • 迭代完成后将最后一代种群赋值self.x ,self.y用于存储种群信息即标点
  • 最后两个调用函数画图不再赘婿,可以在整体代码查看

运行样例

temp = Ga(L=40,G=50)
temp.population_iteration()
  • 1
  • 2

在这里插入图片描述
在这里插入图片描述

整体源码

class Ga:
    def __init__(self,NP=100,L=20,G=10,Pc=0.8,Pm=0.1,Xs=7,Xx=0,Ys=7,Yx=0,is_max=False) -> None:
        self.NP = NP # 种群数目
        self.L = L # 染色体编码长度
        self.G = G # 最大进化代数
        self.Pc= Pc # 交叉概率
        self.Pm = Pm # 变异概率 
        self.Xs = Xs # x边界
        self.Xx = Xx
        self.Ys = Ys # y边界
        self.Yx = Yx
        self.choose = []
        self.is_max = is_max # 是否求最大值
    # 定义目标函数
    def f(self,x,y):
        return x**2+y**2

    # 解码函数
    def decode(self,x,y):
        # 进行解码
        X = x.dot(2**np.arange(self.L)[::-1])/(2**self.L-1)*(self.Xs-self.Xx)+self.Xx
        Y = y.dot(2**np.arange(self.L)[::-1])/(2**self.L-1)*(self.Ys-self.Yx)+self.Yx
        return X,Y
    def generate_population(self):
        l = 2
        '''产生种群 已经编码好 0 1编码长度 L'''
        x = np.random.randint(2, size=(self.NP, self.L))
        y = np.random.randint(2, size=(self.NP, self.L))
        # return np.array([np.random.randint(2, size=(NP, L)) for i in range(l)])
        return x,y
    def fitness(self,x,y):
        re = self.f(x,y)
        # 由于结果可能为负值 但是再下面的选择阶段不允许出现负值,需要进行处理
        # 0值相当于概率0,所以需要加个非常小的正数
        if self.is_max: # 选最大值
            re = re - np.min(re) + 1e-5
        else:
            re = np.max(re) - re + 1e-5

        return re
    def select_population(self,x,y):
        x_ ,y_ =self.decode(x,y)
        result = self.fitness(x_,y_)
        # 挑选适应度高的个体 
        index = np.random.choice(np.arange(self.NP),replace=True,size=self.NP,p=result/result.sum())

        selected_x = x[index]
        selected_y = y[index]
        self.choose.append(self.decode(selected_x,selected_y))
        return selected_x,selected_y
    def cross_mutation(self,x,y):
        father = []

        father.extend(x)
        father.extend(y)
        children = []
        for i in father:
            child = i
            # 交叉操作
            if np.random.rand() < self.Pc:
                
                # 产生随机交叉点
                point = np.random.randint(self.L)
                # 选取母节点
                # print(point)
                child[point:] = i[point:]
            # 变异操作
            if np.random.rand() < self.Pm:
                point = np.random.randint(self.L)
                child[point]^=1 # 取反
            children.append(child)
        return np.array(children[:len(children)//2]),np.array(children[len(children)//2:])

    def population_iteration(self):
        self.process = []
        x,y = self.generate_population()
        # x , y= decode(x,y)
        for i in range(self.G):
            pre_x,pre_y = x , y
            x,y = self.select_population(x,y)
            x,y = self.cross_mutation(x,y)
            
            a,b =self.decode(x,y)
            self.process.append(self.f(a,b).sum())

        self.x ,self.y= self.decode(x,y)
        self.plot_3d()
        self.plot_coss()
    def plot_3d(self):
        
        fig = plt.figure(figsize=(10,7))
        ax = Axes3D(fig)
        X = np.linspace(self.Xs,self.Xx,100)
        Y = np.linspace(self.Ys,self.Yx,100)
        X,Y = np.meshgrid(X, Y)
        Z = self.f(X, Y)
        ax.plot_surface(X,Y,Z,rstride=1, cstride=1, cmap='rainbow')
        # ax.set_zlim(-10,10)
        ax.set_xlabel('x')
        ax.set_ylabel('y')
        ax.set_zlabel('z')

        ax.scatter(self.x,self.y,self.f(self.x,self.y),c='black')
        plt.title("result")
        plt.show()
    def plot_coss(self):
        plt.plot(range(len(self.process)),self.process)
        plt.title("Total Population Values")
        plt.show()  

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/菜鸟追梦旅行/article/detail/661468
推荐阅读
相关标签
  

闽ICP备14008679号