卷积是CNN网络中一个非常重要的操作(Operation或Op),关于卷积的数学原理,大家可以参考维基百科:Convolution。但是我们这里给大家介绍的二维卷积又不同于传统数学的卷积,更像是correlation,因为我们这里的操作不需要进行kernel的旋转。
本文中,我们跟大家介绍如何从tensorflow的graph中提取conv2d的参数,并以简单的约定格式进行保存。最后使用简单的C语言进行模型的加载和推断,最后和tensorflow的python调用结果进行比较,验证结果的正确性。本文我们仅做Op的准确性验证,后续的文章会再跟大家介绍如何针对嵌入式设备利用Halide、ACL(Arm Compute Library)、low-leval SIMD api等进行加速。
我们首先看看数据格式的约定,我们采用的数据排布格式为NCHW,仅考虑对float数据进行处理。Tensor的定义非常简单,可参考如下结构体。
typedef struct Tensor
{
float* data;
int dims[4];
int nums;
} Tensor;
- 卷积操作的基本实现
下面我们来看看卷积的操作,考虑一种非常平凡的实现方式,我们可以嵌套多层,以sliding-windows的方式来实现conv2d。其中,如下的OC、OH、OW指的是输出output的channel、height、width,FC、FH、FW同理。
int oc,oh,ow;
int fc,fh,fw;
for (oc = 0; oc < OC; ++oc)
{
for (oh = 0; oh < OH; ++oh)
{
for (ow = 0; ow < OW; ++ow)
{
float val = 0.0f;
int base_ow = ow * stride_w;
int base_oh = oh * stride_h;
int base_ss = oc * FC * FH * FW;
for (fc = 0; fc < FC; ++fc)
{
for (fh = 0; fh < FH; ++fh)
{
for (fw = 0; fw < FW; ++fw)
{
int input_idx =
(base_ow + fw) +
(base_oh + fh) * IW +
fc * IH * IW;
int filter_idx =
fw +
fh * FW +
fc * FH * FW +
base_ss;
val +&#