目录
一、模块类
模块本身是一个类 nn.Module ,PyTorch 的模型通过继承该类,在类的内部定义子模块的实例化,通过前向计算调用子模块,最后实现深度学习模型的搭建。
import torch.nn as nn
class Model(nn.Module):
def __init__(self,...): #定义类的初始化函数,...是用户传入参数
super(Model,self).__init__()
...#根据传入参数定义子模块
def forward(self,...):
#定义前向计算的输入参数,...一般是张量或者其他的参数
ret = ...# 根据传入的张量和子模块计算返回张量
return ret
二、基于模块类的简单线性回归类
'''PyTorch线性回归模型示例'''
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):
#y = Wx + b
return x.mm(self.weight) + self.bias
线性回归模型是输入一个特征的张量,做线性变换,输出一个预测张量。为了能够构造线性变换,我们需要知道输入特征维度大小,并且知道线性回归的权重( self . weight )和偏置( self . bias )。在 forward 方法中,输入一个特征张量 x (大小为迷你批次大小 x 特征维度大小),做线性变换(使用 mm 方法做矩阵乘法进行线性变换),加偏置的值,最后输出一个预测的值。需要注意的是模型的初始化部分, self . weight 和 self . bias 是模型的参数,并且一开始被初始化,使得每个分量为标准正态分布( torch . randn )。另外,需要使用 nn . Parameter 来包装这些参数,使之成为子模块(仅仅由参数构成的子模块),这是因为在后续训练的时候需要对参数进行优化,只有将张量转换为参数才能在后续的优化过程中被优化器访问到。
在使用线性回归模型之前,首先要做的一件事是模型的初始化,初始化的任务由初始化模型的类实例开始。对于在代码中构造的线性回归模型来说,假如输入的特征大小为 n ,可以直接调用 LinearModel ( n )来构造线性回归模型的一个实例。如果需要预测 mxn 大小的张量对应的输出值,可以直接将 mxn 输入线性回归模型的实例中,如下面的代码所示。
'''PyTorch线性回归模型实例'''
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):
#y = Wx + b
return x.mm(self.weight) + self.bias
line = LinearModel(5) #定义线性回归模型,特征数为 5
x = torch.randn(4,5) #定义随机输入,迷你批次大小为4
print('line(x): \n',line(x))
#运行结果
line(x):
tensor([[ 0.9043],
[-1.8835],
[-0.3824],
[-0.9323]], grad_fn=<AddBackward0>)
三、线性回归类的实例化和方法调用
对于 PyTorch 的模块,有一些常用的方法可以在训练和预测的时候调用。
1.使用 named _ parameters 方法和 parameters 方法获取模型的参数
通过调用 named _ parameters 方法,返回的是 Python 的一个生成器( Generator ),通过访问生成器的对象得到的是该模型所有参数的名称和对应的张量值。通过调用 parameters 方法,返回的也是一个生成器,访问生成器的结果是该模型的所有参数对应张量的值。
PyTorch 的优化器直接接受模型的参数生成器作为函数的参数,并且会根据梯度来优化生成器里的所有张量(需要调用反向传播函数)。
2.使用 train 和 eval 方法进行模型训练和测试状态的转换
在模型的使用过程中,有些子模块(如丢弃层和批次归一化层等)有两种状态,即训练状态和预测状态, PyTorch 的模型经常需要在两种状态中相互转换。通过调用 train 方法会把模块(包括所有的子模块)转换到训练状态;调用 eval 方法会把模块(包括所有的子模块)转换到预测状态。
PyTorch 的模型在不同状态下的预测准确率会有差异,在训练模型的时候需要转换为训练状态,在预测的时候需要转换为预测状态,否则最后模型预测准确率可能会降低,甚至会得到错误的结果。
3.使用 named _ buffers 方法和 buffers 方法获取张量的缓存
除通过反向传播得到梯度来进行训练的参数外,还有一些参数并不参与梯度传播,但是会在训练中得到更新,这种参数称为缓存( Buffer ),其中具体的例子包括批次归一化层的平均值( Mean )和方差( Variance )。通过在模块中调用 register _ buffer 方法可以在模块中加入这种类型的张量,通过 named _ buffers 可以获得缓存的名字和缓存张量的值组成的生成器,通过 buffers 方法可以获取缓存张量值组成的生成器。
4.使用 named _ children 方法和 children 方法获取模型的子模块
有时需要对模块的子模块进行迭代,这时就需要使用 named _ children 方法和 children 方法来获取子模块名字、子模块的生成器,以及只有子模块的生成器。由于 PyTorch 模块的构造可以嵌套,所以子模块还有可能有自身的子模块,如果要获取模块中所有模块的信息,可以使用 named _ modules 和 modules 来(递归地)得到相关信息。
5.使用 apply 方法递归地对子模块进行函数应用
如果需要对 PyTorch 所有的模块应用一个函数,可以使用 apply 方法,通过传入一个函数或者匿名函数(通过 Python 语言的 lambda 关键字定义)来递归地应用这些函数。传入的函数以模块作为参数,在函数内部对模块进行修改。
6.改变模块参数数据类型和存储的位置
除对模块进行修改外,在深度学习模型的构建中还可能对参数进行修改。和张量的运算一样,可以改变模块的参数所在的设备( CPU 或者 GPU ),具体可以通过调用模块自带的 cpu 方法和 cuda 方法来实现。另外,如果需要改变参数的数据类型,可以通过调用 to 方法加上需要转变的目标数据类型来实现(也可以使用具体的一些方法,比如 float 方法会转换所有的参数为单精度浮点数, half 方法会转换所有的参数为半精度浮点数, double 方法会转换所有的参数为双精度浮点数)。具体调用的实例可以参考下面代码。
'''PyTorch线性回归模型实例'''
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):
#y = Wx + b
return x.mm(self.weight) + self.bias
line = LinearModel(5) #定义线性回归模型,特征数为 5
x = torch.randn(4,5) #定义随机输入,迷你批次大小为4
print('line(x): \n',line(x))
print('\n')
print('获取模型参数(带名字)的生成器: \n',line.named_parameters())
print('\n')
print('转换生成器为列表: \n',list(line.named_parameters()))
print('\n')
print('获取模型参数(不带名字)的生成器: \n',line.parameters())
print('\n')
print('转换生成器为列表: \n',list(line.parameters()))
print('\n')
print('将模型参数移到GPU上: \n',line.cuda())
print('\n')
print('显示模型参数,可以看到已经转换到了 GPU 上: \n',list(line.parameters()))
print('\n')
print('转换模型参数为半精度浮点型: \n',line.half())
print('\n')
print('显示模型参数,可以看到已经转换为了半精度浮点数: \n',list(line.parameters()))
print('\n')
#运行结果
line(x):
tensor([[-2.5085],
[-0.8135],
[-2.5966],
[-1.1845]], grad_fn=<AddBackward0>)
获取模型参数(带名字)的生成器:
<generator object Module.named_parameters at 0x000001BC6118EB40>
转换生成器为列表:
[('weight', Parameter containing:
tensor([[ 0.1629],
[ 0.3635],
[-1.2569],
[ 0.2513],
[ 2.0440]], requires_grad=True)), ('bias', Parameter containing:
tensor([-1.0979], requires_grad=True))]
获取模型参数(不带名字)的生成器:
<generator object Module.parameters at 0x000001BC612B8F20>
转换生成器为列表:
[Parameter containing:
tensor([[ 0.1629],
[ 0.3635],
[-1.2569],
[ 0.2513],
[ 2.0440]], requires_grad=True), Parameter containing:
tensor([-1.0979], requires_grad=True)]
将模型参数移到GPU上:
LinearModel()
显示模型参数,可以看到已经转换到了 GPU 上:
[Parameter containing:
tensor([[ 0.1629],
[ 0.3635],
[-1.2569],
[ 0.2513],
[ 2.0440]], device='cuda:0', requires_grad=True), Parameter containing:
tensor([-1.0979], device='cuda:0', requires_grad=True)]
转换模型参数为半精度浮点型:
LinearModel()
显示模型参数,可以看到已经转换为了半精度浮点数:
[Parameter containing:
tensor([[ 0.1628],
[ 0.3635],
[-1.2568],
[ 0.2512],
[ 2.0449]], device='cuda:0', dtype=torch.float16, requires_grad=True), Parameter containing:
tensor([-1.0977], device='cuda:0', dtype=torch.float16, requires_grad=True)]
最新动态,请关注微信公众号:回不去的明天