基于FPGA的VGG16卷积神经网络加速器

news2024/11/19 23:15:04

文章搬运自本人知乎

VGG16网络结构介绍

在这里插入图片描述
VGG在2014年由牛津大学Visual GeometryGroup提出,获得该年lmageNet竞赛中Localization Task(定位任务)第一名和 Classification Task (分类任务)第二名。与AlexNet相比,VGG使用了3个3x3卷积核来代替7x7卷积核,使用了2个3x3卷积核来代替5x5卷积核,从而在保证具有相同感知野的条件下,提升了网络的深度,在一定程度上提升了神经网络的效果。下表中,C即为VGG16的网络结构,其中,VGG16中的16是指该网络具有16个包含权重的网络层(卷积层和全连接层)。更具体地,VGG16由13个卷积层和3个全连接层构成,此外,VGG16还包含了5个2×2的最大池化层。
在这里插入图片描述
在原始的VGG16模型中,并未包含批归一化层(Batch Normalization,BN),这给VGG16的训练带来了难度。因此,在本文中,我们对VGG16进行了一些修改,如下所示:

  1. 在每一层卷积层后都加上批归一化层(BN层)。
  2. 将三个全连接层替换为一个全局平均池化层和一个全连接层。

修改后的网络结构可由pytorch代码描述如下:

import torch
import torch.nn as nn
# VGG16
class VGG16(nn.Module):
    def __init__(self):
        super(VGG16, self).__init__()
        # 特征提取层
        self.features = nn.Sequential(
            nn.Conv2d(in_channels=3,out_channels=64,kernel_size=3,stride=1,padding=1),
            nn.BatchNorm2d(num_features=64),
            nn.ReLU(),
            nn.Conv2d(in_channels=64,out_channels=64,kernel_size=3,stride=1,padding=1),
            nn.BatchNorm2d(num_features=64),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2,stride=2),

            nn.Conv2d(in_channels=64, out_channels=128, kernel_size=3, stride=1, padding=1),
            nn.BatchNorm2d(num_features=128),
            nn.ReLU(),
            nn.Conv2d(in_channels=128, out_channels=128, kernel_size=3, stride=1, padding=1),
            nn.BatchNorm2d(num_features=128),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2, stride=2),

            nn.Conv2d(in_channels=128, out_channels=256, kernel_size=3, stride=1, padding=1),
            nn.BatchNorm2d(num_features=256),
            nn.ReLU(),
            nn.Conv2d(in_channels=256, out_channels=256, kernel_size=3, stride=1, padding=1),
            nn.BatchNorm2d(num_features=256),
            nn.ReLU(),
            nn.Conv2d(in_channels=256, out_channels=256, kernel_size=3, stride=1, padding=1),
            nn.BatchNorm2d(num_features=256),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2,stride=2),

            nn.Conv2d(in_channels=256, out_channels=512, kernel_size=3, stride=1, padding=1),
            nn.BatchNorm2d(num_features=512),
            nn.ReLU(),
            nn.Conv2d(in_channels=512, out_channels=512, kernel_size=3, stride=1, padding=1),
            nn.BatchNorm2d(num_features=512),
            nn.ReLU(),
            nn.Conv2d(in_channels=512, out_channels=512, kernel_size=3, stride=1, padding=1),
            nn.BatchNorm2d(num_features=512),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2, stride=2),

            nn.Conv2d(in_channels=512, out_channels=512, kernel_size=3, stride=1, padding=1),
            nn.BatchNorm2d(num_features=512),
            nn.ReLU(),
            nn.Conv2d(in_channels=512, out_channels=512, kernel_size=3, stride=1, padding=1),
            nn.BatchNorm2d(num_features=512),
            nn.ReLU(),
            nn.Conv2d(in_channels=512, out_channels=512, kernel_size=3, stride=1, padding=1),
            nn.BatchNorm2d(num_features=512),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2, stride=2),
        )
        #
        self.pool = nn.AdaptiveAvgPool2d((1, 1))
        self.fc = nn.Linear(in_features=512,out_features=5)

    def forward(self,x):
        x = self.features(x)
        x = self.pool(x)
        x = x.view(x.size(0),-1)
        result = self.fc(x)
        return result

