WEBVTT

00:00.120 --> 00:02.720
大家好, 欢迎学习本Python教程｡ 

00:02.730 --> 00:08.010
在本教程中, 我们将迈出实施深度学习模型的第一步｡ 

00:08.010 --> 00:13.560
所以基本上我们即将实现深度学习算法的整个过程｡ 

00:13.560 --> 00:16.530
所以我们将使用之前创建的｡ 

00:16.560 --> 00:23.520
这是神经网络的架构来回放记忆, 将其整合到整个深度学习过程中｡

00:23.880 --> 00:28.200
而整个深度学习算法将适合于一个类｡ 

00:28.200 --> 00:32.070
这是我们要做的实现人工智能的最后一门课｡ 

00:32.070 --> 00:35.520
这个类只包含不同的函数｡ 

00:35.520 --> 00:41.730
因此,

00:41.730 --> 00:48.300
我们将使用init函数来创建和初始化附加到我们未来的深度学习对象的所有变量, 这些对象将代表深度学习模型本身, 并将具有一些其他函数｡

00:48.300 --> 00:52.650
其中之一当然是每次都选择正确的行动｡ 

00:52.650 --> 00:59.730
我们还将有一个更新函数, 一个得分函数来得到分数, 并了解学习的进展情况｡

00:59.730 --> 01:05.640
如果进展顺利, 如果探索进展顺利,

01:05.640 --> 01:12.180
如果它可以继续进行开发, 那么我们就会有一个保存函数来保存模型, 也就是保存汽车的大脑, 然后最终会有一个加载函数｡

01:12.180 --> 01:14.400
所以我们有几个函数要做｡ 

01:14.400 --> 01:22.740
我们将为每个教程创建一个函数, 今天我们将像往常一样, 从init函数开始创建类.

01:22.740 --> 01:33.270
但首先我们不要忘了介绍这个类, 所以我们将它命名为D, Q, N表示深Q网络, 然后是一些括号,

01:33.270 --> 01:38.700
冒号, 这是我们的第一个函数｡

01:39.300 --> 01:47.790
让我们这样做def然后在里面加双下划线, 再加双下划线和括号｡ 

01:47.880 --> 01:53.400
正如你在init函数中所理解的, 我们将引入附加到对象上的变量｡

01:53.400 --> 01:59.190
我们将有几行代码, 它们都是单独启动的,

01:59.190 --> 02:03.270
我们将创建并初始化实现深Q网络所需的所有变量｡

02:03.270 --> 02:09.150
例如, 我们将创建一个网络对象, 因为我们当然需要深层神经网络,

02:09.150 --> 02:12.150
然后我们将需要我们的记忆｡

02:12.150 --> 02:14.490
我们将为内存创建另一个变量｡ 

02:14.490 --> 02:17.610
所以我们会有另一个变量self那个记忆｡ 

02:17.610 --> 02:20.280
但这并不是我们要创造的全部｡ 

02:20.280 --> 02:24.660
一些变量为最后一个状态､ 最后一个区段和最后一个奖励｡ 

02:24.690 --> 02:30.150
当然, 这就是你在深度学习算法中看到的变量｡ 

02:30.630 --> 02:31.710
然后呢？

02:31.710 --> 02:37.470
我们还需要一个优化器来执行随机梯度下降,

02:37.470 --> 02:44.190
以便在人工智能出错时, 根据权重对错误的贡献程度来更新权重｡

02:44.190 --> 02:50.220
然后我想这基本上就是我们现在需要创建一个初始化的变量了｡ 

02:50.220 --> 02:54.270
但是在这个init函数中, 我们将输入几个参数｡ 

02:54.270 --> 02:59.910
第一, 作为通常的自我, 这是论证所指的我们的对象｡ 

02:59.940 --> 03:05.130
既然你已经知道了, 我们就创建一个网络类的对象｡ 

03:05.130 --> 03:12.000
因为网络类在init函数中将input､ size和end操作作为参数｡ 

03:12.000 --> 03:13.560
这里也一样｡ 

03:13.560 --> 03:19.860
当创建网络类的对象时, 我们需要在NB操作参数中选择一个输入大小参数｡

03:19.890 --> 03:22.290
因此我们可以复制它们｡ 

03:23.740 --> 03:24.400
还有｡ 

03:25.450 --> 03:26.380
在这里面对他们

03:26.500 --> 03:27.470
我们开始吧｡ 

03:27.490 --> 03:32.950
所以这些论证现在也将成为不同类的一些论证｡ 

