0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

从FPGA说起的深度学习:数据并行性

OpenFPGA 来源:OpenFPGA 2023-05-04 11:22 次阅读

这是新的系列教程,在本教程中,我们将介绍使用 FPGA 实现深度学习的技术,深度学习是近年来人工智能领域的热门话题

在本教程中,旨在加深对深度学习和 FPGA 的理解。

用 C/C++ 编写深度学习推理代码

高级综合 (HLS) 将 C/C++ 代码转换为硬件描述语言

FPGA 运行验证

在之前的文章中,我们已经依次抽取了推理核的任务并行度和循环并行度。在本文中,我们将提取推理内核的数据并行性。

数据并行

数据并行性表示待处理数据之间的并行度。

下面的代码是一个简单的向量加法运算,但是由于c[0]和c[1]计算之间没有依赖关系,所以可以同时计算。这种并行性就是数据并行性。

for(inti=0;i< N; i++) {
    c[i] = a[i] + b[i];
}

另一方面,在以下处理的情况下,b[1]的值取决于b[0] ,因此在这种情况下无法提取数据并行性。

for(inti=0;i< N; i++) {
    b[i+1] = a[i] + b[i];
}

补充一下和上次讨论的循环并行的区别,在循环并行中,每个进程都在一个流水线中执行。因此,上述向量相加处理的处理波形如下。

9cc9902a-e6db-11ed-ab56-dac502259ad0.png

循环并行

另一方面,提取数据并行性对应于复制运算单元。复制两个计算器时的波形如下。

9cd2fe80-e6db-11ed-ab56-dac502259ad0.png

数据并行

处理数据并行性的难点在于,我们提取的数据并行性越多,消耗的硬件资源就越多。访问内存资源(加载/存储)特别容易出现问题。请注意,FPGA 中的 BRAM 每个周期最多只能发出 2 次加载/存储,因此如果每个周期需要超过 3 次加载/存储,则 BRAM 将加倍(如果访问目标是 BRAM)。

如下图所示,可以同时提取循环并行度和数据并行度。

9cdba256-e6db-11ed-ab56-dac502259ad0.png

数据+循环并行

本文所有代码都是数据+循环并行的同时提取。

卷积处理中的数据并行

在卷积过程的6级循环(输出通道,y坐标,x坐标,输入通道,内核y方向,内核x方向)中可以提取出各种并行性。

在本文中,我们将提取其中两者的并行性,提高内核的性能。

首先,可以提取的并行度是下图所示的处理像素之间的并行度。

9ce5027e-e6db-11ed-ab56-dac502259ad0.png 处理像素之间的并行性

由于橙色和蓝色像素的计算是相互独立的,所以它们可以同时进行。此外,用于卷积计算的内核(黄色)可以为两种计算共享。因此,一个过程(两个卷积)所需的内存访问是两次像素读取和一次内核读取。

第二种并行度是下图所示的输出通道之间的并行度。

9cef501c-e6db-11ed-ab56-dac502259ad0.png 输出通道之间的并行度

由于黄色和蓝色核的卷积计算是相互独立的,所以它们也可以同时进行。在这个例子中,内核需要两次读取,但像素只需要一次读取。一个进程(卷积)所需的内存访问是一次像素读取和两次内核读取。

两种并行性的图形表示如下所示。2个pixel reads和2个kernel reads可以计算出4个输出值。

9cfcf564-e6db-11ed-ab56-dac502259ad0.png 处理像素之间的并行度+输出通道之间的并行度

基于此图要实现的HW框图如下。

9d07aa36-e6db-11ed-ab56-dac502259ad0.png 卷积处理块

此处重要的是计算单元 (PE) 可以以网格模式排列。

仅对一个通道(像素/输出通道)进行数据并行化时,并行度只排列一个n算子。n前面提到,并行度的增加会导致内存资源使用量的增加,比如BRAM,在一个通道进行并行化时无法充分使用DSP

