【GPU】GPU CUDA 编程的基本原理是什么?

【GPU】GPU CUDA 编程的基本原理是什么?

作者:董鑫

想学好 CUDA 编程, 第一步就是要理解 GPU 的硬件结构, 说到底, CUDA 的作用就是最大程度压榨出 NVIDIA GPU 的计算资源.

想要从零理解起来, 还有有些难度. 这里希望能够用最简单的方式把一些最基本的内容讲清楚. 所以, 本文以易懂性为主, 牺牲了一些完全准确性.

GPU 结构

这是 GPU 的基本结构. CUDA 编程主打一个多线程 thread.

多个 thread 成为一个 thread block, 而 thread block 就是由这么一个 Streaming Multiprocessor (SM) 来运行的.

CUDA 编程中有一个 “同一个 block 内的 thread 共享一段内存”. 这恰好对应上图下面的那段 “Shared Memory”.

另外, 一个 SM 里面有多个 subcore (本图中有 4 个), 每个 subcore 有一个 32 thread 的 warp scheduler 和 dispatcher, 这个是跟 CUDA 编程中 warp 的概念有关的.

另外, 我们还要理解 GPU 的金字塔状的 Memory 结构.

最快的是 register, 但是非常小.

其次是 l1 cache, 也就是前面提到的 shared memory.

Global memory 就是我们常说的 显存 (GPU memory). 其实是比较慢的.

Global memory 和 shared memory 之间是 L2 cache, L2 cache 比 global memory 快. 每次 shared memory 要到 global memory 找东西的时候, 会去看看 l2 cache 里面有没有, 有的话就不用去 global memory 了.

有的概率越大, 我们说 memory hit rate 越高, CUDA 编程的一个目的也是要尽可能提高 hit rate. 总的来说,

我们就是希望能够尽可能多的利用比较快的 SRAM (shared memory). 但是因为 SRAM 比较小, 所以基本原则就是: 每次往 SRAM 移动数据的, 都可能多的用这个数据. 避免来来回回的移动数据.

其实, 这种 idea 直接促成了最近大火的 FlashAttention. FlashAttention 发现很多操作计算量不大, 但是 latency 很高, 那肯定是不符合上述的 “每次往 SRAM 移动数据的”. 怎么解决呢?

Attention 基本上是由 matrix multiplication 和 softmax 构成的. 我们已经知道了 matrix multiplication 是可以分块做的, 所以就剩下 softmax 能不能分块做? softmax 其实也是可以很简单的被分块做的. 所以就有了 FlashAttention. 关于 GPU Architecture 更进一步细节推荐大家看这个:

https://www.youtube.com/watch?v=Na9_2G6niMw&t=1166s

一些跟 CUDA 有关的库

首先先理一下 NVIDIA 那么多库, 他们之间到底是什么关系?

这里以三个库为例 CuTLASS , CuBLAS, CuDNN .

从名字看, 他们都是用 CUDA 写出来的.总结起来, 他们之间的区别就是封装程度不同, 专注的领域不同.

CuTLASS 和 CuBLAS 都是比较专注于最基本的线性代数的运算的, 比如 矩阵乘法, 矩阵加法, 等等.

而 CuDNN 则是更进一步, 将关注点落在了 Deep Neural Network 上面了. 比如, DNN 中非常常见的 convolution 操作, 是通过 矩阵乘法 来实现的.

那么, CuDNN 做的工作更像是, 完成从 convolution 到 矩阵乘法 的转换, 转换之后, 就可以复用 CuTLASS 或者 CuBLAS 来做.

当前, DNN 里面不全都是矩阵乘法, 遇到一些特殊的算子, CuDNN 也会自己实现一些.而 CuTLASS 和 CuBLAS 之间的区别, 更像是”傻瓜程度” 不同.

CuBLAS 可以理解成 英伟达 给你找了一堆傻瓜相机, 每个相机都针对某个非常非常具体的场景优化到了极致, 你唯一要做的就是根据你的场景找到最适合相机.

因为每个相机已经被写死了, 你不知道英伟达到底做了什么黑魔法优化, 你也没办法去根据想法进一步修改.

虽然 CuBLAS 闭源, 不灵活, 但是只要场景找对了, 效果确实拔群.

