euhidaman/EmberNet

0

stars

165

commits

Python

primary language

Mar 4, 2026

updated

README

EmberNet - Tiny BitNet MoE Vision-Language Model

A high-quality, tiny BitNet b1.58-style Mixture-of-Experts Vision-Language Model (~300M ternary parameters) designed for edge deployment.

What it does: You give it an image + a question, it gives you an intelligent answer. OCR, chart analysis, document understanding, visual reasoning - all in <500MB.


Table of Contents

  1. Quick Start
  2. How It Works
  3. Complete Dataset List
  4. Training Guide
  5. Usage Examples
  6. Architecture Details

Quick Start

Complete Setup & Training Guide

Follow these steps in order to set up and train EmberNet:

Step 1: Install Dependencies

# Navigate to project directory
cd EmberNet

# Install all required packages
pip install -r requirements.txt

Required packages:

  • torch>=2.0.0 - Deep learning framework
  • transformers>=4.36.0 - HuggingFace transformers (for SigLIP)
  • datasets>=2.14.0 - HuggingFace datasets
  • wandb>=0.16.0 - Experiment tracking
  • huggingface_hub>=0.19.0 - HuggingFace authentication
  • Pillow>=9.0.0 - Image processing
  • einops>=0.7.0 - Tensor operations
  • numpy>=1.24.0 - Numerical computing

Step 2: Authentication Setup

2a. HuggingFace Login (REQUIRED - for downloading datasets):

# Login to HuggingFace
huggingface-cli login

# When prompted, enter your HuggingFace token
# Get your token from: https://huggingface.co/settings/tokens
# Create a token with "read" permissions

2b. Weights & Biases Login (OPTIONAL - for experiment tracking):

# Login to W&B
wandb login

# When prompted, enter your W&B API key
# Get your API key from: https://wandb.ai/authorize
# This enables training visualization and metric tracking

Step 3: Download Training Datasets

Choose one option based on your needs:

Option A: All Datasets (~100GB) - Best quality, all datasets

python training/prepare_data.py --all --output-dir ./data

Downloads all 20 datasets for maximum model quality.

Option B: Recommended (~70GB) - Good balance of quality and size

python training/prepare_data.py --recommended --output-dir ./data

Downloads critical + recommended datasets (excludes optional ones).

Option C: Critical Only (~50GB) - Core datasets only

python training/prepare_data.py --critical --output-dir ./data

Downloads only the most important datasets.

Option D: Minimal (~10GB) - Quick testing

python training/prepare_data.py --minimal --output-dir ./data

Downloads a tiny subset for testing the pipeline.

Other useful commands:

# List all available datasets before downloading
python training/prepare_data.py --list

# Download specific datasets only
python training/prepare_data.py --dataset textvqa chartqa vqav2 --output-dir ./data

# Explain how alignment works
python training/prepare_data.py --explain

What gets downloaded:

  • Stage 1 datasets: LLaVA-Instruct, ShareGPT4V, ALLaVA, COCO Captions, etc.
  • Stage 2 datasets: TextVQA, DocVQA, AI2D, ChartQA, PlotQA, VQAv2, GQA, OK-VQA, A-OKVQA, ScienceQA, RefCOCO, NLVR2, VSR, and more

Note: Some datasets (ShareGPT4V, ALLaVA, ChartQA, GQA, VSR) download images from URLs, which may take longer than loading pre-packaged datasets.

What gets saved: After downloading, you'll have:

  • ./data/{dataset_name}/ - Each dataset in its own folder
  • ./data/download_manifest.json - Central tracking file with all download info
  • ./data/dataset_index.json - Index mapping datasets to stages/domains
  • ./data/{dataset_name}/metadata.json - Individual dataset metadata

The download_manifest.json tracks:

  • All download sessions with timestamps
  • Dataset metadata (samples, size, domain, expert)
  • Download times and success/failure status
  • File paths and HuggingFace IDs

Step 4: Train the Model

EmberNet uses a two-stage training pipeline. Use --trial for quick validation or --main for full training.


πŸš€ Quick Start: Single-Command Training

# Trial Run - Quick pipeline validation (minutes, not hours)
python training/train.py --trial --data-dir ./data

# Main Run - Full production training (hours/days)
python training/train.py --main --data-dir ./data

Both commands automatically run Stage 1 β†’ Stage 2 sequentially.


Trial Mode (--trial)

Validates the entire pipeline with minimal data:

python training/train.py --trial --data-dir ./data
SettingValue
Samples per dataset50
Epochs per stage1
Batch size2
Gradient accumulation1
W&B loggingDisabled
Output./checkpoints/trial/stage{1,2}/

Use this to verify everything works before committing to full training.


Main Mode (--main)

Full production training with all data:

python training/train.py --main --data-dir ./data
SettingStage 1Stage 2
SamplesALLALL
Epochs310
Batch size84
Gradient accumulation44
W&B loggingEnabledEnabled
Output./checkpoints/stage1/./checkpoints/stage2/

Run a Specific Stage Only

# Stage 1 only (projector alignment)
python training/train.py --trial --stage 1 --data-dir ./data

# Stage 2 only (expert specialization) - requires Stage 1 checkpoint
python training/train.py --trial --stage 2 --data-dir ./data \
    --resume ./checkpoints/trial/stage1/final_model.pt

Training Options

# Custom epochs and batch size
python training/train.py --main --data-dir ./data --epochs 5 --batch-size 4

# Limit samples per dataset (useful for debugging)
python training/train.py --main --data-dir ./data --max-samples-per-dataset 1000

# Disable specific features
python training/train.py --main --data-dir ./data \
    --no-wandb \          # Disable W&B logging
    --no-ema \            # Disable EMA
    --no-curriculum \     # Disable curriculum learning
    --no-adaptive-clip    # Disable adaptive gradient clipping

# Hardware adjustments
python training/train.py --main --data-dir ./data \
    --device cpu \        # Force CPU (slower)
    --no-amp \            # Disable mixed precision
    --num-workers 2       # Reduce data loading workers

Output Structure

After training completes:

checkpoints/
β”œβ”€β”€ trial/                    # Trial mode outputs
β”‚   β”œβ”€β”€ stage1/
β”‚   β”‚   β”œβ”€β”€ final_model.pt    # Stage 1 checkpoint
β”‚   β”‚   └── checkpoint_epoch_1.pt
β”‚   └── stage2/
β”‚       β”œβ”€β”€ final_model.pt    # Stage 2 checkpoint (final model)
β”‚       └── checkpoint_epoch_1.pt
β”‚
β”œβ”€β”€ stage1/                   # Main mode outputs
β”‚   β”œβ”€β”€ final_model.pt
β”‚   β”œβ”€β”€ best_model.pt
β”‚   └── checkpoint_epoch_*.pt
β”‚
└── stage2/
    β”œβ”€β”€ final_model.pt        # ← Use this for inference
    β”œβ”€β”€ best_model.pt
    └── checkpoint_epoch_*.pt

What Each Stage Does

StagePurposeWhat TrainsWhat's Frozen
Stage 1Vision-Language AlignmentCrossModal Projector, Pooler, CompressorVision Encoder, LM Decoder
Stage 2Expert SpecializationMoE Router, Domain ExpertsVision Encoder, Projector, Embeddings

Step 5: Convert Model (Optional)

Convert to optimized ternary format for deployment:

python inference/convert.py \
    ./checkpoints/stage2/final_model.pt \
    ./embernet_optimized.pt

This packs ternary weights to 2-bit representation, reducing model size to <500MB.


Step 6: Run Inference

Interactive Mode:

python inference/infer.py \
    --model ./checkpoints/stage2/final_model.pt \
    --interactive

Interactive commands:

  • /load image.jpg - Load an image
  • /describe - Describe the image
  • /ocr - Extract text from image
  • /chart - Analyze chart/graph
  • /clear - Reset conversation
  • /quit - Exit

Single Query:

python inference/infer.py \
    --model ./checkpoints/stage2/final_model.pt \
    --image photo.jpg \
    --prompt "What's in this image?"

Quick Reference: All Commands in Order

# 1. Install dependencies
cd EmberNet
pip install -r requirements.txt

# 2. Authenticate (HF required, W&B optional)
huggingface-cli login   # Enter token from https://huggingface.co/settings/tokens
wandb login             # Optional: Enter API key from https://wandb.ai/authorize

# 3. Download training data
python training/prepare_data.py --recommended --output-dir ./data   # ~70GB
# OR: python training/prepare_data.py --all --output-dir ./data     # ~100GB (best quality)
# OR: python training/prepare_data.py --minimal --output-dir ./data # ~10GB (testing only)

# 4. Train the model (SINGLE COMMAND - runs Stage 1 β†’ Stage 2 automatically)
python training/train.py --trial --data-dir ./data   # Quick test (~minutes)
# OR:
python training/train.py --main --data-dir ./data    # Full training (~hours/days)

# 5. Run interactive inference
python inference/infer.py --model ./checkpoints/stage2/final_model.pt --interactive

How It Works

Vision-Language Alignment Explained

