Skip to content

09 — CLI Reference

The CLI (Command Line Interface) lets you run every feature of LLM Fine-Tuner from your terminal — no browser or GUI needed. This is perfect for servers, automation, scripts, and scheduled jobs.


How It Works

Any time you launch main.py with arguments, it runs in CLI mode. With no arguments, it launches the Gradio UI.

python main.py            # → opens the Gradio UI in your browser
python main.py --help     # → shows CLI help
python main.py --version  # → prints the version
python main.py train ...  # → runs headless training

Global Help

python main.py --help

Output:

Usage: main.py [OPTIONS] COMMAND [ARGS]...

  🧠 LLM Fine-Tuner v3.3.0 — headless CLI for every training mode.

Options:
  --version  Show the version and exit.
  --help     Show this message and exit.

Commands:
  train     Headless SFT training
  reward    Train a Reward Model from preference data
  orpo      ORPO alignment training
  grpo      GRPO fine-tuning with a reward model and/or reference answers
  kto       KTO alignment from desirable / undesirable examples
  distill   Knowledge distillation (GKD): train a small student on a larger teacher's outputs
  embed     Fine-tune an embedding model for search / RAG; reports retrieval before and after
  evaluate  Batched BLEU / ROUGE / BERTScore evaluation (greedy decoding)
  benchmark Standard benchmarks with lm-evaluation-harness (ARC, HellaSwag, GSM8K, …)
  merge     Merge a LoRA or IA3 adapter into its base model
  merge-adapters  Combine LoRA adapters trained on the same base model into one (TIES, DARE, SVD, …)
  export    Export for deployment: GGUF or FP8/W4A16 safetensors (vLLM)
  push      Upload a model folder to the Hugging Face Hub
  serve     Serve a model behind an OpenAI-compatible API
  synthesize  Create question/answer training data from documents with an LLM

Each command also has its own --help:

python main.py train --help

The app logs to the console. LFT_LOG_LEVEL=DEBUG (or WARNING, ERROR; default INFO) sets how much its own modules report; other libraries only show warnings.


Commands


train — Supervised Fine-Tuning

The main training command. Reuses exactly the same pipeline as the UI.

python main.py train \
    --model mistralai/Mistral-7B-v0.1 \
    --data train.csv \
    --output ./my_model \
    --epochs 3 \
    --batch-size 2 \
    --lr 2e-4 \
    --peft LoRA \
    --lora-rank 8

All options:

Flag Default Description
--model (required) Base model ID or local path
--data (required) Dataset file (.csv, .json or .jsonl)
--output ./output Where to save the trained model
--epochs 3 Number of training epochs
--batch-size 2 Per-device batch size
--max-length 256 Maximum sequence length in tokens
--lr 2e-4 Learning rate
--peft LoRA PEFT method: LoRA, QLoRA Enhanced, IA3, Full Fine-tuning, Auto
--lora-rank 8 LoRA rank
--lora-variant LoRA LoRA, rsLoRA or DoRA (LoRA goes on every linear layer)
--qlora-enhanced off Enable QLoRA Enhanced (overrides --peft)
--flash-attn off Enable Flash Attention 2
--packing off Pack short samples into full-length sequences (needs --flash-attn on a CUDA GPU; ignored otherwise)
--activation-offloading off Long sequences: keep activations in CPU RAM (CUDA; skipped otherwise)
--padding-free off Long sequences: batches without padding (needs --flash-attn on a CUDA GPU)
--hf-dataset — Hugging Face Hub dataset (owner/name) instead of --data; streamed
--hf-config / --hf-split — / train Hub dataset config and split
--hf-max-rows 20000 Rows to stream from the Hub dataset
--eval-split 0.1 Share of rows held out for evaluation (0 = none)
--seed 42 Random seed for the data split and training (same seed + data + settings = same weights)
--report-to none Experiment tracker: trackio, wandb, mlflow or tensorboard (must be installed)
--config — Replay a saved run_config.yaml: model, mode (SFT/DPO) and all settings come from the file; only --data/--output are used. Warns if the data differs from the recorded fingerprint

Example — fine-tune TinyLlama on a JSONL dataset:

python main.py train \
    --model TinyLlama/TinyLlama-1.1B-Chat-v1.0 \
    --data my_qa_data.jsonl \
    --output ./tinyllama_finetuned \
    --epochs 5 \
    --lr 1e-4

Example — QLoRA Enhanced for low-VRAM machines:

