Skip to main content

Distill verifiable chain-of-thought reasoning into small language models via hierarchical step supervision

Project description

๐Ÿง  step-distill

Distill Verifiable Chain-of-Thought Reasoning into Small Language Models

Open-source framework implementing Step-Aware LoRA โ€” hierarchical step supervision that transfers structured mathematical reasoning from large teacher models into compact student models deployable on commodity hardware.

PyPI version Python 3.10+ License: MIT HuggingFace Model GitHub Stars Coverage Paper

Quick Start โ€ข Demo App โ€ข Train Your Own โ€ข Results โ€ข Architecture โ€ข Citation


๐Ÿค– Context for Antigravity (Read Before Writing Any Code)

This section is for the AI building this codebase. Read fully before starting.

What already exists โ€” do NOT re-implement

All of the following have been experimentally validated on Kaggle 2ร—T4:

Artifact Status Notes
Training pipeline โœ… Done Kaggle notebook, 2ร—T4, 2 epochs
NanoReason-3B weights โœ… Done Upload to ductaiphan/NanoReason-3B
GSM8K results โœ… Done 78.7% zero-shot exact-match
Ablation study โœ… Done 5 variants, per-step accuracy
RFS/SVR metrics โœ… Done RFS=100%, SVR=0% on 1,319 problems

What you BUILD

A clean, installable Python package wrapping the above research. This is software engineering, not research. Algorithms are known โ€” implement them cleanly and match the API signatures exactly.

Critical technical facts (from actual code)

  1. Tag format used in training (from StepType.tag in code):

    #### UNDERSTAND ####
    #### PLAN ####
    #### EXECUTE ####
    #### VERIFY ####
    

    Use exactly this format โ€” 4 hashtags, stage name, 4 hashtags, all uppercase.

  2. Teacher model: Qwen/Qwen2.5-32B-Instruct-AWQ (quantized, served via vLLM). For the framework, any OpenAI-compatible API works.

  3. Training hardware: 2ร—T4 (29GB total). Inference/demo: single T4 (16GB). Peak training VRAM: ~9.8GB per GPU.

  4. LoRA rank: Fixed at 16. Do not implement adaptive rank โ€” the paper uses static rank=16.

  5. Validated loss weights: ฮฑ=0.15, ฮฒ=0.35, ฮณ=0.35, ฮด=0.15, ฮต=0.10. Use these exact values as defaults.

  6. Training: seed=42, batch_size=1, grad_accum=4, max_seq_length=1024, LR=1e-4, warmup=300, cosine decay, label_smoothing=0.1, 2 epochs.

  7. Data format (from actual .jsonl files):

    {
      "id": "math_9650",
      "question": "...",
      "cot_4steps": {
        "understand": "...",
        "plan": "...",
        "execute": "...",
        "verify": "..."
      },
      "ground_truth": "697",
      "is_correct": true
    }
    
  8. No build step for frontend. Vanilla JS + CSS. Single HTML file. No npm/webpack/React.

Build priority order

Priority 1 (Demo-critical โ€” build first):
  Phase 1 โ†’ 2 โ†’ 4 โ†’ 9 โ†’ 10 โ†’ 11

Priority 2 (Training pipeline):
  Phase 3 โ†’ 5 โ†’ 6 โ†’ 7

Priority 3 (Completeness):
  Phase 8 โ†’ 12 โ†’ 13 โ†’ 14 โ†’ 15

โœจ What is step-distill?

step-distill is an open-source framework for structured reasoning distillation โ€” training small language models (1Bโ€“14B) to produce transparent, step-by-step mathematical reasoning by learning from a larger teacher model.

The core problem with standard SFT: Uniform cross-entropy treats every token equally. A mistyped connector word and a catastrophically wrong formula receive the same gradient penalty. This teaches surface text patterns, not reasoning structure.

Our solution: Decompose reasoning into 4 cognitively isolated stages and penalize planning/execution errors proportionally to their causal impact.

Teacher (32B AWQ)                    Student (3B)
     โ”‚                                    โ”‚
     โ”‚  Generate structured traces        โ”‚
     โ”‚ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–บ โ”‚  Runs on
     โ”‚  #### UNDERSTAND ####              โ”‚  single T4 GPU
     โ”‚  #### PLAN ####                    โ”‚  (~9.8GB VRAM)
     โ”‚  #### EXECUTE ####                 โ”‚  $0 on Kaggle
     โ”‚  #### VERIFY ####                  โ”‚

