遗传算法与深度学习实战(36)——NEAT详解与实现
- 0. 前言
- 1. NEAT 算法概述
- 2. NEAT-Python 库安装
- 3. 构建 NEAT 网络解决一阶异或问题
- 小结
- 系列链接
0. 前言
NEAT
(NeuroEvolution of Augmenting Topologies
, 增强拓扑的神经进化)属于神经进化算法家族,能够对神经网络的拓扑结构和连接权重进行进化。其用于进化复杂人工神经网络 (Artificial neural networks
, ANN
),旨在通过在进化过程中逐步完善 ANN
的结构来减少参数搜索空间的维数。在本节中,我们将介绍 NEAT
框架,并构建 NEAT
网络以解决经典的一阶异或问题。
1. NEAT 算法概述
NEAT
由 Ken Stanley
于 2002
年开发,NEAT
框架将神经网络与进化计算相结合,不仅优化超参数、权重参数和架构,还优化了神经网络的实际连接方式。
下图对比了常规深度学习网络和进化后的 NEAT
网络,进化后的 NEAT
网络添加/删除了连接,并且删除/改变了节点。请注意,这与我们之前仅仅改变深度学习 (Deep learning
, DL
) 连接层中节点数量的努力有所不同。
NEAT
将进化 DL
网络的概念推到了极限,允许网络的神经连接和节点数量进行进化。由于 NEAT
还进化了每个节点的网络权重,因此可以消除使用微积分计算反向传播误差的复杂性。这使得 NEAT
网络可以进化成复杂的相互连接的图,甚至允许网络进化出循环连接。
在本节中,我们将介绍 NEAT
的基础知识,并深入研究 Python
实现 NEAT-Python
,这个框架抽象出设置进化和 DL
系统的细节。NEAT
包含多个组件:
- 参数的神经进化:
NEAT
中的权重和参数作为系统的一部分进行进化 - 结构的神经进化:
NEAT
进化网络层,并且结构本身通过进化进行调整 - 超参数优化:
NEAT
不使用学习率、优化器或其他标准的DL
辅助工具。因此,它不需要优化这些参数,但NEAT
引入了另外的超参数来控制网络的进化
2. NEAT-Python 库安装
NEAT-Python
的最佳安装方法直接从 GitHub
存储库安装,而非 PyPi
包。使用 pip
命令安装 NEAT-Python
:
$ pip install git+https://github.com/CodeReclaimers/neat-python.git
安装完成后,使用 import neat
导入NEAT-Python
库:
import neat
3. 构建 NEAT 网络解决一阶异或问题
在本节中,我们将构建 NEAT
网络以解决经典的一阶异或问题。NEAT
提供了多个配置选项,在本节中我们将介绍一些重要的选项。
(1) 构建数据集,包含异或输入 (X
) 和异或输出 (Y
):
xor_inputs = [(0.0, 0.0), (0.0, 1.0), (1.0, 0.0), (1.0, 1.0)]
xor_outputs = [ (0.0,), (1.0,), (1.0,), (0.0,)]
(2) 构建评估函数计算演化的 NEAT
网络的适应度。与 DEAP
不同,评估函数接受一组称为基因组的基因序列,函数循环遍历基因组,并为每个基因组计算适应度,首先赋予一些最大适应度。然后,使用 FeedForwardNetwork.create
函数传入基因组和配置文件创建一个经典前馈网络。构建网络后使用 net.activate
函数对所有数据进行激活运算,传入 X
并产生输出 Y
。在激活每个输入后,将输出与期望输出 xo
进行比较,并从基因组适应度中减去均方误差 (Mean squared error
, MSE
)。最后,eval_genomes
函数的结果更新了每个进化基因组的当前适应度:
def eval_genomes(genomes, config):for genome_id, genome in genomes:genome.fitness = 4.0net = neat.nn.FeedForwardNetwork.create(genome, config)for xi, xo in zip(xor_inputs, xor_outputs):output = net.activate(xi) genome.fitness -= (output[0] - xo[0]) ** 2
(3) 设置用于配置和运行 NEAT
代码的配置文件 config
,NEAT-Python
主要是通过配置驱动的,可以修改或调整多个选项。配置从设置适应度标准、适应度阈值、种群大小和重置选项开始。然后,设置默认的基因组配置,首先是激活选项,本节仅使用 sigmoid
函数,NEAT
允许从多个激活函数中选择,用于内部互连节点和输出:
[NEAT]
fitness_criterion = max
fitness_threshold = 3.99
pop_size = 150
reset_on_extinction = False[DefaultGenome]
# node activation options
activation_default = sigmoid
activation_mutate_rate = 0.0
activation_options = sigmoid# node aggregation options
aggregation_default = sum
aggregation_mutate_rate = 0.0
aggregation_options = sum# node bias options
bias_init_mean = 0.0
bias_init_stdev = 1.0
bias_max_value = 30.0
bias_min_value = -30.0
bias_mutate_power = 0.5
bias_mutate_rate = 0.7
bias_replace_rate = 0.1# genome compatibility options
compatibility_disjoint_coefficient = 1.0
compatibility_weight_coefficient = 0.5# connection add/remove rates
conn_add_prob = 0.5
conn_delete_prob = 0.5# connection enable options
enabled_default = True
enabled_mutate_rate = 0.01feed_forward = True
initial_connection = full# node add/remove rates
node_add_prob = 0.2
node_delete_prob = 0.2# network parameters
num_hidden = 0
num_inputs = 2
num_outputs = 1# node response options
response_init_mean = 1.0
response_init_stdev = 0.0
response_max_value = 30.0
response_min_value = -30.0
response_mutate_power = 0.0
response_mutate_rate = 0.0
response_replace_rate = 0.0# connection weight options
weight_init_mean = 0.0
weight_init_stdev = 1.0
weight_max_value = 30
weight_min_value = -30
weight_mutate_power = 0.5
weight_mutate_rate = 0.8
weight_replace_rate = 0.1[DefaultSpeciesSet]
compatibility_threshold = 3.0[DefaultStagnation]
species_fitness_func = max
max_stagnation = 20
species_elitism = 2[DefaultReproduction]
elitism = 2
survival_threshold = 0.2
(4) 演化 NEAT
网络。首先加载配置并设置基因型、繁殖、物种分化和停滞等。然后,根据配置文件创建基因组种群。然后,将报告器 StdOutReporter
添加到种群对象中以跟踪进化过程:
# Load configuration.
config = neat.Config(neat.DefaultGenome, neat.DefaultReproduction,neat.DefaultSpeciesSet, neat.DefaultStagnation,'config')# Create the population, which is the top-level object for a NEAT run.
p = neat.Population(config)# Add a stdout reporter to show progress in the terminal.
p.add_reporter(neat.StdOutReporter(False))
(5) 通过在种群对象上调用 run()
函数来执行种群的进化。进化完成后,打印出适应度最佳的基因组,并输出预测结果:
# Run until a solution is found.
winner = p.run(eval_genomes)# Display the winning genome.
print('\nBest genome:\n{!s}'.format(winner))# Show output of the most fit genome against training data.
print('\nOutput:')
winner_net = neat.nn.FeedForwardNetwork.create(winner, config)
for xi, xo in zip(xor_inputs, xor_outputs):output = winner_net.activate(xi)print(" input {!r}, expected output {!r}, got {!r}".format(xi, xo, output))
运行结果如下所示,与 DEAP
不同,NEAT-Python
使用适应度阈值控制进化迭代,在配置设置中,将适应度阈值 fitness_threshold
设置为 3.99
。可以看到,网络配置和权重以文本形式输出,以及 XOR
输入的正确预测能力。
可以通过完成以下问题进一步了解 NEAT
:
- 修改种群大小 (
pop_size
),然后重新运行代码,观察种群大小对进化的影响 - 减小
fitness_threshold
,然后观察重新运行代码后的结果有何变化 - 改变输入或输出以匹配其它函数,然后,重新运行代码以查看近似新函数的结果
小结
本节介绍了如何快速设置 NEAT
进化,以创建能够预测 XOR
函数的网络,代码抽象了很多细节,以专注于理解 NEAT
内部工作原理。
系列链接
遗传算法与深度学习实战(1)——进化深度学习
遗传算法与深度学习实战(2)——生命模拟及其应用
遗传算法与深度学习实战(3)——生命模拟与进化论
遗传算法与深度学习实战(4)——遗传算法(Genetic Algorithm)详解与实现
遗传算法与深度学习实战(5)——遗传算法中常用遗传算子
遗传算法与深度学习实战(6)——遗传算法框架DEAP
遗传算法与深度学习实战(7)——DEAP框架初体验
遗传算法与深度学习实战(8)——使用遗传算法解决N皇后问题
遗传算法与深度学习实战(9)——使用遗传算法解决旅行商问题
遗传算法与深度学习实战(10)——使用遗传算法重建图像
遗传算法与深度学习实战(11)——遗传编程详解与实现
遗传算法与深度学习实战(12)——粒子群优化详解与实现
遗传算法与深度学习实战(13)——协同进化详解与实现
遗传算法与深度学习实战(14)——进化策略详解与实现
遗传算法与深度学习实战(15)——差分进化详解与实现
遗传算法与深度学习实战(16)——神经网络超参数优化
遗传算法与深度学习实战(17)——使用随机搜索自动超参数优化
遗传算法与深度学习实战(18)——使用网格搜索自动超参数优化
遗传算法与深度学习实战(19)——使用粒子群优化自动超参数优化
遗传算法与深度学习实战(20)——使用进化策略自动超参数优化
遗传算法与深度学习实战(21)——使用差分搜索自动超参数优化
遗传算法与深度学习实战(22)——使用Numpy构建神经网络
遗传算法与深度学习实战(23)——利用遗传算法优化深度学习模型
遗传算法与深度学习实战(24)——在Keras中应用神经进化优化
遗传算法与深度学习实战(25)——使用Keras构建卷积神经网络
遗传算法与深度学习实战(26)——编码卷积神经网络架构
遗传算法与深度学习实战(27)——进化卷积神经网络
遗传算法与深度学习实战(28)——卷积自编码器详解与实现
遗传算法与深度学习实战(29)——编码卷积自编码器架构
遗传算法与深度学习实战(30)——使用遗传算法优化自编码器模型
遗传算法与深度学习实战(31)——变分自编码器详解与实现
遗传算法与深度学习实战(32)——生成对抗网络详解与实现
遗传算法与深度学习实战(33)——WGAN详解与实现
遗传算法与深度学习实战(34)——编码WGAN
遗传算法与深度学习实战(35)——使用遗传算法优化生成对抗网络