python main.py train \
    --model mistralai/Mistral-7B-v0.1 \
    --data data.csv \
    --output ./mistral_qlora \
    --qlora-enhanced \
    --lora-rank 32


reward — Train a Reward Model

Trains a prompt-aware reward model (a sequence classifier with one score output) from preference pairs. LoRA is merged at the end, so the output folder can be passed straight to grpo --reward-model.

python main.py reward \
    --model TinyLlama/TinyLlama-1.1B-Chat-v1.0 \
    --data reward_pairs.csv \
    --output ./reward_model \
    --epochs 3 \
    --lr 1e-4 \
    --max-length 1024 \
    --batch-size 4

All options:

Flag Default Description
--model (required) Base model ID
--data (required) CSV/JSONL with prompt, chosen and rejected columns
--output ./reward_model Where to save the reward model
--epochs 3 Training epochs
--lr 1e-4 Learning rate (LoRA)
--max-length 1024 Max tokens for prompt + response
--batch-size 4 Batch size

Data format (reward_pairs.csv):

prompt,chosen,rejected
"How long is a year?","About 365.25 days.","No idea."


orpo — ORPO Alignment

Single-step preference alignment — no reward model needed.

python main.py orpo \
    --model TinyLlama/TinyLlama-1.1B-Chat-v1.0 \
    --data preference_pairs.csv \
    --output ./orpo_model \
    --epochs 3 \
    --lr 1e-4 \
    --beta 0.1 \
    --alpha 0.1 \
    --batch-size 2

All options:

Flag Default Description
--model (required) Base model ID
--data (required) CSV/JSONL with prompt, chosen, rejected columns
--output ./orpo_model Output directory
--epochs 3
--lr 1e-4 Learning rate
--beta 0.1 ORPO loss weight
--alpha 0.1 SFT vs preference balance
--batch-size 2

grpo — GRPO Fine-Tuning

Online reinforcement learning: several answers are generated per prompt and the ones that beat their group's average reward are reinforced. At least one reward source is required: --reward-model and/or built-in rewards (--reward). Without --reward, the reference-answer reward is used when the data has a reference column.

python main.py grpo \
    --policy-model TinyLlama/TinyLlama-1.1B-Chat-v1.0 \
    --reward-model ./reward_model \
    --data prompts.csv \
    --output ./grpo_model \
    --num-generations 4 \
    --max-completion-length 128

All options:

Flag Default Description
--policy-model (required) Model to train (HF ID or full model folder)
--data (required) CSV/JSONL with prompt; optional reference (expected answer)
--reward-model — Folder from the reward command
--output ./grpo_model Where the LoRA adapter is saved
--epochs 1 Passes over the prompts
--lr 1e-5 Learning rate
--num-generations 4 Completions per prompt (≥ 2)
--prompts-per-step 1 Prompts per optimisation step
--max-completion-length 128 Tokens generated per completion
--beta 0.0 KL penalty towards the original model (0 = off)
--resume off Continue from the newest checkpoint in --output (saved every 50 steps)
--reward see above Built-in reward, repeatable: reference, math, think_format, json, regex
--regex — Pattern for --reward regex (the whole output must match)
--loss-type dapo dapo, dr_grpo, grpo or bnpo
--lora-rank / --lora-alpha 16 / 32 LoRA size
--lora-variant LoRA LoRA, rsLoRA or DoRA
--use-vllm off Generate with vLLM on the training GPU (CUDA; pip install "trl[vllm]<1.15")

Example — reward JSON output that also matches a pattern:

python main.py grpo --policy-model ./sft_merged --data prompts.csv \
    --reward json --reward regex --regex '\{"answer": \d+\}' --loss-type dr_grpo

Data format (prompts.csv):

prompt,reference
"What is 12 × 12?","144"
"What is the capital of France?","Paris"

A reference-match reward gives 1 when the completion contains the reference text (case-insensitive).


kto — KTO Alignment

Aligns from single responses labelled good or bad — no ranked pairs needed.

python main.py kto \
    --model TinyLlama/TinyLlama-1.1B-Chat-v1.0 \
    --data feedback.csv \
    --output ./kto_model \
    --batch-size 4

All options:

Flag Default Description
--model (required) Base model ID
--data (required) prompt,completion,label or prompt,chosen,rejected
--output ./kto_model Where the LoRA adapter is saved
--epochs 1
--lr 5e-5 Learning rate
--beta 0.1 How far the model may move from the original
--batch-size 4 At least 2
--max-length 512 Max tokens for prompt + response
--resume off Continue from the newest checkpoint in --output (saved every 50 steps)