EmberNet connects images to language through a carefully designed pipeline:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                           IMAGE INPUT                                    β”‚
β”‚                              ↓                                          β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”‚
β”‚  β”‚ 1. VISION ENCODER (SigLIP - Frozen)                            β”‚    β”‚
β”‚  β”‚    β€’ Pretrained on 400M image-text pairs from Google           β”‚    β”‚
β”‚  β”‚    β€’ Extracts 196 visual tokens (14Γ—14 grid)                   β”‚    β”‚
β”‚  β”‚    β€’ Each token is a 768-dimensional feature vector            β”‚    β”‚
β”‚  β”‚    β€’ Already "understands" visual concepts                     β”‚    β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚
β”‚                              ↓                                          β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”‚
β”‚  β”‚ 2. TOKEN COMPRESSION (Trainable)                               β”‚    β”‚
β”‚  β”‚    β€’ Pixel Shuffle: 196 β†’ 49 tokens (merges 2Γ—2 neighbors)     β”‚    β”‚
β”‚  β”‚    β€’ Adaptive Pooling: 49 β†’ 64 tokens (learned queries)        β”‚    β”‚
β”‚  β”‚    β€’ Preserves important visual information                    β”‚    β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚
β”‚                              ↓                                          β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”‚
β”‚  β”‚ 3. PROJECTOR (BitLinear MLP) ← THIS IS WHERE ALIGNMENT HAPPENS β”‚    β”‚
β”‚  β”‚    β€’ 2-layer MLP with ternary weights {-1, 0, +1}              β”‚    β”‚
β”‚  β”‚    β€’ Maps: Vision embedding space β†’ Language embedding space   β”‚    β”‚
β”‚  β”‚    β€’ Trained in Stage 1 on image-caption pairs                 β”‚    β”‚
β”‚  β”‚    β€’ After training, visual tokens "look like" word tokens     β”‚    β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚
β”‚                              ↓                                          β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”‚
β”‚  β”‚ 4. MERGED INPUT SEQUENCE                                       β”‚    β”‚
β”‚  β”‚    [BOS] [IMG₁] [IMGβ‚‚] ... [IMG₆₄] [User: Describe this] ...  β”‚    β”‚
β”‚  β”‚          └── visual tokens β”€β”€β”˜     └── text tokens β”€β”€β”€β”€β”€β”€β”˜     β”‚    β”‚
β”‚  β”‚    The LLM processes both as if they're all "text"             β”‚    β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚
β”‚                              ↓                                          β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”‚
β”‚  β”‚ 5. BITNET MOE DECODER                                          β”‚    β”‚
β”‚  β”‚    β€’ 16 transformer layers with ternary weights                β”‚    β”‚
β”‚  β”‚    β€’ MoE FFN: 8 specialized experts + 1 shared expert          β”‚    β”‚
β”‚  β”‚    β€’ Router sends tokens to relevant experts:                  β”‚    β”‚
β”‚  β”‚      - OCR expert for text reading                             β”‚    β”‚
β”‚  β”‚      - Chart expert for graphs                                 β”‚    β”‚
β”‚  β”‚      - Diagram expert for technical drawings                   β”‚    β”‚
β”‚  β”‚      - etc.                                                    β”‚    β”‚
β”‚  β”‚    β€’ Generates response token by token                         β”‚    β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚
β”‚                              ↓                                          β”‚
β”‚                        TEXT OUTPUT                                      β”‚
β”‚            "This image shows a bar chart comparing..."                  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Why Two Training Stages?

Stage 1 - Projector Alignment:

  • Goal: Teach the model to "see" by connecting visual features to language
  • What's trained: Projector MLP + Token compression layers
  • What's frozen: Vision encoder + Language decoder
  • Data: High-quality image descriptions (LLaVA-Instruct, ShareGPT4V)
  • Why: The projector needs to learn that "this visual pattern" = "the concept of a dog"

Stage 2 - Expert Specialization:

  • Goal: Make experts good at specific tasks (OCR, charts, diagrams, etc.)
  • What's trained: MoE experts + Router
  • What's frozen: Vision encoder + Embeddings
  • Data: Domain-specific datasets (TextVQA, ChartQA, DocVQA, etc.)
  • Why: Different visual tasks need different skills - one expert can't do everything well

Expert Architecture & Dataset Mapping

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    EMBERNET MoE EXPERT ARCHITECTURE                          β”‚
β”‚                                                                              β”‚
β”‚  ROUTING: Each token β†’ TOP-2 Experts + SHARED Expert (always active)        β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                              β”‚
β”‚  EXPERT 0: vision_ocr                                                        β”‚
β”‚  β”œβ”€ Specialty: Read text in images, OCR, document parsing                   β”‚
β”‚  └─ Datasets: TextVQA, DocVQA, OCR-VQA                                      β”‚
β”‚                                                                              β”‚
β”‚  EXPERT 1: vision_diagram                                                    β”‚
β”‚  β”œβ”€ Specialty: Understand diagrams, infographics, technical drawings        β”‚
β”‚  └─ Datasets: AI2D, InfoVQA                                                 β”‚
β”‚                                                                              β”‚
β”‚  EXPERT 2: code_math_chart                                                   β”‚
β”‚  β”œβ”€ Specialty: Analyze charts, graphs, plots, data visualizations           β”‚
β”‚  └─ Datasets: ChartQA, PlotQA, FigureQA, DVQA                              β”‚
β”‚                                                                              β”‚
β”‚  EXPERT 3: code_math_formula                                                 β”‚
β”‚  β”œβ”€ Specialty: Handle math equations, formulas, numerical reasoning         β”‚
β”‚  └─ Datasets: MathVista                                                     β”‚
β”‚                                                                              β”‚
β”‚  EXPERT 4: spatial_scene                                                     β”‚
β”‚  β”œβ”€ Specialty: Scene understanding, object detection, descriptions          β”‚
β”‚  └─ Datasets: VQAv2, Visual Genome                                          β”‚
β”‚                                                                              β”‚
β”‚  EXPERT 5: spatial_reasoning                                                 β”‚
β”‚  β”œβ”€ Specialty: Spatial relationships, counting, positional reasoning        β”‚
β”‚  └─ Datasets: GQA                                                           β”‚
β”‚                                                                              β”‚
β”‚  EXPERT 6: agentic_knowledge                                                 β”‚
β”‚  β”œβ”€ Specialty: Knowledge-based QA, facts requiring world knowledge          β”‚
β”‚  └─ Datasets: OK-VQA, A-OKVQA                                               β”‚
β”‚                                                                              β”‚
β”‚  EXPERT 7: agentic_reasoning                                                 β”‚
β”‚  β”œβ”€ Specialty: Multi-step reasoning, logic, science questions               β”‚
β”‚  └─ Datasets: ScienceQA, CLEVR                                              β”‚
β”‚                                                                              β”‚
β”‚  SHARED EXPERT (Always Active)                                               β”‚
β”‚  β”œβ”€ Specialty: Common patterns, language generation, general knowledge      β”‚
β”‚  └─ Datasets: ALL datasets (learns shared representations)                  β”‚
β”‚                                                                              β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Example Routing:
  User: "What does this chart show? The title says Q3 Sales."
         β”‚
         β”œβ”€> EXPERT 0 (vision_ocr)    - reads "Q3 Sales" text
         β”œβ”€> EXPERT 2 (chart)          - analyzes chart structure  
         └─> SHARED EXPERT             - general language/context
         
  Combined output: "This bar chart shows Q3 sales data..."

Complete Dataset List

Stage 1: Vision-Language Alignment

DatasetHuggingFace IDDescriptionSamplesSize
LLaVA-Instruct-150K β˜…lmms-lab/LLaVA-Instruct-150KGPT-4 generated visual conversations150K~5GB
ShareGPT4V β˜…lmms-lab/ShareGPT4VDetailed image descriptions from GPT-4V100K~8GB
ALLaVAFreedomIntelligence/ALLaVA-4VDiverse visual instructions711K~6GB

Stage 2: Expert Specialization

Vision/OCR Expert Datasets

DatasetHuggingFace IDDescriptionSamplesSize
TextVQA β˜…lmms-lab/TextVQAText in natural scenes45K~2GB
DocVQA β˜…lmms-lab/DocVQADocuments, forms, receipts50K~3GB
AI2D β˜…lmms-lab/ai2dScientific diagrams15K~1.5GB
InfoVQAlmms-lab/InfographicVQAInfographics30K~2.5GB
OCR-VQAhoward-hou/OCR-VQABook covers, signs200K~4GB

Code/Math/Chart Expert Datasets

DatasetHuggingFace IDDescriptionSamplesSize
ChartQA β˜…ahmed-masry/ChartQABar, line, pie charts32K~1GB
MathVista β˜…AI4Math/MathVistaMathematical visual reasoning6K~1GB
PlotQAlmms-lab/PlotQAScientific plots224K~8GB
FigureQAlmms-lab/FigureQAFigure understanding180K~5GB
DVQAlmms-lab/DVQAData visualization300K~3GB

Spatial/Scene Expert Datasets

DatasetHuggingFace IDDescriptionSamplesSize
VQAv2 β˜…lmms-lab/VQAv2General visual QA1.1M~25GB
GQAlmms-lab/GQAScene graph reasoning22M~15GB
Visual Genomelmms-lab/VisualGenomeDense scene annotations108K~15GB

Reasoning Expert Datasets

