当前位置: 首页 > ops >正文

深度学习中的计算图与自动微分原理:静态图与动态图的实现差异

深度学习与计算图的基本概念

在人工智能技术飞速发展的2025年,深度学习已成为推动各领域智能化变革的核心引擎。要理解深度学习系统的运作机制,计算图(Computational Graph)这一基础概念是绕不开的关键环节。计算图不仅是深度学习框架的底层支撑,更是理解现代神经网络训练过程的重要视角。

计算图:深度学习的"施工蓝图"

计算图本质上是一种有向无环图(DAG),它以数学形式精确描述深度学习模型的运算流程。图中节点代表张量(Tensor)或运算操作(Operation),边则代表数据流向。以简单的全连接网络为例,输入数据从图的一端流入,经过层层变换后,最终输出预测结果。

这种图形化表示具有三大核心优势:

  1. 1. 可视化计算流程:将复杂的数学运算转化为直观的拓扑结构
  2. 2. 支持自动微分:为反向传播算法提供结构化计算路径
  3. 3. 优化计算效率:框架可对计算图进行整体优化

计算图的组成要素

现代深度学习框架中的计算图通常包含以下关键组件:

  • 张量节点:存储多维数组数据,包括模型参数和中间计算结果
  • 操作节点:实现各类数学运算,如矩阵乘法、卷积等
  • 依赖边:定义操作之间的执行顺序和数据流向
  • 梯度节点:在反向传播时自动生成,存储各参数的梯度信息

以PyTorch框架为例,当执行z = x @ w + b这样的操作时,框架会自动构建包含矩阵乘法(@)和加法(+)两个操作节点的计算图,同时记录各张量间的依赖关系。

计算图在训练过程中的作用

在模型训练过程中,计算图扮演着双重角色:

  1. 1. 前向传播阶段:按照拓扑顺序执行图中操作,计算预测输出
  2. 2. 反向传播阶段:沿着图的逆向路径,利用链式法则计算各参数梯度

这种双向计算流程使得现代深度学习框架能够实现"自动微分"(Autodifferentiation)这一核心功能。以2025年主流的混合精度训练为例,计算图会智能管理FP16和FP32两种精度的转换节点,确保在保持数值稳定性的同时提升训练速度。

计算图的抽象层次

从实现角度看,计算图可分为不同抽象层次:

  1. 1. 用户级计算图:开发者直接操作的API接口层
  2. 2. 中间表示(IR):框架内部优化的中间形式
  3. 3. 硬件执行图:针对特定计算设备(如GPU、TPU)优化的最终执行计划

这种分层设计使得框架可以在不影响用户编程体验的前提下,在底层进行各种性能优化。例如,TensorFlow 2.x的XLA编译器就会将计算图转换为高度优化的LLVM IR,显著提升模型执行效率。

计算图与模型部署

在模型部署环节,计算图同样发挥着关键作用。通过将动态训练图转换为静态推理图(如ONNX格式),可以实现:

  • • 跨平台部署一致性
  • • 图级优化(算子融合、常量折叠等)
  • • 内存使用效率最大化

2025年新兴的"图感知量化"技术,就是基于计算图结构分析来智能选择各层的量化策略,在保证模型精度的同时实现4-8倍的推理加速。

理解计算图的工作机制,不仅有助于开发者更高效地使用深度学习框架,更能为后续深入探讨静态图与动态图的实现差异奠定基础。这两种图执行模式虽然在表现形式上有所不同,但都基于相同的计算图理论基础,只是在构建时机和执行策略上采取了不同的技术路线。

自动微分原理详解

在深度学习的训练过程中,自动微分(Automatic Differentiation,AD)是支撑神经网络参数优化的核心技术。与传统的符号微分和数值微分不同,自动微分通过分解程序为一系列基础表达式,利用链式法则组合各表达式的微分结果,实现了高效精确的梯度计算。这一过程可以分为正向传播和反向传播两个关键阶段。

自动微分计算流程示意图

 

正向传播:构建计算轨迹

正向传播阶段会记录所有中间变量的计算过程。以一个简单函数为例:f(x,y)=sin(x²)+e^(xy),其计算过程会被分解为:

  1. 1. v₁ = x²
  2. 2. v₂ = sin(v₁)
  3. 3. v₃ = x*y
  4. 4. v₄ = e^(v₃)
  5. 5. v₅ = v₂ + v₄

