文章目录sft_trainer 对象 常用属性/函数sft_trainer.save_model() 保存的是什么时候的状态sft_trainer对象指的是SFTTrainer的示例化对象关于SFTTrainer可以看这篇文章TRL 1.15.010 月 8 日发布SFTTrainer 源码解析全网首批新版详解sft_trainer对象 常用属性/函数以下基于 TRL 1.15.0 源代码sft_trainerSFTTrainer(modelpeft_model,argssft_config,train_datasetdataset_train,processing_classtokenizer,)print(type(sft_trainer))# class trl.trainer.sft_trainer.SFTTrainer一、sft_trainer的继承关系MROsft_trainer 所属类SFTTrainer └── _BaseTrainer └── Trainer (transformers.Trainer) └── objectsft_trainer能调用SFTTrainer、_BaseTrainer、Trainer三层的所有属性和方法。越往下越通用SFTTrainer自己只新增/覆盖 SFT 相关的一小部分。Trainer类体里通过from .trainer_pt_utils import (...)把get_learning_rates、get_num_trainable_parameters、get_optimizer_group、log_metrics、metrics_format、save_metrics、save_state挂成了方法不是继承来的所以sft_trainer.save_state(...)这类调用合法。loss_is_scaled_for_ga原本是Trainer的类属性默认None_BaseTrainer又显式声明 None并在__init__中做兼容处理transformers 5.19 时改model_accepts_loss_kwargs/compute_loss_funcSFTTrainer没有覆盖它实例上保持None。二、通用属性每个sft_trainer实例都具备来自Trainer属性含义sft_trainer.args训练配置即使传入TrainingArguments__init__里也会转成SFTConfig所以这里通常是SFTConfigsft_trainer.acceleratoraccelerate.Accelerator分布式/混合精度上下文sft_trainer.model被训练的核心模型PEFT 时是PeftModelsft_trainer.model_wrapped最外层包装后的模型DDP/DeepSpeed/FSDP 包装后sft_trainer.model_init用户传入的model_init未传时为Nonesft_trainer.model_accepts_loss_kwargs模型 forward 是否接受num_items_in_batch等 kwargssft_trainer.deepspeedDeepSpeed 引擎未启用时Nonesft_trainer.train_dataset训练集已过_prepare_dataset预处理skip_prepare_datasetTrue时未处理sft_trainer.eval_dataset验证集sft_trainer.data_collator批处理 collator这里是DataCollatorForLanguageModeling或DataCollatorForVisionLanguageModelingsft_trainer.processing_classtokenizer 或 processorsft_trainer.optimizer优化器train()前为Nonecreate_optimizer()后赋值sft_trainer.lr_scheduler学习率调度器sft_trainer.optimizer_cls_and_kwargs用户传入的优化器类kwargs默认Nonesft_trainer.label_smootherLabelSmoother实例args.label_smoothing_factor 0时为NoneSFTTrainer 里启用会走额外 forward 拿完整 logitssft_trainer.label_names模型 loss 用到的标签名来自find_labels或args.label_namessft_trainer.can_return_loss模型 forward 是否能返回 losssft_trainer._loss_shifts_labels是否走 causal-LM 的标签 shift 规则影响num_items_in_batch的计数sft_trainer.compute_loss_func自定义 loss 函数SFTTrainer 里非None会触发 FutureWarning并走一条特殊路径sft_trainer.compute_metrics评估指标函数sft_trainer.preprocess_logits_for_metricseval 时对 logits 的预处理函数sft_trainer.stateTrainerStateglobal_step、epoch、log_history、best_metric、best_model_checkpoint、max_steps、num_input_tokens_seen等sft_trainer.controlTrainerControlshould_log、should_save、should_evaluate、should_training_stop等sft_trainer.callback_handler回调管理器callbacks列表、on_*分发sft_trainer.is_in_train是否处于train()生命周期内train()入口置True_finalize_training末尾置回Falsesft_trainer.current_flos当前累计 FLOPs累加于训练步store_flos()后清零sft_trainer.is_deepspeed_enabled是否启用 DeepSpeedsft_trainer.is_fsdp_enabled是否启用 FSDPaccelerate 侧sft_trainer.is_fsdp_xla_enabled是否启用 FSDP-XLAv1v2 总开关sft_trainer.is_fsdp_xla_v1_enabled是否 FSDP-XLA v1sft_trainer.is_fsdp_xla_v2_enabled是否 FSDP-XLA v2sft_trainer.is_model_parallel是否模型并行hf_device_map跨多设备sft_trainer.place_model_on_device是否由 Trainer 自动把模型搬到设备sft_trainer.is_distributed_loading_by_transformers模型是否在加载时已按DistributedConfig分片sft_trainer.hub_model_id推 Hub 时的 repo idpush_to_hubFalse时保持Nonesft_trainer.push_in_progress后台推送状态仅在args.push_to_hubTrue时由init_hf_repo()创建否则属性不存在sft_trainer.gather_function当前使用的 gather 函数默认accelerator.gather_for_metricsevaluation loop 结束后会重置sft_trainer.neftune_noise_alphaNEFTune 噪声系数未启用为Nonesft_trainer.hp_name/hp_search_backend超参搜索相关sft_trainer._signature_columns模型 forward 接受的列名缓存懒加载由_set_signature_columns_if_needed()填充sft_trainer._train_batch_size实际训练 batch sizeauto_find_batch_sizeTrue时会动态调整sft_trainer._created_lr_schedulerLR scheduler 是否由 Trainer 创建sft_trainer._loggers_initialized日志后端是否已初始化sft_trainer._memory_trackerTrainerMemoryTrackersft_trainer._mixed_mesh_grads混合 device mesh 梯度标志懒计算用于梯度裁剪sft_trainer._eval_dataloaders仅在dataloader_persistent_workersTrue时懒创建缓存 eval dataloader来自_BaseTrainer属性含义sft_trainer.loss_is_scaled_for_ga类级None/True/False。None表示“由model_accepts_loss_kwargs和compute_loss_func推断”。SFTTrainer 的compute_loss自己归一化但没有覆盖这个标志所以实例上保持Nonesft_trainer._tag_names[trl, sft]类级add_model_tags时用sft_trainer._nameSFT类级sft_trainer._paper/_template_file类级生成 model card 用来自SFTTrainerSFT 专属实例属性属性含义sft_trainer._tokenizer统一拿到的 tokenizerprocessor.tokenizer或processing_class本身sft_trainer._is_vlmprocessing_class是否为ProcessorMixin多模态sft_trainer._is_vision_dataset训练集是否含image/images字段sft_trainer.padding_free是否 padding-free值为args.padding_free or (args.packing and args.packing_strategy in {bfd,bfd_split})sft_trainer.chat_template当args.assistant_only_lossTrue且当前 template 缺少{% generation %}标记时替换为训练用 chat template否则Nonesft_trainer.completion_only_loss是否只对 completion 段算 losssft_trainer._skip_prepare_dataset是否跳过数据集预处理dataset_kwargs.skip_prepare_datasetTrue或 VLM 时为 Truesft_trainer._formatting_func保存的formatting_func供evaluate()复用sft_trainer.maybe_activation_offload_context激活卸载 context未开启为contextlib.nullcontext()sft_trainer.router_aux_loss_coefMoE 辅助 loss 系数仅 MoE 模型有意义sft_trainer.aux_loss_enabled是否启用 MoE aux loss仅 MoE 模型有意义sft_trainer._metrics{train: defaultdict(list), eval: defaultdict(list)}记录entropy、mean_token_accuracy、num_tokens列表、aux_losslog()后 clearsft_trainer._total_train_tokens累计训练 token 数compute_loss训练分支累加sft_trainer._tp_sizetensor parallel sizeaccelerate ≥ 1.10.0 且有parallelism_config时取parallelism_config.tp_size否则为 1三、通用方法每个sft_trainer实例都可调用来自Trainer的公开 API方法作用sft_trainer.train(resume_from_checkpointNone, trialNone, ignore_keys_for_evalNone)主训练入口返回TrainOutput内部经_inner_training_loopsft_trainer.evaluate(eval_datasetNone, ignore_keysNone, metric_key_prefixeval)评估返回 metrics dictsft_trainer.predict(test_dataset, ignore_keysNone, metric_key_prefixtest)预测返回PredictionOutputsft_trainer.evaluation_loop(dataloader, description, prediction_loss_onlyNone, ignore_keysNone, metric_key_prefixeval)评估/预测共用循环evaluate/predict内部调用也可直接用sft_trainer.save_model(output_dirNone, _internal_callFalse)保存模型PEFT 时存 adaptersft_trainer.push_to_hub(commit_messageEnd of training, blockingTrue, tokenNone, revisionNone, **kwargs)推 Hubsft_trainer.create_model_card(...)生成README.md模型卡_BaseTrainer覆盖签名比Trainer版更少model_name/dataset_name/tagssft_trainer.init_hf_repo(tokenNone)初始化 Hub reposft_trainer.end()销毁进程组脚本最后调用sft_trainer.hyperparameter_search(...)超参搜索sft_trainer.add_callback(callback)/pop_callback(callback)/remove_callback(callback)回调管理sft_trainer.get_train_dataloader()/get_eval_dataloader(eval_datasetNone)/get_test_dataloader(test_dataset)取 DataLoadersft_trainer.num_examples(dataloader)数据集样本数带IterableDatasetShard兼容sft_trainer.is_local_process_zero()/is_world_process_zero()进程角色判断sft_trainer.floating_point_ops(inputs)估算 FLOPssft_trainer.store_flos()把current_flos累加进state.total_flos后清零sft_trainer.log(logs, start_timeNone)记录日志SFTTrainer 覆盖合并_metricssft_trainer.get_learning_rates()/get_num_trainable_parameters()/get_optimizer_group()/log_metrics()/metrics_format()/save_metrics()/save_state()从trainer_pt_utils混入的工具方法来自Trainer的钩子override 或复用子步骤方法作用sft_trainer.compute_loss(model, inputs, return_outputsFalse, num_items_in_batchNone)计算 lossSFTTrainer 已覆盖sft_trainer.training_step(model, inputs, num_items_in_batchNone)单步训练SFTTrainer 覆盖包激活卸载 contextsft_trainer.prediction_step(model, inputs, prediction_loss_only, ignore_keysNone)eval 单步SFTTrainer 覆盖按需返回 outputssft_trainer.create_optimizer(modelNone)/create_scheduler(num_training_steps, optimizerNone)/create_optimizer_and_scheduler(num_training_steps)优化器/调度器构造sft_trainer.get_decay_parameter_names(model)哪些参数参与 weight decaysft_trainer.get_optimizer_cls_and_kwargs(args, modelNone)静态方法按args.optim返回优化器类和 kwargssft_trainer.compute_loss_context_manager()/autocast_smart_context_manager(cache_enabledTrue)autocast 上下文sft_trainer._prepare_input(data)/_prepare_inputs(inputs)把 batch 搬到设备sft_trainer._prepare_context_parallel_inputs(model, inputs)准备 CP 输入/上下文sft_trainer._wrap_model(model, trainingTrue, dataloaderNone)DDP/FSDP/SageMaker 包装sft_trainer._move_model_to_device(model, device)移动模型sft_trainer._get_dataloader(dataset, description, batch_size, sampler_fnNone, is_trainingFalse, dataloader_keyNone)构造 DataLoader 的底层实现sft_trainer._get_train_sampler(datasetNone)/_get_eval_sampler(eval_dataset)sampler 构造sft_trainer._set_signature_columns_if_needed()设置模型接受的列名SFTTrainer 已覆盖sft_trainer._remove_unused_columns(dataset, descriptionNone)/_get_collator_with_removed_columns(...)移除不需要的列sft_trainer._get_num_items_in_batch(batch_samples, device)/get_batch_samples(epoch_iterator, num_batches, device)token 计数/累积sft_trainer.set_initial_training_values(args, dataloader)算 epoch / step / batch 等初值sft_trainer.get_total_train_batch_size(args)/get_sp_size()/get_cp_size()/get_tp_size()各种并行维度尺寸sft_trainer._inner_training_loop(...)/_run_epoch(...)/_prepare_for_training(...)/_finalize_training(...)训练主循环拆分sft_trainer._maybe_log_save_evaluate(...)/_evaluate(...)/_determine_best_metric(...)日志/评估/最优判定sft_trainer._save(output_dirNone, state_dictNone)/_save_checkpoint(model, trial)保存底层实现sft_trainer._load_from_checkpoint(resume_from_checkpoint, modelNone)/_load_best_model()加载 checkpointsft_trainer._get_output_dir(trial)/_save_rng_state(output_dir)/_save_optimizer_and_scheduler(output_dir)/_save_scaler(output_dir)checkpoint 子步骤sft_trainer._load_rng_state(checkpoint)/_load_optimizer_and_scheduler(checkpoint)/_load_scaler(checkpoint)/_load_callback_state()恢复子步骤sft_trainer._issue_warnings_after_load(load_result)加载后的 missing/unexpected key 警告sft_trainer._track_num_input_tokens(inputs)/_clip_grad_norm(model)/_get_grad_norm(model, grad_normNone)训练统计/梯度sft_trainer._mixed_mesh_grad_norm(model, max_norm)/_has_mixed_mesh_grads(model)混合 device mesh 的梯度裁剪/normsft_trainer._sync_replicated_trainable_parameters(model)同步分片加载模型后新增的可训练参数PEFT adaptersft_trainer._update_auto_batch_size(batch_size)auto_find_batch_size时更新 batch sizesft_trainer.create_accelerator_and_postprocess()/_build_accelerator_args(**kwargs)/_validate_args()accelerator 初始化sft_trainer.call_model_init(trialNone)/_hp_search_setup(trial)/_report_to_hp_search(...)/_tune_save_checkpoint(checkpoint_dir)超参搜索sft_trainer._push_from_checkpoint(checkpoint_folder)/_finish_current_push()Hub 推送来自_BaseTrainer方法作用sft_trainer._send_telemetry()匿名上报rank 0 才发sft_trainer.create_model_card(model_nameNone, dataset_nameNone, tagsNone)生成README.md模型卡覆盖 Trainer 版本签名更少来自SFTTrainer的新增/覆盖方法方法类型作用sft_trainer.compute_loss(...)覆盖强制use_cacheFalse、MoEoutput_router_logits、fused LM head、nll/dft、entropy/mean_token_accuracy/num_tokens/aux_loss 记录启用loss_typedft/label_smoothing_factor0/compute_loss_func时会走额外 forward 拿完整 logitssft_trainer.training_step(...)覆盖with self.maybe_activation_offload_context: return super().training_step(...)sft_trainer.prediction_step(...)覆盖只在需要 logits 时让compute_loss返回 outputs省一次 forwardsft_trainer.evaluate(...)覆盖对直接传入的 eval_dataset 也走_prepare_dataset并调用_reject_skip_prepare_without_labels做安全检查sft_trainer.log(...)覆盖把_metrics均值并入 logseval 时加eval_前缀然后super().log()并清空_metrics[mode]sft_trainer._save_checkpoint(model, trial)覆盖保存前create_model_card(model_name...)然后super()._save_checkpoint()sft_trainer._set_signature_columns_if_needed()覆盖文本[input_ids,labels,seq_lengths]VLM[messages,prompt,completion,image,images]sft_trainer._prepare_dataset(dataset, processing_class, args, packing, formatting_func, dataset_name)新增数据集核心预处理chat 模板、EOS、tokenize、mask→labels、截断、过滤全 mask 样本、packing、shufflesft_trainer._reject_skip_prepare_without_labels(datasets, data_collator)新增skip_prepare_datasetTrue但有 mask 列而无labels时抛错补充SFTTrainer.__init__末尾还有self.model.add_model_tags(self._tag_names)会给模型打上trl/sft标签可通过sft_trainer.model.model_tags查看。四、日常最常用的属性速查sft_trainer.args—— 改学习率、batch size、output_dir、save_steps等类型是SFTConfigsft_trainer.state——global_step、epoch、log_history、best_model_checkpoint、best_metric、max_steps、num_input_tokens_seensft_trainer.model/sft_trainer.model_wrapped—— 取 adapter、查参数sft_trainer.accelerator—— 设备、进程数、is_main_processsft_trainer.train_dataset/sft_trainer.eval_dataset—— 检查预处理结果sft_trainer.processing_class/sft_trainer._tokenizer—— tokenizersft_trainer.optimizer/sft_trainer.lr_scheduler——train()之后才有值sft_trainer.callback_handler—— 自定义回调挂载点sft_trainer.control——should_save、should_evaluate、should_training_stopsft_trainer.is_deepspeed_enabled/sft_trainer.is_fsdp_enabled—— 判断并行后端sft_trainer._metrics—— 训练/评估中间指标log()后会 clearsft_trainer.padding_free/sft_trainer.completion_only_loss/sft_trainer.aux_loss_enabled—— SFT 行为开关的实际生效值五、日常最常用的方法速查sft_trainer.train()—— 训练sft_trainer.evaluate()—— 评估sft_trainer.predict(test_dataset)—— 预测sft_trainer.save_model(path)—— 保存PEFT 存 adaptersft_trainer.push_to_hub(...)—— 推 Hubsft_trainer.create_model_card(...)—— 生成模型卡sft_trainer.add_callback(...)/remove_callback(...)—— 回调sft_trainer.get_train_dataloader()/get_eval_dataloader()—— 自己检查 batchsft_trainer.evaluation_loop(...)—— 需要自定义评估循环时直接复用sft_trainer.end()—— 脚本最后销毁进程组写子类时 overridecompute_loss()、prediction_step()、create_optimizer()/create_scheduler()、_prepare_dataset()、_set_signature_columns_if_needed()六、一句话总结sft_trainer这个实例的能力 Trainer的全部通用属性/方法args、model、state、control、accelerator、train/evaluate/predict/save_model/push_to_hub、evaluation_loop、各类_xxx钩子 _BaseTrainer的少量补充_send_telemetry、覆盖版create_model_card、loss_is_scaled_for_ga兼容处理 SFTTrainer的 SFT 专属扩展_tokenizer、_is_vlm、_is_vision_dataset、padding_free、chat_template、completion_only_loss、_metrics、aux_loss_enabled、router_aux_loss_coef、_total_train_tokens、_tp_size等属性覆盖的compute_loss/training_step/prediction_step/evaluate/log/_save_checkpoint/_set_signature_columns_if_needed新增的_prepare_dataset/_reject_skip_prepare_without_labels。sft_trainer.save_model()保存的是什么时候的状态load_best_model_at_endFalse时sft_trainer.save_model(r../../model/SFT)保存的就是训练结束后最后一个 step 的 adapter 状态。但需要特别注意的是它不一定等于“最优”状态。这个最终保存的 adapter 具体与以下几个关键因素强相关与load_best_model_at_end的设置直接相关这是决定最终保存质量的核心开关你的设置load_best_model_at_endFalse结果Trainer不会在训练结束时自动回滚到验证集 loss 最低的那个 checkpoint。save_model()保存的就是最后一个 epoch 走完时、内存中当前的权重。如果模型在最后几个 step 出现了过拟合或 loss 震荡上升你保存的就是一个“变差”了的版本。对比如果设为True且配合 eval_strategyTrainer 会在训练结束前自动把最佳 checkpoint 的权重加载回内存此时save_model()保存的才是最优状态。与save_strategy和save_steps解耦save_strategystepssave_steps5控制的是训练过程中中间 checkpoint 的保存频率。save_model()是你在训练循环之外手动调用的它不受这两个参数限制。即使最后一个 step 不是 5 的倍数它依然会保存当前精确状态。中间保存的 checkpoint 位于output_dir../../output/SFT而save_model()保存到了独立的../../model/SFT两者路径和用途完全不同。⚠️ 补充说明save_model()依赖于训练正常完成并执行到该行代码。若训练中途因 OOM、断电等原因崩溃该方法不会执行此时唯一的恢复来源是output_dir中已保存的 checkpoint。与 Tokenizer / Config 的对齐状态相关如你代码注释所述tokenizer 的eos_token_id248046覆盖了 model config 原始的248044。save_model()会将这份已被 Trainer 对齐修改后的generation_config.json和tokenizer_config.json一并写入../../model/SFT。关键点这意味着该 adapter 目录是“自包含”的。即使原始基座模型路径下的 config 被还原或更改从这个目录加载时依然会使用训练时正确的 EOS token ID。 实践建议由于你关闭了load_best_model_at_end且没有验证集建议在save_model()之前增加一步人工确认# 训练完成后检查最后几步的 loss 是否稳定# 如果 loss 已经发散或明显高于中间 checkpoint应手动加载更优的 checkpoint 再保存importosfrompeftimportPeftModel# 方案A信任最后状态仅当 loss 曲线平稳收敛时sft_trainer.save_model(r../../model/SFT)# 方案B从中间 checkpoint 加载更优状态后再保存推荐# best_checkpoint r../../output/SFT/checkpoint-xx # 根据日志选择 loss 最低的# peft_model PeftModel.from_pretrained(model, best_checkpoint)# peft_model.save_pretrained(r../../model/SFT)总结在你当前的配置下save_model() 训练终止时刻的内存快照 PEFT 默认的 fp32 精度保存 对齐后的 token/config 元数据。它忠实反映了训练终态但不保证是最优态同时需确保训练正常完成否则应回退使用output_dir中的 checkpoint。