背景:实测IPcore在FPGA上运行时,错误语句集中于get_9_weights_to_buffer之中,极有可能是WBRAM尺寸的设定出现了问题。
目的:找出WBRAM尺寸设定的问题,更改代码。
前期工作:
ZynqNet解析(七)实现于BRAM上的Cache https://blog.csdn.net/weixin_36474809/article/details/83860624
卷积函数的FPGA实现(三)加入HLS预编译指令 https://blog.csdn.net/weixin_36474809/article/details/84580456
目录
一、zynqNet的WBRAM的实现
1.1 zynqNet的WBRAM实现方法
1.2 BRAM 32k的尺寸
二、卷积IPcore的尺寸的推断
2.1 已有资源
2.2 总的网络占用
2.3 已有BRAM的实验
三、更改方法
3.1 尺寸的确定
3.2 WBRAM尺寸的确定
3.3 当前WBRAM的地址
3.4 程序之中的更改
3.5 synthesis报告及验证
wegiht_cache.cpp与hpp之中,可能7045的BRAM为BRAM 32k,而我们7035的BRAM为BRAM 18k
其源码尺寸实现为四个维度
data_t WeightsCache::WBRAM[N_PE][NUM_BRAMS_PER_PE][BLOCK_SIZE][9];
// Depth of single BRAM36 in (1K x 32b) configuration
const int BLOCK_SIZE = 1024;
// Number of BRAM36 needed per PE
const int NUM_BRAMS_PER_PE =
(CEIL_DIV(((MAX_WEIGHTS_PER_LAYER) / 8), BLOCK_SIZE) / N_PE);
MAX_WEIGHTS_PER_LAYER为最大的层的weight的bit数目,除以8得到byte数目。
然后除以PE的个数,和block_size的个数即为NUM_BRAMS_PER_PE的个数。
为32k个bit,即32*1024个bit,所以有32kb,即4kB
每个浮点数为4byte,即32bit,所以每个BRAM刚好能存1024个浮点数
由此推算,BRAM 18k能存 512个浮点数。
即 0.5k*32bit=16kb<18kb
BRAM具体尺寸应该查数据手册,但是我们根据目前已有的项目情况和实验推出
BRAM 32k即 32kbit,能存1024个浮点数,
BRAM 18k即18k bit,能存512个浮点数。
我们打出过MTCNN网络最大需要卷积的尺寸。
3*3滤波器的个数最多为16384,即Onet最后一层128*128*3*3的尺寸。128*128=16384
在此尺寸之下,设为8PE并行,则每个PE上需要2048个filter,BRAM 18k显然存不下。
OBRAM设为8个并行,每个BRAM的大小为 MAX_CO /N_PE,OBRAM的最大的输出通道设置为512,每个PE上所存的浮点数为 512/8= 64个。
下表中这样理解,为了更好的并行,每个OBRAM在PE上实现为2个BRAM 18k,每个PE上存64个浮点数,则每个BRAM上面32个浮点数,即每两个BRAM 18k在一个PE上,有64个浮点数(words),每个浮点数(word)占用32bit(4byte*8bit)
关于IBRAM,最初的程序之中最大为3904,现在为8704。(3904的实现,HLS用了8个BRAM来实现)每个BRAM上488个浮点数字。这里,word就被当作了字节。
但是对于WBRAM而言,报告里面生成了64*2个WBRAM 18k.,每两个WBRAM存有了1024个浮点数。
64*1024=65536个浮点数,与预想的权重浮点数 8PE*1024per_PE*9=73728相比少了。WBRAM的内存溢出。
我们需要确定最终需要的尺寸的大小,
// ==========================
// = Architecture Constants =
// ==========================
// Number of Image Cache Lines (need 3, use 4 for simplified Addressing HW)
const int NUM_IMG_CACHE_LINES = 4;
// Number of Processing Elements
const int N_PE = 8;
//1G=268,435,465*sizeof(float) = 1,073,741,824byte=8,589,934,592bit
const int DRAM_DEPTH = 268435465;
//IBRAM, OBRAM, WBRAM size (this value need to be changed by network)
const int MAX_IMAGE_CACHE_SIZE = 8704;
const int MAX_NUM_CHOUT = 128;
//const int MAX_CO_PER_PE=8;
// const int MAX_2D_FILTERS_PER_PE=1024;
const int MAX_2D_FILTERS_PER_PE= 2048;
此尺寸下可以在主程序之中正常运行MTCNN的网络,按照此尺寸构建IPcore。
8N_PE * 2048个filters
多一个维度需要 8 N_PE * 4 BRAMS_PER_FILTERLOC_PER_PE * 512 MAX_FLOAT_SIZE_PER_PE * 9
我们将WBRAM设成此四维实现。
extern float WBRAM[N_PE][BRAMS_PER_FILTERLOC_PER_PE][MAX_FLOAT_SIZE_PER_PE][9];
float WeightsCache::WBRAM[N_PE][BRAMS_PER_FILTERLOC_PER_PE][MAX_FLOAT_SIZE_PER_PE][9];
void WeightsCache::get_WBRAM_addr(const int cur_ci, const int cur_co,
int &PEID, int &BRAM_ID, int &BRAM_loc){
#pragma HLS INLINE
PEID=cur_co%N_PE;
int filterID=(cur_co/N_PE)*inChannelNum+cur_ci;
BRAM_ID=filterID/MAX_FLOAT_SIZE_PER_PE;
BRAM_loc=filterID%MAX_FLOAT_SIZE_PER_PE;
}
WBRAM地址的映射函数如上,所有调用此函数的函数都需要更改。
//get 9 weights from IBRAM to buffer
void WeightsCache::get_9_weights_to_buffer(int cur_ci, int cur_co,float weight_buffer[9]){
#pragma HLS FUNCTION_INSTANTIATE variable = cur_co
#pragma HLS inline
#pragma HLS pipeline
// Array Partitioning
#pragma HLS ARRAY_PARTITION variable = WBRAM complete dim = 1 // PE ID
#pragma HLS ARRAY_PARTITION variable = WBRAM complete dim = 2 // BRAM ID
#pragma HLS ARRAY_PARTITION variable = WBRAM complete dim = 4 // filter loc
#pragma HLS RESOURCE variable = WBRAM core = RAM_S2P_BRAM latency = 3
#pragma HLS ARRAY_PARTITION variable = weight_buffer complete dim = 0
int PEID,BRAM_ID,BRAM_loc;
get_WBRAM_addr(cur_ci,cur_co,PEID,BRAM_ID,BRAM_loc);
for(int i=0;i<9;i++){
weight_buffer[i]=WBRAM[PEID][BRAM_ID][BRAM_loc][i];
}
}
//load weights from DRAM to BRAM
void WeightsCache::load_WBRAM_from_DRAM(volatile float * weight_ptr){
#pragma HLS inline
int PEID,BRAM_ID,BRAM_loc;
float *WBRAM_ptr;volatile float *weight_DRAM_ptr;
for(int cur_co=0;cur_co
程序正确性验证,嵌套入主程序之中验证通过,嵌套入c-simulation验证通过。
WBRAM的个数为[8][4] [512][9]个
分别表示PEID,BRAM_ID, BRAM_loc, filter_loc。
synthesis获得了预想的结果,运行无误。