03:32.950 --> 03:39.130
每当我们创建当前类的一些未来对象时, 也就是一些未来的深度学习模型时, 我们需要指定输入大小,

03:39.130 --> 03:44.800
我提醒一下,

03:44.800 --> 03:52.890
这是向量中编码状态的维数, 输入状态, 以及动作的数量, 也就是汽车可以做出的可能动作的数量｡

03:52.900 --> 03:57.610
所以我提醒你, 要么左转, 要么直行, 要么右转｡ 

03:58.030 --> 03:59.050
好的, 很好｡ 

03:59.050 --> 04:04.580
然后, 我们将创建一个replay memory类的对象,

04:04.580 --> 04:07.090
以创建内存对象来获取转换的内存｡

04:07.240 --> 04:13.390
在init函数中我们有capacity参数, 但是因为我们只使用它一次,

04:13.390 --> 04:19.780
实际上是在我们创建内存的时候, 而不是在之后的任何地方, 我们不需要指定capacity参数｡

04:19.780 --> 04:25.330
我们可以这样做, 但我们将直接输入我们希望内存具有的转换数｡ 

04:26.020 --> 04:32.230
但这样我们就少了一个参数, 那就是深度学习模型中的gamma参数｡ 

04:32.260 --> 04:36.110
请记住, 此gamma参数是延迟系数｡ 

04:36.130 --> 04:38.020
这是方程的参数｡ 

04:38.020 --> 04:42.830
所以我们把它放在这里, 因为我们以后还会用到它｡ 

04:42.850 --> 04:44.770
所以我们把它放在这里｡ 

04:44.800 --> 04:46.690
我们就叫它伽马｡ 

04:46.960 --> 04:53.520
所以这只是参数的名字, 这里是init函数需要的所有参数.

04:53.530 --> 05:01.270
这意味着每当我们创建深度学习模型时, 也就是每当我们创建当前类的新对象时｡

05:01.270 --> 05:10.330
我们需要指定输入大小, 动作数和gamma参数, 我们很快就会输入它们的真实的值｡

05:11.020 --> 05:11.410
好吧, 我会的

05:11.410 --> 05:13.810
现在我们来看看init函数｡ 

05:14.050 --> 05:14.320
好吧, 我会的

05:14.320 --> 05:16.330
所以现在基本上这是很容易的｡ 

05:16.330 --> 05:20.920
我们要创建一个初始化, 所有需要的变量.

05:20.920 --> 05:22.710
让我们从第一个开始｡ 

05:22.720 --> 05:26.010
让我们从延迟系数gamma开始｡ 

05:26.020 --> 05:31.680
既然这是一个变量, 我们想要依附于我们的对象, 我们从自我开始｡ 

05:31.690 --> 05:35.860
所以gamma是我们当前模型的一个变量｡ 

05:35.890 --> 05:42.760
所以self that gamma等于在创建类的对象时输入的参数｡ 

05:42.760 --> 05:46.680
这是第二个参数｡ 

05:46.690 --> 05:50.440
所以第二个论点是奖励窗口｡ 

05:50.590 --> 05:52.240
那么这个奖励窗口是什么呢？

05:52.270 --> 06:00.910
这是最近100次奖励的平均值的滑动窗口, 我们将用它来评估人工智能性能的演变｡

06:00.910 --> 06:06.190
你知道, 我们会有平均的奖励进入这个奖励窗口, 将滑动随着时间的推移｡ 

06:06.190 --> 06:11.620
我们要观察的是最后100个奖励的平均值随时间而增加｡ 

06:11.650 --> 06:18.070
所以我们用self点reward初始化它, 下划线window｡ 

06:18.430 --> 06:25.150
因为这是一个滑动窗口, 显示最近100个奖励的平均值, 我们把它初始化为一个空列表,

06:25.150 --> 06:31.660
然后我们把奖励的平均值随时间的推移添加进去.

06:32.770 --> 06:35.190
好吧, 那么, 更令人兴奋｡ 

06:35.200 --> 06:37.420
让我们创建神经网络｡ 

06:37.420 --> 06:43.600
所以我们称之为self点模型, 因为基本上这是模型的核心｡ 

06:43.600 --> 06:44.980
所以我称之为模特｡ 

06:45.770 --> 06:51.290
这个模型就是网络类的一个对象.

06:51.290 --> 07:01.610
为了创建这样一个对象, 我们取我们的类network, 然后括号, 这里我们只输入network类的参数｡

07:01.610 --> 07:07.850
但是我们把这些参数放在了init函数的参数中, 所以我们只需要把它们复制到这里,

