大模型微调 - 训练参数
大模型微调 - 训练参数
flyfish
定义一个 TrainingArguments 对象,用于配置模型训练的具体参数
from transformers import TrainingArguments
args = TrainingArguments(output_dir="./output/Qwen2-0.5B", # 指定训练过程中生成的输出文件(模型、日志等)的保存路径per_device_train_batch_size=4, # 每个设备(如 GPU 或 CPU)上一次训练的批次大小为 4gradient_accumulation_steps=4, # 梯度累积步数。即每累积4个批次才进行一次梯度更新,相当于实际的有效批次大小为 4 * 4 = 16logging_steps=10, # 每训练10步记录一次日志(如损失函数、指标等)num_train_epochs=2, # 训练的轮次,即整个数据集训练两次save_steps=100, # 每训练100步保存一次模型learning_rate=1e-4, # 学习率设定为 0.0001,控制模型参数更新的步幅save_on_each_node=True, # 在分布式训练中,在每个节点上都保存模型gradient_checkpointing=True, # 启用梯度检查点,以减少内存占用,适合大模型训练report_to="none", # 不将训练信息报告给任何监控工具(如 TensorBoard 或 WandB)
)
将所有训练参数输出出来
TrainingArguments(
_n_gpu=1,
accelerator_config={'split_batches': False, 'dispatch_batches': None, 'even_batches': True, 'use_seedable_sampler': True, 'non_blocking': False, 'gradient_accumulation_kwargs': None, 'use_configured_state': False},
adafactor=False,
adam_beta1=0.9,
adam_beta2=0.999,
adam_epsilon=1e-08,
auto_find_batch_size=False,
batch_eval_metrics=False,
bf16=False,
bf16_full_eval=False,
data_seed=None,
dataloader_drop_last=False,
dataloader_num_workers=0,
dataloader_persistent_workers=False,
dataloader_pin_memory=True,
dataloader_prefetch_factor=None,
ddp_backend=None,
ddp_broadcast_buffers=None,
ddp_bucket_cap_mb=None,
ddp_find_unused_parameters=None,
ddp_timeout=1800,
debug=[],
deepspeed=None,
disable_tqdm=False,
dispatch_batches=None,
do_eval=False,
do_predict=False,
do_train=False,
eval_accumulation_steps=None,
eval_delay=0,
eval_do_concat_batches=True,
eval_on_start=False,
eval_steps=None,
eval_strategy=no,
eval_use_gather_object=False,
evaluation_strategy=None,
fp16=False,
fp16_backend=auto,
fp16_full_eval=False,
fp16_opt_level=O1,
fsdp=[],
fsdp_config={'min_num_params': 0, 'xla': False, 'xla_fsdp_v2': False, 'xla_fsdp_grad_ckpt': False},
fsdp_min_num_params=0,
fsdp_transformer_layer_cls_to_wrap=None,
full_determinism=False,
gradient_accumulation_steps=4,
gradient_checkpointing=True,
gradient_checkpointing_kwargs=None,
greater_is_better=None,
group_by_length=False,
half_precision_backend=auto,
hub_always_push=False,
hub_model_id=None,
hub_private_repo=False,
hub_strategy=every_save,
hub_token=<HUB_TOKEN>,
ignore_data_skip=False,
include_inputs_for_metrics=False,
include_num_input_tokens_seen=False,
include_tokens_per_second=False,
jit_mode_eval=False,
label_names=None,
label_smoothing_factor=0.0,
learning_rate=0.0001,
length_column_name=length,
load_best_model_at_end=False,
local_rank=0,
log_level=passive,
log_level_replica=warning,
log_on_each_node=True,
logging_dir=./output/Qwen2-0.5B/runs/Sep12_14-31-58_sisyphus,
logging_first_step=False,
logging_nan_inf_filter=True,
logging_steps=10,
logging_strategy=steps,
lr_scheduler_kwargs={},
lr_scheduler_type=linear,
max_grad_norm=1.0,
max_steps=-1,
metric_for_best_model=None,
mp_parameters=,
neftune_noise_alpha=None,
no_cuda=False,
num_train_epochs=2,
optim=adamw_torch,
optim_args=None,
optim_target_modules=None,
output_dir=./output/Qwen2-0.5B,
overwrite_output_dir=False,
past_index=-1,
per_device_eval_batch_size=8,
per_device_train_batch_size=4,
prediction_loss_only=False,
push_to_hub=False,
push_to_hub_model_id=None,
push_to_hub_organization=None,
push_to_hub_token=<PUSH_TO_HUB_TOKEN>,
ray_scope=last,
remove_unused_columns=True,
report_to=[],
restore_callback_states_from_checkpoint=False,
resume_from_checkpoint=None,
run_name=./output/Qwen2-0.5B,
save_on_each_node=True,
save_only_model=False,
save_safetensors=True,
save_steps=100,
save_strategy=steps,
save_total_limit=None,
seed=42,
skip_memory_metrics=True,
split_batches=None,
tf32=None,
torch_compile=False,
torch_compile_backend=None,
torch_compile_mode=None,
torch_empty_cache_steps=None,
torchdynamo=None,
tpu_metrics_debug=False,
tpu_num_cores=None,
use_cpu=False,
use_ipex=False,
use_legacy_prediction_loop=False,
use_mps_device=False,
warmup_ratio=0.0,
warmup_steps=0,
weight_decay=0.0,
)
简述 解释,更详细的放后面
-
_n_gpu=1
: 使用 1 个 GPU 进行训练。 -
accelerator_config={...}
: 配置模型在加速器(如 GPU、TPU)上的具体行为,影响批次分配、数据采样等。 -
adafactor=False
: 是否使用 Adafactor 优化器。如果设置为True
,则使用 Adafactor 优化器,而不是 AdamW。 -
adam_beta1=0.9, adam_beta2=0.999, adam_epsilon=1e-08
: AdamW 优化器的超参数配置,分别表示一阶、二阶动量的衰减率和防止除零的epsilon
值。 -
auto_find_batch_size=False
: 是否自动寻找合适的批次大小,如果为True
,则会在训练时动态调整批次大小以避免显存溢出。 -
bf16=False, bf16_full_eval=False
: 是否使用bfloat16
精度进行训练和评估。bf16
是一种 16 位浮点精度,适合在支持它的硬件上提升性能。 -
dataloader_pin_memory=True
: 如果设置为True
,数据加载时将内存锁定到 GPU,可能会提高数据加载的速度。 -
dataloader_num_workers=0
: 控制数据加载时使用的线程数。0
表示使用主线程加载数据。 -
ddp_backend=None
: 分布式数据并行(DDP)训练时的后端配置。如果不进行分布式训练,可以保持None
。 -
do_eval=False, do_predict=False, do_train=False
: 控制是否进行训练、评估或预测。如果设置为True
,则执行对应操作。 -
eval_steps=None, eval_strategy=no
: 指定评估的策略和频率。no
表示不进行评估。 -
fp16=False, fp16_opt_level=O1
: 控制是否使用float16
精度进行训练,并指定混合精度的优化级别。O1
表示对部分模型层应用混合精度。 -
gradient_accumulation_steps=4
: 梯度累积的步数。在这个例子中,每累积 4 步梯度后,模型才进行一次权重更新,相当于增大了有效批次大小。 -
gradient_checkpointing=True
: 启用梯度检查点,以减少内存占用,适合大模型训练。 -
learning_rate=0.0001
: 设置学习率为0.0001
。学习率决定模型参数更新的速度。 -
local_rank=0
: 在多 GPU 训练中表示当前 GPU 的索引号。0
表示主 GPU。 -
logging_dir=./output/Qwen2-0.5B/runs/...
: 指定日志保存的目录。日志包含训练过程中的各种信息,如损失值、评估指标等。 -
logging_steps=10
: 每训练 10 步记录一次日志。 -
max_grad_norm=1.0
: 梯度裁剪的最大范数,用来防止梯度爆炸。 -
num_train_epochs=2
: 训练的轮次,模型将训练 2 个完整的 epoch。 -
output_dir=./output/Qwen2-0.5B
: 输出目录,用于保存模型和其他输出文件。 -
per_device_eval_batch_size=8, per_device_train_batch_size=4
: 每个设备(如 GPU)上的批次大小。训练时每批次处理 4 个样本,评估时每批次处理 8 个样本。 -
save_steps=100, save_strategy=steps
: 每 100 步保存一次模型,保存策略为基于步数。 -
seed=42
: 设置随机种子,以确保实验的可重复性。 -
torch_compile=False
: 是否启用 Torch 编译功能,以提升模型推理和训练速度。 -
warmup_steps=0
: 学习率预热的步数。在训练开始时,学习率从 0 线性增长到设定值,经过warmup_steps
后变为正常的学习率。 -
weight_decay=0.0
: 权重衰减系数,用于防止过拟合。
accelerator_config={...}
的解释
accelerator_config={'split_batches': False, 'dispatch_batches': None, 'even_batches': True, 'use_seedable_sampler': True, 'non_blocking': False, 'gradient_accumulation_kwargs': None, 'use_configured_state': False},
- split_batches: False
作用: 控制是否将批次拆分到不同设备上(如多 GPU)。
解释: 当设为 False 时,批次不会被拆分,整个批次会分配到单个设备上。如果设为 True,则会在多设备上拆分批次以并行处理。 - dispatch_batches: None
作用: 控制是否分配批次给特定设备。
解释: 如果提供自定义的批次分配方法,可以在这里指定。None 意味着使用默认的批次分配策略。这个参数在多设备训练时可以用来微调批次的分发方式。 - even_batches: True
作用: 控制是否确保每个设备上的批次大小一致。
解释: 当设为 True 时,批次会被均匀地分配到每个设备上,确保每个设备处理的样本数量相等。这可以帮助避免因批次不均导致的负载不平衡问题。 - use_seedable_sampler: True
作用: 控制是否使用可设定种子的采样器。
解释: 设为 True 时,数据采样过程将是可重复的,即使在分布式训练中。通过设定随机种子,能够确保每次运行的采样过程一致,便于结果的可重现性。 - non_blocking: False
作用: 控制数据从 CPU 到 GPU 的传输是否为非阻塞操作。
解释: 当设为 False 时,数据传输是阻塞的,模型会等待数据传输完成后继续执行。如果设为 True,数据传输会是异步的,提升计算效率,但可能增加计算的复杂度。 - gradient_accumulation_kwargs: None
作用: 控制梯度累积的其他高级配置。
解释: 如果有自定义的梯度累积逻辑(如自定义的超参数),可以在这里配置。None 表示使用默认的梯度累积配置。 - use_configured_state: False
作用: 控制是否使用预先配置的状态进行训练。
解释: 如果设为 True,将使用已经配置好的模型状态(如检查点等)来控制训练的执行。False 表示不使用这些预设状态,可能适用于从头开始训练的场景。
梯度检查点的解释
梯度检查点(Gradient Checkpointing) 是一种用于减少显存使用 的技术,特别适用于训练大型深度学习模型 。它通过在训练过程中节省部分中间激活值的存储,来降低内存占用,以便在显存有限的情况下,能够使用更大的模型或更大的批次大小进行训练。
原理
在正常情况下,深度学习模型在前向传播 时会计算激活值(即每一层的输出),并将这些激活值保存起来,以便在反向传播 阶段计算梯度时使用。随着模型层数的增加和数据量的增大,保存这些激活值需要大量的显存。梯度检查点技术 改变了这个流程:
-
前向传播 时,模型不会保存所有的中间激活值,而是只保存一部分关键的激活值(检查点)。
-
在反向传播 时,如果某一层需要激活值来计算梯度,而前向传播时没有保存,模型会重新计算那些丢弃的激活值,进行必要的反向传播计算。
这样做的好处是:
通过减少保存的激活值,节省了大量显存。
代价是反向传播时需要重新计算某些丢失的激活值,因此会增加一定的计算成本 ,导致训练时间稍微变长。
例子
假设一个 4 层的模型,在没有梯度检查点时,前向传播计算每层的激活值,并保存下来:
Layer 1 -> Layer 2 -> Layer 3 -> Layer 4
保存所有激活值:A1, A2, A3, A4
使用梯度检查点时,可能只保存关键的激活值(比如 Layer 1 和 Layer 4),并在反向传播时重新计算其他的激活值:
Layer 1 -> Layer 2 -> Layer 3 -> Layer 4
只保存 A1 和 A4
反向传播时重新计算 A2 和 A3
优点 :
大幅降低显存占用,使得较小显存的设备也可以训练大型模型。
允许在同样的硬件条件下使用更大的批次(Batch size),从而提高训练稳定性。
缺点 :
需要在反向传播时重新计算一些前向激活值,增加了计算量,导致训练速度可能变慢。
gradient_accumulation_steps=4的解释
梯度累积 是一种在深度学习训练中使用的技术,尤其在显存较小的设备上非常有用。它允许在多个小批次(mini-batches)上累积梯度,然后再执行一次参数更新。这相当于增大了有效的批次大小,从而能够在有限的显存条件下模拟更大批次的训练效果。
梯度累积的原理:
通常,深度学习模型在每个批次中都会执行以下步骤:
-
前向传播 :通过神经网络计算出输出值。
-
计算损失 :根据模型输出和实际标签计算损失。
-
反向传播 :计算损失相对于模型参数的梯度。
-
更新参数 :根据优化算法(如 Adam 或 SGD)使用这些梯度更新模型的参数。
而在梯度累积 时,模型不会在每个批次中立即更新参数,而是会等到累积了多个批次的梯度之后再更新一次参数。
具体流程:
假设 gradient_accumulation_steps=4
,也就是每 4 个批次累积一次梯度再更新模型权重。具体过程如下:
-
第 1 步 :前向传播 -> 反向传播 -> 累积梯度,但不更新参数。
-
第 2 步 :前向传播 -> 反向传播 -> 累积梯度,但不更新参数。
-
第 3 步 :前向传播 -> 反向传播 -> 累积梯度,但不更新参数。
-
第 4 步 :前向传播 -> 反向传播 -> 累积梯度,然后使用这 4 个批次累积的梯度更新模型参数。
换句话说,在每次更新时,模型的有效批次大小是实际批次大小的 gradient_accumulation_steps
倍。
梯度累积的好处:
- 减少显存占用 :通过将批次大小减小,可以适应显存较小的 GPU;累积多个小批次的梯度再进行一次更新,相当于模拟了更大的批次大小。
- 提高训练稳定性 :较大的批次通常有更稳定的梯度估计,这有助于提高训练的稳定性,尤其是在深度学习中。
示例:
假设原本你想使用批次大小为 16,但显存有限,不能直接支持。在这种情况下,你可以设置 per_device_train_batch_size=4
,并使用 gradient_accumulation_steps=4
来实现相当于有效批次大小为 16 的训练过程。
from transformers import TrainingArgumentstraining_args = TrainingArguments(per_device_train_batch_size=4, # 每个设备上的批次大小为4gradient_accumulation_steps=4, # 每4个小批次累积一次梯度num_train_epochs=2, # 训练2个epochlearning_rate=2e-5, # 设置学习率
)
在这种情况下,虽然每个批次处理 4 个样本,但通过累积 4 个批次的梯度,模型每次更新权重时相当于处理了 16 个样本。