现代深度学习框架如PyTorch和TensorFlow会通过操作符重载(Operator Overloading)技术,在执行这些基础运算时自动构建计算图。2025年最新研究显示,主流框架对正向传播的优化已能将计算开销控制在原始运算的1.05-1.2倍范围内。

反向传播:链式法则的应用

反向传播阶段从输出节点开始,沿着计算图逆向传播梯度。以上述函数为例,假设最终输出为L,反向传播过程为:

  1. 1. ∂L/∂v₅ = 1
  2. 2. ∂L/∂v₄ = ∂L/∂v₅ * ∂v₅/∂v₄ = 1*1
  3. 3. ∂L/∂v₃ = ∂L/∂v₄ * ∂v₄/∂v₃ = 1*e^(v₃)
  4. 4. ∂L/∂y = ∂L/∂v₃ * ∂v₃/∂y = e^(v₃)*x

这个过程体现了自动微分的核心优势:它不需要推导整个函数的解析导数形式,而是通过局部微分的组合来获得最终梯度。根据2024年机器学习系统研讨会的数据,这种方法的计算复杂度仅比原始函数增加O(1)的常数因子。

雅可比矩阵的高效计算

在涉及多输入多输出的场景中,自动微分需要计算雅可比矩阵。以函数f:Rⁿ→Rᵐ为例,其雅可比矩阵J是一个m×n的矩阵,其中J[i,j]=∂fᵢ/∂xⱼ。现代框架通过以下技术优化雅可比计算:

  1. 1. 稀疏矩阵识别:自动检测输入输出间的稀疏依赖关系,跳过零元素计算。如PyTorch的autograd模块在2025年更新中引入了更智能的稀疏模式识别算法。
  2. 2. 向量-雅可比积(VJP):当只需要计算Jᵀv时(如反向传播),直接通过VJP避免构建完整雅可比矩阵。实验表明这能将内存占用降低60-80%。
  3. 3. 分块计算策略:对大型雅可比矩阵采用分块计算,如将1000维输入分成10个100维的块分别处理。最新测试显示,这种方法在RTX 5090显卡上能提升3-5倍计算速度。

微分模式的实现差异

自动微分在实践中分为两种基本模式:

正向模式

  • • 随原始计算同步进行微分
  • • 适合输入维度远小于输出维度的场景
  • • 在2025年的JAX框架中,正向模式对宽神经网络(如宽度达10⁴的全连接层)展现出独特优势

反向模式

  • • 先完成正向计算再反向求导
  • • 更适合深度学习常见的"窄输入-宽中间-单输出"结构
  • • TensorFlow 2.9+版本通过改进的反向传播缓存机制,将梯度计算速度提升了40%

值得注意的是,现代框架如PyTorch 3.0开始支持混合模式,能根据计算图结构自动选择最优微分策略。这种自适应机制在2025年的基准测试中,相比固定模式获得了15-30%的性能提升。

自动微分的实现细节深刻影响着深度学习系统的效率。在编译器优化层面,2024年提出的"微分表达式折叠"技术可以将连续线性运算的微分合并为单次矩阵乘法;而在硬件层面,新一代张量核心(如NVIDIA的Hopper架构)已经原生支持特定微分模式的计算加速。

静态图的实现与特点

在深度学习的实现框架中,静态图(Static Computational Graph)是一种预先定义完整计算流程的范式。与动态图的即时构建不同,静态图要求开发者在模型运行前就明确所有计算节点及其连接关系,这种"先定义后执行"的特性使其在特定场景下展现出独特优势。

静态计算图构建流程

静态计算图构建流程

静态图的构建机制

静态图的构建过程可分为三个关键阶段:

  1. 1. 图定义阶段:开发者通过框架API(如TensorFlow 1.x的Session机制)声明所有张量操作。例如定义全连接层时,需要预先指定输入维度、权重矩阵尺寸等参数,形成固定的计算路径。在2025年的TensorFlow 2.8版本中,虽然默认采用动态图模式,但仍可通过tf.function装饰器将Python函数转换为静态图表示。
  2. 2. 图优化阶段:框架编译器会对完整计算图进行全局优化,包括:
    • • 算子融合(Operator Fusion):将连续执行的多个操作合并为单一核函数
    • • 内存复用:分析张量生命周期,优化显存分配策略
    • • 并行化分析:识别可并行执行的子图分支
  3. 3. 图执行阶段:优化后的计算图被部署到CPU/GPU等硬件设备,此时输入数据按预定流程流动。以图像分类任务为例,静态图会固定从卷积层→池化层→全连接层的计算路径,即使输入图像尺寸变化,计算拓扑结构仍保持不变。

