将Tensor核心引入标准Fortran
将Tensor核心引入标准Fortran
调优的数学库是从HPC系统提取最终性能的一种简单而可靠的方法。但是,对于寿命长的应用程序或需要在各种平台上运行的应用程序,为每个供应商或库版本调整库调用可能是维护的噩梦。
可以自动生成对调优数学库的调用的编译器为提供了两全其美的优势:易于移植和终极性能。在本文中,将展示如何在GPU上无缝加速许多标准Fortran数组内在函数和语言构造。nvfortran编译器通过将Fortran语句映射到NVIDIA cuTENSOR库中的可用功能来自动启用此加速,该库是NVIDIA cuTENSOR的先河,提供GPU加速的张量线性代数库,提供张量收缩,缩小和逐元素运算。
轻松过渡到NVIDIA GPU
以下是标准Fortran数组内在函数如何映射到GPU加速的数学库。在最简单的级别上,只需要两个Fortran语句即可利用cuTENSOR库提供的出色性能:
使用cutensorex
...
c = matmul(a,b)
使用cutensorex预定义模块的第一条语句以重载的Fortran内在过程,数组表达式和重载的赋值形式包含cuTENSOR库的接口。编写接口以仅映射位于GPU设备内存中的阵列。在本文的稍后部分,将从OpenACC和CUDA Fortran程序员的角度讨论这意味着什么。定义了这些接口后,包含matmul()内部调用的第二条语句将自动映射到cuTENSOR函数调用。
这些接口通过识别并匹配可以映射到单个cuTENSOR内核调用的几种常用模式来实现延迟执行。在所有情况下,都将调用多个cuTENSOR函数来设置cuTENSOR所需的句柄,描述符数据结构和工作缓冲区。
但是,只有一个内核被启动到GPU。出于性能考虑,将整个语句(包括分配给左侧数组)映射起来很重要。不希望编译器为右侧操作的输入或结果(中间或最终)创建Fortran中常见的临时数组。
支持的标准Fortran操作
cuTENSOR库包含常规的排列和收缩操作。置换的结果可以可选地通过元素函数来操作,并且可选地缩放。
nvfortran编译器可以识别和映射与通用数组语法结合使用的各种Fortran转换内在函数和基本内在函数,并将其映射到cuTENSOR功能。一些更直接的翻译包括:
d =转置(a)
d =函数(transpose(a))
d = alpha * func(转置(a)
d =重塑(a,shape = [...])
d =重塑(a,shape = [...],order = [...])
d =函数(reshape(a,...))
d = alpha * func(reshape(a,...))
d =点差(a,dim = k,ncopies = n)
d =函数(spread(a,dim = k,ncopies = n))
d = alpha * func(spread(a,dim = k,ncopies = n))
matmul()也可以在cuTENSOR中排列to的输入,并且可以缩放和累加结果。这导致几种可能的组合,例如以下语句:
c = matmul(a,b)
c = c + matmul(a,b)
c = c-matmul(a,b)
c = c + alpha * matmul(a,b)
d = alpha * matmul(a,b)+ beta * c
c = matmul(转置(a),b)
c = matmul(reshape(a,shape = [...],order = [...]),b)
c = matmul(a,转置(b))
c = matmul(a,reshape(b,shape = [...],order = [...]))
使用标准Fortran中的NVIDIA Tensor Core
当使用cutensorex模块中包含的用于随机数生成的功能时,利用cuTENSOR和NVIDIA Tensor Core就像下面的代码示例一样容易:
程序主体
使用cutensorex
整数,参数:: ni = 5120,nj = 5120,nk = 5120,ntimes = 10
实数(8),可分配,尺寸(:,:) :: a,b,d
分配(a(ni,nk),b(nk,nj),d(ni,nj))
呼叫random_number(a)
呼叫random_number(b)
d = 0.0d0
打印*,“裁切器”
呼叫cpu_time(t1)
做nt = 1,ntimes
d = d + matmul(a,b)
做完
呼叫cpu_time(t2)
拖鞋= 2.0 * ni * nj * nk
翻牌=翻牌* n次
打印*,“ times”,t2,t1,t2-t1
打印*,“ GFlops”,flops /(t2-t1)/1.e9
结束程序
该matmul()固有调用映射到cuTENSOR调用,无缝地使用张量核尽可能。将在本文后面显示一些性能结果。
使用nvfortran编译程序
可能会问, cutensorex接口仅将GPU设备阵列上的操作映射到cuTENSOR调用时,该程序如何使用cuTENSOR 。答案在于程序的编译方式:
%nvfortran -acc -gpu =托管-cuda -cudalib main.f90
在这里,将程序编译为OpenACC程序,并利用OpenACC托管内存模式,在该模式下,所有可分配阵列都分配在CUDA统一内存中。由于增加了-cuda,使CUDA Fortran扩展为好,数组实质上CUDA Fortran语言-管理型阵列。CUDA Fortran通用接口匹配的一条规则是,当主机和设备接口同时存在时,优选使用设备接口作为托管实际参数。
当声明,分配和使用位于同一程序单元中时,nvfortran编译器提供一些快捷方式。通常,最好使用OpenACC指令来指示编译器传递设备地址,如以下代码示例所示:
!$ acc host_data use_device(a,b,d)
做nt = 1,ntimes
d = d + matmul(a,b)
做完
!$ acc结束host_data
在这种情况下,-cuda不需要编译器选项。
使用CUDA Fortran中的cuTENSOR
对于CUDA Fortran用户而言,cutensorex模块和Fortran转换内在函数成为获取高性能和完全可移植代码的快速途径。使用!@cuf前哨添加由nvfortran CUDA Fortran编译器解释和编译的代码行,或由标准Fortran编译器作为注释忽略的代码行:
程序主体
!@cuf使用cutensorex
!@cuf使用cudafor
整数,参数:: ni = 5120,nj = 5120,nk = 5120,ntimes = 10
实数(8),可分配,尺寸(:,:) :: a,b,d
!@cuf属性(设备):: a,b,d
分配(a(ni,nk),b(nk,nj),d(ni,nj))
呼叫random_number(a)
呼叫random_number(b)
d = 0.0d0
打印*,“裁切器”
呼叫cpu_time(t1)
做nt = 1,ntimes
d = d + matmul(a,b)
做完
呼叫cpu_time(t2)
拖鞋= 2.0 * ni * nj * nk
翻牌=翻牌* n次
打印*,“ times”,t2,t1,t2-t1
打印*,“ GFlops”,flops /(t2-t1)/1.e9
结束程序
在第6行,使用设备属性声明了数组,将其放置在GPU设备内存中。但是,也可以使用托管属性来声明它。可以编译该程序并将其与以下命令链接:
%nvfortran -Mcudalib main.cuf
实测(8)数据的性能
下面是从前面示例中使用的real(8)(双精度)数据开始的性能观察。可以通过以下几种方法来衡量矩阵乘法性能:
- 单线程CPU实现
- 多线程或多核CPU实现
- 天真编码矩阵乘法使用指令分载
- 该
matmul()映射到cuTENSOR内在
为了获得最佳的线程CPU性能,请使用基本的线性代数子程序(BLAS)库例程DGEMM。以下命令与先前操作的等效DGEMM调用:
呼叫dgemm('n','n',ni,nj,nk,1.0d0,a,ni,b,nk,1.0d0,d,ni)
为了了解经过调整的库可以通过天真的实现提供什么,使用以下OpenACC循环结构在GPU上运行。循环结构不使用特殊的拼贴或硬件指令。
$ acc内核
做j = 1,nj
是否等于1,ni
做k = 1,nk
d(i,j)= d(i,j)+ a(i,k)* b(k,j)
做完
做完
做完
$ acc结束内核
表1显示了real(8)在基于双插槽AMD EPYC 7742 Rome CPU的服务器,单个NVIDIA V100和单个NVIDIA A100 GPU的一个NUMA节点上获得的性能。

表1.双插槽AMD EPYC 7742 Rome基于CPU的服务器,单个V100和单个A100 GPU在一个NUMA节点上的real(8)性能。
不仅可以使用matmul()固有函数在V100和A100 GPU上获得自动GPU加速,而且在A100上matmul()到cuTENSOR调用的映射可以使自动使用FP64 Tensor Core。
在real(4)和real(2)数据上测得的性能
可以使用real(4)(单精度)数据并调用SGEMM而不是DGEMM来执行同一组运行。此外,CUDA 11.0 cuTENSOR Fortran包装器可以利用A100 TF32数据类型和Tensor Core。表2显示了这些运行的性能。

表2.双插槽AMD EPYC 7742 Rome基于CPU的服务器,单个V100和单个A100 GPU的一个NUMA节点上的real(4)性能。
为什么停在那里?nvfortran编译器使用real(2)数据类型支持16位浮点格式(FP16)。可以在较早的测试中更改数组的类型,并以半精度运行计时。
Tensor Core操作是在V100上引入的,用于半精度数据,然后在A100 GPU上进行了扩展,以支持TF32和完整的双精度DP64 Tensor Core。尽管nvfortran支持real(2)V100和A100上的Tensor Core,但它不支持real(2)CPU上的完整和优化,标准BLAS库也不支持。在这种情况下,只有比较GPU加速版本的性能才有意义(表3)。

表3.单个V100和单个A100 GPU的real(2)性能。
尽管A100的性能令人印象深刻且代码可完全移植,但它远低于TF32和FP16的峰值。有固定的开销:在每个调用中,创建并销毁cuTENSOR张量描述符并创建收缩计划。还必须查询和管理收缩中使用的工作空间要求,这最终可能会调用cudaMalloc和cudaFree。如果FP64的开销为5 – 10%,则对于这种大小的问题,TF32的开销将接近25%,FP16的开销将接近35%。
对于需要最终性能的开发人员,nvfortran确实支持HPC SDK中也提供的Fortran cutensor模块中与C cuTENSOR API的Fortran接口。可以自己管理张量描述符,计划和工作区。
结论
在本文中,展示了一些简单的程序以及可以在GPU上自动加速的Fortran内部调用和代码模式的类型。甚至可以通过cuTENSOR自动利用Tensor Core。使用几乎完全是Fortran标准的程序并完全可移植到其编译器和系统的程序,可以在NVIDIA GPU上实现矩阵乘法,矩阵转置,元素数组内在函数以及数组语法的多种组合的近峰性能。
无法预测使用这些新功能可能会做什么。期待着的反馈和结果。NVIDIA继续添加更多功能,使可以使用标准的Fortran结构以最高的性能对NVIDIA GPU进行编程。
将Tensor核心引入标准Fortran的更多相关文章
- A100 Tensor核心可加速HPC
A100 Tensor核心可加速HPC HPC应用程序的性能需求正在迅速增长.众多科学研究领域的许多应用程序都依赖于双精度(FP64)计算. 为了满足HPC计算快速增长的计算需求,A100 GPU支持 ...
- python 生成list的所有的子集 (不使用递归且不引入标准库)
不使用递归且不引入标准库,单纯用两个for循环即可得出一个list的所有子集 L = [1, 2, 3, 4] List = [[]] for i in range(len(L)): ...
- css的核心内容 标准流、盒子模型、浮动、定位等分析
1.块级元素:如:<div></div>2.行内元素:如:<span></span>从效果中看块级元素与行内元素的区别: 通过CSS的设置把行内元素转换 ...
- c++标准库多线程入门
从c++ 11开始,语言核心和标准库开始引入了对多线程的原生支持.如下所示: int doSth(char c) { default_random_engine dre(c); uniform_int ...
- 什么是 C 和 C ++ 标准库?
简要介绍编写C/C ++应用程序的领域,标准库的作用以及它是如何在各种操作系统中实现的. 我已经接触C++一段时间了,一开始就让我感到疑惑的是其内部结构:我所使用的内核函数和类从何而来? 谁发明了它们 ...
- [转]什么是 C 和 C ++ 标准库?
转载地址:https://www.cnblogs.com/findumars/p/9000371.html 简要介绍编写C/C ++应用程序的领域,标准库的作用以及它是如何在各种操作系统中实现的.我已 ...
- CUDA 9中张量核(Tensor Cores)编程
CUDA 9中张量核(Tensor Cores)编程 Programming Tensor Cores in CUDA 9 一.概述 新的Volta GPU架构的一个重要特点是它的Tensor核,使T ...
- 用NVIDIA Tensor Cores和TensorFlow 2加速医学图像分割
用NVIDIA Tensor Cores和TensorFlow 2加速医学图像分割 Accelerating Medical Image Segmentation with NVIDIA Tensor ...
- UNIX环境高级编程笔记之标准I/O库
一.总结 文件I/O一章讲了不带缓冲的I/O,本章讲的是带缓冲的I/O.不带缓冲针对的是内核的系统调用,而带缓冲针对的是用户空间的标准库函数,是基于带缓冲的I/O实现的.不带缓冲的I/O通过文件描述符 ...
随机推荐
- 12- APP接口测试以及接口文档的分析
什么是接口? 为什么要做接口测试? 接口测试流程 需求评审 需求分析 接口用例设计 执行测试用例 bug的定位于追踪 接口文档分析 接口文档分析:开发 内容: 1.接口名称 2.接口地址 3.支持方式 ...
- 使用DirectX截屏
网上有很多关于DirectX截屏的文章,但大都是屏幕截图,很少有窗口截图,本文则两者都涉及到,先讲如何截取整个屏幕,再讲如何截取某个窗口,其实二者的区别不大,只是某个参数的设置不同而已,最后我们还将扩 ...
- android调用号和libc
调用号(以arm平台为例)在/bionic/libc/kernel/uapi/asm-arm/asm/unistd.h: /* WARNING: DO NOT EDIT, AUTO-GENERATED ...
- pr加字幕
选择免费字体 自由字体整理了免费的商用字体 安装字体 将下载好的.ttf文件,右键选择为所有用户安装 如果没有选择为所有用户安装,你在Arctime或者premiere中可能无法找到这个字体 而且想要 ...
- c++通讯录管理系统
代码拷贝 #include<iostream> #include<string> #include<stdlib.h> #define MAX 1000 using ...
- 测试的V模型和W模型
V模型 :后测试 优点: 1.每一阶段都清晰明了,便于把控开发的每一个过程. 2.既包含了单元测试又包含了系统测试 缺点: 1.测试介入的比较晚,所以开发前期的缺陷无从修改. 2.开发和测试串行. W ...
- opencv打开摄像头获取视频程序
// // main.cpp // opencv3 // // Created by PKU on 14-9-16. // Copyright (c) 2014年 PKU. All rights re ...
- [bug] CDH 安装 Error : No matching Packages to list
信息 分析 我的系统是CentOS 7,而 cm 安装包是配合 redhat 6 的,应该选择 redhat 7 目录下的包 参考 https://community.cloudera.com/t5/ ...
- 【海通国际】Joe Lowry(Mr. Lithium)谈全球电池原材料供应危机
[海通国际]Joe Lowry(Mr. Lithium)谈全球电池原材料供应危机 环球锂业公司(Global Lithium)总裁Joe Lowry日前接受了欧洲锰业Euro Manganese的邀请 ...
- linux使用createrepo制作本地yum源
目录 linux使用createrepo制作本地yum源 安装createrepo软件包 进入本地rpm包目录 执行完后可以看到生成的repodata目录 编辑yum配置文件使用 完成,测试使用 关于 ...