遺傳算法-python

遺傳算法-python

  • 注:有很多python-GA的庫,deap、gaft等,這裏選取了一個比較好上手的gaft

簡介

gaft安裝和使用

  • 一句命令行就可以完成,官網的鏈接:https://github.com/PytLab/gaft,上面也有一些其他的博客鏈接,介紹了基於gaft的GA的應用和優化
  • 使用的過程中,主要是按照以下的代碼框架編寫程序,關於具體的參數解釋,在代碼中註釋給出。有些官網的example可能沒有解釋。

使用中可能會碰到的問題

  • windows下如果使用pip install的時候如果報錯,可以先使用easy_install pip安裝pip,之後即可使用pip進行安裝。
  • 在初始化生成種羣時,一定要保證eps小於對應變量的範圍,否則會報錯。
  • python中import之後,即使修改了原來的包,也不會更新導入的內容,因此需要reload。在python3之後可以使用importlib進行引入,具體的引用方式見可視化部分的代碼。參考鏈接:https://blog.csdn.net/liang19890820/article/details/75575122
  • 爲了實現多次引用,防止包名和變量名衝突,我在源碼裏將保存的文件名改爲了dk_best_fit.py
from math import sin, cos, pi

from gaft import GAEngine
from gaft.components import BinaryIndividual
from gaft.components import Population
from gaft.operators import TournamentSelection
from gaft.operators import RouletteWheelSelection
from gaft.operators import UniformCrossover
from gaft.operators import FlipBitBigMutation

# Built-in best fitness analysis.
from gaft.analysis.fitness_store import FitnessStore
from gaft.analysis.console_output import ConsoleOutput

# Define population.
# 變量的範圍以及精度,eps可以是1個值或者是1個list,長度是變量的個數
indv_template = BinaryIndividual(ranges=[(-2, 2), (-2, 2)], eps=[0.0001, 0.0001])

# 種羣中個體個數爲50個
population = Population(indv_template=indv_template, size=50).init()

# Create genetic operators.
#selection = RouletteWheelSelection()
# 選擇個體用於後續產生後代,
# 隨機產生
# selection = TournamentSelection()
# 使用輪盤法,選擇適應度最高的個體
selection = RouletteWheelSelection()

# UniformCrossover表示個體的每個位都有交換的可能性(每個位進行交換的概率爲pe)
# pc的含義爲進行交叉操作的概率(整體)
crossover = UniformCrossover(pc=0.8, pe=0.5)
# 定義變異操作,pm表示當前step進行變異的概率
# 這裏的FlipBitBigMutation是爲了防止陷入局部最優的,也可以使用FlipBitMutation
# pbm和alpha是爲了之後結合engine修正pm的
# pbm取一個大於5pm的在(0,1)內的值,alpha取一個(0.5,1.0)內的值即可
mutation = FlipBitBigMutation(pm=0.1, pbm=0.55, alpha=0.6)

# Create genetic algorithm engine.
# Here we pass all built-in analysis to engine constructor.
engine = GAEngine(population=population, selection=selection,
                  crossover=crossover, mutation=mutation,
                  #analysis=[ FitnessStore])
                  analysis=[ConsoleOutput, FitnessStore])

# Define fitness function.
# 如果優化目標是最小化目標函數
# 則可以加上裝飾器如下
# 如果加上這個裝飾器,相當於返回值加了一個負號,之後還得自己取反
# 因此我建議如果是需要最小化,則可以自己手動修改優化函數(取反即可),更加方便自己的理解
# 注意:在這裏添加適應度函數,如果是其他的方法,使用GA調參之類的,則可以將其他的算法卸載fitness中
@engine.fitness_register
# @engine.minimize # 最小化的裝飾器
def fitness(indv):
    x, y = indv.solution
    ret = y*sin(2*pi*x) + x*cos(2*pi*y) + 10
    return ret

