登入帳戶  | 訂單查詢  | 購物車/收銀台( 0 ) | 在線留言板  | 付款方式  | 聯絡我們  | 運費計算  | 幫助中心 |  加入書簽
會員登入 新註冊 | 新用戶登記
HOME新書上架暢銷書架好書推介特價區會員書架精選月讀2023年度TOP分類閱讀雜誌 香港/國際用戶
最新/最熱/最齊全的簡體書網 品種:超過100萬種書,正品正价,放心網購,悭钱省心 送貨:速遞 / EMS,時效:出貨後2-3日

2024年03月出版新書

2024年02月出版新書

2024年01月出版新書

2023年12月出版新書

2023年11月出版新書

2023年10月出版新書

2023年09月出版新書

2023年08月出版新書

2023年07月出版新書

2023年06月出版新書

2023年05月出版新書

2023年04月出版新書

2023年03月出版新書

2023年02月出版新書

『簡體書』Python神经进化网络实战

書城自編碼: 3621262
分類: 簡體書→大陸圖書→教材研究生/本科/专科教材
作者: [美]雅罗斯拉夫尔·连奥米恩科 著,黄永强 译
國際書號(ISBN): 9787302571285
出版社: 清华大学出版社
出版日期: 2021-03-01

頁數/字數: /
書度/開本: 16开 釘裝: 平装

售價:NT$ 782

我要買

share:

** 我創建的書架 **
未登入.



新書推薦:
饲渊
《 饲渊 》

售價:NT$ 223.0
现金为王:把利润留下来,把成本降下去
《 现金为王:把利润留下来,把成本降下去 》

售價:NT$ 386.0
经纬度丛书·巴勒斯坦人的故事:流亡者的悲情、绝望与抗争
《 经纬度丛书·巴勒斯坦人的故事:流亡者的悲情、绝望与抗争 》

售價:NT$ 493.0
改变世界的哲学家们
《 改变世界的哲学家们 》

售價:NT$ 493.0
将军
《 将军 》

售價:NT$ 269.0
墓志的生成及其在唐代的衍变研究
《 墓志的生成及其在唐代的衍变研究 》

售價:NT$ 549.0
理解中国经济:在大变局中读懂新机遇
《 理解中国经济:在大变局中读懂新机遇 》

售價:NT$ 252.0
饥饿与国家:苏丹的饥荒、奴隶制和权力(1883~1956)
《 饥饿与国家:苏丹的饥荒、奴隶制和权力(1883~1956) 》

售價:NT$ 386.0

建議一齊購買:

+

NT$ 380
《 医用仪器软件设计——基于Qt(Windows版) 》
+

NT$ 210
《 机器学习基础教程 》
+

NT$ 234
《 概率统计与建模(第三版) 》
+

NT$ 289
《 科技文献检索与利用(第二版) 》
+

NT$ 271
《 理论力学 》
+

NT$ 516
《 宏观经济学(第十三版)(经济科学译丛) 》
編輯推薦:
本书讨论了传统的深度机器学习方法的可行替代方案—神经进化算法。神经进化是一系列机器学习方法,它们使用进化算法来简化对复杂任务的解决,如游戏、机器人和自然过程的仿真。
內容簡介:
本书详细阐述了与神经进化网络开发相关的基本解决方案,主要包括神经进化方法概述、Python库和环境设置、使用NEAT进行XOR求解器优化、摆杆平衡实验、自主迷宫导航、新颖性搜索优化方法、基于超立方体的NEAT和视觉辨别、ES-HyperNEAT和视网膜问题、协同进化和SAFE方法、深度神经进化等内容。此外,本书还提供了相应的示例、代码,以帮助读者进一步理解相关方案的实现过程。 本书适合作为高等院校计算机及相关专业的教材和教学参考书,也可作为相关开发人员的自学教材和参考手册。
關於作者:
雅罗斯拉夫尔·连奥米恩科担任首席技术官和研究主管超过10年。他是机器学习研究领域的活跃成员,并在arXiv、ResearchGate平台以及Preprints等刊物上发表了若干篇研究论文。10多年前,他开发了用于手机游戏的自主代理,此后一直从事机器学习的应用。在过去的5年中,他积极参与有关将深度机器学习方法应用于身份验证、个人特征识别、协作机器人技术和合成智能等的研究。他还是一名活跃的软件开发人员,使用Go语言创建了开源神经进化算法的实现。
目錄
第1部分 进化计算算法和神经进化方法的基本原理
第1章 神经进化方法概述 3
1.1 进化算法和基于神经进化的方法 3
1.1.1 遗传算子 5
1.1.2 基因组编码方案 7
1.1.3 协同进化 9
1.1.4 模块化和层次结构 9
1.2 关于NEAT算法 10
1.2.1 NEAT编码方案 10
1.2.2 结构变异 12
1.2.3 使用创新数字交叉 13
1.2.4 物种形成 14
1.3 基于超立方体的NEAT 16
1.3.1 复合模式生成网络 16
1.3.2 基板配置 18
1.3.3 不断进化的连接CPPN和HyperNEAT算法 18
1.4 可进化基板HyperNEAT 20
1.4.1 超立方体中的信息模式 20
1.4.2 使用四叉树作为有效的信息提取器 21
1.4.3 ES-HyperNEAT算法 23
1.5 新颖性搜索优化方法 26
1.5.1 新颖性搜索与自然进化 26
1.5.2 新颖性度量 27
1.6 小结 29
1.7 延伸阅读 29

