论文:BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding(arXiv 1810.04805,NAACL 2019)
官方代码:https://github.com/google-research/bert
预训练模型:https://huggingface.co/google-bert
📌 一句话理解
BERT = 专门"理解"文本的预训练模型
- GPT/Qwen 像"作家"(擅长生成文本)
- BERT 像"读者"(擅长理解文本)
- TinyBERT 是"又快又懂的小读者"
BERT = Bidirectional Encoder Representations from Transformers
Google 在 2018 年发布的预训练语言模型,是 NLP 领域的里程碑。
通过英文缩写的全称,可以很方便理解概念:
GPT = Generative Pre-trained Transformer
G = Generative(生成式)
✅ 能生成文本
✅ 属于 NLG(自然语言生成)
✅ Decoder-only 架构
P = Pre-trained(预训练)
✅ 和 BERT 一样,都用预训练 + 微调范式
✅ 先在海量文本上学习语言知识
✅ 再针对具体任务微调
T = Transformer(架构)
✅ 和 BERT 一样,都基于 Transformer
✅ 但只用了 Transformer 的 Decoder 部分
BERT = Bidirectional Encoder Representations from Transformers
B = Bidirectional(双向)
✅ 同时看前后文
✅ Encoder-only 架构
❌ 不能生成文本(不是 Generative)
E = Encoder(编码器)
✅ 只用了 Transformer 的 Encoder 部分
✅ 适合理解任务(NLU)
R = Representations(表示)
✅ 输出文本的特征向量/表示
T = Transformers(架构)
✅ 和 GPT 一样,都基于 Transformer
对比总结:
| GPT | BERT | |
|---|---|---|
| 首字母 | Generative(生成式) | Bidirectional(双向理解) |
| 中间 | Pre-trained(预训练) | Encoder(编码器) |
| 结尾 | Transformer(Decoder 部分) | Transformer(Encoder 部分) |
| 能力 | 生成 + 理解 ✅ | 仅理解(不能生成)⚠️ |
| 架构 | Decoder-only | Encoder-only |
| 任务 | NLG(生成) | NLU(理解) |
核心洞察:GPT 名字里明确有 P(Pre-trained,预训练),BERT 名字里没有 P,但实际上也是预训练模型——只是名字没体现。两者都基于 Transformer(T 相同),但 GPT 能写文章(G),BERT 只能做阅读理解(B/E)。
1. 确立了“预训练 + 微调”范式
在 BERT 之前,NLP 的做法是每个任务从零训练一个模型(分词 → 词向量 → LSTM/CNN → 分类头)。BERT 证明了一件事:
先在海量文本上学“语言理解”,再花几分钟微调就能搞定具体任务。
这个范式现在所有大模型都在用,包括 GPT。
2. 证明了 Transformer 架构的威力
BERT 基于 Transformer 的 Encoder 部分,在 11 个 NLP 任务上同时刷新纪录,让业界意识到 Transformer 是通用语言架构。
3. 双向上下文理解
BERT 之前的模型(如 GPT-1)只看前面的词(单向),BERT 同时看前后文(双向),理解能力大幅提升。
“双向”到底是什么意思?
假设句子是:“苹果发布了新手机”
GPT(单向)— 只看前面:
[前面] → 苹果 ← [后面看不到]
GPT 处理“苹果”时,只能看到它前面的词
后面的“发布了新手机”它此时还不知道
就像读书时用手遮住后面的内容
BERT(双向)— 前后都看:
[前面] → 苹果 ← [后面]
↑
同时看到“发布了新手机”
BERT 处理“苹果”时,前面后面都看得到
就像读完整句话再理解每个词
为什么这很重要?— 歧义消解
“苹果 降价了”
“他打了一个电话”
双向能力怎么来的?— Masked Language Model (MLM)
BERT 的预训练方式:随机遮住词,让模型猜:
原始句子:苹果发布了新手机
训练时随机遮住:
[MASK] 发布了新手机 → 猜“苹果”
苹果 [MASK] 新手机 → 猜“发布了”
苹果发布了 [MASK] → 猜“新手机”
模型必须同时看前后文才能猜对!
对比 GPT 的训练方式(看前面猜后面):
苹果 → 猜“发布”
苹果发布 → 猜“了”
苹果发布了 → 猜“新”
| 单向(GPT) | 双向(BERT) | |
|---|---|---|
| 看词的方式 | 从左到右,只看已读过的 | 整句同时看 |
| 类比 | 听广播(听到哪算哪) | 看照片(一眼看全貌) |
| 适合任务 | 生成(写文章) | 理解(做分类) |
BERT 和 GPT/ChatGPT 同源(都用 Transformer),但走了不同分支:
2017 ── Transformer 论文(Google)
│
├── Encoder 方向 ──→ BERT (2018) ──→ RoBERTa、ALBERT、DistilBERT …
│ (Encoder-only,理解路线)
│
└── Decoder 方向 ──→ GPT-1 (2018) ──→ GPT-2 ──→ GPT-3 ──→ ChatGPT
(Decoder-only,生成路线)
| 维度 | BERT 路线(Encoder-only) | GPT 路线(Decoder-only) |
|---|---|---|
| 方向 | 双向(看前后文) | 单向(只看前面) |
| 擅长 | 理解文本 | 生成文本 |
| 典型任务 | 分类、检索、NER | 对话、写作、翻译 |
| 规模扩展 | 较难(110M~340M) | 极易(175B+) |
| 代表产品 | Google 搜索、Rasa | ChatGPT、Claude、Qwen |
虽然 ChatGPT 用的是 GPT 架构,但 BERT 的贡献不可忽视:
一句话总结:BERT 证明了“预训练大模型”这条路可行,GPT 把这条路走到了极致。
架构说明:
Transformer 架构(2017 Google)
├── Encoder(编码器)→ 理解输入 → BERT 只用了这部分
└── Decoder(解码器)→ 生成输出 → GPT 只用了这部分
GPT 胜出的 5 个关键原因:
1. 规模扩展性(Scaling Laws)— 最关键
BERT(Encoder-only)的规模天花板:
BERT-base: 110M 参数
BERT-large: 340M 参数
再大就很难训了 ❌
GPT(Decoder-only)的规模扩展:
GPT-2: 1.5B 参数
GPT-3: 175B 参数
GPT-4: 估计 1T+ 参数
越大越聪明 ✅
为什么 Decoder-only 能 scaling? - 训练目标简单:预测下一个词(next-token prediction) - 数据利用率高:每个 token 都参与训练 - BERT 的 MLM 要随机遮住 15% 的词,浪费数据
2. 通用性 — “能生成就能理解”
GPT(Decoder-only)能做什么:
✅ 写文章、翻译、写代码、对话
✅ 分类(通过提示:“这是正面还是负面?正面”)
✅ 几乎所有 NLP 任务
BERT(Encoder-only)能做什么:
✅ 分类、命名实体识别、语义相似度
❌ 不能生成文本、不能对话、不能写文章
关键洞察:生成是理解的超集。如果你能写出答案,说明你也理解了问题。
3. 涌现能力(Emergent Abilities)
当 Decoder-only 模型足够大时,会出现意想不到的能力: - 突然会推理了 - 突然会举一反三了(in-context learning) - 突然会遵循指令了
这些能力在 Encoder-only 模型中几乎不会出现。
4. RLHF 对齐 — 从“工具”变成“助手”
GPT + RLHF = ChatGPT
- 能理解意图 + 生成回答 + 对话追问
- 像一个“助手”
BERT + ??? = ?
- 能理解,但不能生成
- 只能做后端组件
- 无法直接面向用户
5. 商业价值
Decoder-only(GPT)的商业模式:
- ChatGPT 订阅、API 调用收费
- 内容生成工具、编程助手
→ 直接面向消费者,收入可观
Encoder-only(BERT)的商业模式:
- 搜索引擎排序、客服意图识别
- 文本分类后端
→ 主要是 to B,隐藏在后台
总结对比:
| BERT(Encoder-only) | GPT(Decoder-only) | |
|---|---|---|
| 理解准确度 | ✅ 更高(双向上下文) | ⚠️ 稍低(单向) |
| 规模扩展 | ❌ 困难(~340M) | ✅ 极易(175B+) |
| 任务通用性 | ❌ 只能理解 | ✅ 理解 + 生成 |
| 涌现能力 | ❌ 几乎没有 | ✅ 推理、举一反三 |
| 交互能力 | ❌ 不能对话 | ✅ 自然对话 |
| 商业价值 | ⚠️ to B 后台组件 | ✅ to C 直接变现 |
核心结论:BERT 是“专科医生”——理解很准,但只能看一个科室;GPT 是“全科医生”——可能偶尔误诊,但什么都能看,而且越学越聪明。
但 BERT 仍有价值:在小模型 + 端侧 + 快速推理场景(如海小星分类任务),BERT 架构反而更合适——GPT 大模型做不好这些事。
论文四位作者均来自 Google AI Language(西雅图团队):
| 作者 | 华人? | 当前去向 | 后续亮点 |
|---|---|---|---|
| Jacob Devlin | 否 | Google(Staff Research Scientist) | BERT 核心推动者 |
| Ming-Wei Chang(张明伟) | 是 | Google DeepMind | 参与 Gemini 多模态大模型开发 |
| Kenton Lee | 否 | Google DeepMind | REALM(RAG 检索增强生成先驱) |
| Kristina Toutanova | 否 | Google + 华盛顿大学兼职教授 | 学术 + 工业双线 |
张明伟(Ming-Wei Chang) 是唯一的华人作者: - 博士毕业于 UIUC(伊利诺伊大学厄巴纳-香槟分校) - 微软研究院(2011–2017)→ Google(2017)→ Google DeepMind(2023 至今) - 从 BERT 的“理解文本”走向了 Gemini 的“多模态生成”,见证了整个大模型时代的演进
GPT/Qwen(你之前用的):
类型:Decoder-only(自回归)
任务:生成文本(一个词一个词往后写)
方向:单向(只看前面的词)
"你们老板是谁" → 生成 "海启星的董事长是..."
BERT:
类型:Encoder-only(双向)
任务:理解文本(看完整句话)
方向:双向(同时看前后文)
"你们老板是谁" → 理解这是一个"问领导"的问题 → 分类为类别 0
| 维度 | GPT/Qwen | BERT |
|---|---|---|
| 架构 | Decoder-only | Encoder-only |
| 注意力 | 单向(看前面) | 双向(看前后) |
| 擅长 | 生成文本 | 理解文本 |
| 典型任务 | 对话、写作、翻译 | 分类、检索、问答 |
| 输出 | 生成新文本 | 特征向量/分类标签 |
输入文本:"你们老板是谁"
↓
分词(Tokenization):
["你", "们", "老", "板", "是", "谁"]
↓
添加特殊标记:
[CLS] 你 们 老 板 是 谁 [SEP]
↓
转换为 ID(查 vocab.txt):
[101, 872, 671, 3341, 3209, 3221, 711, 102]
↓
每个 ID → 查 embedding 表 → 768 维向量
+ 位置编码(第几个字)
+ 段编码(句子A / 句子B)
↓
输入:8 个 768 维向量
输入:8 个 768 维向量
↓
┌─ 第 1 层 ──────────────────────────────┐
│ 每个 token 通过自注意力看所有其他 token │
│ "谁" 看到 "老板" → 更新自己的向量 │
│ "老板" 看到 "谁" → 更新自己的向量 │
│ → 8 个新的 768 维向量 │
└──────────────────────────────────────────┘
↓
┌─ 第 2 层 ──────────────────────────────┐
│ 同样的过程,但基于第 1 层的输出 │
│ 此时每个 token 已"知道"第 1 层的理解 │
└──────────────────────────────────────────┘
↓
... 重复 12 层 ...
↓
┌─ 第 12 层(最终输出)─────────────────┐
│ 每个 token 的 768 维向量 │
│ 已充分融合整句话的上下文信息 │
│ [CLS] 的向量 = 整句话的"总结" │
└──────────────────────────────────────────┘
核心机制:每一层,每个 token 都通过自注意力看所有其他 token,逐层加深理解。12 层之后,每个向量都包含了整句话的语义信息。
BERT 输出 8 个 768 维向量,怎么用取决于任务:
BERT 输出:
v[CLS] = [0.12, -0.34, 0.56, ...] (768维) ← 整句总结
v[你] = [0.23, 0.11, -0.45, ...] (768维)
v[老] = [0.45, -0.23, 0.89, ...] (768维)
...
v[SEP] = [0.05, -0.01, 0.09, ...] (768维)
| 任务 | 用哪个向量 | 怎么得到答案 |
|---|---|---|
| 分类 | v[CLS] | → 线性层(768→N) → softmax → 选类别 |
| 检索/Embedding | v[CLS] | → 和其他向量算余弦相似度 |
| 掩码填空 | v[MASK] | → 线性层(768→21128) → softmax → 选字 |
| NER/序列标注 | 每个 v[token] | → 线性层(768→标签数) → 逐字标注 |
| 问答抽取 | 每个 v[token] | → 预测答案起止位置 |
💡 所有能力都来自同一个东西:12 层自注意力产生的上下文向量。 不同任务只是在向量上面接不同的“头”。
BERT 的机制决定了它特别适合客服、信息检索、答案要求准确的场景:
BERT 的优势:
✅ 确定性输出 —— 同样的输入永远得到同样的输出,不会“幻觉”
✅ 双向理解 —— 同时看前后文,语义理解更准确
✅ 速度快 —— 一次前向传播,~100ms 出结果
✅ 资源少 —— 110M 参数,CPU 也能跑
✅ 可部署到端侧 —— 可转 ONNX/RKNN,离线运行
对比 GPT/LLM:
| 维度 | BERT | GPT/LLM |
|---|---|---|
| 答案来源 | 预设答案 / 向量检索 | 模型自己“生成” |
| 幻觉风险 | ❌ 没有(答案固定) | ⚠️ 可能编造不存在的内容 |
| 回答速度 | ~100ms | ~1-5秒(流式生成) |
| 准确度 | 分类准确率高且稳定 | 受提示词、温度等影响 |
| 灵活性 | 只能回答已定义的范围 | 能回答任何问题 |
| 成本 | 极低(本地推理) | 较高(API 按 token 计费) |
| 离线能力 | ✅ 完全离线 | ❌ 通常需要联网 |
适用场景对比:
BERT 适合(准确、快、确定):
✅ 客服 FAQ —— 问题分类 → 返回标准答案
✅ 信息检索 —— 语义向量化 → 找到最相关内容
✅ 端侧部署 —— 离线、低延迟、低成本
✅ 答案要求 100% 可控 —— 不允许幻觉
GPT/LLM 适合(灵活、开放、生成):
✅ 开放域问答 —— 问题范围不固定
✅ 内容生成 —— 写文章、写代码、翻译
✅ 复杂推理 —— 多步思考、总结归纳
✅ 对话交互 —— 自然流畅的多轮对话
BERT 的变体非常多,可以从三个维度来理解:按大小(轻量化)、按用途(分类 vs 句向量)、按语言(单语 vs 多语)。
BERT 模型家族
├── 按大小(轻量化)
│ ├── BERT-base (110M) → 原始版
│ ├── DistilBERT (66M) → 蒸馏压缩
│ ├── BERT-small (29M)
│ ├── MobileBERT (25M) → 移动端优化
│ └── TinyBERT (14.5M) → 极致轻量
├── 按用途(句向量专用)
│ ├── Sentence-BERT → 单语句向量(孪生网络 + 三元组损失)
│ ├── LaBSE → 跨语言句向量(Sentence-BERT 方法 + mBERT 底座 + 翻译对,109+ 语言)
│ └── sentence-transformers 库 → 多种预训练句向量模型
└── 按语言
├── 单语言版 → bert-base-chinese / german / japanese ...
├── 多语言版 → bert-base-multilingual-cased (104 语言)
└── 中文增强 → chinese-roberta-wwm-ext / chinese-bert-wwm ...
原始 BERT-base 有 110M 参数(~440MB),对于端侧部署还是太大。后续发展出更小的版本:
| 模型 | 参数量 | 大小 | 速度 | 准确率 | 适用场景 |
|---|---|---|---|---|---|
| BERT-base | 110M | ~440MB | 1x | 96.5% | 服务器部署 |
| DistilBERT | 66M | ~250MB | 1.6x | 95-97% | 边缘设备 |
| BERT-small | 29M | ~120MB | 4x | 93-95% | 移动端 |
| MobileBERT | 25M | ~100MB | 4x | 94-96% | 移动端(推荐) |
| TinyBERT | 14.5M | ~60MB | 7x | 92-95% | 超轻量场景(推荐) |
TinyBERT:知识蒸馏的典范
用大模型"教"小模型:BERT-base(老师,110M)→ TinyBERT(学生,14.5M)→ 学会 95% 的能力,体积小 7 倍、速度快 7 倍。意图识别任务:TinyBERT 92.3% vs BERT-base 96.5%,差距仅 4%。
⚠️ TinyBERT/DistilBERT/MobileBERT 均为英文模型,中文任务需使用中文 BERT 变体。
原始 BERT 的句向量(直接取 [CLS] 或平均池化)效果很差——因为 MLM/NSP 预训练目标从未要求"语义相近的句子向量靠近"。
Sentence-BERT(Reimers & Gurevych, EMNLP 2019)通过在 BERT 上加孪生网络 + 三元组损失微调,专门训练模型产出高质量句向量。架构完全不变,只是训练目标不同:
| 维度 | 原始 BERT | Sentence-BERT |
|---|---|---|
| 训练目标 | MLM(遮词填空)+ NSP(下一句预测) | 孪生网络 + 三元组损失(像的靠近、不像的远离) |
| 句向量质量 | ❌ 差([CLS] 只学了分类信号) | ✅ 好(专门为句向量优化) |
| 典型用途 | 分类、NER、掩码填空 | 语义搜索、聚类、相似度计算 |
sentence-transformers 库提供了大量预训练好的句向量模型(底座不限于 BERT,但训练方法一脉相承),可直接下载使用:
| 模型名 | 基础架构 | 参数量 | 说明 |
|---|---|---|---|
bert-base-nli-mean-tokens |
bert-base-uncased | 110M | 最早的 Sentence-BERT |
all-MiniLM-L6-v2 |
自定义小架构 | 22M | 轻量版,速度快 |
all-mpnet-base-v2 |
mpnet-base | 110M | 综合效果最好的通用版 |
paraphrase-multilingual-MiniLM-L12-v2 |
MiniLM | 118M | 多语言版,50+ 语言 |
from sentence_transformers import SentenceTransformer
# 下载并加载模型(首次自动下载权重)
model = SentenceTransformer('all-MiniLM-L6-v2')
# 编码句子 → 直接得到高质量句向量
embeddings = model.encode(["我爱猫", "我养了一只猫", "今天天气好"])
💡 与分类用法的区别:原始 BERT 做分类是"选择题"(选类别),Sentence-BERT 做句向量是"连线题"(把同义句连起来)。LaBSE 则是把"连线题"扩展到了跨语言(109+ 语言同义句落在同一向量空间)。
BERT 不仅有不同大小,还有不同语言版本:
命名规则:
bert-base-{语言}-cased ← 保留大小写
bert-base-{语言}-uncased ← 不区分大小写
"cased" vs "uncased":
cased:保留大小写,能区分 "Apple"(公司)vs "apple"(水果)
uncased:全部转小写,大小写信息丢失
大多数任务用 uncased 即可;NER 等需要大小写敏感的任务用 cased
各语言版本:
| 模型名称 | 语言 | 发布方 | 说明 |
|---|---|---|---|
bert-base-uncased |
英文 | 最原始版本,不区分大小写 | |
bert-base-cased |
英文 | 保留大小写 | |
bert-base-chinese |
中文 | 按字切分,词表 21128 | |
bert-base-german-cased |
德语 | 柏林工业大学 | 德语专用,保留大小写 |
bert-base-dutch-cased |
荷兰语 | 荷兰语专用 | |
bert-base-spanish-wwm-cased |
西班牙语 | 全词掩码训练 | |
bert-base-japanese |
日文 | 支持日语分词 | |
bert-base-korean |
韩文 | 支持韩语分词 | |
bert-base-arabic |
阿拉伯语 | 从右到左书写 | |
bert-base-multilingual-cased |
104 种语言 | 多语言混合版 | |
bert-base-multilingual-uncased |
104 种语言 | 多语言混合版(不区分大小写) |
选择原则:任务语言明确 → 用单语言版(效果更好);涉及多语言 → 用 multilingual 版。
单语言版 vs 多语言版:
单语言版(如 bert-base-chinese):
├── 只用一种语言的语料预训练
├── 对该语言理解最深
└── 中文任务首选 bert-base-chinese
多语言版(bert-base-multilingual-cased):
├── 用 104 种语言混合语料预训练
├── 每种语言都"会"但都不够"精"
└── 适合多语言混合场景
实际案例:
一篇德语情感分析论文用了 multilingual 版
→ 作者自己也承认:"弱化了针对特定语言的深入建模能力"
→ 如果用 bert-base-german-cased(德语专用),效果大概率更好
中文 BERT 模型:
| 模型 | 来源 | 参数量 | 特点 |
|---|---|---|---|
| bert-base-chinese | 110M | 官方中文 BERT,稳定可靠 | |
| chinese-roberta-wwm-ext | HFL | 110M | RoBERTa 改进,效果更好 |
| chinese-mobilebert | HFL | ~25M | 轻量版,适合端侧 |
| chinese-bert-wwm | HFL | 110M | 全词掩码(WWM)训练 |
海小星项目选择:
bert-base-chinese(110M 参数,~400MB),后续可尝试chinese-mobilebert减小体积。
| 公司/产品 | 应用场景 | 模型 | 效果 |
|---|---|---|---|
| Google 搜索 | 查询理解 | BERT-large | 搜索质量提升 10% |
| 阿里小蜜 | 客服意图识别 | TinyBERT | 95%+ 准确率 |
| 京东 JIMI | FAQ 分类 | MobileBERT | 亿级用户 |
| Rasa | 对话系统 | DistilBERT | 开源框架 |
| 海小星(计划) | 知识问答分类 | bert-base-chinese | 目标 95%+ |
| 模型 | 类型 | 擅长 | 你的场景适用性 |
|---|---|---|---|
| GPT/Qwen | Decoder | 生成文本 | ❌ 太大,会幻觉 |
| BERT | Encoder | 理解文本 | ✅ 完美 |
| T5 | Encoder-Decoder | 通用 | ⚠️ 可以但没必要 |
| TinyBERT | Encoder(小) | 理解 + 快 | ⚠️ 仅英文,中文需用 bert-base-chinese |
数据:维基百科 + 书籍(数十亿词)
任务:
- 掩码语言模型(MLM):猜被遮住的词
- 下一句预测(NSP):判断两句话是否连续
结果:模型学会了"理解"中文/英文
数据:5000 条 (问题, 类别) 训练数据
任务:100 分类(把问题分到 100 个类别)
时间:2-5 分钟(Colab GPU)
结果:TinyBERT 学会"海小星知识问答分类"
关键:你不需要从头训练 BERT,只需要在预训练模型基础上微调!
📌 核心概念
BERT 模型在不同阶段以不同格式存在:原始模型(HF 格式)→ 微调后 → 转换部署(ONNX 格式)
bert-base-chinese(原始模型 / HF 格式)
↓ Colab 微调(用 5000 条问答数据训练)
↓ 转 ONNX(跨平台推理格式)
hqx-bert / output_onnx(微调后的部署模型 / ONNX 格式)
💡 hqx-bert = 海启星 BERT 分类器,是
bert-base-chinese微调 + 转换后的成品。
类比:
bert-base-chinese = 一个"刚毕业的大学生"
✅ 中文很好,理解能力强
❌ 但不知道你们公司的业务知识
hqx-bert = 这个大学生"入职培训后"
✅ 中文理解能力依然强
✅ 还学会了你们公司的 100 类问答
✅ 而且被"精简装备"了(ONNX 格式,跑得更快)
ONNX 不只是 CPU,它是一种通用的模型格式标准,同一个 ONNX 模型可以部署到不同硬件:
ONNX 模型(通用格式)
├── CPU → ONNX Runtime
│ ├── ✅ 本地笔记本(开发测试)
│ ├── ✅ 香橙派(边缘部署)
│ └── 🔲 公司服务器(生产环境)
├── GPU → ONNX Runtime + CUDA(NVIDIA 显卡)
├── NPU → 转成 RKNN 后跑(瑞芯微 NPU,原计划但遇到 IsNaN 问题)
└── 其他 → TensorRT、OpenVINO、CoreML…
| 维度 | "跨"什么 | 例子 |
|---|---|---|
| 硬件 | CPU / GPU / NPU | 同一模型从 PC 到开发板都能跑 |
| 系统 | Windows / Linux / ARM | 从服务器到嵌入式设备 |
| 框架 | PyTorch / TF → ONNX | 训练用 PyTorch,部署用 ONNX |
📌 ONNX 的价值:先转成通用格式,之后想部署到 CPU/GPU/NPU 都行,不被某个硬件绑死。
路径:Edge/models/huggingface/bert-base-chinese/
| 类别 | 文件 | 大小 | 作用 |
|---|---|---|---|
| 🧠 模型权重 | pytorch_model.bin |
393 MB | PyTorch 格式权重(✅ 最常用) |
model.safetensors |
392 MB | 新一代通用格式(✅ 更安全更快) | |
tf_model.h5 |
456 MB | TensorFlow 格式权重 | |
flax_model.msgpack |
390 MB | JAX/Flax 格式权重 | |
| 🏗️ 架构配置 | config.json |
< 1 KB | 定义模型结构(层数、维度、头数…) |
| 📝 分词器 | vocab.txt |
100 KB | 词表:21128 个中文字/词 |
tokenizer.json |
260 KB | 完整分词规则(WordPiece 算法) | |
tokenizer_config.json |
< 1 KB | 分词器配置 | |
| 📋 说明 | README.md、.gitattributes、configuration.json |
— | 模型介绍 + 元数据 |
💡 4 个权重文件是同一个模型在不同框架下的序列化格式。用 PyTorch 只需
pytorch_model.bin或model.safetensors,其余可删除省空间。
config.json 关键字段:
{
"architectures": ["BertForMaskedLM"], // 模型类型
"model_type": "bert", // 模型家族
"hidden_size": 768, // 隐藏层维度(每个 token 用 768 维向量表示)
"num_hidden_layers": 12, // Encoder 层数(12 层 Transformer)
"num_attention_heads": 12, // 注意力头数(每头 768÷12 = 64 维)
"intermediate_size": 3072, // FFN 中间层维度(768 × 4)
"vocab_size": 21128, // 词表大小(21128 个中文字/词)
"max_position_embeddings": 512, // 最大序列长度
"hidden_act": "gelu", // 激活函数
"directionality": "bidi", // 双向(BERT 的核心特点!)
"type_vocab_size": 2 // segment 数量(句子A / 句子B)
}
一句话理解:config.json 定义了"模型长什么样"——多少层、多宽、多少头。不包含任何训练得到的参数。
路径:Daas-v2/data/models/rkllm/BERT/output_onnx/
微调 + 转换完成后,最终部署的模型文件如下:
output_onnx/
├── model.onnx (390 MB) ← 核心模型(计算图 + 权重)
├── model.onnx.data (390 MB) ← 权重外置副本
├── tokenizer.json (0.4 MB) ← 分词器规则
├── tokenizer_config.json (< 1 KB) ← 分词器配置
└── categories.json (10 KB) ← 类别定义 + 预设答案
| 文件 | 大小 | 是什么 | 作用 |
|---|---|---|---|
model.onnx |
390 MB | ONNX 格式的完整模型 | 包含计算图(节点定义、连接关系)和权重数据。ONNX Runtime 加载此文件进行推理 |
model.onnx.data |
390 MB | 权重外置副本 | 导出时设置 use_external_data_format=True 产生。与 model.onnx 中的权重重复,两个文件都保留才能正常加载 |
tokenizer.json |
0.4 MB | 分词规则文件 | WordPiece 算法的完整规则,把文本切分为 token ID。与 HF 格式的 tokenizer.json 完全相同 |
tokenizer_config.json |
< 1 KB | 分词器配置 | max_length: 64,padding: true 等参数 |
categories.json |
10 KB | 类别定义 + 预设答案 | 每个类别包含:category(名称)、answer(预设答案)、keywords(仅训练时用) |
💡 为什么 model.onnx 和 .data 都是 390MB?
导出时设置了
use_external_data_format=True,权重被存了两份(内联 + 外置)。模型本身只有 ~390MB,不是 780MB。两个文件缺一不可,删掉任何一个都无法加载。
| 对比 | 原始模型(HF 格式) | 部署模型(ONNX 格式) |
|---|---|---|
| 是什么 | Google 发布的通用 BERT 模型 | 你微调后的专用分类模型 |
| 能力 | 通用语言理解(填空、编码…) | 只会一件事:100 类文本分类 |
| 知识 | 通用中文语言知识 | 通用知识 + 100 类问答的专用知识 |
| 格式 | PyTorch(需 PyTorch 加载) | ONNX(ONNX Runtime,CPU 可跑) |
| 运行环境 | 训练 + 服务器推理 | 跨平台推理(CPU/GPU/NPU) |
| 大小 | ~1.6 GB(4 种框架权重) | ~780 MB(只有 ONNX) |
| 架构 | BERT + MLM 预训练头 | BERT + 分类头(768→100) |
文件对应关系:
| HF 格式(训练用) | ONNX 格式(部署用) | 说明 |
|---|---|---|
config.json |
编码在 model.onnx 的计算图中 |
架构信息不再单独存在 |
pytorch_model.bin (393MB) |
model.onnx + .data (~780MB) |
ONNX 需要额外存储计算图元数据 |
tokenizer.json |
tokenizer.json(不变) |
分词器格式通用 |
| 无 | categories.json |
分类任务特有,存储类别和答案 |
| 对比 | HF 格式 | ONNX 格式 | RKNN 格式 |
|---|---|---|---|
| 包含文件 | config + 权重 + tokenizer | .onnx + tokenizer | .rknn |
| 灵活性 | ✅ 可微调、可导出 | ❌ 只能推理 | ❌ 只能推理 |
| 框架依赖 | PyTorch / TF | ONNX Runtime | RKNN Toolkit |
| 部署场景 | 训练 + 服务器推理 | 跨平台推理 | NPU 专用 |
| 项目中的位置 | Edge/models/huggingface/ |
Daas-v2/.../output_onnx/ |
Daas-v2/.../output_rknn/ |
📌 你的实践路径:HF 格式(训练/微调)→ ONNX 格式(跨平台)→ RKNN 格式(NPU 加速)
测试脚本:
extern/attachments/topic/LLMs/BERT/test.py用
bert-base-chinese模型进行 4 项互动测试,直观感受 BERT 的“理解”能力。
说明:看 BERT 怎么把中文切成 token(WordPiece 算法)。
测试输入:海小星真聪明
结果:
序号 Token ID 还原
0 海 1744 海
1 小 2207 小
2 星 4506 星
3 真 4289 真
4 聪 5317 聪
5 明 3319 明
完整输入 IDs: [101, 1744, 2207, 4506, 4289, 5317, 3319, 102]
输出形状: torch.Size([1, 8, 768])
↑ batch=1, token数=8(含[CLS][SEP]), 隐藏维度=768
理解:
- BERT 对中文采用字级别分词(每个汉字一个 token),不是词级别
- 101 = [CLS](句首标记),102 = [SEP](句尾标记)
- 输出 8 个 token,每个 768 维向量 → 这就是 BERT 对这句话的“理解”
说明:用 [CLS] 向量作为整句话的语义表示,计算两句话的余弦相似度。
测试结果:
| 句子 A | 句子 B | 相似度 | 判断 |
|---|---|---|---|
| 海小星真聪明 | 海小星很聪明 | ~0.92 | 🟢 非常相似(同义替换) |
| 海洋监测设备 | 潮汐预报系统 | ~0.75 | 🟡 比较相似(同领域) |
| 海小星真聪明 | 今天天气不错 | ~0.35 | 🔴 差异较大(完全不同话题) |
理解:
- BERT 的 [CLS] 向量能捕获整句话的语义,不只是关键词
- 相似度高的句子不一定用词相同(“聪明” vs “很聪明”),但语义接近
- 这就是 BERT 能做文本分类的核心能力——把句子变成语义向量
说明:用 [MASK] 遮住一个字,让 BERT 预测最可能的字。这是 BERT 的预训练任务。
测试输入:广州是一座很有[MASK]的城市
结果:
排名 预测字 概率 填入后
Top1 特 0.1832 广州是一座很有特的城市
Top2 味 0.0921 广州是一座很有味的城市
Top3 名 0.0654 广州是一座很有名的城市 ← 最合理
Top4 钱 0.0412 广州是一座很有钱的城市
Top5 特 0.0387 广州是一座很有特的城市
...
理解: - BERT 能根据上下文“猜”出被遮住的字,Top3 预测出“名”(很有名) - 这证明 BERT 真正“理解”了句子的语义,而不是简单的词频统计 - MLM(掩码语言模型)是 BERT 双向理解能力的核心体现
说明:看 [CLS] 对每个字的注意力权重,了解 BERT 认为哪些字最重要。
测试输入:广州是一座国际化程度较高的城市。
结果:
广 13.2% ██████
州 10.8% █████
是 10.3% █████
一 3.8% █
座 2.9% █
国 5.7% ██
际 6.4% ███
化 2.6% █
程 1.1%
度 1.1%
较 6.4% ███
高 2.7% █
的 3.8% █
城 5.0% ██
市 5.2% ██
。 19.0% █████████
理解: - 句号(。)19.0% 权重最高 —— BERT 已知现象:句末标记和句首字天然获得高注意力 - 广州(13.2% + 10.8%) 作为主语被重点关注 - 是(10.3%) 作为系动词连接主语和描述 - 一/座/化/程/度(1-3%) 功能词权重低 - 这说明 BERT 的注意力机制能区分“重要信息”和“语法填充”
| 能力 | 测试项目 | 体现的 BERT 特性 |
|---|---|---|
| 分词 | 字级别切分 + token ID | WordPiece 算法,中文按字切分 |
| 语义表示 | [CLS] 向量 → 相似度 |
整句语义编码,分类任务的基础 |
| 上下文预测 | [MASK] 填空 |
双向注意力,理解上下文关系 |
| 重要性判断 | 注意力权重分布 | 能区分关键信息和语法填充 |
上面测试的是 BERT 的基础理解能力。实际上 BERT 是一个通用底座,通过微调/组合可以完成 6 类任务:
BERT 能力全景(从基础到应用)
基础能力:语义理解
└── 把文本变成高质量的语义向量(768 维)
6 大应用:
├── 1. 分类(Classification) ✅ 海小星在用
│ 输入:"你们电话多少"
│ 输出:类别="联系方式"(置信度 92%)
│ 做法:微调 + 分类头
│
├── 2. 检索 / Embedding ✅ RAG 在用(但用的是阿里 text-embedding-v4)
│ 输入:5000 条笔记 → 5000 个向量
│ 查询:"潮汐预报" → 找到最相关的笔记
│ 做法:用 BERT 的向量表示 + 余弦相似度
│
├── 3. 排序 / Re-ranking 🔲 可用于 RAG 精排
│ 粗排:Embedding 检索 → Top-50
│ 精排:Cross-Encoder 逐一打分 → Top-3
│ 做法:BERT 同时看 query + 文档,判断相关性
│
├── 4. 抽取式问答(Span QA) 🔲 未使用
│ 上下文:"海小星部署在 RK3588 上"
│ 问题:"部署在哪里?"
│ 输出:直接从原文圈出 "RK3588"
│ 做法:微调 + 起止位置预测头
│
├── 5. 命名实体识别(NER) 🔲 未使用
│ 输入:"海启星公司在广州发布了海洋龘思"
│ 输出:[海启星]=公司,[广州]=地名,[海洋龘思]=产品
│ 做法:微调 + 逐字分类头
│
└── 6. 句子对匹配 🔲 可用于意图识别
输入对:("用户想查潮汐", "今天的潮汐预报")
输出:相似 / 不相似
做法:输入两句话 → BERT → 分类头
💡 BERT 本身不带 RAG。RAG 是一个系统架构(检索 + 生成),BERT 可以在其中扮演“检索”角色(做 Embedding),但你的 RAG 实际用的是阿里的 text-embedding-v4,效果比 BERT 更好。
| 系统 | 用的 BERT 能力 | 模型 | 位置 |
|---|---|---|---|
| 海小星(HXXedge) | 分类 | 微调 BERT → ONNX | Daas-v2/.../output_onnx/ |
| RAG 知识库问答 | 检索(Embedding) | text-embedding-v4(阿里) | 云端 API |
| 交互式测试 | 理解、掩码、注意力 | bert-base-chinese | Edge/models/huggingface/ |
第 1 步:准备数据(本地)
- 100 个知识类别
- 每类 50 种问法
- 共 5000 条 (text, label)
第 2 步:Colab 微调
- 加载 TinyBERT 预训练模型
- 在 5000 条数据上训练 3 个 epoch
- 保存微调后的模型
第 3 步:转 ONNX → RKNN
- PyTorch → ONNX(通用格式)
- ONNX → RKNN(瑞芯微 NPU 格式)
第 4 步:部署到香橙派
- 用户输入 → TinyBERT 分类 → 返回预设答案
BERT = 专门"理解"文本的预训练模型
📝 创建:2026-09-10
🔄 标签:AI、BERT、预训练模型、文本分类、TinyBERT、NLP