Data format (feedback.csv):

prompt,completion,label
"Summarise this email","Meeting moved to Friday at 3pm.",true
"Summarise this email","lol idk",false


distill — Knowledge Distillation

A small student learns a larger teacher's next-token distribution (TRL GKD), partly on its own answers. Teacher and student must share a vocabulary (same model family).

python main.py distill \
    --student Qwen/Qwen3-0.6B \
    --teacher Qwen/Qwen3-8B \
    --data chats.jsonl \
    --output ./distilled_model
Flag Default Description
--student (required) Small model to train (as a LoRA adapter)
--teacher (required) Larger model of the same family
--data (required) Chats (messages), instruction/output or prompt/completion
--output ./distilled_model Where the student adapter is saved
--epochs / --lr / --batch-size / --max-length 1 / 5e-5 / 2 / 512
--lmbda 0.5 Share of batches on the student's own answers (0–1)
--beta 0.5 Divergence: 0 ≈ forward KL, 1 ≈ reverse KL
--temperature 0.9 Sampling temperature for the student's answers
--max-new-tokens 128 Length of the student's own answers
--resume off Continue from the newest checkpoint in --output

embed — Embedding Model (search / RAG)

python main.py synthesize --input handbook.pdf --server http://localhost:8000 --output qa.jsonl
python main.py embed --data qa.jsonl --output ./handbook-embedder --hard-negatives
Flag Default Description
--model sentence-transformers/all-MiniLM-L6-v2 Embedding model (Hub id or folder)
--data (required) anchor/positive (optional negative), instruction/context (synthesize output), instruction/output, prompt/completion or chats
--output ./embedding_model Output directory
--lora off Train LoRA instead of all weights (merged into the saved model)
--epochs / --lr 1 / 2e-5 Training length and learning rate (LoRA: try 1e-4)
--batch-size 32 Bigger is better: the batch's other passages are the negatives
--max-seq-length 256 Tokens per query / passage
--matryoshka/--no-matryoshka on Also train truncated dimensions (512, 256, 128, 64)
--hard-negatives off Mine a similar non-answer passage per pair with the base model
--eval-split 0.1 Share of pairs held out to measure retrieval
--query-prompt the model's own Prefix for queries, e.g. query: for E5

Prints NDCG@10 / MRR@10 / Recall@10 before → after. See Training → Embedding Models.


evaluate — Batch Evaluation

Runs BLEU, ROUGE, and optionally BERTScore on your model. Generation is greedy (deterministic), so two runs — or two models — can be compared fairly.

python main.py evaluate \
    --model mistralai/Mistral-7B-v0.1 \
    --lora ./my_model \
    --data eval.csv \
    --compare-base \
    --max-new-tokens 150

All options:

Flag Default Description
--model (required) Model ID or path
--data (required) CSV/JSONL with a prompt column and optionally reference
--lora (optional) PEFT adapter path
--compare-base off Also score the base model with the LoRA adapter switched off (needs --lora)
--bertscore off Compute BERTScore (slower)
--batch-size 8 Generation batch size
--max-new-tokens 150 Max tokens per response

Output (with --compare-base):

📊 EVALUATION RESULTS
==================================================
metric           fine-tuned        base         Δ
BLEU-1                0.412       0.305     0.107
ROUGE-1               0.674       0.551     0.123
...

✅ Evaluation complete — 50 examples
💾 Saved to: eval_results_20260308_143012.csv

The CSV holds prompt, prediction, base_prediction (with --compare-base) and reference.


benchmark — Standard Benchmarks

Scores a model on standard benchmarks through lm-evaluation-harness (pip install "lm-eval>=0.4.13,<0.5", included in the eval extra).

python main.py benchmark \
    --model mistralai/Mistral-7B-v0.1 \
    --lora ./my_model \
    --tasks arc_easy,hellaswag \
    --limit 200 \
    --compare-base \
    --output scores.csv
Flag Default Description
--model (required) Model ID or path
--tasks arc_easy Comma-separated: arc_easy, arc_challenge, hellaswag, piqa, winogrande, boolq, truthfulqa_mc2, gsm8k
--lora (optional) PEFT adapter path (safetensors)
--limit 100 Examples per benchmark (1–10 000). Small limits give rough estimates
--compare-base off Also score the base model (needs --lora)
--batch-size 8 Evaluation batch size
--output (optional) Save the scores table as CSV

