如何在 Llama-Factory 中自定义损失函数?高级用法指南
在大模型微调日益普及的今天,越来越多的实际任务开始暴露出标准训练流程的局限性。比如,你在训练一个金融客服机器人时发现,尽管整体准确率不错,但模型总是'忽略'那些关键却少见的问题——像'账户被冻结怎么办'这类高风险咨询,出现频率低、样本少,结果在交叉熵损失主导下被梯度淹没。这时候,你真正需要的不是更多数据,而是一种能表达业务优先级的损失函数。
这正是 Llama-Factory 作为现代微调框架的价值所在:它不仅让你'跑得起来',更允许你深入到底层训练逻辑,把领域知识、工程经验甚至产品目标,编码进模型的学习过程中。其中最关键的入口之一,就是自定义损失函数。
Llama-Factory 基于 Hugging Face Transformers 构建,底层使用 PyTorch,其训练流程遵循典型的因果语言建模范式。默认情况下,Trainer 类会调用内置的 CrossEntropyLoss 来计算 token 级别的预测误差。这个过程看似固定,实则留出了清晰的扩展点——只要你重写 compute_loss 方法,就能完全接管损失计算逻辑。
这种设计并非偶然。它的核心思想是:训练引擎负责调度和优化,而损失函数定义'什么是对的'。 换句话说,框架管'怎么学',你来决定'学成什么样'。
举个例子,标签平滑(Label Smoothing)是一种常见的正则化技术,用于防止模型对训练标签过度自信。虽然 Hugging Face 的 Trainer 支持通过参数启用,但在某些场景下你需要更细粒度的控制,比如动态调整平滑强度或结合其他监督信号。这时,直接定制 compute_loss 就成了最灵活的选择。
import torch import torch.nn as nn from transformers import Trainer class CustomTrainer(Trainer): def __init__(self, label_smoothing=0.0, **kwargs): super().__init__(**kwargs) self.label_smoothing = label_smoothing self.ce_loss = nn.CrossEntropyLoss(reduction="none") def compute_loss(self, model, inputs, return_outputs=False): labels = inputs.get("labels") outputs = model(**inputs) logits = outputs.get("logits") # Shift for causal language modeling shift_logits = logits[..., :-1, :].contiguous() shift_labels = labels[..., 1:].contiguous() flat_logits = shift_logits.view(-1, shift_logits.size(-1)) flat_labels = shift_labels.view(-1) if self.label_smoothing > : vocab_size = flat_logits.shape[-] with torch.(): true_probs = torch.(flat_logits, self.label_smoothing / (vocab_size - )) true_probs.(, flat_labels.(), - self.label_smoothing) log_probs = torch.(flat_logits, dim=-) loss = (true_probs * log_probs).(dim=-).() else: loss = self.(flat_logits, flat_labels).() return (loss, outputs) if return_outputs else loss

