旧版 API#

Graph API 部分可以被认为是声明式 API,从某种意义上说,您声明一个图,然后构建并运行它。 以前,cuDNN 只有命令式 API,这对于基本用例来说更方便,但事实证明,随着深度学习领域发展到需要更多操作和更复杂的操作融合,这种 API 过于局限。 随着图 API 的支持范围与旧版 API 达到对等,我们正在逐步弃用和删除旧版 API 的部分内容。 然而,仍然存在差距,因此仍然存在旧版 API。

卷积函数#

先决条件#

对于受支持的 GPU,只有当通过将 mathType 设置为 CUDNN_TENSOR_OP_MATHCUDNN_TENSOR_OP_MATH_ALLOW_CONVERSION 在适当的卷积描述符上调用 cudnnSetConvolutionMathType() 时,才会为卷积函数触发 Tensor Core 操作。

支持的算法#

当满足先决条件时,以下卷积函数可以作为 Tensor Core 操作运行

支持的算法列表#

支持的卷积函数

支持的算法

cudnnConvolutionForward

  • CUDNN_CONVOLUTION_FWD_ALGO_IMPLICIT_PRECOMP_GEMM

  • CUDNN_CONVOLUTION_FWD_ALGO_WINOGRAD_NONFUSED

cudnnConvolutionBackwardData

  • CUDNN_CONVOLUTION_BWD_DATA_ALGO_1

  • CUDNN_CONVOLUTION_BWD_DATA_ALGO_WINOGRAD_NONFUSED

cudnnConvolutionBackwardFilter

  • CUDNN_CONVOLUTION_BWD_FILTER_ALGO_1

  • CUDNN_CONVOLUTION_BWD_FILTER_ALGO_WINOGRAD_NONFUSED

数据和滤波器格式#

cuDNN 库可能会使用填充、折叠和 NCHW 到 NHWC 的转换来调用 Tensor Core 操作。 有关更多信息,请参阅 Tensor 变换

对于 *_ALGO_WINOGRAD_NONFUSED 以外的算法,当满足以下要求时,cuDNN 库将触发 Tensor Core 操作

  • 输入、滤波器和输出描述符(xDescyDescwDescdxDescdyDescdwDesc,如果适用)的 dataType = CUDNN_DATA_HALF(即 FP16)。 对于 FP32 数据类型,请参阅 FP32 到 FP16 的转换

  • 输入和输出特征图的数量(即通道维度 C)是 8 的倍数。 当通道维度不是 8 的倍数时,请参阅 填充

  • 滤波器的类型为 CUDNN_TENSOR_NCHWCUDNN_TENSOR_NHWC

  • 如果使用类型为 CUDNN_TENSOR_NHWC 的滤波器,则输入、滤波器和输出数据指针(XYWdXdYdW,如果适用)与 128 位边界对齐。

RNN 函数#

先决条件#

cudnnSetRNNDescriptor_v8() 中的 mathType 参数设置为 CUDNN_TENSOR_OP_MATHCUDNN_TENSOR_OP_MATH_ALLOW_CONVERSION 时,Tensor Core 操作可用于 RNN 函数 cudnnRNNForward()cudnnRNNBackwardData_v8()cudnnRNNBackwardWeights_v8()

支持的算法#

当满足上述先决条件时,以下 RNN 函数可以作为 Tensor Core 操作运行

支持的算法列表#

支持的 RNN 函数

支持的算法

支持 Tensor Core 操作的所有 RNN 函数

  • CUDNN_RNN_ALGO_STANDARD

  • CUDNN_RNN_ALGO_PERSIST_STATIC

  • CUDNN_RNN_ALGO_PERSIST_STATIC_SMALL_H

数据和滤波器格式#

当满足以下要求时,cuDNN 库将触发 Tensor Core 操作

  • 对于 algo = CUDNN_RNN_ALGO_STANDARD

    • 隐藏状态大小、输入大小和批次大小是 8 的倍数。

    • 所有用户提供的张量和 RNN 权重缓冲区都与 128 位边界对齐。

    • 对于 FP16 输入/输出,选择 CUDNN_TENSOR_OP_MATHCUDNN_TENSOR_OP_MATH_ALLOW_CONVERSION

    • 对于 FP32 输入/输出,选择 CUDNN_TENSOR_OP_MATH_ALLOW_CONVERSION

  • 对于 algo = CUDNN_RNN_ALGO_PERSIST_STATIC

    • 隐藏状态大小和输入大小是 32 的倍数。

    • 批次大小是 8 的倍数。

    • 如果批次大小超过 96(对于前向训练或推理)或 32(对于后向数据),则批次大小约束可能会更严格,并且可能需要较大的 2 的幂批次大小。

    • 所有用户提供的张量和 RNN 权重缓冲区都与 128 位边界对齐。

    • 对于 FP16 输入/输出,选择 CUDNN_TENSOR_OP_MATHCUDNN_TENSOR_OP_MATH_ALLOW_CONVERSION

    • 对于 FP32 输入/输出,选择 CUDNN_TENSOR_OP_MATH_ALLOW_CONVERSION

有关更多信息,请参阅 RNN 函数的特性

RNN 函数的特性#

有关每个 RNN 函数支持的特性列表,请参阅下表。

对于以下每个术语,下表中的简短形式版本用括号显示,以保持简洁: CUDNN_RNN_ALGO_STANDARD (_ALGO_STANDARD)CUDNN_RNN_ALGO_PERSIST_STATIC (_ALGO_PERSIST_STATIC)CUDNN_RNN_ALGO_PERSIST_DYNAMIC (_ALGO_PERSIST_DYNAMIC)CUDNN_RNN_ALGO_PERSIST_STATIC_SMALL_H (_ALGO_SMALL_H)CUDNN_TENSOR_OP_MATH_ALLOW_CONVERSION (_ALLOW_CONVERSION)

RNN 特性#

函数

支持的 I/O 布局

支持批次中的可变序列长度

cudnnRNNForward()

序列主轴解包。 批次主轴解包。 序列主轴打包。

仅适用于 _ALGO_STANDARD。 对于解包布局,不需要输入排序。 对于打包布局,需要输入序列根据长度降序排序。

cudnnRNNBackwardData_v8()

序列主轴解包。 批次主轴解包。 序列主轴打包。

仅适用于 _ALGO_STANDARD。 对于解包布局,不需要输入排序。 对于打包布局,需要输入序列根据长度降序排序。

cudnnRNNBackwardWeights_v8()

序列主轴解包。 批次主轴解包。 序列主轴打包。

仅适用于 _ALGO_STANDARD。 对于解包布局,不需要输入排序。 对于打包布局,需要输入序列根据长度降序排序。

注意

要使用解包布局,请通过 cudnnSetRNNDescriptor_v8()auxFlags 参数设置 CUDNN_RNN_PADDED_IO_ENABLED

常用支持

模式(单元类型)

CUDNN_RNN_RELUCUDNN_RNN_TANHCUDNN_LSTMCUDNN_GRU

算法

_ALGO_STANDARD_ALGO_PERSIST_STATIC_ALGO_PERSIST_DYNAMIC_ALGO_SMALL_H。 请勿在 cudnnRNNForward()cudnnRNNBackwardData_v8()cudnnRNNBackwardWeights_v8() 函数中混合使用不同的算法。

数学模式

CUDNN_DEFAULT_MATHCUDNN_TENSOR_OP_MATH(如果在 Volta 之前的架构上运行或算法不支持 Tensor Core,将自动回退)、_ALLOW_CONVERSION(可能会执行向下转换以利用 Tensor Core)。

方向模式

CUDNN_UNIDIRECTIONALCUDNN_BIDIRECTIONAL

RNN 输入模式

CUDNN_LINEAR_INPUTCUDNN_SKIP_INPUT

按算法支持的特性#

特性

_ALGO_STANDARD

_ALGO_PERSIST_STATIC

_ALGO_SMALL_H

_ALGO_PERSIST_DYNAMIC

  • 半精度输入

  • 单精度累加

  • 半精度输出

  • 支持

  • 半精度中间存储

  • 单精度累加

  • 支持

  • 半精度中间存储

  • 单精度累加

  • 支持

  • 半精度中间存储

  • 单精度累加

  • 支持

  • 半精度中间存储

  • 单精度累加

  • 单精度输入

  • 单精度累加

  • 单精度输出

  • 支持

  • 如果在 Volta 上运行,使用 CUDNN_TENSOR_OP_MATH_ALLOW_CONVERSION,将向下转换并使用半精度中间存储。 否则,使用单精度中间存储。

  • 单精度累加

  • 支持

  • 如果在 Volta 上运行,使用 CUDNN_TENSOR_OP_MATH_ALLOW_CONVERSION,将向下转换并使用半精度中间存储。 否则,使用单精度中间存储。

  • 单精度累加

  • 支持

  • 如果在 Volta 上运行,使用 CUDNN_TENSOR_OP_MATH_ALLOW_CONVERSION,将向下转换并使用半精度中间存储。 否则,使用单精度中间存储。

  • 单精度累加

  • 支持

  • 如果在 Volta 上运行,使用 CUDNN_TENSOR_OP_MATH_ALLOW_CONVERSION,将向下转换并使用半精度中间存储。 否则,使用单精度中间存储。

  • 单精度累加

  • 双精度输入

  • 双精度累加

  • 双精度输出

  • 支持

  • 双精度中间存储

  • 双精度累加

不支持

不支持

  • 支持

  • 双精度中间存储

  • 双精度累加

LSTM 循环投影

支持

不支持

不支持

不支持

LSTM 单元剪裁

支持

支持

支持

支持

批次中的可变序列长度

支持

不支持

不支持

不支持

Tensor Core

  • 对于半精度 I/O,加速需要设置 CUDNN_TENSOR_OP_MATHCUDNN_TENSOR_OP_MATH_ALLOW_CONVERSION。 加速需要 inputSizehiddenSize 为 8 的倍数。

  • 对于 NVIDIA Volta、NVIDIA Xavier 和 NVIDIA Turing 上的单精度 I/O,加速需要设置 CUDNN_TENSOR_OP_MATH_ALLOW_CONVERSION。 加速需要 inputSizehiddenSize 为 8 的倍数。

  • 对于 NVIDIA Ampere 架构上的单精度 I/O,加速需要设置 CUDNN_DEFAULT_MATHCUDNN_TENSOR_OP_MATHCUDNN_TENSOR_OP_MATH_ALLOW_CONVERSION。 加速需要 inputSizehiddenSize 为 4 的倍数。

  • 对于半精度 I/O,加速需要设置 CUDNN_TENSOR_OP_MATHCUDNN_TENSOR_OP_MATH_ALLOW_CONVERSION。 加速需要 inputSizehiddenSize 为 8 的倍数。

  • 对于 NVIDIA Volta、NVIDIA Xavier 和 NVIDIA Turing 上的单精度 I/O,加速需要设置 CUDNN_TENSOR_OP_MATH_ALLOW_CONVERSION。 加速需要 inputSizehiddenSize 为 8 的倍数。

  • 对于 NVIDIA Ampere 架构上的单精度 I/O,加速需要设置 CUDNN_DEFAULT_MATHCUDNN_TENSOR_OP_MATHCUDNN_TENSOR_OP_MATH_ALLOW_CONVERSION。 加速需要 inputSizehiddenSize 为 4 的倍数。

  • 对于半精度 I/O,加速需要设置 CUDNN_TENSOR_OP_MATHCUDNN_TENSOR_OP_MATH_ALLOW_CONVERSION。 加速需要 inputSizehiddenSize 为 8 的倍数。

  • 对于 NVIDIA Volta、NVIDIA Xavier 和 NVIDIA Turing 上的单精度 I/O,加速需要设置 CUDNN_TENSOR_OP_MATH_ALLOW_CONVERSION。 加速需要 inputSizehiddenSize 为 8 的倍数。

  • 对于 NVIDIA Ampere 架构上的单精度 I/O,加速需要设置 CUDNN_DEFAULT_MATHCUDNN_TENSOR_OP_MATHCUDNN_TENSOR_OP_MATH_ALLOW_CONVERSION。 加速需要 inputSizehiddenSize 为 4 的倍数。

不支持,将正常执行,忽略 CUDNN_TENSOR_OP_MATH_ALLOW_CONVERSION

其他限制

最大问题规模受 GPU 规格限制。

  • 前向 RNN:- RELU 和 TANH RNN:hidden_size <= 384 - LSTM 和 GRU:hidden_size <= 192

  • BackwardData RNN:- RELU 和 TANH RNN:hidden_size <= 256 - LSTM 和 GRU:hidden_size <= 128

需要通过 NVRTC 进行实时编译。

Tensor 变换#

cuDNN 库中的一些函数将在执行实际函数操作时执行变换,例如折叠、填充和 NCHW 到 NHWC 的转换。

FP32 和 FP16 之间的转换#

cuDNN API 参考允许您指定可以将 FP32 输入数据复制并在内部转换为 FP16 数据,以使用 Tensor Core 操作来潜在地提高性能。 这可以通过为 cudnnMathType_t 选择 CUDNN_TENSOR_OP_MATH_ALLOW_CONVERSION 枚举来实现。 在此模式下,FP32 张量在内部向下转换为 FP16,执行 Tensor Op 数学运算,最后向上转换为 FP32 作为输出。

Tensor Operation with FP32 Inputs

对于卷积

对于卷积,可以通过将 CUDNN_TENSOR_OP_MATH_ALLOW_CONVERSION 枚举值传递给 cudnnSetConvolutionMathType() 调用来实现 FP32 到 FP16 的转换。

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

对于 RNN

对于 RNN,可以通过将 CUDNN_TENSOR_OP_MATH_ALLOW_CONVERSION 枚举值分配给 cudnnSetRNNDescriptor_v8() 调用的 mathType 参数,以允许 FP32 输入数据向下转换以在 RNN 中使用,从而实现 FP32 到 FP16 的转换。

填充#

对于打包的 NCHW 数据,当通道维度不是 8 的倍数时,cuDNN 库将根据需要填充张量以启用 Tensor Core 操作。 对于 CUDNN_TENSOR_OP_MATHCUDNN_TENSOR_OP_MATH_ALLOW_CONVERSION 两种情况下的打包 NCHW 数据,此填充都是自动的。

折叠#

在折叠操作中,cuDNN 库隐式地执行输入张量的格式化,并将输入张量保存在内部工作区中。 这可以加速对 Tensor Core 的调用。

通过折叠或通道折叠,cuDNN 可以在内部工作区中隐式地格式化输入张量,以加速整体计算。 为用户执行此转换通常允许 cuDNN 使用对卷积步幅有限制的内核来支持带步幅的卷积问题。

NCHW 和 NHWC 之间的转换#

Tensor Core 要求张量采用 NHWC 数据布局。 当用户请求 Tensor Op 数学运算时,将执行 NCHW 和 NHWC 之间的转换。 但是,使用 Tensor Core 的请求只是一个请求,在某些情况下可能不会使用 Tensor Core。 仅当请求并实际使用 Tensor Core 时,cuDNN 库才会在 NCHW 和 NHWC 之间进行转换。

如果您的输入(和输出)为 NCHW,则预期布局会发生变化。

非 Tensor Op 卷积不会执行 NCHW 和 NHWC 之间的转换。

在非常罕见且难以限定的情况下(这是填充和滤波器大小的复杂函数),Tensor Ops 可能未启用。 在这种情况下,用户可以预先填充以启用 Tensor Ops 路径。

混合精度数值精度#

当计算精度和输出精度不同时,数值精度可能会因算法而异。

例如,当计算以 FP32 执行且输出为 FP16 时,CUDNN_CONVOLUTION_BWD_FILTER_ALGO_0 (ALGO_0) 的精度低于 CUDNN_CONVOLUTION_BWD_FILTER_ALGO_1 (ALGO_1)。 这是因为 ALGO_0 不使用额外的工作区,并且被迫以 FP16(即半精度浮点数)累积中间结果,这会降低精度。 另一方面,ALGO_1 使用额外的工作区以 FP32(即全精度浮点数)累积中间值。