《AI安全之对抗样本入门》—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')
- 点赞
- 收藏
- 关注作者
评论(0)