在cuDNN中简化Tensor Ops
在cuDNN中简化Tensor Ops
在Tesla V100 GPU中引入神经网络模型以来,神经网络模型已迅速利用NVIDIA Tensor Cores进行深度学习。例如,基于Tensor Core的解决方案宣布了ResNet50训练的性能记录。
NVIDIA的cuDNN库 使CUDA程序员能够优化循环神经网络和卷积神经网络,以实现GPU加速。概述了cuDNN用户使用Tensor Core 进行卷积的简便方法,并附有说明和示例代码。该文章为cuDNN应用提供了一些简单的规则:FP16数据规则,张量维数规则,ALGO_1的使用等。
cuDNN版本解除了大多数限制。cuDNN 7.2版本取消了FP16数据约束,而cuDNN 7.3删除了张量尺寸约束(对于打包的NCHW张量数据),直接进行改进。
将FP32数据用于Tensor Ops
关于在CUDA中使用Tensor Core的帖子讨论了将FP16输入用于张量操作,如图1所示。虽然张量操作仍然使用FP16数据,但卷积cuDNN API允许用户选择将FP32输入数据转换为FP16。如果需要,卷积的输出数据也将转换为FP32。

图1. FP32数据现在可以用作输入
该CUDNN_TENSOR_OP_MATH_ALLOW_CONVERSION枚举值,在cuDNN 7.2,使cuDNN应用程序员选择转换FP32数据运算使用。该枚举值与枚举值一样传递给cudnnSetConvolutionMathType()调用CUDNN_TENSOR_OP_MATH。此代码段显示了如何执行此操作:
//设置数学类型以允许cuDNN使用Tensor Core:
checkCudnnErr(cudnnSetConvolutionMathType(cudnnConvDesc,CUDNN_TENSOR_OP_MATH_ALLOW_CONVERSION));
将在后面的部分中看到使用代码片段的上下文。
FP32数据也用于RNN
现在还为RNN启用了类似的FP32数据转换。只需将CUDNN_TENSOR_OP_MATH_ALLOW_CONVERSION枚举值传递给cudnnSetRNNMatrixMathType()调用,即可将FP32数据转换为在RNN中使用。如下使用:
//设置数学类型以允许cuDNN使用Tensor Core:
checkCudnnErr(cudnnSetRNNMatrixMathType(cudnnRnnDesc,CUDNN_TENSOR_OP_MATH_ALLOW_CONVERSION));
消除了NCHW张量尺寸约束
早期版本的cuDNN要求所有张量的通道维数必须为8的倍数。cuDNN可以根据需要自动填充张量。
在CUDNN_TENSOR_OP_MATH和CUDNN_TENSOR_OP_MATH_ALLOW_CONVERSION情况下,对于填充的NCHW数据,此填充都是自动的。发生填充时,性能损失可忽略不计。
//设置NCHW张量尺寸,不必设置为8的倍数(此处仅显示输入张量):
int dimA [] = {1,7,32,32};
int strideA [] = {7168,1024,32,1};
下一节中的示例代码演示了如何使用。
样例代码
将张量运算用于FP32数据和任何通道尺寸的逻辑类似于为cuDNN的早期版本编写时使用的逻辑。只有维度和数据类型发生了变化(以及使用CUDNN_TENSOR_OP_MATH_ALLOW_CONVERSION):
//创建一个cuDNN句柄:
checkCudnnErr(cudnnCreate(&handle_));
//创建张量描述符:
checkCudnnErr(cudnnCreateTensorDescriptor(&cudnnIdesc));
checkCudnnErr(cudnnCreateFilterDescriptor(&cudnnFdesc));
checkCudnnErr(cudnnCreateTensorDescriptor(&cudnnOdesc));
checkCudnnErr(cudnnCreateConvolutionDescriptor(&cudnnConvDesc));
//设置NCHW张量尺寸,不必设置为8的倍数(此处仅显示输入张量):
int dimA [] = {1,7,32,32};
int strideA [] = {7168,1024,32,1};
checkCudnnErr(cudnnSetTensorNdDescriptor(cudnnIdesc,CUDNN_DATA_FLOAT,
convDim + 2,dimA,strideA));
//分配和初始化张量(同样,仅显示输入张量):
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));
//设置计算数据类型(以下为CUDNN_DATA_FLOAT):
checkCudnnErr(cudnnSetConvolutionNdDescriptor(cudnnConvDesc,convDim,padA,convstrideA,dilationA,CUDNN_CONVOLUTION,CUDNN_DATA_FLOAT));;
//设置数学类型以允许cuDNN使用Tensor Core:
checkCudnnErr(cudnnSetConvolutionMathType(cudnnConvDesc,CUDNN_TENSOR_OP_MATH_ALLOW_CONVERSION));
//选择支持的算法:
cudnnConvolutionFwdAlgo_t算法= CUDNN_CONVOLUTION_FWD_ALGO_IMPLICIT_PRECOMP_GEMM;
//分配的工作空间:
checkCudnnErr(cudnnGetConvolutionForwardWorkspaceSize(handle_,cudnnIdesc,
cudnnFdesc,cudnnConvDesc,
cudnnOdesc,algo,&workSpaceSize));
如果(workSpaceSize> 0){
cudaMalloc(&workSpace,workSpaceSize);
}
//调用卷积:
checkCudnnErr(cudnnConvolutionForward(handle_,(void *)(&alpha),cudnnIdesc,devPtrI,
cudnnFdesc,devPtrF,cudnnConvDesc,algo,
workSpace,workSpaceSize,(void *)(&beta),
cudnnOdesc,devPtrO));
FP32性能
图2显示了将Tensor Core用于FP32张量数据时卷积的比较性能。该图表将V100张量运算与V100 FMA运算进行了比较,因此,其增益并不像以前的将V100性能与P100 FMA进行比较的图表那样明显。但是,与使用FMA ops相比,与FP32输入一起使用的Tensor ops仍然代表了可观的收益。

