国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

基于FPGA的VGG16卷積神經(jīng)網(wǎng)絡(luò)加速器

這篇具有很好參考價(jià)值的文章主要介紹了基于FPGA的VGG16卷積神經(jīng)網(wǎng)絡(luò)加速器。希望對大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

文章搬運(yùn)自本人知乎

VGG16網(wǎng)絡(luò)結(jié)構(gòu)介紹

基于FPGA的VGG16卷積神經(jīng)網(wǎng)絡(luò)加速器
VGG在2014年由牛津大學(xué)Visual GeometryGroup提出,獲得該年lmageNet競賽中Localization Task(定位任務(wù))第一名和 Classification Task (分類任務(wù))第二名。與AlexNet相比,VGG使用了3個(gè)3x3卷積核來代替7x7卷積核,使用了2個(gè)3x3卷積核來代替5x5卷積核,從而在保證具有相同感知野的條件下,提升了網(wǎng)絡(luò)的深度,在一定程度上提升了神經(jīng)網(wǎng)絡(luò)的效果。下表中,C即為VGG16的網(wǎng)絡(luò)結(jié)構(gòu),其中,VGG16中的16是指該網(wǎng)絡(luò)具有16個(gè)包含權(quán)重的網(wǎng)絡(luò)層(卷積層和全連接層)。更具體地,VGG16由13個(gè)卷積層和3個(gè)全連接層構(gòu)成,此外,VGG16還包含了5個(gè)2×2的最大池化層。
基于FPGA的VGG16卷積神經(jīng)網(wǎng)絡(luò)加速器
在原始的VGG16模型中,并未包含批歸一化層(Batch Normalization,BN),這給VGG16的訓(xùn)練帶來了難度。因此,在本文中,我們對VGG16進(jìn)行了一些修改,如下所示:

  1. 在每一層卷積層后都加上批歸一化層(BN層)。
  2. 將三個(gè)全連接層替換為一個(gè)全局平均池化層和一個(gè)全連接層。

修改后的網(wǎng)絡(luò)結(jié)構(gòu)可由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融合

在模型訓(xùn)練完畢后,我們對卷積層和BN層的權(quán)重進(jìn)行了BN融合操作,其原理也十分簡單。由于該操作十分常見,因此本文不再贅述,詳細(xì)可見博客。

基于FPGA的加速器設(shè)計(jì)

由于VGG16的絕大部分計(jì)算量均集中在卷積層,因此,我們僅設(shè)計(jì)針對卷積的硬件加速IP核。此外,考慮到卷積層后有時(shí)會緊接著一個(gè)池化層,因此,如需要進(jìn)行池化操作,則該硬件加速IP會在卷積完成后立即進(jìn)行池化操作,然后再寫回片外存儲器。這樣做的好處是省去了不必要的片外訪存開銷,既降低了延遲又減少了功耗開銷。

加速器的設(shè)計(jì)是平凡的,主要采用的優(yōu)化方法包括:

循環(huán)分片(loop tiling):對卷積層輸出特征圖的高、寬以及卷積的輸出和輸入通道進(jìn)行了分塊操作,分塊大小分別記為 T r T_r Tr?, T c T_c Tc?, T m T_m Tm?, T n T_n Tn?,目前其值分別取為14,14,4,48。

定點(diǎn)數(shù)量化:將32位浮點(diǎn)數(shù)量化為了16位的定點(diǎn)數(shù),其中,小數(shù)部分占10位,整數(shù)部分占6位,最高位為符號位。在HLS代碼中,該數(shù)據(jù)類型可以表示為ap_fixed<16,6,AP_RND,AP_SAT>。實(shí)驗(yàn)表明,16位定點(diǎn)數(shù)量化顯著減少了加速器的硬件資源消耗(包括存儲資源BRAM以及計(jì)算資源DSP),同時(shí)較好地保持了模型精度。(1個(gè)32位浮點(diǎn)數(shù)乘法需要消耗3個(gè)DSP48E1,而1個(gè)16位定點(diǎn)數(shù)乘法僅需消耗1個(gè)DSP48E1)

流水線:可以有效提升加速器的吞吐率。在HLS中可以簡單的通過#pragma HLS PIPELINE II=1實(shí)現(xiàn)。

循環(huán)展開:所謂循環(huán)展開,體現(xiàn)在硬件層面,就是復(fù)制多個(gè)運(yùn)算單元,并行執(zhí)行循環(huán)中所需的運(yùn)算。在本文中,我們在卷積層的輸入和輸出通道進(jìn)行了展開,展開的大小等于分塊的大小,即 P m = T m P_m=T_m Pm?=Tm?, P n = T n P_n=T_n Pn?=Tn?。在HLS中,循環(huán)展開可以通過#pragma HLS UNROLL實(shí)現(xiàn)。

