首页
/ Transformers 中的 MobileViT:面向移动设备的轻量级视觉 Transformer 全面指南

Transformers 中的 MobileViT:面向移动设备的轻量级视觉 Transformer 全面指南

2026-09-07 22:15:03作者:伍霜盼Ellen

导读

MobileViT 是一个专为移动设备设计的轻量级视觉 Transformer(Vision Transformer, ViT),它把 CNN 的高效率与归纳偏置和 Transformer 的全局上下文建模能力融合在一起,将 Transformer 当作"卷积"来使用,从而在不付出标准 ViT 那样高昂计算代价的前提下完成全局信息建模。本指南以 Transformers 官方模型文档(mobilevit.md)为主体,结合本仓库中 MobileViT 的配置、模型与图像预处理源码(src/transformers/models/mobilevit),系统讲解 MobileViT 的架构原理、配置参数、图像分类与语义分割的实战用法。读完本文,你将掌握如何用 pipelineAutoModel 一行加载 MobileViT 完成推理、如何配置并训练分类/分割模型、以及理解其背后"展开为 patch 做全局注意力再折叠回特征图"的核心设计。

MobileViT 是什么:把 Transformer 当作卷积的轻量架构

MobileViT(论文发布于 2021-10-05,2022-06-29 由社区贡献者 matthijs 合入 Transformers)主打一个核心思想:把 Transformer 当作卷积来使用。卷积运算天然只关注局部感受野,而标准 Transformer 的全局自注意力代价高昂,难以在移动端运行;MobileViT 则在 CNN 骨干之上按 patch 组织信息,用全局自注意力在 patch 之间交换信息,从而在保持移动端友好计算量的同时获得全局上下文建模能力。

官方原始 MobileViT 权重均可从 Apple 组织下(搜索 mobilevit)获取,例如 apple/mobilevit-smallapple/mobilevit-xx-small 等检查点。模型完全面向图像任务设计,其骨干编码器基于 MobileNetV2 的逆残差结构(见 configuration_mobilevit.pymodeling_mobilevit.py)。

移动端友好与全局建模如何兼得:MobileViTLayer 源码解析

modeling_mobilevit.py 的实现可以看到,MobileViT 的基本单元 MobileViTLayer 由下列子模块顺序堆叠而成:

  1. 下采样:当 stride == 2 时,先经过一个 MobileNetV2 风格的逆残差块(MobileViTInvertedResidual)降低空间分辨率;
  2. 局部表征(local representation):先用 conv_kxk(默认 conv_kernel_size=3 卷积)提取局部特征,再用 conv_1x1 将通道投影到 Transformer 的 hidden_size
  3. Unfolding(展开为 patch):把 (batch, channels, height, width) 的特征图按 patch_size × patch_size 切成序列,得到 (batch * patch_area, num_patches, channels) 的张量;
  4. 全局表征(global representation):patch 序列送入多个 MobileViTTransformerLayer(带 Pre-LN 的注意力 + FFN),再做一次 LayerNorm;
  5. Folding(折叠回特征图):将全局建模后的 patch 重新拼回 (batch, channels, height, width) 特征图;
  6. 融合conv_projection 投影后,与步骤 1 保存的残差 residual 在通道维度拼接,由 fusion 卷积融合输出。

关键点在于 Unfolding/Folding 的可逆几何变换(对应源码中的 unfoldingfolding 方法,modeling_mobilevit.py):若空间尺寸不能被 patch_size 整除,源码会先用 nn.functional.interpolate 做双线性上采样到可整除尺寸,全局注意力计算完成后再插值回原尺寸。这种"局部卷积 + patch 级全局注意力 + 残差融合"的组合,让 MobileViT 在不大幅增加参数量和延迟的前提下获得了 ViT 式的全局感受野。

MobileViTConfig:完整的配置参数说明

MobileViTConfig 继承自 PreTrainedConfig,通过 configuration_mobilevit.py 定义。下表汇总了其全部公开参数及默认值:

参数 默认值 说明
num_channels 3 输入图像的通道数(RGB/BGR 均为 3)
image_size 256 输入图像尺寸,可为整数或 (height, width)
patch_size 2 Unfolding/Folding 使用的 patch 边长,默认 2×2
hidden_sizes (144, 192, 240) 三组 MobileViT(Transformer)模块的隐藏层维度
neck_hidden_sizes (16, 32, 64, 96, 128, 160, 640) 骨干各阶段特征图通道数,头部会据此取值
num_attention_heads 4 自注意力头数
mlp_ratio 2.0 Transformer 层中 FFN 中间维度 = hidden_size × mlp_ratio
expand_ratio 4.0 逆残差块的通道扩展系数
hidden_act "silu" 隐藏层激活函数(MobileViT 原始实现使用 Swish/SiLU)
conv_kernel_size 3 局部卷积核尺寸
output_stride 32 编码器输出相对输入的空间缩放;8/16 用于分割任务(详见下文 dilation 说明)
hidden_dropout_prob 0.1 Transformer 输出的 dropout 概率
attention_probs_dropout_prob 0.0 注意力权重 dropout 概率
classifier_dropout_prob 0.1 分类/分割头前的 dropout 概率
initializer_range 0.02 权重初始化标准差范围
layer_norm_eps 1e-5 LayerNorm 的 eps
qkv_bias True Q/K/V 投影是否带 bias
aspp_out_channels 256 语义分割 ASPP 层输出通道数
atrous_rates (6, 12, 18) ASPP 空洞卷积的空洞率(dilation factors)
aspp_dropout_prob 0.1 ASPP 层 dropout 比率
semantic_loss_ignore_index 255 分割损失中被忽略的像素标签索引

配置与模型骨架如何对应(编码器结构)

MobileViTEncodermodeling_mobilevit.py)中,编码器由 5 个阶段组成,neck_hidden_sizes 依次指定各阶段通道数:

  • 第 1、2 阶段为纯 MobileNet 卷积层(MobileViTMobileNetLayer),stage 数分别为 1 与 3;
  • 第 3~5 阶段是 MobileViT 层(MobileViTLayer),分别使用 hidden_sizes[0/1/2](144/192/240)作为 Transformer 隐层维度,stage 数分别为 2、4、3;
  • 编码器入口 conv_stem 是一个 stride=2 的 3×3 卷积,把 3 通道输入提升到 neck_hidden_sizes[0]=16 通道(见 MobileViTModel.__init__)。

有意思的是 output_stride 参数:DeepLab 系分割骨干常通过修改分类骨干的 stride 来控制输出分辨率。源码中当 output_stride == 8 时会同时 dilate 第 4、5 层,当 output_stride == 16 时只 dilate 第 5 层(dilate_layer_4 / dilate_layer_5),并通过把 dilation 传入后续 MobileViT 层来保持更大的特征图分辨率。这就是从结构上印证 MobileViT 能同时服务分类与语义分割两种任务的原因。

快速上手:图像分类

MobileViT 的分类模型在 ImageNet-1k 上预训练,可直接用于图像分类推理。官方文档同时给出了 pipelineAutoModel 两种方式,下面完整复现并逐行说明。

方式一:用 pipeline 一行完成分类

Pipeline 方式最简洁,只需指定 task="image-classification" 与模型名即可:

from transformers import pipeline

classifier = pipeline(
    task="image-classification",
    model="apple/mobilevit-small",
    device=0,
)

preds = classifier("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/pipeline-cat-chonk.jpeg")
print(f"Prediction: {preds}\n")

device=0 表示将模型放到第一块 GPU 上(CPU 环境可省略)。pipeline 会在内部自动加载配套的 MobileViTImageProcessor 完成图像预处理。

方式二:用 AutoModel + AutoImageProcessor 精确控制

若需要更精细的控制,推荐使用 AutoImageProcessorMobileViTForImageClassification 组合:

import requests
import torch
from PIL import Image

from transformers import AutoImageProcessor, MobileViTForImageClassification


image_processor = AutoImageProcessor.from_pretrained(
    "apple/mobilevit-small",
    use_fast=True,
)
model = MobileViTForImageClassification.from_pretrained("apple/mobilevit-small", device_map="auto")

url = "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/pipeline-cat-chonk.jpeg"
image = Image.open(requests.get(url, stream=True).raw)
inputs = image_processor(image, return_tensors="pt").to(model.device)

with torch.no_grad():
    logits = model(**inputs).logits
predicted_class_id = logits.argmax(dim=-1).item()

class_labels = model.config.id2label
predicted_class_label = class_labels[predicted_class_id]
print(f"The predicted class label is:{predicted_class_label}")

