178 lines
7.4 KiB
Markdown
178 lines
7.4 KiB
Markdown
|
|
---
|
|||
|
|
license: apache-2.0
|
|||
|
|
base_model: unsloth/Qwen2.5-1.5B-Instruct
|
|||
|
|
language:
|
|||
|
|
- en
|
|||
|
|
- ru
|
|||
|
|
library_name: transformers
|
|||
|
|
pipeline_tag: text-generation
|
|||
|
|
tags:
|
|||
|
|
- qwen2
|
|||
|
|
- unsloth
|
|||
|
|
- trl
|
|||
|
|
- sft
|
|||
|
|
- lora
|
|||
|
|
- education
|
|||
|
|
- tutoring
|
|||
|
|
- conversational
|
|||
|
|
datasets:
|
|||
|
|
- ptvnck/TutoringDialogs
|
|||
|
|
- eth-nlped/mathdial
|
|||
|
|
model-index:
|
|||
|
|
- name: qwen2.5-1.5b-exam-tutor
|
|||
|
|
results: []
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
<div align="center">
|
|||
|
|
|
|||
|
|
<span style="font-size:44px; font-weight:bold">Qwen2.5-1.5B Exam Tutor</span>
|
|||
|
|
|
|||
|
|
**Tutoring assistant for preparing to exams, fine-tuned to help you *think*, not just get answers.**
|
|||
|
|
|
|||
|
|
[](https://huggingface.co/Qwen/Qwen2.5-1.5B-Instruct)
|
|||
|
|
[](https://www.apache.org/licenses/LICENSE-2.0)
|
|||
|
|
[](https://github.com/unslothai/unsloth)
|
|||
|
|
[]()
|
|||
|
|
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Overview
|
|||
|
|
|
|||
|
|
`qwen2.5-1.5b-exam-tutor` is a LoRA fine-tune of [`Qwen2.5-1.5B-Instruct`](https://huggingface.co/Qwen/Qwen2.5-1.5B-Instruct), trained to behave like a **patient human tutor** rather than an answer-dispensing machine. Instead of solving a problem outright, the model is trained to ask guiding questions, probe for misconceptions, and walk the student toward the solution themselves — the same pattern a good teacher uses during exam prep.
|
|||
|
|
|
|||
|
|
This model is the **first stage** of a larger personal-assistant project for exam preparation, which also includes a RAG pipeline over practice problems and a FastAPI serving layer accelerated with vLLM/Ollama.
|
|||
|
|
|
|||
|
|
> This is an educational / portfolio project, not a production system. Scope, dataset size, and evaluation depth are intentionally sized for a learning exercise — see [Limitations](#-limitations--scope) below.
|
|||
|
|
|
|||
|
|
## Model Details
|
|||
|
|
|
|||
|
|
| | |
|
|||
|
|
|---|---|
|
|||
|
|
| **Base model** | [`unsloth/Qwen2.5-1.5B-Instruct`](https://huggingface.co/unsloth/Qwen2.5-1.5B-Instruct) |
|
|||
|
|
| **Fine-tuning method** | LoRA (rank 16), full precision (no 4-bit quantization) |
|
|||
|
|
| **Frameworks** | [Unsloth](https://github.com/unslothai/unsloth) + [TRL](https://github.com/huggingface/trl) `SFTTrainer` |
|
|||
|
|
| **Weights format** | Merged 16-bit safetensors (adapter merged into base) |
|
|||
|
|
| **Language** | English / Russian |
|
|||
|
|
| **License** | Apache 2.0 (inherited from base model) |
|
|||
|
|
|
|||
|
|
## Intended Use
|
|||
|
|
|
|||
|
|
- Conversational tutoring for exam preparation: math word problems, conceptual explanations, step-by-step reasoning practice.
|
|||
|
|
- Designed to be embedded as the generation backend of a larger RAG + FastAPI tutoring assistant (see [Roadmap](#-roadmap)).
|
|||
|
|
- **Not intended** as a general-purpose assistant, factual knowledge base, or replacement for a real teacher — the model's job is to *guide*, its factual accuracy on niche topics is not separately verified.
|
|||
|
|
|
|||
|
|
## Training Data
|
|||
|
|
|
|||
|
|
650 student ↔ tutor dialogues, combined from two sources:
|
|||
|
|
|
|||
|
|
| Source | Dialogues used | Notes |
|
|||
|
|
|---|---|---|
|
|||
|
|
| [`ptvnck/TutoringDialogs`](https://huggingface.co/datasets/ptvnck/TutoringDialogs) | 500 | Synthetically generated, manually curated tutoring dialogues across mixed subjects |
|
|||
|
|
| [`eth-nlped/mathdial`](https://huggingface.co/datasets/eth-nlped/mathdial) | 150 | Filtered (dialogues with >11 turns) and reformatted subset, added specifically to cover math word-problem tutoring, which was underrepresented in the primary dataset |
|
|||
|
|
|
|||
|
|
Data was split 85/15 into train/validation (≈552 / 98 examples), formatted with the tokenizer's ChatML template, and capped at 2500 tokens (covering the 99th percentile of dialogue length with no truncation).
|
|||
|
|
|
|||
|
|
## Training Procedure
|
|||
|
|
|
|||
|
|
<details>
|
|||
|
|
<summary><b>LoRA configuration</b></summary>
|
|||
|
|
|
|||
|
|
| Parameter | Value |
|
|||
|
|
|---|---|
|
|||
|
|
| Rank (`r`) | 16 |
|
|||
|
|
| Alpha (`lora_alpha`) | 32 |
|
|||
|
|
| Target modules | `q_proj, k_proj, v_proj, o_proj, gate_proj, up_proj, down_proj` |
|
|||
|
|
| Dropout | 0.1 |
|
|||
|
|
| Bias | none |
|
|||
|
|
| Gradient checkpointing | Unsloth-optimized |
|
|||
|
|
|
|||
|
|
</details>
|
|||
|
|
|
|||
|
|
<details>
|
|||
|
|
<summary><b>Optimization hyperparameters</b></summary>
|
|||
|
|
|
|||
|
|
| Parameter | Value |
|
|||
|
|
|---|---|
|
|||
|
|
| Effective batch size | 12 (4 × grad. accumulation 3) |
|
|||
|
|
| Epochs | 4 (best checkpoint auto-selected) |
|
|||
|
|
| Learning rate | 2e-4, cosine schedule |
|
|||
|
|
| Warmup | 10% of total steps |
|
|||
|
|
| Optimizer | AdamW (torch) |
|
|||
|
|
| Precision | fp16 |
|
|||
|
|
| Loss masking | Response-only (`train_on_responses_only`) — loss computed exclusively on tutor turns |
|
|||
|
|
| Hardware | 1× NVIDIA T4 (Google Colab) |
|
|||
|
|
|
|||
|
|
</details>
|
|||
|
|
|
|||
|
|
**Response-only loss masking.** Only the tutor's turns contribute to the training loss; the student's turns are masked out. This keeps the adapter's limited capacity focused entirely on learning *how to tutor*, rather than also learning to imitate the student side of the conversation.
|
|||
|
|
|
|||
|
|
## Results
|
|||
|
|
|
|||
|
|
| Epoch | Training Loss | Validation Loss |
|
|||
|
|
|---|---|---|
|
|||
|
|
| 1 | 1.655 | 1.724 |
|
|||
|
|
| 2 | 1.389 | 1.516 |
|
|||
|
|
| **3** | **1.050** | **1.506** ← best |
|
|||
|
|
| 4 | 0.703 | 1.580 |
|
|||
|
|
|
|||
|
|
- **Best validation loss:** 1.506 (epoch 3) → **perplexity ≈ 4.51**
|
|||
|
|
- Training loss keeps decreasing through epoch 4, while validation loss starts rising after epoch 3 — a clear sign of overfitting setting in on the final epoch, expected given the modest dataset size (~550 training examples).
|
|||
|
|
- `load_best_model_at_end=True` automatically restored the epoch-3 checkpoint as the final model, so the released weights are **not** the last-epoch weights, but the best-validation checkpoint.
|
|||
|
|
|
|||
|
|
Full training curves (loss, LR schedule) were tracked with Weights & Biases.
|
|||
|
|
|
|||
|
|
## How to Use
|
|||
|
|
|
|||
|
|
**With 🤗 Transformers:**
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
from transformers import AutoTokenizer, AutoModelForCausalLM
|
|||
|
|
|
|||
|
|
tokenizer = AutoTokenizer.from_pretrained("ptvnck/qwen2.5-1.5b-exam-tutor")
|
|||
|
|
model = AutoModelForCausalLM.from_pretrained("ptvnck/qwen2.5-1.5b-exam-tutor")
|
|||
|
|
|
|||
|
|
messages = [
|
|||
|
|
{"role": "user", "content": "I need to solve 2x + 5 = 15 but I don't know where to start."}
|
|||
|
|
]
|
|||
|
|
inputs = tokenizer.apply_chat_template(
|
|||
|
|
messages, add_generation_prompt=True, tokenize=True,
|
|||
|
|
return_dict=True, return_tensors="pt"
|
|||
|
|
).to(model.device)
|
|||
|
|
|
|||
|
|
outputs = model.generate(**inputs, max_new_tokens=200, temperature=0.7)
|
|||
|
|
print(tokenizer.decode(outputs[0][inputs["input_ids"].shape[-1]:], skip_special_tokens=True))
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**With Unsloth (2x faster inference):**
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
from unsloth import FastLanguageModel
|
|||
|
|
|
|||
|
|
model, tokenizer = FastLanguageModel.from_pretrained(
|
|||
|
|
model_name="ptvnck/qwen2.5-1.5b-exam-tutor",
|
|||
|
|
max_seq_length=2048,
|
|||
|
|
)
|
|||
|
|
FastLanguageModel.for_inference(model)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**With vLLM:**
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
pip install vllm
|
|||
|
|
vllm serve "ptvnck/qwen2.5-1.5b-exam-tutor"
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## Limitations & Scope
|
|||
|
|
|
|||
|
|
- Trained on 650 dialogues — sufficient to learn a tutoring *pattern*, but not a broad knowledge base. Expect a strong grasp of *conversational tutoring style*, and a shallower grasp of niche subject-matter facts.
|
|||
|
|
- No dedicated generation-quality evaluation (human eval / LLM-as-judge) was run as part of this stage — this is deferred to the RAG + FastAPI integration stage of the project, where end-to-end assistant responses will be evaluated in context rather than in isolation.
|
|||
|
|
- Not safety-tuned beyond what the base `Qwen2.5-1.5B-Instruct` already provides.
|
|||
|
|
|
|||
|
|
## Acknowledgements
|
|||
|
|
|
|||
|
|
- Base model: [Qwen2.5-1.5B-Instruct](https://huggingface.co/Qwen/Qwen2.5-1.5B-Instruct) by the Qwen team
|
|||
|
|
- Training accelerated with [Unsloth](https://github.com/unslothai/unsloth)
|
|||
|
|
- Trained using Hugging Face [TRL](https://github.com/huggingface/trl)
|
|||
|
|
- `mathdial` subset: [eth-nlped/mathdial](https://huggingface.co/datasets/eth-nlped/mathdial)
|