【动手学深度学习笔记】之对模型参数的访问、初始化和共享
时间:2022-07-23
本文章向大家介绍【动手学深度学习笔记】之对模型参数的访问、初始化和共享,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
1. 模型参数
首先回顾一下之前用Sequential创建MLP模型的方法。
net = nn.Sequential(
nn.Linear(4,3),
nn.ReLU(),
nn.Lineaar(3,1),
)
print(net)
Out[1]:
Sequential(
(0): Linear(in_features=4, out_features=3, bias=True)
(1): ReLU()
(2): Linear(in_features=3, out_features=1, bias=True)
)
在创建的过程中,并没有可见的进行参数初始化的过程,因为这里使用了默认的方式进行了初始化参数。
1.1 访问模型参数
使用Module
类的parameters()
或named_parameters()
方法生成迭代器来访问所有参数。其中named_parameters()
还可以返回参数的名字。下面用实例说明这一过程。
#访问所有参数
for name,param in net.named_parameters():
print(name,param)
Out[1]:
#返回的名字以层数作为前缀
0.weight Parameter containing:
tensor([[-0.4466, -0.1915, 0.3137, 0.0990],
[ 0.3665, 0.2707, -0.4795, 0.4625],
[ 0.3726, -0.3353, -0.1634, 0.1339]], requires_grad=True)
0.bias Parameter containing:
tensor([-0.3975, 0.1861, 0.4645], requires_grad=True)
2.weight Parameter containing:
tensor([[-0.2939, 0.1900, 0.1157]], requires_grad=True)
2.bias Parameter containing:
tensor([0.0854], requires_grad=True)
通过使用层数索引和[],可以访问网络中任一层的参数。
for name,param in net[0].named_parameters():
print(name,param)
Out[1]:
#访问单层的参数没有层数索引前缀
weight Parameter containing:
tensor([[-0.1242, 0.4956, -0.0380, -0.0223],
[-0.4294, 0.2217, 0.4595, -0.3092],
[ 0.0738, -0.2290, 0.1326, -0.4832]], requires_grad=True)
bias Parameter containing:
tensor([ 0.2073, 0.0474, -0.4783], requires_grad=True)
1.2 参数的数据类型
参数的类型为torch.nn.parameter.Parameter
,这个类型本质是Tensor
的子类。如果一个Tensor
是torch.nn.parameter.Parameter
类型的,那么它会被自动添加到模型的参数列表。下面是实例说明
class Test(nn.Module):
def __init__(self):
super(Test,self).__init__()
self.weight1 = nn.Parameter(torch.rand(20,20))
self.weight2 = torch.rand(20,20)
def forward(self,x):
pass
#下面看一下哪些参数被添加到了参数列表。
net1 = Test()
for name,param in net1.named_parameters():
print(name)
Out[1]:
#可以看到只有类型为Parameter的weight1被添加到了参数列表。
weight1
1.3 访问参数的数值和梯度
使用data
可以访问参数数值,使用grad
可以访问参数梯度。
#以net1网络为例
for name,param in net1.named_parameters():
print(param.data)
print(param.grad)
Out[1]:
tensor([[0.3835, 0.5893, 0.2007, 0.6323, 0.9700, 0.6664, 0.7636, 0.7858, 0.6420,
0.2491, 0.8562, 0.9641, 0.7165, 0.0363, 0.4048, 0.2425, 0.9410, 0.2126,
0.9872, 0.0461],
......
[0.1776, 0.3865, 0.3770, 0.3702, 0.4588, 0.3745, 0.6851, 0.4005, 0.1305,
0.4921, 0.6546, 0.9982, 0.0174, 0.2351, 0.7404, 0.2557, 0.4719, 0.7664,
0.3595, 0.7744]])
None
1.4 初始化模型参数
PyTorch默认根据不同类型的layer
采取不同的初始化方法。但同样也可以不使用默认的初始化方法,PyTorch中的init
模块提供了多种初始化方法。下面介绍两种较为常用的方法。
#以net网络为例
#将权重参数初始化为均值为0,标准差为0.01的正态分布(使用normal_方法)
for name,param in net.named_parameters()
if 'weight' in name:
init.normal_(param,mean=0,std=0.01)
print(name,param.data)
#将偏差参数初始化为常数(0)(使用constant_方法)
for name,param in net.named_parameters()
if 'bias' in name:
init.constant_(param,val=0)
print(name,param.data)
Out[1]:
0.weight tensor([[ 0.0030, 0.0094, 0.0070, -0.0010],
[ 0.0001, 0.0039, 0.0105, -0.0126],
[ 0.0105, -0.0135, -0.0047, -0.0006]])
2.weight tensor([[-0.0074, 0.0051, 0.0066]])
0.bias tensor([0., 0., 0.])
2.bias tensor([0.])
1.5 自定义初始化方法
当需要使用init
模块中没有的初始化方法时,我们就需要自定义初始化方法。自定义初始化方法需要注意这个过程是不记录梯度的。下面以初始化权重有一半概率初始化为0,有另一半概率初始化为[-10,-5]和[5,10]两个区间里均匀分布的随机数。
#以net网络为例
def init_w(tensor):
#不记录梯度
with torch.no_grad():
tensor.uniform(-10,10) #-10到10的均匀分布
tensor *= (tensor.abs() >= 5).float()
#绝对值小于5的数清零,大于5的数置1,然后与tensor相乘
for name, param in net.named_parameters():
if 'weight' in name:
init_weight_(param)
print(name, param.data)
Out[1]:
0.weight tensor([[ 0.0000, -0.0000, 0.0000, 0.0000],
[-0.0000, 5.4846, 8.1156, 7.4273],
[-5.7105, -0.0000, 6.6128, -9.7673]])
2.weight tensor([[ 0.0000, -7.2850, 6.9467]])
第二种初始化方法,使用data
方法获取参数值并进行操作。
for name, param in net.named_parameters():
if 'bias' in name:
param.data += 1
print(name, param.data)
Out[1]:
0.bias tensor([0.9058, 0.8452, 0.8508])
2.bias tensor([1.1459])
1.6 共享模型参数
当同一个Module
实例(layer
或net
)被传入Sequential
多次,他们的参数也是共享的。
linear = nn.Linear(1, 1, bias=False)
net = nn.Sequential(linear, linear)
print(net)
for name, param in net.named_parameters():
init.constant_(param, val=3)
print(name, param.data)
Out[1]:
Sequential(
(0): Linear(in_features=1, out_features=1, bias=False)
(1): Linear(in_features=1, out_features=1, bias=False)
)
0.weight tensor([[3.]])
另外,在内存中,这两个layer
其实是同一个对象。在计算反向传播计算时,这些共享参数的梯度是累加的。
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- WAF原理及其使用说明
- 还在写Bug?GitHub官方代码扫描工具上线,免费查找漏洞
- n1.Docker安装运行所遇异常解决
- n3.Docker之Win10和Server使用实例
- GitHub 再见 Master !
- IT运维面试问题总结-Linux基础
- 6.Docker使用辅助工具汇总
- IT运维面试问题总结-基础服务、磁盘管理、虚拟平台和系统管理
- IT运维面试问题总结-运维工具、开源应用(Ansible、Ceph、Docker、Apache、Nginx等)
- IT运维面试问题总结-数据库、监控、网络管理(NoSQL、MongoDB、MySQL、Prometheus、Zabbix)
- IT运维面试问题总结-LVS、Keepalived、HAProxy、Kubernetes、OpenShift等
- GitHub 标星 119K+!这些神器仅需一行代码即可下载全网视频!
- React进阶(2)-上手实践Redux-如何获取store的数据
- 关于Python3.9,这张「新特性必知图」就够了
- 3.Docker学习之Dockerfile