当前位置: 首页 > news >正文

大模型原理与实践:第三章-预训练语言模型详解_第1部分-Encoder-only(BERT、RoBERTa、ALBERT)

预训练语言模型详解

总目录

  1. 第一章 NLP基础概念完整指南

    1. 第1部分-概念和发展历史
    2. 第2部分-各种任务(实体识别、关系抽取、文本摘要、机器翻译、自动问答)
    3. 第3部分-文本表示(词向量、语言模型、ELMo)
  2. 第二章 Transformer 架构原理

    1. 第1部分-注意力机制
    2. 第2部分Encoder-Decoder架构
    3. 第3部分-完整Transformer模型)
  3. 第三章 预训练语言模型

    1. 第1部分-Encoder-only(BERT、RoBERTa、ALBERT)
    2. 第2部分-Encoder-Decoder-T5
    3. 第3部分-Decoder-Only(GPT、LLama、GLM)
  4. 第四章 大语言模型

    1. 第1部分-待写
  5. 第五章 动手搭建大模型

    1. 第1部分-待写
  6. 第六章 大模型训练实践

    1. 第1部分-待写
  7. 第七章 大模型应用

    1. 第1部分-待写

目录

  1. 引言

  2. Encoder-only 预训练语言模型

    • 2.1 BERT模型
      • 2.1.1 思想沿承
      • 2.1.2 模型架构——Encoder Only
      • 2.1.3 预训练任务——MLM + NSP
      • 2.1.4 下游任务微调
    • 2.2 RoBERTa模型
      • 2.2.1 优化一:去掉NSP预训练任务
      • 2.2.2 优化二:更大规模的预训练数据和预训练步长
      • 2.2.3 优化三:更大的BPE词表
    • 2.3 ALBERT模型
      • 2.3.1 优化一:Embedding参数分解
      • 2.3.2 优化二:跨层参数共享
      • 2.3.3 优化三:SOP预训练任务

引言

在前一章中,我们详细探讨了为自然语言处理(NLP)领域带来革命性变化的注意力机制,以及基于此机制构建的Transformer模型。Transformer的出现标志着NLP模型发展的一个重要里程碑。正如我们所学,Transformer主要由Encoder(编码器)和Decoder(解码器)两部分构成,这两个组件各有独特的结构和输入输出特性。

针对Encoder和Decoder的不同特点,结合ELMo提出的预训练思路,研究者们开始探索对Transformer进行优化的多种方向。例如:

  • Google选择仅使用Encoder层,通过堆叠多层Encoder并提出掩码语言模型(Masked Language Model, MLM)预训练任务,打造了在自然语言理解(Natural Language Understanding, NLU)任务上表现卓越的BERT模型
  • OpenAI则选择了Decoder层,采用传统的语言模型(Language Model, LM)任务,通过不断扩大模型参数和预训练语料规模,开发了在自然语言生成(Natural Language Generation, NLG)任务上优势明显的GPT系列模型,这也成为了当今大型语言模型(LLM)的基础架构
  • 此外,还有同时保留Encoder和Decoder的方案,如Google发布的T5模型,构建了完整的预训练Transformer架构

本章将按照Encoder-Only、Encoder-Decoder、Decoder-Only的顺序,系统介绍Transformer时代的各个主流预训练模型。我们将深入剖析三种核心模型架构、每种架构选择的预训练任务及其独特优势,这些内容也构成了目前所有主流LLM的理论基础。


Encoder-only 预训练语言模型

BERT模型

BERT(Bidirectional Encoder Representations from Transformers,基于Transformer的双向编码器表示)是Google团队于2018年发布的里程碑式预训练语言模型。该模型在论文《BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding》中首次提出,在包括GLUE、MultiNLI等七个自然语言处理评测任务上实现了当时的最优性能(State Of The Art, SOTA)。

自BERT推出以来,"预训练+微调"的范式成为NLP任务的主流方法。BERT不仅自身在不断迭代优化,还催生了MacBERT、BART等一系列基于BERT改进的模型。可以说,BERT是NLP发展的阶段性成果,标志着预训练模型统治地位的确立。直到大型语言模型(LLM)时代的到来,NLP领域的主导地位才从BERT系模型逐渐转移。即使在LLM时代,要深入理解LLM与NLP,BERT仍然是不可绕过的重要一环。

