access_initialization_sharing_parameters

模型参数的访问、初始化和共享

最近在B站看沐神的动手学深度学习视频,记录一下学习过程
查看本文的jupyter notebook格式,更加清晰美观哦!

from mxnet import nd, init
from mxnet.gluon import nn
net = nn.Sequential()
net.add(nn.Dense(256, activation='relu'),
       nn.Dense(10))
net.initialize()  # 使用默认初始化方式
X = nd.random.uniform(shape=(2, 20))
Y = net(X)  # 前向计算
对于使用Sequential类构造的神经网络,可以通过下标来访问网络中的任一层。通过Block类的params属性可以访问该层包含的所有参数,索引0表示Sequential实例最先添加的隐藏层。
net[0].params, type(net[0].params)
(dense0_ (
   Parameter dense0_weight (shape=(256, 20), dtype=float32)
   Parameter dense0_bias (shape=(256,), dtype=float32)
 ),
 mxnet.gluon.parameter.ParameterDict)
由上面的输出可以得知,它是一个由参数名映射到参数实例的字典(类型为ParameterDict类)。其中权重参数的名称为dense0_weight,它由net[0]的名称(dense0_)和自己的变量名(weight)组成。既可以使用名字来访问字典里面的元素,也可以直接使用它的变量名。通常后者的代码可读性更好。
net[0].params['dense0_weight'], net[0].weight
(Parameter dense0_weight (shape=(256, 20), dtype=float32),
 Parameter dense0_weight (shape=(256, 20), dtype=float32))
Gluon中参数类型为Parameter类,它包含参数和梯度的数值,可以分别通过data函数和grad函数来访问。
net[0].weight.data()
[[ 0.06700657 -0.00369488  0.0418822  ... -0.05517294 -0.01194733
  -0.00369594]
 [-0.03296221 -0.04391347  0.03839272 ...  0.05636378  0.02545484
  -0.007007  ]
 [-0.0196689   0.01582889 -0.00881553 ...  0.01509629 -0.01908049
  -0.02449339]
 ...
 [ 0.00010955  0.0439323  -0.04911506 ...  0.06975312  0.0449558
  -0.03283203]
 [ 0.04106557  0.05671307 -0.00066976 ...  0.06387014 -0.01292654
   0.00974177]
 [ 0.00297424 -0.0281784  -0.06881659 ... -0.04047417  0.00457048
   0.05696651]]
<NDArray 256x20 @cpu(0)>
net[0].weight.grad()  # 由于没有进行反向传播计算,所以梯度的值全为0
[[0. 0. 0. ... 0. 0. 0.]
 [0. 0. 0. ... 0. 0. 0.]
 [0. 0. 0. ... 0. 0. 0.]
 ...
 [0. 0. 0. ... 0. 0. 0.]
 [0. 0. 0. ... 0. 0. 0.]
 [0. 0. 0. ... 0. 0. 0.]]
<NDArray 256x20 @cpu(0)>
net[1].bias.data()  # 输出层的偏差值
[0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
<NDArray 10 @cpu(0)>
使用collect_params函数获取net变量所有嵌套的层所包含的所有参数。返回的是一个由参数名称到参数实例的字典。
net.collect_params()
sequential0_ (
  Parameter dense0_weight (shape=(256, 20), dtype=float32)
  Parameter dense0_bias (shape=(256,), dtype=float32)
  Parameter dense1_weight (shape=(10, 256), dtype=float32)
  Parameter dense1_bias (shape=(10,), dtype=float32)
)
可以使用正则表达式匹配参数名,从而筛选出需要的参数
net.collect_params('.*weight')
sequential0_ (
  Parameter dense0_weight (shape=(256, 20), dtype=float32)
  Parameter dense1_weight (shape=(10, 256), dtype=float32)
)
初始化模型参数。
# 非首次初始化需要指定force_reinit为真
net.initialize(init=init.Normal(sigma=0.01), force_reinit=True)
net[0].weight.data()[0]
[ 0.00195949 -0.0173764   0.00047347  0.00145809  0.00326049  0.00457878
 -0.00894258  0.00493839 -0.00904343 -0.01214079  0.02156406  0.01093822
  0.01827143 -0.0104467   0.01006219  0.0051742  -0.00806932  0.01376901
  0.00205885  0.00994352]
<NDArray 20 @cpu(0)>
使用常数来初始化权重参数
net.initialize(init=init.Constant(1), force_reinit=True)
net[0].weight.data()[0]
[1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]
<NDArray 20 @cpu(0)>
如果只想对某个参数进行初始化,可以调用Parameter类的initialize函数,它与Block类的initialize函数用法一致。下面对隐藏层的权重参数使用Xavier随机初始化方法。
net[0].weight.initialize(init=init.Xavier(), force_reinit=True)
net[0].weight.data()[0]
[ 0.00512482 -0.06579044 -0.10849719 -0.09586414  0.06394844  0.06029618
 -0.03065033 -0.01086642  0.01929168  0.1003869  -0.09339568 -0.08703034
 -0.10472868 -0.09879824 -0.00352201 -0.11063069 -0.04257748  0.06548801
  0.12987629 -0.13846186]
<NDArray 20 @cpu(0)>
自定义初始化方法
如果我们需要的初始化方法并没有在init模块中提供。这时,可以实现一个Initializer类的子类。通常,我们只需要实现_init_weight这个函数,并将传入的NDArray修改成初始化之后的结果。在下面的例子中,我们令权重有一半的概率初始化为0,另一半的概率初始化为[-10, -5]和[5, 10]两个去建立均匀分布的随机数。
class MyInit(init.Initializer):
    def _init_weight(self, name ,data):
        print('Init', name, data.shape)
        data[:] = nd.random.uniform(-10, 10, shape=data.shape)
        data *= data.abs()>=5

net.initialize(MyInit(), force_reinit=True)
net[0].weight.data()[0]
Init dense0_weight (256, 20)
Init dense1_weight (10, 256)






[-5.3659673  7.5773945  8.986376  -0.         8.827555   0.
  5.9840508 -0.         0.         0.         7.4857597 -0.
 -0.         6.8910007  6.9788704 -6.1131554  0.         5.4665203
 -9.735263   9.485172 ]
<NDArray 20 @cpu(0)>
此外,还可以通过Parameter类的set_data函数直接改写模型参数。例如,在下例中我们将隐藏层参数在现有的基础上加1。
net[0].weight.set_data(net[0].weight.data() + 1)
net[0].weight.data()[0]
[-4.3659673  8.5773945  9.986376   1.         9.827555   1.
  6.9840508  1.         1.         1.         8.48576    1.
  1.         7.8910007  7.9788704 -5.1131554  1.         6.4665203
 -8.735263  10.485172 ]
<NDArray 20 @cpu(0)>
共享模型参数。在下面的例子中,第二隐藏层(shared变量)和第三隐藏层共享模型参数。因为模型参数里包含了梯度,所以在反向传播计算时,第二隐藏层和第三隐藏层的梯度都会被累加在shared.params.grad()里。
net = nn.Sequential()
shared = nn.Dense(8, activation='relu')
net.add(nn.Dense(8, activation='relu'),
       shared,
       nn.Dense(8, activation='relu', params=shared.params),
       nn.Dense(10))
net.initialize()

X = nd.random.uniform(shape=(2, 20))
net(X)

net[1].weight.data()[0] == net[2].weight.data()[0]
[1. 1. 1. 1. 1. 1. 1. 1.]
<NDArray 8 @cpu(0)>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值