Tensor Cores 解密:解锁深度学习新篇章

news2024/11/23 2:19:34

 Tensor Cores 使用介绍

   7d36ba8c413ec39cc956ba1f9c23faa4.jpeg

概要介绍

TensorCore是英伟达GPU自Volta架构起支持的特性,允许CUDA开发者利用混合精度来显著提升吞吐量,且不影响精度。TensorCore在Tensorflow、PyTorch、MXNet和Caffe2等深度学习框架中得到广泛支持,用于深度学习训练。本文阐述了如何使用CUDA库在应用程序中运用TensorCore,以及如何在CUDA C++设备代码中对其进行直接编程。

TensorCore

TensorCore 是一种可编程矩阵乘法和累加单元,带来高达 125 Tensor TFLOPS 的训练和推理性能。它的定制数据路径优化了浮点计算吞吐量。
每个 TensorCore 拥有一个 4x4x4 矩阵处理数组,执行运算 D=A*B+C。A 和 B 是 FP16 矩阵,C 和 D 可以是 FP16 或 FP32 矩阵。

b453fa4586c60c9b43bb8204615391a5.jpeg

凭借每时钟可执行 64 个混合精度浮点 FMA 操作的 8 个 TensorCore,每个流多处理器 (SM) 每时钟可处理 1024 个浮点运算。
TensorCore 使用 FP16 输入进行计算,同时以 FP32 累加。以下图所示,FP16 乘法结果为完整精度值,在 4x4x4 矩阵乘积点积计算中,与其他乘积累加在 FP32 操作中。

9102bdd680e7417ee399b43ef55b3266.jpeg

解锁 GPU 性能:使用 Tensor Cores 提速人工智能计算
借助 cuBLAS 和 cuDNN 库,普通用户可通过 CUDA 技术充分利用 Tensor Cores。
cuBLAS 加速矩阵乘法 (GEMM),而 cuDNN 优化卷积和循环神经网络 (RNN) 计算,提升 AI 模型性能。

cuBLAS中使用TensorCore

通过优化cuBLAS代码充分利用Tensor Cores,仅需对cuBLAS API进行微调。遵循简单规则,如示例代码所示,即可指示cuBLAS使用Tensor Cores。此优化可显著提升AI计算性能。

// First, create a cuBLAS handle:
cublasStatus_t cublasStat = cublasCreate(&handle);

// Set the math mode to allow cuBLAS to use Tensor Cores:
cublasStat = cublasSetMathMode(handle, CUBLAS_TENSOR_OP_MATH);

// Allocate and initialize your matrices (only the A matrix is shown):
size_t matrixSizeA = (size_t)rowsA * colsA;
T_ELEM_IN **devPtrA = 0;

cudaMalloc((void**)&devPtrA[0], matrixSizeA * sizeof(devPtrA[0][0]));
T_ELEM_IN A = (T_ELEM_IN *)malloc(matrixSizeA * sizeof(A[0]));

memset( A, 0xFF, matrixSizeA* sizeof(A[0]));
status1 = cublasSetMatrix(rowsA, colsA, sizeof(A[0]), A, rowsA, devPtrA[i], rowsA);

// ... allocate and initialize B and C matrices (not shown) ...

// Invoke the GEMM, ensuring k, lda, ldb, and ldc are all multiples of 8,
// and m is a multiple of 4:
cublasStat = cublasGemmEx(handle, transa, transb, m, n, k, alpha,
A, CUDA_R_16F, lda,
B, CUDA_R_16F, ldb,
beta, C, CUDA_R_16F, ldc, CUDA_R_32F, algo);

cuBLAS用户将注意到与现有的cuBLAS GEMM代码相比有一些变化:

  • 例程必须是一个GEMM;目前只有GEMM支持Tensor Core执行。
  • 数学模式必须设置为CUBLAS_TENSOR_OP_MATH。
  • Tensor Core 运算要求输入数据按 8 步长跨越,因此矩阵维度须为 8 的倍数:
    * k、lda、ldb、ldc:8 的倍数
    * m:4 的倍数
  • 矩阵的输入和输出数据类型必须是半精度或单精度。
  • 不满足上述规则的GEMM将回退到非Tensor Core实现。

cuDNN中使用TensorCore

在 cuDNN 中轻松使用 Tensor Cores,只需对代码进行简单修改。提高性能,无需大动干戈。

// Create a cuDNN handle:
checkCudnnErr(cudnnCreate(&handle_));