静态图的性能优势

静态图的预编译特性带来显著的效率提升:

  • 编译器级优化:Google Brain团队2024年的基准测试显示,对于ResNet-50模型,静态图通过图优化可获得最高23%的训练速度提升。这是因为编译器能进行跨操作符的全局优化,如将相邻的ReLU和卷积操作合并为单个CUDA核函数。
  • 硬件适配优势:静态图在部署时能生成高度优化的机器代码。以华为昇腾910B芯片为例,其图编译器能将静态计算图转换为特定指令集,实现算子级硬件加速。
  • 内存管理效率:MXNet框架的静态内存分配策略可减少达40%的显存碎片,这对于大模型训练尤为重要。通过预先分析张量生命周期,框架能实现内存的精确复用。

静态图的典型应用场景

  1. 1. 工业级模型部署:在自动驾驶系统等实时性要求高的场景,特斯拉的FSD芯片采用静态图实现确定性计算延迟。2025年最新发布的Dojo 2.0超算平台更是依赖静态图进行分布式计算调度。
  2. 2. 跨平台推理:当模型需要转换为ONNX格式部署到移动端时,静态图能确保计算逻辑的一致性。苹果Core ML 4框架就要求输入模型必须具有静态计算图结构。
  3. 3. 大规模分布式训练:在参数服务器架构中,静态图能精确控制通信时机。微软Azure ML的Horovod优化版通过静态图实现梯度聚合的流水线化,将百亿参数模型的训练效率提升18%。

静态图的局限性

尽管有诸多优势,静态图也存在明显约束:

  • 调试复杂度:由于计算图与实际执行分离,错误往往在运行时才暴露。开发者需要借助TensorBoard等可视化工具回溯问题节点,这增加了调试成本。
  • 灵活性限制:对于需要动态调整结构的模型(如递归神经网络中的可变长度处理),静态图需要复杂的控制流实现。PyTorch的TorchScript虽然支持将动态图转为静态表示,但在处理条件分支时仍可能丢失部分灵活性。
  • 开发迭代速度:每次模型结构调整都需要重新构建计算图。Meta的内部测试显示,在原型开发阶段,使用静态图的工程师平均需要多花费15%的时间进行图重建。

在最新的框架演进中,静态图技术正通过混合执行模式寻求突破。如TensorFlow 2.x的AutoGraph功能能自动将Python控制流转换为静态图表示,而PyTorch 2.1的Dynamo编译器则尝试在保持动态编程体验的同时提取静态子图。这些创新正在模糊静态图与动态图的传统界限。

动态图的实现与特点

在深度学习框架的发展历程中,动态图(Dynamic Graph)以其独特的运行时构建机制,成为PyTorch等主流框架的核心竞争力。这种"边执行边构图"的范式彻底改变了开发者的工作流程,使得2025年的模型研发效率相比静态图时代有了质的飞跃。

运行时构建机制剖析

动态图的核心特征在于其即时执行(Eager Execution)模式。当执行x = torch.tensor([1.0], requires_grad=True)这样的语句时,计算图并非预先定义,而是在Python解释器逐行执行代码的过程中动态生成。以PyTorch 2.3版本为例,其自动微分系统会在张量运算发生时实时记录操作序列,形成所谓的"动态计算图"。

这种机制带来三个关键技术特性:

  1. 1. 操作记录的即时性:每个torch.nn.Module的forward方法调用都会触发新的图构建过程
  2. 2. 拓扑结构的可变性:同一个模型对不同的输入可以生成完全不同的计算路径
  3. 3. 调试的透明性:开发者可以使用标准Python调试工具实时检查中间变量
# 动态条件分支的典型实现(PyTorch风格)
class DynamicBlock(nn.Module):def forward(self, x):if x.mean() > 0:  # 运行时决定的图结构return self.layer1(x)else:return self.layer2(x)  # 另一条计算路径

