File size: 20,949 Bytes
f69ec12
 
 
783b282
f69ec12
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1452372
 
f69ec12
 
 
 
 
 
1452372
f69ec12
 
 
783b282
f69ec12
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
769ee58
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f69ec12
 
 
 
 
 
 
 
 
 
1452372
 
783b282
 
 
 
 
 
1452372
783b282
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1452372
783b282
 
 
 
 
 
 
 
 
 
 
 
1452372
783b282
 
 
1452372
 
783b282
 
 
 
 
 
 
 
 
 
 
1452372
f69ec12
 
 
 
 
1452372
 
 
f69ec12
 
1452372
 
f69ec12
1452372
f69ec12
1452372
 
 
f69ec12
1452372
f69ec12
1452372
 
f69ec12
1452372
f69ec12
1452372
f69ec12
 
 
 
1452372
 
 
 
 
f69ec12
 
1452372
 
 
 
f69ec12
 
1452372
 
 
 
 
f69ec12
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
769ee58
 
 
 
 
 
 
 
 
 
 
 
 
f69ec12
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
---
license: other
license_name: layazh-custom-license
license_link: https://huggingface.co/NovaAI6868/layazh-zh/blob/main/LICENSE
language:
- zh
library_name: transformers
pipeline_tag: text-classification
tags:
- laya
- system-one
- calibrated-decisions
- rlcd
- chinese
- classification
- routing
- scoring
- guardrails
- non-autoregressive
- commercial-license-required
base_model: hfl/chinese-roberta-wwm-ext-large
---

# layazh — Laya 中文版决策模型

**已发布:<https://huggingface.co/NovaAI6868/layazh-zh>**

## ⚖️ 许可协议(重要)

本模型采用**自定义协议**,**不是**开源许可:

