44import argparse
55from datasets import load_dataset
66from torch .utils .data import DataLoader , DistributedSampler
7- from transformers import AutoModelForCausalLM , AutoTokenizer , default_data_collator
7+ from transformers import AutoConfig , AutoModelForCausalLM , AutoTokenizer , default_data_collator
88from transformers .integrations .deepspeed import HfDeepSpeedConfig
99import json
1010import random
@@ -28,6 +28,15 @@ def set_seed(seed):
2828
2929
3030DATASET_REGISTRY = {
31+ "tatsu-lab/alpaca" : {
32+ "split" : "train" ,
33+ "preprocessor" : "alpaca" ,
34+ "field_map" : {
35+ "instruction" : "instruction" ,
36+ "input" : "input" ,
37+ "output" : "output" ,
38+ },
39+ },
3140 "sahil2801/CodeAlpaca-20k" : {
3241 "split" : "train" ,
3342 "preprocessor" : "alpaca" ,
@@ -251,9 +260,81 @@ def _save_weights(model_engine, tokenizer, output_dir, step, keep_last=2):
251260 print_r (0 , f"Saved checkpoint to { ckpt_dir } " )
252261
253262
263+ def _save_deepspeed_checkpoint (model_engine , output_dir , step , epoch , step_in_epoch ):
264+ """Save model, optimizer, scheduler, and resume position for exact continuation."""
265+ tag = f"step_{ step } "
266+ client_state = {
267+ "global_step" : step ,
268+ "epoch" : epoch ,
269+ "step_in_epoch" : step_in_epoch ,
270+ }
271+ model_engine .save_checkpoint (output_dir , tag = tag , client_state = client_state )
272+ print_r (0 , f"Saved DeepSpeed checkpoint to { os .path .join (output_dir , tag )} " )
273+
274+
275+ def _load_deepspeed_checkpoint (model_engine , checkpoint_dir , tag ):
276+ load_path , client_state = model_engine .load_checkpoint (checkpoint_dir , tag = tag )
277+ if load_path is None :
278+ raise RuntimeError (f"DeepSpeed checkpoint was not loaded: { checkpoint_dir } /{ tag } " )
279+ return client_state or {}
280+
281+
282+ def _first_tensor (value ):
283+ if torch .is_tensor (value ):
284+ return value
285+ if isinstance (value , (tuple , list )):
286+ for item in value :
287+ tensor = _first_tensor (item )
288+ if tensor is not None :
289+ return tensor
290+ if isinstance (value , dict ):
291+ for item in value .values ():
292+ tensor = _first_tensor (item )
293+ if tensor is not None :
294+ return tensor
295+ return None
296+
297+
298+ def _register_nonfinite_hooks (model ):
299+ state = {"found" : False }
300+ handles = []
301+
302+ def make_hook (name ):
303+ def hook (_module , _inputs , output ):
304+ if state ["found" ] or dist .get_rank () != 0 :
305+ return
306+ tensor = _first_tensor (output )
307+ if tensor is not None and not torch .isfinite (tensor ).all ().item ():
308+ state ["found" ] = True
309+ max_value = tensor .float ().abs ().max ().item ()
310+ print_r (0 , f"First non-finite module output: { name } , shape={ tuple (tensor .shape )} , abs_max={ max_value } " )
311+ return hook
312+
313+ for name , module in model .named_modules ():
314+ handles .append (module .register_forward_hook (make_hook (name )))
315+ return handles
316+
317+
318+ def _reset_rotary_embeddings (model ):
319+ for module in model .modules ():
320+ rotary_emb = getattr (module , "rotary_emb" , None )
321+ if rotary_emb is None or not hasattr (rotary_emb , "inv_freq" ):
322+ continue
323+ inv_freq = 1.0 / (
324+ rotary_emb .base
325+ ** (torch .arange (0 , rotary_emb .dim , 2 , dtype = torch .float32 ) / rotary_emb .dim )
326+ )
327+ rotary_emb .register_buffer ("inv_freq" , inv_freq , persistent = False )
328+ rotary_emb .max_seq_len_cached = None
329+
330+
254331def main (args ):
255332 logging .basicConfig (level = logging .INFO , filename = "pytorch_log.txt" )
256333 set_seed (args .seed )
334+ # Moonlight's checked-in modeling file imports this legacy helper.
335+ from transformers .utils import import_utils
336+ if not hasattr (import_utils , "is_torch_fx_available" ):
337+ import_utils .is_torch_fx_available = lambda : True
257338
258339 # override batch size in ds_config
259340 with open (args .deepspeed_config , "r" ) as f :
@@ -266,6 +347,10 @@ def main(args):
266347 tokenizer = AutoTokenizer .from_pretrained (args .model_name , trust_remote_code = True )
267348 if tokenizer .pad_token is None :
268349 tokenizer .pad_token = tokenizer .eos_token
350+ model_config = AutoConfig .from_pretrained (args .model_name , trust_remote_code = True )
351+ if (isinstance (model_config .rope_scaling , dict )
352+ and model_config .rope_scaling .get ("rope_type" ) == "default" ):
353+ model_config .rope_scaling = None
269354
270355 try :
271356 import flash_attn
@@ -274,10 +359,12 @@ def main(args):
274359 attn_impl = None
275360 model = AutoModelForCausalLM .from_pretrained (
276361 args .model_name ,
362+ config = model_config ,
277363 torch_dtype = torch .bfloat16 ,
278364 trust_remote_code = True ,
279365 attn_implementation = attn_impl ,
280366 )
367+ _reset_rotary_embeddings (model )
281368 model .config .use_cache = False
282369 model .gradient_checkpointing_enable ()
283370
@@ -347,6 +434,8 @@ def main(args):
347434
348435 train_sampler = DistributedSampler (
349436 tokenized_train_dataset ,
437+ num_replicas = dist .get_world_size (),
438+ rank = dist .get_rank (),
350439 shuffle = True ,
351440 seed = args .seed ,
352441 )
@@ -360,7 +449,16 @@ def main(args):
360449 )
361450
362451 model_engine .train ()
452+ nonfinite_hooks = _register_nonfinite_hooks (model_engine .module ) if args .debug_nonfinite else []
363453 global_step = 0
454+ start_epoch = 0
455+ start_step_in_epoch = 0
456+ if args .resume_tag is not None :
457+ client_state = _load_deepspeed_checkpoint (model_engine , args .resume_dir or args .output_dir , args .resume_tag )
458+ global_step = int (client_state .get ("global_step" , 0 ))
459+ start_epoch = int (client_state .get ("epoch" , 0 ))
460+ start_step_in_epoch = int (client_state .get ("step_in_epoch" , 0 ))
461+ print_r (0 , f"Resumed checkpoint at global step { global_step } " )
364462 total_time = 0
365463 total_count = 0
366464
@@ -388,11 +486,13 @@ def main(args):
388486 wandb .init (project = "deepspeed_finetune_demo" , name = args .wandb_name )
389487
390488 global_samples = 0
391- for epoch in range (args .num_train_epochs ):
489+ for epoch in range (start_epoch , args .num_train_epochs ):
392490 print_r (0 , f"Starting epoch { epoch + 1 } /{ args .num_train_epochs } " )
393491 train_dataloader .sampler .set_epoch (epoch )
394492
395493 for step , batch in enumerate (train_dataloader ):
494+ if epoch == start_epoch and step < start_step_in_epoch :
495+ continue
396496 if prof != None and global_step == args .profile_start :
397497 prof .start ()
398498 if prof != None and global_step - args .profile_start == args .profile_steps :
@@ -409,9 +509,18 @@ def main(args):
409509 batch = {k : v .to (model_engine .device ) for k , v in batch .items ()}
410510 outputs = model_engine (** batch )
411511 loss = outputs .loss
512+ if global_step == 0 and dist .get_rank () == 0 :
513+ valid_labels = int ((batch ["labels" ][:, :- 1 ] != - 100 ).sum ().item ())
514+ finite_params = all (torch .isfinite (param ).all ().item () for param in model_engine .module .parameters ())
515+ finite_logits = torch .isfinite (outputs .logits ).all ().item ()
516+ logits_max = outputs .logits .float ().abs ().max ().item ()
517+ print_r (0 , f"First batch valid shifted labels: { valid_labels } , finite params: { finite_params } , "
518+ f"finite logits: { finite_logits } , logits abs max: { logits_max :.4g} , "
519+ f"finite loss: { torch .isfinite (loss ).item ()} " )
412520
413521 model_engine .backward (loss )
414522 model_engine .step ()
523+ global_step += 1
415524 global_samples += model_engine .train_batch_size ()
416525
417526 step_time = time .time () - step_start_time
@@ -460,8 +569,9 @@ def main(args):
460569 and global_step % args .checkpoint_steps == 0
461570 and save_checkpoint_p
462571 ):
463- _save_weights (model_engine , tokenizer , args .output_dir , global_step )
464- global_step += 1
572+ if not args .skip_weight_export :
573+ _save_weights (model_engine , tokenizer , args .output_dir , global_step )
574+ _save_deepspeed_checkpoint (model_engine , args .output_dir , global_step , epoch , step + 1 )
465575 if prof != None :
466576 prof .step ()
467577 if args .max_steps > 0 and global_step >= args .max_steps :
@@ -473,11 +583,16 @@ def main(args):
473583 if args .max_steps > 0 and global_step >= args .max_steps :
474584 break
475585
586+ for handle in nonfinite_hooks :
587+ handle .remove ()
588+
476589 if args .bench_start >= 0 and args .bench_steps > 0 :
477590 print_r (0 , f"Average iteration time = { total_time / total_count } " )
478591
479- if save_checkpoint_p :
480- _save_weights (model_engine , tokenizer , args .output_dir , global_step )
592+ if save_checkpoint_p and args .save_final_checkpoint :
593+ if not args .skip_weight_export :
594+ _save_weights (model_engine , tokenizer , args .output_dir , global_step )
595+ _save_deepspeed_checkpoint (model_engine , args .output_dir , global_step , epoch , step + 1 )
481596
482597 print_r (0 , "Training complete!" )
483598
@@ -520,6 +635,17 @@ def main(args):
520635 "--checkpoint_steps" , type = int , default = 0 ,
521636 help = "Save a checkpoint every N steps (0 disables); keeps last 2" ,
522637 )
638+ parser .add_argument (
639+ "--resume_tag" , type = str , default = None ,
640+ help = "DeepSpeed checkpoint tag to resume from" ,
641+ )
642+ parser .add_argument (
643+ "--resume_dir" , type = str , default = None ,
644+ help = "Directory containing resume_tag (defaults to output_dir)" ,
645+ )
646+ parser .add_argument ("--skip_weight_export" , action = "store_true" )
647+ parser .add_argument ("--save_final_checkpoint" , action = "store_true" )
648+ parser .add_argument ("--debug_nonfinite" , action = "store_true" )
523649 parser .add_argument (
524650 "--eval_batch_size" , type = int , default = 4 , help = "Eval batch size per rank"
525651 )
0 commit comments