灵活性的技术实现

动态图的灵活性源于其底层设计中的几个关键决策:

  • 符号追踪(Symbolic Tracing)延迟:不同于静态图在编译阶段就完成算子融合等优化,动态图将符号追踪推迟到运行时
  • Python控制流原生支持:可以直接使用if/for/while等原生语法,无需转换为特定图操作
  • 动态形状处理:每个前向传播可以处理不同维度的输入张量

这种设计使得处理变长序列等任务变得异常简单。在2024年发布的PyTorch 2.2中,动态图对Transformer类模型的支持效率提升了40%,这正是得益于其对可变长度输入的天然适配能力。

性能与调试的平衡艺术

动态图的优势伴随着明显的性能代价。基准测试显示,相同模型在动态图模式下的训练速度通常比静态图慢15-20%。这种开销主要来自:

  1. 1. 运行时构图成本:每次前向传播都需要重新构建计算图
  2. 2. 优化机会减少:难以进行跨多个操作的全局优化
  3. 3. 内存管理压力:无法预先规划内存复用策略

然而,动态图的调试优势不容忽视。开发者可以:

  • • 使用标准pdb设置断点
  • • 实时打印任意中间变量的值
  • • 动态修改网络结构进行实验
# 动态调试示例
def forward(self, x):h = self.conv1(x)  # 可在此处插入print(h.shape)if h.max() > 1.0:   # 可动态调整阈值return self.branch1(h)...

典型应用场景演化

随着多模态模型的兴起,动态图在以下场景展现出不可替代性:

  1. 1. 文本-图像交叉建模
# 处理变长文本和固定尺寸图像的混合输入
def forward(self, text, image):text_feat = self.text_encoder(text)  # 动态处理不同长度文本image_feat = self.cnn(image)         # 固定结构处理return self.fusion(text_feat, image_feat)  # 动态决定融合方式
  1. 2. 元学习(Meta-Learning)
    在2025年流行的参数高效微调(PEFT)技术中,动态图允许在单个前向传播过程中:
  • • 根据任务描述动态选择适配器模块
  • • 实时构建基于输入特征的残差连接
  • • 条件性冻结特定参数层
  1. 3. 概率编程
    Pyro等概率编程库深度依赖动态图特性,实现:
  • • 随机计算图的动态展开
  • • 运行时观测值的灵活注入
  • • 变分推理结构的自适应调整

框架实现差异比较

主流框架对动态图的实现各有侧重:

特性PyTorch (2.3+)JAX (2025)TensorFlow Eager
控制流支持Python原生jax.laxAutoGraph转换
微分方式反向模式自动微分正/反向自动微分反向模式自动微分
分布式训练原生支持需搭配Ray等框架有限支持
动态形状优化全支持部分支持有限支持

值得注意的是,2024年后出现的框架如MindSpore 3.0开始采用"动静统一"的架构,试图在保持动态图开发体验的同时,通过即时编译(JIT)技术获取接近静态图的性能。

静态图与动态图的对比分析

在深度学习框架的发展历程中,静态图(Static Graph)与动态图(Dynamic Graph)的差异一直是开发者关注的焦点。这两种计算图实现方式在模型构建、执行效率和调试体验上展现出截然不同的特性,深刻影响着框架的设计哲学和应用场景。

静态图与动态图结构对比

 

计算图构建方式的本质差异

静态图的构建过程如同建筑施工蓝图,需要预先完整定义所有计算节点和连接关系。以TensorFlow 1.x为代表的静态图框架要求开发者先通过占位符(placeholder)和操作符(op)构建完整的计算图,再通过Session会话执行具体计算。这种"先定义后执行"的模式使得框架可以在图构建阶段进行全局优化,例如操作融合(operation fusion)和常量折叠(constant folding)。2025年最新发布的TensorFlow 2.8在保留静态图优化的同时,通过XLA编译器进一步提升了图执行效率。

相比之下,动态图采用"边定义边执行"的方式,PyTorch的即时执行(eager execution)模式是其典型代表。开发者可以像编写普通Python代码一样逐行构建计算图,每个操作都会立即执行并返回结果。这种特性使得动态图在2025年的研究领域仍保持绝对优势,特别是在处理Transformer架构中复杂的注意力机制时,开发者可以实时调整计算路径。

性能与灵活性的权衡