DatasetHuggingFace IDDescriptionSamplesSize
ScienceQA β˜…derek-thomas/ScienceQAScience with diagrams21K~2GB
OK-VQAlmms-lab/OK-VQAOutside knowledge VQA14K~1GB
A-OKVQAlmms-lab/A-OKVQAAugmented knowledge VQA25K~1.5GB
CLEVRlmms-lab/CLEVRCompositional reasoning850K~18GB

β˜… = Critical (included in --critical mode)

Download Options

# Minimal (~10GB) - For quick testing only
python training/prepare_data.py --minimal
# Includes: llava_instruct_150k, textvqa, chartqa, vqav2

# Critical (~45GB) - Essential for a working model
python training/prepare_data.py --critical
# Includes: All β˜… marked datasets above

# Recommended (~70GB) - Good quality model
python training/prepare_data.py --recommended
# Includes: Critical + recommended datasets

# All (~100GB) - Maximum quality
python training/prepare_data.py --all
# Includes: Everything

Training Guide

Hardware Requirements

StageMinimumRecommendedNotes
Stage 18GB VRAM16GB VRAMCan use CPU with 16GB RAM (slower)
Stage 212GB VRAM24GB VRAMCan use CPU with 32GB RAM (slower)

Expected Training Time

StageGPU (A100)GPU (RTX 3090)CPU (32 cores)
Stage 1 (3 epochs)6-12 hours12-24 hours3-5 days
Stage 2 (10 epochs)24-48 hours48-96 hours10-15 days

Training Commands Reference

Basic Training (Recommended):

# Stage 1: Projector Alignment
python training/train.py \
    --stage 1 \
    --data-dir ./data \
    --epochs 3 \
    --batch-size 8 \
    --output-dir ./checkpoints

# Stage 2: Expert Specialization  
python training/train.py \
    --stage 2 \
    --data-dir ./data \
    --epochs 10 \
    --batch-size 4 \
    --resume ./checkpoints/checkpoint_epoch_3.pt \
    --output-dir ./checkpoints

With W&B Logging (Recommended):

# Stage 1
python training/train.py \
    --stage 1 \
    --data-dir ./data \
    --epochs 3 \
    --batch-size 8 \
    --wandb-project EmberNet \
    --wandb-run-name stage1_projector

# Stage 2
python training/train.py \
    --stage 2 \
    --data-dir ./data \
    --epochs 10 \
    --batch-size 4 \
    --resume ./checkpoints/checkpoint_epoch_3.pt \
    --wandb-project EmberNet \
    --wandb-run-name stage2_experts

Custom Learning Rate:

python training/train.py \
    --stage 1 \
    --data-dir ./data \
    --epochs 3 \
    --lr 5e-4

Resume from Checkpoint:

python training/train.py \
    --stage 2 \
    --data-dir ./data \
    --resume ./checkpoints/checkpoint_epoch_5.pt

Troubleshooting

Out of Memory (OOM) Errors:

# Reduce batch size and increase gradient accumulation
python training/train.py \
    --stage 1 \
    --data-dir ./data \
    --batch-size 2 \
    --grad-accum 16
# Effective batch size = 2 * 16 = 32

Slow Training:

# Check if GPU is being used
python training/train.py --stage 1 --data-dir ./data --device cuda

# Increase number of data loading workers
python training/train.py --stage 1 --data-dir ./data --num-workers 8

Mixed Precision Issues:

# Disable automatic mixed precision
python training/train.py --stage 1 --data-dir ./data --no-amp

CPU Training:

# Force CPU (much slower but works without GPU)
python training/train.py --stage 1 --data-dir ./data --device cpu --batch-size 1

All Training Arguments

Training Settings:
  --stage {1,2}              Training stage (1=projector, 2=expert SFT)
  --epochs N                 Number of training epochs (default: 3)
  --batch-size N             Training batch size (default: 4)
  --lr LR                    Learning rate (auto-set: 1e-3 for stage1, 1e-4 for stage2)
  --grad-accum N             Gradient accumulation steps (default: 4)

Paths:
  --data-dir DIR             Data directory (default: ./data)
  --output-dir DIR           Output directory for checkpoints (default: ./checkpoints)
  --resume PATH              Resume from checkpoint

Hardware:
  --device DEVICE            Device: cuda/cpu/auto (default: auto)
  --no-amp                   Disable mixed precision training
  --num-workers N            Data loading workers (default: 4)

Experiment Tracking:
  --wandb                    Use W&B logging (default: True)
  --no-wandb                 Disable W&B logging
  --wandb-project NAME       W&B project name (default: EmberNet)
  --wandb-run-name NAME      W&B run name (default: auto-generated)

What Gets Saved

During training, the following checkpoints are saved to --output-dir:

  • checkpoint_epoch_N.pt - Saved after each epoch
  • checkpoint_step_N.pt - Saved every N steps (configurable)
  • best_model.pt - Best model based on validation loss
  • final_model.pt - Final model after all epochs

Each checkpoint contains:

  • Model state dict
  • Optimizer state dict
  • Scheduler state dict
  • Training configuration
  • Current epoch and step
  • Best loss so far

Monitoring Training

With Weights & Biases: Visit https://wandb.ai/your-username/EmberNet to see:

  • Real-time loss curves
  • Learning rate schedules
  • Token statistics
  • Gradient norms
  • Model parameters
  • System metrics (GPU/CPU usage, memory)

Console Output:

======================================================================
Starting Stage 1 Training
======================================================================
Epochs: 3
Steps per epoch: 1000
Total steps: 3000
Batch size: 8
Gradient accumulation: 4
Effective batch size: 32
Learning rate: 0.001
Device: cuda

--- Token Statistics (per sample) ---
Total tokens:  2,048
  β”œβ”€ Image tokens: 64
  └─ Text tokens:  1,984

--- Token Statistics (per batch) ---
Total tokens:  16,384
  β”œβ”€ Image tokens: 512
  └─ Text tokens:  15,872

--- Total Training Tokens (all epochs) ---
Total tokens:  49,152,000
  β”œβ”€ Image tokens: 1,536,000
  └─ Text tokens:  47,616,000
======================================================================

Epoch 1/3 | Step 100 | Loss: 2.3456 | Avg Loss: 2.4567 | LR: 1.00e-03

Usage Examples

Python API

from inference.infer import EmberVLM

# Load model
model = EmberVLM("checkpoints/embernet.pt")

# Basic image Q&A
response = model.chat(
    image="photo.jpg",
    prompt="What's in this image?"
)
print(response)

# OCR - Read text from image
response = model.chat(
    image="document.png",
    prompt="Extract all text from this document"
)

# Chart analysis
response = model.chat(
    image="chart.png",
    prompt="What does this chart show? What's the maximum value?"
)

# Multi-turn conversation (remembers context)
model.chat(image="scene.jpg", prompt="Describe this image")
model.chat(prompt="How many people are there?")  # Uses same image
model.chat(prompt="What are they doing?")        # Continues conversation

# Reset and start fresh
model.clear_history()

Interactive CLI

python inference/infer.py --interactive

# Commands:
#   /load image.jpg  - Load an image
#   /describe        - Describe the image
#   /ocr             - Extract text
#   /chart           - Analyze as chart
#   /clear           - Reset conversation
#   /quit            - Exit

Architecture Details

EmberNet VLM (~300M total parameters)
β”‚
β”œβ”€β”€ Vision Encoder: SigLIP-base (FROZEN)
β”‚   β”œβ”€β”€ Parameters: ~85M (not counted in trainable)
β”‚   β”œβ”€β”€ Input: 224Γ—224 RGB image
β”‚   └── Output: 196 tokens Γ— 768 dims
β”‚
β”œβ”€β”€ Token Compression (TRAINABLE in Stage 1)
β”‚   β”œβ”€β”€ Pixel Shuffle: 196 β†’ 49 tokens
β”‚   β”œβ”€β”€ Adaptive Pooling: 49 β†’ 64 tokens
β”‚   └── Parameters: ~2M
β”‚
β”œβ”€β”€ Projector (TRAINABLE in Stage 1)
β”‚   β”œβ”€β”€ BitLinear MLP (768 β†’ 768 β†’ 768)
β”‚   β”œβ”€β”€ Ternary weights {-1, 0, +1}
β”‚   └── Parameters: ~3M
β”‚
└── Language Decoder: BitNet MoE (TRAINABLE in Stage 2)
    β”œβ”€β”€ Layers: 16 transformer blocks
    β”œβ”€β”€ Hidden size: 768
    β”œβ”€β”€ Attention: GQA (12 heads, 6 KV heads) β€” all projections are BitLinear
    β”œβ”€β”€ MoE FFN:
    β”‚   β”œβ”€β”€ 8 Domain Experts (top-2 routing)
    β”‚   β”‚   β”œβ”€β”€ vision_ocr, vision_diagram
    β”‚   β”‚   β”œβ”€β”€ code_math_chart, code_math_formula
    β”‚   β”‚   β”œβ”€β”€ spatial_reasoning (Γ—2)
    β”‚   β”‚   └── agentic_reasoning (Γ—2)
    β”‚   └── 1 Shared Expert (always active)
    β”œβ”€β”€ All weights: Ternary {-1, 0, +1}
    └── Parameters: ~250M (50M active per forward pass)

