torch.compile

简介

在Pytorch 2.x中,引入了torch.compile特性,主要包含如下4个部分:

TorchDynamo:基于Python Frame Evaluation Hook技术,实现安全的Pytorch的计算图捕获。

AOTAutograd: AOT生成计算图的反向图。

PrimTorch:规范化2000+ PyTorch Operators为250+ Primitive Operators, 极大降低了开发Pytorch后端的难度。

TorchInductor:一个Deep Learning Compiler,为多种加速器生成高性能代码。对NVIDIA和AMD GPUs, 使用OpenAI Triton编译器作为Backend。

torch.compile编译过程如下:

在图编译视角下,Pytorch的软件栈如下,Triton是Inductor的一个Codegen Backend:

示例

以如下pytorch代码为例:

import torch

def mul(x1, x2):
    return x1 * x2

x1 = torch.randn(4096, 390, device='cuda', requires_grad=True)
x2 = torch.randn(4096, 390, device='cuda', requires_grad=True)
fn = torch.compile(mul, backend='inductor')
out = fn(x1, x2)
out.sum().backward()

编译过程

在pytorch/torch/_inductor/codecache.py中的write函数打印调用栈,观察torch.compile的实际编译过程:

def write(
    content: Union[str, bytes],
    extension: str,
    extra: str = "",
    hash_type: str = "code",
    specified_dir: str = "",
) -> Tuple[str, str]:
    # use striped content to compute hash so we don't end up with different
    # hashes just because the content begins/ends with different number of
    # spaces.
    print('#######################################################')
    import traceback
    traceback.print_stack()
    ...

前向图编译

