WEBVTT

00:00.210 --> 00:02.220
大家好, 欢迎学习本教程｡ 

00:02.370 --> 00:07.680
好的, 在之前的教程中, 我们制作了大脑, 或者如果你想要a3c的大脑,

00:07.680 --> 00:09.440
现在我们需要训练这个大脑｡

00:09.450 --> 00:12.900
但为了训练这些大脑, 我们需要一个优化器｡ 

00:12.930 --> 00:17.670
这两个函数将用于随机梯度下降,

00:17.670 --> 00:24.600
根据它们对预测和目标之间误差的贡献程度来更新权重｡ 到目前为止,

00:24.600 --> 00:30.630
我们在第一个和第二个模块中使用了原子优化器, 并在训练中使用了火炬｡

00:30.630 --> 00:41.310
但正如我告诉你的, 我们正在处理一个非常具有挑战性的问题, 即突破和a3c算法本身是不足以解决这个问题｡

00:41.310 --> 00:49.290
我们需要一些定制的优化器和很多不同的技巧来解决这个问题, 而不等待年龄｡

00:49.290 --> 00:56.730
这就是这样做的目的, 这就是为什么我们有一个基于原子优化器的单独的自定义优化器,

00:56.730 --> 01:01.110
它包含在这个共享的原子类中｡

01:01.110 --> 01:02.670
为什么共享原子？

01:02.670 --> 01:07.980
这是因为它实际上是原子优化器, 但它将在共享状态上工作｡ 

01:07.980 --> 01:11.130
因此, 我们将在本教程中解释它的工作原理｡ 

01:11.130 --> 01:15.840
因此, 我们将在这里介绍不同的函数, 但不对它们进行编码,

01:15.840 --> 01:18.480
因为我们希望为下一次实现保留一些能量｡

01:18.480 --> 01:22.950
这是火车, PI文件, 将采取超过100行代码｡ 

01:22.950 --> 01:24.330
所以要做好准备｡ 

01:24.330 --> 01:30.210
所以我们会在一个教程里, 来解释这是怎么回事｡ 

01:30.210 --> 01:31.920
我们现在就开始吧｡ 

01:32.650 --> 01:33.040
好吧, 我会的

01:33.040 --> 01:38.530
首先, 我们介绍这个类的共享项, 它包含三个函数：init函数,

01:38.530 --> 01:40.750
共享内存函数和step函数｡

01:40.960 --> 01:48.250
我们首先要做的是从atom继承, 这个atom当然是atom优化器, 我们从Optim模块,

01:48.250 --> 01:52.010
从torch库中获得｡

01:52.030 --> 01:57.000
因此, 这里我们应用继承来获得所有与原子优化器相关的工具｡ 

01:57.010 --> 01:59.080
然后我们从init函数开始｡ 

01:59.080 --> 02:00.340
那么这里发生了什么？

02:01.040 --> 02:09.020
首先, 我们使用一个超级函数来继承所有的工具和原子类的所有基本参数｡

02:09.020 --> 02:16.000
这些基本参数在这里是params, 学习率, beta, epsilon和权重衰减｡ 

02:16.010 --> 02:20.360
然后我们开始一个for循环, 第一个for循环, for group in self.

02:20.660 --> 02:21.610
参数组｡ 

02:21.620 --> 02:23.940
那么首先, 什么是params组？

02:23.960 --> 02:28.280
参数化组的Self包含优化程序的所有属性｡ 

02:28.280 --> 02:32.480
在这些属性中, 我们有一些参数需要优化｡ 

02:32.480 --> 02:38.840
我们要优化的这些参数是包含在self dot params groups

02:38.840 --> 02:40.730
params中的网络权重｡

02:40.730 --> 02:42.100
好了, 我们走吧｡ 

02:42.110 --> 02:44.690
组属于参数化组的自身｡ 

02:44.690 --> 02:50.840
这里我们有第二个for循环, 它将得到我们想要优化的参数,

02:50.840 --> 02:54.560
这些参数正好包含在self点参数组params中｡

02:54.650 --> 03:00.980
基本上, 我们将遍历包含所有参数的self参数组, 对于self点参数组中的每组参数,

03:00.980 --> 03:07.280
我们将遍历要优化的参数｡

03:07.310 --> 03:14.210
因此, 这里的group params中的p表示我们想要优化的每个传感器的权重｡ 

03:14.210 --> 03:16.940
所以对于每个我们想要优化的权重张量｡ 

03:16.940 --> 03:21.350
然后在这个循环中, 这四行代码会发生什么？

03:21.650 --> 03:30.800
基本上, Atom Optimizer所做的更新是基于梯度的指数移动平均值｡

03:31.160 --> 03:32.810
这就是这行代码｡ 

03:32.810 --> 03:38.210
这是矩梯度的指数移动平均值, 一阶的｡ 

03:38.210 --> 03:46.790
但Atom所做的更新不仅基于此, 它还基于梯度平方根的指数移动平均值｡

03:47.000 --> 03:51.650
这是一个指数移动平均值, 它的移动梯度是2或2｡ 

03:51.800 --> 03:57.320
这是一阶指数移动平均数, 这是二阶指数移动平均数,

