Instructions to use NovaAI6868/layazh-zh with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use NovaAI6868/layazh-zh with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-classification", model="NovaAI6868/layazh-zh")# Load model directly from transformers import AutoModel model = AutoModel.from_pretrained("NovaAI6868/layazh-zh", device_map="auto") - Notebooks
- Google Colab
- Kaggle
layazh — Laya 中文版决策模型
已发布:https://huggingface.co/NovaAI6868/layazh-zh
⚖️ 许可协议(重要)
本模型采用自定义协议,不是开源许可:
个人使用免费 · 商业使用需付费授权
- 个人使用(含研究、学习、非营利、以及年营收 < 1 万元人民币的个人开发者):免费
- 商业使用:需事先取得付费商业授权
- 商业授权联系:
novaweb6868@outlook.com完整条款见本仓库的
LICENSE文件。 提交任何贡献即视为同意该文件第三节的贡献者许可协议(CLA)。
注意:本模型中推理与训练代码源自 Apache-2.0 许可的
convaiinnovations/laya;上述自定义协议
主要约束模型权重。代码部分您仍可按 Apache-2.0 使用。
非自回归的中文 System 1 决策模型。 给它一个 state(中文文本 / 邮件 / 工单 / JSON) 和若干带类型的问题,它在一次前向传播里返回带校准概率的答案。它不生成任何文本, 所以没有东西需要解析,也没有东西可以幻觉。
架构与训练配方对齐 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 包
# 推荐: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_50cubin 的 wheel(可在 sm_52 上执行)。更新的版本不再为这些架构编译内核。本模型就是在 GTX Titan X(sm_52)上用这个组合训练和推理的。另外该架构不支持 bfloat16,代码会自动把 dtype 收敛到 fp16/fp32, 不需要你手动处理。
第 3 步:验证安装
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。
想从源码安装 / 复现训练
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)
用法
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_50SASS (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 选项题的点预测不随输入变化,其"准确率"等于多数类占比; 修正标签极性后恰好落在多数类一侧。证据是它的choiceBrier 高达 0.6191 (本模型 0.5319),且choiceECE 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 的温度:
{"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 选项题过于保守)。 因此本模型不做限幅。若你通过上游
layaSDK 加载本 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
Model tree for NovaAI6868/layazh-zh
Base model
hfl/chinese-roberta-wwm-ext-large