一篇文章入门深度学习框架PyTorch
- 1 Tensor(张量)
- 2 Variable(变量)
- 3 Dataset(数据集)
- 4 nn.Module(模组)
- 5 torch.optim(优化)
- 6 模型的保存和加载
1 Tensor(张量)
PyTorch
里面处理的最基本的操作对象就是Tensor
,Tensor
表示的是一个多维矩阵,比如零维就是一个点,一维就是向量,二维就是一般的矩阵,多维就相当于一个多维数组
Tensor
和Numpy
是对应的,可以和Numpy
的ndarray
互相转换,唯一不同的是PyTorch
可以再GPU
上运行,numpy
只能在CPU
上运行。
- 常用的不同类型的
Tensor
:32
位浮点型torch.FloatTensor
,64
位浮点型torch.DoubleTensor
,16
位整型torch.ShortTensor
,32
位整型torch.IntTensor
,64
位整型torch.LongTensor
import torch
import numpy as np
a = torch.Tensor([[2, 3], [4, 8], [7, 9]])
print('a is {}'.format(a))
print('a size is {}'.format(a.size()))
b = torch.LongTensor(([[2, 3], [4, 8], [7, 9]]))
print('b is {}'.format(b))
c = torch.zeros((3, 2))
print('zeros tensor {}'.format(c))
d = torch.randn((3, 2))
print('d is {}'.format(d))
a[0, 1] = 100
print('changed a is {}'.format(a))
numpy_b = b.numpy()
print('converse to numpy is \n {}'.format(numpy_b))
e = np.array([[2, 3], [4, 5]])
torch_e = torch.from_numpy(e)
print('from numpy to torch.Tensor is \n {}'.format(torch_e))
f_torch_e = torch_e.float()
print('change data type to float tensor \n {}'.format(f_torch_e))
if torch.cuda.is_available():
a_cuda = a.cuda()
print(a_cuda)
D:\software\anaconda3\envs\pytorch_gpu\python.exe D:/IDEA/pytorch_gpu/src/demo.py
a is tensor([[2., 3.],
[4., 8.],
[7., 9.]])
a size is torch.Size([3, 2])
b is tensor([[2, 3],
[4, 8],
[7, 9]])
zeros tensor tensor([[0., 0.],
[0., 0.],
[0., 0.]])
d is tensor([[-0.3689, -0.8400],
[ 1.1293, -0.3011],
[-0.4752, 0.5565]])
changed a is tensor([[ 2., 100.],
[ 4., 8.],
[ 7., 9.]])
converse to numpy is
[[2 3]
[4 8]
[7 9]]
from numpy to torch.Tensor is
tensor([[2, 3],
[4, 5]], dtype=torch.int32)
change data type to float tensor
tensor([[2., 3.],
[4., 5.]])
tensor([[ 2., 100.],
[ 4., 8.],
[ 7., 9.]], device='cuda:0')
Process finished with exit code 0
2 Variable(变量)
Variable
是神经网络计算图里特有的一个概念,提供了自动求导功能,位于torch.autograd.variable
,在Numpy里不存在。神经网络在做运算的时候,需要先构造一个计算图谱,在里面进行前向传播和反向传播。
- Variable和Tensor本质上没有区别,不过
Variable
会被放入一个计算图中,然后进行前向传播,反向传播,自动求导。
- Variable属性结构图
- Variable有三个重要的属性:data,grad,grad_fn。通过
data
可以取出Variable里面的Tensor数值,grad_fn
表示的是得到这个Variable的操作,比如通过加减还是乘除来得到,grad
是这个Variable的反向传播梯度。
- 自动求导是不需要明确哪个函数对哪个函数求导,直接通过一行代码对所有的需要梯度的变量进行求导。
from torch.autograd.variable import *
x = Variable(torch.Tensor([1]), requires_grad=True)
w = Variable(torch.Tensor([2]), requires_grad=True)
b = Variable(torch.Tensor([3]), requires_grad=True)
y = w * x + b
y.backward()
print(x.grad)
print(w.grad)
print(b.grad)
D:\software\anaconda3\envs\pytorch_gpu\python.exe D:/IDEA/pytorch_gpu/src/demo.py
tensor([2.])
tensor([1.])
tensor([1.])
Process finished with exit code 0
from torch.autograd.variable import *
import torch
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)
D:\software\anaconda3\envs\pytorch_gpu\python.exe D:/IDEA/pytorch_gpu/src/demo.py
tensor([-0.4075, -1.0235, -2.4338], grad_fn=<MulBackward0>)
tensor([2.0000, 0.2000, 0.0200])
Process finished with exit code 0
3 Dataset(数据集)
- 在处理任何机器学习问题之前都需要数据读取并进行预处理。torch.utils.data.Dataset是代表这一数据的抽象类,可以自己定义数据类型集成和重写这个抽象类。
import torch
from torch.utils.data import Dataset
import pandas as pd
class myDataset(Dataset):
def __init__(self, csv_file, txt_file, root_dir, other_file):
self.csv_data = pd.read_csv(csv_file)
with open(txt_file, 'r') as f:
data_list = f.readlines();
self.txt_data = data_list
self.root_dir = root_dir
def __len__(self):
return len(self.csv_data)
def __getitem__(self, item):
data = (self.csv_data[item], self.txt_data[item])
return data
- 通过上面的方式,可以定义需要的数据类,通过迭代的方式取得每一个数据,但是很难实现取batch,shuffle或者多线程取数据,可以通过torch.utils.data.DataLoader
import torch
from torch.utils.data import Dataset, DataLoader
import pandas as pd
from torch.utils.data._utils.collate import default_collate
class myDataset(Dataset):
def __init__(self, csv_file, txt_file, root_dir, other_file):
self.csv_data = pd.read_csv(csv_file)
with open(txt_file, 'r') as f:
data_list = f.readlines()
self.txt_data = data_list
self.root_dir = root_dir
def __len__(self):
return len(self.csv_data)
def __getitem__(self, item):
data = (self.csv_data[item], self.txt_data[item])
return data
dataiter = DataLoader(myDataset, batch_size=32, shuffle=True, collate_fn=default_collate)
4 nn.Module(模组)
- 在PyTorch里面编写神经网络,所有的层结构和损失函数都来自于torch.nn,所有的模型构建都继承自nn.Module基类。
import torch.nn as nn
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)
def forward(self, x):
x = self.conv1(x)
return x
- 这样就建立了一个计算图,并且这个结构可以复用多次,每次调用就相当于用该计算图定义的相同参数做一次前向传播,这得益于PyTorch的自动求导功能,所以我们不需要自己编写反向传播,而所有的网络层都由nn这个包得到,如线性层nn.Linear.
- 定义完模型之后,需要通过nn这个包定义损失函数,常见的损失函数有均方误差、多分类的交叉熵、二分类的交叉熵.
criterion = nn.CrossEntropyLoss()
loss = criterion(output, target)
5 torch.optim(优化)
- 在机器学习或者深度学习中,需要通过修改参数使得损失函数最小化或者最大化,优化算法就是一种调整模型参数更新的策略。
一阶优化算法
- 一阶优化算法使用各个参数的梯度值来更新参数,最常用的一阶优化算法是梯度下降。梯度就是导数的多变量表达式,函数的梯度形成了一个向量场,同时也是一个方向,这个方向上的方向导数最大,且等于梯度。梯度下降的功能是通过寻找最小值,控制方差,更新模型参数,最终使模型收敛,网络的参数更新公式是:
二阶优化算法
- 二阶优化算法使用了二阶导数(也叫做
Hessian
方法)来最小化和最大化损失函数,主要基于牛顿法。但是由于二阶导数计算成本很高,所以这种方法并没有广泛使用。
- torch.optim是一个实现各种优化算法的包,大多数常见的算法都能通过这个包来调用,比如随机梯度下降,以及添加动量的随机梯度下降,自适应学习率等。在调用的时候将需要优化的参数传入,这些参数必须是
Variable
,然后传入一些基本的设定,如学习率和动量。
6 模型的保存和加载
- 在PyTorch里面使用
torch.save
来保存模型的结构和参数,有两种保存方式:
(1)保存整个模型的结构信息和参数信息,保存的对象是Model
(2)保存模型的参数,保存的对象是模型的状态:model.state_dict()
torch.save(model,'./model.pth')
torch.save(model.state_dict(),'./model_state.pth')
- 加载模型有两种方式,对应于保存模型的方式
(1)加载完整的模型结构和参数信息,使用load_model=torch.load(‘model.pth')
,在网络较大的时候,加载的时间较长,同时存储空间较大。
(2)加载模型参数信息,需要先导入模型的结构,然后通过model.load_state_dic(torch.load('model_state.pth'))