第2章 Python库和环境设置 31
2.1 适用于神经进化实验的Python库 31
2.1.1 NEAT-Python 31
2.1.2 NEAT-Python用法示例 32
2.1.3 PyTorch NEAT 33
2.1.4 PyTorch NEAT用法示例 34
2.1.5 MultiNEAT 35
2.1.6 MultiNEAT用法示例 36
2.1.7 深度神经进化 37
2.1.8 比较Python神经进化库 40
2.2 环境设定 41
2.2.1 Pipenv 41
2.2.2 Virtualenv 42
2.2.3 Anaconda 43
2.3 小结 44
第2部分 运用神经进化方法解决经典计算机科学问题
第3章 使用NEAT进行XOR求解器优化 47
3.1 技术要求 47
3.2 XOR问题基础知识 47
3.3 XOR实验的目标函数 49
3.4 超参数选择 50
3.4.1 NEAT部分 50
3.4.2 DefaultStagnation部分 51
3.4.3 DefaultReproduction部分 51
3.4.4 DefaultSpeciesSet部分 52
3.4.5 DefaultGenome部分 52
3.4.6 XOR实验超参数 54
3.5 运行XOR实验 56
3.5.1 环境设置 56
3.5.2 XOR实验源代码 57
3.5.3 运行实验并分析结果 60
3.6 练习 65
3.7 小结 67
第4章 摆杆平衡实验 69
4.1 技术要求 69
4.2 单杆平衡问题 69
4.2.1 单杆平衡器的运动方程 70
4.2.2 状态公式和控制动作 72
4.2.3 求解器与模拟器之间的交互 72
4.3 单杆平衡实验的目标函数 74
4.3.1 小车-摆杆装置模拟 74
4.3.2 模拟循环 75
4.3.3 基因组适应度评估 77
4.4 单杆平衡实验 78
4.4.1 超参数选择 78
4.4.2 工作环境设置 79
4.4.3 实验运行程序的实现 80
4.4.4 运行单杆平衡实验 82
4.5 练习1 85
4.6 双杆平衡问题 85
4.6.1 系统状态和运动方程 86
4.6.2 强化信号 89
4.6.3 初始条件和状态更新 89
4.6.4 控制动作 91
4.6.5 求解器与模拟器之间的相互作用 91
4.7 双杆平衡实验的目标函数 92
4.8 双杆平衡实验 93
4.8.1 超参数选择 93
4.8.2 工作环境设置 95
4.8.3 实验运行程序的实现 95
4.8.4 运行双杆平衡实验 96
4.9 练习2 100
4.10 小结 100
第5章 自主迷宫导航 103
5.1 技术要求 103
5.2 迷宫导航问题 103
5.3 迷宫模拟环境 105
5.3.1 迷宫导航代理 105
5.3.2 迷宫模拟环境的实现 107
5.3.3 传感器数据生成 108
5.3.4 代理位置更新 109
5.3.5 代理记录存储 111
5.3.6 代理记录可视化 113
5.4 使用适应度评分的目标函数定义 114
5.5 使用简单迷宫地形运行实验 115
5.5.1 超参数选择 116
5.5.2 迷宫配置文件 117
5.5.3 工作环境设置 118
5.5.4 实验运行程序的实现 118
5.5.5 基因组适应度评估 120
5.5.6 运行简单迷宫导航实验 121
5.5.7 代理记录可视化 125
5.6 练习1 126
5.7 使用难以解决的迷宫配置运行实验 126
5.7.1 超参数选择 127
5.7.2 工作环境设置和实验运行程序实现 127
5.7.3 运行困难级迷宫导航实验 127
5.8 练习2 130
5.9 小结 130
第6章 新颖性搜索优化方法 131
6.1 技术要求 131
6.2 新颖性搜索优化方法 131
6.3 新颖性搜索实现的基础 132
6.3.1 关于NoveltyItem 133
6.3.2 关于NoveltyArchive 133
6.4 适应度函数与新颖性评分 136
6.4.1 新颖性评分 136
6.4.2 新颖性度量指标 139
6.4.3 适应度函数 139
6.4.4 种群适应度评估函数 140
6.4.5 个体适应度评估函数 142
6.5 使用简单迷宫配置进行实验 145
6.5.1 超参数选择 145
6.5.2 工作环境设置 146
6.5.3 实验运行程序的实现 146
6.5.4 运行新颖性搜索优化的简单迷宫导航实验 150
6.5.5 代理记录可视化 153
6.5.6 练习1 155
6.6 使用难以解决的迷宫配置进行实验 155
6.6.1 超参数选择和工作环境设置 156
6.6.2 运行难以解决的迷宫导航实验 156
6.6.3 练习2 158
6.7 小结 159
第3部分 高级神经进化方法
第7章 基于超立方体的NEAT和视觉辨别 163
7.1 技术要求 163
7.2 使用CPPN对ANN进行间接编码 163
7.2.1 CPPN编码 164
7.2.2 基于超立方体的增强拓扑的神经进化 165
7.3 视觉辨别实验的基础知识 165
7.4 视觉辨别实验设置 167
7.4.1 视觉辨别器测试环境 168
7.4.2 可视域定义 168
7.4.3 视觉辨别器环境 170
7.4.4 实验运行程序 175
7.4.5 实验运行程序函数 175
7.4.6 基板生成器函数 179
7.4.7 适应度评估 180
7.5 视觉辨别实验 182
7.5.1 超参数选择 182
7.5.2 工作环境设置 183
7.5.3 运行视觉辨别实验 184
7.6 练习 188
7.7 小结 188
第8章 ES-HyperNEAT和视网膜问题 189
8.1 技术要求 189
8.2 手动建立的神经节点拓扑形态和基于进化配置的神经网络拓扑形态 190
8.3 四叉树信息提取和ES-HyperNEAT基础知识 191
8.4 模块化视网膜问题的基础知识 193
8.5 目标函数定义 195
8.6 模块化视网膜实验设置 196
8.6.1 初始基板配置 196
8.6.2 模块化视网膜问题的测试环境 197
8.6.3 可视对象定义 197
8.6.4 视网膜环境定义 198
8.7 实验运行程序 201
8.7.1 实验运行程序的函数 201
8.7.2 基板生成器函数 205
8.7.3 适应度评估 206
8.8 模块化视网膜实验 208
8.8.1 超参数选择 208
8.8.2 工作环境设置 209
8.8.3 运行模块化视网膜实验 210
8.9 练习 214
8.10 小结 214
第9章 协同进化和SAFE方法 215
9.1 技术要求 215
9.2 协同进化基础知识和常见协同进化策略 215
9.3 关于SAFE算法 216
9.4 改进的迷宫实验介绍 217
9.4.1 迷宫求解代理 217
9.4.2 迷宫环境 218
9.5 适应度函数定义 219
9.5.1 迷宫求解器的适应度函数 219
9.5.2 目标函数候选者的适应度函数 220
9.6 改进的新颖性搜索方法 221
9.6.1 关于_add_novelty_item函数 221
9.6.2 关于evaluate_novelty_score函数 222
9.7 改进的迷宫实验实现 223
9.7.1 协同进化的种群的创建 223
9.7.2 创建目标函数候选者的种群 223
9.7.3 创建迷宫求解器的种群 224
9.8 协同进化种群的适应度评估 225
9.8.1 目标函数候选者的适应度评估 225
9.8.2 迷宫求解器代理的适应度评估 227
9.9 改进的迷宫实验运行程序 230
9.10 改进的迷宫实验的参数设置和运行 233
9.10.1 迷宫求解器种群的超参数 233
9.10.2 目标函数候选者种群的超参数 234
9.10.3 工作环境设置 234
9.10.4 运行修改后的迷宫实验 234
9.11 练习 237
9.12 小结 237

第10章 深度神经进化 239
10.1 技术要求 239
10.2 用于深度强化学习的深度神经进化 240
10.3 使用深层神经进化训练代理玩游戏 241
10.3.1 关于Frostbite游戏 241
10.3.2 将游戏画面映射到动作 242
10.3.3 卷积层 243
10.3.4 训练游戏代理的卷积神经网络架构 244
10.4 针对游戏代理的强化学习训练 245
10.4.1 基因组编码方案 245
10.4.2 简单遗传算法 247
10.5 训练代理玩Frostbite游戏 248
10.5.1 Atari学习环境 248
10.5.2 游戏步进函数 249
10.5.3 游戏观察函数 249
10.5.4 重置Atari环境函数 250
10.6 在GPU核心上的强化学习评估 250
10.6.1 RLEvalutionWorker类 251
10.6.2 ConcurrentWorkers类 254
10.7 实验运行程序 256
10.7.1 实验配置文件 256
10.7.2 实验运行程序的实现 258
10.8 运行Frostbite游戏实验 260
10.8.1 设置工作环境 260
10.8.2 运行实验 262
10.8.3 可视化游戏过程 263
10.9 神经进化的可视检查器 264
10.9.1 建立工作环境 264
10.9.2 使用VINE进行实验的可视化 264
10.10 练习 266
10.11 小结 266