另一方面,如上图所示,如果将两个通道并行化,则像素侧的并行度设为n,输出通道侧的并行度设为m,则总内存访问端口数相对于n+m的增加量,运算器可以排列n*m个。这样一来,FPGA中的大部分资源都可以分配给运算。许多DNN体系结构(如xDNN)都是这样同时提取多通道数据并行性的。

代码更改

由于两个通道的数据并行化是完全一样的,本文只描述两个通道并行化的结果。另外,在上一篇文章中使用移位寄存器达到了II=1,但是这里我们使用以前的版本。后面会介绍使用方法。

修改后的卷积函数如下所示:完整的代码后续会开源。

203template
204staticvoidconv2d_unrolled_v2(constfloat*x,constfloat*weight,constfloat*bias,int32_twidth,int32_theight,
205int32_tin_channels,int32_tout_channels,int32_tksize,float*y){
206
207for(int32_tblock_och=0;block_och< out_channels; block_och += UNROLL_OCH) {
208     for (int32_t h = 0; h < height; ++h) {
209       for (int32_t block_w = 0; block_w < width; block_w += UNROLL_X) {
210         float sum[UNROLL_OCH][UNROLL_X];
211 #pragma HLS array_partition variable=sum complete dim=0
212
213         for (int32_t ich = 0; ich < in_channels; ++ich) {
214           for (int32_t kh = 0; kh < ksize; ++kh) {
215             for (int32_t kw = 0; kw < ksize; ++kw) {
216 #pragma HLS pipeline II=4
217               for (int local_och = 0; local_och < UNROLL_OCH; local_och++) {
218 #pragma HLS unroll
219                 for (int local_w = 0; local_w < UNROLL_X; local_w++) {
220 #pragma HLS unroll
221                   if (block_w + local_w < width && block_och + local_och < out_channels) {
222
223                     int32_t och = block_och + local_och;
224                     int32_t w = block_w + local_w;
...
234                     float last = (ich == 0 && kh == 0 && kw == 0) ? 0 : sum[local_och][local_w];
235
236                     int64_t pix_idx = (ich * height + ph) * width + pw;
237                     int64_t weight_idx = ((och * in_channels + ich) * ksize + kh) * ksize + kw;
238
239                     sum[local_och][local_w] = last + x[pix_idx] * weight[weight_idx];
240                   }
241                 }
242               }
243             }
244           }
245         }
246
247         for (int local_och = 0; local_och < UNROLL_OCH; local_och++) {
248 #pragma HLS unroll
249           for (int local_w = 0; local_w < UNROLL_X; local_w++) {
250 #pragma HLS unroll
251             if (block_w + local_w < width && block_och + local_och < out_channels) {
252               int32_t och = block_och + local_och;
253               int32_t w = block_w + local_w;
254
255               // add bias
256               y[(och * height + h) * width + w] = sum[local_och][local_w] + bias[och];
257             }
258           }
259         }
260       }
261     }
262   }
263 }

主要变化如下。

1、添加模板参数UNROLL_X, UNROLL_OCH(L203)

2、将输出通道回路更改为 2 级(L207、L217、L247)

3、将 x 方向循环更改为 2 步(L209、L219、L249)

4、重复总和寄存器 (L210)

5、添加了新的编译指示unroll(L218、L220、L248、L250)

6、设置内循环管道II为4(L216)

1、添加了一个模板参数,以便可以在外部指定函数的性能。Vivado HLS / Vitis 与 C++ 模板的兼容性非常好,不仅可以像这次这样使用,还可以像这样进行设置#pragma HLS pipeline II=。对于习惯写Verilog HDL等的人来说,parameter几乎可以像模块语法一样使用。

2中执行的输出通道更改为 2 级,内部循环旋转了数据并行化时的并行度,local_och外部block_och循环旋转了UNROLL_OCH宽度。如果这样做,当输出通道数UNROLL_OCH不是2的倍数时,会发生数组元素之外的访问,因此需要像 L221 这样的处理。

此外,local_och循环被移动到原始代码中最内层循环的循环内kw。此更改不会影响此问题的输出,但请注意,根据正在处理的问题,可能存在更改输出的依赖项。

