前向,反向成本计算

我们来详细推导并计算卷积层的前向传播和反向传播在计算成本(乘法与加法次数)和内存占用方面的表达式。


📌 基本设定

  • 输入尺寸:$ c_i \times h \times w $
  • 卷积核尺寸:$ c_o \times c_i \times k_h \times k_w $
  • 填充:$ (p_h, p_w) $
  • 步幅:$ (s_h, s_w) $

输出空间尺寸为:

\[h_{out} = \left\lfloor \frac{h + 2p_h - k_h}{s_h} \right\rfloor + 1,\quad w_{out} = \left\lfloor \frac{w + 2p_w - k_w}{s_w} \right\rfloor + 1 \]


✅ 第一部分:前向传播(Forward Pass)

1. 计算成本(FLOPs)

每个输出点的计算量:

  • 卷积核大小:$ k_h \times k_w \times c_i $ 个权重
  • 每个权重与输入对应位置相乘 → $ k_h \cdot k_w \cdot c_i $ 次乘法
  • 所有结果累加 → $ k_h \cdot k_w \cdot c_i - 1 $ 次加法

所以每个输出点需要:

  • 乘法数:$ k_h \cdot k_w \cdot c_i $
  • 加法数:$ k_h \cdot k_w \cdot c_i - 1 $

总共有 $ c_o \cdot h_{out} \cdot w_{out} $ 个输出点。

总 FLOPs(乘法 + 加法):

\[\text{FLOPs}_{\text{forward}} = c_o \cdot h_{out} \cdot w_{out} \cdot k_h \cdot k_w \cdot c_i \cdot 2 - c_o \cdot h_{out} \cdot w_{out} \]

忽略常数项,通常简化为:

\[\boxed{ \text{FLOPs}_{\text{forward}} \approx 2 \cdot c_o \cdot c_i \cdot k_h \cdot k_w \cdot h_{out} \cdot w_{out} } \]


2. 内存占用(Forward Memory)

考虑以下几部分内存开销:

组成 大小
输入特征图 $ c_i \cdot h \cdot w $
卷积核参数 $ c_o \cdot c_i \cdot k_h \cdot k_w $
输出特征图 $ c_o \cdot h_{out} \cdot w_{out} $

注意:前向传播过程中不需要保存中间激活值用于梯度计算(除非显式开启 retain_grad()),因此不额外增加内存。

总内存占用:

\[\boxed{ \text{Memory}_{\text{forward}} = c_i \cdot h \cdot w + c_o \cdot c_i \cdot k_h \cdot k_w + c_o \cdot h_{out} \cdot w_{out} } \]


✅ 第二部分:反向传播(Backward Pass)

3. 反向传播的内存占用

反向传播中需要存储的内容包括:

组成 大小 说明
输入特征图缓存 $ c_i \cdot h \cdot w $ 前向时保存,用于计算梯度
权重参数 $ c_o \cdot c_i \cdot k_h \cdot k_w $ 用于梯度更新
输出梯度 $ c_o \cdot h_{out} \cdot w_{out} $ 已知
权重梯度 $ c_o \cdot c_i \cdot k_h \cdot k_w $ 计算得到
输入梯度 $ c_i \cdot h \cdot w $ 计算得到

总内存占用:

\[\boxed{ \text{Memory}_{\text{backward}} = 2 \cdot c_i \cdot h \cdot w + 2 \cdot c_o \cdot c_i \cdot k_h \cdot k_w + c_o \cdot h_{out} \cdot w_{out} } \]


4. 反向传播的计算成本(FLOPs)

非常好的问题!我们来详细推导反向传播的计算成本(FLOPs),并解释为什么它是前向传播的 两倍,即:

\[\text{FLOPs}_{\text{backward}} \approx 4 \cdot c_o \cdot c_i \cdot k_h \cdot k_w \cdot h_{out} \cdot w_{out} \]


🔁 回顾前向传播计算量(FLOPs)

  • 输入:$ c_i \times h \times w $
  • 卷积核:$ c_o \times c_i \times k_h \times k_w $
  • 输出:$ c_o \times h_{out} \times w_{out} $

每个输出点需要:

  • $ k_h \cdot k_w \cdot c_i $ 次乘法
  • $ k_h \cdot k_w \cdot c_i - 1 $ 次加法

所以每点约 $ 2 \cdot k_h \cdot k_w \cdot c_i $ 次运算。

总 FLOPs:

\[\text{FLOPs}_{\text{forward}} = c_o \cdot h_{out} \cdot w_{out} \cdot 2 \cdot k_h \cdot k_w \cdot c_i = 2 \cdot c_o \cdot c_i \cdot k_h \cdot k_w \cdot h_{out} \cdot w_{out} \]


🔁 反向传播的两个主要部分

在反向传播中,我们需要计算两个梯度:

1️⃣ 对输入的梯度(Backward with respect to input, grad_input

这一步类似于一个“转置卷积”操作,目的是将输出梯度传递回输入空间。

计算方式:

  • 输入梯度尺寸:$ c_i \times h \times w $
  • 每个输入通道对每个输出通道进行滑动窗口操作。
  • 每次滑动窗口操作涉及 $ k_h \cdot k_w $ 个元素(因为是 kernel 大小)
  • 总共有 $ c_i \cdot c_o \cdot h \cdot w $ 个这样的位置(每个输入通道 × 每个输出通道 × 空间位置)

但注意,实际上不是所有位置都参与计算。更准确地说:

  • 每个输出通道有 $ h_{out} \cdot w_{out} $ 个激活值
  • 每个激活值影响输入图上的 $ k_h \cdot k_w $ 区域
  • 所以总的计算次数为:$ c_o \cdot h_{out} \cdot w_{out} \cdot k_h \cdot k_w \cdot c_i $

因此:

\[\text{FLOPs}_{\text{grad\_input}} = 2 \cdot c_o \cdot c_i \cdot k_h \cdot k_w \cdot h_{out} \cdot w_{out} \]

和前向传播相同。


2️⃣ 对权重的梯度(Backward with respect to weights, grad_weight

这一步用于更新卷积核参数。

计算方式:

  • 权重梯度尺寸:$ c_o \times c_i \times k_h \times k_w $
  • 每个权重需要与对应的局部输入区域做乘加操作
  • 每个输出通道 × 输入通道 × kernel 位置 → 需要遍历输出特征图的所有位置

具体来说:

  • 每个输出通道有 $ h_{out} \cdot w_{out} $ 个输出点
  • 每个点对应一个 $ k_h \cdot k_w $ 的局部区域
  • 所以每个 weight 参数对应的乘加次数为:$ h_{out} \cdot w_{out} $

总计算量:

\[\text{FLOPs}_{\text{grad\_weight}} = 2 \cdot c_o \cdot c_i \cdot k_h \cdot k_w \cdot h_{out} \cdot w_{out} \]

同样和前向传播相同。


📊 总结反向传播的总计算量

\[\text{FLOPs}_{\text{backward}} = \text{FLOPs}_{\text{grad\_input}} + \text{FLOPs}_{\text{grad\_weight}} = 2 \cdot (\text{FLOPs}_{\text{forward}}) = 4 \cdot c_o \cdot c_i \cdot k_h \cdot k_w \cdot h_{out} \cdot w_{out} \]


✅ 最终公式

\[\boxed{ \text{FLOPs}_{\text{backward}} = 4 \cdot c_o \cdot c_i \cdot k_h \cdot k_w \cdot h_{out} \cdot w_{out} } \]


📝 补充说明

项目 计算量
前向传播 $ 2 \cdot c_o \cdot c_i \cdot k_h \cdot k_w \cdot h_{out} \cdot w_{out} $
反向传播(输入梯度) $ 2 \cdot c_o \cdot c_i \cdot k_h \cdot k_w \cdot h_{out} \cdot w_{out} $
反向传播(权重梯度) $ 2 \cdot c_o \cdot c_i \cdot k_h \cdot k_w \cdot h_{out} \cdot w_{out} $
总计反向传播 $ 4 \cdot c_o \cdot c_i \cdot k_h \cdot k_w \cdot h_{out} \cdot w_{out} $

✅ 最终总结表格

项目 表达式
前向计算量(FLOPs) $ 2 \cdot c_o \cdot c_i \cdot k_h \cdot k_w \cdot h_{out} \cdot w_{out} $
前向内存占用 $ c_i h w + c_o c_i k_h k_w + c_o h_{out} w_{out} $
反向计算量(FLOPs) $ 4 \cdot c_o \cdot c_i \cdot k_h \cdot k_w \cdot h_{out} \cdot w_{out} $
反向内存占用 $ 2 c_i h w + 2 c_o c_i k_h k_w + c_o h_{out} w_{out} $

如果你有具体的数值(如输入尺寸、kernel大小等),我也可以帮你代入公式快速计算出实际数值。欢迎继续提问!

posted @ 2025-05-08 14:26  玉米面手雷王  阅读(113)  评论(0)    收藏  举报