思想沿承

BERT统一了多种核心思想,主要包括:

  1. Transformer架构:如第二章所述,2017年发表的《Attention is All You Need》论文提出了完全基于注意力机制、摒弃RNN和LSTM结构的Transformer模型,带来了全新的模型架构。BERT沿承了Transformer的思想,在其基础上进行优化,通过堆叠Encoder结构并扩大模型参数,打造了在NLU任务上表现卓越的模型架构。
  2. 预训练+微调范式:同样在2018年,ELMo模型的诞生标志着预训练+微调范式的确立。ELMo基于双向LSTM架构,在大规模训练数据上使用语言模型进行预训练,再针对下游任务进行微调,展现出更优越的性能。BERT采用了该范式,并通过调整为Transformer架构、引入更适合文本理解的MLM预训练任务,将预训练-微调范式推向高潮。
模型架构—Encoder Only

在这里插入图片描述

BERT的模型架构由Transformer的Encoder部分堆叠而成。其主要结构包括三个核心组件:

整体架构

在这里插入图片描述

  • Embedding层:将输入的token转换为高维向量表示
  • Encoder块:由N层Encoder Layer堆叠而成
  • Prediction Heads:分类头,用于将隐藏状态映射到任务的输出空间

在这里插入图片描述

BERT有两个标准版本:

  • BERT-base:12层Encoder Layer,768维隐藏层,总参数量110M
  • BERT-large:24层Encoder Layer,1024维隐藏层,总参数量340M

处理流程

# 伪代码示例:BERT的前向传播过程
def bert_forward(text):# 1. 分词和编码input_ids = tokenizer(text)  # 将文本转换为token IDs# 2. Embedding层token_embeddings = embedding_layer(input_ids)  # token嵌入position_embeddings = position_embedding_layer(input_ids)  # 位置编码hidden_states = token_embeddings + position_embeddings# 3. 通过N层Encoder Layerfor encoder_layer in encoder_layers:hidden_states = encoder_layer(hidden_states)# 4. Prediction headslogits = prediction_heads(hidden_states)  # 输出分类概率return logits

Encoder Layer结构
在这里插入图片描述

每一层Encoder Layer包含以下组件:

class EncoderLayer:def forward(self, hidden_states):# 1. 多头自注意力机制attention_output = multi_head_attention(query=hidden_states,key=hidden_states,value=hidden_states)# 2. 残差连接和LayerNormhidden_states = layer_norm(hidden_states + attention_output)# 3. 前馈神经网络 (Intermediate层)intermediate_output = feed_forward(hidden_states)# 4. 再次残差连接和LayerNormhidden_states = layer_norm(hidden_states + intermediate_output)return hidden_states