๐Ÿš€ Key Features

Feature Description
๐ŸŽฏ Step-Aware Loss Asymmetric gradient: PLAN/EXECUTE weighted 2.33ร— over UNDERSTAND
๐Ÿ“Š Novel Metrics RFS + SVR โ€” measure process quality, not just final accuracy
๐Ÿ”Œ Plug-and-Play Swap teacher/student models via one YAML config line
๐Ÿ’ป T4-Optimized Single T4 inference; 2ร—T4 training via SDPA + AMP + grad checkpointing
๐ŸŽ“ Ready Model NanoReason-3B: 78.7% zero-shot GSM8K, out of the box
๐Ÿ‡ป๐Ÿ‡ณ Vietnamese Math VNHSGE benchmark support โ€” cross-lingual transfer finding
๐Ÿ–ฅ๏ธ Demo App Student-friendly streaming UI with 4-step reasoning cards
๐Ÿ“ฆ One-line Install pip install step-distill

โšก Quick Start

pip install step-distill
from step_distill import NanoReason

model = NanoReason.from_pretrained("ductaiphan/NanoReason-3B")

result = model.solve(
    "Janet's ducks lay 16 eggs per day. She eats 3 for breakfast "
    "and bakes muffins with 4. She sells the rest at $2/egg. "
    "How much does she make daily?"
)

print(result)
# โ”Œโ”€ UNDERSTAND โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
# โ”‚ Given: 16 eggs/day, eat 3, bake 4, sell @$2   โ”‚
# โ”‚ Goal: calculate daily earnings                 โ”‚
# โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
# โ”Œโ”€ PLAN โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
# โ”‚ Step 1: remaining = 16 - 3 - 4                โ”‚
# โ”‚ Step 2: earnings = remaining ร— $2             โ”‚
# โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
# โ”Œโ”€ EXECUTE โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
# โ”‚ 16 - 3 = 13 โ†’ 13 - 4 = 9 โ†’ 9 ร— 2 = 18       โ”‚
# โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
# โ”Œโ”€ VERIFY โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
# โ”‚ Back-check: 9 ร— $2 = $18 โœ“                   โ”‚
# โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
# Answer: $18

print(result.answer)  # "18"
print(result.rfs)     # 1.0
# Launch student-friendly demo app
step-distill demo
# โ†’ http://localhost:8000

๐ŸŽ“ Demo App

  • ๐ŸŽจ 4 colored reasoning cards โ€” UNDERSTAND (blue) / PLAN (purple) / EXECUTE (amber) / VERIFY (emerald)
  • โšก Real-time token streaming โ€” watch the model think step by step
  • ๐Ÿ“ Problem bank โ€” 15 curated Vietnamese + English problems
  • ๐Ÿ”ฒ Toggle mode โ€” "Show Steps / Answer Only" for classroom use
  • ๐Ÿ“ฑ Mobile responsive

๐Ÿ‹๏ธ Train Your Own

from step_distill import TeacherPipeline, StepAwareTrainer, StepDistillConfig

# Step 1: Generate training data
pipeline = TeacherPipeline(
    teacher_model="Qwen/Qwen2.5-32B-Instruct",  # or AWQ quantized
    temperature=0.6,
    top_p=0.95,
)
dataset = pipeline.generate(
    sources=["gsm8k", "math", "vnhsge"],
    output_path="./data/step_traces.jsonl",
    quality_filters=["syntax", "math", "consistency"],
)