07:07.850 --> 07:12.410
然后粘贴到网络类中.

07:12.980 --> 07:13.850
好了

07:13.850 --> 07:19.280
通过这行代码, 我们为深度学习模型创建了一个神经网络｡ 

07:20.020 --> 07:20.760
好极了｡ 

07:20.770 --> 07:22.620
那我们就创造一个回忆吧｡ 

07:22.630 --> 07:28.930
我们再创建一个新的变量, 我们称之为self, 点记忆｡ 

07:29.710 --> 07:34.090
同样, 这是一个重放内存类的对象.

07:34.090 --> 07:40.210
我们把我们的类名, 复制一下, 粘贴到这里.

07:40.210 --> 07:49.660
在括号中我们需要输入容量, 因为容量是init函数的一个参数, 这是我们需要输入的唯一参数｡

07:49.990 --> 07:51.910
那么, 我们要选择什么样的容量呢？

07:51.910 --> 07:57.370
记住, 对应于转变的次数, 事件的次数, 较少的状态, 新的状态,

07:57.370 --> 07:59.320
较少的行动和较少的奖励｡

07:59.620 --> 08:08.710
就像前面的教程中提到的, 我们将把100, 000个, 100, 000个转换放入内存中,

08:08.710 --> 08:17.350
然后我们将从内存中采样, 以获得少量的随机转换, 这就是模型将学习的基础｡

08:18.080 --> 08:18.500
好吧, 我会的

08:18.590 --> 08:20.170
现在我们有了记忆｡ 

08:20.180 --> 08:20.960
好极了｡ 

08:20.990 --> 08:23.090
现在, 让我们来看看优化器｡ 

08:23.180 --> 08:28.700
因此, 我们创建了一个新的变量self, 称为optimizer｡ 

08:29.480 --> 08:35.200
因此, 优化器是我们未来GQ的另一个变量, 一个自我优化的对象｡ 

08:35.210 --> 08:43.370
现在, 如果我们返回, 您可以看到我们导入了torch, 即Optim, 它是torch的一个模块,

08:43.370 --> 08:46.940
包含了执行随机梯度下降的所有工具｡

08:46.940 --> 08:54.200
当然, 它包含一些优化器, 我们给了它一个快捷方式optim,

08:54.200 --> 09:02.990
因此, 这里我们要做的是采用模型Optim, 它是Optim的火炬, 从这个模块中, 我们要采用一个优化器｡

09:02.990 --> 09:05.510
如您所见, 它们都列在这里｡ 

09:05.630 --> 09:07.280
他们中的许多人都很优秀｡ 

09:07.280 --> 09:10.400
例如, 武器道具是一个很好的优化器｡ 

09:10.430 --> 09:15.860
例如, 强烈建议将其用于常规神经网络或无监督深度学习｡ 

09:15.980 --> 09:22.040
但是另一个非常好的, 我们将选择的是原子优化器｡ 

09:22.310 --> 09:26.330
这就是你会看到的, 与这一个将得到一个很好的自动驾驶汽车｡ 

09:26.330 --> 09:29.120
但是, 同样, 完全欢迎你尝试其他的｡ 

09:29.120 --> 09:32.600
你可以试试武器道具, 但对于我们的模型, 我们将选择原子｡ 

09:32.600 --> 09:37.100
我按下回车键, 你会注意到这里有一个大写字母A.

09:37.100 --> 09:40.340
这是因为我们正在创建一个atom类的对象｡ 

09:40.340 --> 09:44.780
这是一个类, 但对象本身将是一个原子优化器｡ 

09:44.780 --> 09:47.930
但由于这是一个类, 我们需要输入一些参数｡ 

09:47.930 --> 09:55.130
Atom类的参数和参数都是可以自定义您的Atom优化器的参数｡

09:55.130 --> 10:00.230
例如, 这通常是学习速率､ 衰减或其他参数｡ 

10:00.230 --> 10:05.510
除了获取模型的所有参数外, 我们还将指定一个学习率｡ 

10:05.720 --> 10:12.650
因此, 说到我们模型的参数, 我们可以用self dot模型来得到它们｡ 

10:12.650 --> 10:17.330
这就是我们在这里创建的模型, 来自我们网络课程的自学模型｡ 

10:17.330 --> 10:18.800
如此自学成才的典范｡ 

10:18.800 --> 10:27.770
然后为了评估模型的参数, 我们添加了另一个点, 然后简单地用括号括起参数｡

10:27.980 --> 10:34.880
这只是将原子优化器连接到我们的神经网络, 就是我们在这里创建的那个｡ 

