基於FPGA的卷積神經網路實現(六)資料量化(2)

2021-10-08 07:16:42 字數 3322 閱讀 9369

目錄:

簡介框架

資源分配(1)

資源分配(2)

資料量化(1)

資料量化(2)

資料讀寫

卷積模組

池化、全連線與輸出

上一節我們介紹了如何對乙個離線模型進行簡單的線性量化,這一節我們來說一下如何在pytorch上面訓練乙個量化模型。這一節可能是徹底脫離了fpga實現,想要安心做fpga實現的可以跳過這一節。

首先在pytorch實現有兩種情況,一種是訓練的時候就是用int型別,另一種是訓練的引數進行量化,但是使用float來表示。另外就是在實現過程中,現在的研究大家使用了各種各樣的trick來減小量化帶來的誤差,從而進一步減小bit位寬,這不是我們研究的重點,真要研究起來這個領域也是非常的深奧,這裡我們僅圍繞如何在乙個模型的訓練過程裡面加入量化來展開,就是用第二種方式來做例子。

首先我們先來分析乙個pytorch的卷積類。

class conv2d(_convnd):

def __init__(

self,

in_channels: int,

out_channels: int,

kernel_size: _size_2_t,

stride: _size_2_t = 1,

padding: _size_2_t = 0,

dilation: _size_2_t = 1,

groups: int = 1,

bias: bool = true,

padding_mode: str = 'zeros' # todo: refine this type

):kernel_size = _pair(kernel_size)

stride = _pair(stride)

padding = _pair(padding)

dilation = _pair(dilation)

super(conv2d, self).__init__(

in_channels, out_channels, kernel_size, stride, padding, dilation,

false, _pair(0), groups, bias, padding_mode)

def _conv_forward(self, input, weight):

if self.padding_mode != 'zeros':

return f.conv2d(f.pad(input, self._reversed_padding_repeated_twice, mode=self.padding_mode),

weight, self.bias, self.stride,

_pair(0), self.dilation, self.groups)

return f.conv2d(input, weight, self.bias, self.stride,

self.padding, self.dilation, self.groups)

def forward(self, input: tensor) -> tensor:

return self._conv_forward(input, self.weight)

分析一下這個類首先是__ init__方法,這一方法的作用顧名思義,就是初始化各個引數,比如輸入通道數量,輸出通道數量等(實際上這是乙個python的特性,建立該類物件的時候會使用此初始化函式)。之後的_conv_forward方法是乙個功能方法,也就是描述了這個模組的功能,實際上是呼叫function.py檔案中的conv2d方法。最後forward用於該層全向傳播的。

也就是說我們想要自己構造乙個可用的,那麼也需要三部分函式,乙個初始化方法,乙個(或者一些)功能方法,乙個前向傳播方法。至少從這個類看起來是這樣的。

實際上這是pytorch的乙個特性,在前向傳播的時候會呼叫所有網路中的層的forward方法來進行,因此我們在構建自己的類的時候只需要也同樣的使用forward方法,在網路前向傳播的時候就會自動呼叫。那麼反向傳播呢?事實上,如果我們在自己建立的類繼承nn.conv2d,那麼就可以繼承其反向傳播,來更新weight和bias。因此我們自己建立的類裡面需要有這樣幾個要素:

功能方法,在這個方法裡面實現量化的過程

forward方法,在這個方法裡面實現前向傳播過程

weight和bias變數

繼承nn.conv2d

下面來看這段**(要注意的是這並不是一段可執行的**,因為疫情原因我的程式在學校的電腦上沒法取出來,所以只是寫了乙個模板,後面會對他進行更新):

class dcconv2d(nn.conv2d):

def __init__(self, in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=true):

super(dcconv2d, self).__init__(in_channels, out_channels, kernel_size, stride, padding, dilation, groups, bias)

self.lamda = 2**st

def quan(self,x):

max_data = max(x.abs())

scale = max_quan/max_data

x_q = round(self.x*scale)

return x_q

def forward(self, x):

return f.conv2d(self.quan(x), self.quan(self.weight), self.quan(self.bias), self.stride, self.padding, self.dilation, self.groups)

這樣一來,我們在自己建立的類當中定義了quan這一功能方法,並在forward當中呼叫了f.conv2d方法。而後我們在構建網路的時候使用新的類來取代nn.conv2d就好了。

在計算卷積的時候使用的是量化後的引數和資料,而在更新的時候更新的是self.weight和self.bias,對於我們這個類來說,是更新了沒有量化的引數,另一種方式是使用量化後的引數對self.weight和self.bias進行覆蓋,這樣一來更新的也是量化後的引數,兩種方式的優劣還是各位自行比較,因為有許多優化的方法在裡面,通過對quan這一功能方法進行修改,來得到更優的量化效果。當然這種很簡單沒有優化的方法已經比僅僅對訓練好的模型進行量化並部署效果要好很多了。

還是老話,這個系列的文章主要在於介紹整個流程,適用於入門新手,對於深入的研究,每個點都是乙個很深奧的領域,我的研究點在於模型壓縮,對於量化的方法研究的不是非常的深入,有興趣的同學可以自行深入研究。

基於FPGA的卷積神經網路實現(一)簡介

目錄 簡介框架 資源分配 1 資源分配 2 資料量化 1 資料量化 2 資料讀寫 卷積模組 池化 全連線與輸出 事先宣告,僅用於記錄和討論,有任何問題歡迎批評指正,只是覺得菜的大佬們請繞路,就不用在這裡說大實話了,因為本身就是乙個粗糙的demo。提起把專案 講解一下的念頭主要是源於最近乙個同學開始轉...

基於FPGA的卷積神經網路實現(三)資源分配(1)

目錄 簡介框架 資源分配 1 資源分配 2 資料量化 1 資料量化 2 資料讀寫 卷積模組 池化 全連線與輸出 前面曾經說過這個demo使用最簡單的方法,也就是對每一層都單獨分配資源,所以需要提前設計好每一層所分配的資源數量。這裡的資源主要是指dsp單元和片上儲存資源,cnn的卷積層是計算密集型層,...

卷積神經網路 有趣的卷積神經網路

一 前言 最近一直在研究深度學習,聯想起之前所學,感嘆數學是一門樸素而神奇的科學。f g m1 m2 r 萬有引力描述了宇宙星河運轉的規律,e mc 描述了恆星發光的奧秘,v h d哈勃定律描述了宇宙膨脹的奧秘,自然界的大部分現象和規律都可以用數學函式來描述,也就是可以求得乙個函式。神經網路 簡單又...