第4部分 复习和总结
第11章 实践和技巧提示 269
11.1 从问题分析开始 269
11.1.1 预处理数据 269
11.1.2 理解问题领域 272
11.1.3 编写良好模拟器 272
11.2 选择搜索优化方法 272
11.2.1 面向目标的搜索优化 273
11.2.2 新颖性搜索优化 273
11.3 高级可视化 274
11.4 调整超参数 275
11.5 性能指标 276
11.5.1 精确率 277
11.5.2 召回率 277
11.5.3 准确率 278
11.5.4 F1分数 278
11.5.5 ROC AUC 278
11.6 Python编码技巧 280
11.6.1 编码技巧 280
11.6.2 工作环境和编程工具 281
11.7 小结 282
第12章 总结 283
12.1 本书内容复习 283
12.1.1 神经进化方法概述 283
12.1.2 Python库和环境设置 285
12.1.3 使用NEAT进行XOR求解器优化 285
12.1.4 摆杆平衡实验 286
12.1.5 自主迷宫导航 287
12.1.6 新颖性搜索优化方法 288
12.1.7 基于超立方体的NEAT和视觉辨别 289
12.1.8 ES-HyperNEAT和视网膜问题 290
12.1.9 协同进化与SAFE方法 290
12.1.10 深度神经进化 291
12.2 相关资料 292
12.2.1 优步AI实验室 292
12.2.2 alife.org 292
12.2.3 来自Reddit的开放式进化社区 293
12.2.4 NEAT软件目录 293
12.2.5 arXiv.org 293
12.2.6 NEAT算法论文 293
12.3 小结 294
內容試閱
传统的深度学习方法在功能上几乎已经触顶,越来越多的研究人员开始寻找训练人工神经网络的替代方法。
深度机器学习对于模式识别非常有效,但是却无法解决需要理解背景环境的任务。许多研究人员,包括现代深度机器学习之父Geoff Hinton都认同,目前设计人工智能系统的方法不再能够应对当前面临的挑战。
本书讨论了传统的深度机器学习方法的可行替代方案—神经进化算法。神经进化是一系列机器学习方法,它们使用进化算法来简化对复杂任务的解决,如游戏、机器人和自然过程的仿真。
神经进化算法的灵感来自于自然选择的过程。非常简单的人工神经网络可能会变得非常复杂。神经进化的终结果是网络的拓扑形态,这使模型更节能,更易于分析。
在本书中,读者将学习到各种神经进化算法,并获得使用它们来解决不同的计算机科学问题的实用技能,从经典的强化学习到构建用于迷宫自动导航的代理。此外,读者还将学习如何使用神经进化来训练深度神经网络,从而创建可以玩经典Atari游戏的机器人代理。
本书通过各种实验,循序渐进,使读者对神经进化方法有深入的理解。它涵盖了游戏、机器人和自然过程模拟等领域的实际示例,并使用实际示例和数据集来帮助读者更好地理解所探索的概念。在通读完本书之后,读者将能够完成本书所演示的实验,并且举一反三,将神经进化方法应用于自己的工作和研究。
我们编写本书的目标是为读者提供前沿的技术知识,这是传统深度学习的重要替代方法。我们希望神经进化算法在项目中的实际应用能使读者以一种优雅且节能的方式解决当前棘手的问题。
本书读者
本书适用于希望从头开始实现神经进化算法的机器学习从业人员、深度学习研究人员和AI爱好者。读者将学习到如何将这些算法应用于各种实际问题,掌握神经进化方法优化训练人工神经网络的过程,熟悉神经进化的核心概念,并获得在工作和实验中使用它的必要实践技能。学习本书之前,读者必须具备一定的Python和深度学习以及神经网络基础知识。
内容介绍
本书共分4个部分。
? 第1部分为“进化计算算法和神经进化方法的基本原理”,包括第1章和第2章。
? 第1章“神经进化方法概述”,介绍了遗传算法的核心概念,如遗传算子和基因组编码方案。另外,还简要介绍了4种神经进化算法。
? 第2章“Python库和环境设置”,讨论了神经进化方法的实际操作。本章介绍了流行的Python库的优缺点,这些库提供了NEAT算法及其扩展的实现。
? 第2部分为“运用神经进化方法解决经典计算机科学问题”,包括第3~6章。
? 第3章“使用NEAT进行XOR求解器优化”,通过实现经典计算机科学问题的求解器开始尝试NEAT算法。
? 第4章“摆杆平衡实验”,介绍了与强化学习领域中计算机科学经典问题相关的小车-摆杆平衡实验。
? 第5章“自主迷宫导航”,尝试创建可以从迷宫中找到出口的求解器代理。读者将学习如何对具有多个传感器的机器人进行模拟,以检测障碍物并监控其在迷宫中的位置。
? 第6章“新颖性搜索优化方法”,使用在第5章的迷宫求解器创建过程中获得的实践经验来着手创建更高级的求解器。
? 第3部分为“高级神经进化方法”,包括第7~10章。
? 第7章“基于超立方体的NEAT和视觉辨别”,介绍了高级神经进化方法。读者将学习间接基因组编码方案,该方案使用复合模式生成网络(CPPN)来协助对较大的表现型ANN拓扑形态进行编码。
? 第8章“ES-HyperNEAT和视网膜问题”,介绍了如何选择适合特定问题空间的基板配置。
? 第9章“协同进化和SAFE方法”,讨论了在自然界中广泛发现的协同进化策略,并介绍了将共栖策略转移到神经进化领域的方法。
? 第10章“深度神经进化”,介绍了深度神经进化的概念,该概念可用于训练深度人工神经网络(DNN)。此外,本章进行了训练代理玩Frostbite游戏的实验。
? 第4部分为“复习和总结”,包括第11章和第12章。
? 第11章“实践和技巧提示”,指导读者如何着手解决当前遇到的问题,如何调整神经进化算法的超参数以及如何使用高级可视化工具等。此外,本章还介绍了可用于分析算法性能的指标和Python编码技巧等。
? 第12章“总结”,对读者在本书中学到的所有内容进行复习,并为读者提供了继续自学的一些资料。
充分利用本书
Python编程语言的实践知识对于使用本书中提供的示例至关重要。为了更好地理解源代码,好使用支持Python语法突出显示和代码引用位置的集成开发环境。如果读者尚未安装,本书推荐使用Microsoft Visual Studio Code。它是免费的跨平台开发工具,读者可以访问以下网址下载:
https://code.visualstudio.com
Python和我们在本书中讨论的大多数库都是跨平台的,并且与Windows、Linux和mac OS兼容。本书描述的所有实验都是从命令行执行的,因此应熟悉所选操作系统上安装的终端控制台应用程序。
要完成本书第10章“深度神经进化”中描述的实验,读者需要使用配备NVIDIA显卡GeForce GTX 1080 Ti或更高版本的性能较高的计算机。在Ubuntu Linux环境中运行该实验效果会更好。Ubuntu是一个免费的、功能强大的、基于Linux的现代操作系统。熟悉它,会为Python开发带来很多帮助。
下载示例代码文件
读者可以从www.packtpub.com下载本书的示例代码文件。具体步骤如下:
(1)登录或注册www.packtpub.com。
(2)在页面顶部的搜索框中输入图书名称Hands-On-NeuroEvolution-with-Python,如图P-1所示。

图P-1
(3)在出现本书搜索结果后,单击View Details(查看详情)按钮,如图P-2所示。

图P-2
(4)在本书详情页面中,找到并单击Download code files(下载代码文件)按钮,如图P-3所示。

图P-3
(5)在本书源代码页面中,单击右侧Code(代码)按钮,在弹出的下拉菜单中选择Download ZIP(下载压缩包),如图P-4所示。

图P-4
下载文件后,请确保使用版本解压缩或解压缩文件夹:
? WinRAR/7-Zip(Windows系统)
? Zipeg/iZip/UnRarX(Mac系统)
? 7-Zip/PeaZip(Linux系统)
该书的代码包也已经在GitHub上托管,网址如下,欢迎访问:
https://github.com/PacktPublishing/Hands-on-Neuroevolution-with-Python
如果代码有更新,则也会在现有GitHub存储库上更新。
下载彩色图像
我们还提供了一个PDF文件,其中包含本书中使用的屏幕截图、图表的彩色图像,读者可以通过以下网址下载:
https://static.packt-cdn.com/downloads/9781838824914_ColorImages.pdf
本书约定
本书使用了许多文本约定。
(1)CodeInText:表示文本中的代码字、数据库表名、文件夹名、文件名、文件扩展名、路径名、虚拟URL、用户输入和Twitter句柄等。有关该实现的详细信息,请参阅以下网址的agent.py文件:
https://github.com/PacktPublishing/Hands-on-Neuroevolution-with-Python/blob/master/ Chapter5/agent.py
(2)有关代码块的设置如下:
if indices is None:
indices = np.arange(self.batch_size)
(3)任何命令行输入或输出都采用如下所示的粗体代码形式:
$ conda create -n deep_ne python=3.5
(4)术语或重要单词采用中英文对照形式,在括号内保留其英文原文。示例如下:
当从目标点到机器人中心的线落入其视野(Field Of View,FOV,也称为视场)内时,特定的雷达传感器将被激活。
(5)本书还使用了以下两个图标。
图标表示警告或重要的注意事项。
图标表示提示或小技巧。
关于作者
Iaroslav Omelianenko担任首席技术官和研究主管超过10年。他是机器学习研究领域的活跃成员,并在arXiv、ResearchGate平台以及Preprints等刊物上发表了若干篇研究论文。10多年前,他开发了用于手机游戏的自主代理,此后一直从事机器学习的应用。在过去的5年中,他积极参与有关将深度机器学习方法应用于身份验证、个人特征识别、协作机器人技术和合成智能等的研究。他还是一名活跃的软件开发人员,使用Go语言创建了开源神经进化算法的实现。
“我要感谢所有研究人员和开发人员在开源理想的启发下分享他们的工作。没有开放源代码社区,我们的世界将不会像今天这样绚丽多彩。”
关于审稿人
Alan McIntyre是CodeReclaimers公司的首席软件架构师,主要为计算应用程序提供定制软件设计和开发服务,包括计算几何、计算机视觉和机器学习等。他之前曾在通用电气、微软和多家初创公司担任软件工程师。
Unsal Gokdag,2017年以来一直在物流领域担任全职高级数据科学家,此前曾在2013年担任研发工程师。他目前正在攻读博士学位,研究方向是用于图像去斑和偏振SAR图像分类的机器学习算法的比较。他曾从事机器学习、计算机视觉和生物信息学方面的工作。在撰写本科学士学位论文时,他就曾经接触过NEAT算法,此后一直对神经进化算法很感兴趣。他目前居住在德国。

第5章 自主迷宫导航
迷宫导航(Maze Navigation)是与自主导航领域相关的经典计算机科学问题。
在本章,读者将学习如何使用基于神经进化的方法来解决迷宫导航的挑战。此外,我们还将解释如何使用导航机器人代理的适应度得分定义目标导向的适应度函数(该适应度得分是机器人代理与终目标之间距离的导数)。
在学完本章之后,读者将了解到使用神经进化方法训练自主导航机器人代理的基础知识,并为创建更高级的迷宫求解器做好准备。读者将看到高级可视化技术,通过这些技术将更容易理解算法执行的结果。此外,读者还将获得使用Python语言编写迷宫导航机器人和与迷宫环境有关的模拟器的实战经验。
本章将讨论以下主题:
迷宫导航问题的误导性质。编写迷宫导航机器人的模拟器,该模拟器配备了一系列传感器和执行器。定义面向目标的适应度函数,以便在使用神经进化算法创建的迷宫求解器中指引进化的过程。使用简单和困难两种难度级别的迷宫配置运行实验。5.1 技 术 要 求
运行本章实验的技术要求如下。
Windows 8/10、Mac OS 10.13或更高版本、当前版本的Linux。Anaconda发行版03或更高版本。
访问以下网址可获得本章代码:

https://github.com/PacktPublishing/Hands-on-Neuroevolution-with-Python/tree/master/Chapter5

5.2 迷宫导航问题
迷宫导航问题是经典的计算机科学问题,与创建可以在模糊环境中找到路径的自主导航代理(Agent)密切相关。注意,在人工智能领域,Agent通常是指驻留在某一环境下,能持续自主地发挥作用,具备驻留性、反应性、社会性和主动性等特征的计算实体。Agent既可以是软件实体,也可以是硬件实体,所以可以这样理解:Agent是人在AI环境中的代理,是完成各种任务的载体。
迷宫环境是一个很好的演示适应度的误导(欺骗)性问题的领域。在迷宫环境中,面向目标的适应度函数(Goal-Oriented Fitness Function)在接近迷宫终目标点的死胡同中可以具有陡峭的适应度分数梯度。迷宫的这些死胡同区域可能会成为基于目标的搜索算法的局部条件,因此该目标搜索算法可能会收敛于这些区域。当搜索算法收敛于这种误导性的局部时,它将无法找到正确的迷宫求解器代理。
在图5-1所示的示例中,可以看到带有局部死胡同的二维迷宫,所有阴影部分都是有误导性的死胡同区域。
图5-1 二维迷宫结构
图5-1中的迷宫结构直观地显示了误导性适应度评分集中在局部死胡同的情形(以阴影填充)。使用基于目标的搜索算法时,从起始点(底部绿色圆)导航到出口点(顶部红色圆)的迷宫求解器代理很容易就会陷入局部死胡同。同样,诸如此类的误导性适应度评分情况很可能会阻止基于目标的搜索算法成功找到迷宫求解器代理。
我们可以将需要穿越迷宫的代理想象成一个机器人,它配备了一组传感器,可以检测附近的障碍物并找到通往迷宫出口的方向。机器人的运动由两个执行器(Actuator)控制,这两个执行器会影响机器人身体的线性运动和角度运动。机器人的执行器由人工神经网络(ANN)控制,该ANN接收来自传感器的输入并为执行器产生两个控制信号。

5.3 迷宫模拟环境
迷宫模拟的环境由3个主要部分组成,分别作为单独的Python类实现。
Agent类:包含与模拟所使用的迷宫导航器代理相关信息的类(有关其实现的详细信息,参见py文件)。AgentRecordStore类:用于管理与进化过程中所有求解器代理的评估有关的记录的存储。收集的记录可用于在完成进化过程后对其进行分析(有关其实现的详细信息,参见py文件)。MazeEnvironment:包含有关迷宫模拟环境信息的类。该类还提供了管理模拟环境、控制求解器代理的位置、执行碰撞检测以及生成代理的传感器的输入数据的方法(有关其实现的详细信息,参见py文件)。
下面将更详细地研究迷宫模拟环境的各个部分。
5.3.1 迷宫导航代理
本章我们考虑的是二维迷宫导航任务。这个任务很容易可视化,并且为二维迷宫编写迷宫导航机器人的模拟器也相对容易。机器人的主要目标是在指定的时间步骤内穿越迷宫到达定义的出口点。控制机器人的ANN是神经进化过程的产物。
神经进化算法从一个非常基本的初始人工神经网络配置开始,该配置只有传感器的输入节点和执行器的输出节点,人工神经网络会逐渐变得复杂,直至找到成功的迷宫求解器为止。如前文所述,该迷宫的特殊地形具有多个死胡同,使任务变得复杂,因为这会在适应度评分上创建局部值,从而阻止找到通往目标的路线。
图5-2描述了在迷宫求解模拟中使用的迷宫代理的示意图。
图5-2 迷宫代理(机器人)示意图
在图5-2中,实心圆定义了机器人的刚体。实心圆圈内的箭头表示机器人的前进方向。实心圆圈周围的6个箭头表示6个测距仪传感器(Rangefinder Sensor),这些传感器指示在给定方向上到近障碍物的距离。4个外圆线段表示4个扇形雷达传感器(Pie-Slice Radar Sensor),它们充当着指向目标点(迷宫出口)的指南针。
当从目标点到机器人中心的线落入其视野(Field Of View,FOV,也称为视场)内时,特定的雷达传感器将被激活。雷达传感器的检测范围受到落入其FOV的迷宫区域的限制。因此,在任何给定时间,4个雷达传感器之一被激活,指示迷宫出口方向。
雷达传感器相对于机器人的正前方具有的FOV区域如表5-1所示。
表5-1 雷达传感器对应的机器人正前方的视场角

传 感 器

视场角()

传 感 器

视场角()



315.0~405.0



135.0~225.0



45.0~135.0



225.0~315.0


测距仪传感器是从机器人中心沿特定方向绘制的跟踪射线。当与任何障碍物相交时,它将激活,并返回与检测到的障碍物的距离。该传感器的检测范围由特定的配置参数 定义。
机器人的测距仪传感器监视与代理正前方相关的各个方向,如表5-2所示。
表5-2 机器人的测距仪传感器监视的方向

传 感 器

方向()

传 感 器

方向()



-90.0

左前方

45.0

右前方

-45.0



90.0



0.0



-180.0


机器人的运动由两个执行器控制,这两个执行器施加力来转动或推动代理,即改变其线性或角速度。
迷宫求解器代理的Python实现具有多个字段来保存其当前状态并维护其传感器的激活状态,具体如下:

def __init__(self, location, heading=0, speed=0,
angular_vel=0, radius=8.0, range_finder_range=100.0):
self.heading = heading
self.speed = speed
self.angular_vel = angular_vel
self.radius = radius
self.range_finder_range = range_finder_range
self.location = location
# 定义测距仪传感器
self.range_finder_angles = [-90.0, -45.0, 0.0, 45.0, 90.0, -180.0]
# 定义雷达传感器
self.radar_angles = [(315.0, 405.0), (45.0, 135.0),
(135.0, 225.0), (225.0, 315.0)]
# 保存激活的测距仪的列表
self.range_finders = [None] * len(self.range_finder_angles)
# 保存激活的扇形雷达的列表
self.radar = [None] * len(self.radar_angles)
注意:
有关该实现的详细信息,可参见以下网址的agent.py文件:
https://github.com/PacktPublishing/Hands-on-Neuroevolution-with-Python/blob/master/Chapter5/agent.py

上面的代码显示了Agent类的默认构造函数,其中Agent类的所有字段都已被初始化。迷宫环境模拟将使用这些字段在每个模拟步骤中存储代理的当前状态。
5.3.2 迷宫模拟环境的实现
为了模拟在迷宫中导航的求解器代理,我们需要定义一个环境,该环境将管理迷宫墙壁和出口点之类的地形配置,跟踪迷宫求解代理的位置,并为导航机器人的传感器数据数组提供输入。
所有这些功能都将纳入一个逻辑块,该逻辑块封装在MazeEnvironment Python类中,该类具有以下字段(从类构造函数中可以看到):

def __init__(self, agent, walls, exit_point, exit_range=5.0):
self.walls = walls
self.exit_point = exit_point
self.exit_range = exit_range
# 迷宫导航代理
self.agent = agent
# 指示是否找到出口的标志
self.exit_found = False
# 代理与出口的初始距离
self.initial_distance = self.agent_distance_to_exit()

上面的代码显示了MazeEnvironment类的默认构造函数及其所有字段的初始化:
迷宫的配置由wall(墙壁)的列表和exit_point(出口点)确定。墙壁是线段的列表,每个线段代表迷宫中的特定墙壁,而exit_point则是迷宫出口的位置。exit_range字段存储定义出口区域的exit_point周围的距离范围的值。当代理位于该出口区域时,可以认为它已成功解决了迷宫问题。agent字段包含对3.1节中描述的初始化Agent类的引用,该类定义了求解器代理在迷宫中的起始位置,以及其他与代理相关的数据字段。initial_distance字段存储从代理的起始位置到迷宫出口的距离。此值将在以后用于代理的适应度评分计算。5.3.3 传感器数据生成
迷宫求解器代理由ANN控制,该ANN需要接收传感器数据作为输入,以产生相应的控制信号作为输出。如前文所述,导航代理配备了两种传感器。
6个测距仪传感器,用于检测代理与迷宫墙壁的碰撞,指示在特定方向上到近障碍物的距离。4个扇形雷达传感器,指示从迷宫中任何位置到迷宫出口点的方向。
传感器值需要在每个模拟步骤中进行更新,并且MazeEnvironment类提供了两种指定的方法来更新两种类型的传感器。
测距仪传感器的数组更新如下(参见update_rangefinder_sensors函数):