Total Trainable: ~255M ternary parameters
Active per Forward: ~55M parameters
Model Size on Disk: <500MB

Quantization Implementation Details

Which modules are ternary vs. full-precision?

ModulePrecisionNotes
BitNetAttention β€” Q/K/V/O projectionsTernary (1.58-bit)All four projections are BitLinear
BitNetExpert β€” gate / up / down projectionsTernary (1.58-bit)All 8 domain experts + shared expert
VisionProjector β€” fc1, fc2Ternary (1.58-bit)BitLinear MLP in models/vision.py
PixelShuffleCompressor β€” projFP16Standard nn.Linear; small (~600K params)
AdaptivePooler β€” cross-attentionFP16Standard nn.MultiheadAttention
RMSNorm layers (all)FP16Learnable scale only; ~negligible params
Token embeddings + LM head (tied)FP16nn.Embedding + tied nn.Linear
MoE router (nn.Linear)FP16Small (768 Γ— 8); routing must stay precise
SigLIP vision encoderFP16, frozenNot counted in 255M trainable params
VA Refiner MLP classifierFP32 (small)2-layer MLP, ~12K params; explicitly not ternary

Summary: ~250M decoder params (+ ~1M projector) are ternary. Non-quantized components (router, layernorms, embeddings, compressor) account for β‰ˆ25M FP16 params. The "BitNet-b1.58-style" description is accurate for all learnable weight matrices in the decoder and projector.

How ternary quantization works at runtime

BitLinear.forward() in models/bitnet_moe.py applies two Straight-Through Estimator (STE) operations:

# Activation quantization (per-token, 8-bit symmetric)
x_quant = x_norm + (activation_quant(x_norm) - x_norm).detach()

# Weight quantization (ternary: sign(W - mean(W)) * mean|W|)
w_quant = w + (weight_quant(w) - w).detach()

weight_quant() maps float weights to {-scale, 0, +scale} using the signed mean: u = sign(w - mean(w)) * mean(|w|). The STE means gradients flow through as if the quantization were identity β€” the underlying float weights are updated continuously during training and re-quantized at each forward pass.

On-disk packing (inference/convert.py)

After training, convert_to_ternary() calls convert_bitlinear_to_ternary() on every BitLinear module. For each:

  1. weight_quant(module.weight) snaps weights to {-scale, 0, +scale}.
  2. pack_ternary_weights() encodes {-1, 0, +1} as {0b00, 0b01, 0b10} and packs 4 values per byte (2 bits per weight).
  3. A FP32 scalar scale = mean(|w|) is stored alongside.
  4. The resulting TernaryLinear module pre-unpacks weights for fast inference.

Non-BitLinear layers (embeddings, layernorms, router, compressor) are quantized to INT8 via torch.quantization.quantize_dynamic in the same pass.


Project Structure

EmberNet/
β”œβ”€β”€ models/
β”‚   β”œβ”€β”€ bitnet_moe.py      # BitLinear + MoE decoder
β”‚   β”œβ”€β”€ vision.py          # SigLIP encoder + compression
β”‚   β”œβ”€β”€ va_refiner.py      # VA Refiner hallucination mitigation
β”‚   └── vlm.py             # Complete VLM
β”œβ”€β”€ training/
β”‚   β”œβ”€β”€ prepare_data.py    # Dataset download script
β”‚   β”œβ”€β”€ data.py            # Data loading
β”‚   └── train.py           # Training loop
β”œβ”€β”€ inference/
β”‚   β”œβ”€β”€ convert.py         # Model optimization
β”‚   └── infer.py           # User interface
β”œβ”€β”€ visualizations/
β”‚   β”œβ”€β”€ fig_architecture_overview.py  # Fig 1: architecture + params
β”‚   β”œβ”€β”€ fig_ternary_stats.py          # Fig 2: ternary weight stats
β”‚   β”œβ”€β”€ fig_moe_routing.py            # Fig 3: MoE routing patterns
β”‚   β”œβ”€β”€ fig_latency_energy.py         # Fig 4: latency/energy benchmark
β”‚   β”œβ”€β”€ fig_va_token_effects.py       # Fig 5: VA token-level dynamics
β”‚   β”œβ”€β”€ fig_va_answer_level.py        # Fig 6: VA hallucination metrics
β”‚   β”œβ”€β”€ fig_qualitative_grid.py       # Fig 7: qualitative examples
β”‚   └── ...                           # existing training-viz scripts
β”œβ”€β”€ generate_all_plots.py  # Master visualization orchestrator
β”œβ”€β”€ requirements.txt
└── README.md

Hallucination Mitigation (VA Refiner)

EmberNet ships an optional Visual Absence Refiner (VA Refiner) that detects and suppresses hallucinated tokens at inference time β€” particularly tokens that describe visual attributes (colors, objects, counts, spatial relations) that are not grounded in the image.

How it works

The VA Refiner operates in three layers:

  1. Neuron-level monitoring β€” Forward hooks are placed on shared_expert.down_proj in the BitNet MoE layers specified by va_layer_indices (default: layers 6–11). The top-K neuron activations are fed to a lightweight 2-layer MLP that predicts a per-step "visual hallucination score" p_neuron ∈ [0, 1].

  2. Logit discrepancy β€” A null baseline is computed once at the start of generation by running the decoder with image tokens zeroed out. At each step the L1 distance between the live logit distribution and the null baseline is collapsed to a score p_logit = 1 βˆ’ tanh(dist / scale). High similarity to the null baseline means the model is generating as if there were no image β€” a sign of hallucination.

  3. Temporal burst detection β€” A sliding window tracks the blended score p = Ξ±Β·p_neuron + (1βˆ’Ξ±)Β·p_logit. If the window mean exceeds va_burst_threshold, a "burst" is declared and a soft log-prob penalty (va_soft_penalty) is added to every token in VISUAL_KEYWORDS until the window cools.

After generation, calibrate_answer_prefix() checks the mean VA score for the response. If it exceeds 0.70, the response is prefixed with "I cannot see that clearly, but …". If it exceeds 0.40, the prefix is "I might be wrong, but …".

CLI usage

# Single inference with VA Refiner
python inference/infer.py \
  --model checkpoints/embernet.pt \
  --image photo.jpg \
  --prompt "What color is the car?" \
  --use-va-refiner \
  --va-threshold 0.70 \
  --va-burst-threshold 0.70 \
  --va-soft-penalty 5.0 \
  --va-alpha 0.5

Python API

from inference.infer import EmberVLM

model = EmberVLM(
    model_path="checkpoints/embernet.pt",
    use_va_refiner=True,
    va_threshold=0.70,
    va_burst_threshold=0.70,
    va_soft_penalty=5.0,
    va_alpha=0.5,
)
response = model.chat(image="photo.jpg", prompt="What color is the car?")
print(response)

Configuration knobs

ArgumentDefaultDescription
--use-va-refineroffEnable VA Refiner
--va-threshold0.70VA score threshold per token (non-visual)
--va-burst-threshold0.70Window mean that triggers burst mode
--va-soft-penalty5.0Log-prob penalty during bursts
--va-alpha0.5Blend: 1.0 = pure neuron, 0.0 = pure logit discrepancy

Fine-grained knobs (va_layer_indices, va_neuron_k, va_window_size, va_decay_factor, va_logit_scale) can be set programmatically via VARefinerConfig in models/va_refiner.py.

Trade-offs

  • Overhead: one extra decoder forward pass (null baseline) at generation start, plus per-step hook collection. On a single A100 this adds ~5–10% latency per response.
  • Conservative by design: the refiner penalises rather than blocks tokens, so factual accuracy is preserved. Use va_soft_penalty < 3.0 for a lighter touch.

Visualization Suite

EmberNet ships a publication-grade visualization suite in visualizations/. Generate all figures or individual ones via generate_all_plots.py.

Quick commands

# Generate ALL paper figures (Figs 1–7, synthetic data, no model required)
python generate_all_plots.py --paper-only

# Generate ALL plots (training-viz + paper figures)
python generate_all_plots.py --all

# Single paper figure
python generate_all_plots.py --fig fig_ternary_stats

# With a real checkpoint for data-driven figures
python generate_all_plots.py --paper-only --model checkpoints/stage2/final_model.pt

Figure catalogue

FigureScriptDescription
Fig 1fig_architecture_overview.pyPipeline block diagram + parameter/bitwidth breakdown per component
Fig 2fig_ternary_stats.pyPer-layer ternary weight sparsity heatmaps and {-1,0,+1} composition bars
Fig 3fig_moe_routing.pyMoE expert routing frequency matrix across vision-language datasets
Fig 4fig_latency_energy.pyLatency, energy, and throughput: ternary vs FP16 baseline (Β±std bars)
Fig 5fig_va_token_effects.pyPer-token p_VA trajectories with burst-mode and penalisation markers
Fig 6fig_va_answer_level.pyAnswer-level hallucination rate with/without VA Refiner, by visual category
Fig 7fig_qualitative_grid.pyMulti-domain qualitative panel: baseline vs VA-refined answers + p_VA sparklines

All figures are saved as both .pdf (vector, for LaTeX) and .png (300 DPI) in plots/paper_figures/.


License

MIT License

Contributors

euhidaman

165 commits