分类模型内部的 head 结构

从源码(modeling_mobilevit.py)看,MobileViTForImageClassification 由三部分组成:

  • MobileViTModel 骨干输出特征图后,用 conv_1x1_exp 将通道从 neck_hidden_sizes[5]=160 扩展为 neck_hidden_sizes[6]=640,随后在空间维度上做全局平均池化得到 pooler_outputtorch.mean(..., dim=[-2, -1]));
  • dropoutclassifier_dropout_prob,默认 0.1);
  • classifier:输入维度为 neck_hidden_sizes[-1](640)的线性层,输出 num_labels 个类别;当 num_labels == 0 时退化为 nn.Identity()

前向时,若传入 labelsnum_labels > 1 会计算交叉熵损失,num_labels == 1 则计算均方误差(回归)损失,训练时可直接返回 loss 用于反向传播。

语义分割:DeepLabV3 头 + MobileViT 骨干

MobileViT 的分割模型使用 DeepLabV3 head,并在 PASCAL VOC 上预训练。与分类模型不同,分割需要保留空间信息,因此 MobileViTForSemanticSegmentation 内部以 MobileViTModel(config, expand_output=False) 构造骨干(modeling_mobilevit.py),即做最后的 1×1 通道扩展。

分割头的三个关键组件(源码均有注释说明,见 modeling_mobilevit.py):

  • MobileViTASPP:Atrous Spatial Pyramid Pooling,由 1×1 卷积、三个空洞率分别为 atrous_rates=(6, 12, 18) 的 3×3 空洞卷积、以及一个全局平均池化分支组成,五路输出拼接后经 1×1 卷积投影到 aspp_out_channels=256,并施加 aspp_dropout_prob=0.1 的 dropout。源码在 MobileViTASPP.__init__ 中会校验 len(config.atrous_rates) == 3,因此该参数必须为三元组;
  • MobileViTDeepLabV3:在 ASPP 之上再接一个 Dropout2d(classifier_dropout_prob) 与 1×1 卷积分类器,把通道映射到 num_labels
  • 前向需要编码器中间层特征,故 forward 中强制 output_hidden_states=True,把第 4 阶段(分辨率最大的最后一层编码特征)喂给分割头(hidden_states[-1])。

训练时若传入 labels,模型先把 logits 双线性上采样到与标签相同尺寸,再用 CrossEntropyLoss(ignore_index=semantic_loss_ignore_index)(默认忽略索引 255)计算损失。

分割模型的推理示例

模型自带的 docstring 示例可直接参考(完整代码见 modeling_mobilevit.py),示意如下:

import httpx
from io import BytesIO
import torch
from PIL import Image
from transformers import AutoImageProcessor, MobileViTForSemanticSegmentation

url = "http://images.cocodataset.org/val2017/000000039769.jpg"
with httpx.stream("GET", url) as response:
    image = Image.open(BytesIO(response.read()))

image_processor = AutoImageProcessor.from_pretrained("apple/deeplabv3-mobilevit-small")
model = MobileViTForSemanticSegmentation.from_pretrained("apple/deeplabv3-mobilevit-small")

inputs = image_processor(images=image, return_tensors="pt")

with torch.no_grad():
    outputs = model(**inputs)

# logits are of shape (batch_size, num_labels, height, width)
logits = outputs.logits

图像预处理与后处理:MobileViTImageProcessor 完全解读

文档的 Notes 明确要求:使用 MobileViTImageProcessor 预处理图像;如果自行实现预处理,务必保证图像是 BGR 格式(而非 RGB),因为预训练权重是按 BGR 通道顺序训练的。 这是 MobileViT 与大多数默认按 RGB 训练的视觉模型最大的区别之一。

本仓库中 MobileViT 同时提供了两个图像处理器(它们在功能上等价,仅后端不同):

二者的类级默认配置完全相同:

resample = PILImageResampling.BICUBIC          # 缩放插值使用 BICUBIC
image_mean = IMAGENET_STANDARD_MEAN            # ImageNet 均值
image_std = IMAGENET_STANDARD_STD              # ImageNet 标准差
size = {"shortest_edge": 224}                  # 先缩放到最短边 224
crop_size = {"height": 256, "width": 256}      # 再中心裁剪为 256×256
do_resize = True
do_center_crop = True
do_rescale = True
do_flip_channel_order = True                   # 默认把 RGB 翻转为 BGR
do_reduce_labels = False