// Create your tensor descriptors:
checkCudnnErr( cudnnCreateTensorDescriptor( &cudnnIdesc ));
checkCudnnErr( cudnnCreateFilterDescriptor( &cudnnFdesc ));
checkCudnnErr( cudnnCreateTensorDescriptor( &cudnnOdesc ));
checkCudnnErr( cudnnCreateConvolutionDescriptor( &cudnnConvDesc ));

// Set tensor dimensions as multiples of eight (only the input tensor is shown here):
int dimA[] = {1, 8, 32, 32};
int strideA[] = {8192, 1024, 32, 1};

checkCudnnErr( cudnnSetTensorNdDescriptor(cudnnIdesc, getDataType(),
convDim+2, dimA, strideA) );

// Allocate and initialize tensors (again, only the input tensor is shown):
checkCudaErr( cudaMalloc((void**)&(devPtrI), (insize) * sizeof(devPtrI[0]) ));
hostI = (T_ELEM*)calloc (insize, sizeof(hostI[0]) );

initImage(hostI, insize);

checkCudaErr( cudaMemcpy(devPtrI, hostI, sizeof(hostI[0]) * insize, cudaMemcpyHostToDevice));

// Set the compute data type (below as CUDNN_DATA_FLOAT):
checkCudnnErr( cudnnSetConvolutionNdDescriptor(cudnnConvDesc,
convDim,
padA,
convstrideA,
dilationA,
CUDNN_CONVOLUTION,
CUDNN_DATA_FLOAT) );

// Set the math type to allow cuDNN to use Tensor Cores:
checkCudnnErr( cudnnSetConvolutionMathType(cudnnConvDesc, CUDNN_TENSOR_OP_MATH) );

// Choose a supported algorithm:
cudnnConvolutionFwdAlgo_t algo = CUDNN_CONVOLUTION_FWD_ALGO_IMPLICIT_PRECOMP_GEMM;

// Allocate your workspace:
checkCudnnErr( cudnnGetConvolutionForwardWorkspaceSize(handle_, cudnnIdesc,
cudnnFdesc, cudnnConvDesc,
cudnnOdesc, algo, &workSpaceSize) );

if (workSpaceSize > 0) {
cudaMalloc(&workSpace, workSpaceSize);
}

// Invoke the convolution:
checkCudnnErr( cudnnConvolutionForward(handle_, (void*)(&alpha), cudnnIdesc, devPtrI,
cudnnFdesc, devPtrF, cudnnConvDesc, algo,
workSpace, workSpaceSize, (void*)(&beta),
cudnnOdesc, devPtrO) );

注意一下与常见cuDNN使用的一些变化:

  • 卷积算法必须为 ALGO_1(前向传播为 IMPLICIT_PRECOMP_GEMM)。
    ALGO_1 以外的算法,未来版本可能启用 Tensor Core 利用。
  • 数学类型必须设置为CUDNN_TENSOR_OP_MATH,与cuBLAS类似.
  • Tensor Core 数学例程每步处理 8 个值,要求输入和输出通道维度为 8 的倍数,与 cuBLAS 一致,确保了最佳性能。
  • 卷积的输入、滤波器和输出数据类型必须是半精度。
  • 不满足上述规则的卷积将回退到非Tensor Core实现。

CUDA C++中使用TensorCore

虽然cuBLAS和cuDNN涵盖了许多Tensor Cores的潜在用途,但用户还可以直接在CUDA C++中编程。Tensor Cores通过nvcuda::wmma命名空间中的一组函数和类型在CUDA 9.0中公开。这些函数和类型允许您将值加载或初始化到张量核心所需的特殊格式中,执行矩阵乘累加(MMA)步骤,并将值存回内存。在程序执行期间,一个完整的warp可以同时使用多个Tensor Cores,这使得warp能够以非常高的吞吐量执行16x16x16的MMA。核心的API如下所示,详细介绍见文档。

template<typename Use, int m, int n, int k, typename T, typename Layout=void> class fragment;

// 等待直到所有warp lanes都到达load_matrix_sync,然后从内存中加载矩阵片段a。
void load_matrix_sync(fragment<...> &a, const T* mptr, unsigned ldm);
void load_matrix_sync(fragment<...> &a, const T* mptr, unsigned ldm, layout_t layout);

// 等待,直到所有warp lanes都到达store_matrix_sync,然后将矩阵片段a存储到内存中。
void store_matrix_sync(T* mptr, const fragment<...> &a, unsigned ldm, layout_t layout);

// 使用常量值v填充一个矩阵片段。
void fill_fragment(fragment<...> &a, const T& v);

// 等待直到所有warp lanes都到达mma_sync,然后执行warp同步的矩阵乘累加操作D = A * B + C。
void mma_sync(fragment<...> &d, const fragment<...> &a, const fragment<...> &b, const fragment<...> &c, bool satf=false);

