如果你正在学习深度学习尤其是自然语言处理NLP那么“微调预训练模型”这个概念你一定不陌生。但当你真正动手时可能会发现一个尴尬的局面教程里都说用 Hugging Face 的TrainerAPI 很简单几行代码就能搞定可轮到自己跑起来不是显存爆炸就是训练不收敛或者根本不知道如何评估和保存模型。你照着别人的代码敲了一遍能跑通但为什么这么写背后的参数怎么调遇到问题怎么查心里依然没底。这篇文章要解决的正是这个“从会敲代码到真正理解”的 gap。我们不满足于复现一个简单的 BERT 文本分类微调示例而是要拆解TrainerAPI 的每一个关键环节让你不仅知其然更知其所以然。你将彻底明白TrainingArguments里那一长串参数分别控制什么如何根据你的数据集和 GPU 条件配置它们以及训练过程中那些重要的回调Callbacks该如何使用。更重要的是我们会直面微调中的真实痛点显存不够怎么办训练过程怎么监控和可视化模型保存与加载有哪些坑本文将以一个情感分类任务为实战场景带你走完一个完整的、可复现的、包含最佳实践的微调流程。读完本文你不仅能微调 BERT更能掌握一套适用于 Hugging Face 生态中各种预训练模型的微调方法论。1. 为什么你需要认真了解 Trainer API在 Hugging Face 的transformers库中微调模型主要有两种方式一种是“硬核”的手动编写训练循环自己管理优化器、损失函数和梯度更新另一种就是使用高级抽象的TrainerAPI。对于绝大多数应用和实验场景Trainer是首选。它的核心价值在于“标准化”和“自动化”标准化它将数据加载、训练循环、评估、保存、日志记录等繁杂但通用的流程封装起来你只需要关注模型、数据和任务目标。这极大地减少了样板代码降低了出错概率。自动化它内置了混合精度训练、梯度累积、多 GPU/TPU 支持、早停Early Stopping等高级功能。手动实现这些特性不仅复杂而且容易引入 bug。但是Trainer的“黑盒”感也是其最大的学习障碍。很多初学者调用trainer.train()后就对中间发生的一切失去了掌控力。当 loss 不下降、显存溢出时往往无从下手。因此本文的目标是“打开黑盒”。我们将通过一个具体的二分类任务IMDb 电影评论情感分析深入Trainer的配置、训练和评估过程让你获得清晰的掌控感。你会发现掌握了Trainer你就掌握了高效微调绝大多数 Hugging Face 模型的钥匙。2. 核心概念与准备工作在开始写代码之前我们先明确几个关键概念并准备好实验环境。2.1 关键概念澄清预训练模型Pre-trained Model如 BERT是在大规模无标注语料如 Wikipedia上通过自监督任务如掩码语言模型 MLM训练得到的模型。它已经学习了丰富的语言表征但并非为你的特定任务如情感分类、问答量身定制。微调Fine-tuning在预训练模型的基础上使用你的特定任务的有标注数据继续对模型参数进行训练使其适应新任务。这个过程通常比从头训练快得多且效果更好。Trainer APIHugging Facetransformers库提供的一个高级训练类。它封装了完整的训练循环你只需提供模型、数据、训练参数和评估函数它就能自动处理训练、评估、保存和日志记录。TrainingArguments一个数据类用于集中定义所有训练相关的超参数和设置如学习率、批次大小、训练轮数、保存策略等。它是Trainer的核心配置。2.2 环境准备与安装确保你的 Python 环境推荐 3.8并安装必要的包。建议使用虚拟环境。# 安装核心库 pip install transformers datasets torch torchvision torchaudio # 安装评估指标库和可视化工具可选但推荐 pip install evaluate tensorboard scikit-learn版本建议以实际项目为准本文演示通用思路transformers 4.30.0datasets 2.12.0torch 1.12.0(需与你的 CUDA 版本匹配)硬件要求GPU强烈推荐微调 BERT-base 模型batch size 设为 8 时大约需要 4-6 GB 显存。如果没有 GPUCPU 训练会非常慢。内存至少 8 GB 系统内存用于加载数据集和模型。3. 实战使用 Trainer API 微调 BERT 进行情感分类我们将使用 IMDb 数据集这是一个经典的二分类数据集包含 25000 条训练电影评论和 25000 条测试评论标签为“正面”或“负面”。3.1 第一步加载数据集与预训练模型首先我们使用datasets库加载 IMDb 数据并加载预训练的 BERT 模型和对应的分词器。# 文件load_data_and_model.py from datasets import load_dataset from transformers import AutoTokenizer, AutoModelForSequenceClassification import torch # 1. 加载数据集 print(正在加载 IMDb 数据集...) dataset load_dataset(imdb) print(f数据集结构: {dataset}) print(f训练集样本数: {len(dataset[train])}) print(f测试集样本数: {len(dataset[test])}) # 查看一条样本 sample dataset[train][0] print(f\n样本示例:\n文本: {sample[text][:200]}...\n标签: {sample[label]} (0负面, 1正面)) # 2. 加载分词器和模型 # 我们使用 bert-base-uncased这是一个小写的 BERT 基础模型 model_name bert-base-uncased print(f\n正在加载分词器: {model_name}) tokenizer AutoTokenizer.from_pretrained(model_name) print(f正在加载模型: {model_name}) # AutoModelForSequenceClassification 会自动在 BERT 基础上添加一个用于分类的分类头 # num_labels2 指定我们是二分类任务 model AutoModelForSequenceClassification.from_pretrained(model_name, num_labels2) # 检查模型参数和设备 device torch.device(cuda if torch.cuda.is_available() else cpu) model.to(device) print(f模型已加载至设备: {device}) print(f模型总参数量: {sum(p.numel() for p in model.parameters()):,})关键点解释AutoTokenizer.from_pretrained自动加载与model_name匹配的分词器。BERT 使用 WordPiece 分词。AutoModelForSequenceClassification.from_pretrained这是关键。它加载预训练的 BERT 模型并自动在顶部添加一个适合序列分类的线性层。你不需要手动修改模型结构。num_labels参数决定了这个分类头的输出维度。将模型移动到 GPU (model.to(device)) 是必要的否则训练会在 CPU 上进行速度极慢。3.2 第二步数据预处理Tokenization原始文本需要被分词并转换为模型可接受的数字 IDinput_ids同时生成注意力掩码attention_mask等。# 文件tokenize_dataset.py def preprocess_function(examples): 对一批样本进行分词处理 # truncationTrue 和 paddingTrue 是常用设置确保序列被截断/填充到模型最大长度 # max_length512 是 BERT 的最大序列长度 return tokenizer(examples[text], truncationTrue, paddingTrue, max_length512) print(正在对数据集进行分词处理...) # 使用 datasets 的 map 函数高效地对整个数据集进行批处理分词 tokenized_datasets dataset.map(preprocess_function, batchedTrue) print(分词完成) # 查看处理后的数据结构 print(f\n分词后数据集的特征: {tokenized_datasets[train].features}) # 你会看到新增了 input_ids, attention_mask, token_type_ids 等字段 # 为了训练我们需要重命名标签列因为 Trainer 默认期望的列名是 labels tokenized_datasets tokenized_datasets.rename_column(label, labels) # 设置数据集格式为 PyTorch 张量 tokenized_datasets.set_format(torch, columns[input_ids, attention_mask, labels]) print(数据集已转换为 PyTorch 张量格式。) # 可选划分一小部分数据作为验证集 # 从训练集中划分 10% 作为验证集用于训练过程中监控模型在未见数据上的表现 split_datasets tokenized_datasets[train].train_test_split(test_size0.1, seed42) train_dataset split_datasets[train] eval_dataset split_datasets[test] test_dataset tokenized_datasets[test] # 保留原始测试集用于最终评估 print(f训练集大小: {len(train_dataset)}) print(f验证集大小: {len(eval_dataset)}) print(f测试集大小: {len(test_dataset)})为什么需要验证集训练集用于更新模型参数测试集用于最终评估模型泛化能力。验证集则在每个训练周期epoch结束后评估模型用于监控训练过程、调整超参数如早停以及选择最佳模型。没有验证集你很难判断模型是否过拟合。3.3 第三步配置训练参数TrainingArguments这是TrainerAPI 的“大脑”所有训练行为都由它控制。理解每个参数的意义至关重要。# 文件training_args.py from transformers import TrainingArguments # 定义输出目录所有训练产出模型、日志、检查点都会保存在这里 output_dir ./bert-imdb-sentiment training_args TrainingArguments( output_diroutput_dir, # 输出目录 overwrite_output_dirTrue, # 如果输出目录已存在则覆盖 # 训练循环核心参数 num_train_epochs3, # 训练总轮数 per_device_train_batch_size8, # 每个 GPU/CPU 上的训练批次大小 per_device_eval_batch_size16, # 每个 GPU/CPU 上的评估批次大小 learning_rate2e-5, # 初始学习率微调通常使用较小的学习率5e-5, 3e-5, 2e-5 weight_decay0.01, # 权重衰减一种正则化防止过拟合 # 评估与保存策略 evaluation_strategyepoch, # 每个 epoch 结束后进行评估 save_strategyepoch, # 每个 epoch 结束后保存模型 load_best_model_at_endTrue, # 训练结束后加载验证集上性能最好的模型 metric_for_best_modelaccuracy, # 用于选择最佳模型的指标 # 日志与报告 logging_dir./logs, # TensorBoard 日志目录 logging_steps50, # 每多少步记录一次日志 report_totensorboard, # 使用 TensorBoard 可视化训练过程 # 性能优化 fp16torch.cuda.is_available(), # 如果 GPU 支持启用混合精度训练FP16可以节省显存并加速 gradient_accumulation_steps1, # 梯度累积步数。如果显存不足可以增大此值如设为2 # 相当于增大有效批次大小但更新频率变低。 # 其他实用参数 save_total_limit2, # 最多保留的检查点数量避免磁盘占满 seed42, # 随机种子确保实验可复现 )参数深度解析per_device_train_batch_size这是单个设备上的批次大小。如果你有 2 张 GPUTrainer会自动进行数据并行总批次大小将是2 * per_device_train_batch_size。learning_rate微调的学习率必须很小。因为预训练模型已经学到了很好的特征我们只是微调大幅度的参数更新会破坏这些特征。2e-5是 BERT 微调的常用起点。evaluation_strategy和save_strategy设为epoch是最常见的方便观察每一轮的整体表现。也可以设为steps并按步数评估/保存。fp16混合精度训练。利用 GPU 的 Tensor Cores 加速计算同时节省约 50% 的显存。如果 GPU 是 NVIDIA 且支持Volta 架构及以后强烈建议开启。gradient_accumulation_steps解决显存不足的利器。假设你想用批次大小 16 训练但显存只够 8。你可以设置per_device_train_batch_size8和gradient_accumulation_steps2。模型会以批次 8 进行两次前向传播和反向传播累积梯度然后一次性更新参数效果上近似于批次 16。3.4 第四步定义评估函数Trainer在评估时需要知道如何计算指标。我们需要定义一个函数它接收模型预测和标签返回一个字典包含我们关心的指标如准确率、F1 分数。# 文件compute_metrics.py import evaluate import numpy as np # 加载评估指标。evaluate 库是 Hugging Face 的标准评估库。 accuracy_metric evaluate.load(accuracy) f1_metric evaluate.load(f1) def compute_metrics(eval_pred): 计算评估指标 predictions, labels eval_pred # predictions 是模型输出 logits (batch_size, num_labels) # 我们需要取 argmax 得到预测的类别 predictions np.argmax(predictions, axis1) # 计算准确率 acc_result accuracy_metric.compute(predictionspredictions, referenceslabels) # 计算 F1 分数对于二分类默认是 macro-F1也可指定 averagebinary f1_result f1_metric.compute(predictionspredictions, referenceslabels, averagemacro) # 返回一个包含所有指标的字典 return {**acc_result, **f1_result} # 我们可以快速测试一下这个函数 # 假设我们有 3 个样本的预测 logits 和真实标签 test_logits np.array([[1.2, -0.5], [-0.1, 2.3], [0.9, 0.1]]) # 预测 logits test_labels np.array([0, 1, 0]) # 真实标签 test_eval_pred (test_logits, test_labels) metrics compute_metrics(test_eval_pred) print(f测试 compute_metrics: {metrics})3.5 第五步初始化 Trainer 并开始训练现在万事俱备我们可以创建Trainer实例并启动训练了。# 文件train.py from transformers import Trainer # 初始化 Trainer trainer Trainer( modelmodel, # 要训练的模型 argstraining_args, # 训练参数 train_datasettrain_dataset, # 训练数据集 eval_dataseteval_dataset, # 验证数据集 tokenizertokenizer, # 分词器用于模型保存时也保存分词器 compute_metricscompute_metrics # 评估函数 ) print(开始训练...) # 启动训练这将执行完整的训练循环包括在每个 epoch 后评估验证集。 train_result trainer.train() print(训练完成) # 训练完成后保存最终模型包括分词器 trainer.save_model(output_dir) print(f模型已保存至: {output_dir}) # 保存训练指标 metrics_train train_result.metrics trainer.log_metrics(train, metrics_train) trainer.save_metrics(train, metrics_train) trainer.save_state() # 保存训练状态如优化器状态可用于恢复训练运行上述代码你将看到类似下面的输出展示了训练和评估的进度***** Running training ***** Num examples 22500 Num Epochs 3 Instantaneous batch size per device 8 Total train batch size (w. parallel, distributed accumulation) 8 Gradient Accumulation steps 1 Total optimization steps 8438 Number of trainable parameters 109,483,778 ... Epoch | Training Loss | Validation Loss | Accuracy | F1 | 1 | 0.223100 | 0.185200 | 0.932000 | 0.931800 | 2 | 0.112300 | 0.172100 | 0.942500 | 0.942300 | 3 | 0.062500 | 0.180500 | 0.941000 | 0.940800 |3.6 第六步在测试集上评估与推理训练完成后我们应在完全未参与训练和验证的测试集上评估模型的最终泛化性能。# 文件evaluate_and_predict.py print(\n在测试集上进行最终评估...) test_metrics trainer.evaluate(eval_datasettest_dataset, metric_key_prefixtest) print(f测试集评估结果: {test_metrics}) # 使用训练好的模型进行单条样本推理 print(\n进行单条样本推理测试...) # 加载刚刚保存的最佳模型也可以直接使用 trainer.model from transformers import pipeline # 创建文本分类管道非常方便 classifier pipeline(text-classification, modeloutput_dir, tokenizeroutput_dir, device0 if torch.cuda.is_available() else -1) # 测试一些评论 test_texts [ This movie was absolutely fantastic! The acting was superb and the plot was engaging from start to finish., A complete waste of time. The story made no sense and the characters were utterly boring., It was okay, nothing special. Some parts were good, others were a bit dull. ] for text in test_texts: result classifier(text, truncationTrue, max_length512) # result 是一个列表例如 [{label: LABEL_1, score: 0.998}] # 注意标签映射可能不同需要根据模型配置查看。通常 LABEL_0 对应负面LABEL_1 对应正面。 label_map {0: 负面, 1: 正面} predicted_label int(result[0][label].split(_)[-1]) # 提取标签数字 confidence result[0][score] print(f评论: {text[:80]}...) print(f 预测情感: {label_map[predicted_label]} (置信度: {confidence:.4f})\n)4. 核心流程拆解与深度理解现在我们已经跑通了整个流程。但为了真正掌握让我们回头拆解Trainer内部的关键环节。4.1 Trainer 的训练循环在做什么当你调用trainer.train()时背后发生了以下事情数据加载Trainer使用DataLoader从train_dataset中按批次加载数据。前向传播将批次数据input_ids,attention_mask送入模型得到预测 logits。损失计算根据labels和预测 logits 计算交叉熵损失对于分类任务。Trainer会自动选择合适的损失函数。反向传播计算损失相对于模型参数的梯度。优化器步骤使用优化器默认为AdamW根据梯度更新模型参数。如果设置了gradient_accumulation_steps会累积多个批次的梯度后再更新。学习率调度根据调度器默认为线性衰减更新学习率。日志记录每隔logging_steps步记录损失、学习率等到日志和 TensorBoard。评估在每个 epoch 结束时如果evaluation_strategyepoch在eval_dataset上运行评估循环计算compute_metrics定义的指标。模型保存根据save_strategy保存模型检查点。如果load_best_model_at_endTrue训练结束后会加载验证集上指标最好的模型。4.2 如何监控训练过程—— 使用 TensorBoardTrainingArguments中设置了report_totensorboard。训练开始后会在logging_dir这里是./logs目录下生成日志文件。# 在终端启动 TensorBoard在项目根目录下运行 tensorboard --logdir./logs然后在浏览器中打开http://localhost:6006你可以看到训练/验证损失曲线监控模型是否在学习是否过拟合训练损失下降但验证损失上升。准确率/F1 曲线监控模型性能。学习率曲线查看学习率调度是否正常。GPU 利用率检查硬件是否被充分利用。这是诊断训练问题如学习率过高、模型不收敛最直观的工具。5. 常见问题与排查思路微调过程中你几乎一定会遇到下面这些问题。这里提供系统的排查思路。问题现象可能原因排查方式解决方案CUDA out of memory (OOM)批次大小太大模型太大序列长度太长。1. 运行nvidia-smi监控显存使用。2. 尝试减小per_device_train_batch_size。3. 检查数据集中序列的最大长度。1.首要方案减小per_device_train_batch_size如从 16 降到 8。2.启用混合精度设置fp16True。3.使用梯度累积保持小批次但增大gradient_accumulation_steps。4.动态填充在tokenizer中设置paddingmax_length并指定一个较小的max_length如 128 或 256而不是默认的 512。训练 Loss 不下降学习率不合适数据预处理有问题模型未正确加载。1. 检查前几个批次的损失值是否正常应在 0.5-1.0 左右开始。2. 检查compute_metrics函数是否在验证集上有提升。3. 检查分词后的input_ids是否包含[PAD](0) 和[CLS],[SEP]等特殊 token。1.调整学习率尝试更小的学习率如5e-6,1e-5。2.检查数据确保labels与input_ids正确对应。打印几条样本看看。3.冻结部分层对于小数据集可以先冻结 BERT 的前几层只训练分类头和最后几层。验证集性能远差于训练集过拟合训练数据太少模型太复杂训练轮数太多。观察 TensorBoard 中训练损失和验证损失的曲线是否逐渐分离。1.数据增强对文本进行回译、同义词替换等对于 NLP 较复杂。2.更强的正则化增大weight_decay如从 0.01 到 0.1。3.早停Early Stopping使用EarlyStoppingCallback。4.减少模型容量使用更小的预训练模型如distilbert-base-uncased。评估时指标计算错误compute_metrics函数逻辑错误预测和标签形状不匹配。在compute_metrics函数内部打印predictions和labels的 shape 和值。1. 确保predictions是 logits需要np.argmax(predictions, axis1)得到预测类别。2. 确保labels是整数标签不是 one-hot 编码。3. 使用evaluate库的标准指标函数进行验证。模型保存后无法加载保存的模型文件不完整分词器未保存配置文件丢失。检查输出目录是否包含pytorch_model.bin(或model.safetensors)、config.json、tokenizer.json等文件。1. 使用Trainer的save_model方法它会自动保存模型、分词器和配置。2. 加载时使用AutoModelForSequenceClassification.from_pretrained(‘./your_model_dir’)和AutoTokenizer.from_pretrained(‘./your_model_dir’)。6. 高级技巧与最佳实践掌握了基础流程后这些技巧能让你的微调更高效、更稳健。6.1 使用回调Callbacks增强控制Trainer支持回调允许你在训练循环的特定节点插入自定义逻辑。from transformers import TrainerCallback, EarlyStoppingCallback import numpy as np # 自定义回调示例在每个 epoch 结束时打印自定义信息 class CustomLoggingCallback(TrainerCallback): def on_epoch_end(self, args, state, control, **kwargs): print(f\n[自定义回调] Epoch {state.epoch} 结束。当前全局步数: {state.global_step}) # 早停回调如果验证集指标在若干次评估后不再提升则停止训练 # 需要先安装 sklearn 以获取评估指标 early_stopping_callback EarlyStoppingCallback( early_stopping_patience2, # 容忍多少次评估指标没有提升 early_stopping_threshold0.001, # 提升小于此阈值视为无提升 ) # 在创建 Trainer 时传入 callbacks 参数 trainer Trainer( modelmodel, argstraining_args, train_datasettrain_dataset, eval_dataseteval_dataset, compute_metricscompute_metrics, tokenizertokenizer, callbacks[CustomLoggingCallback(), early_stopping_callback] # 添加回调 )6.2 冻结底层参数只微调顶层对于小数据集微调所有参数容易过拟合。一个常见策略是冻结 BERT 的底层靠近输入的层只训练顶层和分类头。# 冻结 BERT 模型的前 6 层总共 12 层 def freeze_layers(model, num_frozen_layers): # BERT 的 encoder 由 12 个 layer 组成 for i, layer in enumerate(model.bert.encoder.layer): if i num_frozen_layers: for param in layer.parameters(): param.requires_grad False # 冻结参数 # 也可以选择冻结 embedding 层 # for param in model.bert.embeddings.parameters(): # param.requires_grad False return model # 应用冻结 model AutoModelForSequenceClassification.from_pretrained(model_name, num_labels2) model freeze_layers(model, num_frozen_layers6) # 统计可训练参数数量 trainable_params sum(p.numel() for p in model.parameters() if p.requires_grad) total_params sum(p.numel() for p in model.parameters()) print(f总参数量: {total_params:,}) print(f可训练参数量: {trainable_params:,} (冻结了 {total_params - trainable_params:,} 个参数))6.3 超参数搜索Hyperparameter Search手动调参费时费力。Trainer支持与optuna或ray tune集成进行超参数搜索。# 示例使用 optuna 进行超参数搜索需要安装 optuna # pip install optuna def model_init(): # 每次试验都需要返回一个新的模型实例 return AutoModelForSequenceClassification.from_pretrained(model_name, num_labels2) def hp_space(trial): # 定义要搜索的超参数空间 return { learning_rate: trial.suggest_float(learning_rate, 1e-5, 5e-5, logTrue), num_train_epochs: trial.suggest_int(num_train_epochs, 2, 5), per_device_train_batch_size: trial.suggest_categorical(per_device_train_batch_size, [8, 16, 32]), weight_decay: trial.suggest_float(weight_decay, 0.0, 0.1), } trainer Trainer( model_initmodel_init, # 使用 model_init 而不是 model argstraining_args, train_datasettrain_dataset, eval_dataseteval_dataset, compute_metricscompute_metrics, tokenizertokenizer, ) # 运行超参数搜索这会非常耗时 best_run trainer.hyperparameter_search( directionmaximize, # 我们希望最大化评估指标如准确率 hp_spacehp_space, n_trials10, # 试验次数 backendoptuna, ) print(f最佳超参数组合: {best_run.hyperparameters}) print(f最佳运行对应的评估指标: {best_run.objective})6.4 生产环境部署建议模型格式转换训练完成后可以考虑将 PyTorch 模型转换为 ONNX 或 TensorRT 格式以获得更快的推理速度特别是在 GPU 上。创建推理服务使用 FastAPI 或 Flask 将模型封装为 REST API 服务。监控与日志在生产环境中记录模型的输入、输出、延迟和资源使用情况。版本控制使用 Hugging Face Hub 或公司内部的模型仓库管理不同版本的模型确保可追溯和可回滚。7. 总结与下一步通过本文的详细拆解你应该已经掌握了使用 Hugging FaceTrainerAPI 微调 BERT 等预训练模型的完整流程和核心要点。我们不仅跑通了一个情感分类的示例更深入探讨了参数配置、问题排查和高级技巧。关键收获TrainerAPI 的核心价值在于标准化和自动化但理解其配置TrainingArguments是高效使用的关键。微调的核心是用小学习率在特定任务数据上更新预训练模型的参数。数据预处理、验证集划分、评估函数定义是保证实验可靠性的基础。显存管理批次大小、混合精度、梯度累积和训练监控TensorBoard是实践中的必备技能。通过回调、参数冻结、超参数搜索等高级功能可以进一步优化微调过程。下一步你可以探索的方向尝试其他任务将代码迁移到其他 NLP 任务如命名实体识别NER、问答QA、文本摘要。只需更换模型如AutoModelForTokenClassification和数据集。尝试其他模型Hugging Face 上有成千上万的预训练模型RoBERTa, DistilBERT, ALBERT, DeBERTa。尝试用相同的Trainer流程微调它们比较效果和效率。探索更高效的微调方法对于大模型或小数据全参数微调成本高。可以学习LoRA (Low-Rank Adaptation)或Prefix-Tuning等参数高效微调方法它们只训练少量新增参数能大幅降低显存消耗。深入源码如果遇到复杂需求可以阅读transformers/trainer.py源码理解Trainer的内部机制甚至继承并重写部分方法。本文的完整代码已涵盖了从环境准备到生产推理的主要环节建议你收藏并在自己的项目中实践。遇到问题时多回顾第 5 部分的排查思路。微调预训练模型是现代 NLP 应用的基石而熟练使用TrainerAPI 将使你在这条路上事半功倍。