03:57.320 --> 04:00.530
梯度的EMA.

04:00.530 --> 04:12.260
如果你想更深入地了解指数移动平均线是如何工作的, 我强烈建议你看看这篇研究论文, 亚当,

04:12.260 --> 04:20.480
随机优化的一种方法, 因为基本上我们现在实现的原子优化器就是基于这里的算法一｡

04:20.630 --> 04:27.380
因此, 如果您想了解算法如何工作的更多细节, 那么, 本文肯定会有所帮助｡

04:27.380 --> 04:32.600
然后你会对原子更新规则的算法做一些进一步的解释｡ 

04:32.600 --> 04:38.990
所以, 你知道, 只有当你想在攻击我们之后要做的大火车功能之前攻击这个功能的时候｡

04:39.230 --> 04:45.740
好了, 让我们回到Python, 现在我们来看看第二个函数, 共享内存｡ 

04:46.010 --> 04:47.810
所以现在我只想说几句话｡ 

04:47.810 --> 04:55.610
这种共享内存功能的概念有点像Cuda的张量, CUDA是一种基于GPU的加速器｡

04:55.640 --> 05:03.110
所以基本上这里发生的是, 我们有这些状态的传感器, 这些状态共享这里的记忆, 这里和这里的记忆,

05:03.110 --> 05:07.790
它们的行为有点像张量, 也就是Cuda｡

05:07.970 --> 05:10.160
所以, 你知道, 加速计算｡ 

05:10.160 --> 05:17.000
但不同的是, 这里的张量是共享内存, 将计算发送到GPU或CPU的一部分,

05:17.000 --> 05:21.950
所有瘫痪的线程都可以访问｡

05:21.950 --> 05:23.510
这基本上就是它在这里所做的｡ 

05:23.510 --> 05:31.460
这有点像张量Cuda, 但它只发送到GPU或CPU的一部分, 可供并行线线程访问｡

05:31.910 --> 05:32.390
好吧, 我会的

05:32.390 --> 05:34.940
然后是最后一个函数步骤｡ 

05:34.940 --> 05:41.330
这个函数, 就像我们在本课程中使用过的原子优化器的单步方法｡

05:41.630 --> 05:47.060
同样, 这是基于算法的, 我们之前看到的同一篇论文｡ 

05:47.060 --> 05:48.500
所以这个算法｡ 

05:48.590 --> 05:53.600
所以, 如果你想详细理解下面的代码行, 那么,

05:53.600 --> 05:57.170
我再次鼓励你看一下本文中的算法｡

05:57.320 --> 06:06.980
此外, 这里所做的并不是强制性的, 因为这实际上是对优化后的原子类的step方法的复制粘贴｡

06:06.980 --> 06:09.470
那么这里基本上做了什么呢？

06:09.470 --> 06:15.350
我们可以通过使用继承来完成, 因为这里我们继承自优化的原子｡ 

06:15.350 --> 06:22.640
为了更好地使用继承, 我们可以做的, 而不是做这些, 我在这里写注释.

06:22.670 --> 06:27.530
它只是使用我们应用于共享的超级函数｡ 

06:28.290 --> 06:31.410
原子类然后是对象self｡ 

06:31.410 --> 06:34.640
这里我们只需要加上一个带括号的步骤｡ 

06:34.650 --> 06:40.470
Step是优化的item类的方法, 这是完全相同的｡ 

06:40.470 --> 06:46.410
这就是为什么我刚才说这里只是一个复制粘贴的Optim原子类的step方法｡ 

06:46.710 --> 06:55.920
所以我认为如果你用这个超级函数来代替, 共享原子和单步方法, 我们可能会得到完全一样的结果｡

06:57.090 --> 06:57.450
好吧, 我会的

06:57.450 --> 06:59.720
所以快速浏览一下很有意思｡ 

06:59.730 --> 07:02.670
基本上, 您可以将其视为原子优化器｡ 

07:02.700 --> 07:04.410
好像我们对它有了更深入的了解｡ 

07:04.410 --> 07:09.630
但是, 如果你想了解更多细节, 如果你想了解幕后发生了什么,

07:09.630 --> 07:13.950
那么, 我鼓励你看看这篇研究论文｡

07:13.980 --> 07:15.900
我会把链接在评论这里｡ 

07:15.900 --> 07:19.800
你知道, 记住, 你会有所有的代码注释在很大的细节｡ 

07:19.800 --> 07:21.900
所以如果你能看一下就好了｡ 

07:22.320 --> 07:30.270
现在我希望你们有很大的精力, 因为我们将继续学习训练文件, 它将包含这个巨大的训练函数, 它将基本上训练我们的大脑,

07:30.270 --> 07:37.440
现在我们可以这样做, 因为我们有了优化器｡

07:37.440 --> 07:40.080
所以现在好好休息, 好好睡一觉｡ 

07:40.080 --> 07:43.980
无论何时, 只要你感觉状态良好, 我们就进入下一步｡ 

07:44.220 --> 07:45.420
在那之前, 好好享受吧｡ 

07:45.420 --> 07:45.900
一､ 
