CV和NLP中常见的shape在常见网络层下的变化
在深度学习的CV(计算机视觉)和NLP(自然语言处理)任务中,理解张量形状在不同网络层中的变化至关重要。以下是常见网络层及其输入/输出形状变化的细致总结(使用PyTorch/Numpy的维度约定:(Batch Size, Channels/Features/Embedding Dim, Height, Width)
或 (Batch Size, Sequence Length, Hidden Size/Embedding Dim)
):
核心维度概念
1.N
/ batch_size
: 批次大小(样本数)
2.C
/ channels
/ features
/ embedding_dim
/ d_model
/ hidden_size
: 特征维度(通道、词嵌入大小、隐藏层大小)
3.H
: 特征图高度 (CV)
4.W
: 特征图宽度 (CV)
5.L
/ seq_len
: 序列长度 (NLP / 1D CV)
6.K
: 卷积核大小 (单个维度)
7.S
/ stride
: 步长
8.P
/ padding
: 填充 (通常指单边添加的数量)
9.D
/ dilation
: 膨胀率
10. O
/ out_channels
: 卷积输出通道数
11. G
/ groups
: 分组数 (分组卷积)
12. num_heads
: Transformer中的注意力头数
常见层及其形状变化
1. 全连接层 (Linear / Dense / Feed-Forward)
*输入形状: (N, *, In_Features)
**
表示任意数量的额外维度(会被展平)。
*In_Features
是输入特征维度。
*输出形状: (N, *, Out_Features)
*变化说明:
*无论输入有多少额外维度(如序列长度L
、图像高度H
、宽度W
),该层将所有额外维度 展平 (view(N, -1)
)。
*执行 Y = XW^T + b
,其中 W
的形状是 (Out_Features, In_Features)
。
2. 卷积层 (Convolution)
*输入形状 (CV - 2D): (N, C_in, H_in, W_in)
*输出形状 (CV - 2D): (N, C_out, H_out, W_out)
*计算单个维度输出长度公式:Output_Length = floor((Input_Length + 2 * Padding - Dilation * (Kernel_Size - 1) - 1) / Stride + 1)
*常见简化公式 (当 dilation=1
):Output_Length = floor((Input_Length + 2 * Padding - Kernel_Size) / Stride) + 1
*变化说明:
*通道数由 C_in
变为 C_out
(由 out_channels
参数指定)。
*空间维度 (H, W)
根据上述公式收缩(通常)。
*分组卷积 (groups>1
): 要求 C_in
和 C_out
都能被 groups
整除。每个分组处理 C_in/groups
个输入通道,产生 C_out/groups
个输出通道,最后拼接。参数量显著减少。
*膨胀卷积 (dilation>1
): 通过跳过输入像素扩大感受野,不影响通道数,但影响空间尺寸计算。
*输入形状 (NLP/1D - Conv1d): (N, C_in, L_in)
(或有时定义为 (N, L_in, C_in)
,需注意框架约定)
*输出形状 (NLP/1D - Conv1d): (N, C_out, L_out)
3. 转置卷积层 (Transposed Convolution / Deconvolution / ConvTranspose)
*目的: 常用于上采样(如分割、生成模型)。
*输入形状 (CV - 2D): (N, C_in, H_in, W_in)
*输出形状 (CV - 2D): (N, C_out, H_out, W_out)
*计算单个维度输出长度公式:Output_Length = (Input_Length - 1) * Stride - 2 * Padding + Dilation * (Kernel_Size - 1) + Output_Padding + 1
*简化公式 (常用参数 dilation=1
, output_padding=0
):Output_Length = (Input_Length - 1) * Stride - 2 * Padding + Kernel_Size
*变化说明:
*通道数由 C_in
变为 C_out
(由 out_channels
参数指定)。
*空间维度 (H, W)
根据上述公式 扩张(通常)。output_padding
用于解决因 stride>1
导致的形状模糊问题。
4. 池化层 (Pooling - Max, Avg, Adaptive)
*输入形状 (CV - 2D): (N, C, H_in, W_in)
*输出形状 (CV - 2D): (N, C, H_out, W_out)
*计算单个维度输出长度公式 (与卷积公式相同):Output_Length = floor((Input_Length + 2 * Padding - Dilation * (Kernel_Size - 1) - 1) / Stride + 1)
Output_Length = floor((Input_Length + 2 * Padding - Kernel_Size) / Stride) + 1
(当 dilation=1
)
*变化说明:
*通道数 C
保持不变(核心区别)。
*空间维度 (H, W)
根据上述公式收缩(通常)。
*自适应池化 (AdaptivePooling): 直接指定输出尺寸 (H_out, W_out)
,忽略 kernel_size
, stride
, padding
。内部自动计算所需参数以达到目标尺寸。
5. 归一化层 (Normalization)
*批归一化 (BatchNorm - CV):
*输入形状: (N, C, H, W)
*输出形状: (N, C, H, W)
(完全相同)
*变化说明: 沿 N, H, W
维度计算统计量 (均值、方差),对每个通道 C
独立进行缩放和平移。
*层归一化 (LayerNorm - NLP/CV):
*输入形状: (N, *, Normalized_Shape)
(PyTorch)。Normalized_Shape
是最后几个需要归一化的维度(如 (L, C)
或 (C,)
)。
*输出形状: (N, *, Normalized_Shape)
(完全相同)
*变化说明: 沿指定的 Normalized_Shape
维度计算统计量(独立于 N
和其他未指定维度)。NLP 中常用 (..., L, C)
的最后两个维度 (L, C)
进行归一化(对每个样本的每个时间步的特征独立归一化)。
*实例归一化 (InstanceNorm - CV Style Transfer):
*输入形状: (N, C, H, W)
*输出形状: (N, C, H, W)
(完全相同)
*变化说明: 沿 H, W
维度计算统计量,对每个样本 N
的每个通道 C
独立进行缩放和平移。
6. 循环神经网络层 (RNN, LSTM, GRU)
*输入形状: (N, L, H_in)
或 (L, N, H_in)
(PyTorch 通过 batch_first=True
控制,前者更常见)。
*输出形状:
***output
:** (N, L, D * H_out)
。
*H_out
是隐藏层大小 (hidden_size
)。
*D = 2
如果是双向RNN (bidirectional=True
),否则 D = 1
。hidden
/ (h_n, c_n)
(LSTM):*
*h_n
: (D * num_layers, N, H_out)
*c_n
: (D * num_layers, N, H_out)
(仅LSTM)
变化说明:*
*output
包含所有时间步**的隐藏状态。
*hidden
/ (h_n, c_n)
包含最后一个时间步**的隐藏状态(和细胞状态)。
*num_layers
决定了堆叠层数。
*输入维度 H_in
是输入特征大小,输出维度 H_out
是RNN单元定义的隐藏状态大小。
7. 嵌入层 (Embedding)
*输入形状: (N, L)
或 (L, N)
(包含整数索引)。
*输出形状: (N, L, E)
或 (L, N, E)
。E
是嵌入维度 (embedding_dim
)。
*变化说明: 将每个整数索引映射到一个 E
维的稠密向量。增加了特征维 E
。
8. Transformer 核心层
*输入形状: (N, L, d_model)
(词嵌入序列 + 位置编码)。
*多头自注意力 (Multi-Head Self-Attention):
*输入: Q, K, V
: 均为 (N, L, d_model)
*线性投影 (Q/K/V): (N, L, d_model) -> (N, L, num_heads * d_k)
(通常 d_k = d_v = d_model / num_heads
)
*Reshape: (N, L, num_heads * d_k) -> (N, L, num_heads, d_k) -> (N, num_heads, L, d_k)
(转置以并行计算头)。
*计算注意力分数 & 输出: (N, num_heads, L, d_k) @ (N, num_heads, d_k, L) -> (N, num_heads, L, L)
(分数)
*Softmax & Weighted Sum: (N, num_heads, L, L) @ (N, num_heads, L, d_v) -> (N, num_heads, L, d_v)
*Reshape & 拼接: (N, num_heads, L, d_v) -> (N, L, num_heads * d_v) = (N, L, d_model)
(因为 d_v = d_model / num_heads
)。
*线性投影 (输出): (N, L, d_model) -> (N, L, d_model)
(可选,但标准Transformer有)。
*输出形状: (N, L, d_model)
(与输入形状相同)。
*前馈网络 (Position-wise Feed-Forward Network - FFN):
*输入: (N, L, d_model)
*第一层: (N, L, d_model) -> (N, L, d_ff)
(扩张,d_ff
通常 > d_model
, 如 4*d_model
)。
*激活函数 (如ReLU, GELU)。
*第二层: (N, L, d_ff) -> (N, L, d_model)
(投影回 d_model
)。
*输出形状: (N, L, d_model)
(与输入形状相同)。
*层归一化 (LayerNorm) & 残差连接 (Add): 不改变形状 ((N, L, d_model)
-> (N, L, d_model)
)。
关键总结与提示
1.N
(Batch Size): 几乎总是贯穿所有层保持不变。
2.通道/特征维度 (C
, H_in/H_out
, embedding_dim
, hidden_size
, d_model
):
*全连接层、卷积层 (out_channels
)、嵌入层 (embedding_dim
)、RNN (hidden_size
)、Transformer (d_model
) 显式改变此维度。
*池化层、归一化层(BatchNorm/InstanceNorm/LayerNorm)通常保持此维度不变(LayerNorm作用于指定的维度)。
3.空间/序列维度 (H
, W
, L
):
*卷积层、池化层:根据公式改变尺寸(通常缩小)。
*转置卷积层:根据公式改变尺寸(通常扩大)。
*全连接层:展平(消失)。
*RNN、Transformer、嵌入层、归一化层 (LayerNorm作用于序列):保持序列长度 L
不变。
4.RNN/Transformer vs CNN:
*RNN/Transformer:核心处理维度是**序列长度 L
+ 特征维度 (hidden_size
/d_model
)**。
*CNN (CV):核心处理维度是**空间维度 (H, W)
+ 通道维度 C
**。
5.框架约定: 特别注意维度顺序!PyTorch CV默认 (N, C, H, W)
,NLP默认 (L, N, *)
但常设 batch_first=True
为 (N, L, *)
。TensorFlow有时用 (N, H, W, C)
。
6.形状推导工具: 善用 model.summary()
(Keras/TF), print(model)
/ torchinfo.summary()
(PyTorch) 或直接 print(x.shape)
在模型中调试。
7.维度匹配: 形状错误最常见的原因是层之间维度不匹配(尤其是卷积/转置卷积输出尺寸计算错误,或全连接层输入未正确展平)。
8.自适应层: 当需要固定输出尺寸时(如分类头前),自适应池化 (AdaptiveAvgPool2d(1)
) 非常有用,直接输出 (N, C, 1, 1)
-> 展平为 (N, C)
。
理解这些核心层的形状变换规律是设计和调试深度学习模型的基础。务必结合具体公式和实际调试进行验证。