而 CuTLASS 是一个模板库, 相当于有这么一些不同 系列 的相机, 有拍夜景, 拍近景的, 等等. 当然, 就夜景而言, 肯定还有各种不同场景, 对应不同配置可以尝试. 在 CuTLASS 你可以尝试不同的配置, 直到你满意为止.

矩阵乘法 (CuTLASS)

假设做 GEMM (general matrix multiplication), 我们以 CuTLASS 里面的实现来讲解

C = A * B

A 是 M x K

B 是 K x N

这张图的信息量很大.

1. 第一部分:

是关于如何拆分一个大矩阵乘法到多个小矩阵乘法. 也就是说, 这段时间我们就 focus on 某个小矩阵的计算. 其他部分我们不管.

这样, 因为不同小矩阵之间是完全独立的, 就可以很容易实现并行.

具体来说 也是需要多次紫色和黄色部分的矩阵乘法. 紫色从左到右滑动, 黄色从上到下滑动. 他们的滑动的次数是完全一样.

他们每滑动一次, 就是一次矩阵乘法(及加法, 因为要把乘出来的结果加到之前的结果之上). 下图是滑动到某个位置的情况.

之所以绿色部分没有高亮, 是因为要把所有都滑动完, 才能得到最终绿色部分的结果.


2. 第二部分:

先忽略绿色部分.注意, 这紫色的一整行和黄色的一整列都是由一个 thread block 处理的.为什么? 因为他们都要在同一块 C tile 上面累加.

如果切换 thread block 的话, 就会比较麻烦.理论上来说, 紫色的一整行和黄色的一整列都要被 load 到 shared memory.

但是, 因为我们每次只会用到 紫色高亮部分 和 黄色高亮部分, 所以完全可以声明一块小内存, 每次只 load 一小块 (A tile and B tile), 用完之后就可以覆盖掉, 用来 load 下一个滑动位置.具体到某一次滑动,

把 紫色高亮部分 (A tile) 和 黄色高亮部分 (B tile) 从 global memory 移动到 shared memory (SMEM).接下来要做的就是计算 A tile * B tile, 然后把结果累加到 C tile 上面.好了, 现在我们明确两点:A tile 和 B tile 都在 shared memory 了.

也就是说, thread block 里面的每一个 thread 都可以看到 A tile 和 B tile.A tile 和 B tile 每次窗口滑动是需要重新 load 的,

但是 C tile 每次窗口滑动是需要在原来的基础上更新的.因为 C tile 一直需要更新, 而且这个更新是计算驱动的 (不是 load 驱动的),

所以我们最好把 C tile 放到 register (RF) 里面去. register 是一种比 shared memory 更快的内存, 而且 register 是跟 thread 相关的.

其实计算的时候, A tile 和 B tile 也必须从 shared memory 被 load 到 register. 只是 C tile 一直待在 register 里面等待被更新.


3. 第三部分:

刚刚讲了, 我们需要把 C tile held 在 register, 而 register 有是跟具体某个 thread 是关联的. 所以我们自然需要根据 thread 再来划分 C tile.

但是, CUDA 其实在 thread 和 thread block 还有一层叫做 warp. 我们可以暂时理解把 warp 一种计量单位: 1 warp = 32 thread.在上述例子中, 一个 thread block 被分成了八个 warp.每个 warp 承担了 C tile 中的 16*8 个数字.

假设每个数字是 32bit, 那么恰好是一个 register 的容量.那么, 也就是说, 我们需要 16*8 个 registers. 前面讲了一个 warp 是 32 thread. 这并不矛盾. 因为一个 thread 可以配有多个 registers.

但是, 某个 thread 是不定访问 其他 thread 的 register 的. CUDA 之所以这么限制, 主要原因还是 thread 之间做 sync 太复杂.这里, 要算一个 warp 对应的结果, 还是跟前面的讲的一样. 横向滑动紫色高亮块, 纵向滑动黄色高亮块,

每次滑动, 都是将当前高亮块从 shared memory load 到 register 中, 计算矩阵乘法 (虽然看着像向量, 但是不一定是向量), 然后累加到 C warp tile 上面. 正如前面所说, C warp tile 一直都是在 register 上面的.


4. 第四部分:

最终, 还是要落到单个 thread 上面.

