如何提高深度神经网络的训练推理速度一直是人工智能从业者关注的问题。现在,intel的oneAPI为我们提供了成套的解决方案,只需要调用几个api,就能轻松加速模型训练。
本文使用的是oneAPI AI分析工具套件(Intel® AI Analytics Toolkit)中的Intel Optimization for PyTorch来对卷积神经网络(CNN)的训练进行加速。文章展示了如何在Intel DevCloud上用现成的环境快速进行CNN加速实验,同时用数据说明了加速效果。
CNN
还是先简单介绍一下卷积神经网络。由于这不是本文的重点,所以仅粗略的介绍其原理。
卷积神经网络(CNN)一般用来处理计算机视觉方面的任务。它是对多层感知机的改进,主要是用卷积去处理二维的输入数据。CNN最初是在20世纪80年代由杨立昆提出的。
CNN构成
卷积神经网络的基本结构大致包括:卷积层、激活函数、池化层、全连接层、输出层等。
卷积层中最重要的概念是卷积核,卷积核可以理解为是一种特征,将输入和卷积核相乘得到的结果就是输入在这个特征上的投影,这个投影可以称之为特征图。以图像识别为例,假设有一个特征表示物体的轮廓,将输入的图像和这个特征相乘得到的就是图像的轮廓图。卷积层就是在提取图像的特征。
激活函数是用来加入非线性因素,提高网络表达能力,卷积神经网络中最常用的是ReLU,这里也采取了ReLU作为激活函数。
池化操作使用某位置相邻输出的总体统计特征作为该位置的输出。常见的池化有最大值池化和平均池化两种,顾名思义就是在池化窗口内计算最大值和平均值作为池化结果。
全连接层对卷积层和池化层输出的特征图(二维)进行降维,将学到的特征表示映射到样本标记空间。
CNN训练算法
在训练CNN的时候,采用的是随机梯度下降(SGD),也称增量梯度下降的方法。实验中用于优化可微分目标函数的迭代算法。
其训练算法描述如下:
Step 1:用随机数初始化所有的卷积核和参数/权重
Step 2:将训练图片作为输入,执行反向传播步骤并计算每个类别的对应输出概率
Step 3:计算输出层的总误差
Step 4:反向传播算法计算误差相对于所有权重的梯度,并用梯度下降法更新所有的卷积核和参数/权重的值,以使输出误差最小化
代码实现
这里用Pytorch实现一个最简单的CNN,含有一个3乘3的卷积层,激活函数为ReLU,接上一个池化层,最后是一个全连接层。
import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import datasets, transforms
from tqdm import tqdm
# 定义卷积神经网络模型
class SimpleCNN(nn.Module):
def __init__(self):
super(SimpleCNN, self).__init__()
self.conv1 = nn.Conv2d(1, 32, kernel_size=3, stride=1, padding=1)
self.relu = nn.ReLU()
self.pool = nn.MaxPool2d(kernel_size=2, stride=2)
self.fc1 = nn.Linear(32 * 14 * 14, 10)
def forward(self, x):
x = self.conv1(x)
x = self.relu(x)
x = self.pool(x)
x = x.view(x.size(0), -1)
x = self.fc1(x)
return x
# 设置随机种子,以便结果可复现
torch.manual_seed(123)
# 定义数据预处理
transform = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.1307,), (0.3081,))
])
# 加载训练集和测试集
train_dataset = datasets.MNIST(root='./data', train=True, transform=transform, download=True)
test_dataset = datasets.MNIST(root='./data', train=False, transform=transform)
# 定义数据加载器
batch_size = 64
train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=batch_size, shuffle=False)
# 初始化模型
model = SimpleCNN()
# 定义损失函数和优化器
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.001, momentum=0.9)
# 训练循环
num_epochs = 10
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model.to(device)
for epoch in range(num_epochs):
model.train() # 设置模型为训练模式
running_loss = 0.0
correct = 0
total = 0
with tqdm(train_loader, unit="batch") as t: # 使用tqdm创建进度条
for inputs, labels in t:
inputs, labels = inputs.to(device), labels.to(device)
optimizer.zero_grad()
# 前向传播
outputs = model(inputs)
loss = criterion(outputs, labels)
# 反向传播和优化器更新
loss.backward()
optimizer.step()
# 统计准确率
_, predicted = outputs.max(1)
total += labels.size(0)
correct += predicted.eq(labels).sum().item()
# 更新进度条描述
t.set_postfix({"loss": loss.item(), "accuracy": 100*correct/total})
# 在测试集上验证模型性能
model.eval() # 设置模型为评估模式
test_loss = 0.0
test_correct = 0
test_total = 0
with torch.no_grad():
for inputs, labels in test_loader:
inputs, labels = inputs.to(device), labels.to(device)
outputs = model(inputs)
test_loss += criterion(outputs, labels).item()
_, predicted = outputs.max(1)
test_total += labels.size(0)
test_correct += predicted.eq(labels).sum().item()
# 打印训练和测试信息
train_accuracy = 100 * correct / total
test_accuracy = 100 * test_correct / test_total
print(f"Epoch [{epoch+1}/{num_epochs}], Train Accuracy: {train_accuracy:.2f}%, Test Accuracy: {test_accuracy:.2f}%")
用Intel DevCloud 进行实验
DevCloud介绍
英特尔® Developer Cloud for the Edge 概述 (intel.cn)
这是一个为边缘计算开发者提供的云平台,它提供了一系列工具、资源和服务,帮助开发者在边缘设备上开发、测试和部署应用程序。它可以提供计算能力、存储资源、边缘机器学习支持等,使开发者能够更方便地构建和部署适用于边缘环境的应用。
环境搭建
首先,需要注册Intel账号,然后进入到Developer Cloud for the Edge的页面,选择裸机开发
进入后的页面如下图,点击DL Workbench AI Tools
进入如下页面:
接下来按照notebook的指导运行相应的代码块进行初始化设置
最后直接在后面嵌入代码块,运行就可以了
利用oneAPI加速
只需要在代码开头加入一行:
import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import datasets, transforms
from tqdm import tqdm
# 使用Intel MKL-DNN进行优化
torch.backends.mkldnn.enabled = True
这段代码调用了Intel(R) MKL-DNN,其全称是Intel(R) Math Kernel Library for Deep Neural Networks。它是一种针对深度学习(DL)应用的开源性能库,主要在Intel(R) CPU、Intel(R) GPU以及Xe图形处理器上对深度神经网络进行op级以及指令集级的优化。oneAPI对PyTorch的优化中集成了这个库。
实验结果
我用MNIST数据集训练了10个epoch。两个结果是在相同的软硬件环境下得到的。
没有用oneAPI加速的结果如下:
每个epoch的耗时大约在27秒左右
用oneAPI加速之后:
每个epoch的耗减小到了24秒左右,训练时长减小了11%,同时loss数据和accuracy数据是一致的,这说明优化没有改变训练的结果
oneAPI加速原理
根据网络资料,我找到了oneAPI针对CNN的优化原理,这能够解释为什么模型训练会加快。由于卷积的计算占训练计算的大头,所以oneAPI针对卷积计算进行了专门的优化,主要有三个方法:
1)直接法:利用SIMD指令集直接执行卷积计算。
2)Winograd算法:使用Winograd算法进行卷积计算,该方法虽然减少了计算复杂度,但同时也降低了精度并增加了内存消耗。
3)GEMM算法:采用GEMM算法进行卷积计算。
总结
本文展现了使用Intel oneAPI加速CNN训练的实验过程和结果。通过实验,我体会到了oneAPI对AI模型的强大加速能力。