国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

CUDA:矩陣轉(zhuǎn)置的GPU實現(xiàn)(Share Memory)

這篇具有很好參考價值的文章主要介紹了CUDA:矩陣轉(zhuǎn)置的GPU實現(xiàn)(Share Memory)。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

本文參加2022CUDA on Platform線上訓(xùn)練營學(xué)習(xí)筆記

歡迎各位大犇提意見

一、矩陣轉(zhuǎn)置(Matrix Transpose)基礎(chǔ)

cuda矩陣轉(zhuǎn)置,CUDA_On_Arm_2022夏令營,矩陣,算法,線性代數(shù),人工智能
上圖中將m * n的矩陣A通過矩陣轉(zhuǎn)置變成了n * m的 AT,簡單來講矩陣轉(zhuǎn)置即為將原始矩陣的第一行轉(zhuǎn)置為目標(biāo)矩陣的第一列,以此類推,相信基礎(chǔ)扎實的你簡單地看看CPU端的代碼就能理解

二、矩陣轉(zhuǎn)置的CPU端實現(xiàn)

__host__ void cpu_transpose(int *matrix,int *tr_matrix,int m,int n) {
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < m; j++) {
			tr_matrix[i * m + j] = matrix[j * n + i];
		}
	}
	return;
}

定義一個名為cpu_transpose的函數(shù),將矩陣matrix轉(zhuǎn)置為矩陣tr_matrix,通過觀察代碼不難發(fā)現(xiàn)tr_matrix[i][j]=matrix[j][i],這里需要注意到的是坐標(biāo)的轉(zhuǎn)換,轉(zhuǎn)置后的矩陣行數(shù)和列數(shù)發(fā)生變換,留意m和n不要乘錯了。

原始矩陣:
cuda矩陣轉(zhuǎn)置,CUDA_On_Arm_2022夏令營,矩陣,算法,線性代數(shù),人工智能
CPU端執(zhí)行結(jié)果:
cuda矩陣轉(zhuǎn)置,CUDA_On_Arm_2022夏令營,矩陣,算法,線性代數(shù),人工智能

三、矩陣轉(zhuǎn)置的GPU端實現(xiàn)(share Memory)

1、核函數(shù)的編寫

GPU端的實現(xiàn)與CPU端類似,首先根據(jù)各個線程的index(索引)計算出當(dāng)前線程在原始矩陣中的位置rowcol,在原始矩陣中的row行,col

	int row = blockDim.y * blockIdx.y + threadIdx.y;
	int col = blockDim.x * blockIdx.x + threadIdx.x;

下邊我們申請同一個block中的線程可以訪問的shared Memory

__shared__ int smem_matrix[BLOCK_SIZE][BLOCK_SIZE];

在GPU中申請了一塊名為smem_matrix大小為sizeof(int)*BLOCK_SIZE^2的共享內(nèi)存,在執(zhí)行賦值操作之前將當(dāng)前block中的線程需要訪問到的數(shù)據(jù)從Global_Memory中復(fù)制到share_Memory

smem_matrix[threadIdx.y][threadIdx.x] = row < m&& col < n ? matrix[row*n+col] : 0;

賦值時需要注意的是:由于我們?yōu)閮?nèi)核函數(shù)設(shè)置執(zhí)行配置的時候通常會向上取整,會申請多于實際需求的線程數(shù),所以在我們賦值之前需要判斷當(dāng)前線程的坐標(biāo)是否是需求坐標(biāo),以此來防止訪問matrixrow*n+col成為野指針,對我們的數(shù)據(jù)造成重大的危害
有了同一個block中的線程申請一個share Memory的概念后,需要做的是同步同一個BLock中的線程

__syncthreads();

通過上邊一系列的操作,我們就可以開始真正的轉(zhuǎn)置操作了,需要注意的是,我們已經(jīng)把線程所需的數(shù)據(jù)賦值到share Memory當(dāng)中,所以我們在賦值時只需調(diào)用smem_matrix,同樣,賦值操作之前,我們需要判斷當(dāng)前的坐標(biāo)是否實際有效

	if(blockIdx.x * blockDim.x + threadIdx.y < n && threadIdx.x + blockIdx.y * blockDim.x < m)
	tr_matrix[threadIdx.x+blockIdx.y*blockDim.x+m*(blockIdx.x*blockDim.x+threadIdx.y)] = smem_matrix[threadIdx.x][threadIdx.y];

