从零构建并训练 BERT 架构大模型实战指南
详细阐述从零构建并训练 BERT 架构大模型的完整流程。内容涵盖使用 Hugging Face tokenizers 库定制 WordPiece 分词器,配置 BertLMHeadModel 模型结构,利用文本语料进行预训练,以及完成后的推理测试。通过完整代码示例展示从环境准备、分词器保存、模型加载到训练参数设置的全过程,深入解析分词步骤、模型配置及训练策略,帮助开发者掌握大模型基础训练的核心技术细节。

详细阐述从零构建并训练 BERT 架构大模型的完整流程。内容涵盖使用 Hugging Face tokenizers 库定制 WordPiece 分词器,配置 BertLMHeadModel 模型结构,利用文本语料进行预训练,以及完成后的推理测试。通过完整代码示例展示从环境准备、分词器保存、模型加载到训练参数设置的全过程,深入解析分词步骤、模型配置及训练策略,帮助开发者掌握大模型基础训练的核心技术细节。

本文旨在详细讲解如何从零开始构建基于 BERT 架构的大语言模型。不同于常见的模型微调(Fine-tuning),本教程涵盖从分词器(Tokenizer)的独立训练到模型架构搭建及预训练的全过程。内容基于 Hugging Face 生态库,适合希望深入理解大模型底层原理的开发者。
在开始之前,请确保已安装 Python 3.8+ 环境,并安装以下核心依赖库:
pip install transformers tokenizers datasets accelerate torch
建议使用 GPU 加速训练,若本地无显卡,可配置 CPU 模式但速度会显著降低。
BERT 模型通常使用 WordPiece 算法进行分词。自定义分词器能更好地适应特定领域的语料分布。
我们需要从 tokenizers 库中获取构建分词器所需的组件,包括 Normalizer、PreTokenizer、Model 和 Decoder。
from tokenizers import Tokenizer, processors
from tokenizers.models import WordPiece
from tokenizers.trainers import WordPieceTrainer
from tokenizers.normalizers import BertNormalizer
from tokenizers.pre_tokenizers import BertPreTokenizer
from tokenizers.decoders import WordPiece as WordPieceDecoder
首先实例化一个空的 WordPiece 模型,并指定未识别词(UNK)的标记。加载待训练的文本文件路径。
tokenizer = Tokenizer(WordPiece(unk_token="[UNK]"))
files = ["./sanguo.txt"] # 替换为你的训练数据路径
BERT 标准做法是将所有字符转换为小写,并去除多余空格。这有助于减少词汇表大小并提高泛化能力。
tokenizer.normalizer = BertNormalizer(lowercase=True)
在正式切分单词前,先对文本进行初步处理。BertPreTokenizer 能够正确处理标点符号与单词之间的边界。
tokenizer.pre_tokenizer = BertPreTokenizer()
定义特殊标记列表,如 [CLS], [SEP], [MASK] 等,这些是 BERT 架构所必需的。设置词表大小(Vocab Size),例如 50000。
special_tokens = ["[UNK]", "[PAD]", "[CLS]", "[SEP]", "[MASK]"]
trainer = WordPieceTrainer(
vocab_size=50000,
show_progress=True,
special_tokens=special_tokens
)
tokenizer.train(files, trainer)
为了符合 BERT 的输入格式,需要配置 TemplateProcessing 来处理单句和双句输入的特殊标记位置。同时设置解码器前缀为 ##,这是 WordPiece 的标准格式。
cls_token_id = tokenizer.token_to_id("[CLS]")
sep_token_id = tokenizer.token_to_id("[SEP]")
tokenizer.post_processor = processors.TemplateProcessing(
single=f"[CLS]:0 $A:0 [SEP]:0",
pair=f"[CLS]:0 $A:0 [SEP]:0 $B:1 [SEP]:1",
special_tokens=[("[CLS]", cls_token_id), ("[SEP]", sep_token_id)],
)
tokenizer.decoder = WordPieceDecoder(prefix="##")
将训练好的分词器保存为 JSON 格式,以便后续加载使用。
tokenizer.save("tokenizer.json")
为了让 Hugging Face 的 transformers 库识别该分词器,需将其包装在 BertTokenizerFast 类中。
from transformers import BertTokenizerFast
wrapped_tokenizer = BertTokenizerFast(tokenizer_object=tokenizer)
wrapped_tokenizer.save_pretrained("./bert")
此时,./bert 目录下将生成 vocab.txt, tokenizer.json, tokenizer_config.json 等文件。
完成分词器后,接下来构建语言模型并进行预训练。
from transformers import (
BertConfig, BertLMHeadModel, BertTokenizer,
LineByLineTextDataset, DataCollatorForLanguageModeling,
Trainer, TrainingArguments
)
import os
os.environ["TOKENIZERS_PARALLELISM"] = "false"
使用上一步保存的分词器路径加载。
tokenizer = BertTokenizer.from_pretrained("./bert")
BERT 本身是 Encoder 架构,若要用于自回归生成任务(类似 GPT),需开启 is_decoder=True 并使用 BertLMHeadModel。
config = BertConfig(
vocab_size=tokenizer.vocab_size,
is_decoder=True,
max_position_embeddings=512
)
model = BertLMHeadModel(config)
使用 LineByLineTextDataset 按行读取文本,并设定块大小(Block Size)。对于长文本,建议根据显存调整此参数。
dataset = LineByLineTextDataset(
tokenizer=tokenizer,
file_path="./sanguo.txt",
block_size=32 # 根据显存情况调整,越大效果越好但越吃资源
)
data_collator = DataCollatorForLanguageModeling(
tokenizer=tokenizer,
mlm=False, # 设为 False 表示自回归训练,True 为掩码语言模型
mlm_probability=0.15
)
配置输出目录、训练轮次、批次大小等关键参数。
training_args = TrainingArguments(
output_dir="./output",
overwrite_output_dir=True,
num_train_epochs=20,
per_device_train_batch_size=16,
save_steps=2000,
save_total_limit=2,
logging_steps=100,
fp16=True # 启用混合精度训练以节省显存
)
trainer = Trainer(
model=model,
args=training_args,
data_collator=data_collator,
train_dataset=dataset
)
trainer.train()
训练完成后,保存模型权重。
model.save_pretrained("./bert")
训练完成后,可以使用 pipeline 快速进行文本生成测试。
from transformers import pipeline, set_seed
generator = pipeline("text-generation", model="./bert")
set_seed(42) # 固定随机种子以保证结果可复现
# 测试示例 1
txt = generator("吕布", max_length=50, do_sample=True)
print(txt)
# 测试示例 2
txt = generator("接着奏乐", max_length=50, do_sample=True)
print(txt)
注意:BERT 架构主要用于编码任务,虽然通过 LM Head 可实现生成,但在长文本连贯性上通常不如专门的 Decoder-only 架构(如 GPT 系列)。在小规模语料下,BERT 可能表现出较好的局部拟合能力。
per_device_train_batch_size 或 block_size。也可尝试梯度累积(Gradient Accumulation)。max_length 不宜设置过大,否则会导致生成质量下降或显存溢出。本文完整展示了从零训练 BERT 架构模型的流程。通过自定义分词器和配置模型参数,开发者可以灵活控制模型的词汇表和结构。尽管 BERT 并非专为生成设计,但掌握其训练逻辑对于理解 Transformer 架构至关重要。在实际生产中,建议结合具体业务场景选择 Encoder、Decoder 或 Encoder-Decoder 架构。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online
基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online
解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online