在路上

 找回密码
 立即注册
在路上 站点首页 学习 查看内容

基于遗传算法的优化问题求解

2016-8-29 13:27| 发布者: zhangjf| 查看: 559| 评论: 0

摘要: 生物学中的进化论的核心为“物竞天择,适者生存”,暗含了的规则是生物能否生存是不定的,但是适应环境的生物更容易生存。生物的多样性能够保持来源于繁殖和变异。没错,你没有点错,这的确是一篇有关人工智能入门的 ...

生物学中的进化论的核心为“物竞天择,适者生存”,暗含了的规则是生物能否生存是不定的,但是适应环境的生物更容易生存。生物的多样性能够保持来源于繁殖和变异。
没错,你没有点错,这的确是一篇有关人工智能入门的博客。开篇先提到一些生物学的观点是因为,人工智能中遗传算法的灵感来源于生物学,它是一种仿生的概念。

一.遗传算法
那么,什么是遗传算法呢?我们来举个栗子吧。
在爬虫动物园里有着各种各样的蚂蚁,我想选出一种蚂蚁来代表动物园去参加全城动物园的蚂蚁战斗比赛。那我该怎么选呢?这里有一个聪明人提出了一个方法:首先,我们从各个蚂蚁的种群中选择出一部分来(选择初代种群),让他们相互打架,然后把胜者留下来互相繁殖(交叉产生子代,选择了比较好的基因进行遗传)。把小蚂蚁养大,然后再让它们打架,胜者繁殖(不断生成子代)。通过多次的繁殖和选择,动物园有极大的可能选出的蚂蚁是所有蚂蚁中打架最厉害的。
好吧,这个例子不是特别的好。我理解的遗传算法,就是一个多点的不定向搜索。它通过多次的实验,来找到符合适应度函数的个体。

二.基本步骤
基本的步骤如下:
1.编码:将我们可以用来搜索的部分编码,常用二进制串
2.产生初代:
3.计算每个个体的适应度及适应度占总体的比例(这里我使用了轮盘赌方案):
4.以交叉概率选择父代母代进行交叉
5.以变异概率进行变异
6.生成满足种群容量的子代
7.进化多代