上述分析使我們獲得了完整的GPU代碼

__global__ void cuda_transpose(int *matrix,int *tr_matrix,int m,int n) {
	int row = blockDim.y * blockIdx.y + threadIdx.y;
	int col = blockDim.x * blockIdx.x + threadIdx.x;
	__shared__ int smem_matrix[BLOCK_SIZE][BLOCK_SIZE];
	smem_matrix[threadIdx.y][threadIdx.x] = row < m&& col < n ? matrix[row*n+col] : 0;
	__syncthreads();
	if(blockIdx.x * blockDim.x + threadIdx.y < n && threadIdx.x + blockIdx.y * blockDim.x < m)
	tr_matrix[threadIdx.x+blockIdx.y*blockDim.x+m*(blockIdx.x*blockDim.x+threadIdx.y)] = smem_matrix[threadIdx.x][threadIdx.y];
	return;
}

2、核函數(shù)的啟動

在設(shè)備端申請兩個指針并為其分配內(nèi)存

	int* d_matrix, *dtr_matrix;
	cudaMalloc((void**)&d_matrix, sizeof(int) * m * n);
	cudaMalloc((void**)&dtr_matrix, sizeof(int) * m * n);

手動將matrix中的數(shù)據(jù)通過Pcie復(fù)制到設(shè)備端的Global Memory當(dāng)中

cudaMemcpy(d_matrix, matrix, sizeof(int) * m * n, cudaMemcpyHostToDevice);

核函數(shù)執(zhí)行設(shè)置的設(shè)定,一個warp通常為32個線程所以我們一個Block中的線程數(shù)最好設(shè)置為32的整數(shù)倍,從此提高使用率,有效防止inactive code的出現(xiàn)

dim3 block = { BLOCK_SIZE,BLOCK_SIZE,1 }; //BLOCK_SIZE = 16

gridDim的設(shè)置最需關(guān)注的就是申請的線程能夠有效的覆蓋真?zhèn)€矩陣,寧可多申請,通過核函數(shù)中的if屏蔽,也不少申請,導(dǎo)致計算的缺失,所以我們在計算中采用向上取整的方法
需要注意的使 dim3 類型中的三個成員都是要求unsigned int 類型的所以我們在前面添加(unsigned int)來強制將我們的計算結(jié)果轉(zhuǎn)換為無符號

dim3 gird = { (unsigned int)(n - 1 + BLOCK_SIZE) / BLOCK_SIZE, (unsigned int)(m - 1 + BLOCK_SIZE) / BLOCK_SIZE,1 };

核函數(shù)啟動!

cuda_transpose << < gird , block  >> > (d_matrix, dtr_matrix, m, n);

3、核函數(shù)性能計數(shù)

在CUDA中有一種特殊的類型cudaEvent_t,可以幫助我們記錄核函數(shù)的執(zhí)行信息

	cudaEvent_t kernel_start;
	cudaEvent_t kernel_end;

	cudaEventCreate(&kernel_start);
	cudaEventCreate(&kernel_end);

kernel_start用于記錄核函數(shù)開始執(zhí)行時的信息,kernel_end用來記錄核函數(shù)運行結(jié)束時的信息,這里使用到了兩個函數(shù)cudaEventQuery(kernel_start);,cudaEventSynchronize(kernel_end);,前者是非阻塞的,只要執(zhí)行到就直接記錄,后者是阻塞式的,需要前面的執(zhí)行完畢才能運行,具體的性能計數(shù)函數(shù)如下
cuda矩陣轉(zhuǎn)置,CUDA_On_Arm_2022夏令營,矩陣,算法,線性代數(shù),人工智能
通過簡單的邏輯組合,就可以得到核函數(shù)的實際運行時間,具體代碼如下

	cudaEventCreate(&kernel_start);
	cudaEventCreate(&kernel_end);
	cudaEventRecord(kernel_start);
	cudaEventQuery(kernel_start);
	cuda_transpose << < gird , block  >> > (d_matrix, dtr_matrix, m, n);
	cudaEventRecord(kernel_end);
	cudaEventSynchronize(kernel_end);
	float ms;
	cudaEventElapsedTime(&ms, kernel_start, kernel_end);

