最近在学习LU的并行加速,从paper中得到了一些idea,就想着用GPU来实现一下。学习CUDA的过程中踩了不少坑,不过最终还是完成了测试。

一、LU基本算法

1、LU 分解是计算机做矩阵运算过程中重要的一步,通过将矩阵分解为一个上三角矩阵U和下三角矩阵L,能够有效的缩短计算时间。


LU分解的计算过程如下,采用高斯消元法。

2、基本算法
  • 每一次循环都将A的第i行和第i列更新为L\U的一部分。
  • 每一次循环分为三个部分。如果先计算左上角的元素,则下侧的L矩阵部分和右侧的U矩阵部分可以同时运算,没有干扰。比如当i==1时,因为更新L的第一列(l32、l42)需要先得到u22的值,而u22要通过更新U的第二行得到,所以如果先计算出u22,L和U的更新就可以并行了。
void lud_base(int *a, int size)
{int i,j,k;int sum;for (i=0; i<size; i++){//先计算左上角的U元素sum=a[i*size+i];for (k=0; k<i; k++) sum -= a[i*size+k]*a[k*size+i];a[i*size+i]=sum;//计算下侧的L矩阵部分for (j=i+1;j<size; j++){sum=a[j*size+i];for (k=0; k<i; k++) sum -=a[j*size+k]*a[k*size+i];a[j*size+i]=sum/a[i*size+i];}//计算右侧的U矩阵部分for (j=i+1; j<size; j++){sum=a[i*size+j];for (k=0; k<i; k++) sum -= a[i*size+k]*a[k*size+j];a[i*size+j]=sum;}}
}

上述代码其实存在一个问题,对左上角元素的更新是一个累计操作。CUDA进行累计操作有两种方法,但是都不太好用

  1. 单thread执行
  2. 归约的编程方式

所以我对代码再次进行了修改,还是以i==1时为例,如果我们直接对L和U进行更新呢,得到的结果是这样的:
    U(第1行):U22、U23、U24
    L(第1列):l32**U22、l42*U22
所以我们再加一个步骤将L的每一项都除以U22即可,而这一步可以很容易的并行。代码如下:

void lud_base(int *a, int size)
{int i,j,k;int sum;for (i=0; i<size; i++){//计算下侧的L矩阵部分for (j=i+1;j<size; j++){sum=a[j*size+i];for (k=0; k<i; k++) sum -=a[j*size+k]*a[k*size+i];a[j*size+i]=sum;}//计算右侧的U矩阵部分for (j=i; j<size; j++){sum=a[i*size+j];for (k=0; k<i; k++) sum -= a[i*size+k]*a[k*size+j];a[i*size+j]=sum;}//对下侧的L矩阵后续处理for (j=i+1;j<size; j++)a[j*size+i]=sum/a[i*size+i];}}
}

二、LU分解常用的并行化算法

LU分解的并行化算法,可以分类为right-looking和left-looking。我采用right-looking算法进行测试。

Left-looking算法存在循环间的依赖关系,因为左侧的1,2,3列都要对第4列的数据进行更新,所以不能并行。
right-looking算法虽然并行度非常高,但是存在大量重复的访问和读取,因为要不断更新右侧的子矩阵。

left-looking算法如下:

right-looking算法如下:

三、CUDA加速

先记录一下花了好久才找出的Bug和解决的问题(学习还不深入,如果有误烦请指出):

  1. cuda支持累计操作,但是必须在单线程(sp)上,而且左值必须是声明的局部变量,如果左值是数组地址的话,那么每个线程都会去该地址寻址并写回,产生冲突导致结果错误。所以累加操作要用归约编程。
  2. if-else内部不能有__syncthreads(),因为部分线程不会运行。
  3. 线程束分化。一个warp中如果部分thread执行if块内的代码,另一部分线程condition不成立。则不成立的thread限制,等待其他thread执行完毕。会造成严重的性能下降。所以最好通过手动调整让一个warp中的线程都执行if或else。
  4. 一些size变量要设置为全局变量才能被GPU识别,所有数据都要手动搬入显存。
  5. 要根据显卡的硬件参数来设置block和grid,包括SM最大block数,最大线程数目等。
  6. 出现《核心段错误》是由于GPU占用率接近100%了。

right-looking算法的CUDA代码

 __global__ void  lud_right_looking(float *m)
{__shared__ float shadow[BLOCK_SIZE][BLOCK_SIZE];for (int tix = threadIdx.x; tix<BLOCK_SIZE; tix += blockDim.x) shadow[tix][threadIdx.y] =  m[tix*BLOCK_SIZE+threadIdx.y];__syncthreads();for (int k=0; k< BLOCK_SIZE-1; k++){//这行语句不适合放进下面的for循环中,多执行一次就多浪费一次资源。if (threadIdx.y>k && threadIdx.x==0)shadow[threadIdx.y][k]=shadow[threadIdx.y][k]/shadow[k][k];__syncthreads();for (int tix = threadIdx.x; tix<BLOCK_SIZE; tix += blockDim.x) {if(tix>k && threadIdx.y>k)shadow[tix][threadIdx.y] -= shadow[tix][k]*shadow[k][threadIdx.y];__syncthreads();}}for (int tix = threadIdx.x; tix<BLOCK_SIZE; tix += blockDim.x) m[tix*BLOCK_SIZE+threadIdx.y]=shadow[tix][threadIdx.y];

基本算法的CUDA代码

__global__ void  lud_base_cuda(float *m)
{__shared__ float shadow[BLOCK_SIZE][BLOCK_SIZE];int i,j;for (int tix = threadIdx.x; tix<BLOCK_SIZE; tix += blockDim.x) shadow[tix][threadIdx.y] =  m[tix*BLOCK_SIZE+threadIdx.y];__syncthreads();for(i=0; i < BLOCK_SIZE-1; i++){if ( threadIdx.y>i && threadIdx.x==0 )//计算下侧的L部分{for(j=0; j < i; j++)shadow[threadIdx.y][i] -= shadow[threadIdx.y][j]*shadow[j][i];}else if(threadIdx.y>=i   && threadIdx.x==1 ) //计算上侧的U部分{for(j=0; j < i; j++)shadow[i][threadIdx.y] -= shadow[i][j]*shadow[j][threadIdx.y];}__syncthreads();if(threadIdx.y>i && threadIdx.x==0)//对L进行后续处理{shadow[threadIdx.y][i] /= shadow[i][i];}__syncthreads();}for (int tix = threadIdx.x; tix<BLOCK_SIZE; tix += blockDim.x) m[tix*BLOCK_SIZE+threadIdx.y]=shadow[tix][threadIdx.y];
}
输入矩阵大小为64*64,运行时间如下
lud_base_cuda lud_right_looking lud_right_looking CPU
128 1024 64
0.22184 ms 0.1825 ms 0.3882 ms 0.172 ms

lud_right_looking的并行度是最高的,所以分配了1024的线程, lud_base_cuda并行度不高所以只需要128线程(实际上还有可提取的部分,将累计操作用归约实现)。综上,虽然lud_right_looking会产生额外的大量访问,但是在足够资源下并行度是最高的,性能优于ud_base_cuda。因为数据量太小,所以性能不如CPU。

引用
1、2005.LU-GPU Efficient Algorithms for Solving Dense Linear Systems on Graphics Hardware
2、2016.GPU-Accelerated Parallel Sparse LU Factorization
3、2017.GPU-Based Batch LU-Factorization Solver for Concurrent
4、2010.Blocking LU Decomposition for FPGAs
5、求大神帮忙,怎么在MATLAB上用LU分解法? - 琦钒的回答 - 知乎

CUDA学习笔记(LU分解)相关推荐

  1. CUDA学习笔记之 CUDA存储器模型

    CUDA学习笔记之 CUDA存储器模型 标签: cuda存储bindingcache编程api 2010-12-14 01:33 1223人阅读 评论(0) 收藏 举报 分类: CUDA(26) GP ...

  2. CUDA学习笔记之程序优化

    CUDA学习笔记之程序优化 标签: cuda优化conflict存储算法数学计算 2010-01-05 17:18 5035人阅读 评论(4) 收藏 举报 分类: CUDA(6) 版权声明:本文为博主 ...

  3. 深度学习(三十六)异构计算CUDA学习笔记(1)

    异构计算CUDA学习笔记(1) 原文地址:http://blog.csdn.net/hjimce/article/details/51506207 作者:hjimce 近日因为感觉自己在深度学习工程化 ...

  4. CUDA学习笔记(持续更新——蜗速)

    CUDA学习笔记(持续更新--蜗速) 1.CUDA 程序实现流程如下 2.内存管理 3.核函数 4.全局数据访问唯一索引 5.设备管理 附录代码 1.CUDA 程序实现流程如下 将数据从CPU内存拷贝 ...

  5. matlab lud矩阵分解,MIT线性代数总结笔记——LU分解

    MIT线性代数总结笔记--LU分解 矩阵分解 矩阵分解(Matrix Factorizations)就是将一个矩阵用两个以上的矩阵相乘的等式来表达.而矩阵乘法涉及到数据的合成(即将两个或多个线性变换的 ...

  6. cuda学习笔记5——CUDA实现图像形态学腐蚀、膨胀

    cuda学习笔记5--CUDA实现图像形态学腐蚀.膨胀 代码 linux如何编译cuda和opencv代码 耗时情况 代码 #include "cuda_runtime.h" #i ...

  7. Cuda学习笔记(一)——sm流处理器簇对blocks的调度策略

    由于GPU目前在各行各业的广泛应用,无论是深度学习.大数据.云计算等都离不开GPU的并行加速,前阵子自学了Cuda-c编程,希望将来的研究工作能够用得上. Cuda系列总共有4篇,这里主要用于记录本人 ...

  8. CUDA学习笔记(1)——腐蚀

    前言 本篇博客是在我学习别人的博客内容上实验出来的,所以大部分并非原创内容,参考地址:秘籍传送. 在此篇博客的基础上,我将其中的程序实验,并自己阅读了一番,下面是具体内容. 主要目标 是对一张转换为灰 ...

  9. 学习笔记10--ASIL分解与冗余功能安全

    本系列博客包括6个专栏,分别为:<自动驾驶技术概览>.<自动驾驶汽车平台技术基础>.<自动驾驶汽车定位技术>.<自动驾驶汽车环境感知>.<自动驾驶 ...

最新文章

  1. 成功解决‘pip‘ 不是内部或外部命令,也不是可运行的程序 或批处理文件
  2. C++操作SQLite简明教程
  3. leetcoed123. 买卖股票的最佳时机 III
  4. PHP代码20个实用技巧(转)
  5. cocos2d-x C++ 原始工程引擎运行机制解析
  6. linux用户名是什么_什么是Linux用户?
  7. docker 镜像导入导出
  8. html5 ios keychain,ios Keychain KeychainItemWrapper
  9. 什么是servlet?servlet有什么用?
  10. SQL Server学习之路(一):建立数据库、建立表
  11. 基于web在线餐饮网站的设计与实现——蛋糕甜品店铺(HTML+CSS+JavaScript)
  12. StudentManageSystem(学生管理系统)
  13. 常用工具软件的交叉编译
  14. 2016大学计算机陈春丽,2016级计算机类专业分流结果公示.PDF
  15. 服务端开发基础知识点
  16. SolrCloud下DIH实践
  17. Widget是一切,Widget简介
  18. 每日新闻丨华为被拘留前员工再回应;亚马逊云发布量子计算服务Braket预览;硅谷“六巨头”10年避税超千亿美元...
  19. python中self image_Python3用tkinter和PIL实现看图工具
  20. 尚硅谷大数据视频_Zookeeper视频教程

热门文章

  1. 如何判断img加载完成?
  2. 虽然分模块了,但是 mapActions 写法,照样可用
  3. 感谢帮我的人们(Revit二次开发)
  4. windows下安装mongodb时报错verify that you have sufficient privileges to start system services解决方法
  5. 移动小工具——利用python进行综合调度班的区县信息处理
  6. Docker下Prometheus和Grafana三部曲之三:自定义监控项开发和配置
  7. 线性代数:第四章 向量组的线性相关性(1)向量组的线性相关性 向量组的秩
  8. win10的c语言程序闪退,win10内置应用出现闪退怎么回事? win10打开应用总闪退的解决方法...
  9. itunes更新系统显示网络连接到服务器,iTunes网络连接被重设怎么办
  10. OCI指南—OCIStmtExecute()函数