if __name__=='__main__':
    net=VGG16()
    x=torch.randn(1,3,224,224)
    print(net(x).size())

卷积BN融合

在模型训练完毕后,我们对卷积层和BN层的权重进行了BN融合操作,其原理也十分简单。由于该操作十分常见,因此本文不再赘述,详细可见博客。

基于FPGA的加速器设计

由于VGG16的绝大部分计算量均集中在卷积层,因此,我们仅设计针对卷积的硬件加速IP核。此外,考虑到卷积层后有时会紧接着一个池化层,因此,如需要进行池化操作,则该硬件加速IP会在卷积完成后立即进行池化操作,然后再写回片外存储器。这样做的好处是省去了不必要的片外访存开销,既降低了延迟又减少了功耗开销。

加速器的设计是平凡的,主要采用的优化方法包括:

循环分片(loop tiling):对卷积层输出特征图的高、宽以及卷积的输出和输入通道进行了分块操作,分块大小分别记为 T r T_r Tr, T c T_c Tc, T m T_m Tm, T n T_n Tn,目前其值分别取为1414448

定点数量化:将32位浮点数量化为了16位的定点数,其中,小数部分占10位,整数部分占6位,最高位为符号位。在HLS代码中,该数据类型可以表示为ap_fixed<16,6,AP_RND,AP_SAT>。实验表明,16位定点数量化显著减少了加速器的硬件资源消耗(包括存储资源BRAM以及计算资源DSP),同时较好地保持了模型精度。(1个32位浮点数乘法需要消耗3个DSP48E1,而1个16位定点数乘法仅需消耗1个DSP48E1)

流水线:可以有效提升加速器的吞吐率。在HLS中可以简单的通过#pragma HLS PIPELINE II=1实现。

循环展开:所谓循环展开,体现在硬件层面,就是复制多个运算单元,并行执行循环中所需的运算。在本文中,我们在卷积层的输入和输出通道进行了展开,展开的大小等于分块的大小,即 P m = T m P_m=T_m Pm=Tm, P n = T n P_n=T_n Pn=Tn。在HLS中,循环展开可以通过#pragma HLS UNROLL实现。

乒乓操作:乒乓操作是一个常常应用于数据流控制的设计思想,典型的乒乓操作如下图所示,其处理流程为:输入数据流通过“输入数据选择单元”将数据流等时分配到两个“数据缓冲模块”, 数据缓冲模块可以为任何存储模块,比较常用的存储单元为双口RAM (DPRAM)、单口RAM (SPRAM)、FIFO等。 在第2个缓冲周期, 通过“输入数据选择单元”的切换,将输入的数据流缓存到“数据缓冲模块2”,同时将“数据缓冲模块1”缓存的第1个周期数据通过“输出数据选择单元”的选择,送到“数据流运算处理模块”进行运算处理。事实上,乒乓操作是一种粗粒度的流水线技术,它以硬件资源(或面积)为代价,提升了系统整体的吞吐率。
在这里插入图片描述

PS部分设计

HLS代码编写完毕后,可以通过C仿真、C/RTL协同仿真验证其正确性,然后通过C综合将它转化为RTL代码,最后导出为Vivado可用的IP核。在Vivado中,我们将该IP核与ZYNQ IP核通过AXI总线连接在一起,然后综合、实现、生成比特流文件。

上述步骤完毕后,我们便可以在Vitis中编写C/C++代码,通过调用挂载在ZYNQ上的加速器,实现对VGG16网络的加速。如下代码展示了如何在PS上调用FPGA部分的加速器。

void conv_and_pool_init(){
	XStd_conv_Initialize(&hls_inst, 0);
}