这里的 Warp tile 代表这一整个 tile 都是由一个 Warp 完成的.先看左上角灰色的部分, 后面的内容也是在这个灰色的部分.数一下, 恰好是 32 个格子.

而我们知道一个 Warp 是 32 个 thread. 也就是说, 一个 thread 处理一个灰色的格子. 这 32 个格子中, 有一个绿色的格子 (先不要看另外三个绿色的),

这个绿色的格子就是我们现在要讨论的 32 个 thread 中的某个 thread.实际上, 这个绿色的格子里面有 16 个数, 也就说是一个 44 的迷你矩阵.

也就说, 一个 thread 要处理这样一个 44 的矩阵. 那么, 既然想得到这样 44 的矩阵, 就需要读入 41 的紫色部分, 1*4 的黄色部分.

好, 现在我们可以跳出左上角灰色部分了. 我们发现这个 Warp tile 还有剩下三个部分, 但是在左上角灰色部分我们已经这个 Warp 中 32 个 thread 用过一遍了, 怎么办?

谁说 Warp 只能用一遍? 完全可以让这个 Warp keep alive, 再如法炮制地去分别按顺序处理 (所以这里其实在时间上不是并行的) 剩下的三个部分.这个时候, 我们再看一个thread的工作量.

首先, 一个 thread 要被用 4 次, 然后每次要处理 4x4 的迷你矩阵,

所以总的来看, 一个 thread 相当于处理了一个 8x8 的矩阵. 这就是上图右边想表达的意思.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/351267.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

03 Redis之命令(基本命令+Key命令)

Redis 根据命令所操作对象的不同,可以分为三大类:对 Redis 进行基础性操作的命令,对 Key 的操作命令,对 Value 的操作命令。 3.1 Redis 基本命令 首先通过 redis-cli 命令进入到 Redis 命令行客户端,然后再运行下面的…

【Linux 基础】常用基础指令(上)

文章目录 一、 创建新用户并设置密码二、ls指令ls指令基本概念ls指令的简写操作 三、pwd指令四、cd指令五、touch指令六、rm指令七、mkdir指令八、rmdir 指令 一、 创建新用户并设置密码 ls /home —— 查看存在多少用户 whoami —— 查看当前用户名 adduser 用户名 —— 创建新…

【Uni-App】Vuex在vue3版本中的使用与持久化

Vuex是什么 Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。 简而言之就是用来存数据,可以有效减少使用组件传参出现的问题。 基本元素:…

Java变量命名规则

目录 变量完整代码变量的声明变量的赋值变量的使用 变量的内存练习 分析 变量的作用域 变量 变量本质上就是代表一个”可操作的存储空间”,空间位置是确定的,但是里面放置什么值不确定。我们可通过变量名来访问“对应的存储空间”,从而操纵这…

青少年人工智能实验基地解决方案

1. 方案背景 1.1人工智能创新教育解决方案背景 人工智能已成为引领未来的新兴技术,中国将人工智能列为国家重点发展战略,对人工智能的发展做出了总体部署,全面加速人工智能在研发应用和人才培养的步伐。2021年1月教育部官网公布《关于政协十…

无状态应用管理Deployment

无状态应用管理Deployment 1、Deployment介绍 Deployment一般用于部署公司的无状态服务。 格式: apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment labels: app: nginx spec: replicas: 3 selector: matchLabels: app: nginx …

windows定时任务的查看、取消、启动和创建

一、查看 Windows 自动执行的指令 1.使用任务计划程序:任务计划程序是 Windows 内置的工具,可以用于创建、编辑和管理计划任务。您可以按照以下步骤查看已设置的计划任务: 1.1 按下 Win R 键,然后输入 “taskschd.msc”&#xff…

网络变压器的工作原理

Hqst华强盛导读:网络变压器是一种用于变换电压的电气设备,其工作原理基于电磁感应定律。网络变压器通常由两个或多个线圈和一个共同的铁芯组成。 当网络变压器的输入端施加一个交流电压时,主线圈中的电流会产生一个交变磁场。这个磁场会穿过铁…

1.26学习总结