# Step 2: Fine-tune with Step-Aware LoRA
config = StepDistillConfig(
    student_model="Qwen/Qwen2.5-3B-Instruct",
    # Validated loss weights from paper
    alpha=0.15,    # UNDERSTAND
    beta=0.35,     # PLAN       โ† highest: planning errors cascade
    gamma=0.35,    # EXECUTE    โ† highest: arithmetic correctness
    delta=0.15,    # VERIFY
    epsilon=0.10,  # Transition penalty
    # LoRA
    lora_rank=16, lora_alpha=32, lora_dropout=0.05,
    target_modules=["q_proj","k_proj","v_proj","o_proj",
                    "gate_proj","up_proj","down_proj"],
    # Training
    num_epochs=2, learning_rate=1e-4, warmup_steps=300,
    batch_size=1, gradient_accumulation_steps=4,
    max_seq_length=1024, label_smoothing=0.1,
    # Efficiency
    use_sdpa=True, mixed_precision="fp16",
    gradient_checkpointing=True,
)
trainer = StepAwareTrainer(config=config, train_data="./data/step_traces.jsonl")
trainer.train(output_dir="./nanoreason-3b")

# Step 3: Evaluate
from step_distill import Evaluator
results = Evaluator("./nanoreason-3b").evaluate(
    benchmarks=["gsm8k", "math", "vnhsge"],
    metrics=["accuracy", "rfs", "svr"],
)
print(results.summary())

๐Ÿ“ Architecture

4-Stage Cognitive Decomposition

Grounded in Pรณlya's problem-solving framework (1945):

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  UNDERSTAND  โ”‚     PLAN     โ”‚   EXECUTE    โ”‚    VERIFY      โ”‚
โ”‚   ฮฑ = 0.15  โ”‚   ฮฒ = 0.35  โ”‚   ฮณ = 0.35  โ”‚   ฮด = 0.15    โ”‚
โ”‚              โ”‚              โ”‚              โ”‚                โ”‚
โ”‚ Extract:     โ”‚ Retrieve:    โ”‚ Substitute:  โ”‚ Back-calc:     โ”‚
โ”‚ โ€ข Variables  โ”‚ โ€ข Theorems   โ”‚ โ€ข Values     โ”‚ โ€ข Check result โ”‚
โ”‚ โ€ข Givens     โ”‚ โ€ข Formulas   โ”‚ โ€ข Arithmetic โ”‚ โ€ข Verify logic โ”‚
โ”‚ โ€ข Objective  โ”‚ โ€ข Algorithm  โ”‚ โ€ข Steps      โ”‚                โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
         ฮต = 0.10 (Transition Penalty โ€” enforces stage order)

Step-Aware Loss

L_step = ฮฑยทL_U + ฮฒยทL_P + ฮณยทL_E + ฮดยทL_V + ฮตยทL_tr

where L_s = -(1/|M_s|) ยท ฮฃ_{t: M_s[t]=1} log p_ฮธ(y_t | y_{<t}, x)

ฮฒ/ฮฑ = ฮณ/ฮฑ = 2.33 โ€” PLAN/EXECUTE errors penalized 2.33ร— heavier
Weights sum to 1.10 โ€” importance multipliers, not probability simplex

Two-Tier Parser

Raw text with #### TAGS ####
    โ†’ Tier 1 (Regex): locate tag boundaries
    โ†’ Tier 2 (Rules): classify each token โ†’ {U, P, E, V, IGNORE}
    โ†’ Output: M_U, M_P, M_E, M_V โˆˆ {0,1}^L (binary mask matrices)

Central Finding: Formโ€“Function Dissociation

RFS = 100.0%  โ† perfect structural form โ€” achievable via SFT โœ…
SVR = 0.0%    โ† functional self-correction โ€” requires RL signals โš ๏ธ

Perfect Teacher Syndrome: Training on 18,044 perfect trajectories produces perfect form (RFS=100%) but cannot produce functional self-correction (SVR=0%) because the training data contains zero examples of VERIFY catching an error. This is a distribution mismatch โ€” not a bug, but a theoretically grounded finding that precisely motivates GRPO as the next step.


๐Ÿ“Š Results

GSM8K Zero-Shot (1,319 test problems)

Model Params GSM8K RFS SVR
NanoReason-3B (ours) 3B 78.7% 100.0% 0.0%*
Qwen2.5-3B SFT-LoRA 3B 77.9% โ€” โ€”
Qwen2.5-3B-Instruct 3B 83.9%โ€  โ€” โ€”
DeepSeek-R1-Distill-1.5B 1.5B 40.9% โ€” โ€”

*SVR=0%: documented limitation โ€” see Perfect Teacher Syndrome โ€ 83.9% without structured reasoning (Alignment Tax โ€” intentional trade-off for pedagogy)