for i, angle in enumerate(self.agent.range_finder_angles):
rad = geometry.deg_to_rad(angle)
projection_point = geometry.Point(
x = self.agent.location.x math.cos(rad) * \ self.agent.range_finder_range,
y = self.agent.location.y math.sin(rad) * \ self.agent.range_finder_range
)
projection_point.rotate(self.agent.heading,
self.agent.location)
projection_line = geometry.Line(a = self.agent.location,
b = projection_point)
min_range = self.agent.range_finder_range
for wall in self.walls:
found, intersection = wall.intersection(projection_line)
if found:
found_range = intersection.distance(
self.agent.location)
if found_range < min_range:
min_range = found_range
# 存储代理到近障碍物的距离
self.agent.range_finders[i] = min_range

上述代码枚举了测距仪传感器的所有检测方向,这些方向由方向角确定(参见Agent构造函数中的range_finder_angles字段初始化)。针对每个方向创建一条投影线,该投影线从代理的当前位置开始,其长度等于测距仪的检测范围。之后,测试投影线是否与任何迷宫的墙壁相交。如果检测到多个交叉点,则到近墙壁的距离将存储为特定测距仪传感器的值。否则,检测范围将保存为测距仪传感器的值。
需要使用MazeEnvironment类中的以下代码来更新扇形雷达传感器的数据:

def update_radars(self):
target = geometry.Point(self.exit_point.x, self.exit_point.y)
target.rotate(self.agent.heading, self.agent.location)
target.x -= self.agent.location.x
target.y -= self.agent.location.y
angle = target.angle()
for i, r_angles in enumerate(self.agent.radar_angles):
self.agent.radar[i] = 0.0 # reset specific radar
if (angle >= r_angles[0] and angle < r_angles[1]) or
(angle 360 >= r_angles[0] and angle 360 < r_angles[1]):
# 激活雷达
self.agent.radar[i] = 1.0

上面的代码将创建迷宫出口点的副本,并相对于代理的正前方(Heading)和全局坐标系内的位置旋转迷宫出口点。平移目标点以使其与迷宫求解器代理的局部坐标系对齐,代理被放置在坐标的原点。之后,计算从坐标的原点到代理的局部坐标系内目标点的矢量角度。该角度是从当前代理位置到迷宫出口点的方位角(Azimuth)。找到方位角后,我们将枚举已注册的扇形雷达传感器,以找到在其视场中包含该方位角的传感器。通过将其值设置为1来激活相应的雷达传感器,而停用其他雷达传感器(将其值清零即可)。
5.3.4 代理位置更新
在从控制器ANN接收到相应的控制信号后,在每个模拟步骤中都需要更新迷宫中求解器代理的位置。执行以下代码,即可更新迷宫求解器代理的位置:

def update(self, control_signals):
if self.exit_found:
return True # 迷宫出口已经找到
self.apply_control_signals(control_signals)
vx = math.cos(geometry.deg_to_rad(self.agent.heading)) * \ self.agent.speed
vy = math.sin(geometry.deg_to_rad(self.agent.heading)) * \ self.agent.speed
self.agent.heading = self.agent.angular_vel
if self.agent.heading > 360:
self.agent.heading -= 360
elif self.agent.heading < 0:
self.agent.heading = 360
new_loc = geometry.Point(
x = self.agent.location.x vx,
y = self.agent.location.y vy
)
if not self.test_wall_collision(new_loc):
self.agent.location = new_loc
self.update_rangefinder_sensors()
self.update_radars()
distance = self.agent_distance_to_exit()
self.exit_found = (distance < self.exit_range)
return self.exit_found

update(self, control_signals)函数在MazeEnvironment类中定义,并在每个模拟时间步骤中调用。它接收一个包含控制信号的列表作为输入,并返回一个布尔值,指示迷宫求解器代理在位置更新后是否已到达出口区域。
该函数开头的代码将接收到的控制信号应用于代理的角速度和线性速度的当前值,如下所示(参见apply_control_signals(self, control_signals)函数):

self.agent.angular_vel =(control_signals [0]-0.5)
self.agent.speed =(control_signals [1]-0.5)

计算x和y速度分量以及代理的正前方的方向,并将其用于估计代理在迷宫中的新位置。如果此新位置不会与迷宫中的任何墙壁发生碰撞,则将其分配给代理并使其变成代理的当前位置:

vx = math.cos(geometry.deg_to_rad(self.agent.heading)) * \ self.agent.speed
vy = math.sin(geometry.deg_to_rad(self.agent.heading)) * \ self.agent.speed
self.agent.heading = self.agent.angular_vel
if self.agent.heading > 360:
self.agent.heading -= 360
elif self.agent.heading < 0:
self.agent.heading = 360
new_loc = geometry.Point(
x = self.agent.location.x vx,
y = self.agent.location.y vy
)
if not self.test_wall_collision(new_loc):
self.agent.location = new_loc

新的代理位置将在以下函数中使用,这些函数会更新测距仪和雷达传感器,以估计下一个步骤的新传感器输入:

self.update_rangefinder_sensors()
self.update_radars()

以下函数将测试代理是否已到达迷宫出口,该出口由围绕出口点的圆形区域(半径等于exit_range字段的值)定义:

distance = self.agent_distance_to_exit()
self.exit_found = (distance < self.exit_range)
return self.exit_found

如果已到达迷宫出口,则将exit_found字段的值设置为True,以指示任务已成功完成,并且其值从函数调用中返回。
注意:
有关该实现的详细信息,参见以下网址的maze_environment.py文件:
https://github.com/PacktPublishing/Hands-on-Neuroevolution-with-Python/blob/master/Chapter5/maze_environment.py

5.3.5 代理记录存储
在完成实验后,即可评估和可视化在所有世代的神经进化过程中各个求解器代理的表现。这是通过收集每个代理在指定时间段内运行迷宫模拟之后的相关统计数据来实现的。代理记录的收集由两个Python类完成:AgentRecord类和AgentRecordStore类。
从AgentRecord类的构造函数中可以看出,该类包含以下数据字段:

def __init__(self, generation, agent_id):
self.generation = generation
self.agent_id = agent_id
self.x = -1
self.y = -1
self.fitness = -1
self.hit_exit = False
self.species_id = -1
self.species_age = -1

这些字段的定义如下。
generation:创建代理记录时,generation保留世代的ID。agent_id:代理的标识符。x和y:完成模拟后,代理在迷宫中的位置。fitness:代理的适应度评分。hit_exit:一个标志,指示代理是否已到达迷宫出口区域。species_id:代理所属的物种ID。species_age:代理所属的物种年龄。
AgentRecordStore类包含一个代理记录列表,并提供用于从特定文件加载已收集的记录或将已收集的记录保存到特定文件的函数。
注意:
有关完整的实现信息,参见本章源代码存储库中的agent.py文件。
在评估了基因组的适应度后,即可将新的AgentRecord实例添加到存储中。适应度评估由在maze_experiment.py文件中实现的eval_fitness(genome_id, genome, config, time_ steps = 400)函数定义。其代码如下:

def eval_fitness(genome_id, genome, config, time_steps=400):
maze_env = copy.deepcopy(trialSim.orig_maze_environment)
control_net = neat.nn.FeedForwardNetwork.create(genome, config)
fitness = maze.maze_simulation_evaluate(
env=maze_env, net=control_net, time_steps=time_steps)
record = agent.AgentRecord(
generation=trialSim.population.generation,
agent_id=genome_id)
record.fitness = fitness
record.x = maze_env.agent.location.x
record.y = maze_env.agent.location.y
record.hit_exit = maze_env.exit_found
record.species_id = trialSim.population.species.\ get_species_id(genome_id)
record.species_age = record.generation - \ trialSim.population.species.get_species(genome_id).created
trialSim.record_store.add_record(record)
return fitness

该代码首先创建原始迷宫环境的deepcopy,以避免评估运行之间的干扰。之后,它使用提供的NEAT配置从指定的基因组创建控制ANN,并在给定的时间步骤数量下开始评估迷宫模拟。然后,将返回的代理适应度评分以及其他统计信息存储到特定的AgentRecord实例中,并将其添加到记录存储中。
在一次试验中收集的记录将保存到output目录的data.pickle文件中,它将用于可视化所有已评估代理的性能。
注意:
有关完整的实现细节,可根据前言中的“下载示例代码”下载maze_experiment.py文件。
5.3.6 代理记录可视化
在神经进化过程中收集了所有代理的评估记录后,即可对记录进行可视化处理,以获得对性能的直观见解。
可视化应包括所有求解器代理的终位置,并允许设置物种适应度的阈值,以控制将哪些物种添加到相应的绘图中。
我们决定将收集到的代理记录呈现在两个图上,一个在上,一个在下。上面的图用于适应度评分大于或等于指定的适应度阈值的物种的代理记录,下面的图则用于其余代理的记录。
代理记录的可视化在visualize.py脚本的新方法中实现。本书前面描述的实验中多次介绍了此脚本,相信读者已经很熟悉它了。
注意:
参阅visualize.py文件中的draw_maze_records(maze_env, records, best_threshold = 0.8, filename = None, view = False, show_axes = False, width = 400, height = 400)函数定义。该文件的地址如下:
https://github.com/PacktPublishing/Hands-on-Neuroevolution-with-Python/blob/master/Chapter5/visualize.py