euhidaman/EmberNet

0

stars

165

commits

Python

primary language

Mar 4, 2026

updated

README

EmberNet - Tiny BitNet MoE Vision-Language Model

A high-quality, tiny BitNet b1.58-style Mixture-of-Experts Vision-Language Model (~300M ternary parameters) designed for edge deployment.

What it does: You give it an image + a question, it gives you an intelligent answer. OCR, chart analysis, document understanding, visual reasoning - all in <500MB.


Table of Contents

  1. Quick Start
  2. How It Works
  3. Complete Dataset List
  4. Training Guide
  5. Usage Examples
  6. Architecture Details

Quick Start

Complete Setup & Training Guide

Follow these steps in order to set up and train EmberNet:

Step 1: Install Dependencies

# Navigate to project directory
cd EmberNet

# Install all required packages
pip install -r requirements.txt

Required packages:

  • torch>=2.0.0 - Deep learning framework
  • transformers>=4.36.0 - HuggingFace transformers (for SigLIP)
  • datasets>=2.14.0 - HuggingFace datasets
  • wandb>=0.16.0 - Experiment tracking
  • huggingface_hub>=0.19.0 - HuggingFace authentication
  • Pillow>=9.0.0 - Image processing
  • einops>=0.7.0 - Tensor operations
  • numpy>=1.24.0 - Numerical computing

Step 2: Authentication Setup

2a. HuggingFace Login (REQUIRED - for downloading datasets):

# Login to HuggingFace
huggingface-cli login

# When prompted, enter your HuggingFace token
# Get your token from: https://huggingface.co/settings/tokens
# Create a token with "read" permissions

2b. Weights & Biases Login (OPTIONAL - for experiment tracking):

# Login to W&B
wandb login

# When prompted, enter your W&B API key
# Get your API key from: https://wandb.ai/authorize
# This enables training visualization and metric tracking

Step 3: Download Training Datasets

Choose one option based on your needs:

Option A: All Datasets (~100GB) - Best quality, all datasets

python training/prepare_data.py --all --output-dir ./data

Downloads all 20 datasets for maximum model quality.

Option B: Recommended (~70GB) - Good balance of quality and size

python training/prepare_data.py --recommended --output-dir ./data

Downloads critical + recommended datasets (excludes optional ones).

Option C: Critical Only (~50GB) - Core datasets only

python training/prepare_data.py --critical --output-dir ./data

Downloads only the most important datasets.

Option D: Minimal (~10GB) - Quick testing

python training/prepare_data.py --minimal --output-dir ./data

Downloads a tiny subset for testing the pipeline.

Other useful commands:

# List all available datasets before downloading
python training/prepare_data.py --list

# Download specific datasets only
python training/prepare_data.py --dataset textvqa chartqa vqav2 --output-dir ./data

# Explain how alignment works
python training/prepare_data.py --explain

What gets downloaded:

  • Stage 1 datasets: LLaVA-Instruct, ShareGPT4V, ALLaVA, COCO Captions, etc.
  • Stage 2 datasets: TextVQA, DocVQA, AI2D, ChartQA, PlotQA, VQAv2, GQA, OK-VQA, A-OKVQA, ScienceQA, RefCOCO, NLVR2, VSR, and more

Note: Some datasets (ShareGPT4V, ALLaVA, ChartQA, GQA, VSR) download images from URLs, which may take longer than loading pre-packaged datasets.

What gets saved: After downloading, you'll have:

  • ./data/{dataset_name}/ - Each dataset in its own folder
  • ./data/download_manifest.json - Central tracking file with all download info
  • ./data/dataset_index.json - Index mapping datasets to stages/domains
  • ./data/{dataset_name}/metadata.json - Individual dataset metadata

The download_manifest.json tracks:

  • All download sessions with timestamps
  • Dataset metadata (samples, size, domain, expert)
  • Download times and success/failure status
  • File paths and HuggingFace IDs

Step 4: Train the Model

EmberNet uses a two-stage training pipeline. Use --trial for quick validation or --main for full training.


πŸš€ Quick Start: Single-Command Training

# Trial Run - Quick pipeline validation (minutes, not hours)
python training/train.py --trial --data-dir ./data

# Main Run - Full production training (hours/days)
python training/train.py --main --data-dir ./data

Both commands automatically run Stage 1 β†’ Stage 2 sequentially.


Trial Mode (--trial)

Validates the entire pipeline with minimal data:

python training/train.py --trial --data-dir ./data
SettingValue
Samples per dataset50
Epochs per stage1
Batch size2
Gradient accumulation1
W&B loggingDisabled
Output./checkpoints/trial/stage{1,2}/

Use this to verify everything works before committing to full training.


Main Mode (--main)

Full production training with all data:

python training/train.py --main --data-dir ./data
SettingStage 1Stage 2
SamplesALLALL
Epochs310
Batch size84
Gradient accumulation44
W&B loggingEnabledEnabled
Output./checkpoints/stage1/./checkpoints/stage2/

Run a Specific Stage Only

# Stage 1 only (projector alignment)
python training/train.py --trial --stage 1 --data-dir ./data

# Stage 2 only (expert specialization) - requires Stage 1 checkpoint
python training/train.py --trial --stage 2 --data-dir ./data \
    --resume ./checkpoints/trial/stage1/final_model.pt

Training Options

# Custom epochs and batch size
python training/train.py --main --data-dir ./data --epochs 5 --batch-size 4

# Limit samples per dataset (useful for debugging)
python training/train.py --main --data-dir ./data --max-samples-per-dataset 1000

# Disable specific features
python training/train.py --main --data-dir ./data \
    --no-wandb \          # Disable W&B logging
    --no-ema \            # Disable EMA
    --no-curriculum \     # Disable curriculum learning
    --no-adaptive-clip    # Disable adaptive gradient clipping

# Hardware adjustments
python training/train.py --main --data-dir ./data \
    --device cpu \        # Force CPU (slower)
    --no-amp \            # Disable mixed precision
    --num-workers 2       # Reduce data loading workers

Output Structure

After training completes:

checkpoints/
β”œβ”€β”€ trial/                    # Trial mode outputs
β”‚   β”œβ”€β”€ stage1/
β”‚   β”‚   β”œβ”€β”€ final_model.pt    # Stage 1 checkpoint
β”‚   β”‚   └── checkpoint_epoch_1.pt
β”‚   └── stage2/
β”‚       β”œβ”€β”€ final_model.pt    # Stage 2 checkpoint (final model)
β”‚       └── checkpoint_epoch_1.pt
β”‚
β”œβ”€β”€ stage1/                   # Main mode outputs
β”‚   β”œβ”€β”€ final_model.pt
β”‚   β”œβ”€β”€ best_model.pt
β”‚   └── checkpoint_epoch_*.pt
β”‚
└── stage2/
    β”œβ”€β”€ final_model.pt        # ← Use this for inference
    β”œβ”€β”€ best_model.pt
    └── checkpoint_epoch_*.pt

What Each Stage Does

StagePurposeWhat TrainsWhat's Frozen
Stage 1Vision-Language AlignmentCrossModal Projector, Pooler, CompressorVision Encoder, LM Decoder
Stage 2Expert SpecializationMoE Router, Domain ExpertsVision Encoder, Projector, Embeddings

Step 5: Convert Model (Optional)

Convert to optimized ternary format for deployment:

python inference/convert.py \
    ./checkpoints/stage2/final_model.pt \
    ./embernet_optimized.pt

This packs ternary weights to 2-bit representation, reducing model size to <500MB.


Step 6: Run Inference

Interactive Mode:

python inference/infer.py \
    --model ./checkpoints/stage2/final_model.pt \
    --interactive

Interactive commands:

  • /load image.jpg - Load an image
  • /describe - Describe the image
  • /ocr - Extract text from image
  • /chart - Analyze chart/graph
  • /clear - Reset conversation
  • /quit - Exit

Single Query:

python inference/infer.py \
    --model ./checkpoints/stage2/final_model.pt \
    --image photo.jpg \
    --prompt "What's in this image?"

Quick Reference: All Commands in Order

# 1. Install dependencies
cd EmberNet
pip install -r requirements.txt

# 2. Authenticate (HF required, W&B optional)
huggingface-cli login   # Enter token from https://huggingface.co/settings/tokens
wandb login             # Optional: Enter API key from https://wandb.ai/authorize

# 3. Download training data
python training/prepare_data.py --recommended --output-dir ./data   # ~70GB
# OR: python training/prepare_data.py --all --output-dir ./data     # ~100GB (best quality)
# OR: python training/prepare_data.py --minimal --output-dir ./data # ~10GB (testing only)

# 4. Train the model (SINGLE COMMAND - runs Stage 1 β†’ Stage 2 automatically)
python training/train.py --trial --data-dir ./data   # Quick test (~minutes)
# OR:
python training/train.py --main --data-dir ./data    # Full training (~hours/days)

# 5. Run interactive inference
python inference/infer.py --model ./checkpoints/stage2/final_model.pt --interactive

How It Works

Vision-Language Alignment Explained

