奇闻异事#
本节包含一系列随机主题和概念。
cuDNN 库配置#
cuDNN 以子库集合的形式交付。cuDNN 的默认用法需要所有子库;但是,可以删除某些子库,而 cuDNN 仍然可以工作,从而节省二进制文件大小,但会减少支持范围和性能。在此,我们记录了库的哪些子集是有效的配置。
配置通过环境变量 CUDNN_LIB_CONFIG
启用。下表列出了有效的配置。通过适当设置环境变量,您可以从 cuDNN 安装中删除除必需子库之外的所有子库。随着时间的推移,我们希望支持更多配置。
|
摘要 |
必需的子库 |
---|---|---|
|
cuDNN 的默认用法 |
全部 |
|
支持仅限于图 API,仅使用 JIT 引擎(没有预编译内核)。 |
|
库概述 部分的 API 参考文档提供了关于子库分解和依赖关系图的更多详细信息。
FULL
配置#
这是 cuDNN 的默认用法。我们希望大多数用户继续使用此配置,除非他们想要探索二进制文件大小缩减的权衡。
GRAPH_JIT_ONLY
配置#
此配置提供
与
FULL
相比,显著减小二进制文件大小仅 JIT 引擎
支持 NVIDIA Ampere 及更高版本的 GPU 架构
图 API 的功能覆盖范围(在下面有一些注意事项)
在许多情况下性能接近
FULL
,但下面列出了注意事项
由于 GRAPH_JIT_ONLY
配置不包括带有预编译内核的引擎(这些内核位于最大的子库中),因此它与 FULL
相比,二进制文件大小显著减小。为了实现这种减小,请仅保留上表中必需的子库列中的库,并删除其余不需要的 cuDNN 子库。
这种减小二进制文件大小的权衡是,根据用例,您可能会看到与 FULL
相比的功能或性能差距。特别是,在某些情况下,您可能会由于缺少功能支持而看到运行时错误。特别是,这可能会发生在 专用预编译引擎 支持的图模式中。FULL
支持的所有其他图模式也受 GRAPH_JIT_ONLY
支持。
此外,对于功能上支持的模式,FULL
和 GRAPH_JIT_ONLY
配置之间可能存在性能差异,具体取决于图模式和问题大小。作为粗略指导
单算子
ConvolutionBwdFilter
平均而言存在较大的性能差距。单算子
Matmul
和单算子ConvolutionBwdData
平均而言存在较小的性能差距。单算子
ConvolutionFwd
平均而言性能相当,但根据问题大小,您可能会看到性能差距。当迁移到
GRAPH_JIT_ONLY
时,多算子融合应具有相当的性能
这是 GRAPH_JIT_ONLY
的初始版本。我们正在积极努力缩小与 FULL
的差距。在未来,我们希望 GRAPH_JIT_ONLY
具有与 FULL
相同的图 API 功能覆盖范围,但对于某些在 FULL
中具有高度优化的预编译内核的特殊情况,性能可能存在一些差距。
注意
GRAPH_JIT_ONLY
支持 NVIDIA Ampere 及更高版本,但不支持 Ampere 之前的 GPU 架构。
子库配置说明#
由于 FULL
配置是默认配置,因此无需执行任何操作即可启用它。
要使用非默认配置(目前,唯一的非默认配置是 GRAPH_JIT_ONLY
),请执行以下操作
将环境变量
CUDNN_LIB_CONFIG
设置为GRAPH_JIT_ONLY
。确保必需的子库位于
LD_LIBRARY_PATH
(或 Windows 上的PATH
)中。注意
GRAPH_JIT_ONLY
配置仅在使用 cuDNN 动态库时受支持,目前不适用于静态库。我们正在努力添加此支持。
线程安全#
cuDNN 库是线程安全的。只要线程不同时共享同一个 cuDNN 句柄,就可以从多个主机线程调用其函数。
在创建每个线程的 cuDNN 句柄时,建议在每个线程异步创建自己的句柄之前,首先同步调用一次 cudnnCreate()。
根据 cudnnCreate(),对于从不同线程使用同一设备的多线程应用程序,推荐的编程模型是为每个线程创建一个(或几个,如果方便的话)cuDNN 句柄,并在线程的整个生命周期中使用该 cuDNN 句柄。
cuDNN 后端要求#
有关 cuDNN 后端的兼容版本,请参阅 支持的产品。
SM Carveout#
从 cuDNN 8.9.5 开始,NVIDIA Hopper GPU 上支持 SM carveout,允许专业用户为单独 CUDA 流上的并发执行保留 SM。用户可以将目标 SM 计数设置为 cuDNN 启发式算法,并获取将在执行期间使用该数量 SM 的引擎配置列表。对于没有 cuDNN 启发式算法的高级用例,用户还可以从头开始创建引擎配置,并配置 SM carveout(下表中列出了支持此功能的引擎)。
以下代码片段是启发式用例的示例。
// Create heuristics descriptor cudnnBackendDescriptor_t engHeur; cudnnBackendCreateDescriptor(CUDNN_BACKEND_ENGINEHEUR_DESCRIPTOR, &engHeur); cudnnBackendSetAttribute(engHeur, CUDNN_ATTR_ENGINEHEUR_OPERATION_GRAPH, CUDNN_TYPE_BACKEND_DESCRIPTOR, 1, &opGraph); cudnnBackendSetAttribute(engHeur, CUDNN_ATTR_ENGINEHEUR_MODE, CUDNN_TYPE_HEUR_MODE, 1, &heurMode); // SM carveout int32_t targetSMCount = 66; cudnnBackendSetAttribute(engHeur, CUDNN_ATTR_ENGINEHEUR_SM_COUNT_TARGET, CUDNN_TYPE_INT32, 1, &targetSMCount); cudnnBackendFinalize(engHeur); // Create engine config descriptor cudnnBackendDescriptor_t engConfig; cudnnBackendCreateDescriptor(CUDNN_BACKEND_ENGINECFG_DESCRIPTOR, &engConfig); // Retrieve optimal engine config(s) from heuristics cudnnBackendGetAttribute(engHeur, CUDNN_ATTR_ENGINEHEUR_RESULTS, CUDNN_TYPE_BACKEND_DESCRIPTOR, 1, &returnedCount, engConfig); // "engConfig" should now be ready with target SM count as 66
此功能目前受正常卷积(Fprop
、Dgrad
和 Wgrad
)以及 Conv-Bias-Act 融合支持。
卷积前向 |
卷积反向数据 |
卷积反向滤波器 |
|
---|---|---|---|
|
|
|
|
原生 CUDA 图 API#
对于选定的引擎,cuDNN 现在提供了一种直接从执行计划和一组变体指针构建 CUDA 图(不要与 cuDNN 图混淆)的方法。这是一种比使用 CUDA 图捕获更灵活的替代方案,因为它允许使用新的变体包指针更新现有的 CUDA 图。与其他 CUDA 图一样,生成的图可以从不同的流中任意多次执行,并且可以作为较大 CUDA 图的子节点嵌入。
支持这些 API 的引擎具有行为注释 CUDNN_BEHAVIOR_NOTE_SUPPORTS_CUDA_GRAPH_NATIVE_API
。
C++ 和 Python API 都包含两个函数
populate_cuda_graph()
update_cuda_graph()
有关 C++ 中这些函数的示例用法,请参阅 cudagraphs.cpp 示例。