> ### 个人使用免费 · 商业使用需付费授权
>
> - **个人使用(含研究、学习、非营利、以及年营收 < 1 万元人民币的个人开发者):免费**
> - **商业使用:需事先取得付费商业授权**
> - **商业授权联系:`novaweb6868@outlook.com`**
>
> 完整条款见本仓库的 [`LICENSE`](https://huggingface.co/NovaAI6868/layazh-zh/blob/main/LICENSE) 文件。
> 提交任何贡献即视为同意该文件第三节的贡献者许可协议(CLA)。

注意:本模型中**推理与训练代码**源自 Apache-2.0 许可的
[`convaiinnovations/laya`](https://huggingface.co/convaiinnovations/laya);上述自定义协议
主要约束**模型权重**。代码部分您仍可按 Apache-2.0 使用。

---

**非自回归的中文 System 1 决策模型。** 给它一个 **state**(中文文本 / 邮件 / 工单 / JSON)
和若干**带类型的问题**,它在**一次前向传播**里返回带校准概率的答案。它**不生成任何文本**,
所以没有东西需要解析,也没有东西可以幻觉。

架构与训练配方对齐 [`convaiinnovations/laya`](https://huggingface.co/convaiinnovations/laya),
编码器换为中文预训练 backbone 并在中文决策数据上微调。

## 与上游 Laya 的关系

| | 上游 `convaiinnovations/laya`(仓库根) | **layazh(本模型)** |
|---|---|---|
| 定位 | 英文 | **中文** |
| 编码器 | `answerdotai/ModernBERT-large`(28 层, 1024 hidden, 395M) | `hfl/chinese-roberta-wwm-ext-large`(24 层, 1024 hidden, 325M) |
| 决策头 | 2 层 TransformerEncoder + marker scorer + act head | **同构**(逐行对齐上游 `DecisionModel`) |
| 总参数 | 421M | **352M** |
| 上下文 | 512 tokens | 512 tokens |
| 选项预算 | `head_max_len = 192` | `head_max_len = 192` |
| 训练配方 | RLCD:log + 0.5·spherical(序数题另加 RPS),REINFORCE + group-mean baseline,多轮 TD(λ=1) | 同配方,实测采用:`rl_weight=8`、`kl_weight=1`、`group=4`、`σ=0.5`、`τ=1.5` |

**训练配方的具体做法(同构部分与实测取值)**

奖励函数两侧**逐字一致**(我方 `layazh.model.proper_reward` 与上游 `laya.common.proper_reward` 对拍
确认默认参数相同):

```
reward = log_score + 0.5 × spherical_score        # 所有题型
       − 1.0 × ranked_probability_score           # 仅序数题 (score)
```

三者都是**严格恰当评分规则**,因此最大化期望奖励的唯一方式就是如实报告概率——
这是校准性的来源,而不是事后补丁。

具体训练设置(我方为实测值;上游的这几项未随 checkpoint 发布,故不臆测):

| 项 | 上游 | 本模型(layazh) |
|---|---|---|
| 策略梯度估计 | REINFORCE + group-mean baseline(GRPO 风格) | 同 |
| 探索噪声 | 对选项 logits 加零均值高斯噪声 | `σ = 0.5`,每组采样 `4` 次取组均值作基线 |
| 采样温度 | 未公开 | `τ = 1.5` |
| 目标函数 | 策略梯度 + 稠密 masked-KL 辅助项 | `8.0 × PG + 1.0 × KL` |
| 多轮对话 | TD(λ = 1.0) 于前缀切片 | 同(代码路径一致) |
| 决策头 lr | 未公开 | `3e-4`(AdamW) |
| 编码器 lr | 未公开 | `2e-5`(分组,`encoder_lr_scale=0.067`) |
| 可训练范围 | 全量微调编码器 | **顶部 8/24 层** + 决策头(12 GB 显存约束) |
| LR 调度 | 未公开 | 线性 warmup 6% + cosine 衰减 |
| 其他 | — | 选项顺序增强开、grad clip 1.0、gradient checkpointing 开、fp32 |

> **诚实说明**:上游只发布了**权重与推理配置**,没有发布 RLCD 的训练超参
> (`rl_agent_config.json` 里只有 `temperature` 与 `updates: 7313 / hours: 1.96` 这类元数据)。
> 因此"同配方"指的是**算法与奖励函数相同**,而上表中的具体数值是本项目自行确定并实测的,
> 不能声称与上游的隐藏设置一致。

序列模板与上游完全一致(已用上游 `laya` 包内的 `render_options` / `QTYPES` 做过程序化对齐校验):

```
[CLS] <qtype> 问题:<中文指令> [SEP] [MASK] 选项0 [MASK] 选项1 ... [SEP] <state> [SEP]
```

每个选项前一个 `[MASK]` marker,决策头读这些 marker 位置的隐状态并在该问题的选项上做 softmax。
`noul` 恒渲染为 `[false, true]`,故 `p[1]` = “该命题成立”的概率。

## 安装

`layazh` 包**已随本仓库提供 wheel**,无需克隆仓库、也无需 Hugging Face token。

### 第 1 步:安装 layazh 包

```bash
# 推荐:uv(也可直接用 pip,把 uv pip 换成 pip 即可)
uv venv --python 3.11 .venv
source .venv/bin/activate        # Windows: .venv\Scripts\activate

# 从本仓库安装(固定到当前 commit,长期可复现;依赖会自动装好)
uv pip install https://huggingface.co/NovaAI6868/layazh-zh/resolve/d55f726a84aa2c17186c49d20fc35cf49c633f0e/layazh-0.1.0-py3-none-any.whl
```

这会把 `torch` / `transformers` / `numpy` / `safetensors` / `huggingface_hub` 一起装上,
之后 `from layazh import ZhAgent` 在任何目录都能直接用,**不需要改 `sys.path`**。

### 第 2 步(**老显卡必读**):换成匹配你 GPU 架构的 PyTorch

上一步装的是默认 PyTorch(面向较新的 CUDA)。如果你的卡比较老,需要替换:

| 你的 GPU | 命令 |
|---|---|
| **Maxwell / Pascal**(GTX 750–1080、Titan X 等,sm_50–sm_61) | `uv pip install torch==2.7.1 --index-url https://download.pytorch.org/whl/cu128` |
| Turing / Volta(RTX 20 系、T4) | `uv pip install torch --index-url https://download.pytorch.org/whl/cu121` |
| Ampere 及更新(RTX 30/40 系、A100) | 默认装的即可,无需替换 |

> **为什么 Maxwell 要锁 2.7.1**:`torch 2.7.1 + cu128` 是最后一个包含 `sm_50` cubin 的
> wheel(可在 sm_52 上执行)。更新的版本不再为这些架构编译内核。本模型就是在
> GTX Titan X(sm_52)上用这个组合训练和推理的。
>
> 另外该架构**不支持 bfloat16**,代码会自动把 dtype 收敛到 fp16/fp32,
> 不需要你手动处理。

### 第 3 步:验证安装

```python
import layazh
print(layazh.__version__)          # -> 0.1.0

from layazh import ZhAgent
agent = ZhAgent.from_pretrained("NovaAI6868/layazh-zh")   # 首次下载约 1.4 GB
print(agent.device)                # -> cuda 或 cpu
```

没有 GPU 也能跑(CPU 推理,只是慢一些)。仅安装 CPU 版 PyTorch 可以用
`--index-url https://download.pytorch.org/whl/cpu`。

### 想从源码安装 / 复现训练

```bash
git clone https://huggingface.co/NovaAI6868/layazh-zh layazh-zh
cd layazh-zh
uv pip install -e .                # 可编辑安装
uv pip install -e ".[train]"       # 训练所需额外依赖(pandas/pyarrow/scipy)
```

## 用法

```python
from layazh import ZhAgent

# 从 Hub 加载(首次自动下载约 1.4 GB)
agent = ZhAgent.from_pretrained("NovaAI6868/layazh-zh")
# 也可从本地目录加载:agent = ZhAgent("checkpoints/layazh-zh")

res = agent.system_one(
    "这家酒店位置很好,出门就是地铁站,前台小姐姐特别热情,还帮我们升级了房型。"
    "房间干净整洁,早餐品种也很丰富,下次来一定还住这里。",
    {
        "sentiment": {
            "type": "choice",
            "instructions": "这条评论的情感倾向是什么?",
            "criteria": {"positive": "正面评价,表达满意或推荐",
                         "negative": "负面评价,表达不满或抱怨"},
        },
        "rating": {
            "type": "score",
            "instructions": "这条评论给出的总体评分是多少?",
            "criteria": ["非常差", "较差", "一般", "不错", "非常好"],
        },
        "recommend": {
            "type": "noul",
            "instructions": "这位用户是否推荐该酒店?",
        },
    },
)

print(res["answers"]["sentiment"]["choice"])      # -> positive
print(res["answers"]["sentiment"]["confidence"])  # -> 1.0
print(res["answers"]["rating"]["score"])          # -> 3.10   (0–4 的期望值)
print(res["answers"]["recommend"]["noul"])        # -> 0.986  P(推荐)
print(res["usage"]["output_tokens"])              # -> 0      不生成任何文本
```

> 上面这些输出是本模型在**实际运行**中产生的(非示意)。

一次调用里的**所有问题在同一次前向传播中批量作答**。

三种 primitive:

- **`choice`** — 给定 `criteria` 键值对,返回 argmax 选项 + 全部选项概率
  + `confidence`(1 − 归一化熵)。
- **`score`** — 有序选项列表,返回期望分值 `Σ i·pᵢ` 与完整分布。
  **序数感知**:训练时额外用 ranked probability score 惩罚累积分布偏差。
- **`noul`** — 二元命题,返回 `P(成立)`。

## 架构

- **编码器**:`hfl/chinese-roberta-wwm-ext-large`,24 层 / hidden 1024 / 16 头 / 21128 词表,
  中文全词掩码(whole word masking)预训练,325M 参数。使用 SDPA 注意力。
- **决策头**(从头训练,26.5M 参数):
  - `type_emb(3)` — 题型嵌入(choice / score / noul)
  - 2 层 `nn.TransformerEncoderLayer`(`norm_first=True`, `src_key_padding_mask`)
  - `scorer`:`LayerNorm → Linear(d,d) → GELU → Linear(d,1)`,作用于每个 marker 位置
  - `act_head`:`Linear(d+4, 256) → GELU → Linear(256, n_act)`,输入为 `[CLS]` 池化表示
    加上答案分布的**已 detach** 摘要(top1、top1−top2、归一化熵、选项数/255)
- **单次前向**:一次 `system_one` 调用里所有问题在同一次前向传播中批量作答。

## 训练

### 数据(全部为**人工标注**中文语料,非模型自标注)

| 来源 | 许可 | 产出 | 记录数 |
|---|---|---|---|
| TNews (CLUE) | Apache-2.0 | `choice`(15 类新闻主题) | 18,756 |
| ChnSentiCorp | **research / 仅研究用途** | `choice` + `score` + `noul` | 10,160 |
| yf_dianping | **research / 仅研究用途** | `choice` + `score` + `noul` | 18,836 |
| **合计(train / eval)** | | **99,184 / 6,244 个问题** | 47,752 / 3,048 |

> ⚠️ **上游数据许可提示(请务必阅读)**
>
> 三个语料中,TNews 为 Apache-2.0,可自由使用;而 **ChnSentiCorp 与 yf_dianping 在其
> 原始发布页标注为研究用途(research-only)**,并未提供明确的商业使用授权。
>
> 本模型仓库采用"个人免费 / 商用付费"协议,但**该协议无法覆盖上游数据集的限制**。
> 因此:
>
> - 若您计划**商业使用**本模型,请自行确认 ChnSentiCorp / yf_dianping 的原始许可,
>   或联系我们获取**仅用 Apache-2.0 语料(TNews 等)重训**的版本;
> - 本项目已尽量披露数据来源以便下游合规评估,但不对下游使用场景的合规性作担保
>   (见 `LICENSE` 第五节)。

一条文本扇出成多个 typed question(一条大众点评评论同时给出情感 `choice`、1–5 星序数
`score`、以及“是否推荐”的 `noul`),与 Laya 自己构造 typed-decisions benchmark 的方式一致。
大众点评原始文件按餐厅分组,因此用**蓄水池采样**从 2,979,616 条可用评论中均匀抽样,
而不是截取文件头部(那会严重偏向少数餐厅的客群)。

### 训练配置

决策头随机初始化,与编码器顶部 8 层联合微调:

| 项 | 值 |
|---|---|
| 可训练参数 | 128.3M / 352M(编码器顶部 8/24 层 101.8M + 决策头 26.5M) |
| 决策头 lr | 3e-4 |
| 编码器 lr | 2e-5 |
| LR 调度 | 线性 warmup 6% + cosine 衰减 |
| batch | 4096 padded tokens,≤64 序列 |
| epochs | 3(14,493 步) |
| 梯度裁剪 | 1.0 |
| 选项顺序增强 | 开启(choice/noul 的选项顺序每轮打乱,target 同步重排;`score` 不打乱,因其为序数) |
| 梯度检查点 | 开启(12 GB 显存约束) |
| 混合精度 | **fp32**(本机 sm_52 无原生 bf16) |

训练中每 100 步在一个固定的、跨来源均匀抽样的 400 条探针集上记录真实准确率,
并把探针最优的权重单独存为 `*-best` 快照——因为这比 running-mean loss 可靠得多:
batch 混合了 2 选项与 15 选项的题目,loss 水平主要由构成比例决定。

### 训练过程中测得的关键结论

**学习率与 warmup 是决定性的**(同一份 6000 条数据、同一探针集,唯一变量是 lr/warmup):

| 配置 | 探针准确率轨迹 |
|---|---|
| 编码器 lr 1e-4,**无 warmup** | 0.5113 → 0.3251 → **0.2551**(坍缩) |
| 编码器 lr 2e-5 + warmup 6% + cosine | 0.4199 → 0.5621 → 0.7032 → **0.7404**(持续上升) |

**RLCD 项当前贡献很小。** 日志中策略梯度项 `pg ≈ 0.002–0.024`,稠密 masked-KL 项
`kl ≈ 0.5–2.0`。即使 `rl_weight` 已从 1.0 提到 8.0,RLCD 仍只占损失的一小部分,
因此本版主要由有监督 KL 驱动;RLCD 的严格恰当评分规则主要作用于**概率校准**
(见下方温度标定结果),对 argmax 准确率贡献有限。

### 本机硬件与数值选择

训练在本机 **GTX Titan X(Maxwell, compute capability 5.2, 12 GB, CUDA 12.6)** 上完成。
该架构有三个硬性后果,已在代码中显式处理(均为实测,非推测):

- **不支持 bfloat16** → 上游配置里的 `"amp_dtype": "bf16"` 在本机不可用;
  `layazh.config.resolve_amp_dtype` 会把 dtype 收敛到 fp16/fp32,
  绝不在 sm_52 上使用 bf16。
- **无 FlashAttention** → 编码器使用 SDPA(math kernel)。
- **PyTorch 支持止于 2.7.1 + cu128** —— 该 wheel 内含可从 sm_52 执行的 `sm_50` SASS
  (`torch.cuda.get_arch_list()` = `['sm_50','sm_60',...,'sm_120']`)。

实测数值特性(反直觉,故记录):fp16 matmul **3.80 TFLOP/s** 略快于 fp32 **2.94 TFLOP/s**,
因此推理用 fp16 权重是净收益;训练仍用 fp32 以保证稳定性。

## 评测

### 同台对比(1,200 道**完全相同**的中文题目、**修正后的** ground truth)

两个模型回答 byte-identical 的中文问题,走同一套代码路径与指标实现
(`scripts/benchmark_ab.py`):

| 指标 | **layazh-zh** | Laya `multilingual` | 变化 |
|---|---|---|---|
| **总体准确率** | **0.7150** | 0.4783 | **+0.237** |
| `choice` 准确率 | 0.6127 | 0.6039 | +0.009 |
| `score` 准确率 | **0.6854** | **0.1461** | **+0.539** |
| `noul` 准确率 | **0.9638** | 0.6486 | +0.315 |
| Brier(越低越好) | **0.3930** | 0.8040 | −0.411 |
| ECE(越低越好) | 0.2639 | 0.2626 | +0.001 |
| AURC(越低越好) | **0.1127** | 0.4239 | −0.311 |
| 单题延迟 | 67.0 ms | **35.5 ms** | 慢 1.9× |

> **关于 `choice` 的一项必要说明。** 上游在 `choice` 上看似打平(0.6039 vs 0.6127),
> 但这是**巧合**:上游对 2 选项题的点预测不随输入变化,其"准确率"等于多数类占比;
> 修正标签极性后恰好落在多数类一侧。证据是它的 `choice` Brier 高达 **0.6191**
> (本模型 0.5319),且 `choice` ECE 0.1752 是在"几乎恒定输出"下取得的。
> 逐来源看更能说明问题:在 15 类的 TNews 上上游接近随机水平。
>
> 其余三个 primitive 上本模型全面领先,其中 `score` 提升 **+0.539**。

### 全量评测(6,244 个问题,本模型)

| 分组 | n | 准确率 | ECE |
|---|---|---|---|
| **ALL** | 6,244 | **0.6951** | 0.3440 |
| `type:noul` | 1,392 | **0.9375** | 0.2131 |
| `type:score` | 1,804 | **0.6996** | 0.1645 |
| `type:choice` | 3,048 | 0.5817 | 0.5100 |
| `senticorp/choice` | 640 | 0.8688 | 0.8097 |
| `senticorp/score` | 640 | 0.9109 | 0.2334 |
| `senticorp/noul` | 640 | 0.9125 | 0.2588 |
| `dianping/noul` | 752 | 0.9588 | 0.1743 |
| `dianping/choice` | 1,164 | 0.7096 | 0.6000 |
| `dianping/score` | 1,164 | 0.5833 | 0.1266 |
| `tnews/choice`(15 类) | 1,244 | 0.3143 | 0.2715 |

**必须看地板线,否则准确率数字没有意义:**

| | 总体准确率 |
|---|---|
| 随机猜 | 0.2959 |
| 多数类(先验) | 0.4734 |
| Laya `multilingual`(上游实测) | 0.4783 |
| **layazh-zh** | **0.6951** |

### 温度标定

温度按 `(题型, 选项数)` 分桶拟合,**在同一半数据上拟合、在不相交的另一半上报告**。
三种方案在留出半集(3,122 题)上的 ECE 对比:

| 方案 | 留出集 ECE |
|---|---|
| 不标定(恒等) | 0.3512 |
| 每题型一个温度 | 0.2684 |
| **每 (题型, 选项数) 分桶**(最终采用) | **0.2547** |

最终写入本仓库 `rl_agent_config.json` 的温度:

```json
{"choice:11+": 0.466635, "choice:2": 0.253066, "choice:3-5": 0.545042,
 "noul:2": 0.970277, "score:3-5": 1.034508}
```

> **与上游 SDK 的一处已知差异。** 上游 `laya` 包在加载 checkpoint 时会用
> `clamp_temperature` 把温度限制在 **[0.5, 5.0]**,而本模型的 `choice:2` 桶
> 拟合值为 **0.253**(低于下界)。我实测了加这个限幅的影响:
>
> | 温度限幅 | ECE(全部 6,244 题) |
> |---|---|
> | 不限幅(本模型默认) | **0.2498** |
> | `[0.5, 5.0]`(上游 SDK 行为) | 0.2799 |
>
> 限幅会让 ECE 变差,说明该桶确实需要更强的锐化(模型对 2 选项题过于保守)。
> 因此本模型**不做限幅**。若你通过上游 `laya` SDK 加载本 checkpoint,
> 温度会被自动限幅到 0.5,ECE 将为 0.2799 —— 这是可预期的差异,不是 bug。

> 分桶温度是**由留出数据挑选**出来的,不是默认采用上游做法。
> 这一点很重要:同一套分桶在各方案比较中只赢了 0.0137 ECE,
> 如果不做留出对比就无从判断它是否真的更好。
>
> 标定必须拟合在**未经温度缩放的原始 logits** 上,否则拟合会永远收敛到 ~1.0。

### 已知弱点

- **`choice` 是明确弱项(0.5817),15 类 TNews 仅 0.3143。** 15 个选项在 512 token
  预算下每个只剩几个 token,正是上游模型卡承认的"选项数越多每项 token 越少导致准确率骤降"。
  改进方向:调大 `head_max_len`,或改层级式 coarse-to-fine 选择。
- **`choice` 校准最差(ECE 0.5100)**,因为 `choice` 混合了 2/3/15 三种选项数。
- **上下文上限 512 token**(中文约 500 字),超长文档需先切分。
- **延迟慢于上游 1.9×**(67.0 ms vs 35.5 ms):中文 RoBERTa-large(24 层)比
  上游 mmBERT-base 更大,这是精度换速度的取舍。
- **RLCD 贡献有限**:本版准确率主要由有监督 KL 驱动,RLCD 的严格恰当评分规则
  主要体现于校准。
- **训练未跑满计划轮数**(见 `REPORT.md`),是一个接近平台期、而非训练到极限的版本。

## 诚实的边界

以下限制继承自上游 Laya 的 Honest Limits,中文版同样适用,另外加上中文特有的几条:

- **零样本能力弱。** 上游基础 checkpoint 在 typed-decisions benchmark 上仅 0.362
  (随机 0.318、多数类 0.461)。Laya 是**快速专精的底座**,不是开箱即用的决策引擎;
  价值在于在中文数据上定向微调后的表现。
- **`score` 序数题是最弱的 primitive**(上游 SST-5 仅 0.372)。
- **选项数 > 20 时准确率骤降**:选项共享固定的 `head_max_len` 预算,77 个选项时每项只剩
  3–4 个 token。解法是调大 `head_max_len` 或改用层级式 coarse-to-fine 选择。
- **`noul` 可能跟着选项标签走而不是跟着 state 走**(上游 issue #156)。
  若怀疑卡住,改用中性 key 的双选项 `choice`。
- **`action.act_probability` 暂无可用信号**(上游 issue #185)。请用 `confidence` 门控。
- **开箱过度自信**:务必在自己的数据上重新拟合温度。
- **中文上下文只有 512 token。** 中文 BERT 词表基本 1 字 1 token,因此有效正文约 500 字。
  超长中文文档需要先切分或用支持更长上下文的编码器。
- **数据域偏移**:训练语料是新闻 / 酒店评论 / 餐厅点评,不等于你业务里的邮件或工单。
  在你的领域上继续微调仍然必要。

## 引用

- Laya 模型卡与权重:<https://huggingface.co/convaiinnovations/laya>
- Laya 代码:<https://github.com/NandhaKishorM/laya>
- CLUE / TNews:<https://github.com/CLUEbenchmark/CLUE>
- 中文 RoBERTa:<https://github.com/ymcui/Chinese-BERT-wwm>