5.4 使用适应度评分的目标函数定义
本节将介绍使用面向目标的目标函数来指引神经进化过程,从而创建成功的迷宫求解器代理。该目标函数基于迷宫求解器适应度评分的估计,而迷宫求解器的适应度评分又是通过执行400个模拟步骤后测量代理的终位置与迷宫出口之间的距离来估算的。因此,该目标函数是面向目标的,并且仅取决于实验的终目标,即到达迷宫出口区域。
第6章将考虑基于新颖性搜索(Novelty Search,NS)优化方法的另一种解决方案搜索优化方法。新颖性搜索优化方法建立在探索进化过程中求解器代理的新颖性的基础上,并且在目标函数定义中不包含与终目标的接近度。具体到本示例来说,就是不再以迷宫出口为目标,而是以新地形为目标。事实证明,新颖性方法优于在本章讨论的传统的面向目标的目标函数定义。
本实验中使用的面向目标的目标函数可以按如下方式确定。
我们需要将损失函数(Loss Function)定义为在模拟结束时求解器代理的终位置与迷宫出口位置之间的欧几里得距离:
L
其中, L是损失函数,是求解器代理终位置的坐标,而则是迷宫出口的坐标。在此实验中,我们考虑的是二维迷宫配置,因此坐标具有两个值,每个维度一个值。
使用上面定义的损失函数,现在可以指定适应度函数:

Fn

L

F

L

其中,是迷宫出口点附近的出口区域的半径, Fn是归一化的适应度得分。归一化的适应度评分按如下方式给出:
Fn
其中,是导航模拟开始时从求解器代理到迷宫出口的初始距离(Initial Distance)。

Fn

该公式将适应度分数归一化为(0,1],但是,在极少数情况下,当代理的终位置远离其初始位置和迷宫出口时,可能会导致负值。因此,需要对归一化的适应度评分应用以下修正来避免出现负值:

Fn

Fn
当适应度评分小于或等于0.01时,将为其分配支持的小适应度评分值(0.01);否则,使用原值。我们选择的小适应度评分高于零,以使每个基因组都有繁殖的机会。
Python中的以下代码实现了面向目标的目标函数:

# 基于求解器代理与出口的距离计算适应度评分
fitness = env.agent_distance_to_exit()
if fitness <= self.exit_range:
fitness = 1.0
else:
# 将适应度评分归一化到(0,1]
fitness = (env.initial_distance - fitness) / \ env.initial_distance
if fitness <= 0.01:
fitness = 0.01

该代码首先调用 agent_distance_to_exit()函数,该函数将计算从当前代理位置到迷宫出口的欧几里得距离,并将返回值用作适应度评分的个近似值。之后,将适应度得分(代理到迷宫出口的距离)与出口范围值进行比较,如果适应度分数小于或等于出口范围值,则表明代理已经找到出口,于是直接将其指定为终值1.0;否则,将对适应度得分进行归一化处理。归一化的计算方法为:先计算代理到迷宫出口的初始距离与终距离之间的差值,然后再除以初始距离。如前文所述,在某些情况下,这可能导致归一化适应度值变为负值,可以将适应度值与0.01进行比较,然后进行必要的修正。
注意:
有关完整的实现信息,参见maze_environment.py脚本。
5.5 使用简单迷宫地形运行实验
现在可以开始使用简单迷宫地形创建与成功迷宫导航代理有关的实验。简单的迷宫地形虽然同样具有前面讨论过的误导性局部解,但是从起点到出口点的路径相对简单。
图5-3显示了用于此实验的迷宫地形。
图5-3中的迷宫有两个特定的位置,均使用实心圆圈标记。左上方的绿色圆圈(在黑白印刷的纸质图书上可能需要仔细查看才能发现)表示迷宫导航代理的起始位置。右下角的红色圆圈则标记了迷宫求解器需要找到的迷宫出口的确切位置。迷宫求解器代理需要到达迷宫出口点附近的迷宫出口区域(该出口区域由红色圆圈周围的特定范围区域表示),才算是完成任务。
图5-3 简单的迷宫地形
5.5.1 超参数选择
根据目标函数定义,当导航代理到达迷宫出口区域时,可以获得的适应度评分的值为1.0。可以预见的是,本实验的控制器ANN的初始配置会比本书前面描述的实验更加复杂,这将影响算法的执行速度。因此,在中等性能PC上可能需要花费很长时间才能完成具有相当大的基因组种群的神经进化算法。而且,本实验的任务比以前的实验要复杂得多,并且需要使用更宽的搜索范围来成功进行解决方案探索。因此,通过反复试验,我们发现种群大小设置为250比较合适。
配置文件的NEAT部分包含上述参数的定义:

[NEAT]
fitness_criterion = max
fitness_threshold = 1.0
pop_size = 250
reset_on_extinction = False

表现型ANN的初始配置包括10个输入节点、2个输出节点和1个隐藏节点。输入节点对应于输入传感器,输出节点对应于控制信号输出。提供隐藏节点是为了从神经进化过程的一开始就引入非线性,并节省进化过程发现它的时间。该ANN配置如下:

num_hidden = 1
num_inputs = 10
num_outputs = 2

为了扩展解决方案的搜索范围,我们需要增强种群的物种形成,以在有限的世代内尝试不同的基因组配置。这可以通过降低相容性阈值或通过增加用于执行基因组相容性评分计算的系数来完成。
在本实验中,我们同时使用了这两个修正,因为适应度函数具有误导性,并且我们需要强调基因组配置中的微小变化都能创建新物种。以下配置参数会受到影响:

[NEAT]
compatibility_disjoint_coefficient = 1.1
[DefaultSpeciesSet]
compatibility_threshold = 3.0

我们对创建具有小数量的隐藏节点和连接的迷宫求解器控制 ANN 的配置特别感兴趣。ANN配置在通过神经进化过程进行训练期间以及在迷宫求解模拟器中的推理阶段,在计算上的开销较小。可以通过减少添加新节点的可能性来产生ANN配置,因此,可以在NEAT配置文件中进行以下超参数配置:

node_add_prob = 0.1
node_delete_prob = 0.1

后,我们允许神经进化过程不仅可以利用具有前馈连接的ANN配置,而且还可以利用循环连接。在使用循环连接的情况下,ANN有可能拥有记忆并变成一个状态机(State Machine),而这对进化过程是有益的。以下配置超参数可以控制此行为:

feed_forward = False

本节描述的超参数对于该实验中使用NEAT算法在有限的几个世代内创建成功的迷宫求解代理是很有帮助的。
注意:
有关简单迷宫导航实验中使用的超参数的完整列表,参见以下网址的maze_config.ini文件:
https://github.com/PacktPublishing/Hands-on-Neuroevolution-with-Python/blob/master/Chapter5/maze_config.ini

5.5.2 迷宫配置文件
在本实验中,有关迷宫地形的配置是以纯文本形式提供的。该文件被加载到模拟环境中,并且将实例化相应的迷宫配置。配置文件的内容类似于以下形式:

11
30 22
0
270 100
5 5 295 5
295 5 295 135
295 135 5 135


对迷宫地形配置文件的格式解释如下。
第1行包含迷宫中的墙壁数量。第2行确定代理的起始位置坐标(x, y)。第3行表示代理的初始正前方,以度为单位。第4行显示迷宫出口位置坐标(x, y)。后面的几行定义了迷宫的墙壁。迷宫墙壁的数量由第1行的数字给出。
迷宫墙壁显示为线段,前两个数字定义线段起点的坐标,后两个数字确定线段终点的坐标。
导航代理的起始位置和迷宫出口的位置均以两个数字的形式表示,指示二维空间中某个点的x和y坐标。
5.5.3 工作环境设置
可以通过在终端应用程序中输入以下命令来设置简单迷宫实验的工作环境:

$ conda create --name maze_objective_neat python=3.5
$ conda activate maze_objective_neat
$ pip install neat-python==0.92
$ conda install matplotlib
$ conda install graphviz
$ conda install python-graphviz

