
苦猿的大模型日记 · Day07 · BERT 中文微调实战-帮普通人把AI学进简历系列前言一个反直觉的招聘数据我前两天干了一件事——在 BOSS 直聘上手动数了 100 条AI 算法工程师的 JD。我想搞清楚一个问题国内招聘市场到底更想要会 BERT 的人还是会 GPT 预训练的人LLM 时代按理说 GPT 那一套才是主旋律。结果是——100 条 JD 里提到BERT 微调或会用 BERT/RoBERTa 做下游任务的有 47 条。提到会 GPT 预训练或训练过 LLM的只有 8 条。差了快6 倍。我当时盯着这个数字看了半天突然想明白一件事——LLM 是聚光灯下的叙事BERT 是简历上的门槛。大厂训练大模型的人就那么多但每家做 NLP 落地的公司——做搜索、做推荐、做客服、做风控——都需要会微调 BERT 的工程师。我顺手又翻了下我带的几个学员——简历上写了 BERT 微调项目的面邀率比没写的高 3 倍。写会调用 GPT API的几乎没差异。为啥因为会调 API证明不了工程能力——会调 API 的人太多了。但会微调 BERT证明的是——你会装 CUDA、会用 HuggingFace、会调超参、会避坑。是一整套真本事。所以 Day07 我决定先拐个弯。按 Day06 结尾的预告本来该进GPT 预训练主线。但这个招聘数据告诉我先把 BERT 这一支讲透对读者简历的边际收益更高。而且BERT 对普通人特别友好——不挑硬件单卡 16GB 显存够用CPU 都能跑虽然慢不挑数据千条级别就能微调出可用的模型不挑领域情感、意图、NER、句对、检索都能套门槛低、ROI 高、简历认可度高——这就是为啥 Day07 必须先讲它。而且 Day06 PART 06 我自己埋了个钩子——Encoder 看全句BERT 那一派Decoder 只看前文GPT 那一派——后者赢了。今天就把这半句补完。读完 Day07你能搞懂 BERT 跟 GPT 的本质区别不止 Encoder vs Decoder训练任务也完全不同知道[CLS]/[SEP]/[MASK]这三个特殊 token 各自干嘛理解 BERT 的两个预训练任务MLM完形填空和 NSP下一句预测用 HuggingFacetransformers三行代码加载bert-base-chinese在ChnSentiCorp中文评论数据集上微调 BERT跟 Day05 LSTM(88%) / Day06 mini-Transformer 正面对比PART 01Encoder vs Decoder——Transformer 的两派之争回到 Day06。我们在 PART 06 拆 Transformer 架构时画过一张图——完整的 Transformer 有两部分Encoder 和 Decoder。Encoder每个词同时看到前后文双向Decoder每个词只能看前面单向因为有 Masked Attention那篇论文 *Attention Is All You Need* 当年是用来做翻译的Encoder Decoder 都用上。但后来的人发现——这两半可以单独拎出来用而且各自长出了一派派系用哪半代表模型擅长Encoder 派只用 EncoderBERT / RoBERTa / ALBERT理解——分类、NER、检索Decoder 派只用 DecoderGPT 系列 / Llama / Qwen生成——对话、写代码、写文章Encoder-Decoder两半都用T5 / BART翻译、摘要为啥 Decoder 在生成任务上赢麻了Decoder 的核心动作叫auto-regressive自回归生成——给一段前文 → 预测下一个词 → 把这个词拼回输入 → 再预测下一个 → ……循环GPT 写文章就是这么一个字一个字吐出来的。Masked Attention 让它只能看前面跟边写边读的生成动作天然契合。举个真实生成过程——输入今天天气真好我们去第 1 步生成公园 → 当前序列今天天气真好我们去公园第 2 步生成散步 → 当前序列今天天气真好我们去公园散步第 3 步生成。 → 结束每一步都只能基于已生成的前文看不到未来。这就是 auto-regressive。而 Encoder 的双向机制反而不能用来做生成——你能看到后面那个词还没生成呢逻辑上不成立。所以——生成任务的市场更大对话、写代码、写文案OpenAI 押注 Decoder-onlyGPT 系一路赢到现在。但不代表 Encoder 派死了BERT 在理解型 NLP 任务上至今统治企业落地。举个具体场景——假设你是一家电商的算法工程师每天要给 5000 万条商品评论自动分类正向/负向/吐槽/物流/质量。两条路路线 ALLM每条调一次 GPT-4 API单次 0.01 元 →每天 50 万路线 BBERT微调一次后本地部署单次推理 ≈ 0 →每天 0一个月就是 1500 万 vs 0 的差距。LLM 自己也能干这些但贵。所以——会调 GPT API 不稀奇会微调 BERT 才是真门槛。一句话总结这两派读用 BERT写用 GPT。PART 02BERT 长啥样——三个特殊 token 的玄机派系搞清楚了看 BERT 具体长啥样。第一步是搞懂它的输入格式。BERT 的输入不是直接一串中文而是会在头尾加几个特殊 token——这三个 token 各有玄机。[CLS]每句话开头的摘要员每句话开头必加[CLS]Classification。它不是简单的句首标记——它的最终隐藏状态就是整句话的语义向量。做分类任务时你不取所有词的输出只取[CLS]这一个位置扔给分类头。为啥因为 BERT 在预训练时就被设计成让[CLS]这一位去总结整句。理解这一点你就理解了 BERT 做分类为啥比 LSTM 强——LSTM 是把所有词的隐藏状态池化平均BERT 是专门训练了一位摘要员。[SEP]句子的边界句与句之间加[SEP]Separator告诉模型这是两句话。这个主要用于句对任务——比如判断两句话是否矛盾、问答的问题-答案对。[MASK]预训练时的被盖住的词[MASK]是 BERT 预训练时用的——随机盖住 15% 的词让模型猜。注意——只在预训练阶段出现微调时不会用到。但理解它的作用是搞懂 BERT 怎么学会语言的关键PART 03 展开。一个真实例子from transformers import AutoTokenizer tokenizer AutoTokenizer.from_pretrained(bert-base-chinese) tokens tokenizer(这部电影太好看了) print(tokenizer.convert_ids_to_tokens(tokens[input_ids])) # [[CLS], 这, 部, 电, 影, 太, 好, 看, 了, [SEP]]注意——bert-base-chinese是字级别的每个汉字一个 token不是词级别。字级别 vs Subword——一个反直觉的设计这里有个反直觉点——英文 BERTbert-base-uncased不是字级别而是WordPiece 子词。比如单词 playing英文 BERT 会拆成[play, ##ing]两个 token——既保留了词根语义又能控制词表大小英文 BERT 词表约 30K。而bert-base-chinese为什么走字级别因为中文没有词的明确边界——上海是一个词还是两个字比亚迪是三个字还是一个公司名分词本身就是个 NLP 难题。走字级别绕开了分词争议且中文汉字总数也就 2 万多常用字词表很好控制。这个差异会影响 max_length 的设置——中文128 token ≈128 字够装 90% 评论英文128 token ≈90-100 单词短了点所以别照搬英文教程的 max_length中文按字数推。金句[CLS]是 BERT 给每句话配的摘要员——一个人代表整支队伍。PART 03BERT 是怎么预训练出来的——MLM NSP[MASK]引出一个核心问题——BERT 是怎么学会用[MASK]猜词的答案预训练。BERT 的预训练有两个任务搞懂这两个你就搞懂了 BERT 的内功。任务 1MLMMasked Language Model完形填空MLM 的玩法从一句话里随机盖住 15% 的词让模型根据上下文猜出被盖住的词。比如原句这部电影太好看了MLM 输入这部电影太[MASK]看了模型预测[MASK] 好关键点——模型能同时看到[MASK]前面和后面的词双向。这就是 Encoder 派的核心优势LSTM 只能根据前面猜BERT 能根据前后一起猜。类比一下——MLM 就是给 BERT 做了 100 亿次的完形填空题。做完这 100 亿题BERT 就学会语言了。任务 2NSPNext Sentence Prediction下一句预测NSP 的玩法给模型两句话 A 和 B让它判断B 是不是真的跟在 A 后面。例A今天天气真好B我们去公园散步吧 → 标签是下一句A今天天气真好BPython 是一门编程语言 → 标签不是下一句这个任务让 BERT 学句间关系对问答、句对任务有帮助。但有个反直觉的事实——后来 RoBERTa 论文Facebook2019证明NSP 其实没啥用去掉反而更好。具体怎么个没用法——RoBERTa 做了对照实验保留 NSP和去掉 NSP训了两个一样的模型在 GLUE 基准上对比——去掉 NSP 的版本几乎所有任务都更准。为啥因为 NSP 任务太简单——模型只要看两句话的主题相关性就能猜出答案没真学到句间逻辑反而干扰了 MLM 的学习信号。所以后来主流 BERT 变体RoBERTa / ALBERT / DeBERTa都改了预训练配方但分类头、[CLS]这些下游接口跟 BERT 一致——你今天学的微调代码换模型名就能用。但原始 BERT 就是这么训的我们理解原理即可——不需要纠结 NSP 该不该有。预训练的代价BERT-base 的预训练规模16GB 纯文本BooksCorpus 英文 Wikipedia33 亿词4 张 Cloud TPU v3训了4 天按当前云市场价折算——单次预训练成本 1 万美金起。中文版bert-base-chinese在中文维基百科 百度百科等语料上重新训的规模量级类似。这就是为啥你不能自己预训练 BERT——烧不起那个钱。横向对比一下把这种规模感拉满——训练任务数据量硬件成本Day05 LSTM 微调IMDb 25K 条你的笔记本5 分钟 / 0 元Day06 mini-TransformerIMDb 25K 条你的笔记本8 分钟 / 0 元Day07 BERT微调ChnSentiCorp 7.6K 条你的笔记本10 分钟 / 0 元BERT预训练33 亿词4 张 TPU v31 万美金 4 天GPT-3 预训练5000 亿词上万张 A100460 万美金最底下两行——就是为啥 HF 模型超市存在。别人烧了钱你拿来微调——这就是 2026 年做 NLP 的标准姿势。那你能干啥用别人预训练好的 BERT搬到自己的任务上——这叫微调。这是 Day07 的核心动作。金句BERT 的预训练是别人烧的钱你的活是把它搬到自己的任务上——这叫微调。PART 04HuggingFace transformers 入门——三行代码加载 BERT预训练是别人烧的我们怎么搬答案是HuggingFacetransformers库——NLP 界的模型超市几乎所有公开的预训练模型都在这里。安装pip install transformers datasets国内镜像重要第一次加载bert-base-chinese会下载约400MB 权重文件国内直连 HuggingFace 很慢甚至超时强烈建议设镜像export HF_ENDPOINThttps://hf-mirror.comWindows PowerShell$env:HF_ENDPOINT https://hf-mirror.com三行代码加载from transformers import AutoTokenizer, AutoModelForSequenceClassification tokenizer AutoTokenizer.from_pretrained(bert-base-chinese) model AutoModelForSequenceClassification.from_pretrained( bert-base-chinese, num_labels2 )就这么点。三个对象每个都值得说一下——AutoTokenizer把中文拆成 token 转 IDPART 02 那个[CLS] 这 部 电...就是它干的AutoModelForSequenceClassification直接给你一个带分类头的 BERT——预训练权重已加载好顶上的分类头是随机初始化的num_labels2ChnSentiCorp 是二分类正向/负向所以是 2AutoModelvsAutoModelForSequenceClassification——一个高频踩坑新手常误用AutoModel# 错误写法 from transformers import AutoModel model AutoModel.from_pretrained(bert-base-chinese) # 只到 Encoder没有分类头 output model(input_ids) # output.last_hidden_state 形状 [B, seq_len, 768] # 没法直接拿去分类得自己接一层 LinearAutoModel只加载到 Encoder 部分输出是每个 token 的 768 维向量没有分类头。要分类任务必须用AutoModelForSequenceClassification——它内部已经帮你接好了[CLS] → Linear(768, num_labels)的分类头。加载时那两行 warning——别慌第一次加载你会看到Some weights of the model checkpoint at bert-base-chinese were not used when initializing BertForSequenceClassification: [cls.predictions..., cls.seq_relationship...] - This IS expected if you are initializing BertForSequenceClassification from the checkpoint of a model trained on another task...翻译成人话——预训练时 BERT 有两个头MLM 头和 NSP 头微调时换成分类头所以那两个头的权重没被加载扔了。这是正常行为不是错误。紧接着还有一行Some weights of BertForSequenceClassification were not initialized from the model checkpoint and are newly initialized: [classifier.weight, classifier.bias] - You should probably TRAIN this model on a down-stream task...这就是 PART 03 说的分类头随机初始化——这正是你需要微调的原因。注意一个反差点——Day06 你手写 mini-Transformer 训了 ~89%所有权重从随机初始化开始。今天加载的 BERT预训练权重已就位——它的起点不是 0是已经会中文。顺带提一句 HF 还有个更省事的快捷方式——from transformers import pipeline clf pipeline(sentiment-analysis, modelbert-base-chinese) print(clf(这家酒店真不错)) # [{label: LABEL_1, score: 0.99}]但这是直接用预训练权重 随机头没在你的数据上微调过——准确率不会高。快捷方式适合做 demo正经项目还得走 Trainer 微调——下一节展开。Day06 你从 0 搭 Transformer 学原理今天你从已会语言的 BERT 起步学微调——这就是预训练模型的意义。PART 05实战——bert-base-chinese 微调 ChnSentiCorp模型加载好了开干。数据集简介ChnSentiCorp——中文评论情感二分类数据集。来源酒店、书籍、电脑三个品类的中文评论规模训练集7659条 / 验证集960条 / 测试集1200条标签正向1/ 负向0跟 Day05 的 IMDb同任务不同语言——刚好可以做跨篇对比。加载数据from datasets import load_dataset ds load_dataset(seamew/ChnSentiCorp) print(ds) # DatasetDict({ # train: Dataset({features: [text, label], num_rows: 7659}) # validation: Dataset({..., num_rows: 960}) # test: Dataset({..., num_rows: 1200}) # })看几条样本感受一下数据for i in [0, 100, 5000]: sample ds[train][i] print(flabel{sample[label]} text{sample[text][:60]}) # label1 选择途安的理由。1、总起来说看中途安的外观比较低调... # label1 地理位置非常好就在步行街旁边购物吃饭都很方便... # label0 这破书也能出版错别字一大堆作者是不是没校对...label1是正向label0是负向。正负样本比例约 6:4不算特别不均衡可以不做重采样。tokenize把文字喂给 BERT 之前先转成 ID 序列def tokenize(batch): return tokenizer( batch[text], paddingmax_length, truncationTrue, max_length128, ) ds ds.map(tokenize, batchedTrue)这里有两个踩坑高发点——max_length128中文评论很多 2000 字BERT 最大只支持512不设上限直接 OOM。128 对 ChnSentiCorp 够用了。truncationTrue超过 max_length 自动截断。忘记加这个batch 里长度不齐直接报错。Trainer——HuggingFace 的训练循环跟 Day04/Day05/Day06 我们手写的训练循环不同HuggingFace 提供Trainer封装——一行trainer.train()完成所有训练逻辑。from transformers import TrainingArguments, Trainer import numpy as np from evaluate import load accuracy load(accuracy) def compute_metrics(eval_pred): logits, labels eval_pred preds np.argmax(logits, axis-1) return accuracy.compute(predictionspreds, referenceslabels) args TrainingArguments( output_dir./bert-chnsent, num_train_epochs3, per_device_train_batch_size16, learning_rate2e-5, weight_decay0.01, evaluation_strategyepoch, save_strategyepoch, load_best_model_at_endTrue, metric_for_best_modelaccuracy, ) trainer Trainer( modelmodel, argsargs, train_datasetds[train], eval_datasetds[validation], compute_metricscompute_metrics, ) trainer.train()逐参数解释这些数字是 BERT 微调的事实标准——参数取值为啥num_train_epochs33BERT 微调一般 2-5 epoch多了过拟合per_device_train_batch_size161616GB 显存的极限再大 OOMlearning_rate2e-52e-5BERT 微调标准 lr太大权重打飞weight_decay0.010.01L2 正则防过拟合evaluation_strategyepochepoch每个 epoch 结束跑一次验证load_best_model_at_endTrueTrue训练结束加载验证集最优的 checkpoint不是最后一个compute_metrics的作用——默认 Trainer 只输出 loss不会自动算 accuracy。compute_metrics是一个回调函数每个 epoch 末被调用把模型输出和真实标签传给你你返回什么指标日志里就显示什么。按回车。单卡 5-10 分钟3 个 epoch 跑完。结果验证集准确率典型值在 93-94%。我贴一下我本地一次跑的真实日志数值仅供参考你跑可能上下浮动 1-2 个点Epoch 1: train_loss0.32, eval_accuracy0.912 Epoch 2: train_loss0.14, eval_accuracy0.931 Epoch 3: train_loss0.08, eval_accuracy0.935把这个数字跟前两篇放一起——模型IMDb/ChnSentiCorp 准确率单次训练成本简历可写度Day05 LSTM88%5 分钟会用 RNN 做文本分类Day06 mini-Transformer~89%8 分钟理解 Transformer 架构Day07 BERT93%10 分钟会用预训练模型 BERT 微调准确率涨了 5 个点。但这 5 个点不是BERT 算法更好那么简单——是预训练知识迁移到了下游任务。Day05 的 LSTM 是从 0 学认字。Day06 的 mini-Transformer 也是从 0 学只是架构更好。Day07 的 BERT——带着 33 亿词的语料功底来考试。起点就不一样。金句LSTM 是从 0 学认字BERT 是带着 33 亿词的功底来考试——起点就不一样。PART 06从训练完成到上线——部署 ONNX 加速到这里你已经训出了一个 93% 准确率的 BERT。但面试官不会只问你训出多少准确率——下一句往往是那你这个模型部署过吗推理延迟多少这是简历的第二行门槛——会微调只值一行简历会部署加速值第二行。Step 1先看 PyTorch 原生推理的基线# 加载训好的模型 model AutoModelForSequenceClassification.from_pretrained(./bert-chnsent) model.eval() model.cuda() # 单条推理 inputs tokenizer(这家酒店服务态度真好, return_tensorspt).to(cuda) with torch.no_grad(): logits model(**inputs).logits pred torch.argmax(logits, dim-1).item()测一下单条延迟——典型值 30-50msGPU/ 200-300msCPU。听起来不慢但放到生产场景——API 单次延迟 200msQPS 上限就 5日处理 5000 万条评论 → 需要115 个 GPU 实例并行这就贵了。BERT-base 推理慢的根本原因——PyTorch 模型是动态图每次推理都要翻译一遍算子没有针对推理场景优化。Step 2导出 ONNX——把动态图变成静态计算图ONNXOpen Neural Network Exchange是微软搞的模型中间格式——把 PyTorch 的动态图冻结成静态计算图再做算子融合、常数折叠等优化。导出代码from transformers.convert_graph_to_onnx import convert convert( frameworkpt, model./bert-chnsent, output./bert-chnsent.onnx, opset14, # ONNX 算子集版本14 支持 BERT 全部算子 )或者更可控的写法import torch from transformers import AutoModelForSequenceClassification model AutoModelForSequenceClassification.from_pretrained(./bert-chnsent) model.eval() dummy_input tokenizer(测试样本, return_tensorspt) torch.onnx.export( model, (dummy_input[input_ids], dummy_input[attention_mask], dummy_input[token_type_ids]), ./bert-chnsent.onnx, input_names[input_ids, attention_mask, token_type_ids], output_names[logits], dynamic_axes{ input_ids: {0: batch}, attention_mask: {0: batch}, token_type_ids: {0: batch}, logits: {0: batch}, }, opset_version14, )dynamic_axes关键——让 batch 维度可变否则只能跑 batch1。Step 3用 ONNX Runtime 推理 加速import onnxruntime as ort import numpy as np session ort.InferenceSession( ./bert-chnsent.onnx, providers[CUDAExecutionProvider, CPUExecutionProvider], ) def predict(text): inputs tokenizer(text, return_tensorsnp, paddingmax_length, truncationTrue, max_length128) logits session.run( [logits], { input_ids: inputs[input_ids].astype(np.int64), attention_mask: inputs[attention_mask].astype(np.int64), token_type_ids: inputs[token_type_ids].astype(np.int64), }, )[0] return np.argmax(logits, axis-1)[0]再测延迟——推理方式GPU 延迟CPU 延迟加速比PyTorch 原生30-50ms200-300ms基线ONNX Runtime12-18ms60-90ms2-3 倍单这一招QPS 翻 2-3 倍所需 GPU 数量减半。Step 4进阶量化 INT8如果还想再压一档——动态量化把权重从 FP32 压成 INT8模型体积砍 75%CPU 推理再快 2 倍from onnxruntime.quantization import quantize_dynamic, QuantType quantize_dynamic( ./bert-chnsent.onnx, ./bert-chnsent-int8.onnx, weight_typeQuantType.QInt8, )代价——精度损失 0.5-1 个点93% → 92%。生产部署里这是常见取舍换 75% 的体积和 2 倍的速度掉 1 个点准确率划得来。Step 5包成 FastAPI 服务最后一步——给推理包个 HTTP 接口前端/中间层才能调from fastapi import FastAPI from pydantic import BaseModel app FastAPI() class Request(BaseModel): text: str app.post(/predict) def predict_api(req: Request): label predict(req.text) return {label: int(label), sentiment: 正向 if label 1 else 负向}启动uvicorn server:app --host 0.0.0.0 --port 8000测试curl -X POST http://localhost:8000/predict \ -H Content-Type: application/json \ -d {text: 这家酒店位置好服务也好} # {label: 1, sentiment: 正向}到这一步BERT 才算真正上线——从微调 → ONNX 导出 → 量化 → FastAPI 服务这是一套完整的工业级 NLP 部署链路。简历上能写——基于 BERT 微调实现中文情感分类导出 ONNX INT8 量化CPU 推理延迟从 250ms 优化到 30msFastAPI 部署支持 QPS 50。这一段是 90% 的 BERT 教程不会写的部分——但面试官最爱听。金句微调把模型训出来部署把模型用起来——前者是入门券后者才是分水岭。PART 07踩坑实录 三模型横向对比BERT 微调的坑不少挑 5 个最高频的全部踩过一遍写进简历才踏实。坑 1max_length没设上限 → OOM# 错误写法 tokenizer(batch[text]) # 不截断长文本直接 OOM # 正确写法 tokenizer(batch[text], truncationTrue, max_length128)中文评论最长的有 2000 字BERT 最大支持512——不截断 爆显存。坑 2忘记truncationTrue# 错误写法 tokenizer(batch[text], max_length128) # Warning: token indices sequence length is longer than the specified maximum sequence length光设max_length不够必须配truncationTrue才会真截断。否则 tokenizer 只警告不处理训练时 batch 内长度不齐直接报错。坑 3learning_rate太大 → 权重打飞# 错误写法 TrainingArguments(learning_rate1e-3) # BERT 微调直接发散预训练模型对 lr 极度敏感。从 0 训的模型 lr 可以是1e-3但 BERT 微调标准是2e-5~5e-5——小三个数量级。lr 太大前 10 步 loss 直接 NaN权重被打飞回不来。坑 4num_labels跟数据集标签数不匹配# 错误写法 model AutoModelForSequenceClassification.from_pretrained( bert-base-chinese # 忘记传 num_labels ) # 二分类数据集模型默认 num_labels2 看似没事 # 但如果是 5 分类输出维度对不上运行时崩养成习惯——加载模型时一定显式传num_labelsN别依赖默认值。坑 5分类头是随机初始化的 → 前几步 loss 很高第一次训练时前几个 step 的 loss 可能高到0.7接近随机猜。别慌——加载的预训练权重只到 Encoder 部分顶上的分类头是从 0 随机初始化的需要几个 step 学到合理范围。跑完第一个 epochloss 一般能降到0.2 以下。坑 6ONNX 导出时token_type_ids漏了# 错误写法——只传 input_ids torch.onnx.export( model, dummy_input[input_ids], ./bert.onnx, ... ) # 推理时报错input token_type_ids is missingBERT 的前向传播接受三个输入input_ids/attention_mask/token_type_ids。导出时三个都得作为输入否则 ONNX 模型推理时会缺参数报错。新手最常漏token_type_ids——单句任务里它全 0看着没用但模型签名里有它就得传。坑 7INT8 量化后准确率掉太多# 标准量化 quantize_dynamic(./bert.onnx, ./bert-int8.onnx, weight_typeQuantType.QInt8) # 推理accuracy 从 93% 掉到 88%——多了 5 个点正常 INT8 量化只该掉0.5-1 个点。掉 5 个点说明——数据分布偏移严重训练集和线上数据分布差太大某些层对量化敏感可以用QuantFormat.QOperator 校准数据集做静态量化退路——用 FP16 代替 INT8体积砍半但精度几乎不掉。写完这些坑我又意识到一遍——深度学习的门槛从来不是数学是工程。从 CV 到 NLP从 RNN 到 BERT 部署踩坑的姿势都一样。结尾BERT 派为啥没落但仍值得学Day06 说 Decoder 赢了Day07 又花整篇讲 BERT——是不是矛盾不矛盾。Decoder 赢的是生成BERT 统治的是理解。GPT 系撑起了 LLM 时代的舞台聚光灯BERT/RoBERTa 仍守着企业 NLP 落地的后厨——做搜索排序、做评论筛选、做客服意图识别。LLM 自己也能干这些但贵。每推理一次几分钱对日处理上亿条 query 的公司就是几百万的差距。所以 BERT 没死它只是从舞台中央退到了简历的必填项里。简历视角——你简历上会用 BERT 微调这一行是面试官最认的那一行。但真正拉开差距的是后面那一行——部署 ONNX 加速。因为这一行背后藏着会装环境、会用 HF、会调超参、会导出 ONNX、会量化、会写 API的完整工程能力——会微调的人多会部署的人少。这就是分水岭。Day08 预告BERT 的预训练是别人烧的。那 GPT 的预训练到底怎么烧Day08 我们正式进 LLM 预训练主线——Next-token prediction看前文预测下一个词——GPT 的核心训练目标交叉熵损失怎么算Scaling Law——为啥参数越多越聪明KV Cache——推理加速的关键揭开 GPT 那一套生成式预训练的底层逻辑。Decoder 赢了舞台聚光灯BERT 仍守着企业落地的后厨——前者是时代叙事后者是简历门槛。互动时间你简历上写过 BERT 项目吗面试时被问过最难的 BERT 相关问题是什么评论区告诉我Day08 我会把高频坑写进预训练主线。下一篇预告Day08 | GPT 预训练到底怎么烧钱——Next-token prediction 全解— END —苦猿 · 帮普通人把 AI 学进简历