void conv_and_pool_pl(short* in,short* weight,short* bias,short* out,int ch_in,int ch_out,int h,int w,int pool){
	//Xil_DCacheFlushRange((u32)in,ch_in*h*w*sizeof(short));
	XStd_conv_Set_in1_V(&hls_inst, (u32)in);
	XStd_conv_Set_in2_V(&hls_inst, (u32)in);
	XStd_conv_Set_in3_V(&hls_inst, (u32)in);
	XStd_conv_Set_in4_V(&hls_inst, (u32)in);
	//
	XStd_conv_Set_w1_V(&hls_inst, (u32)weight);
	XStd_conv_Set_w2_V(&hls_inst, (u32)weight);
	XStd_conv_Set_w3_V(&hls_inst, (u32)weight);
	XStd_conv_Set_w4_V(&hls_inst, (u32)weight);
	//
	XStd_conv_Set_bias_V(&hls_inst, (u32)bias);
	XStd_conv_Set_out1_V(&hls_inst, (u32)out);
	XStd_conv_Set_out2_V(&hls_inst, (u32)out);
    XStd_conv_Set_out3_V(&hls_inst, (u32)out);
	XStd_conv_Set_out4_V(&hls_inst, (u32)out);
	//
    XStd_conv_Set_ch_in(&hls_inst, (u32)ch_in);
	XStd_conv_Set_ch_out(&hls_inst, (u32)ch_out);
	XStd_conv_Set_fm_size(&hls_inst, (u32)h);
	XStd_conv_Set_pool(&hls_inst, (u32)pool);
	XStd_conv_Start(&hls_inst);
	while(XStd_conv_IsDone(&hls_inst)==0);
	//if(pool==1)
	// 	Xil_DCacheInvalidateRange((u32)((unsigned int)out&0xffffffe0), 32*((ch_out*h*w/4*sizeof(short))/32+2));
	//else
    //    Xil_DCacheInvalidateRange((u32)((unsigned int)out&0xffffffe0), 32*((ch_out*h*w*sizeof(short))/32+2));
}

其中,conv_and_pool_init函数用于初始化加速器,而conv_and_pool_pl函数用于调用加速器进行计算,其参数的含义解释如下:

in: 输入特征图在DDR中的的起始地址。

weight: 权重在DDR中的起始地址。

bias: 偏置在DDR中的起始地址。

out: 输出特征图在DDR中的起始地址。

ch_in: 卷积的输入通道数。

ch_out: 卷积的输出通道数。

h: 输入特征图的高度。

w: 输入特征图的宽度。

pool: 是否进行池化操作,为1表示需要进行池化操作,为0则表示无需进行池化操作。

上述两个函数中用到的驱动函数可在头文件xstd_conv.h中查询(如下图),这些驱动函数是由HLS工具自动生成的,可以大大简化程序员调用加速器的难度。
在这里插入图片描述

结果

实验的硬件平台为zynq7020开发板(xc7z020clg400-2),所用的vivado版本为2019.2。硬件加速器的资源、功耗情况(时钟频率130MHz)如下图所示。
在这里插入图片描述
由图可知,加速器的片上功耗为2.939W,共消耗了35874个LUTs,40766个FF以及220个DSP。可见,加速器的规模主要受限于DSP的数目(zynq7020的DSP总数仅为220个)。

推理测试

在这里插入图片描述
共测试了100张图片,精度为0.95,总共耗时约74000000us,故单张图片的推理延迟为0.74s,考虑到VGG16的计算量为15.5GMACs(15.5G乘累加操作),如果将一次乘累加操作算作2次运算,则VGG16的GOPs为31GOPs,因此,加速器的吞吐率为31/0.74=41.9GOP/s。

(CNN计算量的计算方法可以参见博客)

附:整个工程有偿出售(包括Python代码,HLS代码以及Vitis代码),若有意向可私聊。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/516772.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

全景丨0基础学习VR全景制作,平台篇第22章:热点功能-导航

大家好&#xff0c;欢迎观看蛙色VR官方——后台使用系列课程&#xff01; 功能说明 应用场景 热点&#xff0c;指在全景作品中添加各种类型图标的按钮&#xff0c;引导用户通过按钮产生更多的交互&#xff0c;增加用户的多元化体验。 导航热点&#xff0c;标注具体位置&…

