损失函数¶
Mint Recursive 内置了监督学习和强化学习的损失函数。通过把名称传给 forward_backward 来选择:
损失如何读取数据¶
每条训练样本都是一个 Datum——一串 token 序列加上损失计算所需的一切。一个 Datum 包含:
model_input—— 模型看到的 token 序列。loss_fn_inputs—— 损失函数逐 token 读取的张量字典(目标、权重、advantage、采样对数概率……)。
设计原则是:损失只读取 Datum 里的内容。 没有 batch 级状态,也没有外部查找,因此每条样本都是自包含的。
SFT 的交叉熵只需要目标和权重:
import mint
from mint import types
datum = types.Datum(
model_input=types.ModelInput.from_ints(input_tokens),
loss_fn_inputs={
"target_tokens": target_tokens, # what to predict at each position
"weights": weights, # 0 on the prompt, 1 on the completion
},
)
future = training_client.forward_backward([datum], loss_fn="cross_entropy")
result = future.result()
print(f"Loss: {result.loss}")
RL 的损失还会带上 rollout 的采样对数概率和逐 token 的 advantage:
rl_datum = types.Datum(
model_input=types.ModelInput.from_ints(tokens),
loss_fn_inputs={
"target_tokens": target_tokens,
"weights": weights,
"logprobs": sampling_logprobs, # recorded by the sampler
"advantages": advantages, # reward signal per token
},
)
future = training_client.forward_backward([rl_datum], loss_fn="importance_sampling")
forward_backward 返回一个 ForwardBackwardOutput;逐 token 的输出落在 result.loss_fn_outputs 里(例如学习器自己的对数概率)。
选择损失函数¶
| 损失函数 | 适用场景 | 核心思想 |
|---|---|---|
cross_entropy |
监督学习 | 最大化目标 token 的对数概率 |
importance_sampling |
RL(策略梯度) | 用 (p/q) 比重加权,修正离策略样本 |
ppo |
RL(截断) | 截断 (p/q) 比重,限制单步更新幅度 |
cispo |
RL(截断系数) | 截断比重,但作为梯度系数施加 |
dro |
RL(离策略) | 对策略散度加二次惩罚 |
forward_backward_custom |
其他 | 在对数概率上写任意损失 |
符号约定¶
在这些页面中:(p_\theta) 是学习器策略,(q) 是采样策略,(A) 是逐 token 的 advantage。我们把完整的 completion 序列记作 (x)。
所有损失都在 token 级别运行。张量形状为 (N,),其中 N 为 model_input.length,可以是 numpy.ndarray 或 torch.Tensor——返回值的类型与传入类型一致。
关于 RL 损失的一般说明:
- 这些公式有意保持通用:数据的生成和 advantage 的计算都在你自己的代码里完成。典型做法是每个 prompt 采样多条 rollout,并对其 advantage 做中心化(GRPO 做法,Shao et al., 2024)。
- 内置的策略梯度目标不单独添加 KL 项(原始 GRPO 的 KL 项已被指出在数学上不自洽,见 Zhang et al., 2025)。如果需要 KL 正则化,把它折进奖励里——这才是数学上正确的做法。
- token 级别的损失在序列上求和。想要别的聚合方式?把它写进 advantage 张量里。