Instructions to use Niarfe/qwen2.5-7b-positional-reasoning with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- PEFT
How to use Niarfe/qwen2.5-7b-positional-reasoning with PEFT:
from peft import PeftModel from transformers import AutoModelForCausalLM base_model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen2.5-7B-Instruct") model = PeftModel.from_pretrained(base_model, "Niarfe/qwen2.5-7b-positional-reasoning") - Notebooks
- Google Colab
- Kaggle
| """QLoRA fine-tuning of Qwen2.5-7B-Instruct on the positional reasoning dataset. | |
| Three hyperparameter combos (see Deliverable4/README.md training plan): | |
| A: lr 1e-5, target q_proj/v_proj (conservative — HW6 baseline, expected weak) | |
| B: lr 1e-4, target q_proj/v_proj (TRL-recommended adapter lr) | |
| C: lr 2e-4, target all-linear (QLoRA-style full coverage) | |
| Usage (on the GPU box, inside a venv with transformers/trl/peft/bitsandbytes): | |
| python3 train_qlora.py A # or B, C | |
| nohup python3 train_qlora.py B > combo_B.log 2>&1 & # survives ssh disconnects | |
| Writes to ./runs/<combo>/: checkpoints, best model adapter, metrics.json | |
| (train/eval loss history) for display in the check-in notebook. | |
| """ | |
| import json | |
| import os | |
| import sys | |
| import torch | |
| from datasets import Dataset | |
| from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig | |
| from peft import LoraConfig, get_peft_model, prepare_model_for_kbit_training | |
| from trl import SFTConfig, SFTTrainer | |
| MODEL_ID = "Qwen/Qwen2.5-7B-Instruct" | |
| DATA = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "pipeline", "data", "accepted.jsonl") | |
| SEED = 42 | |
| COMBOS = { | |
| "A": {"lr": 1e-5, "target_modules": ["q_proj", "v_proj"]}, | |
| "B": {"lr": 1e-4, "target_modules": ["q_proj", "v_proj"]}, | |
| "C": {"lr": 2e-4, "target_modules": "all-linear"}, | |
| } | |
| SYSTEM = ("You solve math word problems using positional reasoning: a chain of typed " | |
| "nodes, each committing to a prediction before the next step is computed. " | |
| "End with the final answer in <answer></answer> tags.") | |
| def load_split(tokenizer): | |
| rows = [json.loads(l) for l in open(DATA)] | |
| ds = Dataset.from_list([ | |
| { | |
| "prompt": tokenizer.apply_chat_template( | |
| [{"role": "system", "content": SYSTEM}, | |
| {"role": "user", "content": r["question"]}], | |
| tokenize=False, add_generation_prompt=True), | |
| "completion": r["positional"] + tokenizer.eos_token, | |
| } | |
| for r in rows | |
| ]) | |
| split = ds.train_test_split(test_size=0.1, seed=SEED) | |
| return split["train"], split["test"] | |
| def main(combo_name): | |
| combo = COMBOS[combo_name] | |
| out_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "runs", combo_name) | |
| os.makedirs(out_dir, exist_ok=True) | |
| tokenizer = AutoTokenizer.from_pretrained(MODEL_ID) | |
| train_ds, eval_ds = load_split(tokenizer) | |
| print(f"combo {combo_name}: {len(train_ds)} train / {len(eval_ds)} eval examples") | |
| bnb = BitsAndBytesConfig( | |
| load_in_4bit=True, | |
| bnb_4bit_quant_type="nf4", | |
| bnb_4bit_compute_dtype=torch.float16, # T4 has no bf16 | |
| bnb_4bit_use_double_quant=True, | |
| ) | |
| model = AutoModelForCausalLM.from_pretrained( | |
| MODEL_ID, quantization_config=bnb, device_map="auto", torch_dtype=torch.float16) | |
| model = prepare_model_for_kbit_training(model) | |
| model.config.use_cache = False | |
| lora = LoraConfig( | |
| r=64, lora_alpha=64, lora_dropout=0.05, bias="none", | |
| task_type="CAUSAL_LM", target_modules=combo["target_modules"]) | |
| model = get_peft_model(model, lora) | |
| model.print_trainable_parameters() | |
| args = SFTConfig( | |
| output_dir=out_dir, | |
| num_train_epochs=2, | |
| per_device_train_batch_size=1, | |
| gradient_accumulation_steps=8, | |
| learning_rate=combo["lr"], | |
| logging_steps=10, | |
| eval_strategy="steps", | |
| eval_steps=25, | |
| save_steps=25, | |
| save_total_limit=2, | |
| load_best_model_at_end=True, | |
| fp16=True, | |
| max_length=1600, | |
| gradient_checkpointing=True, | |
| optim="paged_adamw_8bit", | |
| report_to=[], | |
| seed=SEED, | |
| ) | |
| trainer = SFTTrainer( | |
| model=model, args=args, | |
| train_dataset=train_ds, eval_dataset=eval_ds) | |
| # TRL's SFTTrainer unconditionally casts LoRA adapter params to bfloat16 | |
| # for any quantized model during __init__ (QLoRA paper recommendation) -- | |
| # confirmed via trl/trainer/sft_trainer.py, no config option to opt out | |
| # for quantized models. bfloat16 has no unscale kernel for fp16's | |
| # GradScaler, and this T4 has no bf16 hardware support anyway. The correct | |
| # fix (confirmed via a standalone diagnostic) is fp32, not fp16: fp16 | |
| # mixed-precision training expects fp32 "master weight" params with | |
| # autocast handling the fp16 compute internally -- GradScaler explicitly | |
| # rejects unscaling gradients that are already fp16 leaf params | |
| # ("Attempting to unscale FP16 gradients"). Re-cast to fp32 after the | |
| # trainer is built, undoing TRL's bf16 cast rather than fighting it | |
| # beforehand. | |
| for p in trainer.model.parameters(): | |
| if p.requires_grad: | |
| p.data = p.data.to(torch.float32) | |
| trainer.train() | |
| trainer.model.save_pretrained(os.path.join(out_dir, "best_model")) | |
| with open(os.path.join(out_dir, "metrics.json"), "w") as f: | |
| json.dump(trainer.state.log_history, f, indent=1) | |
| print(f"combo {combo_name} done -> {out_dir}/best_model") | |
| if __name__ == "__main__": | |
| name = sys.argv[1] if len(sys.argv) > 1 else None | |
| if name not in COMBOS: | |
| print(f"usage: python3 train_qlora.py [{'|'.join(COMBOS)}]") | |
| sys.exit(1) | |
| main(name) | |