EmberNet connects images to language through a carefully designed pipeline:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                           IMAGE INPUT                                    β”‚
β”‚                              ↓                                          β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”‚
β”‚  β”‚ 1. VISION ENCODER (SigLIP - Frozen)                            β”‚    β”‚
β”‚  β”‚    β€’ Pretrained on 400M image-text pairs from Google           β”‚    β”‚
β”‚  β”‚    β€’ Extracts 196 visual tokens (14Γ—14 grid)                   β”‚    β”‚
β”‚  β”‚    β€’ Each token is a 768-dimensional feature vector            β”‚    β”‚
β”‚  β”‚    β€’ Already "understands" visual concepts                     β”‚    β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚
β”‚                              ↓                                          β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”‚
β”‚  β”‚ 2. TOKEN COMPRESSION (Trainable)                               β”‚    β”‚
β”‚  β”‚    β€’ Pixel Shuffle: 196 β†’ 49 tokens (merges 2Γ—2 neighbors)     β”‚    β”‚
β”‚  β”‚    β€’ Adaptive Pooling: 49 β†’ 64 tokens (learned queries)        β”‚    β”‚
β”‚  β”‚    β€’ Preserves important visual information                    β”‚    β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚
β”‚                              ↓                                          β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”‚
β”‚  β”‚ 3. PROJECTOR (BitLinear MLP) ← THIS IS WHERE ALIGNMENT HAPPENS β”‚    β”‚
β”‚  β”‚    β€’ 2-layer MLP with ternary weights {-1, 0, +1}              β”‚    β”‚
β”‚  β”‚    β€’ Maps: Vision embedding space β†’ Language embedding space   β”‚    β”‚
β”‚  β”‚    β€’ Trained in Stage 1 on image-caption pairs                 β”‚    β”‚
β”‚  β”‚    β€’ After training, visual tokens "look like" word tokens     β”‚    β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚
β”‚                              ↓                                          β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”‚
β”‚  β”‚ 4. MERGED INPUT SEQUENCE                                       β”‚    β”‚
β”‚  β”‚    [BOS] [IMG₁] [IMGβ‚‚] ... [IMG₆₄] [User: Describe this] ...  β”‚    β”‚
β”‚  β”‚          └── visual tokens β”€β”€β”˜     └── text tokens β”€β”€β”€β”€β”€β”€β”˜     β”‚    β”‚
β”‚  β”‚    The LLM processes both as if they're all "text"             β”‚    β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚
β”‚                              ↓                                          β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”‚
β”‚  β”‚ 5. BITNET MOE DECODER                                          β”‚    β”‚
β”‚  β”‚    β€’ 16 transformer layers with ternary weights                β”‚    β”‚
β”‚  β”‚    β€’ MoE FFN: 8 specialized experts + 1 shared expert          β”‚    β”‚
β”‚  β”‚    β€’ Router sends tokens to relevant experts:                  β”‚    β”‚
β”‚  β”‚      - OCR expert for text reading                             β”‚    β”‚
β”‚  β”‚      - Chart expert for graphs                                 β”‚    β”‚
β”‚  β”‚      - Diagram expert for technical drawings                   β”‚    β”‚
β”‚  β”‚      - etc.                                                    β”‚    β”‚
β”‚  β”‚    β€’ Generates response token by token                         β”‚    β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚
β”‚                              ↓                                          β”‚
β”‚                        TEXT OUTPUT                                      β”‚
β”‚            "This image shows a bar chart comparing..."                  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Why Two Training Stages?

Stage 1 - Projector Alignment:

  • Goal: Teach the model to "see" by connecting visual features to language
  • What's trained: Projector MLP + Token compression layers
  • What's frozen: Vision encoder + Language decoder
  • Data: High-quality image descriptions (LLaVA-Instruct, ShareGPT4V)
  • Why: The projector needs to learn that "this visual pattern" = "the concept of a dog"

Stage 2 - Expert Specialization:

  • Goal: Make experts good at specific tasks (OCR, charts, diagrams, etc.)
  • What's trained: MoE experts + Router
  • What's frozen: Vision encoder + Embeddings
  • Data: Domain-specific datasets (TextVQA, ChartQA, DocVQA, etc.)
  • Why: Different visual tasks need different skills - one expert can't do everything well

Expert Architecture & Dataset Mapping

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    EMBERNET MoE EXPERT ARCHITECTURE                          β”‚
β”‚                                                                              β”‚
β”‚  ROUTING: Each token β†’ TOP-2 Experts + SHARED Expert (always active)        β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                              β”‚
β”‚  EXPERT 0: vision_ocr                                                        β”‚
β”‚  β”œβ”€ Specialty: Read text in images, OCR, document parsing                   β”‚
β”‚  └─ Datasets: TextVQA, DocVQA, OCR-VQA                                      β”‚
β”‚                                                                              β”‚
β”‚  EXPERT 1: vision_diagram                                                    β”‚
β”‚  β”œβ”€ Specialty: Understand diagrams, infographics, technical drawings        β”‚
β”‚  └─ Datasets: AI2D, InfoVQA                                                 β”‚
β”‚                                                                              β”‚
β”‚  EXPERT 2: code_math_chart                                                   β”‚
β”‚  β”œβ”€ Specialty: Analyze charts, graphs, plots, data visualizations           β”‚
β”‚  └─ Datasets: ChartQA, PlotQA, FigureQA, DVQA                              β”‚
β”‚                                                                              β”‚
β”‚  EXPERT 3: code_math_formula                                                 β”‚
β”‚  β”œβ”€ Specialty: Handle math equations, formulas, numerical reasoning         β”‚
β”‚  └─ Datasets: MathVista                                                     β”‚
β”‚                                                                              β”‚
β”‚  EXPERT 4: spatial_scene                                                     β”‚
β”‚  β”œβ”€ Specialty: Scene understanding, object detection, descriptions          β”‚
β”‚  └─ Datasets: VQAv2, Visual Genome                                          β”‚
β”‚                                                                              β”‚
β”‚  EXPERT 5: spatial_reasoning                                                 β”‚
β”‚  β”œβ”€ Specialty: Spatial relationships, counting, positional reasoning        β”‚
β”‚  └─ Datasets: GQA                                                           β”‚
β”‚                                                                              β”‚
β”‚  EXPERT 6: agentic_knowledge                                                 β”‚
β”‚  β”œβ”€ Specialty: Knowledge-based QA, facts requiring world knowledge          β”‚
β”‚  └─ Datasets: OK-VQA, A-OKVQA                                               β”‚
β”‚                                                                              β”‚
β”‚  EXPERT 7: agentic_reasoning                                                 β”‚
β”‚  β”œβ”€ Specialty: Multi-step reasoning, logic, science questions               β”‚
β”‚  └─ Datasets: ScienceQA, CLEVR                                              β”‚
β”‚                                                                              β”‚
β”‚  SHARED EXPERT (Always Active)                                               β”‚
β”‚  β”œβ”€ Specialty: Common patterns, language generation, general knowledge      β”‚
β”‚  └─ Datasets: ALL datasets (learns shared representations)                  β”‚
β”‚                                                                              β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Example Routing:
  User: "What does this chart show? The title says Q3 Sales."
         β”‚
         β”œβ”€> EXPERT 0 (vision_ocr)    - reads "Q3 Sales" text
         β”œβ”€> EXPERT 2 (chart)          - analyzes chart structure  
         └─> SHARED EXPERT             - general language/context
         
  Combined output: "This bar chart shows Q3 sales data..."

Complete Dataset List

Stage 1: Vision-Language Alignment

DatasetHuggingFace IDDescriptionSamplesSize
LLaVA-Instruct-150K β˜…lmms-lab/LLaVA-Instruct-150KGPT-4 generated visual conversations150K~5GB
ShareGPT4V β˜…lmms-lab/ShareGPT4VDetailed image descriptions from GPT-4V100K~8GB
ALLaVAFreedomIntelligence/ALLaVA-4VDiverse visual instructions711K~6GB

Stage 2: Expert Specialization

Vision/OCR Expert Datasets

DatasetHuggingFace IDDescriptionSamplesSize
TextVQA β˜…lmms-lab/TextVQAText in natural scenes45K~2GB
DocVQA β˜…lmms-lab/DocVQADocuments, forms, receipts50K~3GB
AI2D β˜…lmms-lab/ai2dScientific diagrams15K~1.5GB
InfoVQAlmms-lab/InfographicVQAInfographics30K~2.5GB
OCR-VQAhoward-hou/OCR-VQABook covers, signs200K~4GB

Code/Math/Chart Expert Datasets

DatasetHuggingFace IDDescriptionSamplesSize
ChartQA β˜…ahmed-masry/ChartQABar, line, pie charts32K~1GB
MathVista β˜…AI4Math/MathVistaMathematical visual reasoning6K~1GB
PlotQAlmms-lab/PlotQAScientific plots224K~8GB
FigureQAlmms-lab/FigureQAFigure understanding180K~5GB
DVQAlmms-lab/DVQAData visualization300K~3GB

Spatial/Scene Expert Datasets

DatasetHuggingFace IDDescriptionSamplesSize
VQAv2 β˜…lmms-lab/VQAv2General visual QA1.1M~25GB
GQAlmms-lab/GQAScene graph reasoning22M~15GB
Visual Genomelmms-lab/VisualGenomeDense scene annotations108K~15GB

Reasoning Expert Datasets

