WEBVTT

00:00.390 --> 00:02.370
大家好, 欢迎学习本教程｡ 

00:02.490 --> 00:04.470
现在我们有了模型的大脑｡ 

00:04.500 --> 00:06.170
我们还有优化器｡ 

00:06.180 --> 00:09.810
所以基本上我们已经准备好训练不同的探员了｡ 

00:09.810 --> 00:11.520
那是我们不同的大脑｡ 

00:11.520 --> 00:18.180
所以从现在开始, 我们将创建一个包含所有a3c算法的大型train函数｡ 

00:18.180 --> 00:25.080
因此我们要在这列火车上实现的, P文件就是这个巨大的火车函数｡ 

00:25.080 --> 00:29.220
他们将只是这个大火车功能, 没有别的, 没有阶级｡ 

00:29.220 --> 00:33.840
但我们将在本模块的最后一步中使用此train函数和主代码｡ 

00:33.840 --> 00:34.850
好了, 我们走吧｡ 

00:34.860 --> 00:39.000
但是在我们开始之前, 你可以注意到, 首先我们导入一些库｡ 

00:39.000 --> 00:44.700
这是带torch模块的经典库, 我指的是torch库, 然后是创建Atari环境的最终库,

00:44.700 --> 00:48.900
这将是突破｡

00:48.900 --> 00:55.710
然后, 我们将从模型文件导入活动类｡ 

00:56.130 --> 01:05.550
最后, 我们将使用火炬大学生的变量来运行高性能的梯度计算, 这要归功于动态图｡

01:05.730 --> 01:11.880
然后我们有一个确保共享梯度的函数, 我不想在这上面花太多时间,

01:11.880 --> 01:20.250
因为首先, 如果代理使用的模型没有任何共享梯度, 这个函数将确保一切都正常工作｡

01:20.250 --> 01:22.980
所以这就是为什么它被称为确保共享grats｡ 

01:22.980 --> 01:27.870
而另一个原因是我认为这个功能是不必要的, 但我们永远不知道｡ 

01:27.870 --> 01:32.820
而且至少有了这个, 就可以100%确定代码会正确执行｡ 

01:32.820 --> 01:34.620
但这并不重要｡ 

01:34.620 --> 01:40.410
我们必须关注的是我们现在就要开始制作的火车功能｡ 

01:40.770 --> 01:44.280
我们开始吧, 戴夫和训练｡ 

01:44.280 --> 01:45.960
我们就简单地称之为火车｡ 

01:45.960 --> 01:48.720
而这个train函数将采用几个参数｡ 

01:48.810 --> 01:50.220
第一个是等级｡ 

01:50.220 --> 01:52.440
我将在第二节中解释它是什么｡ 

01:52.710 --> 02:02.640
第二个参数是params, 这样所有的参数都是环境的, 第三个参数是要共享的模型｡

02:02.910 --> 02:09.990
大家知道, 共享模型是代理在一定数量的步骤上运行其小探索的模型｡

02:10.410 --> 02:14.910
最后, 最后一个参数是优化器｡ 

02:14.910 --> 02:16.980
那是我们之前做的那个｡ 

02:17.620 --> 02:18.480
太完美了｡ 

02:18.490 --> 02:19.930
这就是我们的四个论点｡ 

02:19.930 --> 02:23.870
现在, 我们准备开始实施这一列车功能｡ 

02:23.890 --> 02:28.840
所以我们要做的第一件事是, 你知道, 你记得a3c代表什么｡ 

02:28.840 --> 02:32.320
它代表一个同步的活跃的批评家代理人｡ 

02:32.320 --> 02:34.780
所以在a3c中, 有一个同步的｡ 

02:34.780 --> 02:40.900
正如你所理解的, 我们必须同步每个训练代理, 为了同步它们,

02:40.900 --> 02:45.460
我们将使用秩来移动每个种子｡

02:45.460 --> 02:52.030
所以这里的秩参数只是为了移动种子, 使每个训练代理同步｡ 

02:52.360 --> 02:59.200
因此, 例如, 如果有n个训练代理, 那么等级将从1到N,

02:59.200 --> 03:02.360
并且每个代理将有一个从1到n的整数｡

03:02.380 --> 03:10.990
因此, 当我们通过一个线程移动种子时, 该线程创建的所有伪随机数将完全独立于其他线程｡

03:11.320 --> 03:18.550
然而, 种子是固定的数字, 所以当我们再现经验时,

03:18.550 --> 03:23.440
我们会发现完全相同的事件, 这是因为它是关于种子的确定性｡

03:23.440 --> 03:25.390
所以理解这点很重要｡ 

03:25.390 --> 03:34.120
这就是为什么我们要做的第一件事就是同步每个训练代理通过使用这里的秩来移动种子｡

03:34.120 --> 03:35.020
所以我们开始吧｡ 

03:35.020 --> 03:38.710
为此, 我们要把我们的火炬图书馆｡ 

03:39.010 --> 03:45.250
然后我们将得到带有手动下划线和种子括号的种子｡ 

