文章目录
PyTorch模块类
PyTorch通过继承模块类nn.Module,在类的内部定义子模块的实例化,通过前向计算调用子模块,最后实现深度学习模型的搭建。
构建模块类时,首先导入torch.nn库,然后基于继承nn.Module的方法构建深度学习模块。整个模块的函数主要由两部分组成:通过__init__方法初始化整个模块,forward方法对该模型进行前向计算。其中,在使用__init__方法的时候,可以在类内部初始化子模块。通过使用super()函数来获取当前类的父类,然后调用父类的构造方法,从而初始化一些必要的变量和参数。
例如:
import torch.nn as nn
class Model(nn.Module):
# 定义类的初始化函数,...是用户的传入参数
def __init__(self, ...):
super(Model, self).__init__()
# 根据传入的参数定义子模块
...
# 定义前向计算的输入参数,...一般是张量或者其他的参数
def forward(self, ...):
# 根据传入的张量和子模块计算返回张量
ret = ...
return ret
基于模块类的简单线性回归类
对于线性回归模型来说,其是输入一个特征的张量,做线性变换后输出一个预测的张量。为了能够构造线性变换需要知道输入特征的维度大小,并且知道线性回归的权重和偏置。
在forward方法中,输入一个特征张量x,做线性变换,加偏置的值,最后输出预测的值。需要注意的是模型的初始化部分,权重和偏置是模型的参数,并且一开始被初始化使得每个分量为标准正态分布。另外,需要使用nn.Parameter来包装这些参数使之成为子模块,以外在后续训练的时候需要对参数进行优化,只有将张量转换为参数才能在后续的优化中被优化器访问到。
import torch
import torch.nn as nn
class LinearModel(nn.Module):
def __init__(self, ndim):
super(LinearModel, self).__init__()
self.ndim = ndim
self.weight = nn.Parameter(torch.randn(ndim, 1))
self.bias = nn.Parameter(torch,.randn(1))
def forward(self, x):
return x.mm(self.weight) + self.bias
在使用线性回归模型之前,首先要对模型进行初始化,初始化的任务由舒适化模型的类实例开始。对于如上代码中构造的线性回归模型来说,假如输入的特征大小为n,可以直接调用LinearModel(n)来构造线性回归模型的一个实例。如果需要预测的是m×n大小的张量对应的输出值,可以将m×n输入线性回归的模型实例中。
lm = LinearModel(5)
x = torch.randn(4, 5)
print(lm(x))
得到的输出结果为:
tensor([[-2.7862],
[ 1.3666],
[-3.9845],
[-3.6125]], grad_fn=<AddBackward0>)
线性回归类的实例化和方法调用
1.使用name_parameters方法和parameters方法获取模型的参数
通过调用name_parameters方法,返回的是一个python的一个生成器,通过访问生成器的对象得到的是该模型所有参数的名称和对应的张量值。
通过调用parameters方法,返回的也是一个生成器,访问生成器的结果是该模型的所有参数对应的张量值。
PyTorch的优化器直接接受模型的参数生成器作为函数的参数,并且会根据梯度来优化生成器里的所有张量。
print(lm.named_parameters())
print(list(lm.parameters()))
<generator object Module.named_parameters at 0x00000212276D7580>
[Parameter containing:
tensor([[-0.2208],
[-0.2866],
[-1.4014],
[ 0.6780],
[ 0.1449]], requires_grad=True), Parameter containing:
tensor([-0.6338], requires_grad=True)]
2.使用train方法和eval方法进行模型训练和测试状态的转换
在模型的使用过程中,有些子模块有两种状态,即训练状态和预测状态,PyTorch的模型经常需要在两种状态中相互转换。通过调用train方法会把模块转换到训练状态,调用eval方法会转换到预测状态。
PyTorch的模型在不同状态下的预测准确率会有差异,在训练或预测的时候要转换到相应的状态,否则可能最后的预测准确率会降低,甚至得到错误的结果。
3.使用named_buffers方法和buffers方法获取张量的缓存
除了通过反向传播得到梯度来进行训练的参数外,还有一些参数并不参与梯度传播,但是会在训练中得到更新,例如批次归一化层的平均值和方差。
通过调用register_buffer方法可以在模块中加入这种类型的张量,通过named_buffers可以获得缓存的名字和缓存张量的值组成的生成器,通过buffers方法可以获取张量值组成的生成器。
4.使用named_children方法和children方法获取模型的子模块
在对子模块进行迭代时,需要用到named_children方法和children方法来获取子模块的名字、子模块的生成器以及只有子模块的生成器。
由于PyTorch模块的构造可以嵌套,所以子模块还可能有自身的子模块,如果要获取模块中的所有模块信息,可以使用named_modules和modules来得到。
5.使用apply方法递归地对子模块进行函数应用
如果需要对PyTorch所有模块应用一个函数,可以使用apply方法通过传入一个函数或匿名函数来递归地应用。传入的函数以模块为参数,在函数内部对模块进行修改。
总结
PyTorch提供了nn.modeule抽象类,通过继承这一个抽象类,并且在创建类的时候构建子模块,PyTorch实现了深度学习的模块化,即可以通过组合子模块称为更大的深度学习模块,最后将所有的模块组合在一起构造深度学习模型。这个构造过程充分利用了深度学习子模块的相似性。
通过在模型中构建一系列的不同参数的子模块实例,并且把它们组合在一起,就能方便地构造复杂的深度学习模型。同时,PyTorch的模块抽象类还提供了一系列方法,方便地在模型训练和预测之间进行转换,以及能够快速获取一个模型所有的参数,方便优化器的调用。