SmolVLA 模型架构

1. 整体架构概览

SmolVLA (Small Vision-Language-Action) 是由 Hugging Face 设计的轻量级视觉-语言-动作 (VLA) 模型,采用 SmolVLM2-500M-Video-Instruct 作为视觉语言主干网络,并引入独立的 Action Expert 网络通过交叉注意力机制从 VLM 中提取特征来生成机器人动作。SmolVLA 使用 Flow Matching(与 Pi0 相同的范式)进行动作生成,通过迭代去噪将高斯噪声转化为动作轨迹。其核心设计理念是:VLM 处理前缀序列(图像 + 语言 + 状态),Action Expert 处理后缀序列(含噪动作 + 时间步),两者通过交叉注意力层交互,最终输出预测动作。

graph TB subgraph Input["输入"] IMG["相机图像
(1~N 个视角)"] TXT["语言指令
(token 化)"] STATE["机器人状态
[B, max_state_dim]"] end subgraph VLMBackbone["SmolVLM2-500M 主干网络 (可冻结)"] VE["SigLIP 视觉编码器"] CONN["Connector 投影层"] LLM["SmolVLM2 语言模型
(前 16 层)"] end subgraph Projection["投影层"] SP["state_proj
Linear: state_dim -> hidden_size"] end subgraph ActionExpert["Action Expert 网络"] AIP["action_in_proj
Linear: action_dim -> expert_hidden"] TML["action_time_mlp
时间步融合 MLP"] EXP["lm_expert
(交叉注意力 + 自注意力
交替的 Transformer 层)"] AOP["action_out_proj
Linear: expert_hidden -> action_dim"] end subgraph FlowMatch["Flow Matching"] FM["高斯噪声采样
+ Beta(1.5, 1.0) 时间步"] end subgraph Output["输出"] ACT["预测动作轨迹
[B, chunk_size, action_dim]"] end IMG --> VE --> CONN --> LLM TXT --> LLM STATE --> SP SP -->|"状态嵌入"| LLM LLM -->|"KV Cache
前缀特征"| EXP FM -->|"含噪动作 x_t"| AIP AIP --> TML TML -->|"动作+时间步嵌入"| EXP EXP --> AOP --> ACT style Input fill:#e8f4fd,stroke:#2196F3 style VLMBackbone fill:#fff3e0,stroke:#FF9800 style Projection fill:#f3e5f5,stroke:#9C27B0 style ActionExpert fill:#e8f5e9,stroke:#4CAF50 style FlowMatch fill:#e0f7fa,stroke:#00BCD4 style Output fill:#fce4ec,stroke:#E91E63

SmolVLA 的核心设计特点:

特性 SmolVLA GR00T N1.5 (对比)
VLM 主干 SmolVLM2-500M (SigLIP + SmolLM2) Eagle (SigLIP2 + Qwen3-1.7B)
动作生成 Action Expert (交叉注意力) DiT (交替注意力)
动作范式 Flow Matching (连续) Flow Matching (连续)
注意力模式 前缀双向 + 后缀交叉注意力 交替交叉/自注意力
模型规模 ~500M 参数 ~2B+ 参数
推理步数 10 步 4 步

2. 核心组件详解

2.1 SmolVLM2-500M 视觉语言模型

SmolVLA 使用 HuggingFaceTB/SmolVLM2-500M-Video-Instruct 作为 VLM 主干,内部包含 SigLIP 视觉编码器、Connector 投影层和 SmolLM2 语言模型。VLM 的作用是处理前缀序列(图像 + 语言 + 状态),生成供 Action Expert 使用的 KV Cache。

graph LR subgraph VisionEncoder["SigLIP 视觉编码器 (vision_model)"] PIX["pixel_values
[B, 3, 512, 512]
像素范围 [-1, 1]"] --> SIG["SigLIP
视觉编码器"] SIG --> FEAT["图像特征
[B, N_patches, vis_dim]"] end subgraph Connector["Connector 投影层"] FEAT --> CPROJ["Connector
(Modality Projection
+ Resampling)"] CPROJ --> VFEAT["投影后特征
[B, N_tokens, hidden_size]"] end subgraph TextModel["SmolLM2 语言模型 (text_model)"] LANG["语言 token
[B, seq_len]"] --> LEMB["词元嵌入层"] LEMB --> NORM["嵌入 * sqrt(dim)
归一化"] VFEAT -->|"图像特殊 token
包裹后拼接"| MERGE["融合至序列"] NORM --> MERGE MERGE --> LAYERS["SmolLM2 Transformer
前 num_vlm_layers 层
(默认 16 层)"] end LAYERS -->|"VLM 隐藏状态
[B, prefix_len, hidden_size]"| OUT["前缀特征"] style VisionEncoder fill:#e3f2fd,stroke:#2196F3 style Connector fill:#f3e5f5,stroke:#9C27B0 style TextModel fill:#e8f5e9,stroke:#4CAF50

图像预处理流程:

  1. 图像缩放至 512x512,保持宽高比并用 0 填充(resize_with_pad
  2. 像素值从 [0, 1] 映射至 [-1, 1](SigLIP 要求)
  3. SigLIP 编码后经过 Connector 投影至语言模型维度
  4. 图像嵌入乘以 sqrt(dim) 进行归一化
  5. 可选:添加特殊图像 token(fake_image_token + global_image_token)包裹

前缀序列拼接顺序:

[图像1特殊token] [图像1 patch嵌入] [图像1结束token] ... [语言嵌入] [状态嵌入]

VLM 层截断: 与 GR00T 类似,SmolVLA 通过 num_vlm_layers 参数(默认 16)截断 VLM 的 Transformer 层数,仅使用前 16 层。

冻结策略: - freeze_vision_encoder=True(默认):SigLIP 视觉编码器完全冻结 - train_expert_only=True(默认):整个 VLM 冻结,仅训练 Action Expert


2.2 Action Expert 网络(交叉注意力)

Action Expert 是 SmolVLA 的核心创新:一个独立的、更小的 Transformer 网络,通过交叉注意力从 VLM 的 KV Cache 中读取信息。其宽度通过 expert_width_multiplier(默认 0.75)控制,隐藏维度为 VLM 隐藏维度的 75%。

graph TB subgraph ExpertConfig["Action Expert 配置"] direction LR C1["hidden_size = int(vlm_hidden * 0.75)"] C2["intermediate_size = get_intermediate_size(hidden_size)"] C3["num_layers = num_vlm_layers (默认 16)"] C4["每 2 层交替一次自注意力"] end subgraph ExpertArch["Action Expert Transformer 层结构"] direction TB subgraph Layer0["Layer 0 — 自注意力层 (layer_idx % 2 == 0)"] IN0["后缀嵌入"] --> LN0["RMSNorm"] LN0 --> SA0["自注意力
Q, K, V 均来自后缀"] SA0 --> RES0["+ 残差"] RES0 --> PLN0["Post-Attention RMSNorm"] PLN0 --> MLP0["前馈 MLP"] MLP0 --> PRES0["+ 残差"] end subgraph Layer1["Layer 1 — 交叉注意力层 (layer_idx % 2 != 0)"] IN1["后缀嵌入"] --> LN1["RMSNorm"] LN1 --> CA1["交叉注意力
Q 来自后缀
K, V 来自 VLM KV Cache"] CA1 --> RES1["+ 残差"] RES1 --> PLN1["Post-Attention RMSNorm"] PLN1 --> MLP1["前馈 MLP"] MLP1 --> PRES1["+ 残差"] end PRES0 --> IN1 subgraph Layer2["Layer 2 — 自注意力层"] SA2["自注意力..."] end PRES1 --> SA2 SA2 --> DOTS["... 交替至第 N 层"] end subgraph KVSource["KV 来源"] VLM_KV["VLM KV Cache
(前缀特征的 K, V)"] end VLM_KV -->|"K, V 投影
(k_proj, v_proj 重新定义
输入维度 = vlm_kv_dim)"| CA1 style ExpertConfig fill:#fff8e1,stroke:#FFC107 style ExpertArch fill:#e8f5e9,stroke:#4CAF50 style Layer0 fill:#e3f2fd,stroke:#2196F3 style Layer1 fill:#fce4ec,stroke:#E91E63 style Layer2 fill:#e3f2fd,stroke:#2196F3 style KVSource fill:#fff3e0,stroke:#FF9800

交叉注意力层的 K, V 投影重塑:

在交叉注意力层中,K 和 V 来自 VLM 的 KV Cache,其维度为 num_kv_heads * head_dim。由于 Expert 的隐藏维度不同于 VLM,SmolVLA 在初始化时重新创建了这些层的 k_projv_proj

# 交叉注意力层的 K, V 投影
k_proj = Linear(vlm_kv_heads * vlm_head_dim, expert_kv_heads * expert_head_dim)
v_proj = Linear(vlm_kv_heads * vlm_head_dim, expert_kv_heads * expert_head_dim)

层对应关系:num_expert_layers < num_vlm_layers 时,Expert 层与 VLM 层按比例对应。例如 VLM 有 16 层、Expert 有 8 层时,每隔一层 VLM 层对应一个 Expert 层。未对应的层跳过 Expert 处理。


2.3 Flow Matching 扩散机制

SmolVLA 使用 Flow Matching(条件流匹配)范式生成动作,与 Pi0 相同。核心思想是学习从噪声分布到动作分布的"速度场",训练时通过线性插值构造含噪样本,推理时通过欧拉积分迭代去噪。

graph TB subgraph Training["训练时: 构造含噪样本"] direction TB A_GT["真实动作 a
[B, 50, action_dim]"] NOISE["高斯噪声 epsilon
~ N(0, 1)"] BETA["时间步 t
~ Beta(1.5, 1.0) * 0.999 + 0.001"] A_GT --> INTERP["线性插值
x_t = t * epsilon + (1 - t) * a"] NOISE --> INTERP BETA --> INTERP A_GT --> TARGET["速度目标
u_t = epsilon - a"] NOISE --> TARGET INTERP --> XT["含噪动作 x_t"] TARGET --> UT["目标速度 u_t"] end subgraph Model["模型预测"] XT --> VLA["SmolVLA
(VLM + Expert)"] BETA -->|"时间步条件"| VLA VLA --> VT["预测速度 v_t"] end subgraph Loss["损失"] UT --> MSE["MSE Loss
||u_t - v_t||^2"] VT --> MSE end style Training fill:#e0f7fa,stroke:#00BCD4 style Model fill:#e8f5e9,stroke:#4CAF50 style Loss fill:#fce4ec,stroke:#E91E63

Flow Matching 关键公式:

公式 说明
t ~ Beta(1.5, 1.0) * 0.999 + 0.001 时间步采样,偏向 t 接近 1(更接近噪声)
x_t = t * noise + (1 - t) * action 线性插值构造含噪样本(t=0 为干净动作,t=1 为纯噪声)
u_t = noise - action 速度目标(从动作到噪声的方向)
loss = MSE(u_t, v_t) 训练损失
x_{t+dt} = x_t + dt * v_t 推理时欧拉积分(dt = -1/num_steps)

注意: SmolVLA 的插值方向与某些文献相反:t=0 对应干净动作,t=1 对应纯噪声。推理时从 t=1 开始,逐步向 t=0 去噪。


2.4 状态投影与动作投影

SmolVLA 通过一系列线性投影层实现不同维度空间之间的映射。

graph LR subgraph StateProj["状态投影 (state_proj)"] S_IN["机器人状态
[B, max_state_dim=32]"] S_IN --> SP["Linear
(32 -> vlm_hidden_size)"] SP --> S_OUT["状态嵌入
[B, 1, vlm_hidden_size]"] end subgraph ActionInProj["动作输入投影 (action_in_proj)"] A_IN["含噪动作 x_t
[B, 50, max_action_dim=32]"] A_IN --> AIP["Linear
(32 -> expert_hidden_size)"] AIP --> A_EMB["动作嵌入
[B, 50, expert_hidden]"] end subgraph TimeEmb["时间步嵌入"] T_IN["时间步 t
[B]"] T_IN --> SIN["正弦余弦位置编码
dim=expert_hidden_size
period: [4e-3, 4.0]"] SIN --> T_EMB["时间嵌入
[B, 1, expert_hidden]"] T_EMB --> EXPAND["广播至动作长度
[B, 50, expert_hidden]"] end subgraph TimeFusion["时间步融合 MLP (action_time_mlp)"] A_EMB --> CAT["Concat
[B, 50, expert_hidden*2]"] EXPAND --> CAT CAT --> MLP_IN["Linear
(expert_hidden*2 -> expert_hidden)"] MLP_IN --> SILU["SiLU 激活函数"] SILU --> MLP_OUT["Linear
(expert_hidden -> expert_hidden)"] MLP_OUT --> FUSED["融合后的动作+时间嵌入
[B, 50, expert_hidden]"] end subgraph ActionOutProj["动作输出投影 (action_out_proj)"] EXP_OUT["Expert 输出
[B, 50, expert_hidden]"] EXP_OUT --> CAST["上转型至 float32"] CAST --> AOP["Linear
(expert_hidden -> 32)"] AOP --> V_OUT["预测速度 v_t
[B, 50, max_action_dim=32]"] end style StateProj fill:#e3f2fd,stroke:#2196F3 style ActionInProj fill:#f3e5f5,stroke:#9C27B0 style TimeEmb fill:#fff8e1,stroke:#FFC107 style TimeFusion fill:#e0f7fa,stroke:#00BCD4 style ActionOutProj fill:#fce4ec,stroke:#E91E63

维度填充机制: SmolVLA 将所有状态和动作向量填充至固定维度(max_state_dim=32max_action_dim=32),不足部分补零。推理后再截断回原始维度。这使得模型能够兼容不同自由度的机器人。


3. 训练流水线

训练时,模型接收完整的前缀和后缀序列,一次前向传播同时处理 VLM 和 Expert。注意力掩码确保前缀序列(图像、语言)采用双向注意力,而后缀序列(含噪动作)只能通过交叉注意力关注前缀。

graph TB subgraph DataPrep["数据准备"] direction LR IMG_RAW["原始图像"] --> RESIZE["resize_with_pad
-> [512, 512]
-> [-1, 1]"] STATE_RAW["原始状态"] --> PAD_S["pad_vector
-> [max_state_dim=32]"] ACT_RAW["原始动作"] --> PAD_A["pad_vector
-> [B, 50, 32]"] LANG_RAW["语言指令"] --> TOKENIZE["分词器
max_length=48"] end subgraph NoiseSample["噪声采样"] direction LR EPSILON["epsilon ~ N(0, 1)
[B, 50, 32]"] T_SAMPLE["t ~ Beta(1.5, 1.0)
* 0.999 + 0.001"] T_SAMPLE --> INTERP EPSILON --> INTERP["x_t = t*epsilon + (1-t)*action"] PAD_A --> INTERP EPSILON --> VEL_TARGET["u_t = epsilon - action"] PAD_A --> VEL_TARGET end subgraph PrefixEmbed["前缀嵌入 (embed_prefix)"] RESIZE --> VE["SigLIP 编码"] VE --> IMG_EMB["图像嵌入 * sqrt(dim)"] TOKENIZE --> LANG_EMB["语言嵌入 * sqrt(dim)"] PAD_S --> STATE_EMB["state_proj"] IMG_EMB --> PREFIX_CAT["拼接: [img | lang | state]"] LANG_EMB --> PREFIX_CAT STATE_EMB --> PREFIX_CAT PREFIX_CAT --> PREFIX["prefix_embs
[B, prefix_len, vlm_hidden]"] end subgraph SuffixEmbed["后缀嵌入 (embed_suffix)"] INTERP --> AIN["action_in_proj"] T_SAMPLE --> TIME_EMB["正弦余弦编码"] AIN --> FUSE["concat + action_time_mlp
+ SiLU"] TIME_EMB --> FUSE FUSE --> SUFFIX["suffix_embs
[B, 50, expert_hidden]"] end subgraph AttMask["注意力掩码构造"] direction LR AM1["前缀 att_mask: 0
(双向注意力)"] AM2["状态 att_mask: 1
(因果边界)"] AM3["后缀 att_mask: 1
(因果边界)"] AM1 --> MASK_2D["make_att_2d_masks
构造 2D 注意力掩码"] AM2 --> MASK_2D AM3 --> MASK_2D end subgraph Forward["联合前向传播"] PREFIX --> VLM_EXP["VLM + Expert
逐层交替处理"] SUFFIX --> VLM_EXP MASK_2D --> VLM_EXP VLM_EXP --> EXPERT_OUT["Expert 输出
取最后 50 个 token"] EXPERT_OUT --> AOUT["action_out_proj
(float32)"] AOUT --> V_PRED["预测速度 v_t"] end subgraph LossCalc["损失计算"] V_PRED --> MSE["MSE Loss
||u_t - v_t||^2"] VEL_TARGET --> MSE MSE --> MASK_LOSS["应用 in_episode_bound 掩码
+ 截断至原始 action_dim"] MASK_LOSS --> FINAL_LOSS["最终损失"] end style DataPrep fill:#fff3e0,stroke:#FF9800 style NoiseSample fill:#e0f7fa,stroke:#00BCD4 style PrefixEmbed fill:#e3f2fd,stroke:#2196F3 style SuffixEmbed fill:#f3e5f5,stroke:#9C27B0 style AttMask fill:#fff8e1,stroke:#FFC107 style Forward fill:#e8f5e9,stroke:#4CAF50 style LossCalc fill:#fce4ec,stroke:#E91E63

训练时注意力掩码详解:

前缀 (图像+语言):  att_mask = [0, 0, 0, ..., 0]  -> 双向注意力(互相可见)
前缀 (状态):       att_mask = [1]                   -> 因果边界(图像/语言不关注状态)
后缀 (动作+时间):  att_mask = [1, 1, ..., 1]        -> 因果边界(前缀不关注后缀)

通过 make_att_2d_masks 函数,基于 att_mask 的累积和构造完整的 2D 注意力掩码矩阵。结果是: - 图像和语言 token 之间双向可见 - 状态和动作 token 可以看到前面的所有 token - 图像和语言 token 无法看到状态和动作 token


4. 推理流水线

推理时采用两阶段:先计算前缀的 KV Cache(一次),然后通过 10 步欧拉积分迭代去噪后缀。KV Cache 使得前缀只需计算一次,大幅节省推理时间。

graph TB subgraph Phase1["阶段 1: 前缀编码 (一次性)"] IMG_IN["图像"] --> EMB_P["embed_prefix
SigLIP + 语言嵌入 + 状态投影"] LANG_IN["语言指令"] --> EMB_P STATE_IN["机器人状态"] --> EMB_P EMB_P --> VLM_FWD["VLM 前向
fill_kv_cache=True"] VLM_FWD --> KV["KV Cache
(每层的 key_states, value_states)"] end subgraph Phase2["阶段 2: 迭代去噪 (10 步欧拉积分)"] INIT["初始化
x_1 ~ N(0, 1)
[B, 50, 32]"] INIT --> STEP1 subgraph STEP1["Step 1: t=1.0"] E1["embed_suffix(x_t, t)"] --> D1["denoise_step
Expert 前向 + KV Cache"] D1 --> V1["v_1"] V1 --> U1["x_t += dt * v_1
dt = -0.1"] end subgraph STEP2["Step 2: t=0.9"] E2["embed_suffix(x_t, t)"] --> D2["denoise_step"] D2 --> V2["v_2"] V2 --> U2["x_t += dt * v_2"] end subgraph STEP3["Step 3~9: t=0.8 ... 0.2"] DOTS2["...重复去噪..."] end subgraph STEP10["Step 10: t=0.1"] E10["embed_suffix(x_t, t)"] --> D10["denoise_step"] D10 --> V10["v_10"] V10 --> U10["x_t += dt * v_10"] end U1 --> STEP2 U2 --> STEP3 STEP3 --> STEP10 end KV -->|"传入每步"| D1 KV -->|"传入每步"| D2 KV -->|"传入每步"| D10 subgraph Output["输出"] U10 --> UNPAD["截断至原始 action_dim"] UNPAD --> ACTIONS["最终动作轨迹
[B, 50, action_dim]"] end style Phase1 fill:#e3f2fd,stroke:#2196F3 style Phase2 fill:#e8f5e9,stroke:#4CAF50 style STEP1 fill:#f1f8e9,stroke:#8BC34A style STEP2 fill:#f1f8e9,stroke:#8BC34A style STEP3 fill:#f1f8e9,stroke:#8BC34A style STEP10 fill:#f1f8e9,stroke:#8BC34A style Output fill:#fce4ec,stroke:#E91E63

单步去噪详解 (denoise_step)

graph LR XT["x_t
[B, 50, 32]"] --> AIP["action_in_proj"] TS["timestep t"] --> SIN_COS["正弦余弦编码
[B, expert_hidden]"] AIP --> ACT_EMB["动作嵌入
[B, 50, expert_hidden]"] SIN_COS --> EXPAND["广播
[B, 50, expert_hidden]"] ACT_EMB --> CAT["Concat
[B, 50, expert_hidden*2]"] EXPAND --> CAT CAT --> TML_IN["action_time_mlp_in"] TML_IN --> SILU["SiLU"] SILU --> TML_OUT["action_time_mlp_out"] TML_OUT --> SUFFIX["suffix_embs"] SUFFIX --> ATTN["构造注意力掩码
(prefix KV + suffix 2D mask)"] KV["KV Cache"] --> ATTN ATTN --> EXPERT["Expert 前向
(交叉注意力读取 KV Cache)"] EXPERT --> LAST50["取最后 50 token"] LAST50 --> FP32["转为 float32"] FP32 --> AOP["action_out_proj"] AOP --> VT["预测速度 v_t
[B, 50, 32]"] style XT fill:#e0f7fa,stroke:#00BCD4 style EXPERT fill:#e8f5e9,stroke:#4CAF50 style VT fill:#fce4ec,stroke:#E91E63

推理时的注意力掩码: 后缀的每个 token 可以通过交叉注意力看到前缀 KV Cache 中的所有有效 token(基于 prefix_pad_masks),同时后缀 token 之间通过 suffix_att_masks 控制可见性。


5. 关键超参数表

参数 默认值 说明
模型结构
vlm_model_name HuggingFaceTB/SmolVLM2-500M-Video-Instruct VLM 主干模型
num_vlm_layers 16 VLM 使用的 Transformer 层数
num_expert_layers -1 (与 VLM 相同) Action Expert 层数
expert_width_multiplier 0.75 Expert 隐藏维度 = VLM 隐藏维度 * 0.75
self_attn_every_n_layers 2 每 2 层插入一个自注意力层
attention_mode cross_attn 交叉注意力模式
输入/输出
chunk_size 50 动作块大小(预测未来 50 步)
n_action_steps 50 每次执行的动作步数
n_obs_steps 1 观测步数
max_state_dim 32 状态向量最大维度(不足补零)
max_action_dim 32 动作向量最大维度(不足补零)
图像处理
resize_imgs_with_padding (512, 512) 图像缩放至 512x512
empty_cameras 0 空相机数量(用零填充)
add_image_special_tokens False 是否添加图像特殊 token
Flow Matching
num_steps 10 推理去噪步数
噪声分布 N(0, 1) 高斯噪声
时间步分布 Beta(1.5, 1.0) * 0.999 + 0.001 偏向 t 接近 1
min_period 4e-3 时间步正弦编码最小周期
max_period 4.0 时间步正弦编码最大周期
训练设置
freeze_vision_encoder True 冻结 SigLIP 视觉编码器
train_expert_only True 仅训练 Action Expert
train_state_proj True 训练状态投影层
optimizer_lr 1e-4 学习率
optimizer_betas (0.9, 0.95) Adam beta 参数
optimizer_weight_decay 1e-10 权重衰减
optimizer_grad_clip_norm 10 梯度裁剪
scheduler_warmup_steps 1,000 学习率预热步数
scheduler_decay_steps 30,000 余弦衰减步数
scheduler_decay_lr 2.5e-6 衰减后最低学习率
推理优化
use_cache True 使用 KV Cache 加速推理
tokenizer_max_length 48 分词器最大长度
prefix_length -1 (不填充) 前缀固定长度(-1 表示不填充)

6. 关键源文件表

组件 类名 文件路径
策略封装 SmolVLAPolicy lerobot/policies/smolvla/modeling_smolvla.py:225
核心模型 VLAFlowMatching lerobot/policies/smolvla/modeling_smolvla.py:530
VLM + Expert 封装 SmolVLMWithExpertModel lerobot/policies/smolvla/smolvlm_with_expert.py:61
模型配置 SmolVLAConfig lerobot/policies/smolvla/configuration_smolvla.py:29
注意力掩码工具 make_att_2d_masks lerobot/policies/smolvla/modeling_smolvla.py:102
正弦位置编码 create_sinusoidal_pos_embedding lerobot/policies/smolvla/modeling_smolvla.py:81
RoPE 实现 apply_rope lerobot/policies/smolvla/smolvlm_with_expert.py:28
图像缩放 resize_with_pad lerobot/policies/smolvla/modeling_smolvla.py:135
向量填充 pad_vector lerobot/policies/smolvla/modeling_smolvla.py:157
RTC 处理器 RTCProcessor lerobot/policies/rtc/modeling_rtc.py