在前面的理论讲解和网络实现中,我们断断续续的学习了 Tensorflow 和 keras 两个著名的深度学习框架。当然主要还是 Tensorflow,keras 的底层计算都是以 Tensorflow 为后端的。在正式进入下一环节的学习前,笔者先给 pytorch 入个门,至于系统的学习,还是需要依靠各种项目实战来锻炼。 
pytorch 是一款可以媲美于 Tensorflow 优秀的深度学习计算框架,但又相比于 Tensorflow 在语法上更具备灵活性。pytorch 原生于一款小众语言 lua,而后基于 python 版本后具备了强大的生命力。作为一款基于 python 的深度学习计算库,pytorch 提供了高于 numpy 的强大的张量计算能力和兼具灵活度和速度的深度学习研究功能。 
下面笔者就以 pytorch 基本张量运算、自动求导机制和基于 LeNet-5 的训练实例对 pytorch 进行一个快速的入门和上手。 torch 的张量运算 和学习 Tensorflow 中的张量 tensor 一样,torch 的张量运算也可以理解为 numpy 科学计算的加强版。底层的计算逻辑基本一致,torch 张量的强大之处可以利用 GPU 来加速运算。 创建一个 2x3 的矩阵: x = torch.Tensor(2, 3)print(x)

获取矩阵的大小: print(x.size())
torch.Size([2, 3]) 执行张量运算: y = torch.rand(2, 3)print(x + y)

或者是提供一种指定输出张量的运算语法: result = torch.Tensor(2, 3)torch.add(x, y, out = result)print(result)
当然 torch 也可以方便的与 numpy 数组进行转换。 torch 张量转为 numpy 数组: a = torch.ones(5).numpy()print(a)
[1. 1. 1. 1. 1.] numpy 数组转为 torch 张量: import numpy as npprint(torch.from_numpy(np.ones(5)))

使用 .cuda 方法将 tensor 在 GPU 上运行: if torch.cuda.is_available(): x = x.cuda() y = y.cuda() x + y
由上述操作可见,torch 的张量运算和 numpy 一样非常简单,相较于 tensorflow 的张量运算要更加灵活。 自动求导 在神经网络的反向传播中涉及了大量的求导运算,pytorch 中求导的核心计算模块 autograd 可以帮助我们快速实现复杂的求导运算。而求导运算又是建立在 torch 变量 Variable 基础之上的,Variable 对 torch 的 Tensor 进行了包装,当神经网络的结构和前向计算完成后,可以方便的对变量调用 backward 方法执行反向计算。 创建一个 Variable: from torch.autograd import Variablex = Variable(torch.ones(2, 3), requires_grad = True)print(x)

执行梯度计算: y = x + 2z = y * y * 5out = z.mean()out.backward()print(x.grad)

需要注意的是 torch 计算梯度时关于目标变量的梯度计算的表达方式为 Variable.grad 。 基于 torch 的 LeNet-5 训练 cifar10 LeNet-5 网络我们在第 14 讲的时候已经对论文进行了详细的解读和实现。参看第 14 讲的链接:深度学习笔记14:CNN经典论文研读之Le-Net5及其Tensorflow实现 数据准备和转换: transform = transforms.Compose( [transforms.ToTensor(), transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])trainset = torchvision.datasets.CIFAR10(root='./data', train=True, download=True, transform=transform)trainloader = torch.utils.data.DataLoader(trainset, batch_size=4, shuffle=True, num_workers=2)testset = torchvision.datasets.CIFAR10(root='./data', train=False, download=True, transform=transform)testloader = torch.utils.data.DataLoader(testset, batch_size=4, shuffle=False, num_workers=2)classes = ('plane', 'car', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck')
torchvision 是用来服务于 torch 包的,用于生成、转换和准备预训练模型。cifar10 数据集:

定义 LeNet-5 网络结构: from torch.autograd import Variable import torch.nn as nn import torch.nn.functional as F
class Net(nn.Module): def __init__(self): super(Net, self).__init__() self.conv1 = nn.Conv2d(3, 6, 5) self.pool = nn.MaxPool2d(2, 2) self.conv2 = nn.Conv2d(6, 16, 5) self.fc1 = nn.Linear(16 * 5 * 5, 120) self.fc2 = nn.Linear(120, 84) self.fc3 = nn.Linear(84, 10) def forward(self, x): x = self.pool(F.relu(self.conv1(x))) x = self.pool(F.relu(self.conv2(x))) x = x.view(-1, 16 * 5 * 5) x = F.relu(self.fc1(x)) x = F.relu(self.fc2(x)) x = self.fc3(x) return xnet = Net()
定义损失函数和优化器: import torch.optim as optimcriterion = nn.CrossEntropyLoss()optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)
训练 LeNet-5: for epoch in range(5): running_loss = 0.0 for i, data in enumerate(trainloader, 0): # get input data inputs, labels = data # variable the data inputs, labels = Variable(inputs), Variable(labels) # gradients zeros optimizer.zero_grad() # forward + backward + optimize outputs = net(inputs) loss = criterion(outputs, labels) loss.backward() optimizer.step() # print model train info running_loss += loss.data[0] if i % 2000 == 1999: print('[%d, %5d] loss: %.3f' % (epoch + 1, i + 1, running_loss / 2000)) running_loss = 0.0
print('Finished Training')

在测试集上展示训练效果: import matplotlib.pyplot as plt def imshow(img): img = img / 2 + 0.5 npimg = img.numpy() plt.imshow(np.transpose(npimg, (1, 2, 0))) # test the net on test datasets# ground truth dataiter = iter(testloader)images, labels = dataiter.next() # print image imshow(torchvision.utils.make_grid(images))print('GroundTruth: ', ' '.join('%5s' % classes[labels[j]] for j in range(4)))

看看 LeNet-5 的预测结果:
# the net predict result outputs = net(Variable(images))_, predicted = torch.max(outputs.data, 1)print('Predicted: ', ' '.join('%5s' % classes[predicted[j]] for j in range(4)))
(‘Predicted: ‘, ‘ cat ship ship plane’) 貌似训练效果很好。再来看一下模型在全部测试集上的表现: # test on all test data correct = 0 total = 0 for data in testloader: images, labels = data outputs = net(Variable(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: 61 % 准确率达到 61%,已经远超随机猜测的10%的准确率了。 再看看模型在每一类别上的分类准确率的表现: class_correct = list(0. for i in range(10))class_total = list(0. for i in range(10)) for data in testloader: images, labels = data outputs = net(Variable(images)) _, predicted = torch.max(outputs.data, 1) c = (predicted == labels).squeeze() for i in range(4): label = labels[i] class_correct[label] += c[i] class_total[label] += 1
for i in range(10): print('Accuracy of %5s : %2d %%' % ( classes[i], 100 * class_correct[i] / class_total[i]))

可见模型在猫和鸟等小型动物上分类效果较差,在车船飞机等大型物体上效果较好。该实例来自于 pytorch 的官方 tutorial 60 分钟快速上手文档,能够让大家非常快速的入门学习 pytorch 。 在对神经网络的基本原理有深刻理解的基础上,对比之前的 tensorflow 和 keras,相信大家都能快速掌握 pytorch 。 参考资料: http://pytorch.org/tutorials/ http://pytorch./cn/tutorials/
|