Ablation Study (per-step accuracy, 1 epoch)

Variant U% P% E% V% Avg
NanoReason-3B 92.1 91.1 97.1 93.3 93.4
Zero-Penalty 92.1 91.2 97.4 93.4 93.5
LoRA Rank-32 91.4 86.4 94.7 90.0 90.6
Uniform Loss 91.2 86.6 94.6 89.7 90.5
No-CoT 94.3 N/A N/A N/A โ€”

Key: Step-Aware Loss โ†’ +4.5pp on PLAN vs Uniform Loss. This is the most direct validation of asymmetric gradient pressure.

Training Dynamics

Total loss: 1.928 โ†’ 1.723 (โˆ’10.6%, 2 epochs, ~8,500 steps)
Per-step improvement:  UNDERSTAND +14.1%  PLAN +11.4%
                       EXECUTE    +8.9%   VERIFY +8.1%

๐Ÿ“ฆ Novel Evaluation Metrics

RFS โ€” Reasoning Format Score

# Measures Form Competence โ€” structural adherence
RFS(g) = (1/4) ยท ฮฃ_{s โˆˆ {U,P,E,V}} 1_s(g)
# where 1_s(g) = 1 if stage s present with โ‰ฅ10 chars content
RFS_full = fraction of outputs where RFS(g) = 1.0
# NanoReason-3B: RFS_full = 100.0%

SVR โ€” Self-Verification Rate

# Measures Functional Competence โ€” genuine self-correction
SVR = |{g: VERIFY catches error AND reverses prior answer}| / N
# NanoReason-3B: SVR = 0.0% โ€” Perfect Teacher Syndrome
# Requires RL training to improve (future work)

โš™๏ธ Configuration Reference

# step_distill_config.yaml
student_model: "Qwen/Qwen2.5-3B-Instruct"
teacher_model: "Qwen/Qwen2.5-32B-Instruct"

loss_weights:
  alpha: 0.15    # UNDERSTAND
  beta: 0.35     # PLAN
  gamma: 0.35    # EXECUTE
  delta: 0.15    # VERIFY
  epsilon: 0.10  # Transition penalty

lora:
  rank: 16
  alpha: 32
  dropout: 0.05
  target_modules: [q_proj, k_proj, v_proj, o_proj, gate_proj, up_proj, down_proj]

training:
  epochs: 2
  learning_rate: 1.0e-4
  min_lr: 1.0e-6
  scheduler: cosine_with_warmup
  warmup_steps: 300
  batch_size: 1
  gradient_accumulation_steps: 4
  max_seq_length: 1024
  weight_decay: 0.01
  max_grad_norm: 1.0
  label_smoothing: 0.1

efficiency:
  use_sdpa: true
  mixed_precision: fp16
  gradient_checkpointing: true
  # Peak VRAM: ~9.8GB per T4 GPU

๐Ÿ”Œ Extensibility

# Custom dataset
from step_distill import DataSource
class MySource(DataSource):
    def load(self) -> list[dict]:
        return [{"question": "...", "answer": "..."}, ...]

# Custom teacher (any OpenAI-compatible API)
pipeline = TeacherPipeline(teacher_model="gpt-4o", api_key="...")

# Custom student (any HuggingFace CausalLM)
config = StepDistillConfig(student_model="meta-llama/Llama-3.1-8B-Instruct")

๐Ÿ› ๏ธ CLI Reference

step-distill generate --teacher Qwen/Qwen2.5-32B-Instruct \
    --sources gsm8k math vnhsge --output ./data/traces.jsonl

step-distill train --config config.yaml --data ./data/traces.jsonl \
    --output ./my-model

step-distill eval --model ./my-model \
    --benchmarks gsm8k math vnhsge --metrics accuracy rfs svr

step-distill demo --model ductaiphan/NanoReason-3B --port 8000

step-distill solve "If x + 5 = 12, what is x?"

step-distill run --config config.yaml   # full pipeline

๐Ÿ“ Project Structure