3和2的修改完全一样,4的求和寄存器变成了存储上述格运算单元(PE)计算结果的寄存器。

5#pragma HLS unroll是用于将数据并行性应用于循环并布置多个运算单元的编译指示。默认情况下,运算符根据循环的迭代次数重复,但factor=N可以通过提供参数来控制运算符的重复次数。

由于我们将这个 pragma 设置为local_och, local_w两个循环,所以 L223-239 中的求和操作和 L252-L256 中的偏置加法和输出操作UNROLL_W * UNROLL_OCH是重复的。看起来L239进行x, weight的加载处理也UNROLL_W * UNROLL_OCH加了1,但是由于编译器优化,每个端口UNROLL_W, UNROLL_OCH只加1。

6中设置的II=4的值就是我们在上一篇文章中看到的处理延迟。在上一篇文章中,我介绍了一种使用移位寄存器实现如下波形的技术。

9d0e791a-e6db-11ed-ab56-dac502259ad0.png

在这个例子中,我们使用了一个移位寄存器来处理每个周期切换输出目标寄存器,但是如果你像这次做数据并行化,你只需要每个周期切换数据作为计算目标。我只是更改了左侧的标签,但是如果对此进行说明,它将如下图所示。

9d151018-e6db-11ed-ab56-dac502259ad0.png

如果这样做,就不需要像上次那样需要移位寄存器之间的求和,所以效率很高。

设置 II=4 的另一个原因是x, weight端口数。它们基本上是作为 BRAM 实现的,每个周期总共允许两次读/写。由于x只是在卷积层处理的过程中被卷积层读取,所以每个周期最多可以读取2次,但是这样一来,当数据并行化的并行度设置为4时,端口数就不够用了。

由于这次II=4,当并行度为4时,每4个周期供给4个数据就足够了。它只需要 1 个读取端口,因此 BRAM 默认带宽就足够了。快速说明如果想要超过 16 度的并行度该怎么做,这可以通过#pragma HLS array_partition pragma来完成,下面附上UG902中的示意图。

9d24e8c6-e6db-11ed-ab56-dac502259ad0.png

C 中定义的数组默认为 1 端口数组,如图中左侧所示。如果它像我在上一篇/这篇文章中使用的那样扩展为一个寄存器,或者如果它被并发访问,就像在这个complete循环 其实适当设置这个pragma而不降低II才是王道,但是这个pragma必须定义在数组资源(本次函数)的定义范围内,而且改变需要时间,所以这次没有使用。

综合结果/性能

使用x方向平行度为4、输出通道方向平行度为4的卷积函数综合推理函数。由于这个卷积函数如上所述有II=4,所以它每4个周期执行16次操作。在这个配置中,需要的运算单元个数为16/4 = 4,每个内存的访问端口为一个4/4 = 1端口。

查看综合结果,卷积函数中浮点运算单元资源使用量变化如下。

9d3bc014-e6db-11ed-ab56-dac502259ad0.png

原始配置有两个 fadds 和一个 fmul,具有两个 fadds 的那个full_dsp_1用于添加偏差。另一方面,在数据并行化后的结果中,fadd为6,fmul为4。除了偏置加法的数量full_dsp_1增加到2之外,fadd/fmul各为4,资源量符合预期。

性能报告如下,conv2的执行时间,上篇文章时为0.423ms,加速到82.875us。

9d608ab6-e6db-11ed-ab56-dac502259ad0.png

审核编辑:汤梓红

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • FPGA
    +关注

    关注

    1602

    文章

    21320

    浏览量

    593195
  • 内核
    +关注

    关注

    3

    文章

    1309

    浏览量

    39846
  • 人工智能
    +关注

    关注

    1776

    文章

    43845

    浏览量

    230600
  • C++
    C++
    +关注

    关注

    21

    文章

    2066

    浏览量

    72900
  • 深度学习
    +关注

    关注

    73

    文章

    5237

    浏览量

    119908