03:45.250 --> 03:46.420
这是一个函数｡ 

03:46.420 --> 03:53.020
现在我们要取所有代理的种子, 我们可以用params, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,

03:53.020 --> 03:56.620
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,

03:56.620 --> 03:59.650
我们在这里加一个字｡ 

04:00.340 --> 04:09.370
这将转移种子与排名, 以剥夺每个培训代理, 因为有一个种子, 为每个培训代理｡

04:09.820 --> 04:11.380
好了, 第一件事搞定了｡ 

04:11.380 --> 04:13.090
现在是下一步｡ 

04:13.090 --> 04:15.310
下一步是获取环境｡ 

04:15.310 --> 04:20.770
因此, 我们将创建一个新的变量, 称为env, 现在我们将使用end模块中的create

04:20.770 --> 04:25.990
Atari end函数来创建分线环境｡

04:25.990 --> 04:27.930
那就是得到突围的环境｡ 

04:27.940 --> 04:33.460
所以我们用这个函数, 创建雅达利和｡ 

04:34.040 --> 04:39.680
现在我们只需要输入一个参数, 就是环境的参数,

04:39.680 --> 04:42.550
我们有这些参数是因为这是train函数的输入之一｡

04:42.560 --> 04:47.270
此参数将成为接线盒环境的参数｡ 

04:47.270 --> 04:54.920
因此, 为了获得突破环境, 我们取这个参数, 然后点,

04:54.920 --> 05:01.910
然后我们得到env名称, 它在未来的下一个代码中, 包含将执行整个代码的主函数,

05:01.910 --> 05:05.020
将是突破年｡

05:05.850 --> 05:06.180
好吧, 我会的

05:06.180 --> 05:08.940
这样我们的环境就完美了｡ 

05:09.330 --> 05:15.810
现在, 下一步是在其中一个代理上对齐环境的种子｡ 

05:15.900 --> 05:17.340
我们为什么要这么做？

05:17.370 --> 05:25.770
这是因为, 请记住, a3c模型的每个代理人都有自己的环境愿景, 就像它自己的环境副本一样｡

05:25.770 --> 05:31.890
因此, 我们需要在环境的一个特定版本上协调每个代理｡ 

05:31.890 --> 05:37.230
为了做到这一点, 我们将使用种子, 因为每一个种子都决定了一个特定的环境｡ 

05:37.230 --> 05:42.060
因此, 通过将不同的种子与每个代理相关联, 我们将得到我们想要的结果｡ 

05:42.090 --> 05:45.960
也就是说, 每个代理都有自己的环境｡ 

05:46.350 --> 05:47.730
那么我们如何才能做到这一点呢？

05:47.730 --> 05:57.270
我们可以取环境, 然后添加它, 然后使用seed函数来选择我们想为环境获得的种子｡

05:57.270 --> 06:02.460
现在要将环境的种子与代理的种子对齐, 我们只需要得到这个,

06:02.460 --> 06:10.380
因为它对应于代理的种子, 由于等级的原因, 代理被移动了, 得到了这个同步训练代理,

06:10.380 --> 06:13.800
因为它们都在不同的种子上｡

06:13.950 --> 06:16.350
所以我们只需要把它放在这里｡ 

06:16.350 --> 06:20.220
这将使环境的种子与其中一个代理对齐｡ 

06:20.970 --> 06:21.530
好吧, 我会的

06:21.990 --> 06:26.940
现在我们将得到我们的模型, 即我们的三个关键大脑｡ 

06:26.940 --> 06:32.070
现在我们要使用模型文件中的活动评论家类｡ 

06:32.070 --> 06:40.950
我们要创建一个演员类的对象, 如果你愿意, 我们可以称之为对象模型或大脑.

06:40.950 --> 06:49.350
但基本上这个对象将包含所有的卷积､ STM､ 线性全连接和传播信号的前向函数｡

06:49.350 --> 06:58.590
所以它基本上包含了演员和评论家的大脑, 能够将信号传播到整个大脑, 以获得最终的输出｡

06:59.010 --> 07:00.000
所以我们开始吧｡ 

07:00.000 --> 07:02.520
让我们创建模型｡ 

07:02.520 --> 07:06.570
正如我们所说的, 我们要把这个对象模型称为｡ 

07:06.900 --> 07:14.940
所以我们创建了一个act类的对象, 然后我们取了我们的类, actor, critic,

07:14.940 --> 07:17.130
现在记住我们需要输入什么参数｡

07:17.130 --> 07:22.350
这实际上是init函数的参数, 所以我们不需要输入它｡ 

07:22.560 --> 07:26.250
这就是我们在init方法中使用对象所要做的｡ 

07:26.250 --> 07:31.500
但是我们必须输入的参数是nom输入, 也就是输入形状｡ 

07:31.500 --> 07:38.460
这是我们输入的维度, 图像和动作空间, 包含了一系列的动作｡

07:38.460 --> 07:42.480
所以让我们把这些参数输入train函数｡ 

