从FPGA说起的深度学习(六)-任务并行性
这是新的系列教程,在本教程中,我们将介绍使用 FPGA 实现深度学习的技术,深度学习是近年来人工智能领域的热门话题。
在本教程中,旨在加深对深度学习和 FPGA 的理解。
用 C/C++ 编写深度学习推理代码
高级综合 (HLS) 将 C/C++ 代码转换为硬件描述语言
FPGA 运行验证

从这篇文章中,我们将从之前创建的网络模型中提取并行性,并确认处理速度得到了提高。首先,我们检查当前模型的架构,并考虑什么样的并行化是可性的。
并行化方法研究
当前模型架构的框图如下所示。限于篇幅省略了maxpool2d和relu。

在这个模块中,conv1、conv2、fc1、fc2都是作为不同的模块实现的。FPGA内部的SRAM在每一层之间插入一个缓冲区(x', x'', x''' ),这个缓冲区成为每一层的输入和输出。此后,每一层(conv1、conv2、fc1、fc2)被称为一个任务。
顺序处理(基线)
下图显示了使用该模块对 3 帧图像执行推理处理时的执行时间可视化。
每个任务的执行时间以推理模块的实际运行波形为准,是conv2>conv1>fc1>fc2的关系。在该模块中,conv1、conv2、fc1和fc2作为单独的任务实施,但是这些任务一次只能运行一个(后面会解释原因)。因此,如果将conv1、conv2、fc1、fc2各层的执行时间作为最终的执行时间,则这3帧图像的t0, t1, t2, t3处理时间为3 * (t0 + t1 + t2 + t3)

任务并行度
假设我们可以修复这些任务并发运行。这种情况下的执行时间如下所示,多个任务可以同时处理不同的帧。

提取并行性使多个任务可以同时运行,称为任务并行化。在这个过程中,conv2的执行时间占主导地位,所以3帧的处理时间为t0 + 3 * t1 + t2 + t3。
理想的任务并行度
最后,我们考虑可以理想地执行任务并行化的模式。如上所述,如果只提取任务并行性,最慢的任务就会成为瓶颈,整体处理速度会受到该任务性能的限制。因此,最有效的任务并行是所有任务都具有相同的执行时间。

在这种情况下,处理时间t0 + 3 * t1 + t2 + t3保持不变,但t0 = t1 = t2 = t3调整了每个任务的执行时间,从而提高了性能。在本课程中,实现这种加速的技术被称为循环并行化和数据并行化。这两种并行度提取方法将在下一篇文章中介绍。
任务并行化
在本文中,第一个目标是执行任务并行化。
由于这次创建的模块中有多个任务,貌似已经可以并行处理了,但在实际波形中并不是这样。之所以不能并行化,是因为作为x', x'', x'''任务间接口的buffer()不能被多个任务同时使用。对于任务并行化,任务之间的接口必须可以同时被两个或多个任务读写。
在这个模块x'中,任务级并行化是通过在任务之间使用乒乓缓冲区来实现的。乒乓缓冲区有两个缓冲区,一个用于写入,一个用于读取。带有乒乓缓冲器的框图如下所示:

如果以这种方式配置电路,存储 conv1 输出的缓冲区和 conv2 从中读取输入的缓冲区是分开的,因此 conv1 和 conv2 可以同时运行。虽然图中省略了,但所有层都可以通过双缓冲conv2 <-> fc1,fc1 <-> fc2同时操作。
要在 RTL 中实现这一点,准备两个缓冲区并实现切换机制会很麻烦,但在 Vivado/Vitis HLS 中,只需添加一些 pragma 即可实现这种并行化。
代码更改
对于此任务并行化,我们需要添加以下三种类型的编译指示。
#pragma HLS dataflow
#pragma HLS stable
#pragma HLS interface ap_ctrl_chain
在解释每个pragma的作用之前,我先inference_dataflow展示一下新增函数的源代码。与第五篇中的inference_top函数重叠的部分省略。
60 void inference_dataflow(const float x[kMaxSize],61 const float weight0[kMaxSize], const float bias0[kMaxSize],62 const float weight1[kMaxSize], const float bias1[kMaxSize],63 const float weight2[kMaxSize], const float bias2[kMaxSize],64 const float weight3[kMaxSize], const float bias3[kMaxSize],65 float y[kMaxSize]) {66 #pragma HLS dataflow67 #pragma HLS interface m_axi port=x offset=slave bundle=gmem0...76 #pragma HLS interface m_axi port=y offset=slave bundle=gmem977 #pragma HLS interface s_axilite port=x bundle=control...86 #pragma HLS interface s_axilite port=y bundle=control87 #pragma HLS interface s_axilite port=return bundle=control88 #pragma HLS interface ap_ctrl_chain port=return bundle=control8990 #pragma HLS stable variable=x91 #pragma HLS stable variable=weight092 #pragma HLS stable variable=bias093 #pragma HLS stable variable=weight194 #pragma HLS stable variable=bias195 #pragma HLS stable variable=weight296 #pragma HLS stable variable=bias297 #pragma HLS stable variable=weight398 #pragma HLS stable variable=bias399 #pragma HLS stable variable=y
100
101 dnnk::inference(x,
102 weight0, bias0,
103 weight1, bias1,
104 weight2, bias2,
105 weight3, bias3,
106 y);
107 }
第66 行添加#pragma HLS dataflow的 pragma使inference_dataflow这些内部函数之间的接口成为乒乓缓冲区并启用任务并行化。第 101 行调用的函数dnnk::inference是下面的函数,它通过第 20 行的#pragma HLS inline编译指示在函数内inference_dataflow内嵌展开。因此,诸如 conv2d, relu的函数符合任务并行化的条件,它们的接口 ( x1, x2, ...) 是一个乒乓缓冲区。
14 static void inference(const float* x,15 const float* weight0, const float* bias0,16 const float* weight1, const float* bias1,17 const float* weight2, const float* bias2,18 const float* weight3, const float* bias3,19 float* y) {20 #pragma HLS inline...3435 // 1st layer36 conv2d(x, weight0, bias0, kWidths[0], kHeights[0], kChannels[0], kChannels[1], 3, x1);37 relu(x1, kWidths[0] * kHeights[0] * kChannels[1], x2);38 maxpool2d(x2, kWidths[0], kHeights[0], kChannels[1], 2, x3);39...4849 // 4th layer50 linear(x8, weight3, bias3, kChannels[3], kChannels[4], y);51 }
inference_dataflow从函数的第90行#pragma HLS stable开始,在x, weight0, y输入/输出等函数inference_dataflow的入口/出口处自动完成同步。如果不去掉这个同步,两个进程之间就会产生依赖,比如“上一帧y输出完成->下一帧x输入准备好”,多任务就不行了。另请参阅Vivado HLS 官方文档 ( UG902 ),了解有关稳定阵列部分的详细说明。
最后,inference_dataflow该函数第88行的pragma修改了外部寄存器接口,使得#pragma HLS interface ap_ctrl_chain port=return该函数可以用于同时处理多个帧。inference_dataflow如果没有这个 pragma,即使你实现了 ping-pong 缓冲区,主机端也只会尝试一个一个地执行它们,性能不会提高。
综合结果确认
可以在检查综合时检查任务并行化是否顺利进行。
下面是HLS综合结果报告,Latency -> Summary一栏列出了整个函数的延迟和执行间隔(Interval)。在这里,整体延迟仍然是所有任务处理时间的总和,但执行间隔的值conv2d_232_U0与第二个卷积层的执行周期数相匹配。该模块的吞吐量是第二个卷积层执行间隔的倒数。

正如本文开头所解释的,conv2d_232_U0处理时间成为此任务并行化后电路中的瓶颈。任务并行化的速度提升率为947407 / 504898 = 1.88倍。
通过这种方式,我们能够确认 HLS 能够正确实现任务并行化。
总结
在本文中,我们通过提取任务并行性来加速处理。本来conv2占用了一半以上的执行时间,所以提速幅度不到2倍,如果设置为N,最大提速为N倍。
在下一篇文章中,我们将通过对卷积层应用数据并行化和循环并行化来解决每一层处理时间的不平衡。
关注我们
OpenFPGA,与数万打工人共同成长
相关文章:

从FPGA说起的深度学习(六)-任务并行性
这是新的系列教程,在本教程中,我们将介绍使用 FPGA 实现深度学习的技术,深度学习是近年来人工智能领域的热门话题。在本教程中,旨在加深对深度学习和 FPGA 的理解。用 C/C 编写深度学习推理代码高级综合 (HLS) 将 C/C 代码转换为硬…...

5.39 综合案例2.0 - STM32蓝牙遥控小车4(体感控制)
综合案例2.0 - 蓝牙遥控小车4- 体感控制成品展示案例说明器件说明小车连线小车源码遥控手柄遥控器连线遥控器代码1.摇杆PS2模块说明2.六轴MPU-6050说明成品展示 案例说明 用STM32单片机做了一辆蓝牙控制的麦轮小车,分享一下小车的原理和制作过程。 控制部分分为手机…...

Scala之面向对象
目录 Scala包: 基础语法: Scala包的三大作用: 包名的命名规范: 写包的好处: 包对象: 导包说明: 类和对象: 定义类: 封装: 构造器: 主从…...

深度学习目标检测项目实战(四)—基于Tensorflow object detection API的骨折目标检测及其界面运行
深度学习目标检测项目实战(四)—基于Tensorflow object detection API的骨折目标检测及其界面运行 使用tensorflow object detection进行训练检测 参考原始代码:https://github.com/tensorflow/models/tree/master/research 我用的是1.x的版本 所以环境必须有gpu版…...

嵌入式工程师如何快速的阅读datasheet的方法
目录 ▎从项目角度来看datasheet ▎各取所需 ▎最后 Datasheet(数据手册)的快速阅读能力,是每个工程师都应该具备的基本素养。 无论是项目开始阶段的选型还是后续的软硬件设计,到后期的项目调试,经常有工程师对着英…...
(三)合约广告
1. 广告位(CPT)合约 系统:广告排期系统 网站把某一个广告位卖给广告商,这段时间归广告商所有,到点了下线 (1)流量选择的维度:时间段、地域等 (2)典型场景…...

【Android -- 软技能】分享一个学习方法
前言 很多人都想通过学习来提升自己,但是,可能因为两个问题,阻碍了自己的高效提升: 学什么? 怎么学? 本文将从自己的学习实践出发,针对这两个问题,给出自己的一套学习流程。 1…...
Python-DQN代码阅读(10)
目录 1.代码 1.1 代码阅读 1.2 代码分解 1.2.1 f open("experiments/" str(env.spec.id) "/performance.txt", "a") 1.2.2 f.write(str(ep) " " str(time_steps) " " str(episode_rewards) " " str(…...

MongoDB入坑
MongoDB入坑一、体系架构1、简介2、MongoDB VS RDBMS3、文件4、体系结构二、权限管理1、开启2、角色三、存储引擎四、备份 & 恢复五、高可用0、主从复制1、副本集2、分片一、体系架构 1、简介 DBMS No.5;NoSQL Document No.1 1)BSON BSON(Binary …...

【论文总结】针对操作系统级虚拟化的抽象资源攻击
介绍 这是一篇来自2021CCS的论文,作者有Nanzi Yang, Wenbo Shen, Jinku Li, Yutian Yang, Kangjie Lu, Jietao Xiao, Tianyu Zhou, Chenggang Qin, Wang Yu, Jianfeng Ma, Kui Ren。 概述 本文的贡献如下: 新的攻击面:作者揭示了一个影响操…...
C# 提取 PDF 文档中的文本
C# .Net 使用 IText7 从PDF文件中提取出所有文本内容 【文 / 张赐荣】 首先在 Nuget 包管理器中,安装"itext7" 和 "itext7.font-asian"。 如果不安装 "itext7.font-asian" PDF 文件中有非Unicode编码的字符,将会抛出运行时异常:iText.IO.Excep…...

mac如何升级node版本、切换node版本
一、mac如何升级node版本 当前官网稳定版本是18.15.0 所以我从v14.17.4升级到v18.15.0 二、mac如何切换node版本 切换到16.20.0版本 三、这里是用node.js的多版本管理器n来升级和切换的,命令如下: 1、sudo npm cache clean -f //清除node.js的cache …...
一位大专学历的女程序员要求月薪25K,学历重要吗?来看看面试过程
“请提供一份完整的简历,以便我审查。从您的简历中,我感觉您写得还不错。方便的话,您可以自我简单介绍一下吗?“ ”好的,我叫李娟,拥有大专学位,目前正在寻找一份Java开发架构师的工作岗位。“…...

ESP32驱动1.28寸GC9A01播放视频(一、视频分辨率的调整和视频格式的转换)
ESP32驱动1.28寸GC9A01播放视频(一、视频分辨率的调整和视频格式的转换)播放前准备转换视频分辨率用FFmpeg将.MP4转换为.mjpeg格式FFmpeg的win10环境搭建FFmpeg的下载环境变量的搭建MP4转换成mjpeg格式总结播放前准备 1.28寸GC9A01屏幕的分辨率是240x24…...

epoll的LT模式(水平触发)和ET模式(边沿触发)
前言 epoll的触发模式是个引发讨论非常多的话题,网络上这方面总结的文章也很多,首先从名字上就不是很统一,LT模式常被称为水平触发、电平触发、条件触发,而ET模式常被称为边缘触发、边沿触发等,这些都是从英文翻译过来…...
Java基础面试20题
Java的八大基本数据类型 答:可以分4种类型:布尔类型(boolean),字符类型(char),浮点类型(double,float),整型(byte,short,int, long)。 String,StringBuffer与StringBuilder的区别? …...
Java面向对象封装
目录 封装的概念 封装具体实现步骤 示例代码如下 封装具体语法 封装的概念 Java封装是一种面向对象的编程方法,它的主要思想是将类的内部细节(包括数据和方法)隐藏起来,对外只提供公共的访问接口,从而保证了程序的安全性和稳定性。 封装具体实现步骤 1、声明类的成…...

队列实现图书信息管理(C语言)
文章目录Queue.hmain.cQueue.c用队列实现一个图书信息管理,这里放一下有哪些文件。(ps:我之前写的是学生信息管理,但是有人说我们的作业是写图书,就该了下内容,没有改文件名)队列是用链表实现的…...

Java开发 - 读写分离初体验
前言 上一篇中,我们介绍了主从复制,相信学过的小伙伴已经能够很好的掌握主从复制的技术,实际上也并没有那么难,虽然没有讲一主多从,多主多从的配置,但是从一主一从的配置中也很容易联想到该怎么配置&#…...

图文详解CAN Log文件 - ASC文件格式
目录 1 CAN Log文件 -- ASC文件格式 1.1 Header 1.2 版本编号 1.3 经典CAN网络中的描述 1.3.1 经典CAN Standard标准帧的描述 1.3.2 经典CAN Extended扩展帧的描述 1.3.3 CAN Remote远程帧的描述 1.3.4 CAN Error错误帧的描述 1.4 CANFD网络中的描述 1.4.1 经典CAN S…...

第19节 Node.js Express 框架
Express 是一个为Node.js设计的web开发框架,它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用,和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...
Vue记事本应用实现教程
文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展:显示创建时间8. 功能扩展:记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...

css实现圆环展示百分比,根据值动态展示所占比例
代码如下 <view class""><view class"circle-chart"><view v-if"!!num" class"pie-item" :style"{background: conic-gradient(var(--one-color) 0%,#E9E6F1 ${num}%),}"></view><view v-else …...

Python:操作 Excel 折叠
💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Python 操作 Excel 系列 读取单元格数据按行写入设置行高和列宽自动调整行高和列宽水平…...

Docker 运行 Kafka 带 SASL 认证教程
Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明:server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...

基于Flask实现的医疗保险欺诈识别监测模型
基于Flask实现的医疗保险欺诈识别监测模型 项目截图 项目简介 社会医疗保险是国家通过立法形式强制实施,由雇主和个人按一定比例缴纳保险费,建立社会医疗保险基金,支付雇员医疗费用的一种医疗保险制度, 它是促进社会文明和进步的…...

对WWDC 2025 Keynote 内容的预测
借助我们以往对苹果公司发展路径的深入研究经验,以及大语言模型的分析能力,我们系统梳理了多年来苹果 WWDC 主题演讲的规律。在 WWDC 2025 即将揭幕之际,我们让 ChatGPT 对今年的 Keynote 内容进行了一个初步预测,聊作存档。等到明…...

HBuilderX安装(uni-app和小程序开发)
下载HBuilderX 访问官方网站:https://www.dcloud.io/hbuilderx.html 根据您的操作系统选择合适版本: Windows版(推荐下载标准版) Windows系统安装步骤 运行安装程序: 双击下载的.exe安装文件 如果出现安全提示&…...
聊一聊接口测试的意义有哪些?
目录 一、隔离性 & 早期测试 二、保障系统集成质量 三、验证业务逻辑的核心层 四、提升测试效率与覆盖度 五、系统稳定性的守护者 六、驱动团队协作与契约管理 七、性能与扩展性的前置评估 八、持续交付的核心支撑 接口测试的意义可以从四个维度展开,首…...

SAP学习笔记 - 开发26 - 前端Fiori开发 OData V2 和 V4 的差异 (Deepseek整理)
上一章用到了V2 的概念,其实 Fiori当中还有 V4,咱们这一章来总结一下 V2 和 V4。 SAP学习笔记 - 开发25 - 前端Fiori开发 Remote OData Service(使用远端Odata服务),代理中间件(ui5-middleware-simpleproxy)-CSDN博客…...