DatasetHuggingFace IDDescriptionSamplesSize
ScienceQA β˜…derek-thomas/ScienceQAScience with diagrams21K~2GB
OK-VQAlmms-lab/OK-VQAOutside knowledge VQA14K~1GB
A-OKVQAlmms-lab/A-OKVQAAugmented knowledge VQA25K~1.5GB
CLEVRlmms-lab/CLEVRCompositional reasoning850K~18GB

β˜… = Critical (included in --critical mode)

Download Options

# Minimal (~10GB) - For quick testing only
python training/prepare_data.py --minimal
# Includes: llava_instruct_150k, textvqa, chartqa, vqav2

# Critical (~45GB) - Essential for a working model
python training/prepare_data.py --critical
# Includes: All β˜… marked datasets above

# Recommended (~70GB) - Good quality model
python training/prepare_data.py --recommended
# Includes: Critical + recommended datasets

# All (~100GB) - Maximum quality
python training/prepare_data.py --all
# Includes: Everything

Training Guide

Hardware Requirements

StageMinimumRecommendedNotes
Stage 18GB VRAM16GB VRAMCan use CPU with 16GB RAM (slower)
Stage 212GB VRAM24GB VRAMCan use CPU with 32GB RAM (slower)

Expected Training Time

StageGPU (A100)GPU (RTX 3090)CPU (32 cores)
Stage 1 (3 epochs)6-12 hours12-24 hours3-5 days
Stage 2 (10 epochs)24-48 hours48-96 hours10-15 days

Training Commands Reference

Basic Training (Recommended):

# Stage 1: Projector Alignment
python training/train.py \
    --stage 1 \
    --data-dir ./data \
    --epochs 3 \
    --batch-size 8 \
    --output-dir ./checkpoints

# Stage 2: Expert Specialization  
python training/train.py \
    --stage 2 \
    --data-dir ./data \
    --epochs 10 \
    --batch-size 4 \
    --resume ./checkpoints/checkpoint_epoch_3.pt \
    --output-dir ./checkpoints

With W&B Logging (Recommended):

# Stage 1
python training/train.py \
    --stage 1 \
    --data-dir ./data \
    --epochs 3 \
    --batch-size 8 \
    --wandb-project EmberNet \
    --wandb-run-name stage1_projector

# Stage 2
python training/train.py \
    --stage 2 \
    --data-dir ./data \
    --epochs 10 \
    --batch-size 4 \
    --resume ./checkpoints/checkpoint_epoch_3.pt \
    --wandb-project EmberNet \
    --wandb-run-name stage2_experts

Custom Learning Rate:

python training/train.py \
    --stage 1 \
    --data-dir ./data \
    --epochs 3 \
    --lr 5e-4

Resume from Checkpoint:

python training/train.py \
    --stage 2 \
    --data-dir ./data \
    --resume ./checkpoints/checkpoint_epoch_5.pt

Troubleshooting

Out of Memory (OOM) Errors:

# Reduce batch size and increase gradient accumulation
python training/train.py \
    --stage 1 \
    --data-dir ./data \
    --batch-size 2 \
    --grad-accum 16
# Effective batch size = 2 * 16 = 32

Slow Training:

# Check if GPU is being used
python training/train.py --stage 1 --data-dir ./data --device cuda

# Increase number of data loading workers
python training/train.py --stage 1 --data-dir ./data --num-workers 8

Mixed Precision Issues:

# Disable automatic mixed precision
python training/train.py --stage 1 --data-dir ./data --no-amp

CPU Training:

# Force CPU (much slower but works without GPU)
python training/train.py --stage 1 --data-dir ./data --device cpu --batch-size 1

All Training Arguments

Training Settings:
  --stage {1,2}              Training stage (1=projector, 2=expert SFT)
  --epochs N                 Number of training epochs (default: 3)
  --batch-size N             Training batch size (default: 4)
  --lr LR                    Learning rate (auto-set: 1e-3 for stage1, 1e-4 for stage2)
  --grad-accum N             Gradient accumulation steps (default: 4)

Paths:
  --data-dir DIR             Data directory (default: ./data)
  --output-dir DIR           Output directory for checkpoints (default: ./checkpoints)
  --resume PATH              Resume from checkpoint

Hardware:
  --device DEVICE            Device: cuda/cpu/auto (default: auto)
  --no-amp                   Disable mixed precision training
  --num-workers N            Data loading workers (default: 4)

Experiment Tracking:
  --wandb                    Use W&B logging (default: True)
  --no-wandb                 Disable W&B logging
  --wandb-project NAME       W&B project name (default: EmberNet)
  --wandb-run-name NAME      W&B run name (default: auto-generated)

What Gets Saved

During training, the following checkpoints are saved to --output-dir:

  • checkpoint_epoch_N.pt - Saved after each epoch
  • checkpoint_step_N.pt - Saved every N steps (configurable)
  • best_model.pt - Best model based on validation loss
  • final_model.pt - Final model after all epochs

Each checkpoint contains:

  • Model state dict
  • Optimizer state dict
  • Scheduler state dict
  • Training configuration
  • Current epoch and step
  • Best loss so far

Monitoring Training

With Weights & Biases: Visit https://wandb.ai/your-username/EmberNet to see:

  • Real-time loss curves
  • Learning rate schedules
  • Token statistics
  • Gradient norms
  • Model parameters
  • System metrics (GPU/CPU usage, memory)

Console Output:

======================================================================
Starting Stage 1 Training
======================================================================
Epochs: 3
Steps per epoch: 1000
Total steps: 3000
Batch size: 8
Gradient accumulation: 4
Effective batch size: 32
Learning rate: 0.001
Device: cuda

--- Token Statistics (per sample) ---
Total tokens:  2,048
  β”œβ”€ Image tokens: 64
  └─ Text tokens:  1,984

--- Token Statistics (per batch) ---
Total tokens:  16,384
  β”œβ”€ Image tokens: 512
  └─ Text tokens:  15,872

--- Total Training Tokens (all epochs) ---
Total tokens:  49,152,000
  β”œβ”€ Image tokens: 1,536,000
  └─ Text tokens:  47,616,000
======================================================================

Epoch 1/3 | Step 100 | Loss: 2.3456 | Avg Loss: 2.4567 | LR: 1.00e-03

Usage Examples

Python API

from inference.infer import EmberVLM

# Load model
model = EmberVLM("checkpoints/embernet.pt")

# Basic image Q&A
response = model.chat(
    image="photo.jpg",
    prompt="What's in this image?"
)
print(response)

# OCR - Read text from image
response = model.chat(
    image="document.png",
    prompt="Extract all text from this document"
)

# Chart analysis
response = model.chat(
    image="chart.png",
    prompt="What does this chart show? What's the maximum value?"
)

# Multi-turn conversation (remembers context)
model.chat(image="scene.jpg", prompt="Describe this image")
model.chat(prompt="How many people are there?")  # Uses same image
model.chat(prompt="What are they doing?")        # Continues conversation

# Reset and start fresh
model.clear_history()

Interactive CLI

python inference/infer.py --interactive

# Commands:
#   /load image.jpg  - Load an image
#   /describe        - Describe the image
#   /ocr             - Extract text
#   /chart           - Analyze as chart
#   /clear           - Reset conversation
#   /quit            - Exit

Architecture Details

EmberNet VLM (~300M total parameters)
β”‚
β”œβ”€β”€ Vision Encoder: SigLIP-base (FROZEN)
β”‚   β”œβ”€β”€ Parameters: ~85M (not counted in trainable)
β”‚   β”œβ”€β”€ Input: 224Γ—224 RGB image
β”‚   └── Output: 196 tokens Γ— 768 dims
β”‚
β”œβ”€β”€ Token Compression (TRAINABLE in Stage 1)
β”‚   β”œβ”€β”€ Pixel Shuffle: 196 β†’ 49 tokens
β”‚   β”œβ”€β”€ Adaptive Pooling: 49 β†’ 64 tokens
β”‚   └── Parameters: ~2M
β”‚
β”œβ”€β”€ Projector (TRAINABLE in Stage 1)
β”‚   β”œβ”€β”€ BitLinear MLP (768 β†’ 768 β†’ 768)
β”‚   β”œβ”€β”€ Ternary weights {-1, 0, +1}
β”‚   └── Parameters: ~3M
β”‚
└── Language Decoder: BitNet MoE (TRAINABLE in Stage 2)
    β”œβ”€β”€ Layers: 16 transformer blocks
    β”œβ”€β”€ Hidden size: 768
    β”œβ”€β”€ Attention: GQA (12 heads, 6 KV heads) β€” all projections are BitLinear
    β”œβ”€β”€ MoE FFN:
    β”‚   β”œβ”€β”€ 8 Domain Experts (top-2 routing)
    β”‚   β”‚   β”œβ”€β”€ vision_ocr, vision_diagram
    β”‚   β”‚   β”œβ”€β”€ code_math_chart, code_math_formula
    β”‚   β”‚   β”œβ”€β”€ spatial_reasoning (Γ—2)
    β”‚   β”‚   └── agentic_reasoning (Γ—2)
    β”‚   └── 1 Shared Expert (always active)
    β”œβ”€β”€ All weights: Ternary {-1, 0, +1}
    └── Parameters: ~250M (50M active per forward pass)