07:42.480 --> 07:49.770
第一个, 我们可以用环境和点得到它, 然后我们用观察空间｡ 

07:50.980 --> 07:56.800
这是观察空间, 然后是dut, 然后得到输入的个数, 我们得到形状｡ 

07:57.470 --> 07:58.970
括号零｡ 

07:59.000 --> 07:59.390
好吧, 我会的

07:59.390 --> 08:01.010
这就是四个数字输入｡ 

08:01.010 --> 08:04.550
现在是行动空间｡ 

08:04.580 --> 08:06.080
嗯, 那几乎一样｡ 

08:06.080 --> 08:09.620
但我们需要从我们的环境中得到我们是进口的｡ 

08:09.620 --> 08:11.900
然后是dut, 然后是动作空间｡ 

08:12.740 --> 08:13.160
好吧, 我会的

08:13.160 --> 08:17.770
这就给了我们在创建对象时需要输入的参数｡ 

08:17.780 --> 08:20.030
创造一个阶级行为的道德｡ 

08:20.630 --> 08:25.000
现在我们有了模型, 下一步是准备输入状态｡ 

08:25.010 --> 08:27.530
所以记住, 我们仍然在做深度强化学习｡ 

08:27.530 --> 08:34.340
因此, 输入状态是输入图像, 因此, 这最初将是一个numpy数组, 它将包含一个通道,

08:34.340 --> 08:40.580
因为我们将处理白色图像, 它将具有42 × 42的维度｡

08:40.730 --> 08:46.250
但重要的是要理解并记住, 输入状态就是输入图像｡ 

08:46.400 --> 08:51.800
首先, 我们要做的是得到编号, 然后我们将它转换成火炬张量｡ 

08:51.800 --> 08:58.880
但第一步和我们之前做的一样, 是建立一个正确的帝国, 要建立起来, 其实很简单｡

08:58.880 --> 09:05.030
首先, 我们需要为输入状态创建一个变量, 我们将其命名为state,

09:05.030 --> 09:12.770
为了得到数组, 我们只需要取我们的环境, 然后添加它, 然后使用reset函数｡

09:12.920 --> 09:22.340
这将初始化state为一个1 × 42 × 42的维度数组, 1表示一个通道,

09:22.340 --> 09:28.220
所以黑白图像, 42 × 42当然是图像的维度,

09:28.220 --> 09:30.620
宽度上的像素数和高度上的像素数｡

09:30.620 --> 09:34.490
所以基本上这就是我们要处理的维度｡ 

09:34.520 --> 09:41.270
现在, 现在我们已经有了这个, 因为这将得到这些阵列中的图像,

09:41.270 --> 09:45.320
现在我们可以把它们转换成手电筒传感器｡

09:45.320 --> 09:50.750
为了做好这一点, 我们将再次更新状态, 因为我们不需要保留病毒｡ 

09:50.930 --> 09:54.950
这就是我们使用手电筒模块的地方｡ 

09:54.950 --> 09:57.470
记住, 我们已经为末日做过了｡ 

09:57.590 --> 10:05.080
我们使用函数from underline num by par括号,

10:05.100 --> 10:08.300
在这个函数中我们需要输入我们想要转换成火炬张量的数字｡

10:08.300 --> 10:09.950
这就是国家｡ 

10:09.950 --> 10:17.030
numpy数组中的先前版本的状态将通过应用来自它们的by函数而变成一个火炬张量｡

10:17.030 --> 10:24.740
这就从状态中创建了一个张量, 现在我们只需要初始化完成变量｡ 

10:24.740 --> 10:40.580
请记住done变量通常是表示一集结束或者游戏结束的变量, 这里我们只想引入这个done变量并初始化为true来指定当游戏结束时这个done变量将等于true

10:41.000 --> 10:45.650
这对以后的游戏很有用, 这样AI就不会无限期地玩游戏｡ 

10:46.690 --> 10:47.230
好吧, 我会的

10:47.230 --> 10:55.150
这基本上就是这个训练函数的开始, 包括一些初始化和一些我们必须做的事情｡

10:55.180 --> 11:00.370
这里最重要的部分是我们必须同步每个训练代理｡ 

11:00.370 --> 11:04.870
这就是我们必须应用的a3c模型的1/1原理｡ 

11:04.870 --> 11:09.660
现在, 在下一个教程中, 我们将继续进行与共享模型的同步｡ 

11:09.670 --> 11:15.940
我们不要忘记, 有不同的模型, 但也有共享模型, 这是一个所有代理共享的模型｡

11:15.940 --> 11:21.850
所以我们必须与这个共享模型同步, 这样每个代理都可以得到这个共享模型,

11:21.850 --> 11:25.420
以进行一定数量步骤的小探索｡

11:25.720 --> 11:27.940
这就是我们在下一个教程中要做的｡ 

11:27.940 --> 11:29.260
在那之前, 好好享受吧｡ 

11:29.260 --> 11:29.770
一､ 