在计算性能方面,静态图具有显著优势。由于整个计算流程在运行前就已确定,框架可以进行深度的内存预分配和并行调度优化。工业级部署数据显示,静态图在批量推理场景下能达到动态图1.5-3倍的吞吐量。这也是为什么TensorFlow Serving和ONNX Runtime等生产环境工具链仍然主要基于静态图技术。

动态图的优势则体现在开发灵活性和调试便利性上。研究者可以:

  • • 使用标准Python调试工具实时检查中间变量
  • • 动态修改网络结构(如条件分支和循环控制)
  • • 实现更复杂的数据依赖控制流

2024年arXiv上发表的《Dynamic Graph Neural Networks for Evolving Topologies》论文显示,在涉及动态图结构的GNN应用中,PyTorch的实现效率反而超越静态图方案,这得益于动态图对不规则计算的自然支持。

内存管理机制的对比

静态图的内存管理采用预分配策略,框架在编译阶段就能精确计算各张量的生命周期。以MXNet为例,其内存共享算法可以重复利用中间结果的存储空间,在ResNet-152等深层网络上能减少40%的显存占用。但这种优化也带来了限制——开发者无法在运行时灵活调整张量形状。

动态图则采用即时内存分配策略,每个操作都会立即申请所需内存。虽然PyTorch 2.0引入的torch.compile尝试通过图捕获技术优化这一问题,但在处理超大规模参数模型时,静态图的内存管理优势仍然明显。实际测试表明,在训练参数量超过100B的模型时,静态图框架的内存峰值比动态图低15-20%。

自动微分实现的底层差异

两种模式在自动微分实现上也有根本区别。静态图通常采用符号微分(Symbolic Differentiation),在构建计算图时就记录微分规则。TensorFlow通过gradient_tape机制将微分信息编码在图结构中,这种设计使得高阶导数计算更加高效。

动态图则主要依赖追踪微分(Tape-Based Differentiation),PyTorch的autograd引擎会在执行过程中动态记录操作历史。这种机制虽然增加了运行时开销,但支持更灵活的微分控制。2025年PyTorch新增的functorch模块就充分利用了这一特性,实现了可组合的函数变换。

典型应用场景分析

在计算机视觉领域,静态图在以下场景表现突出:

  • • 固定结构的CNN模型部署
  • • 移动端模型量化(如TensorFlow Lite)
  • • 多GPU数据并行训练

而动态图则在以下场景不可替代:

  • • NLP中的动态序列处理
  • • 强化学习的策略梯度计算
  • • 元学习(Meta-Learning)中的内循环优化

值得注意的是,随着JIT(Just-In-Time)编译技术的发展,两种模式的界限正在模糊。PyTorch的TorchScript和TensorFlow的tf.function都试图在保持接口灵活性的同时,获得静态图的性能优势。2025年发布的OneFlow 0.9甚至实现了动态图到静态图的实时转换,在BERT训练任务中取得了接近静态图的性能。

如何选择适合的实现方式

在深度学习项目的实际开发中,选择静态图还是动态图实现方式需要综合考虑多个维度的因素。2025年的主流框架如PyTorch和TensorFlow已经实现了两种模式的兼容,但核心差异仍然存在,这直接关系到开发效率、模型性能和部署灵活性。

开发阶段与调试需求

动态图的即时执行特性使其成为研究和原型开发的首选。当项目处于以下场景时,建议优先考虑动态图:

  • 模型结构频繁迭代:在NLP领域处理变长序列时,动态图允许根据输入长度实时调整网络结构。例如Transformer模型中注意力掩码的动态生成
  • 复杂控制流需求:涉及条件分支(如不同样本采用不同子网络)或循环结构(如递归神经网络)时,使用Python原生控制流比静态图的tf.cond()等特殊操作更直观
  • 调试密集型任务:动态图支持逐行执行和实时变量检查,在排查梯度消失/爆炸问题时,能够直接观察中间张量的数值分布

PyTorch的Eager模式典型案例显示,在模型开发初期采用动态图可将调试时间缩短40-60%,这在2025年各大实验室的实践中得到验证。

性能敏感型场景

