Qwen3.5-MoE 系列详解:混合专家 + 线性注意力 + 多模态的完整生命周期

本文档以 Qwen3.5-MoE 模型为例,将 Transformers 框架的所有模块串联起来,深度剖析最前沿的 混合专家 + 多模态 + 线性注意力 模型在 Transformers 中的完整生命周期。

源码文件:

  • [configuration_qwen3_5_moe.py](file:///workspace/src/transformers/models/qwen3_5_moe/configuration_qwen3_5_moe.py)
  • [modeling_qwen3_5_moe.py](file:///workspace/src/transformers/models/qwen3_5_moe/modeling_qwen3_5_moe.py)
  • [modular_qwen3_5_moe.py](file:///workspace/src/transformers/models/qwen3_5_moe/modular_qwen3_5_moe.py)

相关文章:
Hugging Face Transformers 源码全景解读
01-Hugging Face Transformers 核心基础设施深度分析
02-Hugging Face Transformers 配置系统深度分析
03-Hugging Face Transformers 模型系统深度分析
04-Hugging Face Transformers 注意力与掩码系统深度分析
05-Hugging Face Transformers 缓存系统深度分析
06-Hugging Face Transformers 生成系统深度分析
07-Hugging Face Transformers 分词器系统深度分析
08-Hugging Face Transformers 多模态处理系统深度分析
09-Hugging Face Transformers 训练系统深度分析
10-Hugging Face Transformers 量化系统深度分析
11-Hugging Face Transformers 分布式与并行系统深度分析
12-Hugging Face Transformers之Pipeline 推理管道深入分析
13-Hugging Face Transformers之AutoModel 自动分发机制深入分析
14-Hugging Face Transformers 模型实现模式深度分析
15-Hugging Face Transformers之CLI 与工具架构总览
16-Hugging Face Transformers之测试体系架构总览
17-Hugging Face Transformers之BERT 案例详解:Transformers 框架全模块串联
18-Hugging Face Transformers之GPT-2 案例详解:Decoder-only 自回归模型的完整生命周期
19-Hugging Face Transformers之Qwen3.5-MoE 系列详解:混合专家 + 线性注意力 + 多模态的完整生命周期

1. Qwen3.5-MoE 在 Transformers 中的定位

Qwen3.5-MoE 是 Qwen 系列中最前沿的混合架构模型,它同时融合了三大创新:混合注意力层(full_attention + linear_attention 交替)、MoE 专家路由(256 专家 Top-8 路由 + 共享专家)和多模态视觉编码器(Vision Transformer + PatchMerger)。

1.1 架构定位图

Qwen 模型家族

Qwen2
纯 Dense + 标准注意力

Qwen2-VL
Dense + 多模态 + 标准注意力

Qwen2-MoE
MoE + 标准注意力

Qwen3-VL
Dense + 多模态 + 标准注意力

Qwen3-MoE
MoE + 标准注意力

Qwen3
Dense + 标准注意力 + 思考模式

Qwen3-VL-MoE
MoE + 多模态 + 标准注意力

Qwen3-Next
Dense + 混合注意力 + MoE

Qwen3.5
Dense + 混合注意力

Qwen3.5-MoE
🔥 MoE + 混合注意力 + 多模态

1.2 三大创新点图示

创新点 3:多模态视觉编码器

PatchEmbed
3D 卷积

VisionBlocks × 27
+ 旋转位置编码

PatchMerger
空间合并 + 投影

创新点 2:MoE 专家路由

TopKRouter
256 专家 Top-8

Qwen3_5MoeExperts
3D 参数张量

SharedExpert
+ SharedExpertGate

创新点 1:混合注意力层

每隔 4 层交替

每隔 4 层交替

full_attention 层
标准 Softmax 注意力
+ QK Norm + Gate

linear_attention 层
GatedDeltaNet
+ 因果卷积 + 门控 Delta 规则

1.3 继承关系

从 [modular_qwen3_5_moe.py](file:///workspace/src/transformers/models/qwen3_5_moe/modular_qwen3_5_moe.py) 可以看出,Qwen3.5-MoE 的类继承链非常清晰:

Qwen3.5-MoE 类 直接父类 来源模块
Qwen3_5MoeTextConfig Qwen3NextConfig qwen3_next
Qwen3_5MoeVisionConfig Qwen3_5VisionConfig qwen3_5
Qwen3_5MoeConfig Qwen3VLConfig qwen3_vl
Qwen3_5MoeGatedDeltaNet Qwen3_5GatedDeltaNet qwen3_5
Qwen3_5MoeAttention Qwen3NextAttention qwen3_next
Qwen3_5MoeExperts Qwen3NextExperts qwen3_next
Qwen3_5MoeTopKRouter Qwen3VLMoeTextTopKRouter qwen3_vl_moe
Qwen3_5MoeSparseMoeBlock Qwen3NextSparseMoeBlock qwen3_next
Qwen3_5MoeForConditionalGeneration Qwen3VLMoeForConditionalGeneration qwen3_vl_moe

2. Config 三层嵌套设计

Qwen3.5-MoE 采用三层 Config 嵌套设计,顶层 Qwen3_5MoeConfig 包含 text_configvision_config 两个子配置。

2.1 Config 嵌套类图

text_config

vision_config

PreTrainedConfig

+model_type: str

+post_init()

+to_dict()

Qwen3_5MoeTextConfig

+model_type = "qwen3_5_moe_text"

+base_config_key = "text_config"

+vocab_size: int = 248320

+hidden_size: int = 2048

+num_hidden_layers: int = 40

+num_attention_heads: int = 16

+num_key_value_heads: int = 2

+head_dim: int = 256

+num_experts: int = 256

+num_experts_per_tok: int = 8

+moe_intermediate_size: int = 512

+shared_expert_intermediate_size: int = 512

+layer_types: list<str> | None

+linear_conv_kernel_dim: int = 4

+linear_key_head_dim: int = 128

+linear_value_head_dim: int = 128

+linear_num_key_heads: int = 16

+linear_num_value_heads: int = 32

+base_model_tp_plan: dict

+base_model_pp_plan: dict

+post_init()

Qwen3_5MoeVisionConfig

+model_type = "qwen3_5_moe_vision"

+base_config_key = "vision_config"

+depth: int = 27

+hidden_size: int = 1152

+intermediate_size: int = 4304

+num_heads: int = 16

+in_channels: int = 3

+patch_size: int = 16

+spatial_merge_size: int = 2

+temporal_patch_size: int = 2

+out_hidden_size: int = 3584

+num_position_embeddings: int = 2304

Qwen3_5MoeConfig

+model_type = "qwen3_5_moe"

+sub_configs: dict

+text_config: Qwen3_5MoeTextConfig

+vision_config: Qwen3_5MoeVisionConfig

+image_token_id: int = 248056

+video_token_id: int = 248057

+vision_start_token_id: int = 248053

+vision_end_token_id: int = 248054

+post_init()

2.2 sub_configs 机制图

sub_configs 是 Transformers 中多模态模型的标准机制,定义在 [configuration_qwen3_5_moe.py:171](file:///workspace/src/transformers/models/qwen3_5_moe/configuration_qwen3_5_moe.py#L171):

class Qwen3_5MoeConfig(PreTrainedConfig):
    sub_configs = {"vision_config": Qwen3_5MoeVisionConfig, "text_config": Qwen3_5MoeTextConfig}
Qwen3_5MoeVisionConfig Qwen3_5MoeTextConfig Qwen3_5MoeConfig config.json Qwen3_5MoeVisionConfig Qwen3_5MoeTextConfig Qwen3_5MoeConfig config.json alt [text_config 是 dict] [text_config 是 None] alt [vision_config 是 dict] [vision_config 是 None] self.text_config 和 self.vision_config 均为实例化的 Config 对象 加载顶层配置 __post_init__() 检查 text_config Qwen3_5MoeTextConfig(**text_config) Qwen3_5MoeTextConfig() 使用默认值 __post_init__() 检查 vision_config Qwen3_5MoeVisionConfig(**vision_config) Qwen3_5MoeVisionConfig() 使用默认值

关键代码在 [configuration_qwen3_5_moe.py:183-194](file:///workspace/src/transformers/models/qwen3_5_moe/configuration_qwen3_5_moe.py#L183):

def __post_init__(self, **kwargs):
    if isinstance(self.vision_config, dict):
        self.vision_config = self.sub_configs["vision_config"](**self.vision_config)
    elif self.vision_config is None:
        self.vision_config = self.sub_configs["vision_config"]()

    if isinstance(self.text_config, dict):
        self.text_config = self.sub_configs["text_config"](**self.text_config)
    elif self.text_config is None:
        self.text_config = self.sub_configs["text_config"]()

    super().__post_init__(**kwargs)

2.3 base_model_tp_plan / base_model_pp_plan 并行策略声明图

Qwen3_5MoeTextConfig 在 [configuration_qwen3_5_moe.py:59-77](file:///workspace/src/transformers/models/qwen3_5_moe/configuration_qwen3_5_moe.py#L59) 声明了张量并行(TP)和流水线并行(PP)策略:

PP 策略 (base_model_pp_plan)

embed_tokens
输入: input_ids
输出: inputs_embeds

layers
输入: hidden_states, attention_mask
输出: hidden_states

norm
输入: hidden_states
输出: hidden_states

TP 策略 (base_model_tp_plan)

q_proj → colwise

k_proj → colwise

v_proj → colwise

o_proj → rowwise

q_norm → replicated_with_grad_allreduce

k_norm → replicated_with_grad_allreduce

experts.gate_up_proj → packed_colwise

experts.down_proj → rowwise

experts → moe_tp_experts

shared_expert.gate_proj → colwise

shared_expert.up_proj → colwise

shared_expert.down_proj → rowwise


3. from_pretrained 完整时序

Qwen3_5MoeForConditionalGeneration.from_pretrained('Qwen/Qwen3.5-35B-A3B') 到模型就绪的完整流程。

3.1 时序图

Qwen3_5MoeTextModel Qwen3_5MoeVisionModel Qwen3_5MoeModel Qwen3_5MoeForConditionalGeneration PreTrainedModel Qwen3_5MoeVisionConfig Qwen3_5MoeTextConfig Qwen3_5MoeConfig AutoModelForCausalLM 用户代码 Qwen3_5MoeTextModel Qwen3_5MoeVisionModel Qwen3_5MoeModel Qwen3_5MoeForConditionalGeneration PreTrainedModel Qwen3_5MoeVisionConfig Qwen3_5MoeTextConfig Qwen3_5MoeConfig AutoModelForCausalLM 用户代码 __post_init__() 自动将 dict 转为 Config 对象 构建 40 层 DecoderLayer 每层根据 layer_types 选择 full_attention 或 linear_attention 每层均使用 Qwen3_5MoeSparseMoeBlock (256 专家 + 共享专家) MoE 权重特殊处理: experts.gate_up_proj shape: [256, 1024, 2048] experts.down_proj shape: [256, 2048, 512] GatedDeltaNet: dt_bias=1, A_log~U(0,16) RMSNorm: weight=0 (1-centered) Experts: normal_(std=initializer_range) from_pretrained('Qwen/Qwen3.5-35B-A3B') 从 config.json 实例化 Config 解析 text_config dict → Qwen3_5MoeTextConfig 解析 vision_config dict → Qwen3_5MoeVisionConfig Qwen3_5MoeForConditionalGeneration(config) Qwen3_5MoeModel(config) Qwen3_5MoeVisionModel._from_config(config.vision_config) Qwen3_5MoeTextModel._from_config(config.text_config) self.lm_head = Linear(2048, 248320) load_state_dict() 加载权重 权重分配完成 post_init() → _init_weights()

3.2 MoE 权重加载特殊处理

Qwen3.5-MoE 的专家权重以 3D 张量存储,这是 MoE 模型与 Dense 模型的关键区别。在 [modeling_qwen3_5_moe.py:736-772](file:///workspace/src/transformers/models/qwen3_5_moe/modeling_qwen3_5_moe.py#L736) 中:

@use_experts_implementation
class Qwen3_5MoeExperts(nn.Module):
    def __init__(self, config):
        super().__init__()
        self.num_experts = config.num_experts          # 256
        self.hidden_dim = config.hidden_size           # 2048
        self.intermediate_dim = config.moe_intermediate_size  # 512
        # 3D 参数张量:[num_experts, intermediate_dim*2, hidden_dim]
        self.gate_up_proj = nn.Parameter(torch.empty(self.num_experts, 2 * self.intermediate_dim, self.hidden_dim))
        # 3D 参数张量:[num_experts, hidden_dim, intermediate_dim]
        self.down_proj = nn.Parameter(torch.empty(self.num_experts, self.hidden_dim, self.intermediate_dim))

MoE 模型权重 (3D)

Dense 模型权重 (2D)

MoE: 融合为 3D

MoE: 融合为 3D

MoE: 扩展为 3D

gate_proj: [2048, 512]

up_proj: [2048, 512]

down_proj: [512, 2048]

gate_up_proj: [256, 1024, 2048]
256个专家共享一个参数张量
gate和up融合存储

down_proj: [256, 2048, 512]
256个专家共享一个参数张量


4. 混合注意力层架构

Qwen3.5-MoE 的核心创新在于 full_attention 层和 linear_attention 层交替排列,这是混合注意力架构的首次大规模应用。

4.1 层类型分布图

layer_types 在 [configuration_qwen3_5_moe.py:112-119](file:///workspace/src/transformers/models/qwen3_5_moe/configuration_qwen3_5_moe.py#L112) 中自动生成,默认 full_attention_interval=4

def __post_init__(self, **kwargs):
    if self.layer_types is None:
        interval_pattern = kwargs.pop("full_attention_interval", 4)
        self.layer_types = [
            "linear_attention" if bool((i + 1) % interval_pattern) else "full_attention"
            for i in range(self.num_hidden_layers)
        ]

40层 DecoderLayer 的 layer_types 分布

Layer 0
linear_attention

Layer 1
linear_attention

Layer 2
linear_attention

Layer 3
🔥full_attention

Layer 4
linear_attention

Layer 5
linear_attention

Layer 6
linear_attention

Layer 7
🔥full_attention

...

Layer 39
🔥full_attention

规律:每 4 层中,第 0-2 层为 linear_attention,第 3 层为 full_attention。40 层中共有 10 个 full_attention 层和 30 个 linear_attention 层。

4.2 Qwen3_5MoeAttention 内部结构图

定义在 [modeling_qwen3_5_moe.py:642-716](file:///workspace/src/transformers/models/qwen3_5_moe/modeling_qwen3_5_moe.py#L642):

query

gate

hidden_states
[bs, seq, 2048]

q_proj
[2048, 16×256×2=8192]
输出含 gate

k_proj
[2048, 2×256=512]

v_proj
[2048, 2×256=512]

torch.chunk(dim=-1)
拆分为 query 和 gate

q_norm (RMSNorm)
head_dim=256

k_norm (RMSNorm)
head_dim=256

apply_rotary_pos_emb
M-RoPE 位置编码

KV Cache 更新
past_key_values.update()

Attention Interface
FlashAttn/SDPA/Eager

Sigmoid Gate
attn_output *= σ(gate)

o_proj
[16×256, 2048]

attn_output
[bs, seq, 2048]

三大创新点

  1. QK Normq_normk_norm 对 Q/K 做 RMSNorm,稳定训练
  2. Gate 机制q_proj 输出维度翻倍(head_dim * 2),一半作为 query,一半经 sigmoid 门控
  3. M-RoPE:多模态旋转位置编码,支持文本/图像/视频的 3D 位置

4.3 Qwen3_5MoeGatedDeltaNet 内部结构图

定义在 [modeling_qwen3_5_moe.py:367-555](file:///workspace/src/transformers/models/qwen3_5_moe/modeling_qwen3_5_moe.py#L367):

Q, K, V

hidden_states
[bs, seq, 2048]

in_proj_qkv
[2048, 2×2048+4096=8192]
QKV 融合投影

in_proj_z
[2048, 4096]
门控 z

in_proj_b
[2048, 32]
beta 投影

in_proj_a
[2048, 32]
衰减率投影

causal_conv1d
kernel_size=4, groups=conv_dim
因果卷积

torch.split → Q, K, V

β = σ(b)
erasure 门控

g = -exp(A_log) × softplus(a + dt_bias)
衰减率

Gated Delta Rule
chunk 模式 (prefill)
recurrent 模式 (decode)

RMSNormGated
norm + silu(z) 门控

out_proj
[4096, 2048]

output
[bs, seq, 2048]

GatedDeltaNet 核心公式

# 递推模式(单 token 解码):
S_t = S_{t-1} * exp(g_t)                    # 衰减旧状态
kv_mem = (S_t * k_t).sum(dim=-2)            # 检索记忆
δ_t = (v_t - kv_mem) * β_t                  # 计算修正量
S_t = S_t + k_t^T * δ_t                     # 更新状态
o_t = (S_t * q_t).sum(dim=-2)               # 查询输出

4.4 两种注意力层的数据流对比图

linear_attention 层

hidden_states

input_layernorm

in_proj_qkv + in_proj_z/b/a

causal_conv1d
kernel=4

Gated Delta Rule
O(n) 复杂度

RMSNormGated
norm + silu(z)

residual + output

full_attention 层

hidden_states

input_layernorm

q_proj + k_proj + v_proj

q_norm + k_norm

M-RoPE

Softmax Attention
O(n²) 复杂度

Sigmoid Gate

residual + output

特性 full_attention linear_attention
复杂度 O(n²) O(n)
缓存类型 KV Cache conv_state + recurrent_state
位置编码 M-RoPE 无(卷积隐式编码)
QK Norm ❌(使用 L2 Norm)
Gate 机制 Sigmoid Gate on Q RMSNormGated with z
适用场景 精确长程依赖 高效序列建模

5. MoE 专家路由系统

Qwen3.5-MoE 采用 256 专家 Top-8 路由 + 共享专家的混合架构,每个 token 同时经过 8 个路由专家和 1 个共享专家。

5.1 MoE 路由流程图

共享专家

专家计算

路由决策

top_k_index, top_k_weights

hidden_states
[bs, seq, 2048]

Qwen3_5MoeTopKRouter
weight: [256, 2048]

Softmax → router_probs

Top-8 选择 → indices + weights

归一化 weights
w /= sum(w)

遍历 256 个专家
仅计算被选中的专家

gate_up_proj[expert_idx]
F.linear → chunk → SiLU(gate)*up

down_proj[expert_idx]
F.linear → down_proj

× routing_weights

index_add_ 累加

SharedExpert (标准 MLP)
gate_proj + up_proj + down_proj

SharedExpertGate
σ(Linear(x))

expert_output + shared_expert_output

output
[bs, seq, 2048]

5.2 Qwen3_5MoeSparseMoeBlock 内部结构图

定义在 [modeling_qwen3_5_moe.py:794-813](file:///workspace/src/transformers/models/qwen3_5_moe/modeling_qwen3_5_moe.py#L794):

共享专家路径

稀疏路由路径

hidden_states
[bs, seq, 2048]

reshape → [-1, 2048]

gate (TopKRouter)
→ router_logits, routing_weights, selected_experts

experts (Qwen3_5MoeExperts)
→ expert_output

shared_expert (MLP)
gate_proj [2048, 512]
up_proj [2048, 512]
down_proj [512, 2048]

shared_expert_gate
Linear(2048, 1)
σ(x) * shared_output

expert_output + gated_shared_output

reshape → [bs, seq, 2048]

output

关键代码:

class Qwen3_5MoeSparseMoeBlock(nn.Module):
    def __init__(self, config):
        self.gate = Qwen3_5MoeTopKRouter(config)
        self.experts = Qwen3_5MoeExperts(config)
        self.shared_expert = Qwen3_5MoeMLP(config, intermediate_size=config.shared_expert_intermediate_size)
        self.shared_expert_gate = torch.nn.Linear(config.hidden_size, 1, bias=False)

    def forward(self, hidden_states):
        shared_expert_output = self.shared_expert(hidden_states_reshaped)
        _, routing_weights, selected_experts = self.gate(hidden_states_reshaped)
        expert_output = self.experts(hidden_states_reshaped, selected_experts, routing_weights)
        shared_expert_output = F.sigmoid(self.shared_expert_gate(hidden_states_reshaped)) * shared_expert_output
        expert_output = expert_output + shared_expert_output

5.3 @use_experts_implementation 装饰器的工作原理

定义在 [integrations/moe.py:523](file:///workspace/src/transformers/integrations/moe.py),该装饰器允许将默认的 PyTorch 专家实现替换为优化版本(如 megablocksgrouped_gemm):

默认

megablocks

grouped_gemm

原始 Qwen3_5MoeExperts
forward() 逐专家循环

@use_experts_implementation
装饰器

experts_interface.dispatch()
根据运行时选择实现

PyTorch 实现
逐专家循环计算

MegaBlocks 实现
Block-Sparse 矩阵乘法

GroupedGEMM 实现
批量矩阵乘法

5.4 负载均衡损失计算图

定义在 [modeling_qwen3_5_moe.py:1755-1834](file:///workspace/src/transformers/models/qwen3_5_moe/modeling_qwen3_5_moe.py#L1755):

无 attention_mask

有 attention_mask

tokens_per_expert
= sum(mask * expert_mask) / sum(mask)

router_prob_per_expert
= sum(weights * mask) / sum(mask)

gate_logits
每层的路由 logits
shape: [bs*seq, 256]

torch.cat 所有层的 logits

Softmax → routing_weights

Top-K → selected_experts

one_hot → expert_mask

tokens_per_expert
= mean(expert_mask)

router_prob_per_expert
= mean(routing_weights)

overall_loss
= sum(tokens_per_expert × router_prob_per_expert) × num_experts

公式:L_aux = N × Σ_i(f_i × P_i),其中 f_i 是分配给专家 i 的 token 比例,P_i 是路由到专家 i 的平均概率。


6. 多模态视觉编码器

6.1 视觉编码流程图

27 层 VisionBlock

×27

pixel_values
[num_patches, 3, 2, 16, 16]
(C, T, H, W)

Qwen3_5MoeVisionPatchEmbed
Conv3d: kernel=[2,16,16]
stride=[2,16,16]

位置嵌入
bilinear 插值 + pos_embed

旋转位置编码
rotary_pos_emb(position_ids)

norm1 (LayerNorm)

VisionAttention
qkv → RoPE → Attention → proj

norm2 (LayerNorm)

VisionMLP
fc1 → GELU → fc2

PatchMerger
LayerNorm → fc1 → GELU → fc2
[1152×4, 3584]

image_embeds / video_embeds
[num_tokens, 3584]

6.2 3D 位置编码(M-RoPE)计算图

视觉 token 的 3D 位置编码由 get_vision_position_ids 方法计算,定义在 [modeling_qwen3_5_moe.py:1394-1450](file:///workspace/src/transformers/models/qwen3_5_moe/modeling_qwen3_5_moe.py#L1394):

三维位置计算

空间合并

grid_thw
[T, H, W]

spatial_merge_size = 2

temporal_merge_size = 1

position_temporal
arange(T) × time_interval
+ start_position

position_height
arange(H//2) + start_position
repeat_interleave(W//2) × T

position_width
arange(W//2) + start_position
repeat(H//2 × T)

torch.stack([T, H, W])
shape: [3, num_tokens]

关键代码:

def get_vision_position_ids(self, start_position, grid_thw, ...):
    llm_grid_t = grid_thw[0] // temp_merge_size
    llm_grid_h = grid_thw[1] // spatial_merge_size
    llm_grid_w = grid_thw[2] // spatial_merge_size

    position_temporal = torch.arange(llm_grid_t) * time_interval
    position_width = torch.arange(llm_grid_w) + start_position
    position_height = torch.arange(llm_grid_h) + start_position

    position_width = position_width.repeat(llm_grid_h * llm_grid_t)
    position_height = position_height.repeat_interleave(llm_grid_w).repeat(llm_grid_t)
    position_temporal = position_temporal.repeat_interleave(llm_grid_h * llm_grid_w) + start_position

    return torch.stack([position_temporal, position_height, position_width], dim=0)

6.3 视觉 token 与文本 token 的融合流程图

在 [modeling_qwen3_5_moe.py:1707-1727](file:///workspace/src/transformers/models/qwen3_5_moe/modeling_qwen3_5_moe.py#L1707) 中,使用 masked_scatter 将视觉嵌入融合到文本嵌入中:

input_ids
[bs, seq]
含 image_token_id 占位符

embed_tokens(input_ids)
[bs, seq, 2048]

pixel_values
图像/视频像素

VisionModel 编码
→ image_embeds / video_embeds

get_placeholder_mask()
定位 image_token_id / video_token_id

torch_compilable_check
验证 token 数 == feature 数

masked_scatter(mask, embeds)
将视觉嵌入填入占位符位置

inputs_embeds
[bs, seq, 2048]
文本+视觉融合嵌入

关键代码:

if pixel_values is not None:
    image_embeds = self.get_image_features(pixel_values, image_grid_thw)
    image_mask, _ = self.get_placeholder_mask(input_ids, inputs_embeds=inputs_embeds, image_features=image_embeds)
    inputs_embeds = inputs_embeds.masked_scatter(image_mask, image_embeds)

if pixel_values_videos is not None:
    video_embeds = self.get_video_features(pixel_values_videos, video_grid_thw)
    _, video_mask = self.get_placeholder_mask(input_ids, inputs_embeds=inputs_embeds, video_features=video_embeds)
    inputs_embeds = inputs_embeds.masked_scatter(video_mask, video_embeds)

7. RoPE 与 M-RoPE 位置编码

M-RoPE(Multimodal Rotary Position Embedding)是 Qwen3.5 系列的核心位置编码方案,支持文本的 1D 位置和图像/视频的 3D 位置。

7.1 M-RoPE 原理图

视频 token (3D 位置)

grid_thw = [T, H, W]

T: 0,0,...,0,1,1,...,1,...
(帧间递增)

H: 0,0,1,1,...,0,0,1,1,...
(每帧内行重复)

W: 0,1,0,1,...,0,1,0,1,...
(每帧内列重复)

图像 token (3D 位置)

grid_thw = [1, H, W]

T: 0,0,0,...,0
(单帧,全0)

H: 0,0,1,1,2,2,...
(行重复)

W: 0,1,0,1,0,1,...
(列重复)

文本 token (1D 位置)

position_ids = [0,1,2,3,...]
三个维度使用相同位置

T: 0,1,2,3,...

H: 0,1,2,3,...

W: 0,1,2,3,...

7.2 apply_interleaved_mrope 交错排列图

在 [modeling_qwen3_5_moe.py:165-180](file:///workspace/src/transformers/models/qwen3_5_moe/modeling_qwen3_5_moe.py#L165) 中,M-RoPE 将三维频率交错排列:

交错排列后

分块频率 (mrope_section=[11,11,10])

T 频率: [f0...f10]
11 个维度

H 频率: [f0...f10]
11 个维度

W 频率: [f0...f9]
10 个维度

[T0, H0, W0, T1, H1, W1, ..., T10, H10, T10, H10]
THW 交错 → 保持频率连续性

关键代码:

def apply_interleaved_mrope(self, freqs, mrope_section):
    freqs_t = freqs[0]  # 以 T 维度为基底
    for dim, offset in enumerate((1, 2), start=1):  # H, W
        length = mrope_section[dim] * 3
        idx = slice(offset, length, 3)  # 交错索引
        freqs_t[..., idx] = freqs[dim, ..., idx]
    return freqs_t

7.3 get_rope_index 位置计算流程图

定义在 [modeling_qwen3_5_moe.py:1452-1543](file:///workspace/src/transformers/models/qwen3_5_moe/modeling_qwen3_5_moe.py#L1452):

视频组 (type=2)

图像组 (type=1)

文本组 (type=0)

input_ids + mm_token_type_ids
+ image_grid_thw + video_grid_thw

按 token_type 分组
itertools.groupby

arange(text_len) + current_pos
expand(3, -1) → T/H/W 相同

next(image_grid_thw_iter)

get_vision_position_ids(current_pos, grid_thw)

current_pos += max(H,W) // merge_size

next(video_grid_thw_iter)

get_vision_position_ids(current_pos, grid_thw)

current_pos += max(H,W) // merge_size

torch.cat 所有组的位置
shape: [3, bs, seq_len]

mrope_position_deltas
= max(position) + 1 - seq_len

视频特殊处理:由于 Qwen3.5 使用时间戳分隔视频帧,video_grid_thw 需要按帧拆分:

if video_grid_thw is not None:
    video_grid_thw = torch.repeat_interleave(video_grid_thw, video_grid_thw[:, 0], dim=0)
    video_grid_thw[:, 0] = 1  # 每帧独立

8. 缓存系统

Qwen3.5-MoE 的混合注意力架构需要混合缓存:full_attention 层使用 KV Cache,linear_attention 层使用 conv_state + recurrent_state

8.1 混合缓存架构图

DynamicCache (统一管理)

linear_attention 层缓存

full_attention 层缓存

full_attention

linear_attention

linear_attention

CacheLayer
key_cache: [bs, heads, seq, dim]
value_cache: [bs, heads, seq, dim]

LinearAttentionCacheLayerMixin
conv_states: [bs, conv_dim, kernel_size]
因果卷积状态

recurrent_states: [bs, heads, k_dim, v_dim]
DeltaNet 递推状态

config.layer_types
确定每层缓存类型

DynamicCache 在初始化时根据 config.layer_types 自动判断每层的缓存类型,定义在 [cache_utils.py:1229](file:///workspace/src/transformers/cache_utils.py)。

8.2 linear_attention 层的缓存更新流程

recurrent_state conv_state DynamicCache Qwen3_5MoeGatedDeltaNet recurrent_state conv_state DynamicCache Qwen3_5MoeGatedDeltaNet Prefill 阶段 (seq_len > 1) Decode 阶段 (seq_len == 1) conv_state 原地更新 S_t = S_{t-1} * g + k^T * δ has_previous_state(layer_idx)? False (首次) in_proj_qkv → causal_conv1d update_conv_state(new_conv_state, layer_idx) 懒初始化 + copy chunk_gated_delta_rule(Q, K, V, g, β) update_recurrent_state(last_recurrent_state, layer_idx) copy has_previous_state(layer_idx)? True conv_state, recurrent_state causal_conv1d_update (单步更新) recurrent_gated_delta_rule (递推) update_recurrent_state(new_state, layer_idx) copy

关键代码在 [modeling_qwen3_5_moe.py:449-546](file:///workspace/src/transformers/models/qwen3_5_moe/modeling_qwen3_5_moe.py#L449):

use_precomputed_states = cache_params is not None and cache_params.has_previous_state(self.layer_idx)

if use_precomputed_states:
    conv_state = cache_params.layers[self.layer_idx].conv_states
    recurrent_state = cache_params.layers[self.layer_idx].recurrent_states

# Prefill: 多 token,使用 chunk 模式
if not (use_precomputed_states and seq_len == 1):
    if cache_params is not None:
        new_conv_state = F.pad(mixed_qkv, (self.conv_kernel_size - mixed_qkv.shape[-1], 0))
        cache_params.update_conv_state(new_conv_state, self.layer_idx)
    core_attn_out, last_recurrent_state = self.chunk_gated_delta_rule(...)

# Decode: 单 token,使用 recurrent 模式
else:
    mixed_qkv = self.causal_conv1d_update(mixed_qkv, conv_state, ...)
    core_attn_out, last_recurrent_state = self.recurrent_gated_delta_rule(...)

if cache_params is not None:
    cache_params.update_recurrent_state(last_recurrent_state, self.layer_idx)

9. generate() 生成全流程

9.1 生成循环时序图

DynamicCache Qwen3_5MoeTextModel Qwen3_5MoeVisionModel Qwen3_5MoeForConditionalGeneration AutoProcessor 用户 DynamicCache Qwen3_5MoeTextModel Qwen3_5MoeVisionModel Qwen3_5MoeForConditionalGeneration AutoProcessor 用户 首次迭代 (is_first_iteration=True) 后续迭代 (is_first_iteration=False) loop [生成循环] 处理图像+文本 input_ids + pixel_values + grid_thw + mm_token_type_ids prepare_inputs_for_generation() get_image_features(pixel_values, grid_thw) image_embeds masked_scatter 融合视觉嵌入 _prepare_position_ids_for_generation() 计算 3D position_ids + rope_deltas forward(inputs_embeds, position_ids, ...) 初始化 DynamicCache hidden_states lm_head → logits → 采样 next_token prepare_inputs_for_generation() 清除 pixel_values/grid_thw _prepare_position_ids_for_generation() 使用 rope_deltas 推算位置 forward(input_ids=next_token, position_ids, past_key_values) 读取/更新缓存 hidden_states lm_head → logits → 采样 next_token generated_ids

9.2 prepare_inputs_for_generation 的特殊处理

定义在 [modeling_qwen3_5_moe.py:2106-2142](file:///workspace/src/transformers/models/qwen3_5_moe/modeling_qwen3_5_moe.py#L2106):

def prepare_inputs_for_generation(self, input_ids, past_key_values=None, ...,
                                   pixel_values=None, pixel_values_videos=None,
                                   image_grid_thw=None, video_grid_thw=None,
                                   is_first_iteration=False, **kwargs):
    model_inputs = super().prepare_inputs_for_generation(...)

    # 首次迭代后清除视觉输入,避免重复编码
    if not is_first_iteration and use_cache:
        model_inputs["pixel_values"] = None
        model_inputs["pixel_values_videos"] = None

    return model_inputs

后续迭代

pixel_values: ❌ None

→ 仅文本 token,使用 rope_deltas 推算位置

image_grid_thw: ❌ None

mm_token_type_ids: ❌ None

首次迭代

pixel_values: ✅ 有值

→ 视觉编码 + masked_scatter

image_grid_thw: ✅ 有值

mm_token_type_ids: ✅ 有值

9.3 _prepare_position_ids_for_generation 的 3D 位置编码处理

定义在 [modeling_qwen3_5_moe.py:2144-2180](file:///workspace/src/transformers/models/qwen3_5_moe/modeling_qwen3_5_moe.py#L2144):

_prepare_position_ids_for_generation

past_length != 0
且 rope_deltas 存在?

position_ids = text_positions + rope_deltas
直接使用缓存的 delta

有 input_ids 且
有 mm_token_type_ids 且
有 image/video_grid_thw?

get_rope_index(input_ids, ...)
计算完整 3D 位置

存储 rope_deltas

vision_positions = text_positions.expand(3,-1,-1)
纯文本:三个维度相同

rope_deltas = zeros
无多模态偏移

torch.cat([text_positions, vision_positions])
shape: [4, bs, seq]

position_ids [4, bs, seq]

关键代码:

def _prepare_position_ids_for_generation(self, inputs_tensor, model_kwargs):
    text_positions = super()._prepare_position_ids_for_generation(inputs_tensor, model_kwargs)

    # 增量生成:直接用缓存的 rope_deltas
    past_length = 0
    if (cache := model_kwargs.get("past_key_values")) is not None:
        past_length = cache.get_seq_length()
    if past_length != 0 and self.model.rope_deltas is not None:
        position_ids = text_positions[None, ...] + self.model.rope_deltas
        return position_ids

    # 首次生成:计算 3D 位置
    if is_input_ids and model_kwargs.get("mm_token_type_ids") is not None and ...:
        vision_positions, rope_deltas = self.model.get_rope_index(inputs_tensor, **model_kwargs)
        self.model.rope_deltas = rope_deltas
    else:
        vision_positions = text_positions.unsqueeze(0).expand(3, -1, -1)
        self.model.rope_deltas = torch.zeros(...)

    # 拼接 [text, T, H, W] → [4, bs, seq]
    text_positions = text_positions[None, ...]
    position_ids = torch.cat([text_positions, vision_positions], dim=0)
    return position_ids

10. 分布式并行

10.1 TP 策略映射图

定义在 [configuration_qwen3_5_moe.py:59-72](file:///workspace/src/transformers/models/qwen3_5_moe/configuration_qwen3_5_moe.py#L59):

MoE 专家并行策略

experts.gate_up_proj → packed_colwise
打包列切分 [256, 1024, 2048]

experts.down_proj → rowwise

experts → moe_tp_experts
🔥 专家级并行:每个 GPU 持有部分专家

shared_expert.gate_proj → colwise

shared_expert.up_proj → colwise

shared_expert.down_proj → rowwise

注意力层并行策略

q_proj → colwise
按列切分,每个 GPU 计算部分 head

k_proj → colwise

v_proj → colwise

o_proj → rowwise
按行切分,结果 all-reduce

q_norm → replicated_with_grad_allreduce
复制,梯度 all-reduce

k_norm → replicated_with_grad_allreduce

10.2 MoE 专家并行(moe_tp_experts)原理图

4 GPU 张量并行

GPU 3

GPU 2

GPU 1

GPU 0

Expert 0-63
gate_up_proj[0:64]
down_proj[0:64]

Expert 64-127
gate_up_proj[64:128]
down_proj[64:128]

Expert 128-191
gate_up_proj[128:192]
down_proj[128:192]

Expert 192-255
gate_up_proj[192:256]
down_proj[192:256]

hidden_states
[bs, seq, 2048]

TopKRouter
每个 GPU 完整计算路由

All-to-All 通信
将 token 发送到对应专家所在 GPU

各 GPU 并行计算
本地专家前向

All-to-All 通信
收集计算结果

expert_output
[bs, seq, 2048]

moe_tp_experts 与普通 colwise/rowwise 的区别:

  • colwise/rowwise:切分单个线性层的权重矩阵
  • moe_tp_experts:按专家维度切分,每个 GPU 持有 256/tp_size 个完整专家

11. 状态与生命周期总结

11.1 状态机图

渲染错误: Mermaid 渲染失败: Parse error on line 41: ...生成: full_attention 层: KV Cache
linea... -----------------------^ Expecting 'SPACE', 'NL', 'HIDE_EMPTY', 'scale', 'COMPOSIT_STATE', 'STRUCT_STOP', 'STATE_DESCR', 'ID', 'FORK', 'JOIN', 'CHOICE', 'CONCURRENT', 'note', 'acc_title', 'acc_descr', 'acc_descr_multiline_value', 'CLICK', 'classDef', 'style', 'class', 'direction_tb', 'direction_bt', 'direction_rl', 'direction_lr', 'EDGE_STATE', got 'DESCR'

11.2 关键数据流总结

输出

文本模型

位置编码

嵌入融合

视觉编码

输入

每层

input_layernorm

full_attention / linear_attention

post_attention_layernorm

SparseMoeBlock
256专家Top8 + 共享专家

input_ids

pixel_values

grid_thw

mm_token_type_ids

VisionModel
PatchEmbed → 27 Blocks → Merger

image_embeds
[num_tokens, 3584]

masked_scatter
视觉嵌入 → 占位符

inputs_embeds
[bs, seq, 2048]

get_rope_index
3D M-RoPE

position_ids
[4, bs, seq]

embed_tokens

40 层 DecoderLayer

RMSNorm

lm_head
[2048, 248320]

logits

11.3 核心设计哲学

Qwen3.5-MoE 在 Transformers 中的实现体现了以下设计哲学:

  1. 模块化继承:通过 modular_qwen3_5_moe.py 中的类继承(Qwen3_5MoeGatedDeltaNet ← Qwen3_5GatedDeltaNet),最大化代码复用,最小化重复
  2. 混合架构统一管理DynamicCache 根据 config.layer_types 自动分发不同缓存类型,上层代码无需感知底层差异
  3. 多模态位置编码:M-RoPE 将文本 1D 位置和视觉 3D 位置统一到同一框架,通过 rope_deltas 在增量生成时高效推算
  4. MoE 专家并行moe_tp_experts 策略让 256 个专家可以跨 GPU 分布,配合 @use_experts_implementation 装饰器支持多种优化后端
  5. 生成效率linear_attention 层的 O(n) 复杂度 + recurrent_state 缓存,使得增量解码无需维护完整的 KV Cache,大幅降低长序列生成的内存开销

更多推荐