参数访问
# 单隐藏层MLP,参数获取
import torch
from torch import nn
net=nn.Sequential(nn.Linear(4,8),nn.ReLU(),nn.Linear(8,1))
X=torch.rand(size=(2,4))
net(X)
# 访问指定层所有参数
# net[2]拿到0,1,2。拿到nn.Linear(8,1)
# nn.Sequential(nn.Linear(4,8),nn.ReLU(),nn.Linear(8,1))
# state?权重从自动机角度来看就是状态机
# OrderedDict?有weight和bias
print(net[2].state_dict())
# 访问指定层的指定参数
# torch.nn.parameter.Parameter定义的是可以优化的参数
print(type(net[2].bias))
# 访问参数
print(net[2].bias)
# 访问参数的数据
print(net[2].bias.data)
# 访问参数的梯度
# 还没有做反向传播,所以=None
net[2].weight.grad==None
print("============")
# 访问神经网络中的所有参数
# named_parameters含有name和parameter
print(*[(name,param.shape) for name,param in net[0].named_parameters()])
print(*[(name,param.shape) for name,param in net.named_parameters()])
# 网络的所有参数的第3层的偏置的数据
# !神经元+输出算作1层(神经元和突起),激活函数算作1层
net.state_dict()['2.bias'].data
OrderedDict([('weight', tensor([[-0.1736, 0.0939, 0.1715, -0.2786, 0.0999, 0.1209, 0.1512, -0.1243]])), ('bias', tensor([-0.0326]))])
Parameter containing:
tensor([-0.0326], requires_grad=True)
tensor([-0.0326])
============
('weight', torch.Size([8, 4])) ('bias', torch.Size([8]))
('0.weight', torch.Size([8, 4])) ('0.bias', torch.Size([8])) ('2.weight', torch.Size([1, 8])) ('2.bias', torch.Size([1]))
tensor([-0.0326])
# 参数访问
# 嵌套神经网络,参数获取
def block1():
return nn.Sequential(nn.Linear(4,8),nn.ReLU(),nn.Linear(8,4),nn.ReLU())
def block2():
net=nn.Sequential()
for i in range(4):
# 嵌套4次block1, 给每个module1个名字
net.add_module(f'block {i}',block1())
return net
# rgnet共有5层
rgnet=nn.Sequential(block2(),nn.Linear(4,1))
rgnet(X)
# 通过print打印神经网络结构
print(rgnet)
Sequential(
(0): Sequential(
(block 0): Sequential(
(0): Linear(in_features=4, out_features=8, bias=True)
(1): ReLU()
(2): Linear(in_features=8, out_features=4, bias=True)
(3): ReLU()
)
(block 1): Sequential(
(0): Linear(in_features=4, out_features=8, bias=True)
(1): ReLU()
(2): Linear(in_features=8, out_features=4, bias=True)
(3): ReLU()
)
(block 2): Sequential(
(0): Linear(in_features=4, out_features=8, bias=True)
(1): ReLU()
(2): Linear(in_features=8, out_features=4, bias=True)
(3): ReLU()
)
(block 3): Sequential(
(0): Linear(in_features=4, out_features=8, bias=True)
(1): ReLU()
(2): Linear(in_features=8, out_features=4, bias=True)
(3): ReLU()
)
)
(1): Linear(in_features=4, out_features=1, bias=True)
)
初始化参数
# 内置初始化函数
def init_normal(m):
'''
:param m nn.Module类型
'''
if type(m)==nn.Linear:
# 正态分布
# !替换函数,normal_后下划线的写法表示这个函数是替换函数,替换m.weight
# !所有替换函数都在initModule里面
nn.init.normal_(m.weight,mean=0,std=0.01)
nn.init.zeros_(m.bias)
# net中所有的层都应用这个初始化函数
net.apply(init_normal)
net[0].weight.data[0],net[0].bias.data[0]
# 内置初始化函数
def init_constant(m):
'''
:param m nn.Module类型
'''
if type(m)==nn.Linear:
# 正态分布
# !替换函数,normal_后下划线的写法表示这个函数是替换函数,替换m.weight
# !所有替换函数都在initModule里面
nn.init.constant_(m.weight,1)
nn.init.zeros_(m.bias)
# net中所有的层都应用这个初始化函数
net.apply(init_constant)
net[0].weight.data[0],net[0].bias.data[0]
(tensor([1., 1., 1., 1.]), tensor(0.))
# 某些层定制化初始化
def xavier(m):
'''
xavier权重初始化方法
xavier可以保证数值稳定性,进而防止梯度消失或爆炸
Xavier是常用的权重初始化方法,它表示权重和梯度期望=0,权重和梯度的方差由第t层输入和输出的神经元数量决定
'''
if type(m)==nn.Linear:
nn.init.xavier_uniform_(m.weight)
def init_42(m):
if type(m)==nn.Linear:
nn.init.constant_(m.weight,42)
net[0].apply(xavier)
net[2].apply(init_42)
print(net[0].weight.data[0])
print(net[2].weight.data)
tensor([-0.1978, 0.5860, -0.2494, -0.5379])
tensor([[42., 42., 42., 42., 42., 42., 42., 42.]])
# 自定义初始化
def my_init(m):
if type(m)==nn.Linear:
# 打印初始化参数名称
print('Init',*[(name,param.shape)for name,param in m.named_parameters()][0])
nn.init.uniform_(m.weight,-10,10)
# *元素相乘。注意广播机制
# 保留weight绝对值大于等于5的元素值
m.weight.data*=m.weight.data.abs()>=5
net.apply(my_init)
net[2].weight[:2]
Init weight torch.Size([8, 4])
Init weight torch.Size([1, 8])
tensor([[-0.0000, -9.1786, -0.0000, -6.5656, -7.9464, 9.2016, 0.0000, -0.0000]],
grad_fn=)
# 直接操作神经网络层参数值
net[0].weight.data[:]+=1
net[0].weight.data[0,0]=42
net[0].weight.data[0]
tensor([42.0000, 1.0000, 1.0000, -6.7708])
参数绑定,某些层共享权重
# 某些层共享权重
# 构建了shared层
shared=nn.Linear(8,8)
# net[2]和net[4]都是shared层
net=nn.Sequential(nn.Linear(4,8),nn.ReLU(),shared,nn.ReLU(),shared,nn.ReLU(),nn.Linear(8,1))
net(X)
# !为什么是一样的 因为引用的对象是同一个
print(net[2].weight.data[0]==net[4].weight.data[0])
net[2].weight.data[0,0]=100
print(net[2].weight.data[0]==net[4].weight.data[0])
tensor([True, True, True, True, True, True, True, True])
tensor([True, True, True, True, True, True, True, True])