10:35.720 --> 10:42.130
然后, 就像我们刚才提到的, 我们要加上一个学习率,

10:42.140 --> 10:49.130
它的自变量是l, r, 我们要把它设为一个值, 这样学习就不会发生得太快｡

10:49.160 --> 10:53.630
如果我们的学习率太大, 那么人工智能就不能正确学习｡ 

10:53.630 --> 10:58.730
我们想给予人工智能一些时间去探索, 从它的错误中学习｡ 

10:58.730 --> 11:04.100
你知道, 当我们惩罚它的时候, 当它犯了一些错误的时候,

11:04.100 --> 11:08.690
比如走到沙子上或者太靠近一堵墙的时候, 我们想给予人工智能一些时间来学习｡

11:08.690 --> 11:11.930
我们希望等待神经网络正确更新｡ 

11:11.930 --> 11:20.480
所以我在尝试了几种方法后得到的学习率的一个很好的值是0｡  01.

11:21.050 --> 11:21.410
好吧, 我会的

11:21.410 --> 11:24.500
这就是我们创建优化器所需要的一切｡ 

11:24.500 --> 11:28.130
所以基本上我们是在创建一个atom类的对象｡ 

11:28.400 --> 11:28.910
好极了｡ 

11:28.910 --> 11:35.750
最后三个变量是构成过渡事件的变量｡ 

11:35.930 --> 11:39.920
这是最后一个状态, 最后一个部分, 最后一个奖励｡ 

11:39.920 --> 11:44.690
这基本上就是我们现在要创建的, 我们只需要初始化它们｡ 

11:45.050 --> 11:46.820
我们从上次约会开始吧｡ 

11:46.820 --> 11:55.910
最后一个日期, 我们称之为self, 点, 最后一个下划线状态, 然后我们如何初始化它？

11:55.910 --> 12:04.670
记住, 最后一个状态是一个五维向量, 一个编码环境中一个状态的向量｡

12:04.670 --> 12:10.640
提醒一下, 这五个维度是三个传感器的三个信号左, 直, 右,

12:10.640 --> 12:14.540
方向和负方向｡

12:14.990 --> 12:20.990
所以这是一个直观意义上的向量, 但是对于PyTorch来说, 它需要比向量更大的意义｡ 

12:21.020 --> 12:23.600
它实际上需要一个火炬张量｡ 

12:23.600 --> 12:29.930
但它不仅需要是一个火炬张量, 而且还需要多一个维度, 我喜欢称之为假维度,

12:29.930 --> 12:33.350
对应于批次｡

12:33.350 --> 12:38.270
这是因为最后一个状态将是神经网络的输入｡ 

12:38.270 --> 12:44.180
但是, 在使用神经网络时, 无论是使用TensorFlow carries还是PyTorch,

12:44.180 --> 12:47.990
输入向量本身都不能是简单向量｡

12:47.990 --> 12:49.490
一定是一批的｡ 

12:49.610 --> 12:57.650
网络只能接受一批输入观测值, 因此我们不仅要为输入状态向量创建一个张量,

12:57.650 --> 13:04.430
还要创建与该批观测值对应的伪维数｡

13:05.000 --> 13:09.530
让我们这样做, 我们从初始化火炬张量开始｡ 

13:09.530 --> 13:12.230
所以要做到这一点, 没有什么比这更简单的了｡ 

13:12.230 --> 13:21.770
我们用火炬库, 然后点, 然后我们要用张量类, 因为你可能已经猜到了,

13:21.770 --> 13:27.650
这将创建一个新的张量类对象, 也就是张量对象｡

13:27.980 --> 13:29.020
在这个张量类中｡ 

13:29.180 --> 13:34.380
我们需要输入一个参数来指定张量的大小｡ 

13:34.400 --> 13:38.620
你可以把张量想象成一个只有一种类型的数组｡ 

13:38.630 --> 13:45.590
但基本上, 这表示的是输入状态, 你可以看到它是一个向量｡ 

13:45.980 --> 13:49.290
所以要指定这个张量必须包含的元素数｡ 

13:49.310 --> 13:54.410
当然, 我们需要使用输入大小,

13:54.410 --> 13:57.140
因为输入大小正好是输入状态向量的维数｡

13:57.350 --> 13:58.940
现在我应该说是传感器｡ 

13:58.940 --> 14:05.420
所以我们只需要在张量类中输入, 就可以创建张量对象｡ 

14:05.810 --> 14:07.160
这是输入大小｡ 