通过分析调用栈,可以看到:

  • JIT编译:前向图的编译在调用编译的模型时触发:out = fn(x1, x2),并不是在fn = torch.compile(mul, backend='inductor')时触发。
  • TorchDynamo:从out = fn(x1, x2)到return compile_fx(model_, inputs_, config_patches=self.config)完成了Python Bytecode捕获,并转换为FX Graph。
  • AOT Autograd:从return compile_fx(model_, inputs_, config_patches=self.config)到return self.compiler_fn(gm, example_inputs),完成了反向图FX Graph的生成和Autograd注册,为后续反向图编译打下了基础。
  • Inductor:从return inner_compile到return self._compile_to_module实现了FX Graph到Triton Kernel的编译。
  File "/home/vincent/mul.py", line 10, in <module>
    out = fn(x1, x2)
  File "/home/vincent/pytorch/torch/_dynamo/eval_frame.py", line 574, in _fn
    return fn(*args, **kwargs)
  File "/home/vincent/pytorch/torch/_dynamo/convert_frame.py", line 1380, in __call__
    return self._torchdynamo_orig_callable(
  File "/home/vincent/pytorch/torch/_dynamo/convert_frame.py", line 1164, in __call__
    result = self._inner_convert(
  File "/home/vincent/pytorch/torch/_dynamo/convert_frame.py", line 547, in __call__
    return _compile(
  File "/home/vincent/pytorch/torch/_dynamo/convert_frame.py", line 986, in _compile
    guarded_code = compile_inner(code, one_graph, hooks, transform)
  File "/home/vincent/pytorch/torch/_dynamo/convert_frame.py", line 715, in compile_inner
    return _compile_inner(code, one_graph, hooks, transform)
  File "/home/vincent/pytorch/torch/_utils_internal.py", line 95, in wrapper_function
    return function(*args, **kwargs)
  File "/home/vincent/pytorch/torch/_dynamo/convert_frame.py", line 750, in _compile_inner
    out_code = transform_code_object(code, transform)
  File "/home/vincent/pytorch/torch/_dynamo/bytecode_transformation.py", line 1361, in transform_code_object
    transformations(instructions, code_options)
  File "/home/vincent/pytorch/torch/_dynamo/convert_frame.py", line 231, in _fn
    return fn(*args, **kwargs)
  File "/home/vincent/pytorch/torch/_dynamo/convert_frame.py", line 662, in transform
    tracer.run()
  File "/home/vincent/pytorch/torch/_dynamo/symbolic_convert.py", line 2868, in run
    super().run()
  File "/home/vincent/pytorch/torch/_dynamo/symbolic_convert.py", line 1052, in run
    while self.step():
  File "/home/vincent/pytorch/torch/_dynamo/symbolic_convert.py", line 962, in step
    self.dispatch_table[inst.opcode](self, inst)
  File "/home/vincent/pytorch/torch/_dynamo/symbolic_convert.py", line 3048, in RETURN_VALUE
    self._return(inst)
  File "/home/vincent/pytorch/torch/_dynamo/symbolic_convert.py", line 3033, in _return
    self.output.compile_subgraph(
  File "/home/vincent/pytorch/torch/_dynamo/output_graph.py", line 1101, in compile_subgraph
    self.compile_and_call_fx_graph(
  File "/home/vincent/pytorch/torch/_dynamo/output_graph.py", line 1382, in compile_and_call_fx_graph
    compiled_fn = self.call_user_compiler(gm)
  File "/home/vincent/pytorch/torch/_dynamo/output_graph.py", line 1432, in call_user_compiler
    return self._call_user_compiler(gm)
  File "/home/vincent/pytorch/torch/_dynamo/output_graph.py", line 1462, in _call_user_compiler
    compiled_fn = compiler_fn(gm, self.example_inputs())
  File "/home/vincent/pytorch/torch/_dynamo/repro/after_dynamo.py", line 130, in __call__
    compiled_gm = compiler_fn(gm, example_inputs)
  File "/home/vincent/pytorch/torch/__init__.py", line 2340, in __call__
    return compile_fx(model_, inputs_, config_patches=self.config)
  File "/home/vincent/pytorch/torch/_inductor/compile_fx.py", line 1863, in compile_fx
    return aot_autograd(
  File "/home/vincent/pytorch/torch/_dynamo/backends/common.py", line 83, in __call__
    cg = aot_module_simplified(gm, example_inputs, **s
<think>我们被要求用中文回答,并在最后提出3-5个相关问题,以“§§相关问题§§”开头,然后列出问题。 用户的问题是:torch.compile是什么用法 首先,回答torch.compile的用法: torch.compilePyTorch 2.0 引入的一个功能,用于将 PyTorch 模型编译成更高效的表示形式,从而加速模型运行。它通过使用即时(JIT)编译技术,将模型图优化并转换为底层硬件特定的代码,以提高执行速度。 具体用法: 1. 基本用法:使用 torch.compile 包裹一个模型(nn.Module 实例)或一个函数。 2. 参数说明: - model_or_function: 要编译的模型或函数。 - mode: 编译模式,可选 "default"(平衡优化)、"reduce-overhead"(减少框架开销,适用于小模型)和 "max-autotune"(最大程度优化,编译时间长)。 - dynamic: 是否开启动态形状支持(适用于输入形状变化的场景)。 示例代码: ```python import torch # 定义一个简单的模型 class MyModel(torch.nn.Module): def __init__(self): super().__init__() self.linear = torch.nn.Linear(10, 10) def forward(self, x): return self.linear(x) model = MyModel() # 编译模型 compiled_model = torch.compile(model) # 使用编译后的模型 input_tensor = torch.randn(1, 10) output = compiled_model(input_tensor) ``` 3. 注意事项: - 第一次调用编译后的函数或模型时,会进行编译,因此会较慢,后续调用会使用缓存。 - 对于动态图(每次执行图结构变化的情况)可能不适用。 4. 高级用法:使用 `torch.compile` 也可以编译任意函数,例如: ```python def my_function(x, y): return x @ y compiled_function = torch.compile(my_function) result = compiled_function(torch.randn(2,2), torch.randn(2,2)) ``` 5. 性能建议: - 对于循环中的小操作,编译整个循环而不是内部操作。 - 对于大模型,使用 `mode="max-autotune"` 可能获得最佳性能,但需要更长的编译时间。 接下来,根据问题和回答,提出3-5个相关问题。 相关问题可围绕以下方面: 1. torch.compile 的工作原理 2. 不同模式的区别和选择 3. 实际应用中的性能提升 4. 使用限制和注意事项 因此,我们可以提出以下问题: §§相关问题§§ 1. torch.compile 在底层使用了哪些编译技术来加速 PyTorch 模型? 2. 如何根据模型的大小和结构选择合适的 torch.compile 模式(如 "default"、"reduce-overhead"、"max-autotune")? 3. 在实际项目中,使用 torch.compile 通常能带来多少性能提升?请举例说明。 4. 在哪些情况下不适合使用 torch.compile? 5. 如何诊断 torch.compile 编译后的模型性能瓶颈? </think> ### `torch.compile` 的用法详解 `tororch.compile` 是 PyTorch 2.0 引入的核心特性,用于**动态编译模型图**,显著提升计算效率。其核心机制是通过即时编译(JIT)将 Python 模型转换为优化的底层代码(如 C++/CUDA)。以下是关键用法: #### 1. 基础语法 ```python compiled_fn = torch.compile( fn, # 待编译的函数或 nn.Module *, mode="default", # 编译模式 dynamic=False, # 动态形状支持 fullgraph=False, # 强制完整编译 backend="inductor", # 默认后端 options=None # 后端配置 ) ``` #### 2. 核心参数解析 | 参数 | 可选值 | 作用 | |------|--------|------| | **`mode`** | `"default"` (平衡优化)<br>`"reduce-overhead"` (减少小模型开销)<br>`"max-autotune"` (极致性能) | 优化策略选择 | | **`dynamic`** | `True`/`False` | 启用动态形状支持(处理可变输入尺寸) | | **`fullgraph`** | `True`/`False` | 强制整个模型可编译(否则回退 eager 模式) | | **`backend`** | `"inductor"` (默认)<br>`"aot_eager"`<br>`"nvfuser"` | 编译引擎选择 | #### 3. 典型使用场景 **场景 1:加速自定义函数** ```python def cosine_sim(x, y): return x @ y.T / (x.norm(dim=1) * y.norm(dim=1)) # 编译函数(减少 3-5 倍耗时) compiled_cos = torch.compile(cosine_sim) result = compiled_cos(tensor_a, tensor_b) ``` **场景 2:优化神经网络(官网示例应用)** ```python from e3nn import o3 # 原始张量积操作 tp = o3.FullTensorProduct(irreps_in1="1o", irreps_in2="1o") # 编译为高效内核(首次运行慢,后续加速 2-10 倍) tp_compiled = torch.compile(tp, fullgraph=True, mode="max-autotune") z = tp_compiled(x, x) # 编译发生在首次调用 ``` #### 4. 性能对比建议 ```python import timeit # 基准测试(未编译) t1 = timeit.timeit(lambda: tp(x,x), number=100) # 基准测试(已编译) t2 = timeit.timeit(lambda: tp_compiled(x,x), number=100) print(f"加速比: {t1/t2:.1f}x") # 典型输出: 加速比: 4.8x ``` #### 5. 注意事项 - **预热阶段**:首次调用会触发编译(较慢),后续调用高速运行 - **动态形状限制**:默认仅支持静态形状,启用 `dynamic=True` 处理变长输入 - **算子覆盖**:部分自定义算子需注册才能编译([参见文档](https://pytorch.org/docs/stable/torch.compiler.html)) > **适用场景**:循环计算/科学计算/3D 处理(如 e3nn)/大模型推理
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值