• 【Deep Learning 1】遗传算法GA


    🍊本文以一个案例题目出发,详细描述了遗传算法过程,并做了两个实验复现题目

    🍊实验一:纯手打原生代码复现案例

    🍊实验二:使用第三方库scikit-opt复现案例

    一、Introduction

    遗传算法源自自然界生物的遗传和进化过程:通过染色体之间的选择、交叉和变异来形成。同时符合自然界优胜劣汰的规则。因此遗传算法本质上是一种全局优化搜索算法,即已知评价方程和参数范围,求解目标函数最优解。

    二、 Principle

    2.1 算法总体流程

    算法流程

    1 设计编码器和解码器

    2 初始化种群 

    3 个体适应度评价

    4 交叉运算

    5 变异运算

    6 选择运算

    7 判断遗传进化是否达到迭代阈值

    接下来我们使用GA来解决以下问题

     题目:求解以下函数的最小值

    题目分析:我们目标是求解该函数的最小值。限制条件为x的取值范围在-20~20

    2.2 编码器和解码器

    GA最先要做的事情就是对自变量X编码成字符串,每个字符类似于生物学中的染色体,而一条字符串就是一个个体。该题目中变量x整数为20-(-20)=40个。很多时候我们变量是有精度,因此我们需要对其进行扩充,如40*10=400个。

    接下来我们要考虑使用什么规则来对X进行编码,最常见的方法是使用0、1构成的二进制编码

    因此我们采用9位二进制数表示x值。

    代码上我们设计Encoder编码器函数和Decoder解码器函数进行编码和解码。

    2.2 初始化种群

    初始化种群主要是随机产生几个个体。假设我们随机产生了4个个体

    个体编码数值染色体
    1号11.7100111101
    2号-11.6001010100
    3号-6.9010000011
    4号6.2100000110

    2.3 个体适应度评价

    衡量一条染色体质量的指标即适应度,通常来说就是将个体代入目标函数的函数值

    个体编码数值染色体f(x)
    1号11.7100111101273.78
    2号-11.6001010100269.12
    3号-6.901000001195.22
    4号6.210000011076.88

    2.4 交叉

    染色体在进化的过程中会不断进行两两交叉配对。染色体具体交叉配对的过程为从几号位置染色体交换染色体

    个体编码染色体f(x)交换个体编码对象交换位置
    1号100111101273.783号5
    2号001010100269.124号4
    3号01000001195.221号8
    4号10000011076.882号8

    交换后的结果为

    个体编码染色体f(x)
    1号100110011228.97
    2号001000110338.0
    3号01000001195.22
    4号10000011076.88

    2.5 变异

    看过《异形》的小伙伴都知道生物可能会发生变异。而变异的具体过程就是染色体发生突变。本例子中我们需要设定一个变异概率的值,某条染色体0、1互换。若变异后的超出变量x的阈值,则变异失败

    个体编码染色体是否发生变异变异位置是否成功变异变异结果
    1号1001100113100010011
    2号001000110---
    3号010000011---
    4号100000110---

    2.6 选择

    在自然界中有着优胜劣汰的规则,因此我们需要挑选出适应度高的个体。在自然界中,有着良好基因的个体往往有更大概率存活下来,根据该规律,传统的使用的是轮盘赌算法,即适应度与被选择的概率成正比,适应度越高,被选择的概论也就越高。

    但是因为所求的是最小值,即函数值越高,概率越低,因此需要特别设计一个规则。

    作者想出了两种方案

    第一种方案,是从适应度函数下手如下,那么求解最小值等价于求解该适应度函数的最大值,这样可以继续使用传统的轮盘赌算法 

    第二种方案,是从轮盘赌算法下手,f(x)概率越小,分子越小,f(x0值越小,种群适应度越高。且概率之和为1,下述的代码也是采用本方案。这里的n是初始化种群的个体数量

    注意这里被选中次数之和与选中前的个数总和一致

    个体编码数值染色体f(x)被选择的概率被选中的次数
    17.5100010011112.50.20561
    2-13.0001000110338.00.2078-
    3-6.901000001195.220.28891
    46.210000011076.880.29742

    选择之后进行繁衍,更新表格数据为

    个体编码染色体f(x)初始f(x)(这里做对比)
    1100010011112.5273.78
    201000001195.22269.12
    310000011076.8895.22
    410000011076.8876.88

    可以看到经过一轮的遗传进化之后,种群的f(x)普遍降低,种群的适应度总体提高不少

    最后判断是否达到最大迭代次数,若没有,则重新回到2.3 步骤

    三、Experiment

    3.1 方案一:原生代码

    Code

    1. import numpy as np
    2. from matplotlib import pyplot as plt
    3. PRECISION = 10.0 # 自变量精度
    4. INDIVIDUALS_NUM = 50 # 初始化个体数量
    5. EVOLUTION_NUM = 10000 # 进化次数
    6. LOWER_LIMIT = -20 # 染色体下限值
    7. UPPER_LIMIT = 20 # 染色体上限值
    8. CROSS_RATE = 0.6 # 交叉概率
    9. MUTATION_RATE = 0.005 # 变异概率
    10. def encoder(x):
    11. result = []
    12. for i in x:
    13. i = bin(int((i + 20) * PRECISION))[2:]
    14. for j in range(9 - len(i)):
    15. i = '0' + i
    16. result.append(i)
    17. return result
    18. def decoder(x):
    19. result = []
    20. for i in x:
    21. i = int(i, 2) - 200
    22. i = i / PRECISION
    23. result.append(i)
    24. return result
    25. def initialize():
    26. def transform(x):
    27. return (x - 200) / PRECISION
    28. p = np.random.randint(0, 400, size=INDIVIDUALS_NUM)
    29. p = encoder(list(map(transform, p)))
    30. return p
    31. def choose(x, ada):
    32. x, ada = np.asarray(x), np.asarray(ada)
    33. #print('概率情况',(1-ada / ada.sum())/(INDIVIDUALS_NUM-1))
    34. index = np.random.choice(np.arange(INDIVIDUALS_NUM), size=INDIVIDUALS_NUM, replace=True, p=(1-ada / ada.sum())/(INDIVIDUALS_NUM-1))
    35. #print('\nChoose index:', index)
    36. return x[index]
    37. def threshold_limit(x):
    38. l = []
    39. l.append(x)
    40. x = decoder(l)[0]
    41. if x >= -20 and x <= 20:
    42. return True
    43. else:
    44. return False
    45. def cross(x):
    46. result = []
    47. for chromosome in x:
    48. chromosome_A = list(chromosome)
    49. if np.random.rand() < CROSS_RATE:
    50. chromosome_B = x[np.random.randint(INDIVIDUALS_NUM)]
    51. cross_points = np.random.randint(low=0, high=8)
    52. # 观察交叉后的数据会不会超过自变量x的阈值
    53. fake = chromosome_A
    54. fake[cross_points:] = list(chromosome_B)[cross_points:]
    55. if threshold_limit(''.join(fake)):
    56. chromosome_A = fake
    57. result.append(''.join(chromosome_A))
    58. return result
    59. def mutations(x):
    60. result = []
    61. for chromosome in x:
    62. if np.random.rand() < MUTATION_RATE:
    63. mut_points = np.random.randint(0, 8)
    64. chromosome = list(chromosome)
    65. # 观察变异后的数据会不会超过自变量x的阈值
    66. fake = chromosome
    67. fake[mut_points] = '1' if chromosome[mut_points] == '0' else '0'
    68. if threshold_limit(''.join(fake)):
    69. chromosome = fake
    70. result.append(''.join(chromosome))
    71. return result
    72. def adaptability(list):
    73. result = []
    74. for i in list:
    75. result.append(2 * pow(i, 2))
    76. return result
    77. def best_chr(x):
    78. dec = decoder(x)
    79. ada = adaptability(dec)
    80. best_index = np.argmin(ada)
    81. return (ada[best_index])
    82. if __name__ == '__main__':
    83. # 初始化种群
    84. pop = initialize()
    85. #print(decoder(pop))
    86. print('Initializing Populations', pop)
    87. best=[]
    88. for i in range(EVOLUTION_NUM):
    89. ada = adaptability(decoder(pop))
    90. #print('Adaptability', ada)
    91. pop = cross(pop)
    92. #print('Cross', pop)
    93. pop = mutations(pop)
    94. #print('Chromosome',pop)
    95. #print('hanshuzhi',decoder(pop))
    96. pop = choose(pop, ada)
    97. #print('Choose', pop)
    98. best.append(best_chr(pop))
    99. plt.plot(range(EVOLUTION_NUM), best)
    100. plt.ylabel('f(x)')
    101. plt.xlabel('Epoch')
    102. plt.show()

    Result

    这个结果非常有意思

    1 目标函数值最优解为0,所求的结果大部分接近0,且最终也趋向于0,说明该算法是有效的

    2 中间有几个凸集,主要是因为有染色体变异的情况,但最终还是趋向于0了

    3 这其实反映了生物进化的过程,有些时候发生了生物变异,它具有很强的适应性,在某个时期具有一定的地位。但是随着生物的不断遗传进化,物竞天择的自然规律,最终,最适应的染色体始终占据了主导地位

    3.2 方案二:第三方库

    安装第三方库

    pip install scikit-opt
    

    Code

    1. from sko.GA import GA
    2. def adapt(x):
    3. return 2 * pow(x, 2)
    4. # func 适应度函数
    5. # n_dim 自变量的个数
    6. # size_pop 种群初始化个体数量
    7. # max_iter 进化迭代次数
    8. # prob_mut 变异概率
    9. # lb 自变量下限
    10. # ub 自变量上限
    11. # precision 精度
    12. ga = GA(func=adapt, n_dim=1, size_pop=50, max_iter=800, prob_mut=0.001, lb=-20, ub=20, precision=1e-2)
    13. best_x, best_y = ga.run()
    14. print('best_x:', best_x, '\n', 'best_y:', best_y)

  • 相关阅读:
    初识OpenGL (-)VAO&VBO
    弘辽科技:淘宝什么情况下需要提升销量?店铺怎么提升销量?
    设计模式——备忘录模式(memento)
    利用alt实现图片加载时显示图片加载效果
    掌控变量(C语言变量初步详解)
    开发眼里的网络
    用 50 张游戏显卡检测癌症,这是“业余”程序员?
    数据结构题目收录(三)
    基于R语言极值统计学及其在相关领域中的应用
    安卓开发项目优化小技巧
  • 原文地址:https://blog.csdn.net/ccaoshangfei/article/details/126886176