下面来看个实际的简单例子。

头文件引用

#include <mma.h>
using namespace nvcuda;

声明和定义

GEMM算法优化:
通过分配每个warp处理输出矩阵一个16x16部分,算法有效利用了二维网格和线程块。该策略允许灵活地处理a或b的转置,并支持数据步幅大于矩阵步幅。

// The only dimensions currently supported by WMMA
const int WMMA_M = 16;
const int WMMA_N = 16;
const int WMMA_K = 16;

__global__ void wmma_example(half *a, half *b, float *c,
int M, int N, int K,
float alpha, float beta)
{

// Leading dimensions. Packed with no transpositions.
int lda = M;
int ldb = K;
int ldc = M;

// Tile using a 2D grid
int warpM = (blockIdx.x * blockDim.x + threadIdx.x) / warpSize;
int warpN = (blockIdx.y * blockDim.y + threadIdx.y);

在执行MMA操作之前,操作数矩阵必须表示在GPU的寄存器中。由于MMA是一个warp范围的操作,这些寄存器分布在warp的各个线程之间,每个线程持有整个矩阵的一个fragment。在CUDA中,fragment是一个模板类型,具有描述片段持有的矩阵、整个WMMA操作的形状、数据类型以及A和B矩阵中数据是按行还是按列主序的模板参数。最后一个参数可以用于对A或B矩阵进行转置。这个示例中没有进行转置,所以两个矩阵都是按列主序的,这是GEMM的标准方式。

// Declare the fragments
wmma::fragment<wmma::matrix_a, WMMA_M, WMMA_N, WMMA_K, half, wmma::col_major> a_frag;
wmma::fragment<wmma::matrix_b, WMMA_M, WMMA_N, WMMA_K, half, wmma::col_major> b_frag;
wmma::fragment<wmma::accumulator, WMMA_M, WMMA_N, WMMA_K, float> acc_frag;
wmma::fragment<wmma::accumulator, WMMA_M, WMMA_N, WMMA_K, float> c_frag;

// set o in accumulator fragment
wmma::fill_fragment(acc_frag, 0.0f);

内部循环

我们用于GEMM的策略是每个warp计算输出矩阵的一个tile。为此,我们需要在A矩阵的行和B矩阵的列上进行循环。这沿着这两个矩阵的K维度进行,并生成一个MxN的输出tile。load矩阵函数从内存中获取数据(在这个示例中是全局内存,尽管它可以是任何内存空间),并将其放入一个fragment中。load的第三个参数是矩阵在内存中的“主导维度”;我们加载的16×16 tile在内存中是不连续的,因此函数需要知道连续列(或行,如果这些是按行主序的片段)之间的跨度。MMA调用在原地累积,因此第一个和最后一个参数都是我们之前初始化为零的累加器fragment。

// Loop over the K-dimension
for (int i = 0; i < K; i += WMMA_K) {
int aRow = warpM * WMMA_M;
int aCol = i;
int bRow = i;
int bCol = warpN * WMMA_N;

// Bounds checking
if (aRow < M && aCol < K && bRow < K && bCol < N) {
// Load the inputs
wmma::load_matrix_sync(a_frag, a + aRow + aCol * lda, lda);
wmma::load_matrix_sync(b_frag, b + bRow + bCol * ldb, ldb);

// Perform the matrix multiplication
wmma::mma_sync(acc_frag, a_frag, b_frag, acc_frag);
}
}

结果写回

现在,acc_frag根据A和B的乘积持有了这个warp输出tile的结果。完整的GEMM规范允许对这个结果进行缩放,并且可以就地累积到一个矩阵上。进行这种缩放的一种方法是对fragment执行逐元素操作。尽管从矩阵坐标到线程的映射未定义,但逐元素操作不需要知道这种映射,因此仍然可以使用片段执行这些操作。因此,对fragment执行缩放操作或将一个fragment的内容添加到另一个fragment中是合法的,只要这两个fragment具有相同的模板参数。利用这个特性,我们加载了C中的现有数据,并在正确的缩放下将计算结果迄今为止与之累积。

数据存储于内存中,目标指针可指向 GPU 可见的内存空间。主导维度必须指定,此外可选择按行或列主序写入输出。

// Load in current value of c, scale by beta, and add to result scaled by alpha
int cRow = warpM * WMMA_M;
int cCol = warpN * WMMA_N;

if (cRow < M && cCol < N) {
wmma::load_matrix_sync(c_frag, c + cRow + cCol * ldc, ldc, wmma::mem_col_major);

for(int i=0; i < c_frag.num_elements; i++) {
c_frag.x[i] = alpha * acc_frag.x[i] + beta * c_frag.x[i];
}
// Store the output
wmma::store_matrix_sync(c + cRow + cCol * ldc, c_frag, ldc, wmma::mem_col_major);
}
}

