deap遗传算法 tirads代码解读
- 写在最前面
- Overview 程序概览
- 参考
- deap框架介绍
- creator模块
- 创建适应度类Types
- 定义适应度策略
- 创建个体类
- Toolbox类
- 创建种群(个体、策略以及粒子)Initialization
- 1. 创建 attr_int 运算符
- 2. 创建 individual_guess() 运算
- 3.创建新运算 individual()(注:本文为Seedling a Population初始化方法与常规初始化方法的结合,因而官方文档中没有该部分)
- 4.创建新运算 population_guess()
- 该论文的种群创建与官方文档的对比
- 创建遗传算子 Operators
- mutate方法
- 常用实现函数 tools 模块
- 计算适应度
- 计算程序 Algorithms
写在最前面
以代码解读为主,方便后续换数据后改代码
一开始直接看的代码,但感觉和之前的不一样,一步理解错了,后面全理解不了(果然和wl老师说的一样,得一步步查,理解里面的参数)
然后根据代码查到了deap的简介和使用,结果发现这篇论文的代码不是基础的个体初始化
后面又查到了Seedling a Population初始化种群,发现大体一样,但还是有区别
最后从官方文档的注释,猜测是Seedling a Population初始化方法与常规初始化方法的结合,这才把创建种群这部分的代码理解的七七八八
Overview 程序概览
1.Types : 选择你要解决的问题类型,确定要求解的问题个数,最大值还是最小值
2. Initialization : 初始化基因编码位数,初始值,等基本信息
3. Operators : 操作,设计evaluate函数,在工具箱中注册参数信息:交叉,变异,保留个体,评价函数
4. Algorithm : 设计main函数,确定参数并运行得到结果
参考
官方文档:http://deap.readthedocs.io/en/master/index.html
deap框架中文翻译,主要参考:
https://developer.aliyun.com/article/833958
创建种群类部分,参考:
https://www.jianshu.com/p/ee8ee76225c1
通过猜测的值来初始化进化函数,参考:
https://zhuanlan.zhihu.com/p/69071128
补充,参考:
https://blog.csdn.net/FontThrone/article/details/78253230
deap框架介绍
目前,有许多可用于遗传算法的 Python 框架 —— GAFT,DEAP,Pyevolve 和 PyGMO 等。
其中,deap (Distributed Evolutionary Algorithms in Python) 框架支持使用遗传算法以及其他进化计算技术快速开发解决方案,得到了广泛的应用。deap 提供了各种数据结构和工具,这些数据和工具在实现各种基于遗传算法的解决方案时必不可少。
creator模块
creator 模块可以作为元工厂,能够通过添加新属性来扩展现有类。
例如,传递给 create() 函数的 第一个参数 是新类的名称。第二个参数 是要扩展的现有类,接下来是使用其他参数定义新类的属性。
如果为参数分配了一个类(例如 dict 或 set ),它将作为构造函数中初始化的实例属性添加到新类中。如果参数不是类(例如字符串),则将其添加为静态 (static) 属性。
这个新类存在于 creator 模块中,因此需要引用时使用 creator.Developer。
使用 deap 时,creator 模块通常用于创建 Fitness 类以及 Individual 类。
创建适应度类Types
使用 deap 时,适应度封装在 Fitness 类中。在 deap 框架中适应度可以有多个组成部分,每个组成部分都有自己的权重(weights)。
这些权重的组合定义了适合给定问题的行为或策略。
定义适应度策略
产生一个 creator.FitnessMax 类,该类扩展了 base.Fitness 类,并将 weights 类属性初始化为 (1.0,)值。
需要注意的是:weights 参数是一个元组。
FitnessMax 类的策略是在遗传算法过程中 最大化单目标解的适应度值。
from deap import base, creator
creator.create("FitnessMax", base.Fitness, weights=(1.0,))
(备注)相反,如果有一个单目标问题,需要使适应度值最小的解,则可以使用以下定义来 创建最小化策略:
creator.create("FitnessMin",base.Fitness,weights=(-1.0,))
还可以定义具有优化多个目标且重要性不同的策略
creator.create("FitnessCompound",base.Fitness,weights=(1.0,0.2,-0.5))
它拥有三个不同的适应度组成部分。第一部分权重为 1.0,第二部分权重为 0.2,第三部分权重为 -0.5。这将倾向于使第一和第二部分(或目标)最大化,而使第三部分(或目标)最小化。
创建个体类
在 deap 中,creator 工具的第二个常见用途是定义构成遗传算法种群的个体。
遗传算法中的个体使用可以由遗传算子操纵的染色体来表示,通过扩展表示染色体的基类来创建 Individual 类。
另外,deap 中的每个个体实例都需要包含其适应度函数作为属性。
creator.create("Individual", list, fitness=creator.FitnessMax)
该代码片段具有以下两个效果:
• 创建的 Individual 类扩展了 Python 的 list 类,这意味着使用的染色体是列表类型
• 创建的 Individual 类的每个实例将具有之前创建的 FitnessMax 属性:最大化单目标解的适应度值
Toolbox类
deap 框架提供的第二种高效创建遗传算法的机制是 base.Toolbox 类。
Toolbox 用作函数(或操作)的容器,能够通过别名机制和自定义现有函数来创建新的运算符。
在使用时首先要调用base.Toolbox()。
import base
toolbox = base.Toolbox()
然后再对register进行调用。
传递给 register() 函数的参数
第一个参数 是新运算符所需的名称(或别名),第二个参数 是被定制的现有函数。
创建完成后,每当调用新运算符时,其他参数都会自动传递给创建的函数。
创建种群(个体、策略以及粒子)Initialization
种群 与个体非常类似,它们不是用属性初始化,而是充满了个体、策略以及粒子(针对不同方法采取不同的种群)。
需要将deap包中所带方法与要编写的演化算法进行 固定:包括初始化、操作方法以及适应度函数的计算。
该论文代码中,使用的是Seedling a Population初始化方法与常规初始化方法的结合,这样就可以拥有部分随机个体和部分非随机个体。
优点:一定程度上可以加快收敛,并且也提供了不完全随机的生成方法。
Seedling a Population,通过猜想来对数据进行手动初始化。
DEAP1.2.2文档(二)中关于该方案的解读:
有时候,需要一个 猜测种群来初始化进化算法。使用猜测值进行初始化,而非使用随机个体的群体。
关键思想是,需要建立一个将内容作为参数的个体初始化函数。
原代码对该段函数的注释
Individual is a list of 19 integers corresponding to ACR TI-RADS features excluding cyctic and spongiform (which are not optimized) and anechoich and extra-thyroidal extension (which are not available)
Individual是一个19个整数的列表,对应于ACR TI-RADS特征不包括环状和海绵状(未优化)和无回声和甲状腺外延伸(这是不可用的)
利用 Toolbox,用于创建和初始化遗传算法的函数
1. 创建 attr_int 运算符
重定向 到random.radint()函数,返回[0,3]范围内的整数值
import random
from deap import tools
# Attribute generator
# 属性生成器
toolbox.register("attr_int", random.randint, 0, 3)
random randint() 方法 返回指定范围内的整数。
random.randint(start, stop)
参数说明:
start – 必需, 一个整数,指定开始值。
stop – 必需,一个整数,指定结束值。
2. 创建 individual_guess() 运算
使用 toolbox,创建一个新的运算 individual_guess()
该运算符利用 initIndividual() 函数创建,传递通过猜测值来初始化创建个体的参数
def initIndividual(icls, content):
return icls(content)
# Structure initializers
# 结构初始化器
toolbox.register("individual_guess", initIndividual, creator.Individual)
其中,initIndividual为前面定义的函数,creator.Individual为前面创建的个体类
3.创建新运算 individual()(注:本文为Seedling a Population初始化方法与常规初始化方法的结合,因而官方文档中没有该部分)
需要导入模块:
# from deap import tools [as 别名]
# 或: from deap.tools import initRepeat [as 别名]
该运算符利用 initIndividual() 函数创建,传递创建个体们的参数:由19个随机的整数构成,并且它们的适应值是一个最大适应值
IND_SIZE = 19
toolbox.register("individual", tools.initRepeat, creator.Individual, toolbox.attr_int, n = IND_SIZE)
initRepeat()函数,将它容器中的元素填充到creator.Individual class中,它对toolbox.attr_int()函数的func参数根据IND_SIZE(这里的n,即19)进行重复。
注:(原注释)Individual是一个19个整数的列表
toolbox.individual()将会使用设置好的参数调用initRepeat(),并且会返回到一个完成的creator.Individual中
这个creator.Individual是由IND_SIZE的整数和最大化单目标优化适应度信息fitness组成。
即在本例中,individual是由19个随机的整数构成,并且它们的适应值是一个最大适应值。
4.创建新运算 population_guess()
返回:100个种群list(其中,初始化种群为[2, 2, 1, 1, 1, 1, 2, 3, 0, 3, 0, 0, 2, 0, 0, 2, 0, 1, 3])
# Number of indiviguals in population
# 种群中的个体数量
population_count = 100
# All individuals in initial population are ACR TI-RADS
# 初始种群中的所有个体都是ACR TI-RADS
def initPopulation(pcls, ind_init, initial_state):
return [pcls(ind_init(eval(initial_state)))] * population_count
initial_state = '[2, 2, 1, 1, 1, 1, 2, 3, 0, 3, 0, 0, 2, 0, 0, 2, 0, 1, 3]'
toolbox.register("population_guess", initPopulation, list, toolbox.individual_guess, initial_state)
等效于:
initPopulation(list, toolbox.individual_guess, initial_state)
其中,toolbox.individual_guess等效于:种群(初始化种群为[2, 2, 1, 1, 1, 1, 2, 3, 0, 3, 0, 0, 2, 0, 0, 2, 0, 1, 3])
即返回:
100个种群list(初始化种群为[2, 2, 1, 1, 1, 1, 2, 3, 0, 3, 0, 0, 2, 0, 0, 2, 0, 1, 3])
该论文的种群创建与官方文档的对比
该论文为Seedling a Population初始化方法与常规初始化方法的结合,这样就可以拥有部分随机个体和部分非随机个体。
因此官方文档中Seedling a Population没有创建 individual()的部分,但初始化种群为json文件,而该论文代码中为1个list,因此需要这部分
种群将会从文件my_guess.json初始化,将会包含一个拥有第一猜想的列表。
其中,initIndividual()和individual_guess()是可以选择的,这是因为它们的默认结构是相似的。
可以移除212行使用217行的代码代替。
创建遗传算子 Operators
为了快速构建遗传流程,可以使用 Toolbox 类定制 tools 模块的现有函数。tools 模块包含许多便捷的函数,这些函数包括选择、交叉和变异的遗传算子以及程序的初始化等。
下面定义了四个别名函数,用作遗传算子:
# Hyperparameters of genetic algorithm and optimization constraints
# 遗传算法超参数及优化约束
toolbox.register("mate", tools.cxTwoPoint)
toolbox.register("mutate", tools.mutUniformInt, low=0, up=3, indpb=0.05)
toolbox.register("select", tools.selTournament, tournsize=4)
这四个别名函数的详细说明:
- mate (交叉) 注册为 tools 函数 cxTwoPoint() 的别名,这将创建执行两点交叉的toolbox.mate算子
- mutate (变异) 注册为 tools 函数 mutUniformInt() 的别名,并将 indpb 参数设置为 0.05,这将创建一个翻转每个特征的概率为 0.05 的位翻转突变算子。且特征被赋0、1、2或3分的可能值
- select (选择保留最佳个体)注册为 tools 函数 selTournament() 的别名,且 tournsize 参数设置为 4。这将创建 toolbox.select 运算符,其为锦标赛规模为 4 的锦标赛选择算子(即,对后代个体的选择是基于4个随机抽取的父母个体,然后选择最好的一个)
mutate方法
这个函数适用于输入个体的平均值和标准差的高斯突变
mu:python中基于平均值的高斯变异
sigma:python中基于标准差的高斯变异
indpb:每个属性的独立变异概率
常用实现函数 tools 模块
提供了各种遗传算子的实现,以下列示常用遗传算子的实现函数。
选择算子 主要包括:
selRoulette() #轮盘选择
selStochasticUniversalSampling() #随机遍历采样(SUS)
selTournament() #锦标赛选择
交叉算子 主要包括:
cxOnePoint() #单点交叉
cxUniform() #均匀交叉
cxOrdered() #有序交叉
cxPartialyMatched() #实现部分匹配交叉
突变算子 主要包括:
mutFlipBit() #位翻转突变
mutGaussian() #正态分布突变
计算适应度
evaluate : 选择评价函数,要注意返回值的地方最后面要多加一个逗号
def tirads_auc_loss(w):
# Add 0 points for cystic and spongiform features which are not optimized
# 未优化的囊状和海绵状特征添加0个点
w = np.array([w[:1] + [0] + w[1:3] + [0] + w[3:]])
X = df_features.as_matrix()
# Give 0 total points for all cystic and spongiform nodules
# 所有囊性及海绵状结节加0分
x_cyst = X[:, 1]
x_cyst = np.abs(x_cyst - 1)
x_spon = X[:, 4]
x_spon = np.abs(x_spon - 1)
X = X * np.expand_dims(x_cyst, axis=-1)
X = X * np.expand_dims(x_spon, axis=-1)
# Compute AI TI-RADS points
# 计算AI TI-RADS点
ai_tirads_points = np.dot(X, w.T).flatten()
return roc_auc_score(y_true_train, ai_tirads_points),
toolbox.register("evaluate", tirads_auc_loss)
计算程序 Algorithms
epochs = 50
# Random seed for reproducibility
# 随机种子的可重复性,确保可以复现结果
random.seed(0)