| """ |
| 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 |
|
|
| |
| 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 |
|
|
| |
| bnb_config = BitsAndBytesConfig( |
| load_in_4bit=True, |
| bnb_4bit_quant_type="nf4", |
| bnb_4bit_compute_dtype=torch.bfloat16, |
| bnb_4bit_use_double_quant=True, |
| ) |
|
|
| |
| 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 = 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() |
|
|
| |
| 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 = 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", |
| ) |
|
|
| |
| 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() |
|
|
| |
| trainer.save_model(OUTPUT_DIR) |
| tokenizer.save_pretrained(OUTPUT_DIR) |
| print(f"Training complete. Adapter saved to {OUTPUT_DIR}") |
|
|