AVX优化矩阵乘法

1.看了OpenBlas的矩阵乘法优化 尝试写下AVX版本的矩阵优化

2.在单线程情况下 单精度 1000X1000的矩阵乘1000X1000 运行100次 取平均值

Pytorch-Mkl 23.ms
Numpy(应该也是用的MKL) 23.ms
我的 38.ms

以下贴上代码

void addDot8x8Pack(int k, float *A, float *B, float *C, int n) {
	int p;

	float *bp0_pntr = B;

	__m256 Zero1 = _mm256_setzero_ps();
	__m256 Zero2 = _mm256_setzero_ps();
	__m256 Zero3 = _mm256_setzero_ps();
	__m256 Zero4 = _mm256_setzero_ps();
	__m256 Zero5 = _mm256_setzero_ps();
	__m256 Zero6 = _mm256_setzero_ps();
	__m256 Zero7 = _mm256_setzero_ps();
	__m256 Zero8 = _mm256_setzero_ps();



	for (p = 0; p < k; p++) {

		__m256 a0 = _mm256_set1_ps(*(A + p));
		__m256 a1 = _mm256_set1_ps(*(A + n + p));
		__m256 a2 = _mm256_set1_ps(*(A + 2 * n + p));
		__m256 a3 = _mm256_set1_ps(*(A + 3 * n + p));
		__m256 a4 = _mm256_set1_ps(*(A + 4 * n + p));
		__m256 a5 = _mm256_set1_ps(*(A + 5 * n + p));
		__m256 a6 = _mm256_set1_ps(*(A + 6 * n + p));
		__m256 a7 = _mm256_set1_ps(*(A + 7 * n + p));

		__m256 bp = _mm256_load_ps(bp0_pntr);

		Zero1 = _mm256_fmadd_ps(a0, bp, Zero1);
		Zero2 = _mm256_fmadd_ps(a1, bp, Zero2);
		Zero3 = _mm256_fmadd_ps(a2, bp, Zero3);
		Zero4 = _mm256_fmadd_ps(a3, bp, Zero4);
		Zero5 = _mm256_fmadd_ps(a4, bp, Zero5);
		Zero6 = _mm256_fmadd_ps(a5, bp, Zero6);
		Zero7 = _mm256_fmadd_ps(a6, bp, Zero7);
		Zero8 = _mm256_fmadd_ps(a7, bp, Zero8);


		bp0_pntr += 8;

	}

	_mm256_store_ps(C, Zero1);
	_mm256_store_ps(C + n, Zero2);
	_mm256_store_ps(C + 2 * n, Zero3);
	_mm256_store_ps(C + 3 * n, Zero4);
	_mm256_store_ps(C + 4 * n, Zero5);
	_mm256_store_ps(C + 5 * n, Zero6);
	_mm256_store_ps(C + 6 * n, Zero7);
	_mm256_store_ps(C + 7 * n, Zero8);

}
void PackedBMatrix(int j, int n, int k, float *input, float *output) {

	for (int i = 0; i < k; i++) {
		
		memcpy(output + i * 8, input + i * n+j, sizeof(float) * 8);
	}

}
void testBlas3(float *A, float *B, float *C, int m, int n, int k) {
	int i, j;
	float *PackB = new float[8 * k];
	//float *PackA = new float[8 * k];
	for (j = 0; j < n; j += 8) {
		PackedBMatrix(j, n, k, B, PackB);
		for (i = 0; i < m; i += 8) {		
			//addDot8x8R(k, A + i * k, B + j, C + i * n + j, n);
			addDot8x8Pack(k, A + i * k, PackB, C + i * n + j, n);
		}
	}
	delete[]PackB;
}
#include <iostream>
int main(){
	float *A = new float[1000 * 1000];
	float *B = new float[1000 * 1000];

	for (int i = 0; i < 1000 * 1000; i++) {
		A[i] = 1.0f;
		B[i] = 1.0f;
	}
	clock_t v2,v3;
	v2 = clock();
	float *C = nullptr;
	for (int loop = 0; loop < 100; loop++) {
		C = new float[1000 * 1000];
		testBlas3(A, B, C, 1000,1000,1000);
		delete[] C;
	}	
	v3 = clock();
	cout << (v3 - v2)/100.0 << endl;

}

采取8*8分块方式
具体原理讲解参考

OpenBLAS项目与矩阵乘法优化 | AI 研习社
OpenBlas矩阵乘法优化

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
矩阵乘法是一个常见的运算任务,可以通过串行算法、catch优化、SSE/AVX版本和分片策略来实现。下面分别介绍这四种实现方法。 1. 串行算法: 串行算法是最基本的矩阵乘法实现方式。通过两层循环遍历矩阵A和矩阵B的每个元素,计算对应位置的乘积再求和,得到结果矩阵C的对应元素。该过程的时间复杂度为O(n^3),其中n为矩阵的维度。 2. Catch优化: Catch优化是一种优化矩阵乘法性能的方法。它利用计算CPU的高速缓存(Cache)来提高运算速度。通过分块矩阵乘法,将原始矩阵按照一定的块大小划分成多个小块,然后逐个计算小块相乘的结果。在计算过程中,尽量利用Cache的特性,减少Cache的命中次数,从而降低内存访问的开销。 3. SSE/AVX版本: SSE(SIMD Streaming Extensions)和AVX(Advanced Vector Extensions)是一些现代CPU的指令集扩展,支持同一时间进行多个并行计算。在矩阵乘法中,可以利用SSE/AVX指令集来对矩阵的一部分进行并行计算,从而提高计算效率。 4. 分片策略: 分片策略是将矩阵按照行或列进行划分,将矩阵乘法任务分片分配给多个线程或进程并行计算。每个线程或进程处理一个或多个分片,最后将计算结果汇总得到最终的结果矩阵。通过多线程或多进程的方式,可以充分利用多核计算的并行计算能力,加快矩阵乘法的速度。 以上四种实现方式都可以在各自的环境下进行运行。具体执行过程可以根据不同的编程语言和平台来实现。主要考虑到矩阵的大小和硬件平台的特点,选择适合的实现方式来获得最佳的性能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值