乒乓操作:乒乓操作是一個(gè)常常應(yīng)用于數(shù)據(jù)流控制的設(shè)計(jì)思想,典型的乒乓操作如下圖所示,其處理流程為:輸入數(shù)據(jù)流通過“輸入數(shù)據(jù)選擇單元”將數(shù)據(jù)流等時(shí)分配到兩個(gè)“數(shù)據(jù)緩沖模塊”, 數(shù)據(jù)緩沖模塊可以為任何存儲模塊,比較常用的存儲單元為雙口RAM (DPRAM)、單口RAM (SPRAM)、FIFO等。 在第2個(gè)緩沖周期, 通過“輸入數(shù)據(jù)選擇單元”的切換,將輸入的數(shù)據(jù)流緩存到“數(shù)據(jù)緩沖模塊2”,同時(shí)將“數(shù)據(jù)緩沖模塊1”緩存的第1個(gè)周期數(shù)據(jù)通過“輸出數(shù)據(jù)選擇單元”的選擇,送到“數(shù)據(jù)流運(yùn)算處理模塊”進(jìn)行運(yùn)算處理。事實(shí)上,乒乓操作是一種粗粒度的流水線技術(shù),它以硬件資源(或面積)為代價(jià),提升了系統(tǒng)整體的吞吐率。
基于FPGA的VGG16卷積神經(jīng)網(wǎng)絡(luò)加速器

PS部分設(shè)計(jì)

HLS代碼編寫完畢后,可以通過C仿真、C/RTL協(xié)同仿真驗(yàn)證其正確性,然后通過C綜合將它轉(zhuǎn)化為RTL代碼,最后導(dǎo)出為Vivado可用的IP核。在Vivado中,我們將該IP核與ZYNQ IP核通過AXI總線連接在一起,然后綜合、實(shí)現(xiàn)、生成比特流文件。

上述步驟完畢后,我們便可以在Vitis中編寫C/C++代碼,通過調(diào)用掛載在ZYNQ上的加速器,實(shí)現(xiàn)對VGG16網(wǎng)絡(luò)的加速。如下代碼展示了如何在PS上調(diào)用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函數(shù)用于初始化加速器,而conv_and_pool_pl函數(shù)用于調(diào)用加速器進(jìn)行計(jì)算,其參數(shù)的含義解釋如下:

in: 輸入特征圖在DDR中的的起始地址。

weight: 權(quán)重在DDR中的起始地址。

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

out: 輸出特征圖在DDR中的起始地址。

ch_in: 卷積的輸入通道數(shù)。

ch_out: 卷積的輸出通道數(shù)。

h: 輸入特征圖的高度。

w: 輸入特征圖的寬度。

pool: 是否進(jìn)行池化操作,為1表示需要進(jìn)行池化操作,為0則表示無需進(jìn)行池化操作。

上述兩個(gè)函數(shù)中用到的驅(qū)動(dòng)函數(shù)可在頭文件xstd_conv.h中查詢(如下圖),這些驅(qū)動(dòng)函數(shù)是由HLS工具自動(dòng)生成的,可以大大簡化程序員調(diào)用加速器的難度。
基于FPGA的VGG16卷積神經(jīng)網(wǎng)絡(luò)加速器

結(jié)果

實(shí)驗(yàn)的硬件平臺為zynq7020開發(fā)板(xc7z020clg400-2),所用的vivado版本為2019.2。硬件加速器的資源、功耗情況(時(shí)鐘頻率130MHz)如下圖所示。
基于FPGA的VGG16卷積神經(jīng)網(wǎng)絡(luò)加速器
由圖可知,加速器的片上功耗為2.939W,共消耗了35874個(gè)LUTs,40766個(gè)FF以及220個(gè)DSP。可見,加速器的規(guī)模主要受限于DSP的數(shù)目(zynq7020的DSP總數(shù)僅為220個(gè))。

推理測試

基于FPGA的VGG16卷積神經(jīng)網(wǎng)絡(luò)加速器
共測試了100張圖片,精度為0.95,總共耗時(shí)約74000000us,故單張圖片的推理延遲為0.74s,考慮到VGG16的計(jì)算量為15.5GMACs(15.5G乘累加操作),如果將一次乘累加操作算作2次運(yùn)算,則VGG16的GOPs為31GOPs,因此,加速器的吞吐率為31/0.74=41.9GOP/s。

(CNN計(jì)算量的計(jì)算方法可以參見博客)

附:整個(gè)工程有償出售(包括Python代碼,HLS代碼以及Vitis代碼),若有意向可私聊。文章來源地址http://www.zghlxwxcb.cn/news/detail-461487.html

到了這里,關(guān)于基于FPGA的VGG16卷積神經(jīng)網(wǎng)絡(luò)加速器的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包