Openblas加速二维矩阵卷积操作-增加pad计算

上个博客中(http://blog.youkuaiyun.com/samylee/article/details/73251042)提到了openblas加速二维矩阵的卷积计算,本博客增加了pad计算。

下个博客将介绍openblas在三维矩阵卷积计算中的加速。

代码如下(以下程序经博主测试准确无误):

 

//cblas加速二维矩阵卷积操作
//注意:stride=1
//作者:samylee

#include <cblas.h>  
#include <iostream>

using namespace std;

//A加pad的计算
void comput_Apad(const int pad_w, const int Map, float *A_pad, const float *A)
{
	for (int i = 0; i < pad_w; i++)
	{
		for (int j = 0; j < pad_w; j++)
		{
			int col = i*pad_w + j;

			if (i == 0 || i == pad_w - 1)
			{
				A_pad[col] = 0;
			}
			else
			{
				if (j == 0 || j == pad_w - 1)
				{
					A_pad[col] = 0;
				}
				else
				{
					A_pad[col] = A[(i - 1)*Map + j - 1];
				}
			}
		}
	}
}

//pad_A的转换,以适用于Openblas
void convertA(float *A_convert, const int outM, const int convAw, const int pad_w, float *A_pad)
{
	for (int i = 0; i < outM; i++)
	{
		for (int j = 0; j < outM; j++)
		{
			int wh = i * outM * convAw + j * convAw;

			int col1 = i * pad_w + j;
			A_convert[wh] = A_pad[col1];
			A_convert[wh + 1] = A_pad[col1 + 1];
			A_convert[wh + 2] = A_pad[col1 + 2];

			int col2 = (i + 1) * pad_w + j;
			A_convert[wh + 3] = A_pad[col2];
			A_convert[wh + 4] = A_pad[col2 + 1];
			A_convert[wh + 5] = A_pad[col2 + 2];

			int col3 = (i + 2) * pad_w + j;
			A_convert[wh + 6] = A_pad[col3];
			A_convert[wh + 7] = A_pad[col3 + 1];
			A_convert[wh + 8] = A_pad[col3 + 2];
		}
	}
}

//Openblas矩阵乘积计算
void Matrixmul_blas(const int convAh, const int convAw, float *A_convert, float *B, float *C)
{
	const enum CBLAS_ORDER Order = CblasRowMajor;
	const enum CBLAS_TRANSPOSE TransA = CblasNoTrans;
	const enum CBLAS_TRANSPOSE TransB = CblasNoTrans;
	const int M = convAh;//A的行数,C的行数
	const int N = 1;//B的列数,C的列数
	const int K = convAw;//A的列数,B的行数
	const float alpha = 1;
	const float beta = 0;
	const int lda = K;//A的列
	const int ldb = N;//B的列
	const int ldc = N;//C的列

	cblas_sgemm(Order, TransA, TransB, M, N, K, alpha, A_convert, lda, B, ldb, beta, C, ldc);
}

int main() 
{
	//卷积参数初始化
	const int pad = 1;
	const int stride = 1;

	//定义被卷积矩阵
	const int Map = 6;
	const float A[Map * Map] = { 
		1,2,3,4,5,6,
		1,2,3,4,5,6,
		1,2,3,4,5,6,
		1,2,3,4,5,6,
		1,2,3,4,5,6,
		1,2,3,4,5,6 };
	
	//定义卷积核
	const int Kernel = 3;
	float B[Kernel * Kernel] = {
		1,1,1,
		1,1,1,
		1,1,1 };
	
	//计算卷积输出矩阵宽高
	const int outM = (Map - Kernel + 2 * pad) / stride + 1;

	//计算pad_A
	const int pad_w = Map + 2 * pad;
	float A_pad[pad_w*pad_w];
	comput_Apad(pad_w, Map, A_pad, A);

	//定义被卷积矩阵宽高
	const int convAw = Kernel*Kernel;
	const int convAh = outM*outM;

	//转换被卷积矩阵
	float A_convert[convAh*convAw];
	convertA(A_convert, outM, convAw, pad_w, A_pad);

	//定义卷积输出矩阵
	float C[convAh*1];
	//cblas计算输出矩阵
	Matrixmul_blas(convAh, convAw, A_convert, B, C);

	//输出验证
	cout << "A_pad is:" << endl;
	for (int i = 0; i < pad_w; i++)
	{
		for (int j = 0; j < pad_w; j++)
		{
			cout << A_pad[i*pad_w + j] << " ";
		}
		cout << endl;
	}
	cout << endl;

	cout << "B is:" << endl;
	for (int i = 0; i < Kernel; i++)
	{
		for (int j = 0; j < Kernel; j++)
		{
			cout << B[i*Kernel + j] << " ";
		}
		cout << endl;
	}
	cout << endl;

	cout << "C is:" << endl;
	for (int i = 0; i < outM; i++)
	{
		for (int j = 0; j < outM; j++)
		{
			cout << C[i*outM + j] << " ";
		}
		cout << endl;
	}
	cout << endl;

	system("pause");
	return EXIT_SUCCESS;
}

 

 

 

 

 

效果如下:

 

 

任何问题请加唯一QQ2258205918(名称samylee)!

唯一VX:samylee_csdn

 

卷积神经网络(CNN)中,卷积层的核心作用是通过卷积操作提取输入数据的局部特征。权重矩阵(通常称为卷积核或滤波器)与输入数据之间的计算方式主要涉及逐元素相乘和求和的过程。 假设输入数据是一个二维矩阵 $ X $,大小为 $ H \times W $,卷积核是一个二维矩阵 $ K $,大小为 $ k_H \times k_W $。在卷积操作中,卷积核会在输入矩阵上滑动,并在每个位置上与输入数据的局部区域进行点乘,然后将结果求和,再加上偏置项(如果有的话),最终得到输出的一个像素值。 具体计算公式如下: $$ Y[i,j] = \sum_{m=0}^{k_H-1} \sum_{n=0}^{k_W-1} X[i+m, j+n] \cdot K[m,n] + b $$ 其中: - $ Y[i,j] $ 表示输出矩阵在位置 $ (i,j) $ 处的值。 - $ X[i+m,j+n] $ 表示输入矩阵在位置 $ (i+m,j+n) $ 处的值。 - $ K[m,n] $ 表示卷积核在位置 $ (m,n) $ 处的权重。 - $ b $ 是偏置项,通常在整个卷积操作中共享一个偏置值。 卷积核会在输入矩阵上按照设定的步长(stride)滑动,直到覆盖整个输入区域。如果输入矩阵边缘需要填充(padding),则在计算时会将填充的值一并考虑进去[^1]。 卷积层中的每个卷积核都会生成一个对应的特征图(feature map),不同的卷积核会提取不同的特征,例如边缘、角点、纹理等[^2]。这些特征图可以作为下一层网络的输入,从而进行更复杂的特征提取和分类任务。 ### 示例代码:二维卷积操作的实现 以下是一个简单的 Python 实现,用于演示二维卷积操作: ```python import numpy as np def conv2d(X, K, stride=1, padding=0): """ 二维卷积操作实现 :param X: 输入矩阵,形状为 (H, W) :param K: 卷积核,形状为 (kH, kW) :param stride: 步长 :param padding: 填充大小 :return: 输出矩阵 """ H, W = X.shape kH, kW = K.shape # 计算输出矩阵的大小 out_H = (H + 2 * padding - kH) // stride + 1 out_W = (W + 2 * padding - kW) // stride + 1 # 对输入矩阵进行填充 X_padded = np.pad(X, pad_width=padding, mode='constant', constant_values=0) # 初始化输出矩阵 Y = np.zeros((out_H, out_W)) # 卷积操作 for i in range(out_H): for j in range(out_W): h_start = i * stride h_end = h_start + kH w_start = j * stride w_end = w_start + kW window = X_padded[h_start:h_end, w_start:w_end] Y[i, j] = np.sum(window * K) return Y # 示例输入矩阵和卷积核 X = np.array([ [1, 2, 3], [4, 5, 6], [7, 8, 9] ]) K = np.array([ [0, 1], [1, 0] ]) # 进行卷积操作 result = conv2d(X, K, stride=1, padding=0) print(result) ``` 输出结果为: ``` [[ 7. 10.] [13. 16.]] ``` 该代码实现了二维卷积的基本逻辑,展示了卷积核如何与输入数据进行计算
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值