【PyTorch】入门知识
入门知识
本文档基于官网的60min入门教程
《What is PyTprch》
《PyTorch深度学习:60分钟快速入门(官网翻译)》By 黄海广
部分内容来自于《PyTorch机器学习从入门到实战》–机械工业出版社
numpy常用数值操作及特性
pytorch库中有很多操作都可以类比和借鉴numpy库中的处理,且在机器学习中numpy也是一个很重要的强大的数值处理库,建议读者先理一下numpy中的常用操作。
p.s. 以下整理了一些numpy库的思维导图,读者可以对照进行查漏,如果之前没有用过numpy的可以戳下方链接,快速入门~
《numpy教程|菜鸟教程》
又因为numpy库中最重要的一个数据结构就是被称作ndarray的多维数组,其很多特性和操作也可以借鉴python中的列表类型,下方对list的一些概念也进行了整理。
p.s. 整理得很简单,只能用于简单梳理。
什么是PyTorch
PyTorch是一个基于Python的科学计算软件包,主要针对以下两组受众:
- 为了使用GPU的计算功能,用其替代numpy
- 追求灵活和速度的深度学习研究平台
Autograd:自动求导
- 张量(tensor)与ndarray
tensor之于pytorch的关系可以类比ndarray基于numpy的关系,且二者在类型、声明、定义以及运算上有很大的相似性。
【相似的操作】(例举)
x = torch.empty(m,n)#构造一个未初始化的mxn的矩阵
x = torch.rand(m,n)#构造一个随机初始化的mxn的矩阵
x = torch.zeros(m,n,dtype = torch.long)#用零填充一个mxn的矩阵,且元素为long类型
x = torch.tensor([1,2,3]) #通过已知数据来构造张量
【有些许差别的操作】(例举)
x = torch.rand(m,n)
y = x.view(s,t)#将mxn的矩阵x变成sxt维度的矩阵,且是新建改变
x = torch.rand(1)
x.item() #用.item()方法使单个元素张量作为python数字来获得
- 张量与梯度(Gradient)
上图中粉色框框中是需要额外注意的地方,以下也会对其进行一些解释。
[1]:.grad_fn这个属性就是表明了每一个tensor和与之相对应的计算function。
- 用户自己创建的张量对象没有该属性,因为并不是由相关计算得到的
- 根据计算的不同类型,grad_fn属性也是不同
- 如果requires_grad属性未设置True,则得不到相应的grad_fn属性,因为你没有允许其追踪计算记录。
import torch
x = torch.ones(2,2)
y = x + 2
z = x * 3
print(x.grad_fn)
print(y.grad_fn)
print(z.grad_fn)
#None
#None
#None
x = torch.ones(2,2,requires_grad = True)
y = x + 2
z = x * 3
print(x.grad_fn)
print(y.grad_fn)
print(z.grad_fn)
#None
#<AddBackward0 object at 0x000002392660F240>
#<MulBackward0 object at 0x000002392660F2B0>
[2]:防止张量跟踪计算的历史记录和内存使用情况
- 在初始化一个张量时,.requires_grad属性不显式地设置为True
- 使用torch.no_grad()来包装代码块
import torch
x = torch.ones(2,2,requires_grad = True)
print(x.requires_grad)
print((x*2).requires_grad)
with torch.no_grad():
print((x*2).requires_grad)
#True
#True
#False
神经网络
神经网络根据其深度与结构也有深度与否的区别,一个简单的含有输入层-隐含层-输出层的前馈神经网络,只需要弄明白关于前向计算、反向传播、损失函数、激活函数的知识即可。
详情可移步博文《【PyTorch】深度学习基础:神经网络》
1. 单层神经网络的PyTorch实现
下面基于上一篇博文中的一些基础知识,对只含有1层线性隐含层的神经网络进行搭建、训练,
神经网络训练的步骤:
- 数据准备
数据准备——将我们所要使用的数据转换成PyTorch能够处理的格式:对数据集的封装,把结构数据划分成batch。
①提供torch.utils.data.Dataset
对数据进行封装
该类别是所有需要加载数据集的父类,在定义子类时需要重载_len_
和_getitem_
两个函数,前者返回数据集的大小,后者实现数据集的下标索引。
②使用torch.utils.data.DataLoader
对数据进行加载、采样和迭代器的生成
class torch.utils.data.DataLoader(dataset,batch_size = 1,shuffle = False, sampler = None,batch_sampler = None,num_workers = 0,collate_fn = <function default_collate>, pin_memory = False,drop_last = False)
dataset
Dataset的类型,指出要加载的数据集batch_size
指出每个batch需要加载多少样本,默认值为1shuffle
指出是否在每个epoch都需要对数据进行打乱sampler
从数据集中采样样本的策略batch_sampler
与sampler相似,只不过一次会返回一批指标num_workers
加载数据时所使用的子进程数目。默认值为0,表示在主进程中加载数据collate_fn
定义合并样本列表以形成一个mini_batchpin_memory
若设置为true,则数据加载器会将张量复制到CUDA固定内存中,然后返回它们。drop_last
若设置为true,最后一个不完整的batch将会被丢弃。
- 构建网络结构,初始化权重
- 确定激活函数
- 进行前向计算
- 确定损失函数,计算损失值
- 反向传播并更新参数
重复上述前向计算与反向传播的过程,直到收敛或达到终止条件。
import torch
import matplotlib.pyplot as plt
import torch.nn.functional as F
from sklearn.datasets import load_iris
from torch.autograd import Variable
from torch.optim import SGD
#动态判断GPU是否可用,方便在不同类型的处理器上进行迁移
use_cuda = torch.cuda.is_available()
print("use_cuda: ",use_cuda)
#加载数据集,因为是模块里封装好的数据集,只需加载即可使用
iris = load_iris()
print(iris.keys())
#数据预处理,从数据集中将输入输出的信息分离出来并封装成Variable形式
x=iris['data']
y = iris['target']
x = torch.FloatTensor(x)
y = torch.LongTensor(y)
x,y = Variable(x),Variable(y)
#定义神经网络模型
'''
PyTorch中自定义的模型都需要继承Module,并重写forward方法完成前向计算
'''
class Net(torch.nn.Module):
#初始化函数接受自定义额输入特征维数、隐含层特征维数和输出层的特征维数
def __init__(self,n_feature,n_hidden,n_output):
super(Net,self).__init__()
self.hidden = torch.nn.Linear(n_feature,n_hidden)#线性隐含层
self.predict = torch.nn.Linear(n_hidden,n_output)#线性输出层
#重写前向传播过程
def forward(self,x):
x = F.sigmoid(self.hidden(x))
x = self.predict(x)
out = F.log_softmax(x,dim = 1)
return out
#网络实例化并打印查看网络结构
net = Net(n_feature = 4,n_hidden = 5,n_output = 4)
print(net)
#根据iris数据集,输入特征必须是4维的,其余两层的特征维数可以自行选择
#判断GPU是否可用,可以灵活调整数据计算
if use_cuda:
x = x.cuda()
y = y.cuda()
net = net.cuda()
#定义神经网络训练的优化器,并设置学习率为0.5
optimizer = SGD(net.parameters(),lr = 0.5)
#进行训练
px,py = [],[]#用于记录要绘制的数据
for i in range(1000):
#数据传入网络并进行前向计算
prediction = net(x)
#计算loss
loss = F.nll_loss(prediction,y)
#清除网络状态
optimizer.zero_grad()
#loss反向传播
loss.backward()
#更新参数
optimizer.step()
#在训练过程中打印每次迭代的损失情况
print(i," loss: ",loss.data.item())
px.append(i)
py.append(loss.data.item())
#每10次迭代绘制训练动态
if i % 10 == 0:
plt.cla()
plt.plot(px,py,'r-',lw = 1)
plt.text(0,0,'Loss = %.4f' % loss.data.item(),fontdict = {'size':20,'color':'red'})
plt.pause(0.1)
2. PyTorch中神经网络的调用机制
3. PyTorch构建神经网络分类器
有关损失函数、目标函数与优化器的细节可参考下面这篇博文
《【PyTorch】深度神经网络及训练》
利用PyTorch搭建一个由一层输入层、一层全连接的隐层和一层输出层构成的神经网络,对MNIST数据集进行分类。
读者可以借助以下代码对神经网络的特征与参数配置进行熟悉
(1)配置参数
'''
配置库和配置参数
'''
import torch
import torch.nn as nn
import torchvision.datasets as dsets
import torchvision.transforms as transforms
from torch.autograd import Variable
#配置超参数
torch.manual_seed(1)#设置随机数种子,确保结果可能会重复
input_size = 784
hidden_size = 500
num_classes = 10
num_epochs = 5#训练次数
batch_size = 100#批处理大小
learning_rate = 0.001
(2)加载数据集
'''
加载MINST数据集
'''
train_dataset = dsets.MNIST(root= './data',train = True,transform = transforms.ToTensor(),download = True)
#将数据集下载(download)作为训练集(train),其中指定数据保持的位置(root),并且将取值范围从[0,255]转换成[0,1.0](transform)
test_dataset = dsets.MNIST(root = './data',train = False,transform = transforms.ToTensor())
#另保存一份测试集,同样需要进行数值转换
(3)批处理设置
'''
数据批处理设置
'''
#DataLoader(Input Pipeline)
#在训练集中,shuffle必须设置为True,表示次序是随机的
train_loader = torch.utils.data.DataLoader(dataset = train_dataset,batch_size = batch_size,shuffle = True)
test_loader = torch.utils.data.DataLoader(dataset = test_dataset,batch_size = batch_size,shuffle = False)
(4)构建DNN模型
'''
创建DNN模型
'''
class Net(nn.Module):
def __init__(self,input_size,hidden_size,num_classes):
super(Net,self).__init__()
self.fc1 = nn.Linear(input_size,hidden_size)
self.relu = nn.ReLU()
self.fc2 = nn.Linear(hidden_size,num_classes)
def forward(self,x):
out = self.fc1(x)
out = self.relu(out)
out = self.fc2(out)
return out
net = Net(input_size,hidden_size,num_classes)
#打印模型,呈现网络结构
print(net)
【输出结果】
Net(
(fc1): Linear(in_features=784, out_features=500, bias=True)
(relu): ReLU()
(fc2): Linear(in_features=500, out_features=10, bias=True)
)
(5)模型训练
'''
模型训练,将图像和标签都用Variable类进行包装,然后放入模型中进行输出
'''
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(net.parameters(),lr = learning_rate)
#开始训练
for epoch in range(num_epochs):
for i,(images,labels) in enumerate(train_loader):#进行批处理
#将tensor类型转换成Variable类型
images = Variable(images.view(-1,28*28))
Labels = Variable(labels)
#前向计算+反向传播+使用优化器
optimizer.zero_grad()#梯度清零
outputs = net(images)
loss = criterion(outputs,labels)
loss.backward()#后向传播,计算梯度
optimizer.step()#梯度更新
if(i+1)%100 == 0:
print('Epoch [%d/%d],Step[%d/%d],Loss: %.4f'%(epoch+1,num_epochs,i+1,len(train_dataset)//batch_size,loss.data.item()))
【输出结果】
Epoch [1/5],Step[100/600],Loss: 0.1175
Epoch [1/5],Step[200/600],Loss: 0.1390
Epoch [1/5],Step[300/600],Loss: 0.2715
Epoch [1/5],Step[400/600],Loss: 0.1825
Epoch [1/5],Step[500/600],Loss: 0.1173
Epoch [1/5],Step[600/600],Loss: 0.1280
Epoch [2/5],Step[100/600],Loss: 0.1060
Epoch [2/5],Step[200/600],Loss: 0.0543
Epoch [2/5],Step[300/600],Loss: 0.1447
Epoch [2/5],Step[400/600],Loss: 0.1715
Epoch [2/5],Step[500/600],Loss: 0.0646
Epoch [2/5],Step[600/600],Loss: 0.0643
Epoch [3/5],Step[100/600],Loss: 0.1027
Epoch [3/5],Step[200/600],Loss: 0.0191
Epoch [3/5],Step[300/600],Loss: 0.0442
Epoch [3/5],Step[400/600],Loss: 0.0599
Epoch [3/5],Step[500/600],Loss: 0.0470
Epoch [3/5],Step[600/600],Loss: 0.0422
Epoch [4/5],Step[100/600],Loss: 0.0448
Epoch [4/5],Step[200/600],Loss: 0.1024
Epoch [4/5],Step[300/600],Loss: 0.0436
Epoch [4/5],Step[400/600],Loss: 0.0686
Epoch [4/5],Step[500/600],Loss: 0.0393
Epoch [4/5],Step[600/600],Loss: 0.0179
Epoch [5/5],Step[100/600],Loss: 0.0292
Epoch [5/5],Step[200/600],Loss: 0.0473
Epoch [5/5],Step[300/600],Loss: 0.0563
Epoch [5/5],Step[400/600],Loss: 0.0552
Epoch [5/5],Step[500/600],Loss: 0.0352
Epoch [5/5],Step[600/600],Loss: 0.0244
(6)测试集上验证
'''
在测试集测试识别率
'''
correct = 0
total = 0
for images,labels in test_loader:
images = Variable(images.view(-1,28*28))
outputs = net(images)
_,predicted = torch.max(outputs.data,1)#得到预测结果
total += labels.size(0)#正确结果
correct += (predicted == labels).sum()#正确结果总数
print('Accuracy of the network on the 10000 test images: %d %%' % (100*correct // total))
【输出结果】
Accuracy of the network on the 10000 test images: 97 %