使用Pytorch构建神经网络一般分为四个步骤:

  • 数据构建与处理(Dataset)
  • 构建神经网络和损失函数(nn.Module)
  • 对参数进行优化(torch.optim)
  • 模型的保存与加载

一、Tensor(张量)
Pytorch基本操作是OP,被操作的最基本对象是Tensor。Tensor表示一个多维矩阵。比如零位就是一个点,一维就是向量,二维就是矩阵,多维相当于一个多维的数组。这个numpy是对应的。而且Pytorch的Tensor可以和numpy的ndarray相互转换,唯一不同的是Pytorch可以在GPU上运行,而numpy的ndarray只能在CPU上运行。
Tensor与ndarray常用矩阵的构建方法:

二、Variable(变量)

Variable和Tensor本质上没有区别,不过Variable会被放进一个计算图中,然后进行前向传播、反向传播、自动求导。Variable实际上是在torch.autograd.Variable。包含三个组成属性:data,grad,grad_fn。通过data可以去除Variable里面的tensor数值,grad_fn表示的是得到这个Variable的操作,比如通过加减乘除来得到的。最后drad是这个Variabel的方向传播梯度。下图展示了Variable的结构图:

pytorch判断tensor维度 pytorch维度顺序_pytorch判断tensor维度


Variable自动求导例子:

使用Pytorch的自动求导功能,需要满足两个条件:

  • y.requires_grad == True 且 x.requires_grad==True
  • x到y的计算图不能再torch.no_grad()的with block下
    两个条件都很容易满足,只要将x.requires_gradTrue,那么根据Pytorch的运算规则(OP的两个输入进行运算,只要有一个requires_gradTrue,那么输出结果Tensor的requires_grad一定为True),得到的y的requires_grad也为True
    (1)标量求导
import torch
from torch.autograd import Variable

#Create Variable
x = Variable(torch.Tensor([1]),requires_grad=True)
w = Variable(torch.Tensor([2]),requires_grad=True)
b = Variable(torch.Tensor([3]),requires_grad=True)

#Build a computational graph
y = w * x + b   #y = 2 * x + 3

#Compute gradients
y.backward()  # same as y.backward(torch.FloatTensor([1])
#Print out teh gradients
print(x.grad)
print(w.grad)
print(b.grad)

pytorch判断tensor维度 pytorch维度顺序_pytorch判断tensor维度_02


(2)矩阵求导

x = torch.randn(3)
x = Variable(x,requires_grad=True)
y = x * 2
print(y)

y.backward(torch.FloatTensor([1,0.1,0.01]))
print(x.grad)

pytorch判断tensor维度 pytorch维度顺序_参数信息_03


这里对向量求导不能直接使用y.backward(),这样程序是会报错的。这个时候需要传入参数声明,比如y.backward(torch.FloatTensor([1,1,1])),这样得到的结果就是它们每个分量的梯度,或者传入y.backward(torch.FloatTensor([1,0.1,0.1])),这样得到的梯度就是他们原本的梯度分别乘以1,0.1和0.01。

三、Dataset(数据集)

在处理任何机器学习任务之前都需要数据读取,和数据预处理。PyTorch 提供了很多工具使得数据的读取和预处理变得很容易。

torch.utils.data.Dataset 是代表这一数据的抽象类,可以自己定义数据类继承和重写这个抽象类,只需要定义__len__和__getitem__这两个函数:

class myDataset(Dataset):  #自己定义的类需要继承于torch.utils.data.Dataset
    def __init__(self,csv_file,text_file,root_dir,other_file):
        #initialize file path or list of file names
        self.csv_data = pd.read_csv(csv_file)
        with open(text_file,'r') as f:
            data_list = f.readlines()
        self.txt_data = data_list
        self.root_dir = root_dir
        
    def __len__(self):
        #the total size of your dataset 
        return len(self.csv_data)
    def __getitem__(self,idx):
        #1.Read one data from file
        #2.Preprocess the data
        #3.Return a data pair
        data = (self.csv_data[idx],self.txt_data[idx])
        return data

通过上面的方式,可以定义我们需要的数据类,可以通过迭代的方式来取得每一个数据, 但是这样很难实现取batch,shuffle或者是多线程去读取数据,所以PyTorch中提供了一个简单的办法来做这个事情,通过torch.utils.data.DataLoader来定yi义一个新的迭代器.如下:

dataiter = DataLoader(myDataset, batch_size=32, shuffle=True, collate_fn = default_collate)

四、nn.Module(模组)
在PyTorch 里面编写神经网络,所有的层结构和损失函数都来自于torch.nn,所有的模型构建都是从这个基类nn.Module继承的,于是有了下面这个模板:

class net_name(nn.Module):
    def __init__(self,other_arguments):
        super(net_name,self).__init__()
        self,conv1 = nn.Conv2d(in_channels,out_channels,kernel_size)
        #other network layer
    
    def forward(self,x):
        x = self.conv1(x)
        return x

这样就建立了一个计算图,并且这个结构可以复用多次, 每次调用就相当于用该计算图定义的相同参数做一次前向传播,这得益于PyTorch的自动求导功能,所以不需要自己编写反向传播,而所有的网络层都是由nn这个包得到的,比如线性层nn.Linear。
定义完模型之后,计算损失函数。常见的损失函数都已经定义在了nn里,比如均方误差、多分类的交叉熵,以及二分类的交叉熵,等等,直接多起进行调用计算输出和真实目标之间的损失函数:

criterion = nn.CrossEntorpyLoss()  #交叉熵损失
loss = criterion(output,target)

五、torch.optim(优化)
参数优化过程是通过梯度下降法,更新参数使得损失函数得到最优解。torch。optim是一个实现各种优化算法的包。比如梯度下降、添加动量的随机梯度下降、自适应学习率等。

  • 在优化之前需要先将梯度归零,optimizer.zeros()
  • 然后通过loss.backward()反向传播,自动求导得到每个参数的梯度
  • 最后只需要optimizer.step()就可以通过梯度做一步参数更新。

举个例子:

import torch.optim as optim
#create your optimizer 
optimizer = optim.SGD(model.parameters(),lr=0.01,momentum=0.9)
#in your training loop:
for i in range(steps):
    optimizer.zero_grad()  #zero the gradient buffers  因为梯度是累加的,必须清理
    output = model(input_data)
    loss = criterion(output,target)
    loss.backward()
    optimizer.step()  #Do the update

六、模型的保存与加载
1、在Pytroch里面使用torch.save 来保存模型的结构和参数,save的第一个参数是保存对象,第二个参数是保存路径及名称。两种保存形式:
(1)保存整个模型的结构信息和参数信息,保存的对象是模型model

torch.save(model, './model.pth')

(2)保存模型的参数,保存的对象是模型的状态model.state dict()

torch.save(model.state_dict(), './model_state.pth')

2、加载模型有两种方式对应于保存模型的方式:
(1)加载完整的模型结构和参数信息,使用load model = torch.load('model.pth' ) ,在网络较大的时候加载的时间比较长,同时存储空间也比较大
(2)加载模型参数信息,需要先导人模型的结构,然后通过model.load_state_dic (torch.load('model state.pth')) 来导入。

参考文献:《深度学习之Pytorch》读书笔记