四、代碼參考

#include <cuda_runtime.h>
#include <device_launch_parameters.h>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <iostream>
#define BLOCK_SIZE 32
using namespace std;


__global__ void cuda_transpose(int *matrix,int *tr_matrix,int m,int n) {
	int row = blockDim.y * blockIdx.y + threadIdx.y;
	int col = blockDim.x * blockIdx.x + threadIdx.x;
	__shared__ int smem_matrix[BLOCK_SIZE][BLOCK_SIZE];
	smem_matrix[threadIdx.y][threadIdx.x] = row < m&& col < n ? matrix[row*n+col] : 0;
	__syncthreads();
	if(blockIdx.x * blockDim.x + threadIdx.y < n && threadIdx.x + blockIdx.y * blockDim.x < m)
	tr_matrix[threadIdx.x+blockIdx.y*blockDim.x+m*(blockIdx.x*blockDim.x+threadIdx.y)] = smem_matrix[threadIdx.x][threadIdx.y];
	return;
}

__host__ void cpu_transpose(int *matrix,int *tr_matrix,int m,int n) {
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < m; j++) {
			tr_matrix[i * m + j] = matrix[j * n + i];
		}
	}
	return;
}

__host__ void init_matrix(int* matrix,int m,int n) {
	for (int i = 0; i < m; i++) {
		for (int j = 0; j < n; j++) {
			matrix[i*n+j] = rand();
		}
	}
}

void print(int*, string,int,int);
bool check(int*, int*, int, int);

int main() {
	int m = 1111;
	int n = 113;
	int *matrix;
	cudaMallocHost((void**)&matrix, sizeof(int) * m * n);
	init_matrix(matrix,m,n);
	//print(matrix, "init matrix", m, n);


	int* htr_matrix;
	cudaMallocHost((void**)&htr_matrix, sizeof(int) * m * n);
	cpu_transpose(matrix, htr_matrix, m, n);
	//print(htr_matrix, "CPU", n, m);
	//將CPU端執(zhí)行的結(jié)果存放在htr_matrix中 

	int* d_matrix, *dtr_matrix;
	cudaMalloc((void**)&d_matrix, sizeof(int) * m * n);
	cudaMalloc((void**)&dtr_matrix, sizeof(int) * m * n);
	cudaMemcpy(d_matrix, matrix, sizeof(int) * m * n, cudaMemcpyHostToDevice);
	dim3 gird = { (unsigned int)(n - 1 + BLOCK_SIZE) / BLOCK_SIZE, (unsigned int)(m - 1 + BLOCK_SIZE) / BLOCK_SIZE,1 };
	dim3 block = { BLOCK_SIZE,BLOCK_SIZE,1 };


	cudaEvent_t kernel_start;
	cudaEvent_t kernel_end;

	cudaEventCreate(&kernel_start);
	cudaEventCreate(&kernel_end);
	cudaEventRecord(kernel_start);
	cudaEventQuery(kernel_start);
	cuda_transpose << < gird , block  >> > (d_matrix, dtr_matrix, m, n);
	cudaEventRecord(kernel_end);
	cudaEventSynchronize(kernel_end);
	float ms;
	cudaEventElapsedTime(&ms, kernel_start, kernel_end);


	int* hdtr_matrix;
	cudaMallocHost((void**)&hdtr_matrix, sizeof(int) * m * n);
	cudaMemcpy(hdtr_matrix, dtr_matrix, sizeof(int) * m * n, cudaMemcpyDeviceToDevice);
	//print(hdtr_matrix, "GPU", n, m);
	
	if (check(hdtr_matrix, htr_matrix, n, m)) {
		cout << "pass\n";
	}
	else {
		cout << "error\n";
	}
	
	printf("GPU time is : %f \n", ms);

	cudaFree(hdtr_matrix);
	cudaFree(dtr_matrix);
	cudaFree(matrix);
	cudaFree(htr_matrix);
	cudaFree(d_matrix);
	return 0;
}


