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为最大值

目标函数

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

自定义函数可以直接替换即可这里目标函数为
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

产生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
  • 由于编码使用的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
  • 对于函数求最值过程中,以求最小值为例,肯定是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
  • 挑选过程将解码与适应度函数连接了起来,先解码后通过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:])

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

运行样例

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

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

整体源码

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
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
QA-GNN方法的实现主要包括以下步骤: 1. 数据预处理:首先,将问答数据集和知识图谱数据进行预处理,将它们转换为图结构的表示形式。问题和答案可以表示为节点,知识图谱中的实体和关系可以表示为边。 2. 图构建:根据预处理的数据,构建问题-答案图和知识图谱。问题-答案图中的节点表示问题和答案,边表示它们之间的关系。知识图谱中的节点表示实体,边表示实体之间的关系。 3. 特征提取:对于每个节点(问题、答案和知识图谱中的实体),使用语言模型对其进行编码,得到节点的语义特征表示。这可以通过预训练的语言模型(如BERT)来实现。 4. 图神经网络:利用图神经网络对问题-答案图和知识图谱进行推理和表示学习。图神经网络可以通过消息传递机制来传递节点之间的信息,并通过图卷积等操作来更新节点的表示。 5. 答案生成:根据经过图神经网络处理后的节点表示,使用适当的方法生成最终的答案。这可以是基于分类、生成模型或其他技术。 6. 训练和评估:使用已标注的问答数据进行训练,并使用评估指标(如准确率、召回率等)评估模型的性能。 需要注意的是,具体实现中可能还涉及一些细节和技巧,如图神经网络的具体结构、节点特征的融合方式、损失函数的设计等。这些可以根据具体情况进行调整和改进。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值