# 會生成best_fit.py,裏面存儲了迭代過程中的最優點以及目標函數的信息
# 進行30次種羣進化
engine.run(ng=30)
gaft.ConsoleOutput   INFO     Generation number: 30 Population number: 50
gaft.ConsoleOutput   INFO     Generation: 1, best fitness: 12.866, scaled fitness: 12.866
gaft.ConsoleOutput   INFO     Generation: 2, best fitness: 12.866, scaled fitness: 12.866
gaft.ConsoleOutput   INFO     Generation: 3, best fitness: 12.866, scaled fitness: 12.866
gaft.ConsoleOutput   INFO     Generation: 4, best fitness: 12.866, scaled fitness: 12.866
gaft.ConsoleOutput   INFO     Generation: 5, best fitness: 12.866, scaled fitness: 12.866
gaft.ConsoleOutput   INFO     Generation: 6, best fitness: 13.123, scaled fitness: 13.123
gaft.ConsoleOutput   INFO     Generation: 7, best fitness: 13.123, scaled fitness: 13.123
gaft.ConsoleOutput   INFO     Generation: 8, best fitness: 13.126, scaled fitness: 13.126
gaft.ConsoleOutput   INFO     Generation: 9, best fitness: 13.126, scaled fitness: 13.126
gaft.ConsoleOutput   INFO     Generation: 10, best fitness: 13.126, scaled fitness: 13.126
gaft.ConsoleOutput   INFO     Generation: 11, best fitness: 13.224, scaled fitness: 13.224
gaft.ConsoleOutput   INFO     Generation: 12, best fitness: 13.224, scaled fitness: 13.224
gaft.ConsoleOutput   INFO     Generation: 13, best fitness: 13.224, scaled fitness: 13.224
gaft.ConsoleOutput   INFO     Generation: 14, best fitness: 13.224, scaled fitness: 13.224
gaft.ConsoleOutput   INFO     Generation: 15, best fitness: 13.224, scaled fitness: 13.224
gaft.ConsoleOutput   INFO     Generation: 16, best fitness: 13.224, scaled fitness: 13.224
gaft.ConsoleOutput   INFO     Generation: 17, best fitness: 13.224, scaled fitness: 13.224
gaft.ConsoleOutput   INFO     Generation: 18, best fitness: 13.224, scaled fitness: 13.224
gaft.ConsoleOutput   INFO     Generation: 19, best fitness: 13.224, scaled fitness: 13.224
gaft.ConsoleOutput   INFO     Generation: 20, best fitness: 13.224, scaled fitness: 13.224
gaft.ConsoleOutput   INFO     Generation: 21, best fitness: 13.224, scaled fitness: 13.224
gaft.ConsoleOutput   INFO     Generation: 22, best fitness: 13.224, scaled fitness: 13.224
gaft.ConsoleOutput   INFO     Generation: 23, best fitness: 13.224, scaled fitness: 13.224
gaft.ConsoleOutput   INFO     Generation: 24, best fitness: 13.224, scaled fitness: 13.224
gaft.ConsoleOutput   INFO     Generation: 25, best fitness: 13.472, scaled fitness: 13.472
gaft.ConsoleOutput   INFO     Generation: 26, best fitness: 13.472, scaled fitness: 13.472
gaft.ConsoleOutput   INFO     Generation: 27, best fitness: 13.472, scaled fitness: 13.472
gaft.ConsoleOutput   INFO     Generation: 28, best fitness: 13.472, scaled fitness: 13.472
gaft.ConsoleOutput   INFO     Generation: 29, best fitness: 13.472, scaled fitness: 13.472
gaft.ConsoleOutput   INFO     Generation: 30, best fitness: 13.472, scaled fitness: 13.472
gaft.ConsoleOutput   INFO     Optimal solution: ([1.6990966796875, -1.9512939453125], 13.472490804036644)
gaft.FitnessStore   INFO     Best fitness values are written to best_fit.py
import matplotlib.pyplot as plt
import importlib
import os
# 先重載這個文件
# wozai
import dk_best_fit
importlib.reload( dk_best_fit )
# 再引入這個變量,如果先引入變量再重載文件,則無效
from dk_best_fit import best_fit


steps, variants, fits = list(zip(*best_fit))
best_step, best_v, best_f = steps[-1], variants[-1], fits[-1]

fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(steps, fits)
ax.set_xlabel('Generation')
ax.set_ylabel('Fitness')

# Plot the maximum.
ax.scatter([best_step], [best_f], facecolor='r')
ax.annotate(s='x: [{:.2f}, {:.2f}]\ny:{:.2f}'.format(*best_v, best_f),
                                                     xy=(best_step, best_f),
                                                     xytext=(best_step, best_f-0.1))


plt.show()
<matplotlib.figure.Figure at 0x7ebf908>

這裏寫圖片描述

後續的開發

分析結果的保存修改

  • 之前只能保存到best_fit.py中,我按照官網作者的提示實現了自定義的結果保存類,裏面可以定義保存的文件名,代碼如下

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    
    from ..plugin_interfaces.analysis import OnTheFlyAnalysis
    
    # 自定義文件存儲
    class UserFitnessStore(OnTheFlyAnalysis):
    
        # Analysis interval.
        interval = 1
    
        # Only analyze in master process?
        master_only = True
    
        # 保存的文件名
        _save_fp = "my_best_fit.py"
    
        @property
        def save_fp(self):
            return UserFitnessStore._save_fp
    
        @save_fp.setter
        def save_fp(self, fp):
            UserFitnessStore._save_fp = fp
    
        def setup(self, ng, engine):
            # Generation numbers.
            self.ngs = []
    
            # Best fitness in each generation.
            self.fitness_values = []
    
            # Best solution.
            self.solution = []
    
        def register_step(self, g, population, engine):
            # Collect data.
            best_indv = population.best_indv(engine.fitness)
            best_fit = engine.ori_fmax
    
            self.ngs.append(g)
            self.solution.append(best_indv.solution)
            self.fitness_values.append(best_fit)
    
        def finalize(self, population, engine):
            with open(UserFitnessStore.save_fp, 'w', encoding='utf-8') as f:
                f.write('best_fit = [\n')
                for ng, x, y in zip(self.ngs, self.solution, self.fitness_values):
                    f.write('    ({}, {}, {}),\n'.format(ng, x, y))
                f.write(']\n\n')
    
            self.logger.info('Best fitness values are written to best_fit.py')
    
  • 同時還需要在analysis子文件夾下的__init__.py中添加from .user_fitness_store import UserFitnessStore(按照之前有的來就行)

  • 其他的分析輸出的修改方法思路見:https://github.com/PytLab/gaft/issues/19
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章