img2col C++版本代码实现

近期学习了下img2col的原理,自己写了版用C++实现的img2col。img2col对于熟悉深度学习的卷积计算的人来说应该并不陌生,它是一种将普通卷积计算转换为一次矩阵乘法计算的算法,相较于直接计算卷积来说能提升计算效率。

关于img2col的原理,网上有非常多的讲解,在此不再多作描述,不了解的人可以自行百度或参考以下链接:

极智AI | 一文看懂Img2Col卷积加速算法

我所实现的代码,正是基于上文中卷积加速算法的最后一种,也就是利用分块矩阵乘法的计算特性,将加偏置的步骤合并到一次矩阵乘法中,省去了一步矩阵加法。也就是下图中的算法(来自于以上链接):

关键代码如下,如需要测试代码及pytorch_python版的正确性验证代码,请到以下链接下载:

自己实现的img2col-C++代码+测试代码+pytorch-python验证代码

#include <Eigen/Core>

using namespace std;
using namespace Eigen;

typedef struct convRet
{
	int num;
	int width;
	int height;
	int* data;
}convRet;

/***
input:
imgw 原图像素宽
imgh 原图像素高
img 原图像素值
pad padding值
stride 步长
convN 卷积核数目
convW 卷积核宽
convH 卷积核高
conv 卷积核数值
bias 偏置值
output 计算后的输出
**/
void myImg2col(int imgw, int imgh, int* img, int pad, int stride, int convN, int convW, int convH, 
	int* conv, int* bias, convRet* output) {
	int unfoldW = convW * convH + 1;//img展开后的宽,此处加了偏移量扩展
	int unfoldH = ((pad * 2 + imgh - convH) / stride + 1)*((pad * 2 + imgw - convW) / stride + 1);//img展开后的高=卷积乘法次数
	int brow = 0 - pad;
	int bcol = 0 - pad;
	//定义存放img展开后的矩阵的eigen矩阵
	MatrixXi unfold(unfoldH, unfoldW);
	for (int h = 0; h < unfoldH; h++) {
		if (bcol + convW > imgw + pad) {//水平方向上超出了pad后的图片,要换行
			bcol = 0 - pad;
			brow += stride;
		}
		if (brow + convH > imgh + pad) {//竖直方向上已经超出pad后的图片了,一般外层循环就限制了不会到这步,加一个保险
			break;
		}
		for (int w = 0; w < unfoldW - 1; w++) {
			int rowBias = w / convW;
			int colBias = w % convW;
			if (brow + rowBias < 0 || bcol + colBias < 0 || brow + rowBias >= imgh || bcol + colBias >= imgw) {
				//满足此条件则说明在pad的区域里
				unfold(h, w) = 0;
			}
			else {
				unfold(h, w) = img[(brow + rowBias)*imgw + bcol + colBias];
			}
		}
		unfold(h, unfoldW - 1) = 1;
		bcol += stride;
	}


	//定义存放展开后的卷积核的eigen矩阵
	int unfoldConvLen = convH * convW + 1;
	MatrixXi unfoldConv(convN, unfoldConvLen);
	for (int n = 0; n < convN; n++) {
		for (int m = 0; m < unfoldConvLen - 1; m++) {
			unfoldConv(n, m) = conv[n*convW*convH + (m / convW)*convW + m % convW];
		}
		unfoldConv(n, unfoldConvLen - 1) = bias[n];
	}


	//两矩阵相乘
	MatrixXi retMat = unfold * unfoldConv.transpose();


	//取结果
	output->num = convN;
	output->width = (pad * 2 + imgw - convW) / stride + 1;
	output->height = (pad * 2 + imgh - convH) / stride + 1;
	output->data = (int*)malloc(sizeof(int)*convN*output->width*output->height);
	for (int n = 0; n < output->num; n++) {
		for (int h = 0; h < output->height; h++) {
			for (int w = 0; w < output->width; w++) {
				output->data[n*output->width*output->height + h * output->width + w] = retMat(h*output->width + w, n);
			}
		}
	
	}
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

热血大婶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值