三.代码及说明
java代码

  1. import java.math.BigDecimal;
  2. import java.util.Random;
  3. public class Genetic {
  4. int geneSize = 20;
  5. int populationSize = 50;
  6. int iterationNum =100;
  7. double crossoverPro =0.8;
  8. double mutationPro = 0.05;
  9. int [][] individual = new int[populationSize][geneSize];
  10. double [] realValue =new double[populationSize];
  11. double [] fitness =new double [50];
  12. double [] fitnessPro =new double [populationSize];
  13. double currentOpt =0;
  14. int currentX =0;
  15. Random random =new Random();
  16. double [] max =new double[iterationNum];
  17. public void init(){
  18. for(int i =0;i<populationSize;i++){
  19. for(int j =0;j<geneSize;j++){
  20. if(random.nextBoolean())
  21. individual[i][j] =1;
  22. else
  23. individual[i][j] =0;
  24. }
  25. }
  26. }
  27. private void CalRealValue(){
  28. for(int i =0;i<populationSize;i++){
  29. realValue[i] =0;
  30. double decimal = 0;
  31. for(int j =0;j<3;j++){
  32. realValue[i] = realValue[i]*2+individual[i][j];
  33. }
  34. for(int j =geneSize-1;j>=3;j--){
  35. decimal = decimal/2+individual[i][j];
  36. }
  37. realValue[i] += decimal/2;
  38. }
  39. }
  40. private void CalFitnessAndFitnessPro(){
  41. double sum =0;
  42. currentOpt =0;
  43. currentX =0;
  44. for(int i =0;i<populationSize;i++){
  45. fitness[i] = realValue[i]+10*Math.sin(5*realValue[i])+7*Math.cos(4*realValue[i])+17;
  46. if(currentOpt<fitness[i]){
  47. currentOpt =fitness[i];
  48. currentX =i;
  49. }
  50. sum+=fitness[i];
  51. }
  52. double section =0;
  53. for(int i =0;i<populationSize;i++){
  54. section +=fitness[i];
  55. fitnessPro[i] = section/sum;
  56. }
  57. }
  58. private void Reproduction(){
  59. int [][] temp =new int [populationSize][geneSize];
  60. //交叉
  61. for(int i =0;i<populationSize-1;i=i+2){
  62. int [] father =new int [geneSize];
  63. double pro = random.nextDouble();
  64. for(int j=0;j<populationSize;j++){
  65. if(fitnessPro[j]>=pro){
  66. for(int k =0;k<geneSize;k++)
  67. father[k] = individual[j][k];
  68. break;
  69. }
  70. }
  71. pro =random.nextDouble();
  72. int [] mother =new int [geneSize];
  73. for(int j=0;j<populationSize;j++){
  74. if(fitnessPro[j]>=pro){
  75. for(int k =0;k<geneSize;k++)
  76. mother[k] = individual[j][k];
  77. break;
  78. }
  79. }
  80. double pm =random.nextDouble();
  81. if(pm<crossoverPro){
  82. int changePosition =random.nextInt(geneSize);
  83. for(int j=0;j<geneSize;j++){
  84. if(j<changePosition){
  85. temp[i][j] =father[j];
  86. temp[i+1][j] = mother[j];
  87. }
  88. else {
  89. temp[i][j] = mother[j];
  90. temp[i+1][j] = father[j];
  91. }
  92. }
  93. }else{
  94. for(int j=0;j<geneSize;j++){
  95. temp[i][j] =father[j];
  96. temp[i+1][j] = mother[j];
  97. }
  98. }
  99. }
  100. for(int i =0;i<geneSize;i++){
  101. individual[populationSize-1][i] = individual[currentX][i];
  102. }
  103. //变异
  104. for(int i =0;i<populationSize-1;i++){
  105. for(int j =0;j<geneSize;j++){
  106. if(random.nextDouble()<mutationPro)
  107. individual[i][j] = 1- temp[i][j];
  108. else
  109. individual[i][j] = temp[i][j];
  110. }
  111. }
  112. }
  113. public Genetic(){
  114. init();
  115. for(int i =0;i<iterationNum;i++){
  116. CalRealValue();
  117. CalFitnessAndFitnessPro();
  118. BigDecimal optTemp =new BigDecimal(currentOpt-17);
  119. BigDecimal valueTemp =new BigDecimal(realValue[currentX]);
  120. optTemp =optTemp.setScale(5, BigDecimal.ROUND_HALF_UP);
  121. valueTemp =valueTemp.setScale(5, BigDecimal.ROUND_HALF_UP);
  122. System.out.println("第"+i+"代,最大值为:"+optTemp+" 对应X是:"+valueTemp);
  123. max[i] = currentOpt-17;
  124. Reproduction();
  125. }
  126. }
  127. public double[] getMax(){
  128. return max;
  129. }
  130. public static void main(String[] args) {
  131. Genetic genetic =new Genetic();
  132. }
  133. }
复制代码

这里我使用了二进制编码,单点交叉,轮盘赌加精英选择(没代向下完整保留最优个体)。我目标是计算f(x) = x+ 10sin5x + 7cos4x 在[0,9]区间上的极大值,之所以在适应度函数里加入还加了17是因为f(x)在某些位置的时候是取到负数(最小-17),而参与轮盘赌计算的函数必须是正数,所以我加了17.