step-distill/
โ”œโ”€โ”€ step_distill/
โ”‚   โ”œโ”€โ”€ __init__.py          # Exports: NanoReason, StepAwareTrainer,
โ”‚   โ”‚                        #   StepDistillConfig, Evaluator, TeacherPipeline
โ”‚   โ”œโ”€โ”€ core/
โ”‚   โ”‚   โ”œโ”€โ”€ model.py         # NanoReason: from_pretrained, solve, solve_stream
โ”‚   โ”‚   โ”œโ”€โ”€ trainer.py       # StepAwareTrainer: overrides compute_loss()
โ”‚   โ”‚   โ”œโ”€โ”€ loss.py          # StepAwareLoss: the core algorithm
โ”‚   โ”‚   โ”œโ”€โ”€ parser.py        # LabelMatrixParser: 2-tier Regex+Rule
โ”‚   โ”‚   โ””โ”€โ”€ metrics.py       # RFSMetric, SVRMetric, AccuracyMetric, Evaluator
โ”‚   โ”œโ”€โ”€ data/
โ”‚   โ”‚   โ”œโ”€โ”€ pipeline.py      # TeacherPipeline: async generation + 3 quality filters
โ”‚   โ”‚   โ”œโ”€โ”€ sources.py       # DataSource ABC + GSM8K, MATH, VNHSGE implementations
โ”‚   โ”‚   โ”œโ”€โ”€ filters.py       # QualityFilter: syntax, math correctness, step consistency
โ”‚   โ”‚   โ””โ”€โ”€ formatter.py     # PromptFormatter: system prompt, JSON schema
โ”‚   โ”œโ”€โ”€ config/
โ”‚   โ”‚   โ”œโ”€โ”€ config.py        # StepDistillConfig (Pydantic v2, validated)
โ”‚   โ”‚   โ””โ”€โ”€ defaults.yaml    # Exact paper hyperparameters
โ”‚   โ”œโ”€โ”€ app/
โ”‚   โ”‚   โ”œโ”€โ”€ server.py        # FastAPI: POST /api/solve, WS /api/stream
โ”‚   โ”‚   โ””โ”€โ”€ static/
โ”‚   โ”‚       โ”œโ”€โ”€ index.html   # Single HTML file โ€” no build step
โ”‚   โ”‚       โ”œโ”€โ”€ style.css    # Design system
โ”‚   โ”‚       โ””โ”€โ”€ app.js       # Streaming + UI logic (vanilla JS)
โ”‚   โ””โ”€โ”€ cli/
โ”‚       โ””โ”€โ”€ main.py          # Typer CLI
โ”œโ”€โ”€ tests/
โ”‚   โ”œโ”€โ”€ test_loss.py         # Analytical values โ€” must be exact
โ”‚   โ”œโ”€โ”€ test_parser.py       # All edge cases for tag parsing
โ”‚   โ”œโ”€โ”€ test_metrics.py      # Must reproduce 78.7% / 100% / 0%
โ”‚   โ””โ”€โ”€ test_inference.py    # Quick Start end-to-end
โ”œโ”€โ”€ examples/
โ”‚   โ”œโ”€โ”€ basic_inference.py
โ”‚   โ”œโ”€โ”€ train_custom_student.py
โ”‚   โ””โ”€โ”€ evaluate_model.py
โ”œโ”€โ”€ pyproject.toml
โ”œโ”€โ”€ README.md
โ”œโ”€โ”€ CONTRIBUTING.md
โ”œโ”€โ”€ CHANGELOG.md
โ””โ”€โ”€ LICENSE

๐Ÿ—บ๏ธ Development Phases

Phase 1 โ€” Project Scaffold

  • pyproject.toml (see STRATEGY.md for exact spec)
  • step_distill/__init__.py with stub exports
  • Makefile: install, test, build, publish
  • CI: GitHub Actions, Python 3.10/3.11/3.12

Done when: pip install -e . works, from step_distill import NanoReason imports.


Phase 2 โ€” Pydantic Config

  • StepDistillConfig with all fields from config reference above
  • from_yaml(), from_dict() class methods
  • Validator: weight sum โ‰ˆ 1.10 (within 0.01)
  • Validator: lora_rank is power of 2

Done when: Config round-trips YAMLโ†’Pydanticโ†’dict. Validators raise on bad input.


Phase 3 โ€” Label Matrix Parser

  • LabelMatrixParser.parse(text, tokenizer) โ†’ dict[str, np.ndarray[bool]]
  • Tag format: #### UNDERSTAND #### (case-sensitive, exact spacing)
  • Edge cases: missing stages, wrong order, partial tags
  • Keys: "understand", "plan", "execute", "verify", "ignore"

