动手学深度学习5.2 PyTorch教程 参数初始化

1,294 阅读2分钟

参与11月更文挑战的第19天,活动详情查看:2021最后一次更文挑战

import torch
from torch import nn

先新建一个网络,生成测试数据X。

net = nn.Sequential(nn.Linear(4,8),
                    nn.ReLU(),
                    nn.Linear(8,2),
                    nn.MSELoss(),
                    nn.Linear(2,4))
print(net)

X = torch.rand(size=(5, 4))

网络长这样。

>>
Sequential(
  (0): Linear(in_features=4, out_features=8, bias=True)
  (1): ReLU()
  (2): Linear(in_features=8, out_features=2, bias=True)
  (3): MSELoss()
  (4): Linear(in_features=2, out_features=4, bias=True)
)

image.png

内置初始化

def init_normal(m):
    if type(m) == nn.Linear:
        nn.init.normal_(m.weight, mean=0, std=0.01)
        nn.init.zeros_(m.bias)
net.apply(init_normal)

调用内置的初始化器。下面的代码将所有权重参数初始化为标准差为0.01的高斯随机变量,且将偏置参数设置为0。

print(net[4].weight)
print(net[0].bias.data)
>>
Parameter containing:
tensor([[ 0.0047, -0.0060],
        [ 0.0135, -0.0032],
        [ 0.0048, -0.0043],
        [ 0.0058,  0.0013]], requires_grad=True)
tensor([0., 0., 0., 0., 0., 0., 0., 0.])

输出一下权重和偏执看一下。

我们还可以将所有参数初始化为给定的常数。

def init_constant(m):
    if type(m) == nn.Linear:
        nn.init.constant_(m.weight, 5)
        nn.init.zeros_(m.bias)
net.apply(init_constant)

print(net[4].weight)
print(net[0].bias.data)
>>
Parameter containing:
tensor([[5., 5.],
        [5., 5.],
        [5., 5.],
        [5., 5.]], requires_grad=True)
tensor([0., 0., 0., 0., 0., 0., 0., 0.])

除此之外还可以为不同的层应用不同的初始化方法。

net[0].apply(init_normal)
net[2].apply(init_constant)
net[4].apply(init_constant)

print(net[0].weight.data)
print(net[2].weight.data)
>>
tensor([[-0.0138,  0.0057, -0.0061,  0.0052],
        [ 0.0126, -0.0008, -0.0102, -0.0230],
        [ 0.0144, -0.0041,  0.0095,  0.0127],
        [ 0.0108, -0.0063, -0.0181, -0.0175],
        [-0.0085,  0.0055, -0.0014, -0.0086],
        [-0.0082,  0.0100, -0.0025, -0.0020],
        [ 0.0009, -0.0099,  0.0047,  0.0040],
        [ 0.0020, -0.0097, -0.0025, -0.0075]])
tensor([[5., 5., 5., 5., 5., 5., 5., 5.],
        [5., 5., 5., 5., 5., 5., 5., 5.]])

自定义初始化

除了初始化为常数,初始化为高斯分布,pytorch还支持其他初始化方法,更多初始化方法可以看官方手册: torch.nn.init — PyTorch 1.10.0 documentation

但是如果你说这些就是不能满足我的要求,我需要一个其他的初始化方法,那也可以自己写的啦。

比如我们使用以下的分布为任意权重参数ww定义初始化方法:

w{U(5,10) with probability 140 with probability 12U(10,5) with probability 14\begin{aligned} w \sim \begin{cases} U(5, 10) & \text{ with probability } \frac{1}{4} \\ 0 & \text{ with probability } \frac{1}{2} \\ U(-10, -5) & \text{ with probability } \frac{1}{4} \end{cases} \end{aligned}
def my_init(m):
    if type(m) == nn.Linear:
        nn.init.uniform_(m.weight, -10, 10)
        m.weight.data *= m.weight.data.abs() >= 5

net.apply(my_init)

print(net[0].weight.data[0])
print(net[2].weight.data[0])
>>
tensor([-8.9126, -7.9010, -0.0000, -0.0000])
tensor([-0.0000, -8.6281,  0.0000,  9.8472, -0.0000,  9.7564,  0.0000,  8.5654])

实现了一个my_init函数来应用到net。这里只输出权重的第一行。

分析一下nn.init.uniform_(m.weight, -10, 10) m.weight.data *= m.weight.data.abs() >= 5两行代码。

要求是w有14\frac 1 4的概率服从(-10,5)的均匀分布,有14\frac 1 4的概率服从(5,10)的均匀分布,还有12\frac 1 2的概率服等于0。

  • nn.init.uniform_(m.weight, -10, 10)是将w全部初始化为(-10,10)的均匀分布。
  • m.weight.data *= m.weight.data.abs() >= 5进行判定,看每一个权重的绝对值是否大于等于5,如果大于等于5则证明在(5, 10)和(-10,-5)区间上,那返回true,也就是1,m.weight.data乘1数值不变;反之会返回false,也就是0,将m.weight.data置零。至于怎么保证14\frac 1 412\frac 1 2概率,因为是均匀分布,所以默认他们在区间上的分布已经均匀。

手动设定

直接接着上边那段代码写了,我们还可以手动修改某个参数的值,比如:

print(net[4].weight.data)

net[4].weight.data[:] += 10
print(net[4].weight.data)

net[4].weight.data[0, 0] = 666
print(net[4].weight.data)
>>
tensor([[ 0.0000,  6.9226],
        [-0.0000, -0.0000],
        [-8.0648,  9.4455],
        [-5.8219,  5.6904]])
tensor([[10.0000, 16.9226],
        [10.0000, 10.0000],
        [ 1.9352, 19.4455],
        [ 4.1781, 15.6904]])
tensor([[666.0000,  16.9226],
        [ 10.0000,  10.0000],
        [  1.9352,  19.4455],
        [  4.1781,  15.6904]])

参数会在你手动修改的位置发生变化。


  1. 《动手学深度学习》系列更多可以看这里:《动手学深度学习》专栏(juejin.cn)

  2. 笔记Github地址:DeepLearningNotes/d2l(github.com)

还在更新中…………