๐งโโ๏ธ Merlina - Magical Model Training
Train LLMs with ORPO, DPO, SimPO, CPO, IPO, KTO, and SFT using a delightful web interface powered by magic โจ
Features
- ๐จ Beautiful Web Interface - Cute wizard-themed UI with animations
- ๐งช 7 Training Modes - ORPO, DPO, SimPO, CPO, IPO, KTO, and SFT
- ๐ฌ Messages Format Support - Automatic detection and conversion of common chat dataset formats
- ๐ Flexible Datasets - HuggingFace, upload files (JSON/CSV/Parquet), or local paths
- ๐ Multiple Formats - ChatML, Llama 3, Mistral, custom templates, or automatic tokenizer-based formatting
- ๐ค Tokenizer Format - Automatically uses the model's native chat template
- ๐๏ธ 4-bit Quantization - Train large models on consumer GPUs
- ๐ช GGUF Export - Quantize any trained model to GGUF via llama.cpp (Q4_K_M, Q5_K_M, Q8_0, F16, and more)
- ๐ฎ llama-server Inference - Swap between transformers (base + LoRA) and a llama-server GGUF backend from the UI
- ๐ฆ Export & Artifacts - Dedicated Export section for post-hoc GGUF, HuggingFace uploads, and per-model artifact browsing / cleanup
- ๐ Real-time Monitoring - WebSocket updates with live metrics and GPU stats
- ๐พ Persistent Job Storage - SQLite database preserves jobs across restarts
- ๐ Job Queue - Priority-based queue with configurable concurrency
- โ Pre-flight Validation - Catch configuration errors before training starts
- ๐ค HuggingFace Integration - Push models directly to the Hub (public or private) with upload state tracking
- ๐ W&B Logging - Detailed experiment tracking
Quick Start
Pick your path โ all of them end at the same web UI:
| ๐ pip | pip install merlina then merlina serve |
| ๐ณ Docker | docker compose up with GPU passthrough |
| โ๏ธ RunPod | One-line setup script or GHCR image โ guide |
| ๐ Colab | |
| ๐ ๏ธ From source | git clone + pip install -r requirements.txt (below) |
About torch: Merlina deliberately does not install torch/torchvision/torchaudio โ GPU environments (RunPod, Colab, Lambda, etc.) ship CUDA-matched builds that pip would silently replace with broken generic ones. If you don't have torch yet, install it first:
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu128torchvision is required for VLM training (Qwen-VL, LLaVA, etc.) โ without it the model still trains, but the image-processor files are silently skipped and the uploaded checkpoint misses the vision side of the processor.
Option A: pip install
pip install merlina # add [vlm] / [diffusion] / [all] extras as needed
merlina serve # then open http://localhost:8000
Option B: Docker
Requires the NVIDIA Container Toolkit for GPU access.
docker run --gpus all -p 8000:8000 \
-v ./data:/app/data -v ./models:/app/models \
ghcr.io/schneewolf-labs/merlina:latest
Or clone the repo and docker compose up -d (see docker-compose.yml for
volumes and .env wiring).
Option C: From source
git clone https://github.com/Schneewolf-Labs/Merlina.git
cd Merlina
pip install -r requirements.txt
cp .env.example .env # optional: HF token, W&B key, etc.
python merlina.py
Visit http://localhost:8000 and start training! ๐
Interactive API docs (Swagger UI) are available at http://localhost:8000/docs, with ReDoc at http://localhost:8000/redoc and the raw OpenAPI spec at http://localhost:8000/openapi.json.
Training Modes
Merlina supports 7 training modes โ pick the one that fits your data and goals:
| Mode | Description | Requires Rejected? |
|---|---|---|
| ORPO | Odds Ratio Preference Optimization โ single-pass preference + SFT | Yes |
| DPO | Direct Preference Optimization โ log-ratio preference learning | Yes |
| SimPO | Simple Preference Optimization โ reference-free with length normalization | Yes |
| CPO | Contrastive Preference Optimization โ reference-free contrastive learning | Yes |
| IPO | Identity Preference Optimization โ squared-loss DPO, robust to noise | Yes |
| KTO | Kahneman-Tversky Optimization โ binary feedback, works with unpaired data | Optional |
| SFT | Supervised Fine-Tuning โ train on good examples only | No |
How to choose:
- Have paired chosen/rejected responses? โ ORPO, DPO, SimPO, CPO, or IPO
- Have binary feedback (thumbs up/down)? โ KTO
- Only have good examples? โ SFT
Dataset Configuration
Merlina supports flexible dataset sources and formats.
Sources:
- HuggingFace Hub โ Load any dataset from the Hub
- Upload Files โ JSON, JSONL, CSV, or Parquet files
- Local Path โ Use datasets from your filesystem
Formats:
- Tokenizer (Recommended) โ Automatically uses the model's chat template
- ChatML, Llama 3, Mistral โ Manual format selection
- Custom templates โ Define your own format
Messages Format (New in v1.3):
Merlina automatically detects and converts datasets in the common "messages" format used by many chat datasets. Multi-turn conversations are supported. Toggle this on/off via the UI or the convert_messages_format API parameter.
See the Dataset Guide for detailed instructions.
Training Configuration
The interface lets you configure:
- Base Model โ HuggingFace model IDs or local directory paths
- Training Mode โ ORPO, DPO, SimPO, CPO, IPO, KTO, or SFT
- LoRA Settings โ Rank, alpha, dropout, target modules
- Training Parameters โ Learning rate, epochs, batch size
- Mode-specific Hyperparameters โ Beta, gamma (SimPO), label smoothing (DPO/CPO)
- Options โ 4-bit quantization, W&B logging, HF Hub upload (public/private)
The UI dynamically adapts based on the selected training mode, showing only the relevant parameters.
Export & Quantization
After training, the Export section (step 6 in the nav) lets you work on any model under ./models/ without re-training. Three sub-panels:
- ๐ช GGUF Export โ Merge LoRA (if any) and produce one GGUF per selected quant (F16, Q8_0, Q6_K, Q5_K_M, Q5_K_S, Q4_K_M, Q4_K_S, Q3_K_M, Q2_K). Progress streams live over WebSocket. Artifacts land in
./models/{name}/gguf/with amanifest.jsonsidecar that the Inference picker reads. - ๐ค HuggingFace Upload โ Repo ID override, visibility, commit message, license/tags/description, and include-what checkboxes (LoRA adapter, merged full model, GGUF files, README). A "last uploaded" banner shows whether local files have been modified since your last push, plus full history of every upload attempt (success + failure).
- ๐๏ธ Artifacts โ Categorized file browser (adapter, merged, GGUF, tokenizer, processor, config, readme) with sizes and per-file delete. Core files (
config.json,adapter_config.json, tokenizer) are ๐-protected from the API.
llama.cpp integration
GGUF export and the llama-server inference backend are both powered by a local llama.cpp install. Merlina finds the binaries in this order:
LLAMA_CPP_DIRโ path to a llama.cpp checkout (must containconvert_hf_to_gguf.pyandbuild/bin/)LLAMA_CPP_BIN_DIRโ path to just the built binaries- System
$PATHโ ifllama-quantize,llama-server, etc. are installed globally ./vendor/llama.cppโ conventional local clone
If none are found, the GGUF and llama-server features stay disabled in the UI and pre-flight emits an advisory warning (never a blocking error). Check GET /llama-cpp/status to see what the resolver found.
Inference backends
The Inference section exposes two backends:
- transformers โ base model + LoRA adapter, runs on GPU with optional 4-bit quantization. The default.
- llama_cpp โ GGUF served by
llama-serveras a subprocess. Picked automatically when you select a GGUF entry from the model dropdown (they appear as indented sub-options per model).
Directory Structure
merlina/
โโโ merlina.py # Backend server (main entry point)
โโโ config.py # Configuration management
โโโ version.py # Version information
โโโ bump_version.py # Version bumping tool
โโโ requirements.txt # Python dependencies
โโโ Makefile # Build/run shortcuts
โโโ .env.example # Configuration template
โ
โโโ src/ # Source modules
โ โโโ job_manager.py # SQLite job persistence
โ โโโ job_queue.py # Priority-based job queue
โ โโโ websocket_manager.py # Real-time updates
โ โโโ preflight_checks.py # Configuration validation
โ โโโ training_runner.py # Training logic + sync merge orchestration
โ โโโ merge_artifact.py # Ref-counted shared merged-model dir
โ โโโ gguf_exporter.py # LoRA merge + GGUF convert/quantize pipeline
โ โโโ llama_cpp_resolver.py # llama.cpp binary discovery
โ โโโ llama_server.py # llama-server subprocess inference backend
โ โโโ upload_state.py # Per-model HF upload history sidecar
โ โโโ model_artifacts.py # Artifact inventory + safe deletion
โ โโโ config_manager.py # Configuration management
โ โโโ gpu_utils.py # GPU detection and monitoring
โ โโโ model_card.py # Model card generation
โ โโโ constants.py # Shared constants
โ โโโ exceptions.py # Custom exceptions
โ โโโ utils.py # Utilities
โ
โโโ dataset_handlers/ # Dataset pipeline
โ โโโ base.py # Abstract interfaces
โ โโโ loaders.py # Dataset loaders (HF, local, upload)
โ โโโ formatters.py # Format strategies (ChatML, Llama3, etc.)
โ โโโ messages_converter.py # Messages format auto-conversion
โ โโโ factory.py # Formatter factory
โ โโโ validators.py # Validation logic
โ
โโโ frontend/ # Web interface (no build step)
โ โโโ index.html
โ โโโ css/
โ โโโ js/
โ
โโโ docs/ # Documentation
โ โโโ user/ # User guides
โ โโโ dev/ # Developer docs
โ
โโโ examples/ # Example scripts and configs
โโโ tests/ # Test suite
โโโ data/ # Runtime data (created automatically)
โโโ jobs.db # SQLite database
API Endpoints
Training & Jobs:
POST /train?priority=normalโ Submit training job (priority: low/normal/high)GET /status/{job_id}โ Get job progress and queue statusGET /jobsโ List all jobsGET /jobs/historyโ Paginated job historyGET /jobs/{job_id}/metricsโ Detailed training metricsPOST /jobs/{job_id}/stopโ Cancel queued or stop running job
Queue Management:
GET /queue/statusโ Queue statistics and job listsGET /queue/jobsโ List queued and running jobs
Dataset Management:
POST /dataset/previewโ Preview raw dataset (10 samples)POST /dataset/preview-formattedโ Preview with formatting appliedPOST /dataset/upload-fileโ Upload dataset fileGET /dataset/uploadsโ List uploaded datasets
Export & Artifacts:
GET /models/{name}/artifactsโ Categorized file inventory (adapter, merged, GGUF, tokenizer, etc.)DELETE /models/{name}/artifacts?path=โฆโ Delete a file (protected core files refused)GET /models/{name}/upload-stateโ Upload history + "local is newer" freshness hintPOST /models/{name}/uploadโ Post-hoc HuggingFace upload with advanced optionsPOST /models/{name}/export-ggufโ Post-hoc GGUF export (merges LoRA + runs llama-quantize)GET /llama-cpp/statusโ Resolver status (available binaries, supported quant types)
Inference:
GET /inference/modelsโ List local models (plus discovered GGUF artifacts per model)POST /inference/loadโ Load a model (backend: "transformers" | "llama_cpp")POST /inference/chatโ Send a chat completion to the loaded backendPOST /inference/unloadโ Free VRAM / stop llama-serverGET /inference/statusโ Current backend + model
Validation & Info:
POST /validateโ Validate configuration before trainingGET /versionโ Current version infoGET /statsโ Database and system statisticsGET /docsโ Interactive API documentation (Swagger UI)GET /redocโ API documentation (ReDoc)GET /openapi.jsonโ OpenAPI specification
WebSocket:
WS /ws/{job_id}โ Real-time training and export updates (status, metrics,gguf_progress)
Full API documentation: API.md
MCP Server
Merlina ships an MCP server so an LLM agent (Claude Desktop, Claude Code, Cursor, โฆ) can drive the workshop conversationally โ queue training jobs, watch progress, preview datasets, and manage the GPU queue. It's a thin HTTP client to a running Merlina server, so it pulls in no torch.
# 1. Start Merlina as usual
merlina serve # or: python merlina.py
# 2. In another shell (or wired into your MCP client), run the MCP server
pip install 'merlina[mcp]'
MERLINA_API_URL=http://localhost:8000 merlina-mcp
Wire it into an MCP client (e.g. Claude Desktop's claude_desktop_config.json):
{
"mcpServers": {
"merlina": {
"command": "merlina-mcp",
"env": { "MERLINA_API_URL": "http://localhost:8000" }
}
}
}
Exposed tools include start_training, get_job_status, get_job_history,
get_job_metrics, stop_job, queue_status, validate_training_config,
preview_dataset, list_local_models, list_gpus, and get_stats. See
docs/user/mcp.md for the full reference.
GPU Memory Requirements
With 4-bit quantization enabled (default):
| Model Size | VRAM Required |
|---|---|
| 3B params | ~6 GB |
| 7B params | ~10 GB |
| 13B params | ~16 GB |
Environment Variables
Configure via .env file or environment variables:
# External services โ setting these here means clients don't need to send
# tokens in HTTP request bodies. Tokens in requests still override env.
WANDB_API_KEY=your_wandb_key # Weights & Biases logging
HF_TOKEN=your_huggingface_token # HuggingFace Hub access (gated models, uploads)
# Server
HOST=0.0.0.0 # Server bind address
PORT=8000 # Server port
# System
CUDA_VISIBLE_DEVICES=0 # GPU selection
MAX_CONCURRENT_JOBS=1 # Queue concurrency (increase for multi-GPU)
LOG_LEVEL=INFO # Logging verbosity
# llama.cpp (optional โ enables GGUF export and llama-server inference)
LLAMA_CPP_DIR=/opt/llama.cpp # Path to a llama.cpp checkout (preferred)
LLAMA_CPP_BIN_DIR= # Or just the binary directory
See .env.example for all available options.
Docker Support
FROM nvidia/cuda:11.8.0-cudnn8-runtime-ubuntu22.04
WORKDIR /app
RUN apt-get update && apt-get install -y python3.10 python3-pip
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["python3", "merlina.py"]
Build and run:
docker build -t merlina .
docker run --gpus all -p 8000:8000 merlina
Documentation
- ๐ Quick Start Guide โ Get started in minutes
- ๐ Dataset Guide โ Configure datasets (HuggingFace, local, uploads)
- ๐ค Tokenizer Format Guide โ Automatic chat formatting (recommended!)
- โ๏ธ Configuration Management โ Save and reuse training configs
- ๐ New Features Guide โ What's new in v1.1+
- ๐ MCP Server Guide โ Drive Merlina from an LLM agent via Model Context Protocol
- ๐ Examples โ Ready-to-use training configurations
- ๐ก API Reference โ Full REST and WebSocket API docs
For Developers:
- ๐๏ธ Developer Docs โ Implementation details and architecture
- ๐งช Tests โ Test suite and fixtures
Tips
- ๐ฏ Start with 1-2 epochs for testing
- ๐พ Models are saved to
./models/{output_name} - ๐ Enable W&B for detailed metrics
- ๐ง Adjust LoRA rank based on your GPU memory
- โจ Try the Konami code in the UI for a surprise!
Credits
Created with ๐ by Schneewolf Labs
License
MIT License โ feel free to use for your magical model training!
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file merlina-2.2.0.tar.gz.
File metadata
- Download URL: merlina-2.2.0.tar.gz
- Upload date:
- Size: 685.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b02df03ea3939fe559f314788aefbeecbf2fbe44d6c49e80fe8e7f21aadafd47
|
|
| MD5 |
b93e3c404b17b6a4c0a3633e7a895db1
|
|
| BLAKE2b-256 |
a34410ec1d44a3568f1865d6c80122f0574389aad5438543944bc06510c2c15a
|
Provenance
The following attestation bundles were made for merlina-2.2.0.tar.gz:
Publisher:
publish.yml on Schneewolf-Labs/Merlina
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
merlina-2.2.0.tar.gz -
Subject digest:
b02df03ea3939fe559f314788aefbeecbf2fbe44d6c49e80fe8e7f21aadafd47 - Sigstore transparency entry: 2467598435
- Sigstore integration time:
-
Permalink:
Schneewolf-Labs/Merlina@2c308417fbf0b974951a83e3d6b23f684f21a223 -
Branch / Tag:
refs/tags/v2.2.0 - Owner: https://github.com/Schneewolf-Labs
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@2c308417fbf0b974951a83e3d6b23f684f21a223 -
Trigger Event:
release
-
Statement type:
File details
Details for the file merlina-2.2.0-py3-none-any.whl.
File metadata
- Download URL: merlina-2.2.0-py3-none-any.whl
- Upload date:
- Size: 492.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
85480b041c027009dbbefba444970121524254d1c30a18c6c5c5a31a25380325
|
|
| MD5 |
aaf31067c7e294780f1d0389ad6f6918
|
|
| BLAKE2b-256 |
03ff6c44e89c212c16961979cd8ae75f3f90661aa280db259fb207ae6f33a914
|
Provenance
The following attestation bundles were made for merlina-2.2.0-py3-none-any.whl:
Publisher:
publish.yml on Schneewolf-Labs/Merlina
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
merlina-2.2.0-py3-none-any.whl -
Subject digest:
85480b041c027009dbbefba444970121524254d1c30a18c6c5c5a31a25380325 - Sigstore transparency entry: 2467598501
- Sigstore integration time:
-
Permalink:
Schneewolf-Labs/Merlina@2c308417fbf0b974951a83e3d6b23f684f21a223 -
Branch / Tag:
refs/tags/v2.2.0 - Owner: https://github.com/Schneewolf-Labs
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@2c308417fbf0b974951a83e3d6b23f684f21a223 -
Trigger Event:
release
-
Statement type: