快捷键

torch.cuda.graphs 的源代码

# mypy: 允许未类型化定义
导入 gc
导入 打字

导入 火炬

来自 .._utils 导入 _dummy_type


如果 不是 有属性(torch._C, "_CudaStreamBase"):
    定义虚拟基类
    torch._C.字典[_CUDAGraph] = _dummy_type(_CUDAGraph)
    torch._C.字典["_graph_pool_handle"] = _dummy_type("_graph_pool_handle")
    torch._C.字典["_cuda_isCurrentStreamCapturing"] = _dummy_type(
        "_cuda_isCurrentStreamCapturing"
    )

来自 torch._C 导入 (  # noqa: F401
    _cuda_isCurrentStreamCapturing,
    _CUDAGraph,
    _graph_pool_handle,
)


[文档]def is_current_stream_capturing(): r"""正在当前 CUDA 流上执行 CUDA 图捕获时返回 True,否则返回 False。 如果当前设备上不存在 CUDA 上下文,则返回 False 而不初始化上下文。 """ 返回 _cuda_isCurrentStreamCapturing()
Python shim 有助于 Sphinx 更可靠地处理文档字符串。
[文档]def graph_pool_handle(): 返回表示图内存池 ID 的不可见令牌。 查看 :ref:`图内存管理`。 .. 警告:: 该 API 处于测试阶段,未来版本中可能会有所变动。 """ 返回_graph_pool_handle()
Python shim 有助于 Sphinx 更可靠地处理文档字符串。
[文档] CUDAGraph(torch._C._CUDAGraph): rCUDA 图包装器。 .. 警告:: 此 API 处于测试版,未来版本中可能会有所变化。 "沉浸式翻译" def __new__(): 返回 超级().__new__()
[文档] def capture_begin(self, pool=None, capture_error_mode="global"): 开始在当前流上捕获 CUDA 工作。 通常情况下,您不应该自己调用 `capture_begin`。 使用 :class:`~torch.cuda.graph` 或 :func:`~torch.cuda.make_graphed_callables`, 它们内部会调用 `capture_begin`。 参数: 池(可选):令牌(由 :func:`~torch.cuda.graph_pool_handle` 或 meth:`other_Graph_instance.pool()` 返回), 暗示此图可能与指定的池共享内存。 详见 :ref:`图内存管理`。 capture_error_mode (str, optional): 指定图捕获流的 cudaStreamCaptureMode。 可以是 "global"、"thread_local" 或 "relaxed"。在 CUDA 图捕获期间,一些操作,如 cudaMalloc, 可能不安全。"global"在其他线程中的操作将引发错误,"thread_local"只会对线程本地变量引发错误。 当前线程中的操作,并且“relaxed”对这些操作不会出错。不要更改此设置 除非你熟悉 `cudaStreamCaptureMode `_ """ # noqa: B950 super().capture_begin(pool=pool, capture_error_mode=capture_error_mode)
[文档] def capture_end(self): 结束当前流的 CUDA 图捕获。 在调用`capture_end`之后,可以在此实例上调用`replay`。 通常情况下,您不应该自己调用`capture_end`。 使用`:class:`~torch.cuda.graph`或`:func:`~torch.cuda.make_graphed_callables`。 内部调用 `capture_end`。 """ super().capture_end()
[文档] def replay(self): 重放此图捕获的 CUDA 工作。 super().重放()
[文档] def 重置(self): 删除此实例当前持有的图形。 super().reset()
[文档] def pool(self): r"""返回表示此图内存池 id 的不可见令牌。 此 id 可以可选地传递给另一个图的 `capture_begin`, 这暗示其他图可能共享相同的内存池。 """ 返回 super().pool()
[文档] def 启用调试模式(self): 启用 CUDAGraph.debug_dump 的调试模式。 返回 super().enable_debug_mode()。
[文档] def debug_dump(self, debug_path): " 参数: debug_path(必需):导出图的路径。 调用调试函数以导出图,如果通过 CUDAGraph.enable_debug_mode()启用了调试。 调用调试函数以导出图,如果通过 CUDAGraph.enable_debug_mode()启用了调试。 """ 返回调用基类的 debug_dump 方法,并将 debug_path 作为参数
[文档] graph: r捕获 CUDA 工作到 :class:`torch.cuda.CUDAGraph` 对象中,以便稍后回放。有关 CUDA 图的介绍,请参阅 :ref:`CUDA 图语义 ` 有关 CUDA 图的概述,请参阅 :ref:`CUDA 图语义 ` 详细使用说明和约束条件。 参数: cuda_graph (torch.cuda.CUDAGraph):用于捕获的图对象。 pool(可选):由调用 :func:`~torch.cuda.graph_pool_handle()` 返回的不可见令牌( `other_Graph_instance.pool()()` 暗示此图的捕获 可能从指定的池中共享内存。参见 :ref:`图内存管理`。 流 (torch.cuda.Stream, 可选): 如果提供,将设置为上下文中的当前流。 如果未提供,`graph` 将将其内部侧流设置为上下文中的当前流。 capture_error_mode (str, 可选): 指定图捕获流的 cudaStreamCaptureMode。 可以为 "global","thread_local" 或 "relaxed"。在 cuda 图捕获期间,某些操作,如 cudaMalloc, 可能是不安全的。"global" 将在其他线程中的操作上产生错误,"thread_local" 只会在当前线程中的操作上产生错误, "relaxed" 不会在操作上产生错误。请勿更改此设置 除非您熟悉 `cudaStreamCaptureMode `_ .. 注意:: 为了有效共享内存,如果您传递了之前捕获使用的 `pool`,并且之前的捕获使用了显式的 `stream` 参数,那么您应该将相同的 `stream` 参数传递给这次捕获。 此 API 处于测试版,未来版本中可能会有所变化。 .. 警告:: 此 API 处于测试版,未来版本中可能会有所变化。 cudaStreamCaptureMode https://docs.nvidia.com/cuda/cuda-runtime-api/group__CUDART__STREAM.html#group__CUDART__STREAM_1g9d0535d93a214cbf126835257b16ba85 "沉浸式翻译" # 无需注意:B950 默认捕获流: 输入法.可选[torch.cuda.Stream] = def __init__( self, cuda_graph, 泳池=, =, 捕获错误模式: 字符串 = 全局, ): # 懒加载默认捕获流有助于避免循环导入错误。 # 不是线程安全的,但图已经具有一般的(明确记录的) 过程中只能同时进行一个捕获。 如果 self..默认捕获流 : self..默认捕获流 = torch.cuda.() self.泳池 = () 如果 泳池 否则 (泳池,) self.捕获流 = ( 如果 不是 否则 self..默认捕获流 ) 断言 self.捕获流 不是 self.流上下文 = torch.cuda.(self.捕获流) self.CUDA 图 = CUDA 图 self.捕获错误模式 = 捕获错误模式 def __进入__(self): 尽可能释放图所需的内存 torch.cuda.同步() 垃圾回收.收集() torch.cuda.清空缓存() # Stackoverflow 似乎对此模式很自在 # https://stackoverflow.com/questions/26635684/calling-enter-and-exit-manually#39172487 self.流上下文.__进入__() self.cuda_graph.捕获开始( *self.泳池, 捕获错误模式=self.捕获错误模式 ) def __退出__(self, 异常类型, exc_value, 跟踪回溯): self.cuda_graph.捕获结束() self.流上下文.__退出__(异常类型, exc_value, 跟踪回溯)
返回 None 应传播来自 capture_end 或 stream_ctx.__exit__()的异常
[文档]def 生成图形化可调用对象( 可调用对象, 示例参数, 预热迭代次数=3, 允许未使用输入=错误, 泳池= ): r接受可调用对象(函数或:class:`nn.Module`对象)并返回图化版本。 每个图化可调用对象的正向传播运行其源可调用对象的过程。 将 CUDA 工作作为 CUDA 图在单个 autograd 节点内执行。 图形化的可调用对象的正向传递还会向 autograd 图追加。 在反向传播过程中,此节点将可调用对象的反向工作作为 CUDA 图执行。 将可调用对象的反向工作作为 CUDA 图执行。 因此,每个图表化的可调用函数都应该是其源可调用函数的直接替换。 在启用自动求导的训练循环中。 请参阅:ref:`部分网络捕获`以获取详细使用和限制。 如果你传递一个包含多个可调用函数的元组,它们的捕获将使用相同的内存池。 请参阅::ref:`图内存管理`以了解何时适用。 参数: 可调用对象(torch.nn.Module 或 Python 函数,或这些对象的元组):要图化的可调用对象或可调用对象列表。 请参阅::ref:`图内存管理`以了解何时传递可调用对象的元组。 是合适的。如果传递一个可调用对象的元组,它们的顺序必须与元组中的顺序相同 它们将在实时工作负载中运行。 sample_args(张量元组或张量元组的元组):为每个可调用对象提供的样本参数。 如果传递了一个单独的可调用对象,则`sample_args`必须是一个包含参数张量的单个元组。 如果传递了一个可调用对象的元组,则 `sample_args` 必须是元组的元组,其中包含类型为 Tensors 的参数张量。 num_warmup_iters (int):预热迭代次数。目前,`DataDistributedParallel` 需要 11 次预热迭代。默认:`3`。 allow_unused_input (bool):如果为 False,则指定在计算输出时未使用的输入 (因此其梯度始终为零)是一个错误。默认为 False。 池(可选):令牌(由 :func:`~torch.cuda.graph_pool_handle` 返回或 meth:`other_Graph_instance.pool()`) 暗示此图可能与指定的池共享内存 。请参阅 :ref:`图内存管理`。 .. 注意:: 每个 `sample_args` 中的 Tensor 的 `requires_grad` 状态必须匹配 这是训练循环中对应真实输入的预期情况。 .. 警告:: 此 API 处于测试版,未来版本中可能会有所变化。 .. 警告:: 每个可调用对象的 `sample_args` 必须只包含张量。不允许其他类型。 .. 警告:: 返回的可调用对象不支持高阶微分(例如,双重反向)。 .. 警告:: 在传递给 :func:`~make_graphed_callables` 的任何 :class:`~torch.nn.Module` 中,只有参数 可训练。缓冲区必须具有 ``requires_grad=False``。 .. 警告:: 在通过 :class:`torch.nn.Module` 通过 :func:`~make_graphed_callables` 后, 您不能添加或删除该模块的任何参数或缓冲区。 .. 警告:: 传递给 :func:`~torch.cuda.make_graphed_callables` 的 :class:`torch.nn.Module` 不能有模块钩子 在它们传递时注册。然而,在传递模块后 *注册* 插件 通过::func:`~torch.cuda.make_graphed_callables` 是允许的。 .. 警告:: 运行图形可调用函数时,必须以相同的顺序和格式传递其参数 他们出现在那个可调用的`sample_args`中。 .. 警告:: 自动混合精度仅在禁用缓存的情况下支持于:func:`~torch.cuda.make_graphed_callables` 。上下文管理器`torch.cuda.amp.autocast()`必须设置`cache_enabled=False` "沉浸式翻译" 如果 torch.is_autocast_enabled() torch.is_autocast_cache_enabled(): 抛出 运行时错误( "make_graphed_callables 不支持自动缓存。请设置 `cache_enabled=False`。" ) 只有一个可调用对象 = 如果 不是 isinstance(可调用对象, 元组): 只有一个可调用对象 = 真实 可调用对象 = (可调用对象,) 样本参数 = (示例参数,) 展平样本参数 = 输入文本为空,请提供需要翻译的文本 for c, args zip(可调用对象, 示例参数): 如果 isinstance(c, torch.神经网络.模块): 断言 ( 长度(c._backward_hooks) == 0 长度(c._前向钩子) == 0 长度(c._前向预处理钩子) == 0 ), ( 模块在传递时不得注册钩子。然而,注册钩子 + 在通过 make_graphed_callables 处理后允许在模块上进行操作。 ) 断言 所有(b.requires_grad for b c.缓冲区()), ( 在任何`:class:`~torch.nn.Module`传递给` + ":func:`~make_graphed_callables`,只有参数可以是可训练的。所有缓冲区都必须有“ + "``requires_grad=False``。" ) flatten_arg = torch.工具._pytree.arg_tree_leaves(*参数) 展平样本参数.append(元组(展平参数)) 断言 所有(isinstance(arg, torch.张量) for 参数 展平参数), ( 在测试版 API 中,sample_args + "每个可调用对象必须只包含张量。不允许其他类型。" ) # 如果一个可调用对象是一个 nn.Module,其完整输入表面是用户显式传递给 forward 的 args(即其 sample_args)以及模块的参数属性。 # 每个可调用对象的长度用户 args per_callable_len_user_args = [长度(参数) for args 展平样本参数] 每个可调用模块的参数 = [ 元组(c.参数()) 如果 isinstance(c, torch.神经网络.模块) 否则 () for c 可调用对象 ] 每个可调用对象的静态输入表面 = [ 展平样本参数[i] + 可调用模块参数[i] for i 范围(长度(可调用对象)) ] 前向图 = [torch.cuda.CUDAGraph() for _ 范围(长度(可调用对象))] 反向图 = [torch.cuda.CUDAGraph() for _ 范围(长度(可调用对象))] 内存池 = 图池句柄() 如果 泳池 否则 泳池 # 预热 # 希望能防止 cudnn 基准测试和其他懒加载的 cuda 工作 确保不会落入任何捕捉中。 torch.cuda.同步() torch.cuda.(torch.cuda.()): for 函数, 参数, 静态输入表面 zip( 可调用对象, 示例参数, 每个可调用对象的静态输入表面 ): 梯度输入, 输出, 输出_grad = , , for _ 范围(预热迭代次数): 输出 = torch.工具._pytree.树叶(函数(*参数)) 输出_grad = 元组(o for o 输出 如果 o.需要梯度) 如果 长度(输出梯度) > 0: grad_inputs = torch.自动微分.研究生( 输出=输出梯度, 输入=元组( i for i 静态输入表面 如果 i.requires_grad ), 梯度输出=元组( torch.空值类似(o) for o 输出 如果 o.requires_grad ), 仅输入=, 允许未使用=允许未使用输入, ) for v [输出, 输出梯度, 梯度输入] 删除 v torch.cuda.同步() 所有捕获在此共享一个内存池。为了避免重放互相破坏对方的内存。 最安全的做法是按照它们运行的顺序捕获所有遍历: # 前进 1,前进 2,... 前进 N,然后后退 N,后退 N-1,... 后退 1。 捕获前向图 每个可调用静态输出 = 输入文本为空,请提供需要翻译的文本 每个可调用输出未展开规范 = 输入文本为空,请提供需要翻译的文本 for 函数, 参数, 前向图 zip(可调用对象, 示例参数, 前向图): torch.cuda.graph(前向图, 泳池=内存池): 输出 = 函数(*参数) 展平输出, 规范 = torch.工具._pytree.树形展平(输出) 每可调用静态输出.append(元组(展平输出)) 每个可调用输出的反展平规范.append(规格) # 逆序捕获反向图 每个可调用静态梯度输出 = 输入文本为空,请提供需要翻译的文本 每个可调用静态梯度输入 = 输入文本为空,请提供需要翻译的文本 for static_input_surface, static_outputs, 反向图 zip( 反转(每可调用静态输入表面), 反转(每可调用静态输出), 反转(反向图集), ): # 假设所有静态输出都要求梯度 # 断言所有(static_outputs).requires_grad,"图调用函数的输出必须要求梯度。" static_grad_outputs = 元组( torch.空值类似(o) 如果 o.requires_grad 否则 for o 静态输出 ) 输出_grad = 元组(o for o 静态输出 如果 o.需要梯度) grad_inputs = 如果 长度(输出梯度) > 0: torch.cuda.graph(逆图, 泳池=内存池): grad_inputs = torch.自动微分.研究生( 输出=输出梯度, 输入=元组(i for i 静态输入表面 如果 i.需要梯度), 梯度输出=元组(o for o static_grad_outputs 如果 o 不是 ), 仅输入=, 允许未使用=允许未使用输入, ) # 构建适合从 Graphed.backward 返回的元组: # 使用 None 填充实际需要的梯度,以在不需要梯度的输入的梯度槽中填充。 我实在想不出这个模式的俏皮一句话。 静态梯度输入 = 输入文本为空,请提供需要翻译的文本 梯度索引 = 0 for 参数 static_input_surface: 如果 arg.requires_grad grad_inputs 不是 : 静态梯度输入.append(梯度输入[grad_idx]) 梯度索引 += 1 否则: 静态梯度输入.append() # type: ignore[arg-type] 静态梯度输入 = 元组(静态梯度输入) # 类型:忽略[赋值] 每个可调用静态梯度输出.append(静态梯度输出) 每个可调用静态梯度输入.append(静态梯度输入) # 反转最近的两个列表 每个可调用静态梯度输出.reverse() 每个可调用静态梯度输入.reverse() # 现在,对于每个可调用列表,per_callable_*[i] 存储第 i 个可调用的内容 def 创建图形化的自动微分函数( 前向图, 逆图, 模块参数, len_user_args, output_unflatten_spec, static_input_surface, static_outputs, 静态梯度输出, 静态梯度输入, ): 图形化(torch.自动微分.函数): @staticmethod def 前向(ctx, *输入): 在这个阶段,只有用户参数可能(可能)是新的张量。 for i 范围(len_user_args): 如果 static_input_surface[i].数据指针() != 输入[i].数据指针(): static_input_surface[i].复制_(输入[i]) 前向图.回放() 断言 isinstance(static_outputs, 元组) 返回 元组(o.detach() for o static_outputs) @staticmethod @torch.自动微分.函数.一次可微 def 反向(ctx, *梯度): 断言 长度(梯度) == 长度(静态梯度输出) for g, 梯度 zip(静态梯度输出, 梯度): 如果 g 不是 : 如果自动微分之神仁慈的话,请不要复制以下内容 入学新生已经坐在正确的位置 如果 g.数据指针() != 研究生.数据指针(): g.复制_(研究生) 逆图.回放() # 输入参数不需要梯度期望为 None 梯度。 断言 isinstance(静态梯度输入, 元组) 返回 元组( b.detach() 如果 b 不是 否则 b for b 静态梯度输入 ) def 功能化(*用户参数): 运行与图中的所有可能需要梯度的输入相等的自动微分函数 (显式用户参数 + 模块参数) 假设模块参数自捕获以来没有改变。 展平用户参数 = torch.工具._pytree.arg_tree_leaves(*用户参数) out = 图形化.应用(*(元组(展平用户参数) + 模块参数)) 返回 torch.工具._pytree.树形展开(输出, output_unflatten_spec) 返回 函数化 组合最终的图形化可调用对象 返回 = 输入文本为空,请提供需要翻译的文本 for i, 函数 列举(可调用对象): 图形化 = 创建图形化的自动微分函数( 前向图[i] 反向图集[i] 可调用模块参数[i] 每调用长度用户参数[i] 每个可调用输出的反展平规范[i] 每可调用静态输入表面[i] 每可调用静态输出[i] 每个可调用静态梯度输出[i] 每个可调用静态梯度输入[i] ) 如果 isinstance(函数, torch.神经网络.模块): def 制作图形化前向(函数, 图训练状态, 图形化, 原始转发): def 新正向(*用户参数): # 如果模块的训练或评估状态与我们所绘制的相匹配, 运行图,否则运行原始前向方法 如果 函数.训练 == 图训练状态: 返回 图形化(*用户参数) 否则: 返回 原始转发(*用户参数) 返回 新的转发 函数.前向传播 = 制作图形化前向(函数, 函数.训练, 图形化, 函数.前向) # 类型:忽略[赋值] 返回.append(函数) 否则: 返回.append(图形化) 如果 只有一个可调用的: 返回 返回[0] 返回 元组(返回)

© 版权所有 PyTorch 贡献者。

使用 Sphinx 构建,并使用 Read the Docs 提供的主题。

文档

查看 PyTorch 的全面开发者文档

查看文档

教程

深入了解初学者和高级开发者的教程

查看教程

资源

查找开发资源,获取您的疑问解答

查看资源