Files
wehub-resource-sync a203934033
Lint test / lint (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:34:58 +08:00

73 lines
2.7 KiB
Python

# Copyright (c) ModelScope Contributors. All rights reserved.
# Part of the implementation is borrowed from huggingface/transformers.
import torch
from contextlib import contextmanager
from functools import wraps
from peft import PeftModel
from transformers import Trainer as HfTrainer
from swift.sequence_parallel import sequence_parallel
from swift.utils import get_logger
from .arguments import TrainingArguments
from .mixin import DataLoaderMixin, SwiftMixin
logger = get_logger()
class Trainer(SwiftMixin, DataLoaderMixin, HfTrainer):
args: TrainingArguments
def _prepare_inputs(self, inputs):
inputs = super()._prepare_inputs(inputs)
# For tasks whose `labels` are per-sample (e.g. seq_cls/reranker/embedding), we must NOT let
# SP code treat them as token labels. We detect that case by `labels.dim() == 1` and temporarily
# remove labels during `prepare_inputs`.
if self.template.sequence_parallel_size > 1:
labels = inputs.get('labels', None)
pop_labels = isinstance(labels, torch.Tensor) and labels.dim() == 1
if pop_labels:
labels = inputs.pop('labels', None)
try:
sequence_parallel.prepare_inputs(inputs)
finally:
if pop_labels and labels is not None:
inputs['labels'] = labels
return inputs
@contextmanager
def _patch_loss_function(self):
model = self.model
if isinstance(model, PeftModel):
model = model.model
model_cls = model.__class__
if not hasattr(model_cls, 'loss_function'):
yield
return
loss_function = model.loss_function
_old_loss_function = model_cls.loss_function
@staticmethod
@wraps(loss_function)
def new_loss_function(logits, labels, **kwargs):
labels = labels.to(logits.device) # fix device_map
return loss_function(logits=logits, labels=labels, **kwargs)
model_cls.loss_function = new_loss_function
try:
yield
finally:
model_cls.loss_function = _old_loss_function
def train(self, *args, **kwargs):
with self._patch_loss_function():
return super().train(*args, **kwargs)
def compute_loss(self, model, inputs, return_outputs=False, num_items_in_batch=None):
loss, outputs = super().compute_loss(model, inputs, return_outputs=True)
if inputs.get('labels') is not None:
self._compute_acc(outputs, inputs['labels'])
if num_items_in_batch is not None and self.model_accepts_loss_kwargs:
loss = loss / self.args.gradient_accumulation_steps
return (loss, outputs) if return_outputs else loss