14:07.310 --> 14:10.340
稍后, 输入大小将等于5｡ 

14:11.190 --> 14:12.220
好吧, 那很好｡ 

14:12.240 --> 14:13.520
这是第一件事｡ 

14:13.530 --> 14:16.920
我们刚刚初始化了一个张量, 它应该是这样的｡ 

14:17.310 --> 14:19.920
但是, 记住, 我们需要做另一件事｡ 

14:19.920 --> 14:26.010
我们需要创建一个伪维度, 因为这是网络期望的输入, 我们需要创建一个伪维度,

14:26.010 --> 14:31.980
顺便说一句, 它必须是第一个维度｡

14:31.980 --> 14:37.650
你知道, 对应于批次的伪维度将是最后一个变量的第一个维度｡ 

14:38.040 --> 14:42.960
要做到这一点, 我们只需要加上点然后挤压｡ 

14:44.000 --> 14:49.400
然后在一些括号里, 我们需要输入这个模糊维度的索引｡ 

14:49.400 --> 14:54.380
就像我刚才说的, 这个假维度必须是状态的第一维度｡ 

14:54.650 --> 15:03.140
由于Python中的索引从零开始, 我们需要输入零, 这样这个新的维度就成为了第一个维度｡

15:03.290 --> 15:09.260
所以我们有一个对应于批次的第一维, 然后是对应于张量的第一维,

15:09.260 --> 15:13.280
它包含了你输入状态的五个元素｡

15:13.280 --> 15:16.820
有三个信号方向和负方向｡ 

15:17.120 --> 15:22.640
然后, 我们开始, 我们初始化我们的输入状态, 使之完全完美｡ 

15:23.060 --> 15:25.460
还有两个变数｡ 

15:25.460 --> 15:31.730
因为下一个变量是最后一个操作, 所以这就容易多了｡ 

15:31.970 --> 15:36.110
这是一个新的变量, 我们为对象的上一个动作创建的｡ 

15:36.230 --> 15:43.430
记住, 在本节的第一个教程中, 我告诉过你们,

15:43.430 --> 15:51.230
动作要么是01, 要么是2, 然后使用动作2的旋转向量, 我们将把这些动作的索引转换成旋转的角度,

15:51.230 --> 15:57.830
我提醒你们, 是020或-20｡

15:57.830 --> 16:00.800
我们可以用它来刷新我们的记忆｡ 

16:00.950 --> 16:02.930
它就在这里

16:02.930 --> 16:04.370
通过旋转动作｡ 

16:04.640 --> 16:08.990
如果action为零, 那么, 这将对应于这里的第一个索引｡ 

16:08.990 --> 16:14.240
所以0, 如果作用量是1, 这将对应于索引, 这个向量的1｡ 

16:14.240 --> 16:15.380
所以20度｡ 

16:15.380 --> 16:18.950
如果作用力是2, 我们会得到-20度｡ 

16:18.950 --> 16:22.700
这将是我们的车的旋转角度, 当我们玩的行动｡ 

16:23.380 --> 16:24.070
好吧, 我会的

16:24.070 --> 16:31.600
因此, 因为作用量是01或2, 所以作用量是一个简单的数｡

16:31.600 --> 16:35.370
所以很简单, 我们可以将它初始化为零｡ 

16:35.380 --> 16:38.140
我们不需要在这里创建任何张量或其他任何东西｡ 

16:38.140 --> 16:40.750
我们只需要把它初始化为零｡ 

16:41.170 --> 16:44.410
最后, 嗯, 这是最后的奖励｡ 

16:44.410 --> 16:48.190
所以自我打点最后的奖励｡ 

16:48.700 --> 16:49.660
我们走吧｡ 

16:49.660 --> 16:56.230
同样, 奖励是一个浮点数, 我提醒你, 它在负1和正1之间｡ 

16:56.230 --> 16:57.670
又是这个号码｡ 

16:57.670 --> 17:02.830
至于这个动作, 我们将它初始化为零, 就这样｡ 

17:02.830 --> 17:06.070
祝贺您init函数已准备就绪｡ 

17:06.070 --> 17:08.740
所以现在我们准备好进入令人兴奋的部分了｡ 

17:08.740 --> 17:16.210
实际上对我来说最重要的事情就是决定每次玩哪个动作｡

17:16.210 --> 17:23.110
这正是我们在下一个教程中要做的, 通过创建Select Action方法｡ 

17:23.230 --> 17:25.240
我们将在下一个教程中进行此操作｡ 

17:25.240 --> 17:27.250
在那之前, 好好享受我｡ 
