本节摘要:语言片区的房源按预训练目标分三大户型——编码器系(BERT、RoBERTa)做掩码预测、擅长理解类任务;解码器系(GPT)做下一词预测、擅长生成;编码解码系(T5 类)做序列到序列、擅长翻译与摘要。本节讲清两种预训练目标如何塑造模型能力边界,RoBERTa 的优化故事说明预训练工艺本身也在演化,并用代码演示同一句文本在三类模型里的用法差异。
掩码预测(BERT 系):把句子里一部分词遮住,让模型根据双向上下文猜被遮的词。训练时模型同时看到左右两侧信息,天然适合做理解——分类、实体识别、句对匹配。代价是预训练与生成式使用方式脱节,直接拿来逐词生成不顺手。
下一词预测(GPT 系):只看左侧已生成的词,预测下一个词。这与生成任务的使用方式完全一致,模型顺带学会了长文本的连贯性。代价是每个位置只有单向信息,做精细理解类任务时通常需要微调或提示工程补足。
第三种是序列到序列(T5 类):把翻译、摘要、分类全部统一成"文本进、文本出"的格式,编码器负责读入、解码器负责写出。户型最通用,但参数效率不如前两种专精。
| 户型 | 预训练目标 | 注意力方向 | 擅长 | 微调换头 |
|---|---|---|---|---|
| 编码器 BERT RoBERTa | 掩码预测 | 双向 | 分类 识别 匹配 | 池化后接分类头 |
| 解码器 GPT | 下一词预测 | 单向 | 生成 对话 补全 | 语言模型头或提示模板 |
| 编码解码 T5 | 去噪重构 | 编码双向 解码单向 | 翻译 摘要 统一格式 | 输出端词表投影 |
RoBERTa 与 BERT 架构几乎一致(同户型),但重新审视了预训练工艺(施工方法),带来明显提升:去掉下一句预测任务、动态遮罩替代静态遮码、更大批次与更多数据、更长的训练轮数。发表时在多个理解类基准上超过 BERT 数个百分点。这个故事对选宅者的启示:看房源别只看架构户型,预训练数据量、训练轮数、遮码策略这些"施工工艺"同样决定房子质量——模型卡上这些字段值得读。
# 用分词器观察掩码预测的输入形态 from transformers import BertTokenizer tok = BertTokenizer.from_pretrained("bert-base-chinese") text = "迁移学习是把旧宅改造成新居的方法" enc = tok(text, return_tensors="pt") print(f"词元数: {enc['input_ids'].shape[1]}") # 输出: 词元数: 15 # 含首尾特殊词元 [CLS] 与 [SEP] masked = tok("迁移学习是把旧宅改造成[MASK]的方法", return_tensors="pt") print(f"掩码位置: {(masked['input_ids'][0] == tok.mask_token_id).nonzero().flatten().tolist()}") # 输出: 掩码位置: [11] # BERT 的预训练就是反复做“猜第 11 位是什么词”的练习
拿情感分类这个任务,看三类户型分别怎么住:
import torch import torch.nn as nn # 编码器系:取 [CLS] 词元向量接分类头(第5章工地三的方案) class BertForSentiment(nn.Module): def __init__(self, bert, n_classes=2): super().__init__() self.bert = bert self.dropout = nn.Dropout(0.1) self.head = nn.Linear(768, n_classes) # bert-base 隐层 768 维 def forward(self, input_ids, attention_mask): out = self.bert(input_ids=input_ids, attention_mask=attention_mask) cls = out.last_hidden_state[:, 0] # [CLS] 位置即池化摘要 return self.head(self.dropout(cls)) # 解码器系:不用分类头,把任务写进提示模板,取下一词分布 prompt = "评论:这家旧宅改造队的工艺真扎实。情感倾向:" # 生成式问法——比较候选词“正面/负面”的下一词概率即可分类 # 编码解码系:把分类也写成文本生成 # 输入 “classify: 这家旧宅改造队的工艺真扎实” 目标输出 “正面” print("三类户型住法:编码器取CLS接新头,解码器写模板看下一词,编码解码直接生成标签文本")
三类住法的成本结构不同:编码器系微调参数少、推理快;解码器系可以零微调(纯提示)但精度不稳;编码解码系统一优雅但推理最重。选户型时把"住法成本"算进去,别只看基准分数。
做中文任务时,选宅还要多看两眼:
# 快速检查一个模型的词表对中文的友好度 from transformers import BertTokenizer tok = BertTokenizer.from_pretrained("bert-base-chinese") samples = ["承重墙", "微调", "验收", "镕基"] for w in samples: pieces = tok.tokenize(w) print(f"{w}: 切分为 {pieces},共 {len(pieces)} 片") # 典型输出: # 承重墙: 切分为 ['承', '重', '墙'],共 3 片 # 微调: 切分为 ['微', '调'],共 2 片 # 验收: 切分为 ['验', '收'],共 2 片 # 镕基: 切分为 ['镕', '基'],共 2 片 # 中文词表多为字级切分——序列长度可控,但专业词的整词语义要靠模型自己组合
⚠️ 常见坑:拿英文词表的模型直接微调中文任务。字符切分成超长序列后,位置编码不够、推理变慢、精度受损,三重损失。
💡 关键直觉:选语言模型的第一问不是"哪个最强",而是"我的任务是理解还是生成"。理解走编码器系,生成走解码器系,混合任务看编码解码系——户型对口,事半功倍。