Done when: Correctly parses all samples in data/sample_traces.jsonl.


Phase 4 โ€” Step-Aware Loss

  • StepAwareLoss(alpha, beta, gamma, delta, epsilon, label_smoothing=0.0)
  • forward(logits, labels, mask_dict) โ†’ torch.Tensor
  • Per-stage normalization by |M_s| (not total length)
  • Causal shift: correct +1 offset before masking
  • Transition penalty: penalize stage-order violations

Done when: Unit tests pass with known analytical values (single-stage input โ†’ exact CE value).


Phase 5 โ€” Training Pipeline

  • StepAwareTrainer(config, train_data)
  • train(output_dir) โ†’ TrainingResult
  • Overrides compute_loss() with StepAwareLoss
  • LoRA via PEFT, all target_modules from config
  • Auto-enables SDPA + AMP + gradient checkpointing from config flags
  • Per-stage accuracy callback every N steps
  • Multi-GPU via accelerate (2ร—T4 config)

Done when: 10-step smoke test on T4 16GB, no OOM, per-stage accuracy logged.


Phase 6 โ€” Teacher Pipeline

  • TeacherPipeline(teacher_model, temperature=0.6, top_p=0.95)
  • Async generation with retry and batch support
  • 3-layer quality filters (syntax โ†’ math โ†’ step consistency)
  • Resume support: skip already-generated IDs
  • Output format matches data/sample_traces.jsonl exactly (8 fields)

Done when: Generates 100 MATH traces with โ‰ฅ90% pass rate.


Phase 7 โ€” Dataset Sources

  • DataSource ABC with load() โ†’ list[dict], sample(n) โ†’ list[dict]
  • GSM8KSource, MATHSource via HuggingFace datasets
  • VNHSGESource bundled in package (step_distill/data/vnhsge/)
    • 225 training samples, test set withheld

Done when: All 3 sources load. VNHSGE returns correct sample count.


Phase 8 โ€” Evaluation Metrics

  • RFSMetric.compute(responses) โ†’ float
  • SVRMetric.compute(responses) โ†’ float
  • AccuracyMetric.compute(preds, golds) โ†’ float with normalization:
    • Strip $, \boxed{}, commas, trailing units
    • Fraction tolerance (float comparison within 1e-3)
  • Evaluator(model_path).evaluate(benchmarks, metrics) โ†’ EvalResults
  • EvalResults.summary() โ†’ rich table, .to_dict() โ†’ JSON

Done when: Evaluator("ductaiphan/NanoReason-3B") reproduces {gsm8k: 78.7%, rfs: 100.0%, svr: 0.0%} within ยฑ0.1pp.


Phase 9 โ€” NanoReason Inference Wrapper

  • NanoReason.from_pretrained(model_id, device="auto")
    • Auto-detect: LoRA adapter vs merged model
  • solve(question, **gen_kwargs) โ†’ ReasoningResult
    • Default: greedy, repetition_penalty=1.1, max_new_tokens=300
  • solve_stream(question) โ†’ AsyncGenerator[tuple[str, str], None]
    • Yields (token, stage_name)
  • ReasoningResult: .answer, .steps: dict[str, str], .rfs: float, .__repr__() โ†’ boxes

Done when: Quick Start code block runs in <30s on T4. result.answer == "18".


Phase 10 โ€” Demo Backend (FastAPI)

  • POST /api/solve โ†’ ReasoningResult JSON
  • WS /api/stream โ†’ {"token": str, "stage": str} messages
  • GET /api/problems โ†’ 15-item problem bank (see STRATEGY.md)
  • GET /api/health โ†’ {"status": "ok", "model": model_id}
  • Model loads at startup via lifespan

Done when: All endpoints respond correctly. WebSocket streams 3 test problems without drop.


Phase 11 โ€” Demo Frontend (Vanilla JS)

Design tokens (exact โ€” do not deviate):

