报名编号:CICC2469
团队名称:AM
学校名称:广东工业大学
队伍成员:林贤、刘合明、谢泽铭
指导老师:郑欣、高怀恩
环境:Vivado2021.1、NucleiStudio_IDE_202102-win64
内容:从零开始利用NMSIS库搭建神经网络,这一节主讲基本的NMSIS库卷积函数的解读。
一、自测检查
利用NMSIS库之前,先利用简单的加减乘除测试下仿真输出情况是否正确,要先确保自己的整个仿真过程正确无误,才能去debug自己设计的NN是否正确。测试的仿真代码可以先定好,自己想要实现的功能的位宽,这里测试的是32bit和64bit的例子:
#include
#include "hbird_sdk_soc.h"
int main(void)
{
// define 16bit input
int16_t input_data_A;
int16_t input_data_B;
// 32bit input
int32_t input_data_C;
int32_t input_data_D;
// 32bit
int32_t output_data_sum32; // +
// 64bit
int64_t output_data_sum64; // +
// initial
// printf function
printf("%d\n", output_data_sum32);
return 0;
}
这里只展示了代码的思路,具体操作很简单,按照自己的想法去设计测试代码,然后进行build,生成.Verilog代码文件之后,用该文件来进行仿真即可。
二、代码解读与实践
按照官方给出的NMSIS库,我们找到对应的example示例来学习,路径为:NMSIS/NN/Examples/cifar10,里面有几个最为主要的文件,分别是:示例的权重文件riscv_nnexamples_cifar10_weights.h、示例的输入图片数据文件:riscv_nnexamples_cifar10_inputs.h、示例的参数配置文件:riscv_nnexamples_cifar10_parameter.h、示例的顶层c文件:riscv_nnexamples_cifar10.c,首先从最简单的riscv_convolve_HWC_q7_basic()函数看起,进入这个函数的定义文件riscv_convolve_HWC_q7_basic.c文件里面,可以看到如下定义:
riscv_status riscv_convolve_HWC_q7_basic(const q7_t *Im_in,
const uint16_t dim_im_in,
const uint16_t ch_im_in,
const q7_t *wt,
const uint16_t ch_im_out,
const uint16_t dim_kernel,
const uint16_t padding,
const uint16_t stride,
const q7_t *bias,
const uint16_t bias_shift,
const uint16_t out_shift,
q7_t *Im_out,
const uint16_t dim_im_out,
q15_t *bufferA,
q7_t *bufferB)
这里分别是:输入图片数据Im_in、输入图片尺寸dim_im_in、输入通道数ch_im_in、权重文件wt、输出通道数ch_im_out、卷积核尺寸dim_kernel、填充padding、步长stride、偏置bias、偏置移位bias_shift、输出移位out_shift、输出图片Im_out、输出图片尺寸dim_im_out、以及两个buffer。
自己设计的简单卷积操作:6X6输入图片,卷积核是3X3尺寸,输出为4X4尺寸:
#include
#include "hbird_sdk_soc.h"
// data
#define CONV1_WT {...}
#define IMG_DATA {...}
#define CONV1_BIAS {0}
// define
#define CONV1_IM_DIM 6 // image dimension
#define CONV1_IM_CH 1 // image channel
#define CONV1_KER_DIM 3 // kernel dimension
#define CONV1_PADDING 0 // padding
#define CONV1_STRIDE 1 // stride
#define CONV1_OUT_CH 1 // output channel
#define CONV1_OUT_DIM 4 // output dimension
#define CONV1_BIAS_LSHIFT 0 // bias left shift
#define CONV1_OUT_RSHIFT 0 // output right shift
static int8_t conv1_wt[CONV1_IM_CH * CONV1_KER_DIM * CONV1_KER_DIM * CONV1_OUT_CH] = CONV1_WT;
static int8_t conv1_bias[CONV1_OUT_CH] = CONV1_BIAS;
int8_t scratch_buffer[4 * 4 * 1]; // output dim
int8_t scratch_buffer2[6 * 6 * 1] = IMG_DATA; // input dim
int16_t col_buffer[2 * 4 * 4 * 6 * 2];
int main(void)
{
int8_t *img_buffer1 = scratch_buffer; // output
int8_t *img_buffer2 = scratch_buffer2; // input
riscv_convolve_HWC_q7_basic(img_buffer2, CONV1_IM_DIM, CONV1_IM_CH, conv1_wt, CONV1_OUT_CH, CONV1_KER_DIM, CONV1_PADDING,CONV1_STRIDE, conv1_bias, CONV1_BIAS_LSHIFT, CONV1_OUT_RSHIFT, img_buffer1, CONV1_OUT_DIM, (int16_t *) col_buffer, NULL);
// note: img_buffer1 is output data
return 0;
}
这里数据自己定义即可,至此,迈出了搭建NN的第一步,实现卷积操作,其他类似的卷积函数其实都是同一个道理,不多讲,最后再自己打印出数据,拿去仿真即可验证结果。