PyTorch 入门

1 核心概念:Symbolic(符号式) vs. Imperative(命令式)

特性 Symbolic(符号式/声明式) Imperative(命令式)
核心思想 先定义,后执行。像画蓝图,先声明计算流程(计算图),然后再喂入数据执行。 边定义,边执行。像捏粘土,每个操作指令会立即执行并返回结果。
类比 编译器语言(如C++):先写好所有代码,编译生成可执行文件,然后运行。 解释型语言(如Python):写一行代码,解释器就立即执行一行,并给出结果。
工作流程 1. 定义计算图(Placeholder,Variable,Operation)
2. 创建会话(Session)
3. 在会话中喂数据,运行图
1. 定义张量(Tensor)
2. 直接执行操作(如 c = a + b),立即得到结果
优点 - 高性能优化:框架可以看到整个计算图,可以进行大幅度的优化(如操作融合、内存复用)。
- 易于部署:整个计算图可以很容易地序列化、导出并在不同平台部署(移动端、服务器)。
- 语言无关性:计算图是一种中间表示,可以用不同语言实现后端。
- 直观灵活:符合Python编程习惯,易于理解和调试。
- 动态控制流:可以使用Python原生的if...elseforwhile循环,非常适合动态网络结构(如RNN)。
- 易于调试:可以随时打印中间变量的值,像调试普通Python代码一样。
缺点 - 不直观:像“隔墙操作”,定义计算流程和实际执行分离,学习曲线较陡。
- 调试困难:无法在定义图的时候直接打印中间结果,需要使用Session.run()
- 动态结构支持差:处理可变长度输入或复杂控制流的模型时非常笨拙。
- 优化受限:由于是逐行执行,框架无法预知后续操作,难以进行全局优化。
- 开销可能更大:每个操作都可能启动一个GPU内核,带来额外开销。

2 TensorFlow和PyTorch各版本的归属

下面的图表直观地展示了TensorFlow和PyTorch在不同版本中对于符号式和命令式编程模式的侧重与演变历程:

flowchart TD A[深度学习框架范式] --> B{Symbolic 符号式} A --> C{Imperative 命令式} B --> B1[TensorFlow 1.x<br>经典符号式模式] B1 --> B2[TF 2.x + tf.function<br>符号式(默认开启)] C --> C1[PyTorch 1.x<br>经典命令式模式] C1 --> C2[PyTorch 2.x + torch.compile<br>命令式(可编译为图)] B2 -.->|趋势:融合| C2 C2 -.->|趋势:融合| B2

各个版本的具体情况:

框架版本 主要范式 设计哲学
TensorFlow 1.x 符号式 性能优先,为生产环境设计,但牺牲了灵活性。
PyTorch 1.x 命令式 灵活性优先,为研究和实验设计,但早期性能有优化空间。
TensorFlow 2.x 命令式(默认) + 符号式(tf.function 默认采用命令式(即时执行 Eager Execution),但无缝集成符号式(@tf.function),兼顾了性能和灵活性。
PyTorch 2.x 命令式(默认) + 符号式(torch.compile 保持易用性,通过即时编译(JIT)技术追赶性能。命令式为主,大幅增强符号式能力,通过torch.compile等技术引入强大的符号式(图)优化。PyTorch 2.0 的核心是 TorchDynamo 技术,它可以智能地捕获Python程序的计算图,并将其交给TorchInductor 等编译器进行深度优化(如内核融合、图级优化),从而在不改变用户命令式编程习惯的前提下,获得接近静态图的性能。 compiled_model = torch.compile(my_model) # 一行代码获得性能提升;out = compiled_model(x, y) # 第一次调用会编译图,后续调用极快

3 PyTorch的JIT编译技术

Torch的 JIT(Just-In-Time)技术是PyTorch中一种将模型或部分代码转换为中间表示(IR)然后进行优化和执行的编译技术,将动态的命令式的PyTorch代码转换为静态的可优化的计算图。它的主要目标是将动态图(命令式执行)的灵活性与静态图(符号式执行)的性能优势结合起来。

graph TB A[Python代码] --> B{TorchScript转换} B --> C[Tracing<br>跟踪执行] B --> D[Scripting<br>源码解析] C --> E[跟踪图] D --> F[脚本图] E --> G[TorchScript IR] F --> G G --> H[图优化] H --> I[序列化] I --> J[跨平台执行] J --> K[CPU后端] J --> L[GPU后端] J --> M[移动端] J --> N[C++接口]

JIT的核心组件:

  1. TorchScript:这是JIT的核心,它是一种PyTorch代码的中间表示(IR),可以独立于Python运行时运行。TorchScript代码可以通过以下两种方式创建,但trace和script本身是图获取技术,而不是图优化技术:
    • Trace:需要实际运行模型再记录操作来捕获模型结构。它使用示例输入来执行模型,并记录执行的操作。这种方式对于没有分支的模型很有效,但只能记录特定输入下的执行路径,无法捕获依赖于数据的控制流(如循环、条件判断)
    • Script:通过直接解析Python代码来生成TorchScript。它可以捕获所有的控制流,但要求代码必须是TorchScript支持的子集(不能使用部分Python特性)
  2. 优化器:一旦模型被转换为TorchScript,JIT会进行一系列优化,如操作融合、常量传播、死代码消除等,以提高运行效率。
  3. 运行时:优化后的TorchScript可以在高性能的C++运行时中执行,而无需Python解释器,这使得模型可以部署在生产环境中(如移动端、服务器端),并享受性能提升。

JIT的优势:

  • 性能提升:通过图优化和操作融合,减少内核启动次数和内存访问,提高执行速度。
  • 部署友好:可以将模型序列化为一个文件,并在没有Python环境的C++程序中加载运行。
  • 跨平台:支持在GPU、CPU等多种设备上运行,并支持移动端部署。
  • 并行性:图优化可以更好地利用设备并行性。

JIT的局限:

  • Python子集:TorchScript支持Python语法的一个子集,因此不是所有的Python代码都可以被转换。
  • 调试困难:由于图优化和脱离Python环境,调试转换后的模型可能更困难。
  • 动态性限制:虽然脚本模式可以捕获控制流,但一些动态特性(如动态数据结构)可能无法完全支持。

在PyTorch 2.0及以后的版本中,JIT技术仍然被使用,但同时PyTorch也引入了新的编译技术(如TorchDynamo和TorchInductor)来进一步优化性能。这些新技术旨在更好地支持动态图,并提供更简单的使用方式。

posted @ 2025-11-24 17:46  qccz123456  阅读(22)  评论(0)    收藏  举报