void print(int* a, string name,int m,int n) {
	cout << "NAME : " << name << endl;
	for (int i = 0; i < m; i++) {
		for (int j = 0; j < n; j++) {
			printf("%6d ", a[i * n + j]);
		}
		printf("\n");
	}
}

bool check(int* a, int* b, int m, int n) {
	bool check_flag = true;
	for (int i = 0; i < m; i++) {
		for (int j = 0; j < n; j++) {
			if (a[i * n + j] != b[i * n + j]) {
				return false;
			}
		}
	}
	return check_flag;
}


執(zhí)行結(jié)果如圖
cuda矩陣轉(zhuǎn)置,CUDA_On_Arm_2022夏令營,矩陣,算法,線性代數(shù),人工智能

五、實踐心得

本次實踐通過GPU端中的share Memory對核函數(shù)運行時的讀寫問題做了優(yōu)化,當(dāng)線程與線程之間為連續(xù)讀寫時,global Memory的效率是比較高的,不使用share Memory時,使用GPU進(jìn)行矩陣轉(zhuǎn)置會出現(xiàn)兩難問題(1.讀row-major 寫col-major,2寫col-major 讀row-major),而在share Memoryrow-majorcol-major的效率幾乎相同,很好地解決了global memory上的問題,在編寫過程中,需要注意的是,要順著global memory寫,首先保證global memory讀寫時是row-major,以達(dá)到最高的優(yōu)化效率。
遇到的最大問題是,邊界的判斷問題,GPU轉(zhuǎn)置過程中,由于要保證global memoryrow-major,所以坐標(biāo)不像是CPU端中的簡單調(diào)換,具體表現(xiàn)為(在對share 數(shù)字賦值時該線程無意義,而在寫global操作中該線程有意義),所以在__syncthreads();后需要判斷當(dāng)前線程是否有意義

鄙人第一次寫實操博客,有建議必洗耳恭聽
再次感謝偉大的NV 開發(fā)者社區(qū)文章來源地址http://www.zghlxwxcb.cn/news/detail-532243.html