这些命令将使用Python 3.5创建并激活maze_objective_neat虚拟环境。安装版本为0.92的NEAT-Python库以及可视化实用工具所使用的其他依赖项。
执行上述操作后,即可开始实验运行程序的实现。
5.5.4 实验运行程序的实现
本实验运行程序将在maze_experiment.py文件中实现,所以,读者可以参考该文件以获取完整的实现详细信息。该Python脚本提供了以下功能:读取命令行参数、配置和启动神经进化过程,以及在完成后呈现实验结果。此外,脚本还包括回调函数的实现,以评估属于特定种群的基因组的适应度。这些回调函数将在初始化期间提供给NEAT- Python库环境。
现在我们来讨论本章前面未解决的实验运行程序实现的关键部分。
(1)通过以下几行代码初始化迷宫模拟环境:

maze_env_config = os.path.join(local_dir, ‘%s_maze.txt’ %
args.maze)
maze_env = maze.read_environment(maze_env_config)

args.maze指的是用户在启动Python脚本时提供的命令行参数,是我们要进行实验的迷宫环境的类型。它可以具有两个值:medium(中等难度)和hard(困难级)。本实验使用的简单迷宫配置对应于medium值。
(2)为随机数生成器设置特定的种子数字,创建NEAT配置对象,并使用创建的配置对象创建neat.Population对象:

seed = 1559231616
random.seed(seed)
config = neat.Config(neat.DefaultGenome,
neat.DefaultReproduction,
neat.DefaultSpeciesSet,
neat.DefaultStagnation,
config_file)
p = neat.Population(config)
注意:
我们发现双杆平衡实验中的随机种子值也适用于该实验。可以假设我们找到了一个随机吸引子,该吸引子特定于NEAT-Python库实现的随机过程。在本书后面的章节中,我们将检查其他实验是否也如此。
(3)创建合适的迷宫模拟环境并将其存储为全局变量,以简化从适应度评估回调函数对它的访问:

global trialSim
trialSim = MazeSimulationTrial(maze_env=maze_env, population=p)

MazeSimulationTrial对象包含用于访问原始迷宫模拟环境以及用于保存迷宫求解器代理评估结果的记录存储的字段。在每次调用适应度评估回调函数eval_fitness(genome_id, genome, config, time_steps=400)时,将复制原始迷宫模拟环境,并将由特定的求解器代理用于迷宫求解模拟,持续400个时间步骤。此后,将从环境中收集有关迷宫求解器代理的完整统计信息,包括它在迷宫中的终位置,并将其添加到记录存储中。
(4)以下代码已经多次使用,可谓我们实验中的标准操作,相信读者已经熟悉了,它们与添加各种统计报告器有关:

p.add_reporter(neat.StdOutReporter(True))
stats = neat.StatisticsReporter()
p.add_reporter(stats)
p.add_reporter(neat.Checkpointer(5,
filename_prefix=‘%s/maze-neat-checkpoint-’ %
trial_out_dir))

这些报告器可将神经进化过程的中间结果显示在控制台上,并收集更详细的统计信息,这些统计信息将在该过程完成后呈现。
(5)让神经进化过程运行指定的代数,并检查是否找到了解决方案:

start_time = time.time()
best_genome = p.run(eval_genomes, n=n_generations)
elapsed_time = time.time() - start_time
solution_found = (best_genome.fitness >= \ config.fitness_threshold)
if solution_found:
print(”SUCCESS: The stable maze solver controller was found!!!”)
else:
print(”FAILURE: Failed to find the stable maze solver controller!!!”)

如果NEAT-Python库返回的基因组的适应度评分大于或等于配置文件中设置的适应度阈值(1.0),则可以假设已经找到解决方案。计算经过的时间(elapsed_time)以输出完成该过程所花费的时间。
5.5.5 基因组适应度评估
回调函数用于评估属于特定生物种群的所有基因组的适应度得分,具体实现如下:

def eval_genomes(genomes, config):
for genome_id, genome in genomes:
genome.fitness = eval_fitness(genome_id, genome, config)

eval_fitness(genome_id, genome, config)函数通过针对由特定基因组编码的ANN控制的求解器代理运行迷宫求解模拟来评估该基因组的适应度。由于本章已经讨论过此函数(详见第5.3.5节“代理记录存储”),因此此处未提供该函数的实现。

5.5.6 运行简单迷宫导航实验
在实现了迷宫求解器模拟器以及实验运行程序和适应度评估回调函数后,即可开始进行迷宫求解实验。确保将所有相关的Python脚本和配置文件(maze_config.ini和medium_maze.txt)复制到工作目录中。
进入工作目录并在终端应用程序中执行以下命令:

$ python maze_experiment.py -m medium -g 150
注意:
使用以下命令激活适当的虚拟环境:
conda activate maze_objective_neat

上面的命令将从medium_maze.txt文件加载简单迷宫的配置,并创建适当的迷宫模拟环境。之后,使用maze_config.ini文件中指定的超参数,在NEAT算法的控制下启动神经进化过程。NEAT算法使用迷宫求解器模拟环境来评估150代以上的神经进化过程中产生的每个基因组的适应度(命令行参数中的 -g 即指定了进化世代数)。
经过144代的进化后,终于在145代发现成功的迷宫求解器代理。近世代的控制台输出分析如下。
(1)有关基因组种群的一般统计数据:

****** Running generation 145 ******

Maze solved in 388 steps
Populations average fitness: 0.24758 stdev: 0.25627
Best fitness: 1.00000 - size: (3, 11) - species 7 - id 35400

Best individual in generation 145 meets fitness threshold - complexity:
(3, 11)

(2)编码成功的迷宫求解器控制器ANN的基因组配置:

Best genome:
Key: 35400
Fitness: 1.0
Nodes:
0 DefaultNodeGene(key=0, bias=5.534849614521037, response=1.0,
activation=sigmoid, aggregation=sum)
1 DefaultNodeGene(key=1, bias=1.8031133229851957, response=1.0,
activation=sigmoid, aggregation=sum)
158 DefaultNodeGene(key=158, bias=-1.3550878188609456,
response=1.0, activation=sigmoid, aggregation=sum)
Connections:
DefaultConnectionGene(key=(-10, 158), weight=-1.6144052085440168,
enabled=True)
DefaultConnectionGene(key=(-8, 158), weight=-1.1842193888036392,
enabled=True)
DefaultConnectionGene(key=(-7, 0), weight=-0.3263706518456319,
enabled=True)
DefaultConnectionGene(key=(-7, 1), weight=1.3186165993348418,
enabled=True)
DefaultConnectionGene(key=(-6, 0), weight=2.0778575294986945,
enabled=True)
DefaultConnectionGene(key=(-6, 1), weight=-2.9478037554862824,
enabled=True)
DefaultConnectionGene(key=(-6, 158), weight=0.6930281879212032,
enabled=True)
DefaultConnectionGene(key=(-4, 1), weight=-1.9583885391583729,
enabled=True)
DefaultConnectionGene(key=(-3, 1), weight=5.5239054588484775,
enabled=True)
DefaultConnectionGene(key=(-1, 0), weight=0.04865917999517305,
enabled=True)
DefaultConnectionGene(key=(158, 0), weight=0.6973191076874032,
enabled=True)
SUCCESS: The stable maze solver controller was found!!!
Record store file: out/maze_objective/medium/data.pickle

在该控制台输出中,可以看到成功的迷宫求解器控制器是在进化过程中找到的,并且能够从指定的400个时间步骤中以388步到达迷宫出口区域。成功的迷宫求解器的控制ANN的配置包括2个输出节点和1个隐藏节点,以及来自输入节点和这些节点之间的11个连接。控制器ANN的终配置如图5-4所示。
通过图5-4来研究不同的传感器输入如何影响输出控制信号是很有趣的一件事。可以看到,ANN配置完全忽略了机器人前方测距传感器(RF_FR)、左侧测距传感器(RF_L)和后方扇形雷达传感器(RAD_B)的输入。同时,机器人的线性速度(VEL)和角速度(ANG_VEL)将由其他传感器的独特组合控制。
此外,我们可以通过隐藏节点看到左右扇形雷达传感器(RAD_L和RAD_R)与后向测距仪(RF_B)的聚合,然后将聚合的信号中继到控制角速度的节点(ANG_VEL)。如果仔细研究一下图5-3中显示的简单迷宫地形配置,就会发现这样的聚合看起来很自然。当迷宫求解器代理陷入局部适应度的死胡同时,可以使机器人转过身并继续探索迷宫。
图5-4 表现型ANN配置控制的简单迷宫的成功求解器
图5-5说明了各个世代求解器代理的适应度得分。
图5-5 各个世代求解器代理的平均和适应度得分

原 文

译 文

Population’s average and best fitness

种群的平均适应度和适应度

Fitness

适应度

Generations

世代

average

平均

-1 sd

种子值 -1

1 sd

种子值 1

best



