3.4 PyTorch
3.4 pytorch
pytorch是torch的python版本,是由facebook开源的神经网络框架。pytorch虽然是深度学习框架中的后起之秀,但是发展极其迅猛。pytorch提供了numpy风格的tensor操作,熟悉numpy操作的用户非常容易上手。我们以解决经典的手写数字识别的问题为例,介绍pytorch的基本使用方法,代码路径为:
https://github.com/duoergun0729/adversarial_examples/blob/master/code/2-pytorch.ipynb
1. 加载相关库
加载处理经典的手写数字识别问题相关的python库:
import os
import torch
import torchvision
from torch.autograd import variable
import torch.utils.data.dataloader as data
2. 加载数据集
pytorch中针对常见的数据集进行了封装,免去了用户手工下载的过程并简化了预处理的过程。这里需要特别指出的是,pytorch中每个tensor包括输入节点,并且都可以有自己的梯度值,因此训练数据集要设置为train=true,测试数据集要设置为train=false:
train_data = torchvision.datasets.mnist(
'dataset/mnist-pytorch', train=true,
transform=torchvision.transforms.totensor(), download=true
)
test_data = torchvision.datasets.mnist(
'dataset/mnist-pytorch', train=false,
transform=torchvision.transforms.totensor()
)
如果需要对数据进行归一化,可以进一步使用transforms.normalize方法:
transform=transforms.compose([torchvision.transforms.totensor(),
torchvision.transforms.normalize([0.5], [0.5])])
第一次运行该程序时,pytorch会从互联网直接下载数据集并处理:
downloading http://yann.lecun.com/exdb/mnist/train-images-idx3-ubyte.gz
downloading http://yann.lecun.com/exdb/mnist/train-labels-idx1-ubyte.gz
downloading http://yann.lecun.com/exdb/mnist/t10k-images-idx3-ubyte.gz
downloading http://yann.lecun.com/exdb/mnist/t10k-labels-idx1-ubyte.gz
processing... done!
3. 定义网络结构
使用与keras类似的网络结构,即两层隐藏层结构,不过使用batchnorm层替换了dropout层,在抵御过拟合的同时加快了训练的收敛速度。在pytorch中定义网络结构,通常需要继承torch.nn.module类,重点是在forward中完成前向传播的定义,在init中完成主要网络层的定义:
class net(torch.nn.module):
def __init__(self):
super(net, self).__init__()
self.dense = torch.nn.sequential(
#全连接层
torch.nn.linear(784, 512),
#batchnorm层
torch.nn.batchnorm1d(512),
torch.nn.relu(),
torch.nn.linear(512, 10),
torch.nn.relu()
) def forward(self, x):
#把输出转换成大小为784的一维向量
x = x.view(-1, 784)
x=self.dense(x)
return torch.nn.functional.log_softmax(x, dim=1)
最后可视化网络结构,细节如图3-7所示。
图3-7 pytorch处理mnist的网络结构图
4. 定义损失函数和优化器
损失函数使用交叉熵crossentropyloss,优化器使用adam,优化的对象是全部网络参数:
optimizer = torch.optim.adam(model.parameters())
loss_func = torch.nn.crossentropyloss()
5. 训练与验证
pytorch的训练和验证过程是分开的,在训练阶段需要把训练数据进行前向传播后,使用损失函数计算训练数据的真实标签与预测标签之间损失值,然后显示调用反向传递backward(),使用优化器来调整参数,这一操作需要调用optimizer.step():
for i, data in enumerate(train_loader):
inputs, labels = data
inputs, labels = inputs.to(device), labels.to(device)
# 梯度清零
optimizer.zero_grad()
# 前向传播
outputs = model(inputs)
loss = loss_func(outputs, labels)
#反向传递
loss.backward()
optimizer.step()
每轮训练需要花费较长的时间,为了让训练过程可视化,可以打印训练的中间结果,比如每100个批次打印下平均损失值:
# 每训练100个批次打印一次平均损失值
sum_loss += loss.item()
if (i+1) % 100 == 0:
print('epoch=%d, batch=%d loss: %.04f'% (epoch + 1, i+1, sum_loss / 100))
sum_loss = 0.0
验证阶段要手工关闭反向传递,需要通过torch.no_grad()实现:
# 每跑完一次epoch,测试一下准确率进入测试模式,禁止梯度传递
with torch.no_grad():
correct = 0
total = 0
for data in test_loader:
images, labels = data
images, labels = images.to(device), labels.to(device)
outputs = model(images)
# 取得分最高的那个类
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).sum()
print('epoch=%d accuracy=%.02f%%' % (epoch + 1, (100 * correct /
total)))
经过20轮训练,在测试集上准确度达到了97.00%:
epoch=20, batch=100 loss: 0.0035
epoch=20, batch=200 loss: 0.0049
epoch=20, batch=300 loss: 0.0040
epoch=20, batch=400 loss: 0.0042
epoch=20 accuracy=97.00%
pytorch保存的模型文件后缀为pth:
torch.save(model.state_dict(), 'models/pytorch-mnist.pth')
pytorch是torch的python版本,是由facebook开源的神经网络框架。pytorch虽然是深度学习框架中的后起之秀,但是发展极其迅猛。pytorch提供了numpy风格的tensor操作,熟悉numpy操作的用户非常容易上手。我们以解决经典的手写数字识别的问题为例,介绍pytorch的基本使用方法,代码路径为:
https://github.com/duoergun0729/adversarial_examples/blob/master/code/2-pytorch.ipynb
1. 加载相关库
加载处理经典的手写数字识别问题相关的python库:
import os
import torch
import torchvision
from torch.autograd import variable
import torch.utils.data.dataloader as data
2. 加载数据集
pytorch中针对常见的数据集进行了封装,免去了用户手工下载的过程并简化了预处理的过程。这里需要特别指出的是,pytorch中每个tensor包括输入节点,并且都可以有自己的梯度值,因此训练数据集要设置为train=true,测试数据集要设置为train=false:
train_data = torchvision.datasets.mnist(
'dataset/mnist-pytorch', train=true,
transform=torchvision.transforms.totensor(), download=true
)
test_data = torchvision.datasets.mnist(
'dataset/mnist-pytorch', train=false,
transform=torchvision.transforms.totensor()
)
如果需要对数据进行归一化,可以进一步使用transforms.normalize方法:
transform=transforms.compose([torchvision.transforms.totensor(),
torchvision.transforms.normalize([0.5], [0.5])])
第一次运行该程序时,pytorch会从互联网直接下载数据集并处理:
downloading http://yann.lecun.com/exdb/mnist/train-images-idx3-ubyte.gz
downloading http://yann.lecun.com/exdb/mnist/train-labels-idx1-ubyte.gz
downloading http://yann.lecun.com/exdb/mnist/t10k-images-idx3-ubyte.gz
downloading http://yann.lecun.com/exdb/mnist/t10k-labels-idx1-ubyte.gz
processing... done!
3. 定义网络结构
使用与keras类似的网络结构,即两层隐藏层结构,不过使用batchnorm层替换了dropout层,在抵御过拟合的同时加快了训练的收敛速度。在pytorch中定义网络结构,通常需要继承torch.nn.module类,重点是在forward中完成前向传播的定义,在init中完成主要网络层的定义:
class net(torch.nn.module):
def __init__(self):
super(net, self).__init__()
self.dense = torch.nn.sequential(
#全连接层
torch.nn.linear(784, 512),
#batchnorm层
torch.nn.batchnorm1d(512),
torch.nn.relu(),
torch.nn.linear(512, 10),
torch.nn.relu()
) def forward(self, x):
#把输出转换成大小为784的一维向量
x = x.view(-1, 784)
x=self.dense(x)
return torch.nn.functional.log_softmax(x, dim=1)
最后可视化网络结构,细节如图3-7所示。
图3-7 pytorch处理mnist的网络结构图
4. 定义损失函数和优化器
损失函数使用交叉熵crossentropyloss,优化器使用adam,优化的对象是全部网络参数:
optimizer = torch.optim.adam(model.parameters())
loss_func = torch.nn.crossentropyloss()
5. 训练与验证
pytorch的训练和验证过程是分开的,在训练阶段需要把训练数据进行前向传播后,使用损失函数计算训练数据的真实标签与预测标签之间损失值,然后显示调用反向传递backward(),使用优化器来调整参数,这一操作需要调用optimizer.step():
for i, data in enumerate(train_loader):
inputs, labels = data
inputs, labels = inputs.to(device), labels.to(device)
# 梯度清零
optimizer.zero_grad()
# 前向传播
outputs = model(inputs)
loss = loss_func(outputs, labels)
#反向传递
loss.backward()
optimizer.step()
每轮训练需要花费较长的时间,为了让训练过程可视化,可以打印训练的中间结果,比如每100个批次打印下平均损失值:
# 每训练100个批次打印一次平均损失值
sum_loss += loss.item()
if (i+1) % 100 == 0:
print('epoch=%d, batch=%d loss: %.04f'% (epoch + 1, i+1, sum_loss / 100))
sum_loss = 0.0
验证阶段要手工关闭反向传递,需要通过torch.no_grad()实现:
# 每跑完一次epoch,测试一下准确率进入测试模式,禁止梯度传递
with torch.no_grad():
correct = 0
total = 0
for data in test_loader:
images, labels = data
images, labels = images.to(device), labels.to(device)
outputs = model(images)
# 取得分最高的那个类
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).sum()
print('epoch=%d accuracy=%.02f%%' % (epoch + 1, (100 * correct /
total)))
经过20轮训练,在测试集上准确度达到了97.00%:
epoch=20, batch=100 loss: 0.0035
epoch=20, batch=200 loss: 0.0049
epoch=20, batch=300 loss: 0.0040
epoch=20, batch=400 loss: 0.0042
epoch=20 accuracy=97.00%
pytorch保存的模型文件后缀为pth:
torch.save(model.state_dict(), 'models/pytorch-mnist.pth')