目录
0.前言
简单线性网络其实就是全连接网络,比如一个输入形状为(5,),输出形状为(2,)的线性网络结构:

1.代码构建网络
使用pytorch实现这样一个线性网络,代码如下:
import torch
from torch import nn
class LinearModel(nn.Module):
def __init__(self,input_features,out_features):
super(LinearModel,self).__init__()
self.weight=nn.Parameter(torch.randn(input_features,out_features))
self.bias=nn.Parameter(torch.randn(out_features))
def forward(self,x):
# y=Wx+b
return x.mm(self.weight)+self.bias
- torch.randn:正态分布的随机数生成
- nn.Parameter:将一个不可训练的类型Tensor转换成可以训练的类型parameter并将这个parameter绑定到这个module里面
- x.mm:矩阵乘法
从结构图中看出,权重值w有5*2=10个,所以使用torch.randn(input_features,out_features)生成这样一个shape的权重tensor,通过Parameter将其转化为可优化的类型;偏置项可以看出有2个,同样的方法定义shape=(2,)的self.bias
2.网络的调用
# 实例化一个输入为(5,),输出为(2,)的线性网络
model=LinearModel(5,2)
# 同时生成4个输入
input=torc.randn(4,5)
out=model(input)
- input:

- out

3. 进阶
3.1 获取模型的参数
named:说出…的名称; 叫出…的名字; 准确陈述;
这个单词在本届使用挺多的,了解其含义有助于记忆API
-
model.named_parameters():该方法获取模型所有参数的
名称和值

-
model.parameters():该方法获取模型所有参数的
值

3.2 转化模型的状态:train & eval
# 使用训练状态
model.train()
# 使用eval状态
model.eval()
# 实际上train()方法有默认的参数是(True)所以eval实际上也等价于
model.train(False)
在模型的使用过程中,比如dropout层和BN层有两种状态,即训练状态和预测状态。Pytorch模型在不同状态下的预测准确率会有差异。在训练时用训练状态,在预测时用预测状态,否则最后模型的预测准确率可能会降低,甚至会得到错误的结果。
- “仅仅当模型中有Dropout和BatchNorm是才会有影响”-----来自PyTorch中文文档
BN层为什么会有影响?李宏毅中讲到,BN层是需要统计样本的均值和标准差这样的统计信息的,训练时我们batch_size大,样本多,所以此时的统计信息就是直接通过计算batch_size样本得来的;但是当我们测试时,一般只是输入1个样本,此时通过样本计算的统计信息没有任何意义,此时用的均值和方差是全量训练数据的均值和方差,这个可以通过移动平均法求得。。综上所述,BN层在不同状态时,统计信息的来源是不一样的,所以操作时必须设定模型的状态,否则BN层对模型的buff可能就变成了debuff。
Dropout层为什么会有影响?在训练时,使用dropout是为了减小网络过拟合的风险,为使用网络预测时,应该用整个训练好的模型,因此不需要dropout。所以train时,dropout层启用;test时,dropout停用。
3.3获取模型中缓存的张量:named_buffers()
模型中除了通过反向传播得到梯度来进行训练的参数外,还有一些参数不参与梯度传播,但是在训练中会得到更新,这种参数被称为缓存(Buffer)。比如BN层中的均值(Mean)和方差(Variance),这两值在训练时会根据样本计算得到,所以会更新,但不是通过梯度传播更新的。这样的值通过named_buffers()得到:

3.4 获取模型的子模块
一个模型可能是由多个子模型构建起来的,子模块又有子模块
- named_children():该方法获取模型的
子模块名称和子模块的生成器 - children():该方法获取模型的
子模块的生成器 - named_modules():当模型的子模块还有子模块时,使用该函数来(递归地)得到相关信息
这里定义一个TestModel:
class TestModel(nn.Module):
def __init__(self,input_channels):
super(TestModel,self).__init__()
self.block1=nn.Sequential(
nn.Conv2d(input_channels,8,3),
nn.ReLU(),
nn.BatchNorm2d(8))
self.block2=nn.Sequential(
nn.Conv2d(8,16,3),
nn.ReLU())
def forward(self,x):
x=self.block1(x)
x=self.block2(x)
return x
# 实例化一个3通道输入的model
model=TestModel(3)
获取子模块的名称和生成器:

获取子模块的生成器:

3.5 使用apply方法递归地对子模块进行函数应用
如果需要对所有模块进行一个函数处理,可以使用apply方法,该方法通过传入一个函数(或者匿名函数lambda)来递归地应用该函数。传入的函数会自动以模块作为参数,在内部对模块进行修改
3.6 改变模块的数据类型和储存位置
- 改变储存位置:
model.cuda() # 将模型参数移动到GPU上
model.cpu() # 将模型参数移动到CPU上
- 改变数据类型
model.float() # 将模型参数转为单精度浮点数
model.half() # 将模型参数转为半精度浮点数
model.double() # 将模型参数转为双精度浮点数
本文介绍了如何使用PyTorch构建一个简单的线性网络,并探讨了模型参数、状态切换、缓冲张量、子模块获取以及模型数据类型和位置的改变。通过`LinearModel`类展示了全连接网络的实现,强调了模型在训练和预测状态的区别,特别是对Dropout和BatchNorm层的影响。此外,还讨论了如何获取和操作模型的参数、子模块以及缓存张量。
397

被折叠的 条评论
为什么被折叠?