远程访问ERP - 在外远程登录公司局域网金蝶云ERP管理系统

文章目录 前言1.金蝶安装简介2. 安装cpolar内网穿透3. 创建安全隧道映射4. 在外远程访问金蝶云星空管理中心5. 固定访问地址6. 配置固定公网访问地址7.创建数据中心简介8.远程访问数据中心9. 固定远程访问数据中心地址10. 配置固定公网访问地址 前言 金蝶云星空聚焦多组织&…

反病毒技术介绍与发展

1.1 计算机病毒概念 计算机病毒&#xff08;Computer Virus&#xff09;是指编制者在计算机程序中插入的破坏计算机功能或者破坏数据&#xff0c;影响计算机使用并且能够自我复制的一组计算机指令或者程序代码。这是目前对于计算机病毒最通用的定义。计算病毒、蠕虫以及木马是…

Hortic Res | 中国计量大学徐沛组开发了用于促进难转化豆类蔬菜功能基因组学研究的分子工具包

以下文章来源于园艺研究 &#xff0c;作者吴昕扬 园艺研究. 《园艺研究》&#xff08;Horticulture Research&#xff09;是南京农业大学主办的英文学术期刊&#xff0c;采用开放获取形式&#xff0c;专注刊载和园艺作物有关&#xff0c;能引起广泛的国际和学科兴趣的基础和理…

2023 年第八届数维杯大学生数学建模挑战赛 B 题详细思路 节能列车运行控制优化策略

一种可能的建模方法是基于列车的动力学方程和阻力方程&#xff0c;将列车视为单质点&#xff0c;忽略车厢间的车钩力和速度差。根据给定的参数&#xff0c;可以建立如下的方程&#xff1a; $$m(p1)\frac{dv}{dt}F-f(v)-g(i)$$ $$f(v)2.08950.0098v0.006v^2$$ $$g(i)mgi$$ 其…

NAT是如何工作的?

广域网是由很多的局域网组成的&#xff0c;比如公司网络、家庭网络、校园网络等。我们到微观层面&#xff0c;看看局域网是如何工作的。IPv4 的地址不够&#xff0c;因此需要设计子网。当一个公司申请得到一个公网 IP 后&#xff0c;会在自己的公司内部设计一个局域网。这个局域…

8自由度串联四足机器人实现前进功能

1. 功能说明 本文示例将实现R253样机8自由度串联四足机器人前进的功能&#xff0c;该机构是由4个 2自由度串联仿生腿 组成。 2. 串联关节型机器人运动算法 8自由度串联四足机器人的前进步态是将机器人四足分成两组腿&#xff08;身体一侧的前足与另一侧的后足&#xff09;分别进…

集群时间同步

集群时间同步 时间同步的方式&#xff1a;找一个机器&#xff0c;作为时间服务器&#xff0c;所有的机器与这台集群时间进行定时的同步&#xff0c;比如&#xff0c;每隔十分钟&#xff0c;同步一次时间。 1.配置时间同步具体实操&#xff1a; 1.1&#xff09;时间服务器配…

中国20强(上市)游戏公司2022年财报分析:营收结构优化,市场竞争进入白热化

易观&#xff1a;受全球经济增速下行的消极影响&#xff0c;2022年国内外游戏市场规模普遍下滑。但中国游戏公司凭借处于全球领先水平的研发、发行和运营的能力与经验&#xff0c;继续加大海外市场布局&#xff0c;推动高质量发展迈上新台阶。 风险提示&#xff1a;本文内容仅代…

lvm分区扩容

1.前言 此试验对root目录扩容20GB&#xff0c;使用lvm模式扩容&#xff0c;需要先声明&#xff0c;搭建centos主机的时候要把分区模式改成lvm模式&#xff0c;这样后期扩容的时候就比较好处理&#xff0c;如果使用了默认的part模式的话&#xff0c;扩容分区需要将数据先迁移备…

k8s架构了解

