深度学习框架中蕴藏着惊人的技术和有趣的机制,本书旨在揭开这些技术和机制的神秘面纱,帮助读者正确理解技术,体会它们的有趣之处。为此,本书会带领读者从零开始创建一个深度学习框架DeZero。DeZero 是本书原创的框架,它用最少的代码实现了现代深度学习框架的功能。本书分60 个步骤来完成这个框架,在此过程中,读者会加深对PyTorch、TensorFlow 和Chainer 等现代深度学习框架的理解,看清深度学习框架的本质。
本书沿袭《深度学习入门:基于Python 的理论与实现》的风格,语言通俗,代码简洁,讲解详细。在自制框架的过程中,读者还能进一步巩固Python 编程和软件开发相关的知识。
本书适合对深度学习框架感兴趣的读者阅读。
·鱼书《深度学习入门:基于Python的理论与实现》作者又一力作。手把手带你创建深度学习框架,直击现代深度学习框架本质!
·内容简明易懂,讲解详细
本书延续前作的行文风格,采用通俗的语言和大量直观的示意图详细讲解,帮助读者加深对PyTorch、TensorFlow和Chainer等现代深度学习框架的理解,进一步巩固Python编程和软件开发的相关知识。
·通过从零创建,剖析深度学习框架机制
本书会从零创建一个深度学习框架,让读者在运行程序的过程中了解深度学习框架中蕴藏的技术与机制。通过这样的体验,读者可了解到深度学习框架的本质。
·增量开发
本书将繁杂的深度学习框架的创建工作分为60个步骤完成,内容循序渐进,读者可在一步步的实践过程中获得正向的反馈结果,激发学习动力。
斋藤康毅(作者) 1984年生于日本长崎县,东京工业大学毕业,并完成东京大学研究生院课程。目前在某企业从事人工智能相关的研究和开发工作。著有《深度学习入门:基于Python的理论与实现》,同时也是Introducing Python、Python in Practice、The Elements of Computing Systems、Building Machine Learning Systems with Python的日文版译者。 郑明智(译者) 智慧医疗工程师。主要研究方向为医疗与前沿ICT技术的结合及其应用,密切关注人工智能、量子计算等领域。译有《深度学习基础与实践》《详解深度学习》《白话机器学习的数学》等书。
前言 xvii
第 1阶段 自动微分 1
步骤1 作为箱子的变量 3
1.1 什么是变量 3
1.2 实现Variable 类 4
1.3 (补充)NumPy的多维数组 6
步骤2 创建变量的函数 8
2.1 什么是函数 8
2.2 Function类的实现 9
2.3 使用Function 类 10
步骤3 函数的连续调用 13
3.1 Exp函数的实现 13
3.2 函数的连续调用 14
步骤4 数值微分 16
4.1 什么是导数 16
4.2 数值微分的实现 17
4.3 复合函数的导数 20
4.4 数值微分存在的问题 21
步骤5 反向传播的理论知识 22
5.1 链式法则 22
5.2 反向传播的推导 23
5.3 用计算图表示 25
步骤6 手动进行反向传播 27
6.1 Variable 类的功能扩展 27
6.2 Function类的功能扩展 28
6.3 Square类和Exp类的功能扩展 28
6.4 反向传播的实现 29
步骤7 反向传播的自动化 32
7.1 为反向传播的自动化创造条件 33
7.2 尝试反向传播 36
7.3 增加backward方法 38
步骤8 从递归到循环 40
8.1 现在的Variable 类 40
8.2 使用循环实现 41
8.3 代码验证 42
步骤9 让函数更易用 43
9.1 作为Python函数使用 43
9.2 简化backward方法 45
9.3 只支持ndarray 46
步骤10 测试 50
10.1 Python的单元测试 50
10.2 square函数反向传播的测试 52
10.3 通过梯度检验来自动测试 53
10.4 测试小结 54
第 2阶段 用自然的代码表达 59
步骤11 可变长参数(正向传播篇) 61
11.1 修改Function 类 62
11.2 Add类的实现 64
步骤12 可变长参数(改进篇) 65
12.1 第 1 项改进:使函数更容易使用 65
12.2 第 2 项改进:使函数更容易实现 67
12.3 add函数的实现 69
步骤13 可变长参数(反向传播篇) 70
13.1 支持可变长参数的Add类的反向传播 70
13.2 修改Variable 类 71
13.3 Square类的实现 73
步骤14 重复使用同一个变量 75
14.1 问题的原因 76
14.2 解决方案 77
14.3 重置导数 79
步骤15 复杂的计算图(理论篇) 81
15.1 反向传播的正确顺序 82
15.2 当前的DeZero 84
15.3 函数的优先级 87
步骤16 复杂的计算图(实现篇) 88
16.1 增加辈分变量 88
16.2 按照辈分顺序取出元素 90
16.3 Variable 类的backward 92
16.4 代码验证 93
步骤17 内存管理和循环引用 97
17.1 内存管理 97
17.2 引用计数方式的内存管理 98
17.3 循环引用 100
17.4 weakref模块 102
17.5 代码验证 104
步骤18 减少内存使用量的模式 106
18.1 不保留不必要的导数 106
18.2 回顾Function 类 109
18.3 使用Config类进行切换 110
18.4 模式的切换 111
18.5 使用with 语句切换 112
步骤19 让变量更易用 116
19.1 命名变量 116
19.2 实例变量ndarray 117
19.3 len函数和print 函数 119
步骤20 运算符重载(1) 122
20.1 Mul类的实现 122
20.2 运算符重载 125
步骤21 运算符重载(2) 128
21.1 与ndarray 一起使用 128
21.2 与float 和int 一起使用 130
21.3 问题1:左项为float 或int 的情况 131
21.4 问题2:左项为ndarray 实例的情况 133
步骤22 运算符重载(3) 134
22.1 负数 135
22.2 减法 136
22.3 除法 138
22.4 幂运算 139
步骤23 打包 141
23.1 文件结构 142
23.2 将代码移到核心类 142
23.3 运算符重载 144
23.4 实际的_ _init_ _.py 文件 146
23.5 导入dezero 147
步骤24 复杂函数的求导 149
24.1 Sphere函数 150
24.2 matyas函数 151
24.3 Goldstein Price 函数 152
第3阶段 实现高阶导数 161
步骤25 计算图的可视化(1) 163
25.1 安装Graphviz 163
25.2 使用DOT语言描述图形 165
25.3 指定节点属性 165
25.4 连接节点 167
步骤26 计算图的可视化(2) 169
26.1 可视化代码的使用示例 169
26.2 从计算图转换为DOT语言 171
26.3 从DOT语言转换为图像 174
26.4 代码验证 176
步骤27 泰勒展开的导数 178
27.1 sin函数的实现 178
27.2 泰勒展开的理论知识 179
27.3 泰勒展开的实现 180
27.4 计算图的可视化 182
步骤28 函数优化 184
28.1 Rosenbrock函数 184
28.2 求导 185
28.3 梯度下降法的实现 186
步骤29 使用牛顿法进行优化(手动计算) 190
29.1 使用牛顿法进行优化的理论知识 191
29.2 使用牛顿法实现优化 195
步骤30 高阶导数(准备篇) 197
30.1 确认工作①:Variable 实例变量 197
30.2 确认工作②:Function 类 199
30.3 确认工作③:Variable 类的反向传播 201
步骤31 高阶导数(理论篇) 204
31.1 在反向传播时进行的计算 204
31.2 创建反向传播的计算图的方法 206
步骤32 高阶导数(实现篇) 209
32.1 新的DeZero 209
32.2 函数类的反向传播 210
32.3 实现更有效的反向传播(增加模式控制代码) 211
32.4 修改_ _init_ _.py 213
步骤33 使用牛顿法进行优化(自动计算) 215
33.1 求二阶导数 215
33.2 使用牛顿法进行优化 217
步骤34 sin函数的高阶导数 219
34.1 sin函数的实现 219
34.2 cos函数的实现 220
34.3 sin函数的高阶导数 221
步骤35 高阶导数的计算图 225
35.1 tanh函数的导数 226
35.2 tanh函数的实现 226
35.3 高阶导数的计算图可视化 227
步骤36 DeZero的其他用途 234
36.1 double backprop 的用途 234
36.2 深度学习研究中的应用示例 236
第4阶段 创建神经网络 243
步骤37 处理张量 245
37.1 对各元素进行计算 245
37.2 使用张量时的反向传播 247
37.3 使用张量时的反向传播(补充内容) 249
步骤38 改变形状的函数 254
38.1 reshape函数的实现 254
38.2 从Variable 对象调用reshape 258
38.3 矩阵的转置 259
38.4 实际的transpose 函数(补充内容) 262
步骤39 求和的函数 264
39.1 sum函数的反向传播 264
39.2 sum函数的实现 266
39.3 axis 和keepdims 268
步骤40 进行广播的函数 272
40.1 broadcast_to 函数和sum_to 函数 272
40.2 DeZero的broadcast_to 函数和sum_to 函数 275
40.3 支持广播 277
步骤41 矩阵的乘积 280
41.1 向量的内积和矩阵的乘积 280
41.2 检查矩阵的形状 282
41.3 矩阵乘积的反向传播 282
步骤42 线性回归 288
42.1 玩具数据集 288
42.2 线性回归的理论知识 289
42.3 线性回归的实现 291
42.4 DeZero的mean_squared_error函数(补充内容) 295
步骤43 神经网络 298
43.1 DeZero中的linear 函数 298
43.2 非线性数据集 301
43.3 激活函数和神经网络 302
43.4 神经网络的实现 303
步骤44 汇总参数的层 307
44.1 Parameter类的实现 307
44.2 Layer类的实现 309
44.3 Linear类的实现 312
44.4 使用Layer实现神经网络 314
步骤45 汇总层的层 316
45.1 扩展Layer类 316
45.2 Model类 319
45.3 使用Model来解决问题 321
45.4 MLP类 323
步骤46 通过Optimizer更新参数 325
46.1 Optimizer类 325
46.2 SGD类的实现 326
46.3 使用SGD类来解决问题 327
46.4 SGD以外的优化方法 328
步骤47 softmax函数和交叉熵误差 331
47.1 用于切片操作的函数 331
47.2 softmax函数 334
47.3 交叉熵误差 337
步骤48 多分类 340
48.1 螺旋数据集 340
48.2 用于训练的代码 341
步骤49 Dataset类和预处理 346
49.1 Dataset类的实现 346
49.2 大型数据集的情况 348
49.3 数据的连接 349
49.4 用于训练的代码 350
49.5 数据集的预处理 351
步骤50 用于取出小批量数据的DataLoader 354
50.1 什么是迭代器 354
50.2 使用DataLoader 358
50.3 accuracy函数的实现 359
50.4 螺旋数据集的训练代码 360
步骤51 MINST的训练 363
51.1 MNIST数据集 364
51.2 训练MNIST 366
51.3 改进模型 368
第5阶段 DeZero高级挑战 377
步骤52 支持GPU 379
52.1 CuPy的安装和使用方法 379
52.2 cuda模块 382
52.3 向Variable / Layer / DataLoader 类添加代码 383
52.4 函数的相应修改 386
52.5 在GPU上训练MNIST 388
步骤53 模型的保存和加载 391
53.1 NumPy的save 函数和load 函数 391
53.2 Layer类参数的扁平化 394
53.3 Layer类的save 函数和load 函数 395
步骤54 Dropout和测试模式 398
54.1 什么是Dropout 398
54.2 Inverted Dropout 401
54.3 增加测试模式 401
54.4 Dropout的实现 402
步骤55 CNN的机制(1) 404
55.1 CNN的网络结构 404
55.2 卷积运算 405
55.3 填充 407
55.4 步幅 408
55.5 输出大小的计算方法 409
步骤56 CNN的机制(2) 411
56.1 三阶张量 411
56.2 结合方块进行思考 412
56.3 小批量处理 414
56.4 池化层 415
步骤57 conv2d函数和pooling函数 418
57.1 使用im2col 展开 418
57.2 conv2d函数的实现 420
57.3 Conv2d层的实现 425
57.4 pooling 函数的实现 426
步骤58 具有代表性的CNN(VGG16) 429
58.1 VGG16的实现 429
58.2 已训练的权重数据 431
58.3 使用已训练的VGG16 435
步骤59 使用RNN处理时间序列数据 438
59.1 RNN层的实现 438
59.2 RNN模型的实现 442
59.3 切断连接的方法 445
59.4 正弦波的预测 446
步骤60 LSTM与数据加载器 451
60.1 用于时间序列数据的数据加载器 451
60.2 LSTM层的实现 453
附录A in place 运算(步骤14的补充内容) 463
A.1 问题确认 463
A.2 关于复制和覆盖 464
A.3 DeZero的反向传播 465
附录B 实现get_item函数(步骤47的补充内容) 466
附录C 在Google Colaboratory上运行 469
后 记 473
参考文献 477