连通性判断 DFS连通性判断步骤: 1.从图上任意一点u开始遍历,标记u已经走过 2.递归u的所有符合连通条件的邻居点 3.递归结束,找到了的所有与u的连通点,就是一个连通块 4.然后重复这个步骤找到所有的连通块 BFS连通性判断步骤…

SQL查询数据库环境(dm8达梦数据库)

SQL查询数据库环境dm8达梦数据库 环境介绍 环境介绍 某些环境没有图形化界面,可以使用sql语句查询达梦数据库环境情况 SELECT 实例名称 数据库选项,INSTANCE_NAME 数据库选项相关参数值 FROM V$INSTANCE UNION ALL SELECT 授权用户,(SELECT AUTHORIZED_CUSTOMER FROM V$LICE…

Kafka-服务端-PartitionStateMachine

PartitionStateMachine是Controller Leader用于维护分区状态的状态机。分区的状态是通过PartitionState接口定义的,它有四个子类分别代表了分区四种可能的状态,如表所示。 分区各个PartitionState之间的转换如图所示。 下面分析各个状态之间转换时&#…

梯度下降法、模拟训练、拟合二次曲线、最小二乘法、MSELoss、拟合:f(x)=ax^2+bx+c

本文目标: 以这个公式为例,设计一个算法,用梯度下降法来模拟训练过程,最终得出参数a,b,c 原理介绍 目标函数: 损失函数:,就是mse 损失函数展开: 损失函数对a,b,c求导数: 导数就是梯度…

JavaScript高级:闭包

1 概念 一个函数对周围状态的引用,捆绑在一起,内层函数中可以访问到外层函数的作用域。 简单理解:闭包 内层函数 外层函数的变量 先看个简单的代码: function outer() {let a 1function inner() {console.log(a)} } outer(…

tee漏洞学习-翻译-1:从任何上下文中获取 TrustZone 内核中的任意代码执行

原文:http://bits-please.blogspot.com/2015/03/getting-arbitrary-code-execution-in.html 目标是什么? 这将是一系列博客文章,详细介绍我发现的一系列漏洞,这些漏洞将使我们能够将任何用户的权限提升到所有用户的最高权限 - 在…

重磅!讯飞星火V3.5马上发布!AI写作、AI编程、AI绘画等功能全面提升!

讯飞星火大模型相信很多友友已经不陌生了,可以说是国内GPT相关领域的龙头标杆,而对于1月30日即将在讯飞星火发布会发出的V3.5新版本来说,讯飞星火V3.5与之前版本相比,性能提升方面相当明显,在提示语义理解、内容生成、…

Java项目:15 springboot vue的智慧养老手表管理系统

作者主页:源码空间codegym 简介:Java领域优质创作者、Java项目、学习资料、技术互助 文中获取源码 项目介绍 本系统共分为两个角色:家长,养老院管理员 框架:springboot、mybatis、vue 数据库:mysql 5.7&…

【幻兽帕鲁】开服务器,高性能高带宽(100mbps),免费!!!【学生党强推】

【幻兽帕鲁】开服务器,高性能高带宽(100mbps),免费!!!【学生党强推】 教程相关视频地址:https://www.bilibili.com/video/BV16e411Y7Fd/ 目前幻兽帕鲁开服务器有以下几套比较性价比的…

【计算机图形学】实验五 一个简单的交互式绘图系统(实验报告分析+截图+源码)

可以先看一看这篇呀~【计算机图形学】专栏前言-CSDN博客https://blog.csdn.net/m0_55931547/article/details/135863062 目录 一、实验目的 二、实验内容

docker-compose部署单机ES+Kibana

记录部署的操作步骤 准备工作编写docker-compose.yml启动服务验证部署结果 本次elasticsearch和kibana版本为8.2.2 使用环境:centos7.9 本次记录还包括:安装elasticsearch中文分词插件和拼音分词插件 准备工作 1、创建目录和填写配置 mkdir /home/es/s…

杰理方案——WIFI连接物联网配置阿里云操作步骤

demo——DevKitBoard 注意:最好用这个Demo,其它Demo可能会有莫名其妙的错误问题。 wifi配置 需要在app_config.h文件中定义USE_DEMO_WIFI_TEST,工程会在wifi_demo_task.c文件中自动启动wifi相关的任务, 我们将工程配置为连接外部网络STA模式 默认工程会使用如下账号密码 这…
最新文章