Kubernetes(k8s)是用于自动部署、扩展和管理“容器化应用程序”的开源系统 k8s由control plane以及cluster nodes构成 control plane control plane是维护所有k8s对象记录的系统&#xff0c;持续管理着对象状态&#xff0c;并且对集群的变化做出响应&#xff0c;并使状态匹…

2022年美国大学生数学建模竞赛B题水和水力发电分配解题全过程文档及程序

2022年美国大学生数学建模竞赛 B题 水和水力发电分配 原题再现&#xff1a; 背景:   几个世纪以来&#xff0c;人们在河流和溪流.上修建水坝来蓄水建造水库&#xff0c;以此作为管理供水的方式。这些水库储存各种用途的水(如农业、工业、住宅)&#xff0c;提供休闲和娱乐场…

git可视化管理工具SourceTree安装教程

一、背景 本文主要写给&#xff0c;不熟悉git命令或者不喜欢使用git命令的开发者使用&#xff0c;SourceTree可视化见面可以清晰操作git,管理项目方便&#xff0c;可追溯代码编写者及日期。轻松完成项目的dev、sit、线上环境代码管理与合并。无需使用git命令&#xff0c;彻底释…

北京筑龙参编的《国有企业采购操作规范(2023版)》发布

近日&#xff0c;中国物流与采购联合会发布《国有企业采购操作规范&#xff08;2023版&#xff09;》团体标准&#xff0c;北京筑龙作为起草单位之一参与编写。新版团体标准为国有企业编制采购管理制度、规范采购行为提供了参照和依据&#xff0c;有助于进一步提高国企采购的规…

【腾讯云 Finops Crane 集训营】深入了解 Crane 开源项目,集训营实验操作指南,体验过程总结

前言 最近有幸参与了腾讯云举办的Finops Crane的集训营。在这个过程中&#xff0c;老师认真指导&#xff0c;让我受益非浅&#xff0c;也让我真正理解了这一产品所带来的意义。 在听了老师们的介绍和讲解后&#xff0c;我马不停蹄地开始了自己摸索。首先是跟着视频和官方教程…

7.100ASK_V853-PRO开发板支持人形检测和人脸识别

1.前言 ​ V853 芯片内置一颗 NPU核&#xff0c;其处理性能为最大 1 TOPS 并有 128KB 内部高速缓存用于高速数据交换&#xff0c;支持 OpenCL、OpenVX、android NN 与 ONNX 的 API 调用&#xff0c;同时也支持导入大量常用的深度学习模型。本章提供一个例程&#xff0c;展示如…

银医一站式服务终端

01 发卡/充值/挂号业务 ●发卡就诊 ●预约挂号 ●当日挂号 ●自助充值 ●医保关联 ●预约取号 ●现金充值 ●核酸预约 02 打印业务 ●打印检验报告 ●打印检查报告 ●打印费用清单 ●打印病历报告 ●打印住院病历 ●打印检验条码 03 缴费结算业务 ●支付宝支付…

AttributeError: module ‘lib‘ has no attribute ‘X509_V_FLAG_CB_ISSUER_CHECK‘

terminal运行报错AttributeError: module lib has no attribute X509_V_FLAG_CB_ISSUER_CHECK 解决&#xff1a; pip install pyOpenSSL --upgrade

Log4j2远程命令执行(CVE-2021-44228)

漏洞原理 该漏洞是由于&#xff0c;在JNDI客户端的lookup()函数参数外部可控或Reference类构造方法的classFactoryLocation参数外部可控时&#xff0c;会使用户的JNDI客户端访问RMI注册表中绑定的恶意Reference类&#xff0c;从而加载远程服务器上的恶意class文件在客户端本地…

实现微信打开App功能

效果 要求 文档 开发标签文档 android接入指南 android实现 1.接入openSDK dependencies { api ‘com.tencent.mm.opensdk:wechat-sdk-android:6.8.0’ } 2.注册 需要在包名为&#xff08;applicationId&#xff09;wxapi的包下加入以上几个类。 类名功能AppRegister是一…