总结

TensorCore 通过其 API wmma 实现了 warp 级并行矩阵运算。与常规 CUDA C 相比,wmma API 可利用线程寄存器 (GPR) 和 TensorCore 硬件加速运算。所有 API 函数均以 "sync" 结尾,表明所有线程在 TensorCore 操作完成前处于同步状态。
尽管 cuBLAS 和 cuDNN 通常足以满足矩阵运算需求,但直接使用 wmma API 可在某些情况下提供性能优势。

&nbsp;

-对此,您有什么看法见解?-

-欢迎在评论区留言探讨和分享。-

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

VBA在Excel中注册登录界面的应用

Excel工作表也可以做一个小程序,登录注册后可以访问或修改。为了简便,没有做复杂的控件,能说明问题就行。可以根据需要添加更多的判断条件,控制注册和访问人数。本次操作对注册没有任何限制,只要注册后就可以根据注册的账号和密码进行访问和修改。注册登录界面截图: 操作…

Anatomical-Aware Point-Voxel Network for Couinaud Segmentation in Liver CT

文章目录 Anatomical-Aware Point-Voxel Network for Couinaud Segmentation in Liver CT摘要方法实验结果 Anatomical-Aware Point-Voxel Network for Couinaud Segmentation in Liver CT 摘要 在 CT 成像中&#xff0c;将肝脏准确分割为解剖片段对于手术规划和病变监测至关…

web前端学习笔记7-iconfont使用

7. iconfont的使用流程 字体图标使用较多的是阿里巴巴iconfont图标库,它是阿里巴巴体验团队推出的图标库和图标管理平台,提供了大量免费和可定制的矢量图标,以满足网页设计、平面设计、UI设计、应用程序开发和其他创意项目的需求。 官方网站:https://www.iconfont.cn/ 使用…

【Git管理工具】使用Docker+浪浪云服务器部署GitLab服务器

一、什么是GitLab 1.1.GitLab简介 GitLab 是一个开源的 DevOps 平台&#xff0c;它基于 Git 版本控制系统提供了从项目规划、源代码管理到持续集成、持续部署、监控和安全的完整生命周期管理。GitLab 是一个为开发者提供协作工作的工具&#xff0c;它使得团队能够高效地在同一…

海洋行业工业气体检测传感器的重要性

海洋行业是一个广阔而复杂的领域&#xff0c;涉及多个分支和应用&#xff0c;包括浮式生产、储存和卸载&#xff08;FPSO&#xff09;装置、渡轮和潜艇等。这些船舶和设施在执行任务时&#xff0c;都可能遇到各种潜在的气体危害。因此&#xff0c;对于海洋行业来说&#xff0c;…

Redis系列之key过期策略介绍

为什么要有过期策略&#xff1f; Redis是一个内存型的数据库&#xff0c;数据是放在内存里的&#xff0c;但是内存也是有大小的&#xff0c;所以&#xff0c;需要配置redis占用的最大内存&#xff0c;主要通过maxmemory配置 maxmomory <bytes> # redis占用的最大内存官…

python中一些莫名其妙的异常

目录 一、字符串中空格\xa0二、文件写入为空问题三、Counter对NAN空值的统计问题 一、字符串中空格\xa0 对于文本中的一些空格&#xff0c;原始状态时显示为普通“空格”&#xff08;其实是latin1编码字符&#xff09;&#xff0c;但是经过split()操作后&#xff0c;这些latin…

如何用道氏理论进行炒现货白银的技术分析?

要炒现货白银&#xff0c;就要对白银价格进行技术分析。进行炒白银的技术分析&#xff0c;目的是让投资者通过对白银价格图表的分析&#xff0c;判断白银市场趋势&#xff0c;进而寻找入场交易的机会。 道氏理论不光是一种技术分析的理论&#xff0c;它还被称为技术分析的鼻祖。…

【XR806开发板试用】阻塞式串口发送与接收教程

本文基于wsl2搭建的ubuntu18.04 vscode编辑器 很奇怪啊&#xff0c;找了半天居然没人发串口的教程&#xff0c;于是只能自己试一试了&#xff0c;在此发一个阻塞式的串口发送与接收的教程。并且&#xff0c;感谢.ACE彭洪权大佬在我配置环境遇到几十个报错的时候帮我远程搭建环…

H3C Private VLAN实验