当项目进入生产部署阶段,静态图的优势开始凸显。以下情况应当考虑静态图方案:

  • 高吞吐量要求:图像分类服务需要处理每秒数万次请求时,静态图的图优化(算子融合、常量折叠等)能提升30%以上的推理速度
  • 移动端/边缘计算:通过TensorRT或ONNX转换后的静态图模型,在资源受限设备上内存占用可降低50%
  • 跨平台部署:需要同时支持x86 CPU、ARM架构和各类AI加速芯片时,静态图的预编译特性确保一致性

工业界数据显示,2025年超过70%的云端AI服务最终都采用了静态图优化方案。典型的成功案例包括智能客服系统中的意图识别模块,通过TensorFlow的SavedModel格式实现毫秒级响应。

模型复杂度与团队规模

对于超大规模模型训练,两种模式的取舍需要更精细的权衡:

  • 百亿参数模型:静态图的分布式训练优化更成熟,如Megatron-LM采用的流水线并行策略
  • 小规模敏捷团队:5人以下的研发团队更适合动态图快速验证想法,避免陷入静态图构建的复杂性
  • 混合架构趋势:2025年主流框架支持训练时动态图+部署时静态图的混合工作流,如PyTorch的TorchScript可保留动态编程接口的同时生成优化后的静态图

硬件适配考量

不同硬件架构对计算图类型的适配性存在明显差异:

  • GPU集群:静态图能充分发挥CUDA Graph的异步执行优势,NVIDIA H100上的测试显示训练速度提升达25%
  • 新型AI芯片:部分国产TPU对动态图支持有限,需提前确认框架兼容性
  • 内存优化需求:静态图的内存复用策略(如TensorFlow的XLA)可降低显存消耗30-50%,这对大模型训练至关重要

全生命周期成本评估

选择时还需考虑项目全周期的综合成本:

  1. 1. 开发成本:动态图平均节省40%的初期开发时间
  2. 2. 训练成本:静态图可降低15-20%的云计算费用
  3. 3. 维护成本:静态图版本兼容性更好,长期维护成本更低
  4. 4. 转换成本:动态图转静态图需要额外5-15%的工程投入

医疗影像分析领域的实践表明,当模型日调用量超过100万次时,静态图节省的运算成本可在6个月内覆盖额外的转换投入。


引用资料

[1] : https://www.cnblogs.com/ZOMI/articles/18562873

[2] : https://wenku.csdn.net/column/4umna8gini

[3] : https://blog.csdn.net/weixin_60737527/article/details/127414198

http://www.xdnf.cn/news/16351.html

相关文章:

  • 【Oracle】Oracle分区表“排雷“指南:当ORA-14400错误找上门时如何优雅应对
  • 关于GateWay网关
  • 显式等待和隐式等待的区别
  • 【星野AI】minimax非活动时间充值优惠漏洞
  • 基于springboot的图书借阅系统
  • 《计算机组成原理与汇编语言程序设计》实验报告二 基本数字逻辑及汉字显示
  • 方案C,version2
  • 《C++ list 完全指南:从基础到高效使用》
  • Tactile-VLA:解锁视觉-语言-动作模型的物理知识,实现触觉泛化
  • 【AcWing 830题解】单调栈
  • 是德科技 | AI上车后,这条“高速公路”如何畅通?
  • HarmonyOS应用上架流程详解
  • 【音视频协议篇】WebRTC 快速入门
  • unittest 案例执行顺序详解
  • QUIC协议如何在UDP基础上解决网络切换问题
  • 相机标定相关原理
  • NTLite Ent Version
  • leetcode112, 257:二叉树的路径总和、二叉树的所有路径双题对比
  • 【Pandas】pandas Index objects Index.name
  • MGER实验
  • 【面板数据】中国A股上市公司制造业智能制造数据集(1992-2024年)
  • 不正确的 clone() 方法实现与修复方案
  • 中电建路桥集团有限公司重大项目管理办公室成立
  • Vibe Coding | 技术让我们回归了创造的本质
  • Spring Boot 单元测试进阶:JUnit5 + Mock测试与切片测试实战及覆盖率报告生成
  • HTTPS协议
  • 检索召回率优化探究一:基于 LangChain 0.3集成 Milvus 2.5向量数据库构建的智能问答系统
  • 通过redis_exporter监控redis cluster
  • 在Word和WPS文字中要同时查看和编辑一个文档的两个地方?拆分窗口
  • 每日一题【删除有序数组中的重复项 II】