Transformers 中的 ConvNeXt V2:从 FCMAE 自监督预训练到 GRN 架构的纯卷积模型详解
ConvNeXt V2 是 Facebook AI(Meta)在 2023 年提出的纯卷积视觉模型,它把卷积网络的强表达力与掩码自编码器(Masked Autoencoder)式自监督表征学习做了协同设计。本文以 docs/source/en/model_doc/convnextv2.md 为主线,结合当前仓库中 configuration_convnextv2.py、modeling_convnextv2.py 及对应测试与转换脚本,系统讲解其模型族背景、架构组件(GRN、FCMAE)、配置参数含义,以及基于 AutoModel 系列进行推理、图像分类、Backbone 抽取和微调的完整实操方案。
ConvNeXt V2 是什么:纯卷积模型与自监督学习的协同设计
ConvNeXt V2 由 Sanghyun Woo、Shoubhik Debnath、Ronghang Hu、Xinlei Chen、Zhuang Liu、In So Kweon、Saining Xie 在论文 ConvNeXt V2: Co-designing and Scaling ConvNets with Masked Autoencoders 中提出(HF Papers 收录于 2023-01-02,在 Transformers 中由贡献者 adirik 于 2023-03-14 合入)。它是一个纯卷积模型(ConvNet),设计上受 Vision Transformer 启发,是仓库中另一模型 ConvNeXt 的直接后继者。
论文摘要的核心观点是:
尽管以 ConvNeXt 为代表的现代卷积网络已在多种视觉场景中表现出色,但它们最初是为 ImageNet 有监督学习设计的,理论上也能从掩码自编码器(MAE)这类自监督技术中获益。然而作者发现,简单地把两者组合效果并不理想。为此论文提出了一个全卷积掩码自编码器框架(fully convolutional masked autoencoder, FCMAE),以及一个可插入 ConvNeXt 主干的新模块 GRN(Global Response Normalization,全局响应归一化)层,用来增强通道间的特征竞争。这种"自监督训练方法 + 架构改进"的协同设计形成了新的模型族 ConvNeXt V2,在 ImageNet 图像分类、COCO 检测、ADE20K 分割等多项识别基准上显著提升了纯卷积网络的表现。
从论文摘要还可以看到该模型族覆盖的规模区间(注意:以下数字为论文中的报告数据,引用自关联文档,非本仓库实测):小到参数量约 3.7M 的 Atto(ImageNet top-1 约 76.7%),大到 650M 的 Huge(仅用公开训练数据即可达到约 88.9% 的 top-1 精度)。官方预训练权重与原始代码来自 facebookresearch/ConvNeXt-V2,仓库中保留了对应的权重转换脚本 convert_convnextv2_to_pytorch.py,用于把官方 checkpoint 转换为可在 Transformers 中直接加载的格式。
仓库中的代码结构:从配置到四类可加载组件
ConvNeXt V2 的实现集中在 src/transformers/models/convnextv2/ 目录,由 4 个文件组成:
| 文件 | 职责 |
|---|---|
configuration_convnextv2.py |
定义 ConvNextV2Config,声明模型超参与输出特征(out_features/out_indices) |
modeling_convnextv2.py |
PyTorch 实现全部网络模块与三类对外模型 |
convert_convnextv2_to_pytorch.py |
将官方 ConvNeXt V2 权重重命名为 HF 命名并转存 |
__init__.py |
基于 _LazyModule 的惰性导入入口 |
其中 modeling_convnextv2.py 的 __all__ 导出了四个类(建模文件末尾):
ConvNextV2PreTrainedModel:权重初始化、保存加载的公共基类;ConvNextV2Model:纯主干,输出特征图与池化向量;ConvNextV2ForImageClassification:主干 + 分类头(用于 ImageNet 等任务);ConvNextV2Backbone:面向 DETR、MaskFormer 等下游框架的多尺度 Backbone 封装。
在 src/transformers/models/auto/modeling_auto.py 中,convnextv2 这一 model_type 被同时注册到通用模型映射、图像分类映射与 Backbone 映射,因此可以用 AutoModel、AutoModelForImageClassification、AutoBackbone 直接按名称加载。模型内部按 ConvNextV2Embeddings → ConvNextV2Encoder(N 个 ConvNextV2Stage)→ 可选分类头/池化 组织,基础结构代码大量复用自 ConvNeXt(源码注释中多处标注 # Copied from transformers.models.convnext.modeling_convnext.ConvNext...),保证两代模型行为一致、便于维护。
ConvNextV2Config:核心配置参数一览
ConvNextV2Config(配置文件)继承自 PreTrainedConfig 并混入 BackboneConfigMixin,声明了 model_type = "convnextv2"。其类属性的默认值即对应 facebook/convnextv2-tiny-1k-224 这一骨干结构的配置风格(@auto_docstring(checkpoint="facebook/convnextv2-tiny-1k-224") 装饰器会把该 checkpoint 的真实字段注入文档字符串)。
关键参数及其默认值如下:
| 参数 | 默认值 | 说明 |
|---|---|---|
num_channels |
3 |
输入图像的通道数,默认 RGB 三通道 |
patch_size |
4 |
Patch Embedding 卷积的 kernel_size/stride,把图像切成 4×4 patch |
num_stages |
4 |
主干中的 stage 数量 |
hidden_sizes |
(96, 192, 384, 768) |
各 stage 的输出通道数,第 0 项也是 stem 卷积后的宽度 |
depths |
(3, 3, 9, 3) |
各 stage 内残差 Block 的数量 |
hidden_act |
"gelu" |
Block 中激活函数,经 ACT2FN[config.hidden_act] 解析 |
initializer_range |
0.02 |
参数初始化范围 |
layer_norm_eps |
1e-12 |
顶部 nn.LayerNorm 的 epsilon |
drop_path_rate |
0.0 |
随机深度(Stochastic Depth)总衰减率,按层数线性插值分配 |
image_size |
224 |
模型设计输入尺寸 |
out_features / out_indices |
None |
Backbone 需要输出的 stage 名称/索引(可选) |
在 __post_init__ 中,配置会自动生成 stage_names = ["stem"] + [f"stage{idx}" ...],并调用 set_output_features_output_indices 同步 out_features 与 out_indices,因此同一份配置既能驱动分类模型,也能直接驱动多尺度 Backbone。
从随机权重初始化一个模型的最简代码如下(取自配置文件中的官方示例):
>>> from transformers import ConvNextV2Config, ConvNextV2Model
>>> # 以 convnextv2-tiny-1k-224 风格配置初始化
>>> configuration = ConvNextV2Config()
>>> # 用随机权重构建模型
>>> model = ConvNextV2Model(configuration)
>>> # 访问模型配置
>>> configuration = model.config
需要说明的是:示例中的默认配置(depths 为 (3, 3, 9, 3)、hidden_sizes 为 (96, 192, 384, 768))与 tiny 架构的结构一致,但训练好的权重仍应从官方 checkpoint 加载,而不是直接用随机权重做推理。
模型前向接口与返回结构
与多数视觉模型不同,ConvNeXt V2 不使用 input_ids/attention_mask,主输入名为 pixel_values。它的特征提取与分类任务的输出类型都能从返回对象名字里看出"无注意力"的特征。
ConvNextV2Model(特征提取)
前向返回 BaseModelOutputWithPoolingAndNoAttention(实现位置),包含两个核心字段:
last_hidden_state:最后一个 stage 输出的特征图;pooler_output:先对特征图做全局平均池化(hidden_states.mean([-2, -1])),再经nn.LayerNorm(hidden_sizes[-1])得到的(N, C)向量。
>>> from transformers import AutoImageProcessor, AutoModel
>>> from PIL import Image
>>> import httpx
>>> from io import BytesIO
>>> url = "http://images.cocodataset.org/val2017/000000039769.jpg"
>>> image = Image.open(BytesIO(httpx.get(url).content))
>>> processor = AutoImageProcessor.from_pretrained("facebook/convnextv2-tiny-1k-224")
>>> model = AutoModel.from_pretrained("facebook/convnextv2-tiny-1k-224")
>>> inputs = processor(image, return_tensors="pt")
>>> outputs = model(**inputs)
>>> outputs.last_hidden_state.shape, outputs.pooler_output.shape
空间分辨率变化规律可以从结构和测试共同确认:stem 以 stride 4 降采样一次,后续第 2~4 个 stage 各以 stride 2 降采样一次,共缩小 2⁵=32 倍。因此 224×224 输入对应输出约 7×7,测试文件 test_modeling_convnextv2.py 中对 create_and_check_model 的断言即为 (batch_size, hidden_sizes[-1], image_size // 32, image_size // 32)。
ConvNextV2ForImageClassification(图像分类)
在池化特征之上接一个 nn.Linear(config.hidden_sizes[-1], config.num_labels) 分类头;num_labels 为 0 时用 nn.Identity() 占位。前向返回 ImageClassifierOutputWithNoAttention,其中:
logits:形状(batch_size, num_labels);labels:可选。当config.num_labels == 1时计算 MSE 回归损失,num_labels > 1时计算交叉熵分类损失(见 建模文件前向文档)。
>>> from transformers import AutoImageProcessor, AutoModelForImageClassification
>>> import torch
>>> processor = AutoImageProcessor.from_pretrained("facebook/convnextv2-tiny-1k-224")
>>> model = AutoModelForImageClassification.from_pretrained("facebook/convnextv2-tiny-1k-224")
>>> inputs = processor(image, return_tensors="pt")
>>> with torch.no_grad():
... logits = model(**inputs).logits
>>> predicted_label = logits.argmax(-1).item()
在 Pipeline 层面,测试中注册了 image-classification(对应 ConvNextV2ForImageClassification)与 image-feature-extraction(对应 ConvNextV2Model)两个任务管线(见 测试文件 pipeline_model_mapping),所以也可以直接使用:
>>> from transformers import pipeline
>>> classifier = pipeline("image-classification", model="facebook/convnextv2-tiny-1k-224")
>>> classifier(image)
图像预处理不需要单独实现:convnextv2 在 image_processing_auto.py 中注册为复用 ConvNeXt 系列的 ConvNextImageProcessor,因此 AutoImageProcessor.from_pretrained("facebook/convnextv2-tiny-1k-224") 即可获得正确的 resize、归一化与通道处理流程。
ConvNextV2Backbone(多尺度特征抽取)
官方文档将 Backbone 定位为"供 DETR、MaskFormer 这类框架使用"的组件。其构造逻辑(实现位置)为:
num_features = [hidden_sizes[0]] + hidden_sizes,与stem及各 stage 一一对应;- 为每个输出 stage 额外挂一个
ConvNextV2LayerNorm(channels_first格式); - 前向按配置的
out_features/out_indices过滤并归一化各层特征图,返回BackboneOutput(feature_maps=..., hidden_states=...)。
官方 docstring 示例展示了它与 AutoBackbone 的组合用法(建模文件 Backbone 示例):
>>> from transformers import AutoImageProcessor, AutoBackbone
>>> import torch
>>> from PIL import Image
>>> import httpx
>>> from io import BytesIO
>>> url = "http://images.cocodataset.org/val2017/000000039769.jpg"
>>> with httpx.stream("GET", url) as response:
... image = Image.open(BytesIO(response.read()))
>>> processor = AutoImageProcessor.from_pretrained("facebook/convnextv2-tiny-1k-224")
>>> model = AutoBackbone.from_pretrained("facebook/convnextv2-tiny-1k-224")
>>> inputs = processor(image, return_tensors="pt")
>>> outputs = model(**inputs)
>>> outputs.feature_maps # 多尺度特征元组
从源码理解 ConvNeXt V2 的关键设计
GRN:通道间特征竞争的增强层
GRN 是相对 ConvNeXt V1 最核心的新增模块,实现在 modeling_convnextv2.py。源码表明其计算过程分三步:
- 聚合空间信息:对每个通道计算特征图在空间维
(H, W)上的 L2 范数torch.linalg.vector_norm(..., ord=2, dim=(1, 2)),得到全局响应向量; - 归一化:每个通道的范数除以所有通道范数的均值(
+1e-6防止除零),使通道间的响应可比较; - 门控与残差:用可学习的
weight(形状(1, 1, 1, dim))对归一化后的特征做缩放,叠加bias,再与原输入做残差相加。
GRN 由此突出"响应强的通道、抑制响应弱的通道",即论文所称的增强通道间特征竞争。值得一提的实现细节是:它的 weight 与 bias 初始化为全零(见 _init_weights 中对 ConvNextV2GRN 特判的 初始化逻辑),从而在训练初期保证残差路径不改变主分支信号,这与论文"新增结构应从恒等变换起步"的思路一致。
Block 与 Stage:7×7 深度卷积 + 倒瓶颈 + DropPath
ConvNextV2Layer(源码中对应原始实现的 Block)的结构为(实现位置):
- DwConv:7×7、padding=3、
groups=dim的深度卷积(逐通道卷积),负责空间混合; - LayerNorm(channels_last):在
(N, H, W, C)布局上做归一化(注释说明作者实测这种排列在 PyTorch 中更快); - pwconv1:
Linear(dim, 4*dim)放大通道(倒瓶颈,expansion=4); - 激活函数
GELU; - GRN:作用于放大后的 4×dim 特征,抑制无用通道;
- pwconv2:
Linear(4*dim, dim)投影回原宽度; - DropPath 残差:随机深度(每个样本以
drop_prob丢弃整条残差分支),训练时除以keep_prob保持期望值不变。
ConvNextV2Stage 在通道数变化或需要降采样时(in_channels != out_channels or stride > 1)先执行一个 LayerNorm(channels_first) + Conv2d(kernel=2, stride=2) 的下采样块,再堆叠 depth 个 Block。各 Block 的 DropPath 概率由 ConvNextV2Encoder 用 torch.linspace(0, config.drop_path_rate, sum(depths)) 在全部层上线性插值后按各 stage 切分,保证深层的正则化更强。
Patch Embedding 与通道数校验
ConvNextV2Embeddings 用 nn.Conv2d(num_channels, hidden_sizes[0], kernel_size=patch_size, stride=patch_size) 完成 patch 化,再接 channels_first 的 LayerNorm;前向时会校验输入通道数与 num_channels 配置是否一致,否则抛出提示 ValueError(实现位置)。这也意味着加载模型时配置中的 num_channels 必须与实际图像匹配。
微调与上手资源
ConvNeXt V2 属于图像分类任务管线,仓库文档给出如下资源:ConvNextV2ForImageClassification 由 examples/pytorch/image-classification/ 下的官方示例脚本支持(包含训练与评估入口)。具体运行方式(数据集路径、--model_name_or_path facebook/convnextv2-tiny-1k-224、学习率等超参)可参考该目录下的 README.md,脚本内部使用 AutoImageProcessor + AutoModelForImageClassification,因此直接把 model name 换成任意 facebook/convnextv2-* checkpoint 即可开始微调。
如果你拿到的是官方(非 HF)格式的 ConvNeXt V2 权重,仓库提供了转换脚本 convert_convnextv2_to_pytorch.py,它会读取 checkpoint URL 构造 ConvNextV2Config、执行 key 重命名并保存为 Transformers 格式,还附带图像预处理转换逻辑。这保证了"官方预训练 → HF 加载"路径的完整性。
测试与可复现验证
ConvNeXt V2 的测试集中在 tests/models/convnextv2/test_modeling_convnextv2.py,覆盖三个层面:
- 模型行为测试:
ConvNextV2ModelTest同时验证ConvNextV2Model、ConvNextV2ForImageClassification、ConvNextV2Backbone,包括前向形状、梯度 checkpoint、hidden_states 输出、标签损失等; - 快速推理测试(
@slow):加载facebook/convnextv2-tiny-1k-224并对 tests/fixtures/tests_samples/COCO/000000039769.png(两只猫的经典 COCO 样例图)推理,断言logits形状为(1, 1000),且前三个 logits 的期望切片约为[0.9989, 0.1953, -0.4382](见 测试文件 L292)。这份期望值可以直接用来验证你本地环境加载权重与预处理是否一致; - Backbone 专项测试:
ConvNextV2BackboneTest通过BackboneTesterMixin覆盖多尺度输出的配置组合。
此外,测试还显式声明了 has_attentions = False、test_resize_embeddings = False,反映纯卷积模型"无注意力、无 token embedding"的本质属性。
小结:与 ConvNeXt V1 的关系与选用建议
从仓库实现看,ConvNeXt V2 的工程骨架大量复用了 ConvNeXt V1(Patch Embedding、DropPath、Stage 结构均以 # Copied from 方式同步),真正的架构增量集中在每个 Block 中嵌入 GRN 层以及配套的 FCMAE 自监督预训练。如果你正在对比两代模型,可以同时查阅 ConvNeXt 官方文档,两者在配置字段、加载方式与图像处理器上高度一致,便于做公平的消融或性能对比实验。
选用建议(基于仓库可确认的事实归纳,而非外部评测):需要多尺度特征图给检测/分割模型做 Backbone 时,使用 ConvNextV2Backbone 配合 out_features/out_indices;只做图像分类或微调时,直接使用 ConvNextV2ForImageClassification 与官方预训练 checkpoint 即可;而 GRN 的源码实现(L2 范数聚合 + 均值归一化门控 + 全零初始化残差)是理解该模型为何能在纯卷积范式下追平 Transformer 式自监督表征学习的核心阅读材料。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0630
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00