PR 分析报告: [Rust Frontend] Require ModelConfig.vocab_size to be present
执行摘要
本 PR 强化 Rust 前端词汇量处理,将 ModelConfig::vocab_size 改为必需字段(返回 Result 而非 Option),移除冗余的 max_position_embeddings 和 num_attention_heads 字段及相关验证,简化采样限制中的词汇量边界。变更限于 Rust 前端,与 Python 前端行为对齐,提高了可靠性与可维护性。
功能与动机
PR 描述明确:为了收紧 Rust 前端词汇量处理,使采样验证将模型词汇量视为已解析的模型配置不变量,匹配 Python 前端行为。同时清理无用的字段 max_position_embeddings 和 num_attention_heads,它们曾用于前端推导 max_model_len,但现在引擎返回的值被直接使用。
实现拆解
ModelConfig 结构体清理:从 config.rs 中移除 max_position_embeddings 和 num_attention_heads 字段。
- 强制要求
vocab_size:ModelConfig::vocab_size() 方法返回类型从 Option<u32> 改为 Result<u32>,当字段缺失时返回错误。同时递归检查嵌套 text_config(第二次提交实现)。
- 移除冗余验证:删除
validate_text_config_selection() 及其在 load_model_config() 中的调用,该函数曾检查 num_attention_heads 是否存在。
- 简化
SamplingLimits:在 backend/mod.rs 中,model_vocab_size 从 Option<usize> 改为 usize,移除 logprobs_vocab_size() 和 stop_token_vocab_size() 方法,因为不再需要回退到 tokenizer 词汇量。
- 调整
TextBackend trait:model_vocab_size() 返回 usize,默认实现返回 usize::MAX 以兼容轻量级测试后端。
- 更新
HfTextBackend:构造函数中调用 model_config.vocab_size() 并存储结果,model_vocab_size() 返回该存储值。
- 验证路径直接化:在
token_ids.rs 中,将 limits.logprobs_vocab_size() 和 limits.stop_token_vocab_size() 替换为 limits.model_vocab_size。
- 测试适配:调整
SamplingLimits 构造时移除 Some 包装,删除涉及未知模型词汇量的测试用例(lower_sampling_params_uses_tokenizer_vocab_when_model_vocab_is_unknown 等)。
rust/src/text/src/backend/hf/config.rs
核心变更:ModelConfig 结构体移除字段,vocab_size 改为返回 Result,移除 validate_text_config_selection。
/// Model config representation.
/// Removed max_position_embeddings and num_attention_heads fields.
#[derive(Debug, Default, Deserialize)]
#[serde(default)]
pub struct ModelConfig {
model_type: Option<String>,
vocab_size: Option<u32>,
num_experts: Option<OneOrManyExpertCount>,
moe_num_experts: Option<OneOrManyExpertCount>,
n_routed_experts: Option<OneOrManyExpertCount>,
num_local_experts: Option<OneOrManyExpertCount>,
block_configs: Vec<BlockConfig>,
text_config: Option<Box<ModelConfig>>,
}
impl ModelConfig {
/// Return the effective model vocabulary size.
/// Now returns `Result<u32>` instead of `Option<u32>`.
/// Recursively checks nested text_config.
pub fn vocab_size(&self) -> Result<u32> {
if let Some(vocab_size) = self.vocab_size {
Ok(vocab_size)
} else if let Some(text_config) = self.text_config.as_deref() {
// Recursively lookup nested text_config
text_config.vocab_size()
} else {
Err(Error::Tokenizer(
"the model config does not define `vocab_size`".to_string(),
))
}
}
}
rust/src/text/src/backend/mod.rs
定义了 SamplingLimits 和 TextBackend trait,核心类型变更。
/// Effective bounds used to validate and lower sampling requests.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SamplingLimits {
pub max_model_len: u32,
pub max_logprobs: i32,
/// Model vocabulary size from the model config, used to bound generated
/// token IDs and logits-domain sampling controls. Now always present.
pub model_vocab_size: usize,
pub tokenizer_vocab_size: usize,
}
impl SamplingLimits {
/// Return the union bound used to validate token-ID prompts.
pub fn prompt_token_vocab_size(&self) -> usize {
self.tokenizer_vocab_size.max(self.model_vocab_size)
}
}
pub trait TextBackend: Send + Sync {
fn tokenizer(&self) -> DynTokenizer;
fn is_moe(&self) -> bool { false }
fn model_id(&self) -> &str;
fn sampling_hints(&self) -> Result<SamplingHints> { Ok(SamplingHints::default()) }
/// Return the model vocabulary size from the model config.
/// The permissive default exists for lightweight test backends.
fn model_vocab_size(&self) -> usize { usize::MAX }
fn tokenizer_vocab_size(&self) -> usize { self.tokenizer().vocab_size() }
}
评论区精华
- 递归查找问题:Chatgpt-codex-connector 指出新
vocab_size() 只检查直接子 text_config,当复合模型嵌套多层时可能失败。第二次提交已实现递归调用,问题已解决。
- 审批:@njhill 批准了本 PR。
风险与影响
- 核心路径变更:
ModelConfig::vocab_size 现在要求必有值,缺少 vocab_size 的模型在 Rust 前端启动时失败,与 Python 前端行为一致。用户需确保模型配置包含 vocab_size。
- 移除
num_attention_heads 验证:之前用于拒绝无效 text_config,现在由 vocab_size 必需性替代,但可能改变某些复合模型的验证行为。
- 默认
model_vocab_size 为 usize::MAX:测试后端使用该默认值,若新增生产后端忘记覆盖,将导致完全宽松的验证。
- 影响范围:仅限于 Rust 前端,Python 前端不受影响。标准 Hugging Face 模型不受影响。
关联脉络
本 PR 是 Rust 前端验证强化栈的一部分:
-
45674 引入 max_logprobs 验证支持
-
45685 将 out-of-vocab 验证下沉到 text 层
- 本 PR 最终要求
ModelConfig.vocab_size 必须存在,完成契约强化
这些 PR 共同完善了 Rust 前端的采样参数验证体系,逐步消除与 Python 前端的行为差异。
参与讨论