图2.具有Tensor Core的Tesla V100(Volta)与Tesla V100(Volta)的卷积性能比较。比较是在每个神经网络的卷积层运行时间的几何方法之间进行的。两种情况都使用FP32输入/输出数据和FP32计算。一种使用Tensor Core,另一种使用FP32融合乘加(FMA)。
剩余约束
尽管解除了在cuDNN中使用张量运算的主要限制,但仍然存在一些次要限制。一个限制是使用ALGO_1(IMPLICIT_PRECOMP_GEMM用于转发)。cuDNN中还没有其他卷积算法使用张量运算。
另一个较小的限制是卷积滤波器的大小,特别是空间尺寸(r和s)。但是,用于卷积的FFT算法非常适合于滤波器尺寸较大的用例。只需在超出张量运算滤波器限制以达到最佳性能之前就将卷积切换为使用FFT算法即可。
在cuDNN中简化Tensor Ops的更多相关文章
- 在PHP应用中简化OAuth2.0身份验证集成:OAuth 2.0 Client
在PHP应用中简化OAuth2.0身份验证集成:OAuth 2.0 Client 阅读目录 验证代码流程 Refreshing a Token Built-In Providers 这个包能够让你 ...
- TensorFlow中的 tensor 张量到底是什么意思?
详见[Reference]: TensorFlow中的“Tensor”到底是什么? 以下摘录一些要点: 这个图好生动呀!~ 标量和向量都是张量(tensor).
- tensorflow中张量(tensor)的属性——维数(阶)、形状和数据类型
tensorflow的命名来源于本身的运行原理,tensor(张量)意味着N维数组,flow(流)意味着基于数据流图的计算,所以tensorflow字面理解为张量从流图的一端流动到另一端的计算过程. ...
- EL和 JSTL? 在JSP中简化 java代码的写法!
一.servlet部分 package com.aaa.servlet; import com.aaa.dao.IStudentDAO; import com.aaa.dao.Impl.Student ...
- pytorch 中改变tensor维度的几种操作
具体示例如下,注意观察维度的变化 #coding=utf-8 import torch """改变tensor的形状的四种不同变化形式""" ...
- Python中简化的验证码功能实现
#!/usr/bin/env python # _*_ encoding:utf-8 _*_ # author:snate import random def generate_auth_code() ...
- Pytorch中ndarray tensor list互转
1.ndarray->tensor : b=torch.from_numpy(a) 2.tensor->ndarray: b=a.numpy() ''' 但这么写会报错-- Runtime ...
- python中简化的验证码功能
验证码一般用来验证登陆.交易等行为,减少对端为机器操作的概率,python中可以使用random模块,char()内置函数来实现一个简单的验证码功能. import random def veri_c ...
- VIM中简化删除,光标移动和查找操作
# 一.命令行模式下简化删除 1. 向后删除单个字符:[x] 2. 向前删除单个字符:[X] 3. 删除从光标开始到单词结尾:[dw] 删除从光标后的2个单词:[d2w] 4. 删除整个单词:[daw ...
随机推荐
- 【golang】golang中结构体的初始化方法(new方法)
准备工作: 定义结构体:Student import ( "fmt" "reflect") type Student struct { StudentId st ...
- Android动态调试so库JNI_Onload函数-----基于IDA实现
之前看过吾爱破解论坛一个关于Android'逆向动态调试的经验总结帖,那个帖子写的很好,对Android的脱壳和破解很有帮助,之前我们老师在上课的时候也讲过集中调试的方法,但是现在不太实用.对吾爱破解 ...
- Linux内核升级、GRUB2引导故障处理与密码破解
目录 内核升级 GRUB2内核启动设置 GRUB2引导菜单加密 GRUB2引导故障及修复 救援模式管理 Rhel7破解root密码 内核升级 查看当前内核版本: uname -r 查看可升级内核: ...
- Windows核心编程 第四章 进程(中)
4.2 CreateProcess函数 可以用C r e a t e P r o c e s s函数创建一个进程: BOOL CreateProcessW( _In_opt_ LPCWSTR lpAp ...
- 学生免费使用JetBrains全家桶
今天又有一个同学来问我申请流程,因此也就趁着这个机会把整个流程简单地记录一下,供大家分享.下面所提及到的学校邮箱以及相关的操作都是以自己学校为准,学校不同可能会稍有不同,大家按自己学校的操作就好. 学 ...
- Catalan数以及相关性质的证明
\(Catalan\) 数相关证明 Mushroom 2021-5-14 \(Catalan\)数的定义 给定一个凸\(n + 1\)边形, 通过在内部不相交的对角线,把它划分成为三角形的组合,不同的 ...
- BUAAOO第四单元总结与学期回顾
第四单元架构设计 第四单元要完成的是对给定UML元素的建模/统计/分析,考虑到UML元素的组织是树状的,很容易想到基于树状的数据结构完成 由于UML元素已经由官方接口给出,因此结点类采用wrapper ...
- Java 正则表达式实例操作
Regular Expression正则表达式,简称RegExp,常规通用的表达式,在多个开发语言中都有它的实现,可以通过正则表达式来快速的检索.匹配.查找.替换字符串中的文本. 简单实例 匹配网址 ...
- 『动善时』JMeter基础 — 22、JMeter中实现参数化(CSV)
目录 1.参数化的定义 2.什么情况下需要用到参数化 3.JMeter实现参数化的方式 4.CSV数据文件设置界面详细说明 (1)CSV数据文件设置组件界面说明 (2)补充说明:Recycle on ...
- [Qt] Librecad 源码分析
libraries jwwlib libdxfrw:一个免费的C++库,用于读写文本格式或二进制格式的DXF文件(C++ library to read and write DXF/DWG files ...