""" Fine-tune Nemotron Nano 12B v2 VL using QLoRA on AWS service knowledge. Run on AWS (EC2 with GPU or SageMaker). """ import torch from datasets import load_dataset from peft import LoraConfig, get_peft_model, prepare_model_for_kbit_training from transformers import ( AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig, TrainingArguments, ) from trl import SFTTrainer # --- Config --- BASE_MODEL = "nvidia/Llama-3.1-Nemotron-Nano-4B-v1.1" DATA_PATH = "training/data/train.jsonl" OUTPUT_DIR = "training/output" MAX_SEQ_LENGTH = 4096 # --- Quantization (4-bit for QLoRA) --- bnb_config = BitsAndBytesConfig( load_in_4bit=True, bnb_4bit_quant_type="nf4", bnb_4bit_compute_dtype=torch.bfloat16, bnb_4bit_use_double_quant=True, ) # --- Load model and tokenizer --- print(f"Loading base model: {BASE_MODEL}") tokenizer = AutoTokenizer.from_pretrained(BASE_MODEL, trust_remote_code=True) tokenizer.pad_token = tokenizer.eos_token model = AutoModelForCausalLM.from_pretrained( BASE_MODEL, quantization_config=bnb_config, device_map="auto", trust_remote_code=True, ) model = prepare_model_for_kbit_training(model) # --- LoRA config --- lora_config = LoraConfig( r=16, lora_alpha=32, lora_dropout=0.05, bias="none", task_type="CAUSAL_LM", target_modules=["q_proj", "k_proj", "v_proj", "o_proj"], ) model = get_peft_model(model, lora_config) model.print_trainable_parameters() # --- Load dataset --- dataset = load_dataset("json", data_files=DATA_PATH, split="train") def formatting_func(example): """Format messages into a single text string for SFTTrainer.""" return tokenizer.apply_chat_template( example["messages"], tokenize=False, add_generation_prompt=False ) # --- Training args --- training_args = TrainingArguments( output_dir=OUTPUT_DIR, num_train_epochs=3, per_device_train_batch_size=2, gradient_accumulation_steps=8, learning_rate=2e-4, warmup_steps=10, logging_steps=10, save_steps=100, save_total_limit=2, bf16=True, optim="paged_adamw_8bit", report_to="none", ) # --- Train --- trainer = SFTTrainer( model=model, tokenizer=tokenizer, train_dataset=dataset, formatting_func=formatting_func, args=training_args, max_seq_length=MAX_SEQ_LENGTH, ) print("Starting training...") trainer.train() # Save adapter trainer.save_model(OUTPUT_DIR) tokenizer.save_pretrained(OUTPUT_DIR) print(f"Training complete. Adapter saved to {OUTPUT_DIR}")