Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
OpenDocCN
d2l-zh
提交
659db800
D
d2l-zh
项目概览
OpenDocCN
/
d2l-zh
通知
2
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
D
d2l-zh
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
659db800
编写于
5月 03, 2018
作者:
A
Aston Zhang
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
dl compute class deaccent
上级
6df3fa14
变更
3
隐藏空白更改
内联
并排
Showing
3 changed file
with
16 addition
and
19 deletion
+16
-19
chapter_gluon-basics/block.md
chapter_gluon-basics/block.md
+7
-7
chapter_gluon-basics/custom-layer.md
chapter_gluon-basics/custom-layer.md
+4
-4
chapter_gluon-basics/parameters.md
chapter_gluon-basics/parameters.md
+5
-8
未找到文件。
chapter_gluon-basics/block.md
浏览文件 @
659db800
...
...
@@ -49,13 +49,13 @@ class MLP(nn.Block):
*
`__init__`
:创建模型的参数。在上面的例子里,模型的参数被包含在了两个
`Dense`
层里。
*
`forward`
:定义模型的计算。
接下来我们解释一下
`MLP`
里面
用的其他命令:
接下来我们解释一下
MLP类
用的其他命令:
*
`super(MLP, self).__init__(**kwargs)`
:这句话调用
`MLP`
父类Block的构造函数
`__init__`
。这样,我们在调用
`MLP`
的构造函数时还可以指定函数参数
`prefix`
(名字前缀)或
`params`
(模型参数,下一节会介绍)。这两个函数参数将通过
`**kwargs`
传递给Block的构造函数。
*
`super(MLP, self).__init__(**kwargs)`
:这句话调用
MLP
父类Block的构造函数
`__init__`
。这样,我们在调用
`MLP`
的构造函数时还可以指定函数参数
`prefix`
(名字前缀)或
`params`
(模型参数,下一节会介绍)。这两个函数参数将通过
`**kwargs`
传递给Block的构造函数。
*
`with self.name_scope()`
:本例中的两个
`Dense`
层和其中模型参数的名字前面都将带有模型名前缀。该前缀可以通过构造函数参数
`prefix`
指定。若未指定,该前缀将自动生成。我们建议,在构造模型时将每个层至少放在一个
`name_scope()`
里。
*
`with self.name_scope()`
:本例中的两个
Dense
层和其中模型参数的名字前面都将带有模型名前缀。该前缀可以通过构造函数参数
`prefix`
指定。若未指定,该前缀将自动生成。我们建议,在构造模型时将每个层至少放在一个
`name_scope()`
里。
我们可以实例化
`MLP`
类得到
`net2`
,并让
`net2`
根据输入数据
`x`
做一次计算。其中,
`y = net2(x)`
明确调用了
`MLP`
中的
`__call__`
函数(从Block继承得到)。在Gluon中,这将进一步调用
`MLP`
中的
`forward`
函数从而完成一次模型计算。
我们可以实例化
MLP类得到
`net2`
,并让
`net2`
根据输入数据
`x`
做一次计算。其中,
`y = net2(x)`
明确调用了MLP实例
中的
`__call__`
函数(从Block继承得到)。在Gluon中,这将进一步调用
`MLP`
中的
`forward`
函数从而完成一次模型计算。
```
{.python .input n=4}
net = MLP()
...
...
@@ -73,7 +73,7 @@ print('hidden layer name with "my_mlp_" prefix:', net.hidden.name)
print('output layer name with "my_mlp_" prefix:', net.output.name)
```
接下来,我们重新定义
`MLP_NO_NAMESCOPE`
类。它和
`MLP`
的区别就是不含
`with self.name_scope():`
。这是,隐藏层和输出层的名字前都不再含指定的前缀
`prefix`
。
接下来,我们重新定义
MLP_NO_NAMESCOPE
类。它和
`MLP`
的区别就是不含
`with self.name_scope():`
。这是,隐藏层和输出层的名字前都不再含指定的前缀
`prefix`
。
```
{.python .input n=6}
class MLP_NO_NAMESCOPE(nn.Block):
...
...
@@ -95,9 +95,9 @@ print('output layer name without prefix:', net.output.name)
Block主要提供模型参数的存储、模型计算的定义和自动求导。你也许已经发现了,以上Block的子类中并没有定义如何求导,或者是
`backward`
函数。事实上,MXNet会使用
`autograd`
对
`forward`
自动生成相应的
`backward`
函数。
###
`Sequential`
类是Block的子类
###
Sequential
类是Block的子类
在Gluon里,
`Sequential`
类是Block的子类。
`Sequential`
类或实例也可以被看作是一个Block的容器:通过
`add`
函数来添加Block。在
`forward`
函数里,
`Sequential`
实例把添加进来的Block逐一运行。
在Gluon里,
Sequential类是Block的子类。Sequential类或实例也可以被看作是一个Block的容器:通过
`add`
函数来添加Block。在
`forward`
函数里,Sequential
实例把添加进来的Block逐一运行。
一个简单的实现是这样的:
...
...
chapter_gluon-basics/custom-layer.md
浏览文件 @
659db800
# 自定义层
深度学习的一个魅力之处在于神经网络中各式各样的层,例如全连接层和后面章节中将要介绍的卷积层、池化层与循环层。虽然Gluon提供了大量常用的层,但有时候我们依然希望自定义层。本节将介绍如何使用
`NDArray`
来自定义一个Gluon的层,从而以后可以被重复调用。
深度学习的一个魅力之处在于神经网络中各式各样的层,例如全连接层和后面章节中将要介绍的卷积层、池化层与循环层。虽然Gluon提供了大量常用的层,但有时候我们依然希望自定义层。本节将介绍如何使用
NDArray
来自定义一个Gluon的层,从而以后可以被重复调用。
## 不含模型参数的自定义层
...
...
@@ -14,7 +14,7 @@ from mxnet import nd, gluon
from mxnet.gluon import nn
```
下面通过继承Block自定义了一个将输入减掉均值的层
`CenteredLayer`
,并将层的计算放在
`forward`
函数里。这个层里不含模型参数。
下面通过继承Block自定义了一个将输入减掉均值的层
:CenteredLayer类
,并将层的计算放在
`forward`
函数里。这个层里不含模型参数。
```
{.python .input n=1}
class CenteredLayer(nn.Block):
...
...
@@ -52,7 +52,7 @@ y.mean()
## 含模型参数的自定义层
我们还可以自定义含模型参数的自定义层。这样,自定义层里的模型参数就可以通过训练学出来了。我们在
[
“模型参数”
](
parameters.md
)
一节里介绍了
`Parameter`
类。其实,在自定义层的时候我们还可以使用Block自带的
`ParameterDict`
类型的成员变量
`params`
。顾名思义,这是一个由字符串类型的参数名字映射到
`Parameter`
类型的模型参数的字典。我们可以通过
`get`
从
`ParameterDict`
创建
`Parameter`
。
我们还可以自定义含模型参数的自定义层。这样,自定义层里的模型参数就可以通过训练学出来了。我们在
[
“模型参数”
](
parameters.md
)
一节里介绍了
Parameter类。其实,在自定义层的时候我们还可以使用Block自带的ParameterDict类型的成员变量
`params`
。顾名思义,这是一个由字符串类型的参数名字映射到Parameter
类型的模型参数的字典。我们可以通过
`get`
从
`ParameterDict`
创建
`Parameter`
。
```
{.python .input n=7}
params = gluon.ParameterDict(prefix="block1_")
...
...
@@ -75,7 +75,7 @@ class MyDense(nn.Block):
return nd.relu(linear)
```
下面,我们实例化
`MyDense`
来看下它的模型参数。这里我们特意加了名字前缀
`prefix`
。在
[
“模型构造”
](
block.md
)
一节中介绍过,这是Block的构造函数自带的参数。
下面,我们实例化
MyDense类
来看下它的模型参数。这里我们特意加了名字前缀
`prefix`
。在
[
“模型构造”
](
block.md
)
一节中介绍过,这是Block的构造函数自带的参数。
```
{.python .input}
dense = MyDense(5, in_units=10, prefix='o_my_dense_')
...
...
chapter_gluon-basics/parameters.md
浏览文件 @
659db800
...
...
@@ -44,7 +44,7 @@ net(x)
## 访问模型参数
在Gluon中,模型参数的类型是
`Parameter`
。下面让我们创建一个名字叫“good_param”、形状为$2
\t
imes 3$的模型参数。在默认的初始化中,模型参数中的每一个元素是一个在
`[-0.07, 0.07]`
之间均匀分布的随机数。相应地,该模型参数还有一个形状为$2
\t
imes 3$的梯度,初始值为0。
在Gluon中,模型参数的类型是
Parameter类
。下面让我们创建一个名字叫“good_param”、形状为$2
\t
imes 3$的模型参数。在默认的初始化中,模型参数中的每一个元素是一个在
`[-0.07, 0.07]`
之间均匀分布的随机数。相应地,该模型参数还有一个形状为$2
\t
imes 3$的梯度,初始值为0。
```
{.python .input n=4}
my_param = gluon.Parameter("good_param", shape=(2, 3))
...
...
@@ -53,7 +53,7 @@ print('data: ', my_param.data(), '\ngrad: ', my_param.grad(),
'\nname: ', my_param.name)
```
接下来,让我们访问本节开头定义的多层感知机
`net`
中隐藏层
`hidden`
的模型参数:权重
`weight`
和偏差
`bias`
。它们的类型也都是
`Parameter`
。我们可以看到它们的名字、形状和数据类型。
接下来,让我们访问本节开头定义的多层感知机
`net`
中隐藏层
`hidden`
的模型参数:权重
`weight`
和偏差
`bias`
。它们的类型也都是
Parameter类
。我们可以看到它们的名字、形状和数据类型。
```
{.python .input n=5}
w = net.hidden.weight
...
...
@@ -68,7 +68,7 @@ print('weight:', w.data(), '\nweight grad:', w.grad(), '\nbias:', b.data(),
'\nbias grad:', b.grad())
```
另外,我们也可以通过
`collect_params`
来访问Block里的所有参数(包括所有的子Block)。它会返回一个名字到对应
`Parameter`
的字典。在这个字典中,我们既可以用
`[]`
(需要指定前缀),又可以用
`get()`
(不需要指定前缀)来访问模型参数。
另外,我们也可以通过
`collect_params`
来访问Block里的所有参数(包括所有的子Block)。它会返回一个名字到对应
Parameter实例的字典。在这个字典中,我们既可以用
`[]`
(需要指定前缀),又可以用
`get`
函数
(不需要指定前缀)来访问模型参数。
```
{.python .input n=7}
params = net.collect_params()
...
...
@@ -130,10 +130,7 @@ print('output layer modified weight:', net.output.weight.data())
## 延后的初始化
我们在本节开头定义的
`MLP`
模型的层
`nn.Dense(4)`
和
`nn.Dense(2)`
中无需指定它们的输入单元个数。定义
`net = MLP()`
和输入数据
`x`
。我们在
[
“模型构造”
](
block.md
)
一节中介绍过,执行
`net(x)`
将调用
`net`
的
`forward`
函数计算模型输出。在这次计算中,
`net`
也将从输入数据
`x`
的形状自动推断模型中每一层尚未指定的输入单元个数,得到模型中所有参数形状,并真正完成模型参数的初始化。因此,在上面两个例子中,我们总是在调用
`net(x)`
之后访问初始化的模型参数。
这种延后的初始化带来的一大便利是,我们在构造模型时无需指定每一层的输入单元个数。
我们在本节开头定义的MLP类里的层
`nn.Dense(4)`
和
`nn.Dense(2)`
中无需指定它们的输入单元个数。给定
`net = MLP()`
和输入数据
`x`
。我们在
[
“模型构造”
](
block.md
)
一节中介绍过,执行
`net(x)`
将调用
`net`
的
`forward`
函数计算模型输出。在这次计算中,
`net`
也将从输入数据
`x`
的形状自动推断模型中每一层尚未指定的输入单元个数,得到模型中所有参数形状,并真正完成模型参数的初始化。因此,在上面两个例子中,我们总是在调用
`net(x)`
之后访问初始化的模型参数。这种延后的初始化带来的一大便利是,我们在构造模型时无需指定每一层的输入单元个数。
下面,我们具体来看延后的初始化是怎么工作的。让我们新建一个网络并打印所有模型参数。这时,两个全连接层的权重的形状里都有0。它们代表尚未指定的输入单元个数。
...
...
@@ -159,7 +156,7 @@ net.collect_params()
## 共享模型参数
在有些情况下,我们希望模型的多个层之间共享模型参数。这时,我们可以通过Block的
`params`
来指定模型参数。在下面使用
`Sequential`
类构造的多层感知机中,模型的第二隐藏层(
`net[1]`
)和第三隐藏层(
`net[2]`
)共享模型参数。
在有些情况下,我们希望模型的多个层之间共享模型参数。这时,我们可以通过Block的
`params`
来指定模型参数。在下面使用
Sequential
类构造的多层感知机中,模型的第二隐藏层(
`net[1]`
)和第三隐藏层(
`net[2]`
)共享模型参数。
```
{.python .input n=15}
net = nn.Sequential()
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录