到了這里,關(guān)于CUDA:矩陣轉(zhuǎn)置的GPU實現(xiàn)(Share Memory)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進(jìn)行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • CUDA編程模型系列六(利用shared memory和統(tǒng)一內(nèi)存優(yōu)化矩陣乘)

    CUDA編程模型系列六(利用shared memory和統(tǒng)一內(nèi)存優(yōu)化矩陣乘) 本系列教程將介紹具體的CUDA編程代碼的細(xì)節(jié) CUDA編程模型系列六(利用shared memory和統(tǒng)一內(nèi)存優(yōu)化矩陣乘)

    2024年02月11日
    瀏覽(21)
  • CUDA編程:矩陣乘運算從CPU到GPU

    CUDA編程:矩陣乘運算從CPU到GPU

    本文內(nèi)容涉及到CUDA矩陣1D運算、2D運算、共享內(nèi)存、CUBLAS的使用。 文中的全部code: https://github.com/CalvinXKY/BasicCUDA/tree/master/matrix_multiply V100上的測試對比: 運行內(nèi)容“./matMul wA=1024 hA=256 wB=128 hB=1024” 矩陣 C = A x B的數(shù)學(xué)運算,是線性代數(shù)里面最基本的內(nèi)容, 計算的基本公式如下

    2024年04月08日
    瀏覽(24)
  • 解決:RuntimeError: CUDA out of memory. Tried to allocate 160.00 MiB (GPU 0; 10.76 GiB total capacity..

    完整報錯: ? 問題分析: 內(nèi)存分配不足: 需要160MB,,但GPU只剩下135.31MB。 解決辦法: 1.減小batch_size。注意batchsize的調(diào)整要配合學(xué)習(xí)率的調(diào)整,一般是正比關(guān)系,BS增大兩倍,LR增大兩倍或者根號二倍。減小也是相應(yīng)更改。 2.運行torch.cuda.empty_cache()函數(shù)。加在訓(xùn)練開始前即可

    2024年02月16日
    瀏覽(19)
  • torch.cuda.OutOfMemoryError: CUDA out of memory.

    torch.cuda.OutOfMemoryError: CUDA out of memory.

    訓(xùn)練清華ChatGLM-6B時報錯, 原因是顯存不夠 torch.cuda.OutOfMemoryError: CUDA out of memory. Tried to allocate 96.00 MiB (GPU 0; 23.70 GiB total capacity; 4.37 GiB already allocated; 64.81 MiB free; 4.37 GiB reserved in total by PyTorch) If reserved memory is allocated memory try setting max_split_size_mb to avoid fragmentation. ?See documentatio

    2024年02月06日
    瀏覽(18)
  • Pycharm報錯torch.cuda.OutOfMemoryError: CUDA out of memory.

    報錯 做深度學(xué)習(xí)相關(guān)的實驗,可以看到我的顯卡內(nèi)存很小(哭了,不過我有時候是在別的電腦上做的,那個電腦比這個好用),網(wǎng)上搜到的說的 max_split_size_mb:128 這個方法我貼到我代碼上之后沒有效果。 因為我在這個電腦上做的是主實驗后面的一些對比實驗,也就是代碼中很

    2024年02月05日
    瀏覽(29)
  • 【CUDA OUT OF MEMORY】【Pytorch】計算圖與CUDA OOM

    【CUDA OUT OF MEMORY】【Pytorch】計算圖與CUDA OOM

    在實踐過程中多次碰到了CUDA OOM的問題,有時候這個問題是很好解決的,有時候DEBUG一整天還是頭皮發(fā)麻。 最近實踐對由于計算圖積累導(dǎo)致CUDA OOM有一點新的看法,寫下來記錄一下。 包括對計算圖的一些看法和一個由于計算圖引發(fā)錯誤的簡化實例記錄。 本人能力有限,認(rèn)識片

    2024年02月09日
    瀏覽(26)
  • CUDA報錯:Out of Memory

    如果報錯里提示Pytorch?reserved的內(nèi)存遠(yuǎn)大于Already?allocated的內(nèi)存,那么就是因為分配顯存時單位過大,導(dǎo)致出現(xiàn)大量內(nèi)存碎片無法繼續(xù)分配(與操作系統(tǒng)內(nèi)存管理同理)。 我們可以限制一次分配的最大單位來解決這個問題。 隨后代碼便可正常運行了。

    2024年02月15日
    瀏覽(22)
  • 部署stable diffusion 錯誤torch.cuda.OutOfMemoryError: CUDA out of memory.

    部署stable diffusion 錯誤torch.cuda.OutOfMemoryError: CUDA out of memory.

    以來安裝完畢,開始執(zhí)行web_ui.bat 錯誤截圖: ?猜測原因:GPU用錯了 webUI.py加一行代碼 在此啟動web_ui.bat,成功打開網(wǎng)頁頁面

    2024年02月11日
    瀏覽(25)
  • RuntimeError: CUDA out of memory See documentation for Memory Management and PYTORCH_CUDA_ALLOC_CONF

    報錯: If reserved memory is allocated memory try setting max_split_size_mb to avoid fragmentation. See documentation for Memory Management and PYTORCH_CUDA_ALLOC_CONF 當(dāng)reserved memory is allocated memory,進(jìn)行如下設(shè)置,可解決此bug: 代碼如下:

    2024年02月11日
    瀏覽(19)
  • 【CUDA】GPU 算力與 CUDA 版本對應(yīng)關(guān)系

    【CUDA】GPU 算力與 CUDA 版本對應(yīng)關(guān)系

    官方算力表:https://developer.nvidia.com/cuda-gpus#compute 2.1. 信息來源 1 https://docs.nvidia.com/datacenter/tesla/drivers/index.html#cuda-arch-matrix 2.2. 信息來源 2 https://en.wikipedia.org/wiki/CUDA#GPUs_supported

    2024年01月19日
    瀏覽(23)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包