• 遗传算法 初步认识(一)


    简介

    对什么蚁群算法啦,遗传算法啦...... 很感兴趣,遂学习一波
    遗传算法真的是一个美妙的东西,大自然最根本的力量就是进化,淘汰弱者,让强者生存。
    参考文章 核心链接 链接 https://www.zhihu.com/search?q=遗传算法&utm_content=search_history&type=content
    参考文章附带的代码 https://github.com/yanshengjia/artificial-intelligence/blob/master/genetic-algorithm-for-functional-maximum-problem/matlab-ga

    开始个人理解

    首先 个人用python 重写了 matlab

    目标函数

    求解函数 f(x) = x + 10*sin(5*x) + 7*cos(4*x) 在区间[0,9]的最大值

    先来看看 目标函数的的校验吧 看看 在 0 - 9的区间上的值分布

    测试代码

        def testTarget(self):
            plt.figure(1)
            x = np.linspace(0, 9, 10000)
            x = x.astype('float')
            y = []
            for i in range(len(x)):
                y.append(self.targetFun(x[i]))
            print(x)
            print(y)
            plt.plot(x, y)
            plt.show()
    

    result

    可以看出在8附近达到最大值为25
    如果我遗传算法最后的结果在这个区间内的话,那么就可以说是正确答案

    codeResult

    总共迭代了1000次,种群的大小是1000个基因

    最佳个体 10101111011111011
    最优适应度 24.855362812666666
    最优个体对应自变量值 7.856726507007652
    最优个体的迭代次数 11
    

    计算耗时 81 s

    算法流程

    code流

    gaAlgorithm = ga.GeneticAlgorithm()
    # 初始化种群   随机赋值 0110值
    gaAlgorithm.initPopulation()
    # debug
    gaAlgorithm.debug('population')
    maxGN = gaAlgorithm.getMaxNumberIteration()
    start = time.process_time()
    for i in range(maxGN):
        # 计算适应度函数
        gaAlgorithm.fitness()
        # gaAlgorithm.debug('fitnessValue')
        gaAlgorithm.rank()
        # gaAlgorithm.debug('rank')
        gaAlgorithm.selection()
        # gaAlgorithm.debug('population')
        gaAlgorithm.crossOver()
        gaAlgorithm.mutation()
        if (i % 10 == 0):
            print(i, end=' ')
    elapsed = (time.process_time() - start)
    print("Time used:",elapsed)
    gaAlgorithm.plotGA()
    bestFitness, bestGeneration, bestIndividual = gaAlgorithm.getBestThreeAttr()
    

    流程图

    每个流程详解

    计算每个基因对于目标函数的适应性

        def fitness(self):
            '''适应度函数'''
            self.fitnessValue = []
            for i in range(self.populationSize):
                self.fitnessValue.append(0)
            # 先存储字符串转换出来的十进制的值, 然后带入目标函数中计算出真实的值
            for i in range(self.populationSize):
                for j in range(self.chromosomeLength):
                    if (self.population[i][j] == "1"):
                        # print(self.population[i][j])
                        self.fitnessValue[i] = self.fitnessValue[i] + 2**(j)
                self.fitnessValue[i] = self.lowerBound + self.fitnessValue[i] * (self.upperBound - self.lowerBound) / (2**self.chromosomeLength - 1)
                # print('十进制值', self.fitnessValue[i])
                self.fitnessValue[i] = self.targetFun(self.fitnessValue[i]) # 因为这个直接调用了函数所以,求函数的最大值其实就是求适应值
                # print('函数值', self.fitnessValue[i])
    

    说人话

    将字符串基因转为 10进制数 然后求解目标函数 如果你求得是最大值(大部分为正数),那么适应度函数就是 转为10进制后的值 带入目标函数求得值

    排序

        def rank(self):
            '''
            对个体的适应度大小进行排序,并保留最佳个体
            '''
            for i in range(self.populationSize):
                self.fitnessSum.append(0.)
            for i in range(self.populationSize):
                minIndex = i
                for j in range(i, self.populationSize):
                    if (self.fitnessValue[j] < self.fitnessValue[minIndex]):
                        minIndex = j
                if (minIndex != i):
                    tmp = self.fitnessValue[i]
                    self.fitnessValue[i] = self.fitnessValue[minIndex]
                    self.fitnessValue[minIndex] = tmp
                tmpChromosome = self.population[i]
                self.population[i] = self.population[minIndex]
                self.population[minIndex] = tmpChromosome
            for i in range(self.populationSize):
                if i == 0:
                    self.fitnessSum[i] = self.fitnessSum[i] + self.fitnessValue[i]
                else:
                    self.fitnessSum[i] = self.fitnessSum[i-1] + self.fitnessValue[i]
            self.fitnessAverage.append(self.fitnessSum[self.populationSize - 1] / self.populationSize)
            if(self.fitnessValue[self.populationSize - 1] > self.bestFitness):
                self.bestFitness = self.fitnessValue[self.populationSize - 1]
                self.bestGen = len(self.fitnessAverage)
                self.bestIndividual = self.population[self.populationSize - 1]
    

    说人话

    根据所有的基因的适应度,然后从小到大排序。最后一个个体是最优秀的个人(King)

    选择个体

        def selection(self):
            '''
                轮盘赌选择操作,按照[0, 总适应度] 先求出结果这个是要改的 应为 这个放弃了 适应度为负的值
            '''
            self.populationNew = [None] * self.populationSize
            for i in range(self.populationSize):
                r = random.random() * self.fitnessSum[self.populationSize - 1]
                first = 0
                last = self.populationSize - 1
                mid = round((last + first) / 2)
                idx = -1
                # 原文是排序选择和 r 差不多的个体(排中法?)
                while(first <= last and idx==-1):
                    if(r > self.fitnessSum[mid]):
                        first = mid
                    elif( r < self.fitnessSum[mid]):
                        last = mid
                    else:
                        idx = mid # 一般不会走到这个分支因为是浮点数
                        break
                    mid = round((last + first) / 2)
                    if(last - first == 1):
                        idx = last
                        break
                # 产生新一代的个体
                self.populationNew[i] = self.population[idx]
            if self.chooseElite:
                p = self.populationSize - 1
            else:
                p = self.populationSize
            for i in range(p):
                self.population[i] = self.populationNew[i]
    

    说人话

    有些优势基因会重复,因为放弃了(适应值为负的基因),如果开启了优势选择,那么最优秀的个体将会直接出现在新种群(待交叉配对列表) King~

    交叉

        def crossOver(self):
            '''
                交叉 改进 交换前一半的基因 = 交换后一半的基因
            '''
            for i in range(0, self.populationSize, 2):
                # 生成随机概率
                if (random.random() < self.crossoverProbability):
                    crossPosition = round(random.random() * self.chromosomeLength)
                    if (crossPosition == 0) or (crossPosition == 1):
                        continue
                    # 对crossPosition及之后的二进制串进行交换
                    tmp = self.population[i][crossPosition:]
                    self.population[i] = self.population[i][0:crossPosition] + self.population[i+1][crossPosition:]
                    self.population[i+1] = self.population[i+1][0:crossPosition] + tmp
    

    说人话

    虽然生成了待交叉的列表,但不是每对个体都会进行交叉,如果不交叉,那么他们就会自己流传下来,如果发生了交叉,那么就和他的配对对象交换基因。

    变异

        def mutation(self):
            '''
                单点变异操作
            '''
            for i in range(self.populationSize):
                if (random.random() < self.mutationProbability):
                    mutationPosition = round(random.random() * self.chromosomeLength)
                    if mutationPosition == self.chromosomeLength:
                        continue
                    tmp = list(self.population[i])
                    if ( tmp[mutationPosition] == '1'):
                        tmp[mutationPosition] = '0'
                    else:
                        tmp[mutationPosition] = '1'
                    self.population[i] = ''.join(tmp)
    

    说人话

    对于每一条基因,其中的某一个一个序列点 会发生翻转。

    code

    https://github.com/lishaohsuai/algorithm

    自问自答环节

    什么是 轮盘赌算法

    就是每个基因的适应度值放在一个圆盘上,依据其占有的面积(适应度值)放在轮盘上,如果生成一个随机数,如果他落在这个轮盘的一个盘面上,这个小扇形代表的基因就被选中,也就是说,适应度值越高的越有可能被选中。
    如果没有被选中怎么办?恭喜你可以领盒饭了,你的基因序列被自然界丢弃。

    下一步

    现在迭代 1000 个种群,1000次迭代花费了 81s , 下一步改写成 numpy 版本,争取 2s 内完成1000个种群的迭代,另外适应度函数有点问题,逻辑上来说,适应度函数的值不应该是负值。

    Hope is a good thing,maybe the best of things,and no good thing ever dies.----------- Andy Dufresne
  • 相关阅读:
    JVM-对象的创建
    maven依赖无法下载依赖包,PKIX认证不通过
    Object里面的方法
    Java多线程之volatile与synchronized比较
    java 二叉树的创建 遍历
    设计模式之单例模式
    博客园自定义主题 皮肤
    mysql索引 b+树
    sleep和wait的区别(转)
    final/finally/finalize的区别(转)
  • 原文地址:https://www.cnblogs.com/eat-too-much/p/13360813.html
Copyright © 2020-2023  润新知