Scores are fractions (1.0 = 100%). Benchmark datasets are downloaded from the Hugging Face Hub on first use.


merge — Merge a LoRA Adapter

python main.py merge --adapter ./runs/my-run --output ./runs/my-run-merged

--base overrides the base model named in adapter_config.json. Works for LoRA and IA3 adapters.


merge-adapters — Combine LoRA Adapters

Merges several LoRA adapters trained on the same base model (e.g. one per skill) into one adapter, with PEFT's merge methods:

python main.py merge-adapters \
    --adapter ./runs/math --adapter ./runs/code \
    --weight 1 --weight 0.7 \
    --method ties --density 0.5 \
    --output ./runs/math-code
--method What it does
ties (default) Keeps each adapter's largest changes (--density), resolves sign conflicts — same rank
dare_ties / dare_linear Randomly drops and rescales changes, then TIES / weighted sum — same rank
linear Weighted sum — same rank
cat Exact concatenation; rank = sum of ranks
svd Exact sum compressed back with SVD — any ranks

DoRA adapters can't be merged (the merge would drop their magnitude vectors).


export — Export for Deployment

Flag Default Description
--model (required) Trained model or LoRA adapter folder
--output (required) Output folder
--format gguf gguf, fp8 or w4a16
--quant q6_k GGUF quantisation (q8_0, q6_k, q5_k_m, q4_k_m)
--calibration-data — w4a16: CSV/JSONL of training-like examples
--calibration-samples 128 w4a16: how many examples to use

GGUF needs Unsloth or llama.cpp; fp8/w4a16 need pip install -e ".[compress]" (from the repo folder). See 08 — Export & Deploy.


push — Upload to the Hub

HF_TOKEN=hf_... python main.py push --model ./runs/my-run --repo my-user/my-model

Creates the repo if needed and completes the model card (canonical base model, license). --token works too, but the environment keeps the token out of your shell history.


serve — OpenAI-compatible Server

LFT_SERVE_API_KEY=secret python main.py serve --model ./model.gguf --host 0.0.0.0 --port 8000
Flag Default Description
--model (required) .gguf file (llama-server), model/adapter folder or Hub id (vLLM)
--host 127.0.0.1 Bind address
--port 8000 Port
--name model Model name clients send

synthesize — Training Data from Documents

LFT_SYNTH_API_KEY=sk-... python main.py synthesize --input manual.pdf --input notes.md \
    --server http://localhost:8000 --output synthetic.jsonl
Flag Default Description
--input (required, repeatable) PDF / .docx / .txt / .md document
--output synthetic.jsonl JSONL file (instruction, output, context, source, score)
--server — OpenAI-compatible server URL (vLLM, llama-server, Ollama, hosted API)
--server-model first model the server lists Model name on the server
--model — Local model instead of a server (give --server or --model)
--pairs 5 Pairs per text chunk
--threshold 7 Drop pairs the writer rates below this (1–10; 0 keeps all, no rating)
--max-chunks 50 Stop after this many text chunks

The server's API key comes from LFT_SYNTH_API_KEY, never from the command line. The output trains directly: python main.py train --data synthetic.jsonl …. See Data Preparation.


Practical Automation Example

Run a full pipeline with a shell script:

#!/bin/bash
set -e

echo "Step 1: Fine-tune"
python main.py train \
    --model TinyLlama/TinyLlama-1.1B-Chat-v1.0 \
    --data data/train.csv \
    --output ./models/sft \
    --epochs 3

echo "Step 2: Train reward model"
python main.py reward \
    --model TinyLlama/TinyLlama-1.1B-Chat-v1.0 \
    --data data/reward.csv \
    --output ./models/reward \
    --epochs 2

echo "Step 3: GRPO alignment"
# The policy must be a full model: use the base model, or merge the SFT adapter
# first (Inference tab → Merge Adapter) and pass the merged folder.
python main.py grpo \
    --policy-model TinyLlama/TinyLlama-1.1B-Chat-v1.0 \
    --reward-model ./models/reward \
    --data data/prompts.csv \
    --output ./models/final

echo "Step 4: Evaluate"
python main.py evaluate \
    --model TinyLlama/TinyLlama-1.1B-Chat-v1.0 \
    --lora ./models/final \
    --data data/eval.csv \
    --bertscore

echo "All done!"

Exit Codes

Code Meaning
0 Success
1 Error (message printed to stderr)

Next Step

→ 10 — Advanced Usage: Heretic Mode, hardware tips, and expert tuning.