原文标题:从FPGA说起的深度学习(八)-数据并行性

文章出处:【微信号:Open_FPGA,微信公众号:OpenFPGA】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    相比GPU和GPP,FPGA深度学习的未来?

    相比GPU和GPP,FPGA在满足深度学习的硬件需求上提供了具有吸引力的替代方案。凭借流水线并行计算的能力和高效的能耗,FPGA将在一般的
    发表于 07-28 12:16 7369次阅读

    浅析HLS的任务级并行性

    HLS的任务级并行性(Task-level Parallelism)分为两种:一种是控制驱动型;一种是数据驱动型。
    的头像 发表于 07-27 09:21 621次阅读
    浅析HLS的任务级<b class='flag-5'>并行性</b>

    FPGA深度学习应用中或将取代GPU

    系统等其他行业也面临着类似的挑战。 FPGA深度学习 FPGA 是可定制的硬件设备,可对其组件进行调节,因此可以针对特定类型的架构 (如 卷积神经网络) 进行优化。其可定制
    发表于 03-21 15:19

    【详解】FPGA深度学习的未来?

    深度利用流水线并行,这与前馈深度学习方法自然契合。现代FPGA还支持部分动态重新配置,当
    发表于 08-13 09:33

    为什么说FPGA是机器深度学习的未来?

    都出现了重大突破。深度学习是这些领域中所最常使用的技术,也被业界大为关注。然而,深度学习模型需要极为大量的数据和计算能力,只有更好的硬件加速
    发表于 10-10 06:45

    Python中的并行性和并发性分析

      在Python编程语言当中,很多人对Python中的并行性和并发性不了解。今天我们将讨论python中的并发和并行性www.zpedu.com。在这里,我们将研究Python的多线程,多处
    发表于 08-21 17:45

    阻止任务级别并行性的常见情况

    粗粒度并行优化的任务级流水阻止任务级别并行性的常见情况
    发表于 03-09 06:58

    如何利用ARM和FPGA设计一种高速图像数据采集传输系统?

    本文结合实际系统中的前端图像处理和图像数据传输的需要,充分利用ARM的灵活性和FPGA并行性的特点,设计了一种基于ARM+FPGA的高速图像数据
    发表于 06-02 06:18

    什么是深度学习?使用FPGA进行深度学习的好处?

    方便的进行深度学习的应用。然而,深度学习仍然主要使用 GPU 和 CPU 完成。因此,在这里我们将仔细研究使用 FPGA 进行
    发表于 02-17 16:56

    算法隐含并行性的物理模型

    算法隐含并行性的物理模型:利用物理学原理对算法的隐含并行性进行了分析,提出算法的不确定性和高熵态是隐含并行性出现的根源,但算法的隐含并行性会导致算法结果的不确定
    发表于 10-21 08:23 10次下载

    FPGA深度学习的未来

    FPGA深度学习的未来,学习资料,感兴趣的可以看看。
    发表于 10-26 15:29 0次下载

    FPGA深度学习领域的应用

    本文从硬件加速的视角考察深度学习FPGA,指出有哪些趋势和创新使得这些技术相互匹配,并激发对FPGA如何帮助深度
    的头像 发表于 06-28 17:31 6568次阅读

    FPGA说起深度学习

    这是新的系列教程,在本教程中,我们将介绍使用 FPGA 实现深度学习的技术,深度学习是近年来人工智能领域的热门话题。
    的头像 发表于 03-03 09:52 1162次阅读

    FPGA说起深度学习:任务并行性

    这是新的系列教程,在本教程中,我们将介绍使用 FPGA 实现深度学习的技术,深度学习是近年来人工智能领域的热门话题。
    的头像 发表于 04-12 10:19 597次阅读

    Vitis HLS:使用任务级并行性的高性能设计

    电子发烧友网站提供《Vitis HLS:使用任务级并行性的高性能设计.pdf》资料免费下载
    发表于 09-13 17:21 0次下载
    Vitis HLS:使用任务级<b class='flag-5'>并行性</b>的高性能设计