--bg:       #0f0f13;
--card-bg:  rgba(255,255,255,0.04);
--border:   rgba(255,255,255,0.08);
--grad:     linear-gradient(135deg, #6366f1, #8b5cf6);
--understand: #3b82f6;
--plan:       #8b5cf6;
--execute:    #f59e0b;
--verify:     #10b981;

UX requirements:

  • Stage cards slide in from left with 200ms staggered delay
  • Token streaming character-by-character in active card
  • "Show Steps / Answer Only" toggle
  • Problem bank sidebar, click โ†’ auto-fill
  • Mobile responsive (min-width: 320px)
  • No build step

Done when: Runs on localhost:8000, all 15 problems solve, looks like funded startup product.


Phase 12 โ€” CLI

  • Typer app with 6 subcommands: generate, train, eval, demo, solve, run
  • Rich output: progress bars, result tables
  • --config yaml support on all commands

Done when: All CLI commands in CLI Reference section work.


Phase 13 โ€” Tests & CI

  • Unit tests for all core modules
  • test_metrics.py must reproduce paper results
  • โ‰ฅ80% coverage
  • GitHub Actions: Python 3.10/3.11/3.12

Done when: make test green, coverage badge โ‰ฅ80%.


Phase 14 โ€” Documentation

  • MkDocs Material with auto API reference
  • Tutorials: quickstart, training, custom dataset, metrics deep-dive
  • GitHub Pages deploy on main push

Phase 15 โ€” PyPI Release

  • Version 0.1.0 published
  • banner.png, demo.gif, CHANGELOG.md, CONTRIBUTING.md
  • Issue templates enabled

Done when: pip install step-distill && step-distill demo on fresh Python 3.10.


๐Ÿค— Pre-trained Models

Model Params GSM8K Download
NanoReason-3B 3B 78.7% ๐Ÿค— Hub
NanoReason-7B (v0.2.0) 7B TBD Soon

๐Ÿ“„ Citation

@inproceedings{phan2026stepawarelora,
  title     = {Step-Aware {LoRA}: Distilling Verifiable Chain-of-Thought Reasoning
               into Small Language Models via Hierarchical Step Supervision},
  author    = {Phan, Duc Tai and {Trinh Tran}, Trung Duc},
  booktitle = {Proceedings of [Conference]},
  series    = {Lecture Notes in Computer Science},
  publisher = {Springer},
  year      = {2026},
  note      = {University of Transport Ho Chi Minh City, Vietnam}
}

๐Ÿค Contributing

See CONTRIBUTING.md. Priority areas:

  • GRPO with negative trajectories โ†’ fix SVR=0%
  • NanoReason-7B and 14B
  • GGUF export for llama.cpp
  • Multi-GPU DDP training

๐Ÿ“œ License

MIT โ€” use freely, modify freely.


Built with โค๏ธ at University of Transport Ho Chi Minh City, Vietnam

Making high-quality AI reasoning accessible to every student โ€” offline, on commodity hardware, at zero cost.

โญ Star ยท ๐Ÿ› Issues ยท ๐Ÿ’ก Discussions

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

step_distill-0.1.10.tar.gz (93.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

step_distill-0.1.10-py3-none-any.whl (64.1 kB view details)

Uploaded Python 3

File details

Details for the file step_distill-0.1.10.tar.gz.

File metadata

  • Download URL: step_distill-0.1.10.tar.gz
  • Upload date:
  • Size: 93.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for step_distill-0.1.10.tar.gz
Algorithm Hash digest
SHA256 8c69bb3fa618859b4fab5720ca94cb5b3f457de4fb5c12e42cb5316ed5abc39f
MD5 f1055a554a72737d52839be09afcb896
BLAKE2b-256 7571720fe80f3bac2620669c10590082c29a39f14c0943989a99d8d1be57bd5b

See more details on using hashes here.

File details

Details for the file step_distill-0.1.10-py3-none-any.whl.

File metadata

  • Download URL: step_distill-0.1.10-py3-none-any.whl
  • Upload date:
  • Size: 64.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for step_distill-0.1.10-py3-none-any.whl
Algorithm Hash digest
SHA256 80a80563ba5221e70a383705fc4bfddbcc2b6fe48b74523d23e7ff1123300e1a
MD5 5b8719943bec52279d0da0ff467103f3
BLAKE2b-256 8ac9ea47acb835b6f0e061a953d57fb1e9833590421277a42bbb4d2cccd96234

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page