四.小尝试
二进制编码在0.001这样的数的时候是不精确的,于是我想能不能用十进制来解决这个问题呢?下面我尝试做了十进制编码(精确度是0.00001)
Java代码:

  1. import java.math.BigDecimal;
  2. import java.util.Random;
  3. public class DecimalGenetic {
  4. int geneSize = 6;
  5. int populationSize = 50;
  6. int iterationNum =100;
  7. double crossoverPro =0.8;
  8. double mutationPro = 0.01;
  9. int [][] individual = new int[populationSize][geneSize];
  10. double [] realValue =new double[populationSize];
  11. double [] fitness =new double [50];
  12. double [] fitnessPro =new double [populationSize];
  13. double currentOpt =0;
  14. int currentX =0;
  15. Random random =new Random();
  16. double []max =new double[iterationNum];
  17. public void init(){
  18. for(int i =0;i<populationSize;i++){
  19. for(int j =0;j<geneSize;j++){
  20. if(j == 0)
  21. individual[i][j] =random.nextInt(9);
  22. else
  23. individual[i][j] =random.nextInt(10);
  24. }
  25. }
  26. }
  27. private void CalRealValue(){
  28. for(int i =0;i<populationSize;i++){
  29. realValue[i] =0;
  30. realValue[i]+=individual[i][0];
  31. double decimal = 0;
  32. for(int j =geneSize-1;j>0;j--){
  33. decimal = decimal/10+individual[i][j];
  34. }
  35. realValue[i] += decimal/10;
  36. // System.out.println(realValue[i]+" "+i);
  37. }
  38. }
  39. private void CalFitnessAndFitnessPro(){
  40. double sum =0;
  41. currentOpt =0;
  42. currentX =0;
  43. for(int i =0;i<populationSize;i++){
  44. fitness[i] = realValue[i]+10*Math.sin(5*realValue[i])+7*Math.cos(4*realValue[i])+17;
  45. if(currentOpt<fitness[i]){
  46. currentOpt =fitness[i];
  47. currentX =i;
  48. }
  49. sum+=fitness[i];
  50. }
  51. double section =0;
  52. for(int i =0;i<populationSize;i++){
  53. section +=fitness[i];
  54. fitnessPro[i] = section/sum;
  55. }
  56. }
  57. private void Reproduction(){
  58. int [][] temp =new int [populationSize][geneSize];
  59. //产生交叉
  60. for(int i =0;i<populationSize-1;i=i+2){
  61. int [] father =new int [geneSize];
  62. double pro = random.nextDouble();
  63. for(int j=0;j<populationSize;j++){
  64. if(fitnessPro[j]>=pro){
  65. for(int k =0;k<geneSize;k++)
  66. father[k] = individual[j][k];
  67. break;
  68. }
  69. }
  70. pro =random.nextDouble();
  71. int [] mother =new int [geneSize];
  72. for(int j=0;j<populationSize;j++){
  73. if(fitnessPro[j]>=pro){
  74. for(int k =0;k<geneSize;k++)
  75. mother[k] = individual[j][k];
  76. break;
  77. }
  78. }
  79. double pm = random.nextDouble();
  80. if(pm<crossoverPro){
  81. int changePosition =random.nextInt(geneSize);
  82. for(int j=0;j<geneSize;j++){
  83. if(j<changePosition){
  84. temp[i][j] =father[j];
  85. temp[i+1][j] =mother[j];
  86. }
  87. else {
  88. temp[i][j] = mother[j];
  89. temp[i+1][j] = father[j];
  90. }
  91. }
  92. }
  93. else{
  94. for(int j=0;j<geneSize;j++){
  95. temp[i][j] =father[j];
  96. temp[i+1][j] =mother[j];
  97. }
  98. }
  99. }
  100. for(int i =0;i<geneSize;i++){
  101. individual[populationSize-1][i] = individual[currentX][i];
  102. }
  103. //变异
  104. for(int i =0;i<populationSize-1;i++){
  105. for(int j =0;j<geneSize;j++){
  106. if(random.nextDouble()<mutationPro)
  107. individual[i][j] = random.nextInt(10);
  108. else
  109. individual[i][j] = temp[i][j];
  110. }
  111. }
  112. }
  113. public DecimalGenetic(){
  114. init();
  115. for(int i =0;i<iterationNum;i++){
  116. CalRealValue();
  117. CalFitnessAndFitnessPro();
  118. BigDecimal optTemp =new BigDecimal(currentOpt-17);
  119. optTemp =optTemp.setScale(5, BigDecimal.ROUND_HALF_UP);
  120. System.out.println("第"+i+"代,最大值为:"+optTemp+" 对应X是:"+realValue[currentX]);
  121. max[i] = currentOpt-17;
  122. Reproduction();
  123. }
  124. }
  125. public double[] getMax(){
  126. return max;
  127. }
  128. public static void main(String[] args) {
  129. DecimalGenetic decimalGenetic =new DecimalGenetic();
  130. }
  131. }
复制代码

实现和二进制大部分一致,但是在变异部分我用了取随机数这个方法。

五.思考:
关于编码,我在做完之后有一些思考,想和大家分享.我们编码一个数据,用0-1串表示,每一位是没有差别的,但是转换为数字的时候,每一位的权值是不同的。对于真正的自然界,每个性状对于生物的存活几率的影响也是不同的。比如果蝇的翅膀大小和眼色对于它的生存几率的影响是不同的,那反应成我们这里的编码就是位置不同,权重不同.这里算是遗传算法的奇妙之处吧.

下面推荐一个讲述比较完整的博客:https://segmentfault.com/a/1190000004155021

最新评论

小黑屋|在路上 ( 蜀ICP备15035742号-1 

;

GMT+8, 2025-7-8 00:43

Copyright 2015-2025 djqfx

返回顶部