Total Trainable: ~255M ternary parameters
Active per Forward: ~55M parameters
Model Size on Disk: <500MB

Quantization Implementation Details

Which modules are ternary vs. full-precision?

ModulePrecisionNotes
BitNetAttention β€” Q/K/V/O projectionsTernary (1.58-bit)All four projections are BitLinear
BitNetExpert β€” gate / up / down projectionsTernary (1.58-bit)All 8 domain experts + shared expert
VisionProjector β€” fc1, fc2Ternary (1.58-bit)BitLinear MLP in models/vision.py
PixelShuffleCompressor β€” projFP16Standard nn.Linear; small (~600K params)
AdaptivePooler β€” cross-attentionFP16Standard nn.MultiheadAttention
RMSNorm layers (all)FP16Learnable scale only; ~negligible params
Token embeddings + LM head (tied)FP16nn.Embedding + tied nn.Linear
MoE router (nn.Linear)FP16Small (768 Γ— 8); routing must stay precise
SigLIP vision encoderFP16, frozenNot counted in 255M trainable params
VA Refiner MLP classifierFP32 (small)2-layer MLP, ~12K params; explicitly not ternary

Summary: ~250M decoder params (+ ~1M projector) are ternary. Non-quantized components (router, layernorms, embeddings, compressor) account for β‰ˆ25M FP16 params. The "BitNet-b1.58-style" description is accurate for all learnable weight matrices in the decoder and projector.

How ternary quantization works at runtime

BitLinear.forward() in models/bitnet_moe.py applies two Straight-Through Estimator (STE) operations:

# Activation quantization (per-token, 8-bit symmetric)
x_quant = x_norm + (activation_quant(x_norm) - x_norm).detach()

# Weight quantization (ternary: sign(W - mean(W)) * mean|W|)
w_quant = w + (weight_quant(w) - w).detach()

weight_quant() maps float weights to {-scale, 0, +scale} using the signed mean: u = sign(w - mean(w)) * mean(|w|). The STE means gradients flow through as if the quantization were identity β€” the underlying float weights are updated continuously during training and re-quantized at each forward pass.

On-disk packing (inference/convert.py)

After training, convert_to_ternary() calls convert_bitlinear_to_ternary() on every BitLinear module. For each:

  1. weight_quant(module.weight) snaps weights to {-scale, 0, +scale}.
  2. pack_ternary_weights() encodes {-1, 0, +1} as {0b00, 0b01, 0b10} and packs 4 values per byte (2 bits per weight).
  3. A FP32 scalar scale = mean(|w|) is stored alongside.
  4. The resulting TernaryLinear module pre-unpacks weights for fast inference.

Non-BitLinear layers (embeddings, layernorms, router, compressor) are quantized to INT8 via torch.quantization.quantize_dynamic in the same pass.


Project Structure

EmberNet/
β”œβ”€β”€ models/
β”‚   β”œβ”€β”€ bitnet_moe.py      # BitLinear + MoE decoder
β”‚   β”œβ”€β”€ vision.py          # SigLIP encoder + compression
β”‚   β”œβ”€β”€ va_refiner.py      # VA Refiner hallucination mitigation
β”‚   └── vlm.py             # Complete VLM
β”œβ”€β”€ training/
β”‚   β”œβ”€β”€ prepare_data.py    # Dataset download script
β”‚   β”œβ”€β”€ data.py            # Data loading
β”‚   └── train.py           # Training loop
β”œβ”€β”€ inference/
β”‚   β”œβ”€β”€ convert.py         # Model optimization
β”‚   └── infer.py           # User interface
β”œβ”€β”€ visualizations/
β”‚   β”œβ”€β”€ fig_architecture_overview.py  # Fig 1: architecture + params
β”‚   β”œβ”€β”€ fig_ternary_stats.py          # Fig 2: ternary weight stats
β”‚   β”œβ”€β”€ fig_moe_routing.py            # Fig 3: MoE routing patterns
β”‚   β”œβ”€β”€ fig_latency_energy.py         # Fig 4: latency/energy benchmark
β”‚   β”œβ”€β”€ fig_va_token_effects.py       # Fig 5: VA token-level dynamics
β”‚   β”œβ”€β”€ fig_va_answer_level.py        # Fig 6: VA hallucination metrics
β”‚   β”œβ”€β”€ fig_qualitative_grid.py       # Fig 7: qualitative examples
β”‚   └── ...                           # existing training-viz scripts
β”œβ”€β”€ generate_all_plots.py  # Master visualization orchestrator
β”œβ”€β”€ requirements.txt
└── README.md

Hallucination Mitigation (VA Refiner)

EmberNet ships an optional Visual Absence Refiner (VA Refiner) that detects and suppresses hallucinated tokens at inference time β€” particularly tokens that describe visual attributes (colors, objects, counts, spatial relations) that are not grounded in the image.

How it works

The VA Refiner operates in three layers:

  1. Neuron-level monitoring β€” Forward hooks are placed on shared_expert.down_proj in the BitNet MoE layers specified by va_layer_indices (default: layers 6–11). The top-K neuron activations are fed to a lightweight 2-layer MLP that predicts a per-step "visual hallucination score" p_neuron ∈ [0, 1].

  2. Logit discrepancy β€” A null baseline is computed once at the start of generation by running the decoder with image tokens zeroed out. At each step the L1 distance between the live logit distribution and the null baseline is collapsed to a score p_logit = 1 βˆ’ tanh(dist / scale). High similarity to the null baseline means the model is generating as if there were no image β€” a sign of hallucination.

  3. Temporal burst detection β€” A sliding window tracks the blended score p = Ξ±Β·p_neuron + (1βˆ’Ξ±)Β·p_logit. If the window mean exceeds va_burst_threshold, a "burst" is declared and a soft log-prob penalty (va_soft_penalty) is added to every token in VISUAL_KEYWORDS until the window cools.

After generation, calibrate_answer_prefix() checks the mean VA score for the response. If it exceeds 0.70, the response is prefixed with "I cannot see that clearly, but …". If it exceeds 0.40, the prefix is "I might be wrong, but …".

CLI usage

# Single inference with VA Refiner
python inference/infer.py \
  --model checkpoints/embernet.pt \
  --image photo.jpg \
  --prompt "What color is the car?" \
  --use-va-refiner \
  --va-threshold 0.70 \
  --va-burst-threshold 0.70 \
  --va-soft-penalty 5.0 \
  --va-alpha 0.5

Python API

from inference.infer import EmberVLM

model = EmberVLM(
    model_path="checkpoints/embernet.pt",
    use_va_refiner=True,
    va_threshold=0.70,
    va_burst_threshold=0.70,
    va_soft_penalty=5.0,
    va_alpha=0.5,
)
response = model.chat(image="photo.jpg", prompt="What color is the car?")
print(response)

Configuration knobs

ArgumentDefaultDescription
--use-va-refineroffEnable VA Refiner
--va-threshold0.70VA score threshold per token (non-visual)
--va-burst-threshold0.70Window mean that triggers burst mode
--va-soft-penalty5.0Log-prob penalty during bursts
--va-alpha0.5Blend: 1.0 = pure neuron, 0.0 = pure logit discrepancy

Fine-grained knobs (va_layer_indices, va_neuron_k, va_window_size, va_decay_factor, va_logit_scale) can be set programmatically via VARefinerConfig in models/va_refiner.py.

Trade-offs

  • Overhead: one extra decoder forward pass (null baseline) at generation start, plus per-step hook collection. On a single A100 this adds ~5–10% latency per response.
  • Conservative by design: the refiner penalises rather than blocks tokens, so factual accuracy is preserved. Use va_soft_penalty < 3.0 for a lighter touch.

Visualization Suite

EmberNet ships a publication-grade visualization suite in visualizations/. Generate all figures or individual ones via generate_all_plots.py.

Quick commands

# Generate ALL paper figures (Figs 1–7, synthetic data, no model required)
python generate_all_plots.py --paper-only

# Generate ALL plots (training-viz + paper figures)
python generate_all_plots.py --all

# Single paper figure
python generate_all_plots.py --fig fig_ternary_stats

# With a real checkpoint for data-driven figures
python generate_all_plots.py --paper-only --model checkpoints/stage2/final_model.pt

Figure catalogue

FigureScriptDescription
Fig 1fig_architecture_overview.pyPipeline block diagram + parameter/bitwidth breakdown per component
Fig 2fig_ternary_stats.pyPer-layer ternary weight sparsity heatmaps and {-1,0,+1} composition bars
Fig 3fig_moe_routing.pyMoE expert routing frequency matrix across vision-language datasets
Fig 4fig_latency_energy.pyLatency, energy, and throughput: ternary vs FP16 baseline (Β±std bars)
Fig 5fig_va_token_effects.pyPer-token p_VA trajectories with burst-mode and penalisation markers
Fig 6fig_va_answer_level.pyAnswer-level hallucination rate with/without VA Refiner, by visual category
Fig 7fig_qualitative_grid.pyMulti-domain qualitative panel: baseline vs VA-refined answers + p_VA sparklines

All figures are saved as both .pdf (vector, for LaTeX) and .png (300 DPI) in plots/paper_figures/.


License

MIT License

Contributors

euhidaman

165 commits

Languages

Python

100.0%