首先定义一个含单隐藏层的多层感知机,使用默认方法初始化它的参数,并做一次前向运算。
import torch
from torch import nn
from torch.nn import init
net=nn.Sequential(nn.Linear(4,3),nn.ReLU(),nn.Linear(3,1))
#此时Pytorch会进行默认初始化
print(net)
X=torch.rand(2,4)
Y=net(X).sum()
输出:
Sequential(
(0): Linear(in_features=4, out_features=3, bias=True)
(1): ReLU()
(2): Linear(in_features=3, out_features=1, bias=True)
)
一、访问模型参数
对于Sequential示例中含模型参数的层,我们可以通过Module类的parameters()或者named_parameters()方法来访问所有参数(以迭代器的形式返回),后者除了返回参数Tensor外还会返回其名字。下面的代码访问上面net的所有参数:
for name,param in net.named_parameters():
print(name,param.size())
输出:
0.weight torch.Size([3, 4])
0.bias torch.Size([3])
2.weight torch.Size([1, 3])
2.bias torch.Size([1])
可见返回的名字自动加上了层数的索引作为前缀。
接下来访问net中单层的参数。对于使用Sequential类构造的神经网络,我们可以通过方括号[]来访问网络的任一层。
for name,param in net[0].named_parameters():
print(name,param.size(),type(param))
输出:
weight torch.Size([3, 4])
bias torch.Size([3])
因为这里是单维的因此没有层数索引的前缀。另外返回的param的类型为torch.nn.parameter.Parameter,其实这是Tensor的子类,和Tensor不同的是如果一个Tensor是Parameter,那么它会自动被添加到模型的参数列表里面。
因为Parameter是Tensor,即Tensor拥有的属性它都有,因此我们可以用data来访问参数值,用grad来访问参数梯度。
weight_0=list(net[0].parameters())[0]
print(weight_0.data)
#在没有反向传播前梯度为None
print(weight_0.grad)
Y.backward()
print(weight_0.grad)
输出:
tensor([[ 0.0285, 0.4555, 0.3370, 0.2170],
[ 0.2281, 0.0616, -0.4615, -0.1053],
[-0.2828, -0.4555, -0.4292, 0.4989]])
None
tensor([[0.1976, 0.3890, 0.3261, 0.5621],
[0.0000, 0.0000, 0.0000, 0.0000],
[0.0000, 0.0000, 0.0000, 0.0000]])
二、初始化模型参数
Pytorch中nn.Moudule中的模块参数都采取了较为合理的初始化策略(不同类型的layer具体采用的哪一种初始化方法可参考源代码)。但我们经常需要使用其他方法来初始化权重。Pytorch的init模块里提供了多种预设的初始化方法。
在下面的例子中,我们将权重初始化为均值为0、标准差为0.01的正态分布随机数,并将偏差参数清零。
for name,param in net.named_parameters():
if 'weight' in name:
torch.nn.init.normal_(param,mean=0,std=0.01)
print(name,param.data)
输出:
0.weight tensor([[ 0.0098, 0.0141, -0.0097, 0.0053],
[ 0.0224, -0.0045, 0.0074, 0.0173],
[-0.0044, 0.0200, 0.0056, -0.0107]])
2.weight tensor([[ 0.0119, -0.0109, -0.0076]])
我们还可以使用常数来初始化权重参数:
#替换上面的初始化函数
torch.nn.init.constant_(param,val=0)
如果只想对某个特定参数进行初始化,我们可以调用Parameter类的initialize函数,它与Block类提供的initialize函数的使用方法一致。
三、自定义初始化方法
待补充 110