这是新的系列教程,在本教程中,我们将介绍使用 FPGA 实现深度学习的技术,深度学习是近年来人工智能领域的热门话题。
在本教程中,旨在加深对深度学习和 FPGA 的理解。
用 C/C++ 编写深度学习推理代码
高级综合 (HLS) 将 C/C++ 代码转换为硬件描述语言
FPGA 运行验证
在之前的文章中,我们已经依次抽取了推理核的任务并行度和循环并行度和数据并行性。在本文中,我们将继续优化。
最终版本包括全连接层的循环数据并行化
在上篇文章中《从FPGA说起的深度学习(八)-数据并行性》,全连接层是一个瓶颈,所以我们实现了一个优化了全连接层的版本。我不会在此处粘贴代码,因此请查看代码存储库中的linear.h (文末)。全连接层是向量和矩阵的乘积,因此与卷积层不同,它不能在两个通道上并行化,但基本上可以使用与卷积层相同的过程进行优化。
如第 6 篇文章所示,当任务之间的处理时间一致时,任务并行性最有效。下表显示了最终版本的并行化程度和执行周期数,它是根据这个目标进行参数调整的conv1, conv2, fc1, fc2。本来,处理fc2一直很低,但现在其他内核基本平衡了。
层 | 并行度(输出通道) | 平行度(x方向) | 执行周期数 | 执行时间(us) |
---|---|---|---|---|
conv1 | 4 | 4 | 12741 | 42.466 |
conv2 | 4 | 8 | 12937 | 43.119 |
fc1 | 4 | – | 12721 | 43.399 |
fc2 | 1 | – | 383 | 1.277 |
整体加速结果
从第8篇到第3篇,我们将任务并行化、循环并行化、数据并行化应用于推理内核。下表总结了这些方法的优化结果。
名称 | 执行时间(毫秒/图像) | 比以前的实施提速 | 相对于基线的改进百分比 |
---|---|---|---|
基线 | 20.81 | 1.00 | 1.00 |
任务并行化 | 12.65 | 1.65 | 1.65 |
通过本地缓冲区减少外部存储器访问 | 1.61 | 7.86 | 12.93 |
循环并行化(仅限卷积层) | 0.61 | 2.64 | 34.11 |
数据并行化 4×4(仅卷积层) | 0.336 | 1.81 | 61.93 |
最终版本 | 0.0498 | 6.75 | 417.87 |
另外,虽然在之前的文章中没有涉及到,但每个优化结果的资源使用情况如下:
名称 | BRAM_18K | DSP48E | FF | LUT |
---|---|---|---|---|
基线 | 49 | 20 | 13592 | 15600 |
任务并行化 | 61 | 20 | 13785 | 15955 |
通过本地缓冲区减少外部存储器访问 | 84 | 21 | 13800 | 16967 |
循环并行化(仅限卷积层) | 84 | 21 | 15363 | 18653 |
数据并行化 4×4(仅卷积层) | 86 | 43 | 22335 | 27020 |
最终版本 | 90+ | 63 | 32764 | 33674 |
首先,看执行性能,这些调优最终使其比基线快 417.87 倍。两个特别有效的是使用本地缓冲区减少外部内存访问和最终版本(加速完全连接的层+层之间的平衡)。这两者中,前者需要大量增加RAM资源,后者需要增加运算单元资源(DSP、LUT)。
另外,虽然我们已经实现了400多倍的性能提升,但即使是资源增量方面增速最高的DSP,也只是63 / 20 = 3.15翻了一番。特别是任务并行化和循环并行化是非常有利的结果,因为几乎不增加资源就可以提高性能。
即使使用当前内核,FPGA 内部仍有大量资源,因此可以应用进一步的优化。可以像这次一样进一步提取内核内部的数据并行性,也可以复制内核本身,取帧间的并行性。特别是,如果只使用前者,在综合时很难满足时序限制,所以我认为有时不得不采用后者的方法。
总结
本次针对的 MNIST 数据集是一个非常小的数据集,图像大小为 28×28。此外,该模型是一个非常轻量级的网络模型。如果将这些做成更真实的数据模型,计算规模会发生如下变化。
分辨率:28×28 -> 几百到几千的宽高
网络规模:2层(卷积层转换)->几十到几百
粗略计算一个真实模型所需的计算量,大约是本次创建的网络模型量的1000到100万倍。如果这个是1000倍左右的话,即使以现在配置的运算单元数也能处理几十毫秒的量级,但如果再增加的话,60fps这样的实时图像处理就会变得困难。为此,实际上使用量化和修建等技术来降低计算成本。我们将在下一篇也是最后一篇文章中介绍这些内容。
代码链接
❝https://github.com/suisuisi/FPGAandCNN/tree/main/DnnKernelHLS
❞