领域分布小模型 v3
- 3,335 万参数
- 30 类
- 129,600 步
从零训练的中文小语言模型:一边猜下一个字,一边给整段文字判领域。
这是一个 3,335 万参数的 decoder-only 语言模型,从随机初始化开始,在 3.56 亿字中文行业语料上训练。它和普通语言模型只差一个出口:读完最后一个字时,从同一份隐状态里再吐出一个 31 维的领域分布。
两个出口一起训练,用的时候只取领域那路。它没有做任何指令微调,也不是聊天模型——你给它一段文字,它只回答「这段字像哪个行业」,以及「其他行业的可能性各有多大」。
能做什么,不能做什么
可以:给几百字以上的中文段落判行业,用来做语料打标、领域配比统计、数据集体检。
不可以:判断二三十字的短句(见下面的长度曲线,30 字只有 44%,接近瞎猜);判断一条文本是否属于多个领域并按真实比例分配(训练目标是「一个类别 + 5% 平滑」,不是真的软标签);英文、代码以外的大段非中文文本。
结构
| 形态 | decoder-only Transformer,手写 PyTorch,不用 transformers 库 |
|---|---|
| 层数 / 宽度 | 8 层 · d=512 · 8 头 · FFN 2048 |
| 位置编码 | RoPE |
| 上下文 | 512 字(字符级,词表 15,341) |
| 两个出口 | 语言模型头(猜下一个字)+ 领域头(31 维 softmax) |
| 池化 | 取最后一个字的隐状态;前文看不到后文,取平均会混进只看过半句的状态 |
| 权重文件 | best.pt · 382 MB · fp32 存档 |
训练数据
语料来自智源 IndustryCorpus2(Apache-2.0),按行业分了子集,文件夹名本身就是标签——所以一条标注都不用手写。
| 来源 | BAAI/IndustryCorpus2,30 个行业子集(金融、法律、医学、体育、代码、航空航天……) |
|---|---|
| 规模 | 316,712 篇 · 356,481,811 字 |
| 切分 | 训练 285,056 篇 / 验证 31,656 篇(按文档切,同一篇的块不会跨到另一侧) |
| 类别 | 30 类有样本;第 31 个「其他」槽永远没有正样本,实际不会被选中 |
训练过程
| 损失 | 猜字交叉熵 + 2.0 × 领域交叉熵(标签平滑 0.95)+ 0.5 × 两块一致性 + 0.1 × 对比 |
|---|---|
| 优化器 | AdamW,β=(0.9, 0.95),weight decay 0.1,梯度裁剪 1.0 |
| 学习率 | 3e-4,余弦衰减,warmup 800 步 |
| 批与长度 | batch 8 · 块长 512,训练中在 256~512 之间随机切换(长度增广) |
| 训练量 | 129,600 步(最佳快照 129,000 步) |
| 硬件 | 单卡 RTX 2080 SUPER 8G,fp16,显存占用 2.99 GB,约 6 小时 |
计划 15 万步,在 12.96 万步手动停止。学习率已降到 1.4e-5,接近收尾,但不是严格跑满的退火。
效果
按输入长度看(同一批验证文档,只截前 N 字,每类 3 篇共 90 篇):
| 输入 30 字 | 44.4% |
|---|---|
| 输入 80 字 | 51.1% |
| 输入 150 字 | 56.7% |
| 输入 300 字 | 72.2% |
| 输入 512 字 | 82.2% |
把每类取到 20 篇(共 600 篇)重测,类均衡召回 85.2%;按自然分布抽 2000 篇验证集是 88.45%。后者偏高是因为大类文档多,而大类恰好更好分。
按类看:航空航天、计算机编程_代码 100%;数学、消防安全、新闻传媒、信息安全 95%。最差的是计算机_通信 50%、其他制造 60%、科技_科学研究 60%、石油化工 60%、电力能源 65%——这五个的边界本身就重叠。
已知限制
- 不会说「不确定」。类目表有 31 格,但第 31 格「其他」一个训练样本都没有,模型学不会输出它。模糊文本只能从 30 个真类里硬选一个,而且常常很有信心——一篇写城市一天生活的散文被判成「住宿_餐饮_酒店」93%,因为文里有菜市场、面馆、奶茶、烤串。修法在数据侧:补 300~500 篇「什么都不专」的文本。
- 短文本不可用。30 字时只有 44%,因为训练时永远见 512 字,短输入属于没见过的形态。把同样的字重复补齐到 512,命中能从 29.2% 提到 62.5%——说明瓶颈主要是长度,不是信息量。
- 置信度会被补齐动作抬高。同一段话补齐后置信从 0.31 涨到 0.74,但它并没有更懂。当权重用时要注意这一点。
- 全角标点压低置信度,但不影响命中率。训练语料的逗号句号全是半角,词表里只有一个中文标点「·」,没有「,」「。」。原样喂入时每个「,」都变成 <unk>。三组控制变量实验里命中率变化在噪声边缘,置信度却稳定低 0.03~0.06——代价是「模型变得没底」,不是「判错」。已由 textproc.py 归一化处理。
- 输出不是真的软标签。目标分布是「真类 0.95 + 其余均摊」,模型学到的形状由平滑决定,不代表真实的领域共存比例。
- 类目重叠。计算机_通信 / 计算机编程 / 人工智能 三者互相抢;时政 / 新闻传媒 难分;科技_科学研究 是个筐。这类错不是分类头不会分,是那几堆向量本来就没分开。
- 没做温度校准,概率当权重用之前最好自己再校一遍。
- 只训过中文,英文和其他语言没有兜底。
机制层面的解释——两个出口、四项损失、梯度为什么等于「预测减目标」、分类头实测只把第二层从 std 0.020 练到 0.303、关键词假说——单独放在 原理 页。
怎么用
仓库里 start_infer.bat 双击起页面,或者命令行:
python infer.py --checkpoint H:/llm-domain-lab/runs/v3_30class/best.pt --text "……"
批处理打标用 tag.py。按块喂的时候记住:块长 512 字,短于 200 字的段落并进相邻段再判。
来源与许可
- 训练数据:BAAI/IndustryCorpus2,Apache-2.0
- 代码与权重:本机实验产物,未发布,未声明对外许可
- 界面字体:Saira,SIL Open Font License 1.1(许可证随字体存放)
- 界面规范:endfield-ui 套件,仅借结构与排版习惯,未使用任何游戏素材