在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 ...
随机推荐
- Android trap攻防思路整理
Android trap攻防 图/文 h_one 0x01 反 ...
- 关于Java处理串口二进制数据的问题 byte的范围 一个字节8bits
前置知识点 byte的范围[-128~127] 内存里表现为 0x00~0xFF 刚好是一个8bits的字节 问题 byte[] hexData = new byte[] {0x01, 0x03, 0 ...
- C++ string的size()和length()函数没有区别
C++标准库中的string中两者的源代码如下: size_type __CLR_OR_THIS_CALL length() const { // return ...
- opencv打开摄像头获取视频程序
// // main.cpp // opencv3 // // Created by PKU on 14-9-16. // Copyright (c) 2014年 PKU. All rights re ...
- Jenkins 基础篇 - 任务分类
从前面的小节中我们看到在创建 Jenkins 任务的时候有好几种类型,如果你专门安装了 Maven 相关插件,可能还会有一个[构建一个 maven 项目]的任务类型,那这些任务类型究竟有何区别,以及我 ...
- Spring中声明式事务存在的优缺点以及注意事项!
事务管理在系统开发中是不可缺少的一部分,Spring提供了很好事务管理机制,主要分为编程式事务和声明式事务两种. 关于事务的基础知识,如什么是事务,数据库事务以及Spring事务的ACID.隔离级别. ...
- 记一次 .NET 某外贸Web站 内存泄漏分析
一:背景 1. 讲故事 上周四有位朋友加wx咨询他的程序内存存在一定程度的泄漏,并且无法被GC回收,最终机器内存耗尽,很尴尬. 沟通下来,这位朋友能力还是很不错的,也已经做了初步的dump分析,发现了 ...
- [bug] Python Anoconda3 安装完成后开始菜单不显示
版本问题,需更新 win+R打开cmd,敲入命令: conda update menuinst conda install -f console_shortcut ipython ipython-no ...
- Docker——Registry 通过Shell管理私有仓库镜像
使用方法: 复制代码保存为 image_registry.sh sh image_registry.sh -h #查看帮助 HUB=10.0.29.104:5000 改为自己的地址 #!/bin ...
- 攻防世界(四)php_rce
攻防世界系列:php_rce 1.打开题目 看到这个还是很懵的,点开任意连接都是真实的场景. 2.ThinkPHP5,这里我们需要知道它存在 远程代码执行的漏洞. ?s=index/\think\ap ...