ArxivFlow:每日自动更新最新的大模型、agent等前沿论文
首先感觉Jev就像是个大号的Bert,结合一些强化学习的训练,让模型具备对世界知识的决策能力,并有一定的泛化能力。
以Jev api输出Json为例,实现LLM生成JSON schema,有两种方式: 1、标准自回归解码:逐个token生成
- 速度慢:必须逐token按顺序生成,需次多次顺序前向传播,每新增一个token,延迟就会增加
2、并行约束解码:一次预填充,即:输入「上下文 + JSON schema」,仅一次前向传播,一次性对所有字段打分,由校验后的数值组装出JSON。通俗点的步骤就是如下:
(1)输入 OCR 文档文本context + 预先定义好 JSON StructuredSchema
(2)Jev:
s1. prefill 阶段:`context + schema描述`输入模型,算出 KV 缓存
s2. 将 KV 缓存复制多份,每个 JSON 字段对应一个 batch 条目,输入字段后缀 token
s3. **单次前向传播并行计算全部字段 logits**
s4. 对每个字段,仅取出允许候选 token,softmax 算概率,选最高概率
s5. 代码直接组装输出 JSON,**不依赖模型输出括号、引号**
(3)返回结构化结果,附带各字段置信度、性能指标。
Jev目前尚未开源,以社区https://huggingface.co/harshatheg/Qwen-2.5-1B-RLCD的实验方式看。
概念:
Logits 掩码投影:在拿到完整词表 logits 后,屏蔽掉 schema 不允许的 token,只保留字段指定候选 token 的 logits,再做 softmax。很多约束解码(如 Outlines、Guidance)是直接在完整 logits 上做-inf掩码,把非法 token 置负无穷。
# 取出当前字段候选token对应的logits
scores = [float(field_logits[tid].item()) for tid in cand_tokens]
scores_t = torch.tensor(scores, dtype=torch.float32) / max(temperature, 1e-4)
probs = F.softmax(scores_t, dim=-1)
- 它没有对原始完整logits做原地mask(不把其他token设为
-inf); - 而是直接索引提取候选token的logits,单独开一个小向量,只在候选子集上做softmax。
- 数学上等价于:对其余所有token施加负无穷掩码后再softmax,结果完全一样。
数学等价证明:
两种方式输出的候选token概率完全相同。
与传统Logits掩码投影的细微差别
传统logits掩码投影(Outlines / Guidance)拿到完整词表维度 [V] 的logits张量,把所有不合法token位置的值填充为 -inf,之后再执行softmax运算。 会保留完整词表大小的张量,这套方案更适配单token顺序自回归采样的场景。
代码实现方案不修改完整的原始logits,直接通过索引抽取出候选token对应的logits,单独构造小规模向量,仅在候选子集内部执行softmax。 省去对超大词表张量的修改操作,计算开销更低,专门适配这种多字段同时打分的并行批量场景。
数学上二者输出的候选token概率结果完全等价,只是工程实现路径不同。传统做法是“把其他选项废掉再算概率”;Jev社区实现是“只把要用到的选项拿出来单独算概率”。
结合Jev并行架构理解
Jev的核心不是在生成时对每一步token做掩码; 而是在一次前向拿到所有字段logits之后,每个字段独立做候选子集的logit投影。
- 不同字段候选token集合不一样,没法共用一套全局mask;
- 所以采用「提取候选logits,子集softmax」这种轻量化的候选词投影方案。
总结就是:数学上等价于候选词Logits掩码投影,工程实现上没有原地mask完整词表,而是直接抽取候选token的logits做子集softmax,是并行场景下的变体实现。
参考文献
https://huggingface.co/harshatheg/Qwen-2.5-1B-RLCD/blob/main/core/engine_torch.py