Private VLAN 实验1 实验需求 按照图示配置 IP 地址 在 SW1 上配置 Private VLAN&#xff0c;Primary VLAN 为 Vlan30&#xff0c;Secondary VLAN 为 Vlan10 和 Vlan20 SW2 通过 Vlan100 下行连接 SW1&#xff0c;要求 PC3 和 PC4 都能以 Vlan100 访问 PC5 在 SW1 上配置 …

给网站网页PHP页面设置密码访问代码

将MkEncrypt.php文件上传至你网站根目录下或者同级目录下。 MkEncrypt.php里面添加代码&#xff0c;再将调用代码添加到你需要加密的页进行调用 MkEncrypt(‘123456’);括号里面123456修改成你需要设置的密码。 密码正确才能进去页面&#xff0c;进入后会存下cookies值&…

java接受入参是xml格式参数demo

java接受入参是xml格式参数demo 依赖demo1. xml入参定义2.接口定义3. postman请求4. 结果 注解说明 依赖 pom依赖 jackson-dataformat-xml <dependency><groupId>com.fasterxml.jackson.dataformat</groupId><artifactId>jackson-dataformat-xml</…

RCLAMP0854P.TCT ESD抑制器 静电和浪涌保护 应用领域

RCLAMP0854P.TCT 是一款电路保护器件&#xff0c;属于Transient Voltage Suppressor (TVS) 系列产品。它是一种低电容TVS阵列&#xff0c;具有 RailClamp 标志性技术&#xff0c;旨在为电子设备提供高效防护&#xff0c;免受高电压瞬变和静电放电&#xff08;ESD&#xff09;的…

uni-app 超详细教程( 附送250套精选项目源码)

一&#xff0c;uniapp 介绍 &#xff1a; 官方网页 uni-app 是一个使用 Vue.js 开发所有前端应用的框架&#xff0c;开发者编写一套代码&#xff0c;可发布到iOS、Android、Web&#xff08;响应式&#xff09;、以及各种小程序&#xff08;微信/支付宝/百度/头条/飞书/QQ/快手/…

信息泄露中的目录遍历,phpinfo,备份文件下载

一、目录遍历漏洞 1.什么是目录遍历漏洞 指的是在没有授权的情况下读取文件&#xff0c;某些情况下还可对服务器里的文件任意写入 2.目录遍历漏洞成因 网站配置存在缺陷&#xff0c;对输入目录缺少验证&#xff0c;没过滤../之类的目录跳转符&#xff0c;可通过提交目录跳转…

速卖通新卖家测评攻略:从入门到精通

在电商行业中&#xff0c;测评被广泛认为是提升产品转化率和销量的有效手段。对于速卖通的卖家而言&#xff0c;测评的必要性更是显而易见。测评&#xff0c;本质上与国内电商的补单行为相似&#xff0c;是一种通过增加销量来提升产品权重的方法。 特别是在竞争激烈的类目中&a…

【触摸案例-手势解锁案例-按钮高亮 Objective-C语言】

一、我们来说这个self.btns,这个问题啊,为什么不用_btns, 1.我们说,在懒加载里边儿,经常是写下划线啊,_btns,为什么不写,首先啊,这个layoutSubviews:我们第一次,肯定会去执行这个layoutSubviews: 然后呢,去懒加载这个数组, 然后呢,接下来啊,走这一句话, 第一次…

使用 Gitea 进行私有 Git 仓库管理

在本文中&#xff0c;我们将介绍如何使用 Gitea 搭建并管理私有 Git 仓库。Gitea 是一个轻量级的 Git 服务&#xff0c;提供了类似于 GitHub 的功能&#xff0c;适合个人和小团队使用。我们将通过以下步骤来完成搭建和配置 Gitea 服务器。 步骤一&#xff1a;安装 Gitea 首先…

关于Checkmarx、CodeQL和Semgrep的测试结果比较

关于Checkmarx、CodeQL和Semgrep的测试结果比较 随着SAST工具的不断的推陈出新&#xff0c;为了比较一些新的工具是否能够提供更好的扫描结果&#xff0c;针对Checkmarx、CodeQL以及Semgrep几个工具进行了测试评估&#xff0c;具体的评估结果仅供参考。本文列列举了工具的各个方…

SAP生产订单常用状态以及

常用系统状态&#xff1a; 状态 状态 CRTD 已建立 REL 已核发 CNF 已确认 PCNF 已部份确认 DLV 已交货 DLT 删除指示码 LKD 已锁住 TECO 技术完成 GMPS 已发料 关闭 关闭 工单结案前的生产报表分析 路径:后勤系统- 生产- 现场控制- 信息系统-订单信息系…