关键技术细节

  1. 分词方法:BERT采用WordPiece作为分词方法,这是一种基于统计的子词切分算法。其核心思想是将单词拆解为子词单元,例如"playing"可能被切分为[“play”, “##ing”]。
  2. 激活函数:BERT使用GELU(Gaussian Error Linear Unit,高斯误差线性单元)激活函数;

GELU的核心思路是将随机正则的思想引入激活函数,通过输入自身的概率分布来决定是否保留该神经元。

  1. 位置编码:改进版BERT将相对位置编码融合在注意力机制中,将位置编码视为可训练的权重参数。这种方法能够拟合更丰富的相对位置信息,但也增加了模型参数,且无法处理超过训练长度的输入(BERT的最大上下文长度为512个token)。
预训练任务—MLM + NSP

BERT的重大创新在于提出了两个新的预训练任务:

1. 掩码语言模型(Masked Language Model, MLM)

MLM模拟"完形填空"的过程,在文本序列中随机遮蔽部分token,然后要求模型根据未被遮蔽的token预测被遮蔽的token。

示例:

输入:I <MASK> you because you are <MASK>
输出:<MASK> → love; <MASK> → wonderful

MLM的改进策略

为解决预训练和微调不一致的问题,BERT采用了以下策略:

  • 随机选择15%的token进行处理
  • 其中80%被替换为
  • 10%被替换为随机token
  • 10%保持不变
def mask_tokens(tokens, mask_prob=0.15):"""对输入tokens进行掩码处理"""masked_tokens = tokens.copy()labels = tokens.copy()for i in range(len(tokens)):if random.random() < mask_prob:prob = random.random()if prob < 0.8:# 80%的概率替换为[MASK]masked_tokens[i] = '[MASK]'elif prob < 0.9:# 10%的概率替换为随机tokenmasked_tokens[i] = random.choice(vocab)# 10%的概率保持不变else:# 未被选中的token,标签设为-100(不计算损失)labels[i] = -100return masked_tokens, labels

2. 下一句预测(Next Sentence Prediction, NSP)

NSP任务用于训练模型理解句子间的关系,判断两个句子是否为连续的上下文。

示例:

正样本:
Sentence A: I love you.
Sentence B: Because you are wonderful.
标签: 1(连续上下文)负样本:
Sentence A: I love you.
Sentence B: Because today's dinner is so nice.
标签: 0(非连续上下文)

预训练规模

BERT的预训练使用了:

  • 800M的BooksCorpus语料
  • 2500M的英文维基百科语料
  • 总计约3.3B token
  • 90%的数据使用128的上下文长度训练
  • 10%的数据使用512的上下文长度训练
  • Batch size为256,训练1M步(40个Epoch)
  • BERT-base使用16块TPU训练4天
  • BERT-large使用64块TPU训练4天
下游任务微调

BERT确立了预训练-微调的两阶段思想,即在海量无监督语料上预训练获得通用的文本理解能力,再在特定下游任务上进行微调。

关键设计

  1. 特殊token [CLS]:在每个输入序列首部添加[CLS] token,其对应的特征向量代表整个句子的语义表征

  2. 微调策略:

    • 文本分类任务:直接修改prediction_heads的分类头
    • 序列标注任务:集成多层隐含层向量后输出标注结果
    • 文本生成任务:取Encoder输出直接解码
# 微调示例:文本分类任务
class BERTForClassification:def __init__(self, bert_model, num_classes):self.bert = bert_modelself.classifier = nn.Linear(bert_model.hidden_size, num_classes)def forward(self, input_ids, attention_mask):# 获取BERT的输出outputs = self.bert(input_ids, attention_mask=attention_mask)# 取[CLS] token的隐藏状态cls_hidden_state = outputs[0][:, 0, :]# 通过分类器得到logitslogits = self.classifier(cls_hidden_state)return logits

BERT一经提出,直接在11个NLP任务上取得SOTA效果,成为NLU方向当之无愧的霸主。直到LLM时代,BERT仍在许多标注数据丰富的NLU任务上保持最优效果。


RoBERTa模型

RoBERTa(Robustly Optimized BERT Approach)是Facebook于2023年7月发布的BERT优化版本。RoBERTa的核心思想是:BERT使用的13GB预训练数据是否已经让模型充分拟合?如果使用更多预训练语料、优化预训练任务和训练超参数,是否可以进一步提升模型性能?

优化一:去掉NSP预训练任务

有学者质疑NSP任务过于简单,无法显著提升下游任务性能,甚至可能带来负面效果。RoBERTa设置了四组对比实验:

  1. 段落构建的MLM + NSP:BERT原始设置,输入为一对片段
  2. 文档对构建的MLM + NSP:输入为一对句子,通过增大batch保持token数量相同
  3. 跨越文档的MLM:去掉NSP,输入为从一个或多个文档中连续采样的完整句子
  4. 单文档的MLM:去掉NSP,限制输入只能从一个文档中采样

实验结果表明,后两组显著优于前两组,且单文档的MLM在下游任务微调时性能最佳。因此,RoBERTa在预训练中去掉了NSP,只使用MLM任务。

动态遮蔽策略

RoBERTa将Mask操作从数据处理阶段移至训练阶段,实现动态遮蔽,使每个Epoch的训练数据Mask位置都不同。

class DynamicMaskingDataset:"""动态遮蔽数据集"""def __getitem__(self, index):text = self.texts[index]tokens = self.tokenizer(text)# 每次获取样本时动态进行掩码masked_tokens, labels = self.mask_tokens(tokens)return {'input_ids': masked_tokens,'labels': labels}
优化二:更大规模的预训练数据和预训练步长

RoBERTa使用了更大规模的预训练数据:

  • BookCorpus(BERT使用)
  • 英文维基百科(BERT使用)
  • CC-NEWS(CommonCrawl新闻领域英文部分)
  • OPENWEBTEXT(英文网页)
  • STORIES(CommonCrawl故事风格子集)
  • 总计160GB数据,是BERT的10倍

训练策略优化

  1. 更大的Batch Size:从256增加到8K,既提高优化速度,也提升最终性能
  2. 更长的训练步长:训练500K步(约66个Epoch)
  3. 固定序列长度:全部使用512长度训练,不再采用BERT的渐进式策略
# 训练配置对比
bert_config = {'batch_size': 256,'max_length': [128, 512],  # 先用128训练,再用512'training_steps': 1000000,'total_tokens': '3.3B'
}roberta_config = {'batch_size': 8192,'max_length': 512,  # 全程使用512'training_steps': 500000,'total_tokens': '160GB (约50B+)'
}

计算资源:训练一个RoBERTa,Meta使用了1024块V100(32GB显存)训练1天。

优化三:更大的BPE词表

RoBERTa采用BPE(Byte Pair Encoding,字节对编码)作为Tokenizer的编码策略,并将词表大小从BERT的30K扩大到50K。

BPE编码原理

BPE以子词对作为分词单位。例如:

  • “Hello World” → [“Hel”, “lo”, “Wor”, “ld”]
  • 对于中文"我"(UTF-8编码为"E68891")→ [“E68”, “891”]
class BPETokenizer:"""BPE分词器示例"""def __init__(self, vocab_size=50000):self.vocab_size = vocab_sizeself.vocab = {}def train(self, corpus):"""训练BPE词表"""# 1. 初始化:每个字符作为一个tokenvocab = self.get_initial_vocab(corpus)# 2. 迭代合并最频繁的字符对while len(vocab) < self.vocab_size:# 找到最频繁的字符对most_frequent_pair = self.find_most_frequent_pair(corpus, vocab)# 合并该字符对vocab[most_frequent_pair] = len(vocab)# 更新语料corpus = self.merge_pair(corpus, most_frequent_pair)self.vocab = vocab

通过上述三方面优化,RoBERTa成功刷新了多个下游任务的SOTA,证明了更大规模预训练的重要意义,这也为LLM的诞生奠定了基础。


ALBERT模型

ALBERT(A Lite BERT)由Google于2020年提出,从降低模型参数、保持模型能力的角度对BERT进行优化。通过优化模型结构和改进NSP任务,ALBERT以更小的参数量实现了超越BERT的性能。

优化一:Embedding参数分解

BERT的Embedding层参数矩阵维度为V×HV \times H V×H(词表大小 × 隐藏层维度)。对于BERT-large,这相当于30K × 1024 = 30M参数。当隐藏层维度增加到2048时,Embedding参数会膨胀到61M。

ALBERT的解决方案

将Embedding层的输出维度与隐藏层维度解耦,在Embedding层后添加一个线性变换矩阵。

参数量对比:

  • BERT: V×HV \times HV×H
  • ALBERT: V×E+E×HV \times E + E \times HV×E+E×H(当 E≪HE \ll HEH 时,参数量显著减少)

其中:

  • VVV 表示词汇表大小(Vocabulary size)
  • HHH 表示隐藏层维度(Hidden size)
  • EEE 表示Embedding维度(Embedding size)
class FactorizedEmbedding:"""分解的Embedding层"""def __init__(self, vocab_size, embedding_size, hidden_size):# 第一步:从vocab_size映射到较小的embedding_sizeself.word_embeddings = nn.Embedding(vocab_size, embedding_size)# 第二步:从embedding_size映射到hidden_sizeself.projection = nn.Linear(embedding_size, hidden_size)def forward(self, input_ids):# 词嵌入embeddings = self.word_embeddings(input_ids)  # [batch, seq_len, embedding_size]# 投影到隐藏层维度hidden_states = self.projection(embeddings)  # [batch, seq_len, hidden_size]return hidden_states# 参数量计算示例
vocab_size = 30000
hidden_size = 1024
embedding_size = 128# BERT的Embedding参数量
bert_params = vocab_size * hidden_size  # 30,720,000# ALBERT的Embedding参数量
albert_params = vocab_size * embedding_size + embedding_size * hidden_size
# 3,840,000 + 131,072 = 3,971,072print(f"参数减少: {(1 - albert_params/bert_params)*100:.1f}%")  # 减少约87%
优化二:跨层参数共享

ALBERT发现各Encoder层的参数呈现高度一致性,因此提出让所有Encoder层共享参数。

实现方式

class ALBERTEncoder:"""ALBERT的Encoder:所有层共享参数"""def __init__(self, hidden_size, num_layers=24):# 只初始化一个EncoderLayerself.shared_layer = EncoderLayer(hidden_size)self.num_layers = num_layersdef forward(self, hidden_states):# 虽然只有一层参数,但仍进行num_layers次计算for _ in range(self.num_layers):hidden_states = self.shared_layer(hidden_states)return hidden_states

效果对比

模型层数隐藏层维度参数量
BERT-large241024334M
ALBERT-xlarge24204859M

ALBERT-xlarge虽然参数量仅为BERT-large的18%,但效果更优。

局限性:虽然参数量大幅减少,但训练和推理速度并未显著提升,因为仍需进行24次Encoder Layer计算。这也是ALBERT最终未能完全取代BERT的重要原因。

优化三:SOP预训练任务

ALBERT提出了句子顺序预测(Sentence Order Prediction, SOP)任务来替代NSP。

NSP vs SOP

NSP任务:
正样本: [Sent A: "I love you."] [Sent B: "Because you are wonderful."]
负样本: [Sent A: "I love you."] [Sent B: "Today's dinner is nice."]
问题: 负样本来自不同文档,过于简单SOP任务:
正样本: [Sent A: "I love you."] [Sent B: "Because you are wonderful."]
负样本: [Sent A: "Because you are wonderful."] [Sent B: "I love you."]
优势: 模型需要理解句子间的顺序关系,难度更高
def create_sop_training_sample(sentence_a, sentence_b):"""创建SOP训练样本"""if random.random() < 0.5:# 50%概率:正样本(保持原顺序)return {'sentence_a': sentence_a,'sentence_b': sentence_b,'label': 1}else:# 50%概率:负样本(交换顺序)return {'sentence_a': sentence_b,'sentence_b': sentence_a,'label': 0}

实验证明:MLM + SOP > 仅MLM > MLM + NSP,SOP确实能显著提升模型效果。

通过上述三点优化,ALBERT成功以更小的参数实现了更强的性能,其"更宽模型"的思路为后续研究提供了重要参考价值。

http://www.dtcms.com/a/438329.html

相关文章:

  • MySQL 慢查询日志slow query log
  • 刷赞抖音推广网站长沙网站seo分析
  • 怎么做网站界面设计如何推广店铺呢
  • C++笔记(面向对象)六(4+2C++11)个缺省函数详解
  • CTFHub 信息泄露通关笔记7:Git泄露 Log
  • 【Svelte】如何自定义路径别名(alias)?
  • 公司做哪个网站比较好西安外贸网站建设公司
  • DeepSeek-V3.2-Exp + PH8:国产大模型的性价比革命
  • 第二十三讲:特殊类和类型转换
  • 如何区分数学中的定理、引理、命题?
  • 森东网站建设南昌网站排名优化软件
  • 深圳网站建设制作开发公司开发公司app
  • 《强化学习数学原理》学习笔记8——贝尔曼最优公式小结
  • discuz网站开发深圳建设网站首页
  • Linux信号处理的相关数据结构和操作函数
  • 分类信息网站手机企业网站开发
  • 做杂志的网站有哪些织梦网站系统
  • 我的网站百度怎么搜索不到了文山网站建设代理
  • 小程序推广网站免费wordpress模板下载地址
  • 第66篇:AI+交通:智能驾驶、交通流优化与智慧物流
  • 苏州自学网站建设平台做外国美食的视频网站
  • 黄冈app下载推广平台优化视频
  • 学习日记20:GraphGPT
  • 做网站加班多吗蛋糕店网站建设方案
  • 从餐馆迎客看 accept4:更灵活的“接客“高手
  • Metasploit基础(MSF)
  • 浅析物理层过程
  • 总结 IP 协议的相关特性
  • 网球馆自动预约系统的反调试
  • PyQt5 QLineEdit组件详解:单行文本输入控件的完整指南