在图5-5中可以看到,进化过程早在第44代就能够产生适应度评分为0.96738的非常接近成功的迷宫求解器。但是,又花了100代才能进化出编码成功的迷宫求解器代理ANN的基因组。
另外,比较有趣的是,第44代性能的提高是由ID为1的物种产生的,但是成功的迷宫求解器的基因组则属于ID为7的物种,而该物种在产生个峰值时甚至连ID都还不知道。产生冠军的物种在12代之后出现,并保留在种群中直到后,它保留了有益的突变并完成了后的超越。
图5-6描述了世代进化过程中的物种形成。
图5-6 世代进化过程中的物种形成

原 文

译 文

Speciation

物种形成

Size per Species

每个物种的规模

Generations

世代


在该物种形成图上,可以看到ID为7的粉红色的物种。该物种终在进化过程中产生了成功的迷宫求解器的基因组。物种ID为7的个体的数量在其整个生命中变化很大,并且曾经是几个世代(105~108世代)在整个种群中的物种。
5.5.7 代理记录可视化
在此实验中,我们提出了一种新的可视化方法,以便可以在视觉上辨别各个物种在进化过程中的表现。该可视化方法可以使用以下命令从实验的工作目录执行:

$ python visualize.py -m medium -r out/maze_objective/medium/data.pickle --
width 300 --height 150

该命令在进化过程中将加载有关各种迷宫求解器代理的适应度评估的记录,该记录存储在data.pickle文件中。此后,它会在迷宫求解模拟结束时在迷宫地图上绘制代理的终位置。每个代理的终位置均以彩色圆圈表示。圆圈的颜色编码与特定代理所属的种类相关。进化过程中产生的每个物种都有的颜色代码。图5-7说明了求解器代理评估的可视化结果。
图5-7 求解器代理评估的可视化结果
为了使该可视化结果能够提供更加丰富的信息,我们引入了适应度阈值以筛选出性能的物种。在图5-7中,上面的子图显示了属于冠军物种的求解器代理的终位置(适应度得分高于0.8)。可以看到,属于这6个物种的生物是活跃的探索者,它们的基因激发了机器人在迷宫中未知地点的搜索。它们的终位置在起点附近的迷宫区域几乎均匀地分布,并且在局部路径处的密度较低。
与此同时,在下面的子图中可以看到,进化失败者表现出更为保守的行为,主要集中在起始区域和强的局部区域(的死胡同)附近。
5.6 练习1
(1)尝试增加maze_config.ini文件中的compatibility_disjoint_coefficient参数,并使用新设置运行实验。这种改变对进化过程中产生的物种数量有什么影响?其神经进化过程是否能够找到成功的迷宫求解器?
(2)将种群规模增加200%(pop_size参数)。在这种情况下,神经进化过程是否能够找到解决方案?如果可以,那么需要经过多少个世代的进化?
(3)更改随机数生成器的种子值(参见maze_experiment.py文件的第118行,或者第5.5.4节“实验运行程序的实现”)。神经进化过程是否能够以这个新值获得成功?
5.7 使用难以解决的迷宫配置运行实验
现在我们来进行本章的第二个实验,这个实验是运行神经进化过程,以找到能够求解墙壁结构更为复杂的困难级迷宫的导航代理。这种难以解决的迷宫地形配置引入了强大的局部适应度陷阱,并且从代理的起始位置到迷宫出口区域不再有直接路线。该迷宫地形配置如图5-8所示。
该迷宫地形配置的起始位置在左下角,用绿色圆圈标记(需要仔细辨识才能看清),迷宫出口点的位置在左上角,用红色圆圈标记。可以看到,要解决该迷宫问题,导航代理必须制定一种复杂的控制策略,以避免在起点附近出现局部适应度陷阱。从起点到出口,控制策略需要遵循精细的轨迹,该轨迹具有多个转弯和更多的局部陷阱。
图5-8 难以解决的迷宫配置
5.7.1 超参数选择
对于本实验,我们将使用与简单迷宫求解实验相同的超参数。我们的想法是使神经进化算法具有相同的初始条件,以查看是否可以针对不同的而且更复杂的迷宫地形配置进化出成功的求解器代理。这样的比较将体现出算法在相同的超参数设置下应用于不同迷宫地形配置的一般适用性程度。
5.7.2 工作环境设置和实验运行程序实现
本实验工作环境的设置与简单迷宫导航实验相同。实验运行程序的实现也保持不变。我们仅更改描述迷宫地形环境配置的文件。
5.7.3 运行困难级迷宫导航实验
如前文所述,我们将使用与先前实验相同的实验运行程序和相同的NEAT超参数设置。但是将按以下方式配置不同的迷宫环境:

$ python maze_experiment.py -m hard -g 500

在等待一段时间后,当实验结束时,我们看到,即使经过500个世代的进化,也没有找到成功的迷宫求解器。使用神经进化算法获得的基因组编码了一个怪异而完全无效的控制器ANN配置,如图5-9所示。
从图5-9可以看出,机器人的旋转仅取决于正面的测距仪传感器(RF_FR),并且线性移动是由多个测距仪和雷达传感器组合控制的。这种控制配置可简化机器人的线性运动,直至在机器人前面检测到墙壁为止。也就是说,该ANN配置控制下的机器人几乎是直直地奔向死胡同。通过查看图5-10所示的代理评估记录的可视化结果,也可以确认我们对其运动模式的假设。
图5-9 控制困难级迷宫求解器的ANN配置
图5-10 可视化求解器代理的评估记录
求解器代理终位置的可视化表明,大多数物种都被困在起始位置附近,该位置是局部适应度评分值的某些区域。没有一个物种的适应度得分能够超过我们的阈值(0.8)。而且,正如我们前面提到的,由求解器代理的终位置形成了明显可区分的垂直线(创建垂直列的灰色点),这证实了我们对在基因组编码的ANN(在进化过程中发现的)控制下的机器人错误行为的假设(几乎是直直地奔向死胡同)。
图5-11说明了各个世代的平均适应度评分。
图5-11 各个世代的平均适应度评分

原 文

译 文

Population’s average and best fitness

种群的平均适应度和适应度

Fitness

适应度

Generations

世代

average

平均

-1 sd

种子值 -1

1 sd

种子值 1

best



在该平均适应度评分图中,可以看到神经进化过程在前面的世代中就能显著提高求解器代理的适应度评分,但此后则达到了平稳状态,没有任何改善。这意味着进化世代数目的进一步增加没有任何意义,需要采取其他措施来改善神经进化过程的性能。

5.8 练习2
(1)尝试通过调整maze_config.ini文件中的pop_size参数来增加总体大小。这是否有助于神经进化过程进化出成功的迷宫求解器?
(2)尝试在maze_experiment.py文件中修改随机种子值,看看是否能够进化出成功的迷宫求解器。
注意:
练习2(1)可能需要较长的执行时间。
5.9 小 结
本章通过实验清晰阐释了面向目标的适应度函数在求解具有误导(欺骗)性定义的问题时可能会遇到的计划和控制问题。在这种情况下,适应度函数的局部区域会产生多个陷阱,这些陷阱将误导解决方案的搜索过程,这是因为该搜索过程仅基于适应度得分计算,而适应度得分又被计算为从代理到目标的距离的导数。
本章的两个实验已经清楚地表明,常规的面向目标的适应度函数在求解简单的迷宫地形配置时,能够帮助创建成功的迷宫导航代理,而在面对具有强大的局部陷阱的复杂地形迷宫时则会导致失败。
本章提出了一种实用的可视化方法,使实验人员能够可视化迷宫地图上所有评估代理的终位置。通过此可视化方法,实验人员可以对进化过程的性能进行假设,然后根据假设更改配置设置,以进一步提高性能。
此外,我们还从实验中了解到,当适应度函数有更大的机会收敛到局部条件时,神经进化过程往往会产生较少的物种。在情况下,它只会创造一个物种,从而削弱了创新并阻碍了进化过程。为避免这种情况,我们介绍了如何通过更改compatibility_ disjoint_coefficient(相容性不相交系数)的值来强化物种形成,该系数在计算基因组相容性因子时使用。该系数控制的权重将分配给要比较的基因组的多余或不相交部分,较高的系数值增加了所比较的基因组中拓扑形态差异的重要性,并允许更多种不同的基因组属于同一物种。
第6章将介绍新颖性搜索(NS)优化方法,该方法可以更好地解决诸如困难级迷宫导航之类的误导(欺骗)性任务。

 

 

書城介紹  | 合作申請 | 索要書目  | 新手入門 | 聯絡方式  | 幫助中心 | 找書說明  | 送貨方式 | 付款方式 香港用户  | 台灣用户 | 海外用户
megBook.com.tw
Copyright (C) 2013 - 2024 (香港)大書城有限公司 All Rights Reserved.