Files
modelscope--ms-swift/swift/megatron/pipelines/train/sft.py
T
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

98 lines
3.9 KiB
Python

# Copyright (c) ModelScope Contributors. All rights reserved.
import os
import torch
import torch.distributed as dist
from dataclasses import asdict
from transformers.utils import is_torch_npu_available
from typing import List, Optional, Union
from swift.megatron.arguments import MegatronSftArguments
from swift.megatron.trainers import MegatronEmbeddingTrainer, MegatronRerankerTrainer, MegatronTrainer
from swift.pipelines import SwiftSft
from swift.utils import append_to_jsonl, get_logger, is_last_rank, plot_images
if is_torch_npu_available():
# Enable Megatron on Ascend NPU
from mindspeed.megatron_adaptor import repatch
from swift.model.npu_patcher import patch_mindspeed_te_cp_implementation
else:
repatch = None
patch_mindspeed_te_cp_implementation = None
logger = get_logger()
class MegatronSft(SwiftSft):
args_class = MegatronSftArguments
args: args_class
def prepare_trainer(self):
args = self.args
if args.task_type == 'embedding':
return MegatronEmbeddingTrainer(self.args, self.template)
elif args.task_type in {'reranker', 'generative_reranker'}:
return MegatronRerankerTrainer(self.args, self.template)
else:
return MegatronTrainer(self.args, self.template)
def _set_seed(self):
pass
def __init__(self, args: Optional[Union[List[str], MegatronSftArguments]] = None) -> None:
self.train_msg = {}
super(SwiftSft, self).__init__(args)
args = self.args
if repatch is not None:
megatron_args = asdict(self.args)
if args.attention_backend != 'local':
# MindSpeed requires passing `use_flash_attn` to Megatron
# to enable flash attention on Ascend NPU.
args.use_flash_attn = True
megatron_args['use_flash_attn'] = True
patch_mindspeed_te_cp_implementation(megatron_args)
repatch(megatron_args)
template_cls = args.template_meta.template_cls
if args.model_meta.is_multimodal and template_cls and template_cls.use_model:
kwargs = {'return_dummy_model': True}
else:
kwargs = {'load_model': False}
with torch.device('meta'):
self.model, self.processor = args.get_model_processor(**kwargs, download_model=args.mcore_model is None)
self._prepare_template()
args.save_args(args.output_dir)
self.template.use_megatron = True
def run(self):
args = self.args
train_dataset, val_dataset = self._prepare_dataset()
args.init_iters(train_dataset, val_dataset)
trainer = self.prepare_trainer()
try:
trainer.train(train_dataset, val_dataset)
finally:
state = trainer.state
self._handle_trainer_state(trainer, is_last_rank())
self.train_msg.update({
'last_model_checkpoint': state.last_model_checkpoint,
'best_model_checkpoint': state.best_model_checkpoint,
'best_metric': state.best_metric,
})
# Visualization
if is_last_rank():
images_dir = os.path.join(args.output_dir, 'images')
logger.info(f'images_dir: {images_dir}')
plot_images(images_dir, args.tensorboard_dir)
jsonl_path = os.path.join(args.output_dir, 'logging.jsonl')
append_to_jsonl(jsonl_path, self.train_msg, strict=False, write_on_rank='last')
# Exceptions may cause the process to hang, preventing the exception from being propagated.
# Therefore, destroy_process_group() should not be placed inside the finally block.
if dist.is_initialized():
dist.destroy_process_group()
return self.train_msg
def megatron_sft_main(args: Optional[Union[List[str], MegatronSftArguments]] = None):
return MegatronSft(args).main()