首页
/ TensorFlow Models BERT Legacy 实现指南:从预训练 Checkpoint 到 GLUE/SQuAD 微调的完整实战

TensorFlow Models BERT Legacy 实现指南:从预训练 Checkpoint 到 GLUE/SQuAD 微调的完整实战

2026-09-05 11:37:27作者:幸俭卉

本文基于仓库中 official/legacy/bert/README.md 的官方文档,系统讲解该目录内 TensorFlow 2.x 版 BERT legacy 实现的完整使用链路:预训练 checkpoint 与 tf.hub 模块的获取与恢复、tf-nightly/TPU 环境搭建、预训练与微调数据生成,以及用 run_classifier.pyrun_squad.py 在 GPU/TPU 上完成 MRPC 句对分类和 SQuAD 1.1 问答微调。全文在继承原文档全部命令与配置的基础上,结合 official/legacy/bert 下的源码补充了关键命令行参数的默认值、取值范围与底层调用逻辑。

1. Legacy 实现定位:与 nlp/modeling 新实现的关系

需要先明确本文代码的版本定位。README 开头即给出弃用警告:该目录中的大部分代码正在被逐步弃用(deprecating),官方建议改用新教程与 nlp/modeling 中的新代码;而该 README 本身对这份 legacy 实现依然正确。

从源码结构看,legacy 目录的 BERT 模型并非独立实现,而是复用了新代码库的 Keras functional 风格网络:bert_models.py 直接 from official.nlp.modeling import modelsfrom official.nlp.modeling import networksbert_models.py#L23-L24),并引入了 official/legacy/albert/configs.py 以兼容 ALBERT 配置。这与 README 中“已切换到使用 Keras functional-style 网络”的说明一致。

README 中列出的预训练 checkpoint 与 hub 模块均由 TF 1.x 官方 BERT 仓库(google-research/bert)的 checkpoint 转换而来,以保证与 BERT 论文(arXiv: 1810.04805)结果一致。使用这份 legacy 代码的典型场景是:需要对齐论文原始实验配置、迁移旧脚本、或复用 TF1 转换出的 checkpoint 命名结构。

2. 预训练模型:Checkpoint 与 tf.hub 模块

2.1 预训练 Checkpoint 清单

Checkpoint 托管在 Google Cloud Storage 的 gs://cloud-tpu-checkpoints/bert/keras_bert 目录下,README 推荐在使用 Cloud GPU/TPU 时直接以 GCS 路径作为 BERT_DIR。完整清单如下(维度记法为 L-层数_H-隐藏维度_A-注意力头数):

模型 规格 参数规模 GCS 相对位置
BERT-Large, Uncased (Whole Word Masking) 24 层, 1024 隐藏, 16 头 340M wwm_uncased_L-24_H-1024_A-16
BERT-Large, Cased (Whole Word Masking) 24 层, 1024 隐藏, 16 头 340M wwm_cased_L-24_H-1024_A-16
BERT-Base, Uncased 12 层, 768 隐藏, 12 头 110M uncased_L-12_H-768_A-12
BERT-Large, Uncased 24 层, 1024 隐藏, 16 头 340M uncased_L-24_H-1024_A-16
BERT-Base, Cased 12 层, 768 隐藏, 12 头 110M cased_L-12_H-768_A-12
BERT-Large, Cased 24 层, 1024 隐藏, 16 头 340M cased_L-24_H-1024_A-16
BERT-Base, Multilingual Cased 104 种语言, 12 层, 768 隐藏, 12 头 110M multi_cased_L-12_H-768_A-12

每个 checkpoint 目录内含 bert_model.ckptbert_config.jsonvocab.txt,后文微调命令中的 --bert_config_file--init_checkpoint--vocab_file 均指向这些文件。

2.2 用 tf.train.Checkpoint 恢复权重

README 给出的恢复方式是 TF2 标准的 tf.train.Checkpoint 机制:

init_checkpoint = 'the pretrained model checkpoint path.'
model = tf.keras.Model()  # BERT 预训练模型作为特征提取器
checkpoint = tf.train.Checkpoint(model=model)
checkpoint.restore(init_checkpoint)

在仓库源码中可以看到训练入口实际采用的写法。run_classifier.pyrun_keras_compile_fit 中恢复 checkpoint 时注册了两个名称(run_classifier.py#L219-L221):

if init_checkpoint:
  checkpoint = tf.train.Checkpoint(model=sub_model, encoder=sub_model)
  checkpoint.read(init_checkpoint).assert_existing_objects_matched()

这里把同一个子模型同时以 modelencoder 两个名字注册进 tf.train.Checkpoint,再用 read + assert_existing_objects_matched 做匹配校验。从源码结构看,这样命名的目的是同时兼容以 model 命名的 checkpoint 和以 encoder 命名的 tf.hub 模块导出,这正是 --init_checkpoint--hub_module_url 可以互换使用的底层原因。

2.3 预训练 tf.hub 模块

SavedModel 格式的 hub 模块覆盖与 checkpoint 相同的模型矩阵,并额外提供中文模型:

Hub 模块 规格 参数规模
BERT-Large, Uncased (WWL) 24 层, 1024 隐藏, 16 头 340M
BERT-Large, Cased (WWL) 24 层, 1024 隐藏, 16 头 340M
BERT-Base, Uncased 12 层, 768 隐藏, 12 头 110M
BERT-Large, Uncased 24 层, 1024 隐藏, 16 头 340M
BERT-Base, Cased 12 层, 768 隐藏, 12 头 110M
BERT-Large, Cased 24 层, 1024 隐藏, 16 头 340M
BERT-Base, Multilingual Cased 104 种语言, 12 层, 768 隐藏, 12 头 110M
BERT-Base, Chinese 简体中文/繁体, 12 层, 768 隐藏, 12 头 110M

在训练脚本中,用 --hub_module_url=<tfhub 模块路径> 替代 --init_checkpoint 即可加载 hub 模块;common_flags.pyhub_module_url 的定义注明“如果指定了该 flag,则不应再使用 init_checkpoint”(common_flags.py#L71-L75),且 hub_module_trainable 默认为 True,即 hub 模块中的 Keras 层默认参与训练(可微调)而非冻结。

3. 环境搭建

README 给出的环境准备步骤如下:

export PYTHONPATH="$PYTHONPATH:/path/to/models"

安装 tf-nightly 获取最新特性:

pip install tf-nightly-gpu

在 TPU 上训练时无需 GPU 支持,需要先用 ctpu 工具创建一台 tf-nightly 版 TPU 实例:

ctpu up -name <instance name> --tf-version="nightly"

然后在 VM 上安装 TF2 的 tf-nightly

pip install tf-nightly

适用前提说明:该目录代码面向 TF 2.x + tf-nightly,README 中 pip install tf-nightly-gpu / pip install tf-nightlyctpu up --tf-version=nightly 组合使用;运行入口脚本依赖 tensorflow_hubbert_models.py 顶层 import tensorflow_hub as hub)。

4. 数据处理

4.1 预训练数据:create_pretraining_data.py

生成预训练数据的脚本没有变化,使用 official/nlp/data/create_pretraining_data.py——该脚本基本源自 BERT 研究仓库,并已适配 TF2 符号与 Python 3。脚本需要输入/输出目录和词表文件,且 max_seq_length 必须与之后运行预训练时指定的序列长度一致。

README 给出的调用示例:

export WORKING_DIR='local disk or cloud location'
export BERT_DIR='local disk or cloud location'
python models/official/nlp/data/create_pretraining_data.py \
  --input_file=$WORKING_DIR/input/input.txt \
  --output_file=$WORKING_DIR/output/tf_examples.tfrecord \
  --vocab_file=$BERT_DIR/wwm_uncased_L-24_H-1024_A-16/vocab.txt \
  --do_lower_case=True \
  --max_seq_length=512 \
  --max_predictions_per_seq=76 \
  --masked_lm_prob=0.15 \
  --random_seed=12345 \
  --dupe_factor=5

各参数含义:input_file 为原始文本([CLS]/[SEP] 分隔语料),output_file 输出 tfrecord 格式样本;do_lower_case 需与所用 checkpoint 的 cased/uncased 属性匹配;max_seq_length=512 为 BERT 标准上下文长度;max_predictions_per_seq=76 对应每序列最多 76 个 masked token;masked_lm_prob=0.15 即 BERT 论文中 15% 词元被遮蔽的比例(其中 80% 替换为 [MASK]、10% 随机词、10% 保持原样);random_seeddupe_factor=5 分别控制随机种子与语料重复采样轮数。

4.2 微调数据:create_finetuning_data.py

微调数据由 official/nlp/data/create_finetuning_data.py 统一生成,产出 tf_record 格式数据集与训练元数据文件(后续训练/评估脚本通过 --input_meta_data_path 读取该元数据)。任务类型由 --fine_tuning_task_type 指定,源码中可选值包括 classificationregressionretrievalsquadtagging

GLUE 分类任务。先下载 GLUE 任务数据并解压到 $GLUE_DIR(GLUE benchmark 官网提供下载脚本),再准备 checkpoint 目录 $BERT_DIR(可以是 GCS 路径)。以 MNLI 为例:

export GLUE_DIR=~/glue
export BERT_DIR=gs://cloud-tpu-checkpoints/bert/keras_bert/uncased_L-24_H-1024_A-16

export TASK_NAME=MNLI
export OUTPUT_DIR=gs://some_bucket/datasets
python official/nlp/data/create_finetuning_data.py \
 --input_data_dir=${GLUE_DIR}/${TASK_NAME}/ \
 --vocab_file=${BERT_DIR}/vocab.txt \
 --train_data_output_path=${OUTPUT_DIR}/${TASK_NAME}_train.tf_record \
 --eval_data_output_path=${OUTPUT_DIR}/${TASK_NAME}_eval.tf_record \
 --meta_data_file_path=${OUTPUT_DIR}/${TASK_NAME}_meta_data \
 --fine_tuning_task_type=classification --max_seq_length=128 \
 --classification_task_name=${TASK_NAME}

其中 --classification_task_name 限定为 GLUE 任务名(如 MNLI);--max_seq_length=128 需小于或等于 checkpoint 预训练长度 512。

SQuAD 任务。所需文件为 train/dev 的 v1.1 与 v2.0 JSON 以及对应版本官方评估脚本(SQuAD 官网与评估脚本均可从 SQuAD 官方站点获取):

export SQUAD_DIR=~/squad
export SQUAD_VERSION=v1.1
export BERT_DIR=gs://cloud-tpu-checkpoints/bert/keras_bert/uncased_L-24_H-1024_A-16
export OUTPUT_DIR=gs://some_bucket/datasets

python official/nlp/data/create_finetuning_data.py \
 --squad_data_file=${SQUAD_DIR}/train-${SQUAD_VERSION}.json \
 --vocab_file=${BERT_DIR}/vocab.txt \
 --train_data_output_path=${OUTPUT_DIR}/squad_${SQUAD_VERSION}_train.tf_record \
 --meta_data_file_path=${OUTPUT_DIR}/squad_${SQUAD_VERSION}_meta_data \
 --fine_tuning_task_type=squad --max_seq_length=384

注意:生成 SQuAD 2.0 微调数据需要额外加 --version_2_with_negative=True 标志,以保留“无答案”样本的 negative 标注。

5. 句子/句对分类任务微调(MRPC 示例)

本小节以在 MRPC(仅约 3,600 条样本,多数 GPU 上数分钟即可微调)上微调 BERT-Large(uncased_L-24_H-1024_A-16)为例;GPU 显存 16GB 或更小时建议改用 BERT-Base(uncased_L-12_H-768_A-12)。

5.1 GPU 训练命令(完整)

export BERT_DIR=gs://cloud-tpu-checkpoints/bert/keras_bert/uncased_L-24_H-1024_A-16
export MODEL_DIR=gs://some_bucket/my_output_dir
export GLUE_DIR=gs://some_bucket/datasets
export TASK=MRPC

python official/legacy/bert/run_classifier.py \
  --mode='train_and_eval' \
  --input_meta_data_path=${GLUE_DIR}/${TASK}_meta_data \
  --train_data_path=${GLUE_DIR}/${TASK}_train.tf_record \
  --eval_data_path=${GLUE_DIR}/${TASK}_eval.tf_record \
  --bert_config_file=${BERT_DIR}/bert_config.json \
  --init_checkpoint=${BERT_DIR}/bert_model.ckpt \
  --train_batch_size=4 \
  --eval_batch_size=4 \
  --steps_per_loop=1 \
  --learning_rate=2e-5 \
  --num_train_epochs=3 \
  --model_dir=${MODEL_DIR} \
  --distribution_strategy=mirrored

不想用本地/GCS checkpoint 时,可改用 --hub_module_url=<tfhub 模块 URL 及版本号> 替代 --init_checkpoint

5.2 关键参数与源码默认值

结合 run_classifier.pycommon_flags.py 的 flag 定义,上例涉及参数的完整说明如下:

参数 默认值 说明
--mode train_and_eval 枚举 train_and_eval / export_only / predict:边训边评、仅从 model_dir 最新 checkpoint 导出 SavedModel、恢复 checkpoint 对测试集出预测(run_classifier.py#L37-L43
--bert_config_file--input_meta_data_path--model_dir 三个必填 flag(run_classifier.py#L511-L513
--train_batch_size / --eval_batch_size 32 / 32 全局 batch size,内部按 replica 切分
--learning_rate 5e-5 Adam 初始学习率(common_flags.py#L57-L58
--num_train_epochs 3 训练轮数(common_flags.py#L49-L50
--steps_per_loop 按设备自动配置 每个 graph-mode 循环内的训练步数;循环内不触发回调(common_flags.py#L51-L56
--optimizer_type adamw 可选 adamwlambcommon_flags.py#L61-L62
--distribution_strategy 可选 mirrored / tpu 等,TPU 地址由 --tpu=grpc://<IP>:8470 指定
--end_lr 0.0 学习率衰减终点

源码中还有两条值得注意的计算逻辑(run_classifier.py#L373-L382):

  • steps_per_epoch = train_data_size // train_batch_size,且当设置 --num_eval_per_epoch=n 时,实际 epoch 数放大为 num_train_epochs * n,每个 epoch 每处理 N/n 个样本评估一次,用于获得更细粒度的评估分数与 checkpoint;
  • warmup 步数固定取总步数的 10%:warmup_steps = epochs * train_data_size * 0.1 / train_batch_size,配合 official/nlp/optimization.pycreate_optimizer 生成带线性衰减的优化器。

5.3 预测与结果输出

训练完成后,设 --mode=predict 并通过 --eval_data_path 提供测试集 tfrecord 即可获取分类概率:

python official/legacy/bert/run_classifier.py \
  --mode='predict' \
  --input_meta_data_path=${GLUE_DIR}/${TASK}_meta_data \
  --eval_data_path=${GLUE_DIR}/${TASK}_eval.tf_record \
  --bert_config_file=${BERT_DIR}/bert_config.json \
  --eval_batch_size=4 \
  --model_dir=${MODEL_DIR} \
  --distribution_strategy=mirrored

输出写入 model_dir 下的 test_results.tsv,每行对应一个样本,列为各类别的概率。这与源码中 predict 分支的行为一致:恢复 checkpoint(默认取 tf.train.latest_checkpoint(FLAGS.model_dir),也可用 --predict_checkpoint_path 指定)后,对每条样本 softmax 得到概率并逐行 tab 分隔写出(run_classifier.py#L456-L484)。

5.4 TPU 上微调

从 GPU 切到 TPU 只需切换分发策略类型、提供 TPU 地址,并将 checkpoint 存放在远程存储(GCS):

export BERT_DIR=gs://cloud-tpu-checkpoints/bert/keras_bert/uncased_L-24_H-1024_A-16
export TPU_IP_ADDRESS='???'
export MODEL_DIR=gs://some_bucket/my_output_dir
export GLUE_DIR=gs://some_bucket/datasets
export TASK=MRPC

python official/legacy/bert/run_classifier.py \
  --mode='train_and_eval' \
  --input_meta_data_path=${GLUE_DIR}/${TASK}_meta_data \
  --train_data_path=${GLUE_DIR}/${TASK}_train.tf_record \
  --eval_data_path=${GLUE_DIR}/${TASK}_eval.tf_record \
  --bert_config_file=${BERT_DIR}/bert_config.json \
  --init_checkpoint=${BERT_DIR}/bert_model.ckpt \
  --train_batch_size=32 \
  --eval_batch_size=32 \
  --steps_per_loop=1000 \
  --learning_rate=2e-5 \
  --num_train_epochs=3 \
  --model_dir=${MODEL_DIR} \
  --distribution_strategy=tpu \
  --tpu=grpc://${TPU_IP_ADDRESS}:8470

TPU 版将 --steps_per_loop=1000 的原因:把大量训练步封装进 tf.function 图循环执行可显著提升 TPU 利用率(代价是回调不会在循环内部触发)。训练主循环采用 Keras compile/fit + 分发策略 API,steps_per_execution 即透传该值(run_classifier.py#L225-L229)。

6. SQuAD 1.1 微调

同样以 BERT-Large(uncased_L-24_H-1024_A-16)为例;16GB 显存以内建议 BERT-Base

6.1 GPU 训练命令(完整)

export BERT_DIR=gs://cloud-tpu-checkpoints/bert/keras_bert/uncased_L-24_H-1024_A-16
export SQUAD_DIR=gs://some_bucket/datasets
export MODEL_DIR=gs://some_bucket/my_output_dir
export SQUAD_VERSION=v1.1

python official/legacy/bert/run_squad.py \
  --input_meta_data_path=${SQUAD_DIR}/squad_${SQUAD_VERSION}_meta_data \
  --train_data_path=${SQUAD_DIR}/squad_${SQUAD_VERSION}_train.tf_record \
  --predict_file=${SQUAD_DIR}/dev-v1.1.json \
  --vocab_file=${BERT_DIR}/vocab.txt \
  --bert_config_file=${BERT_DIR}/bert_config.json \
  --init_checkpoint=${BERT_DIR}/bert_model.ckpt \
  --train_batch_size=4 \
  --predict_batch_size=4 \
  --learning_rate=8e-5 \
  --num_train_epochs=2 \
  --model_dir=${MODEL_DIR} \
  --distribution_strategy=mirrored

与分类任务一样,可用 --hub_module_url 替代 --init_checkpointrun_squad.py 默认会对 --predict_file 写出预测结果;若将 --mode 设为 predict 并提供 SQuAD 测试数据,则生成预测 JSON 文件。

6.2 SQuAD 专属参数

run_squad_helper.py 中的 define_common_squad_flags 定义了 SQuAD 相关参数(run_squad_helper.py#L37-L92):

参数 默认值 说明
--mode train_and_eval 六种取值:train_and_eval(训练、预测到 JSON 并计算指标)、train_and_predicttrainevalpredictexport_only
--do_lower_case True 输入是否小写化;uncased 模型应为 True,cased 模型应为 False
--predict_batch_size 8 预测全局 batch
--n_best_size 20 输出到 nbest_predictions.json 的 n-best 候选数
--max_answer_length 30 允许生成的最长答案;因 start/end 预测相互独立而必须限制
--null_score_diff_threshold 0.0 仅 SQuAD 2.0 使用:null_score - best_non_null 大于阈值时预测空答案
--predict_file 支持通配符与逗号分隔的多文件模式;eval 模式只支持单个文件

6.3 TPU 训练与评估

切 TPU 同样只需换分发策略:

export BERT_DIR=gs://cloud-tpu-checkpoints/bert/keras_bert/uncased_L-24_H-1024_A-16
export TPU_IP_ADDRESS='???'
export MODEL_DIR=gs://some_bucket/my_output_dir
export SQUAD_DIR=gs://some_bucket/datasets
export SQUAD_VERSION=v1.1

python official/legacy/bert/run_squad.py \
  --input_meta_data_path=${SQUAD_DIR}/squad_${SQUAD_VERSION}_meta_data \
  --train_data_path=${SQUAD_DIR}/squad_${SQUAD_VERSION}_train.tf_record \
  --predict_file=${SQUAD_DIR}/dev-v1.1.json \
  --vocab_file=${BERT_DIR}/vocab.txt \
  --bert_config_file=${BERT_DIR}/bert_config.json \
  --init_checkpoint=${BERT_DIR}/bert_model.ckpt \
  --train_batch_size=32 \
  --learning_rate=8e-5 \
  --num_train_epochs=2 \
  --model_dir=${MODEL_DIR} \
  --distribution_strategy=tpu \
  --tpu=grpc://${TPU_IP_ADDRESS}:8470

dev 集预测保存到 model_dir 下的 predictions.json,随后调用 SQuAD 1.1 官方评估脚本计算 Exact Match / F1:

python $SQUAD_DIR/evaluate-v1.1.py $SQUAD_DIR/dev-v1.1.json ./squad/predictions.json

仓库内也内置了等价的评估实现:run_squad_helper.py 顶部 from official.nlp.tools import squad_evaluate_v1_1squad_evaluate_v2_0run_squad_helper.py#L31-L33),即 --mode=train_and_eval 时评估指标直接由 official/nlp/tools/squad_evaluate_v1_1.py 在进程内计算。

7. 底层实现要点与延伸阅读

综合上述脚本,该 legacy 实现的架构可以概括为:

  1. 模型层bert_models.py 提供 BertPretrainLossAndMetricLayer(masked LM + 下一句预测的加权 loss 与 accuracy 指标)以及分类/问答任务模型工厂,编码器本体复用 official/nlp/modeling 中 Keras functional 风格的 BERT 网络,支持通过 hub_module_url 直接以 hub 模块为编码器。
  2. 数据层:统一走 official/legacy/bert/input_pipeline.py 读取 create_finetuning_data.py 产出的 tf_record,配合元数据文件中的 max_seq_lengthnum_labelslabel_typeint/float)自动切换分类/回归分支(num_classes==1 时按回归处理,使用均方误差,见 run_classifier.py#L133-L135)。
  3. 训练层:基于 distribute_utils.get_distribution_strategy 构建 mirrored/TPU 策略,Keras compile/fit 驱动训练,tf.train.CheckpointManager + SimpleCheckpoint 回调管理 checkpoint(run_classifier.py#L233-L254);混合精度(fp16)通过 common_flags.dtype()performance.set_mixed_precision_policy 开启。
  4. 测试与验证:目录内附 run_classifier 与 SQuAD 相关测试official/legacy/bert/bert_models_test.pyofficial/legacy/bert/model_training_utils_test.py),可用于验证模型构建与训练工具函数行为。

如需长期维护的新项目,建议迁移到 official/nlp 下基于 gin 实验配置的训练框架;本文命令与参数仅对该 legacy 目录内的脚本适用。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
528
588
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
906
1.82 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
docsdocs
暂无描述
Markdown
891
5.78 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.53 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.34 K
1.45 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
987
504
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384