preprocess:分类与分割的差异化处理

preprocess 除接收 images 外还可接收 segmentation_maps。两者的处理链在 _preprocess 中体现(image_processing_mobilevit.py):

  • 图像路径:resize(BICUBIC) → center_crop(256×256) → rescale(1/255) → flip_channel_order(RGB→BGR)
  • 分割标签图路径则单独走一套配置:do_rescale=Falsedo_flip_channel_order=False,并且插值方式从 BICUBIC 换成 NEAREST(源码注释明确说明"Nearest interpolation is used for segmentation maps instead of BICUBIC"),避免标签类别被平滑污染。预处理后标签图被 squeeze 并转为 int64 存入 labels

flip_channel_order 的实现(image_processing_mobilevit.py)支持单图 (C,H,W) 与 batch (B,C,H,W) 两种情形,把前三个通道按 [2,1,0] 逆序重排。do_reduce_labels=True 时会把标签图逐像素减 1、背景 0 替换为 255(用于 ADE20k 这类背景不出现在类别集合中的数据集)。

结果后处理:post_process_semantic_segmentation

post_process_semantic_segmentationimage_processing_mobilevit.py)把分割模型的原始 logits 转成分割图:

  • 不传 target_sizes:直接对每张图的 logits 沿类别维取 argmax,返回形状 (height, width) 的类别索引图;
  • 传入 target_sizes(每张图期望的 (height, width)):先用双线性插值把 logits 上采样到目标尺寸再 argmax
  • return_segmentation_scores=True 时返回带 segmentation(类别索引)与 segmentation_scores(形状 (num_classes, height, width) 的概率图)的结构化输出。

同时该处理器还要求 batch 尺寸与 target_sizes 数量一致,否则会抛出 ValueError 提示用户检查输入。

使用注意事项(官方 Notes 完整汇总)

结合 mobilevit.md 的 Notes 与原论文设置,使用 MobileViT 时有以下几点需要牢记:

  • 不处理序列数据:MobileViT 纯粹为图像任务设计,不适用于 NLP 等序列任务;
  • 特征图直接参与建模:与把图像切块展平为标准 token embedding 的经典 ViT 不同,MobileViT 直接基于卷积特征图运作,只是按 patch 组织后做 Transformer 前向;
  • 预处理必须用专属处理器:请通过 MobileViTImageProcessor / AutoImageProcessor.from_pretrained(..., use_fast=True) 进行预处理;
  • 自定义预处理必须是 BGR:若你绕开处理器自行实现,务必在送入模型前把通道从 RGB 翻转为 BGR,否则预训练权重的效果会明显退化;
  • 分类权重来源:分类模型在 ImageNet-1k 上预训练;
  • 分割权重来源:分割模型使用 DeepLabV3 head,在 PASCAL VOC 上预训练。

从零构建自定义 MobileViT 与相关源码索引

若想基于本仓库做二次开发(如自定义 backbone 通道数、patch 大小或注意力头数),可参考如下代码模式(对应 configuration_mobilevit.py 的 docstring):

from transformers import MobileViTConfig, MobileViTModel

# Initializing a mobilevit-small style configuration
configuration = MobileViTConfig()

# Initializing a model from the mobilevit-small style configuration
model = MobileViTModel(configuration)

# Accessing the model configuration
configuration = model.config

模型测试样例(test_modeling_mobilevit.py)大量使用 apple/mobilevit-smallapple/mobilevit-xx-smallapple/deeplabv3-mobilevit-small 等真实检查点进行集成验证,可作为端到端行为的参考。仓库中值得继续深读的相关文件索引如下:

总的来说,MobileViT 通过"局部卷积 + patch 展开的全局 Transformer + 残差融合"三步式 MobileViT 层,在移动端延迟预算内获得了全局上下文建模能力;在 Transformers 中,它提供了分类与语义分割两种开箱即用的头部,加上默认帮用户完成 RGB→BGR 翻转的专属图像处理器,是轻量级边缘视觉任务中一个非常实用的选择。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.13 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
897
5.8 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
529
593
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
915
1.83 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.58 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.35 K
1.46 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.01 K
515
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
547
388