檔案建立日期: 2019/12/23
最後修訂日期: None
相關軟體資訊:
Win 10 | Python 3.7.2 | deap 1.3.0 | Numpy 1.17.3 | scoop 0.7.1.1 |
參考檔案: AI with Python Tutorial
說明: 所有內容歡迎引用, 只需註明來源及作者, 本文內容如有錯誤或用詞不當, 敬請指正.
標題: 人工智慧 (13) 遺傳演算法
遺傳演算法 ( GA, Genetic Algorithms )
基於搜尋的演算法,基於自然選擇和遺傳學的概念。為給定問題提供了可能的解決方案池。然後進行重組和突變,產生了新的方案,它會不斷髮展更好的個人或解決方案,直到達到停止標準為止。
- 隨機生成初始種群。
- 選擇具有最佳適應性值的初始解決方案。
- 使用變異和交叉運算元重新組合選定的解決方案。
- 將後代插入種群。
- 如果不滿足停止條件,再回到2。
例 1. 隨機生成500個人, 45個基因(0或1), 經十代繁殖及突變出只有15個基因為1的後代
# -----------------------------------------------------------------------------
# Using Genetic Algorithms
# ------------------------------------------------------------------------------
import random
from deap import base, creator, tools
def eval_func(individual):
# N個基因(0或1), 最好的基因為15個是1
# 當符合條件, 表示N個基因是符合要求的
# 函式返回符合的基因數, 最好是N個
target_sum = 15
return len(individual) - abs(sum(individual) - target_sum)
def create_toolbox(num_bits):
# 定義FitnessMax為Fitness(一個計算方案質量的度量), 引數為1.0
creator.create("FitnessMax", base.Fitness, weights=(1.0,))
# 定義Individual為list(FitnessMax)
creator.create("Individual", list, fitness=creator.FitnessMax)
# 建立一個工具箱
toolbox = base.Toolbox()
# 定義attr_bool為random.randint(0,1)
toolbox.register("attr_bool", random.randint, 0, 1)
# 定義individual為重複執行45次的list(random.randint(0,1))
toolbox.register("individual", tools.initRepeat, creator.Individual,
toolbox.attr_bool, num_bits)
# 定義population為list(individual)
toolbox.register("population", tools.initRepeat, list, toolbox.individual)
# 定義evaluate為eval_func函式
toolbox.register("evaluate", eval_func)
# 定義mate為輸入在某兩點位內容交換, 會修改引數內容
toolbox.register("mate", tools.cxTwoPoint)
# 定義mutate為布林值翻轉函式, 翻轉機率為0.05
toolbox.register("mutate", tools.mutFlipBit, indpb=0.05)
# 定義select為隨機選擇3箇中的最佳元素 (執行k次)
toolbox.register("select", tools.selTournament, tournsize=3)
return toolbox
num_bits = 45 # 45個0或1的隨機數
toolbox = create_toolbox(num_bits) # 建立工具箱
random.seed(7)
population = toolbox.population(n=500) # 人口為[[0/1隨機數*45]*500]
probab_crossing, probab_mutating = 0.5, 0.2 # 基因交換/突變機率
num_generations = 10 # 十代
print('\nEvolution process starts')
fitnesses = list(map(toolbox.evaluate, population)) # 對所有'人口'作eval_func()
for ind, fit in zip(population, fitnesses):
ind.fitness.values = (fit,) # 質量=eval_func計算值
print('\nEvaluated', len(population), 'individuals')
for g in range(num_generations):
print("\n- Generation", g)
offspring = toolbox.select(population, len(population)) # 三取一, 取人口數個
offspring = list(map(toolbox.clone, offspring)) # 複製樣品
for child1, child2 in zip(offspring[::2], offspring[1::2]): # 分兩群
if random.random() < probab_crossing:
toolbox.mate(child1, child2) # 基因交換
del child1.fitness.values
del child2.fitness.values
for mutant in offspring: # 基因突變
if random.random() < probab_mutating:
toolbox.mutate(mutant)
del mutant.fitness.values
invalid_ind = [ind for ind in offspring if not ind.fitness.valid] #剔除無效
fitnesses = map(toolbox.evaluate, invalid_ind) #計算質量
for ind, fit in zip(invalid_ind, fitnesses):
ind.fitness.values = (fit,)
print('Evaluated', len(invalid_ind), 'individuals')
population[:] = offspring
fits = [ind.fitness.values[0] for ind in population]
length = len(population) # 計算平均值及標準偏差
mean = sum(fits) / length
sum2 = sum(x*x for x in fits)
std = abs(sum2 / length - mean**2)**0.5
print('Min =', min(fits), ', Max =', max(fits))
print('Average =', round(mean, 2), ', Standard deviation =', round(std, 2))
print("\n- Evolution ends")
best_ind = tools.selBest(population, 1)[0]
print('\nBest individual:\n', best_ind)
print('\nNumber of ones:', sum(best_ind))
例 2. 符號迴歸問題
# -----------------------------------------------------------------------------
# Symbol Regression Problem - 5x^3 - 6x^2 + 8x = 1
# Note: This script cannot run under Python again, must quit from Python,
# then execute it again.
# ------------------------------------------------------------------------------
import operator
import math
import random
import numpy as np
from deap import algorithms, base, creator, tools, gp
def division_operator(numerator, denominator): # 除法運算子: 分子/分母
if denominator == 0: # 另外定義的目的在避免除0出錯
return 1
return numerator / denominator
def eval_func(individual, points):
# sum[(輸入表示式-內建表示式的差)^2]/點數, 內建表示式: 5x^3-6x^2+8x-1
func = toolbox.compile(expr=individual)
mse = ((func(x) - (5 * x**3 - 6 * x**2 + 8 * x - 1))**2 for x in points)
return (math.fsum(mse) / len(points),)
def create_toolbox():
pset = gp.PrimitiveSet("MAIN", 1) # 定義"MAIN"只有一個輸入變數
pset.addPrimitive(operator.add, 2) # +,-(減),*,/ 有兩個輸入
pset.addPrimitive(operator.sub, 2) # -(負), cos, sin 有一個輸入
pset.addPrimitive(operator.mul, 2)
pset.addPrimitive(division_operator, 2)
pset.addPrimitive(operator.neg, 1)
pset.addPrimitive(math.cos, 1)
pset.addPrimitive(math.sin, 1) # rand101是一個運算值, 定義方式不同
pset.addEphemeralConstant("rand101", lambda: random.randint(-1,1))
pset.renameArguments(ARG0='x') # 第0個輸入變數為x
# 定義FitnessMax為Fitness(一個計算方案質量的度量), 引數為-1.0
creator.create("FitnessMin", base.Fitness, weights=(-1.0,))
# 定義Individual為gp.PrimitiveTree(FitnessMax)
# gp.PrimitiveTree是最佳化遺傳程式設計操作而專門格式化的樹狀結構
creator.create("Individual",gp.PrimitiveTree,fitness=creator.FitnessMin)
# 建立一個工具箱
toolbox = base.Toolbox()
# 定義expr為生成表示式, pset原生資料集, 高度1~2
toolbox.register("expr", gp.genHalfAndHalf, pset=pset, min_=1, max_=2)
# 定義indivial為迭代呼叫Individual來自expr的輸出
toolbox.register("individual", tools.initIterate,
creator.Individual, toolbox.expr)
# 定義population為list(individual)
toolbox.register("population",tools.initRepeat,list, toolbox.individual)
# 定義compile為python執行表示式, 輸入型式為pset原生資料集
toolbox.register("compile", gp.compile, pset=pset)
# 定義evaluate為eval_func函式, 共20個點 [-1 ~ 0.9]
toolbox.register("evaluate", eval_func,
points=[x/10. for x in range(-10,10)])
# 定義select為隨機選擇3箇中的最佳元素 (執行k次)
toolbox.register("select", tools.selTournament, tournsize=3)
# 定義mate為輸入在某點內容交換, 會修改引數內容
toolbox.register("mate", gp.cxOnePoint)
# 定義expr_mut為產生一個表示式樹, 在具有同樣高度下, 高度在0~2之間
toolbox.register("expr_mut", gp.genFull, min_=0, max_=2)
# 定義mutate為在樹中隨機找一個點, 以expr_mut取代
toolbox.register("mutate", gp.mutUniform, expr=toolbox.expr_mut, pset=pset)
# 定義mate為對GP樹上的某些度量實施靜態限制, 避免生成無效後代, 最大高度17
toolbox.decorate("mate", gp.staticLimit(key=operator.attrgetter("height"),
max_value=17))
# 定義mumate為對GP樹上的某些度量實施靜態限制, 避免生成無效後代, 最大高度17
toolbox.decorate("mutate", gp.staticLimit(key=operator.attrgetter("height"),
max_value=17))
return toolbox
random.seed(7)
toolbox = create_toolbox() # 建立工具箱
population = toolbox.population(n=450) # 建立表示式n=450
hall_of_fame = tools.HallOfFame(1) # 耳出一個最佳個體
stats_fit = tools.Statistics(lambda x: x.fitness.values)# 統計函式stats_fit
stats_size = tools.Statistics(len) # 統計函式stats_size
mstats = tools.MultiStatistics(fitness=stats_fit, size=stats_size) # 多重統計
mstats.register("avg", np.mean) # 定義avg為np.mean
mstats.register("std", np.std) # 定義std為np.std
mstats.register("min", np.min) # 定義min為np.min
mstats.register("max", np.max) # 定義max為np.max
probab_crossover = 0.4 # 基因交換機率
probab_mutate = 0.2 # 基因突變機率
number_gen = 10 # 十代
# eaSimple演算法(輸入個體,工具箱,交換機率,突變機率,代數目, 統計, 最佳個體,記錄)
# 最簡單的進化演算法 Back, Fogel and Michalewicz, “Evolutionary Computation 1 :
# Basic Algorithms and Operators”, 2000.
population, log = algorithms.eaSimple(population, toolbox,
probab_crossover, probab_mutate, number_gen,
stats=mstats, halloffame=hall_of_fame, verbose=True)
fitness size
------------------------------------------ ----------------------------------
gen nevals avg gen max min nevals std avg gen max min nevals std
0 450 65.3059 0 106.2100 41.3678 450 10.33940 3.73556 0 7 2 450 1.62449
1 238 62.0487 1 1216.7200 41.8757 238 55.06550 3.80444 1 10 1 238 1.77813
2 232 55.6696 2 79.6906 41.5774 232 7.45130 3.96889 2 13 1 232 1.87946
3 248 52.9092 3 88.0317 41.5774 248 7.83529 4.17333 3 13 1 248 1.83574
4 232 50.9084 4 104.8650 32.7140 232 9.00519 4.87556 4 13 1 232 2.12552
5 208 47.6437 5 97.6900 32.7140 208 7.60911 5.52444 5 15 1 208 2.4323
6 218 45.7589 6 149.3100 32.7140 218 9.39208 6.68667 6 15 1 218 2.82088
7 231 43.4631 7 104.8650 26.5704 231 9.41258 7.89333 7 19 1 231 3.3196
8 224 41.3779 8 161.5110 18.1649 224 11.25450 9.32222 8 28 1 224 3.96156
9 223 39.3688 9 187.9040 15.1825 223 14.03400 10.7533 9 28 1 223 3.98152
10 235 37.5933 10 258.5880 14.3541 235 17.65240 12.1467 10 30 1 235 4.4866
本作品採用《CC 協議》,轉載必須註明作者和本文連結