Knowledge distillation framework for 3D vision-language models (VLMs): transfer 3D spatial understanding from a 7B-parameter teacher (LLaVA-3D) to a compact 2.29B-parameter student with 8.7× inference speedup and 3× model compression while retaining 54–72% of teacher performance on specialized spatial reasoning. Features VGGT (Visual Geometry Grounded Transformer) as the vision encoder, multi-task distillation with uncertainty-based loss weighting, and Hidden Chain-of-Thought (Hidden CoT)—a latent scratchpad for improved reasoning without chain-of-thought data or interface changes.
Large 3D VLMs like LLaVA-3D excel at spatial reasoning but are too heavy for edge and real-time use. This project:
Outcomes: 8.7× faster inference, 3× smaller model, 54–72% of teacher performance on spatial tasks (68–72% on proximity/contact). Supports ScanNet and 3D-FRONT.
ChaimZhu/LLaVA-3D-7B)facebook/VGGT-1B)scripts/diagnostic_cot.py) for interpretability.torch, torchvisiontransformers (Hugging Face)accelerate, einops, pillow, numpy, scipy, scikit-learn, tqdm, pyyamlultralytics (YOLO), bitsandbytes (8-bit optimizer)cd ~/scratch
git clone <your-repo-url> distilled-llava3d
cd distilled-llava3d
# Create virtual environment
python3.11 -m venv distilled-llava3d-env
# Activate environment
source distilled-llava3d-env/bin/activate
# Upgrade pip
pip install --upgrade pip
# Install PyTorch (adjust CUDA version as needed)
# For CUDA 11.8:
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118
# For CUDA 12.1:
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121
# Install core ML libraries
pip install transformers>=4.35.0
pip install accelerate>=0.24.0
pip install einops
pip install pillow
pip install opencv-python
pip install numpy
pip install scipy
pip install scikit-learn
pip install tqdm
pip install pyyaml
pip install wandb # Optional: for experiment tracking
VGGT can be installed in two ways:
The code will automatically download VGGT from HuggingFace when first used:
# No additional installation needed - transformers library handles it
# Model will be downloaded from: facebook/VGGT-1B
If you prefer to install from source:
# Clone VGGT repository
cd ~/scratch
git clone https://github.com/facebookresearch/vggt.git
cd vggt
# Install VGGT
pip install -e .
# Install additional dependencies
pip install einops
# Return to project directory
cd ~/scratch/distilled-llava3d
Or use the provided installation script:
bash install_vggt.sh
Note: The student model will automatically detect VGGT from either HuggingFace or the local installation.
The teacher model is automatically downloaded from HuggingFace when first used. However, you need to set up the LLaVA-3D source code for proper integration:
# Clone LLaVA-3D repository (for utilities and model loading)
cd ~/scratch
git clone https://github.com/ChaimZhu/LLaVA-3D.git llava-3d
cd llava-3d/LLaVA-3D
# Install LLaVA-3D dependencies
pip install -e .
# Install additional requirements
pip install -r requirements.txt
# Return to project directory
cd ~/scratch/distilled-llava3d
Note: The teacher model (ChaimZhu/LLaVA-3D-7B) will be automatically downloaded from HuggingFace (~14GB) on first use. Ensure you have:
# For depth estimation (DPT)
pip install transformers[vision]
# For object detection (YOLO)
pip install ultralytics
# For 3D data processing
pip install trimesh
pip install open3d # Optional: for advanced 3D processing
Test that all components are properly installed:
# Test VGGT integration
python test_vggt_integration.py
# Test teacher model loading (this will download the model on first run)
python -c "from real_llava3d_teacher import RealLLaVA3DTeacher; teacher = RealLLaVA3DTeacher(device='cpu'); print('✅ Teacher model loaded successfully')"
Training expects a data/ directory under the project root with one or more of:
data/
├── scannet/ # or scannet_real
│ └── <scene_id>/ # e.g. scene0000_00
│ ├── *.jpg # and/or *.png, *.jpeg
│ └── images/ # optional subfolder
├── 3d_front/ # or 3d_front_real
│ └── <scene_id>/
│ └── *.jpg
.jpg, .png, or .jpeg directly in the scene dir or in images/.*_real) and up to 10 images per scene.data/scannet/data/3d_front/Train the student with Hidden CoT (K=8 by default; answer-only loss):
source distilled-llava3d-env/bin/activate
export PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True
# Local
python train_cot.py --data_root data --checkpoint_dir checkpoints
# With options
python train_cot.py --data_root data --checkpoint_dir checkpoints \
--num_thinking_tokens 8 --max_epochs 50
Cluster (SLURM):
# Edit scripts/training/run_cot_train.sbatch: set account, paths, and optionally data_root/checkpoint_dir via env or script.
sbatch scripts/training/run_cot_train.sbatch
Checkpoints: checkpoints/cot_model_best.pt, checkpoints/cot_model_epoch_*.pt. Results summary: checkpoints/cot_training_results.json.
# Train each K in {2,4,8,16} for 3 epochs (quick sweep)
python scripts/training/run_cot_ablation_k.py --k 2 4 8 16 --max_epochs 3 --base_dir checkpoints/cot_ablation_k
# Collect results only (after some runs)
python scripts/training/run_cot_ablation_k.py --collect_only --base_dir checkpoints/cot_ablation_k
fixed_training_pipeline.py, improved_training_pipeline.py: Baseline (non-CoT) distillation.scripts/training/run_train.sbatch, run_train_with_validation.sbatch: SLURM for non-CoT runs.Training depends on real LLaVA-3D teacher (real_llava3d_teacher). If that module is not available, CoT training will fail at import; ensure the teacher is set up as in your environment (e.g. LLaVA-3D repo or a custom wrapper).
python scripts/diagnostic_cot.py --checkpoint checkpoints/cot_model_best.pt \
--image data/3d_front_real/bedroom_000/view_000.jpg \
--question "Describe this 3D scene and identify objects."
python scripts/benchmark_cross_platform.py --checkpoint checkpoints/cot_model_best.pt \
--warmup 3 --iters 20 --output results/cross_platform_results.csv
python scripts/generate_hidden_cot_comparison_figure.py --image data/3d_front_real/.../view_000.jpg --output results/figures/hidden_cot_comparison.pngpython scripts/generate_training_loss_chart.py --output results/figures/training_loss_convergence.pngdistilled-llava3d/
├── README.md
│
├── train_cot.py # Hidden CoT training entry
├── real_llava3d_teacher.py # LLaVA-3D teacher wrapper
├── real_depth_teacher.py # Depth teacher (DPT)
├── object_detection_integration.py # Detection (YOLO)
├── install_vggt.sh # VGGT install helper
│
├── scripts/
│ ├── distillation/
│ │ ├── student_model.py # Student + VGGT + Hidden CoT
│ │ ├── uncertainty_loss.py # Uncertainty-based loss
│ │ ├── dataset_loader.py
│ │ └── ...
│ ├── training/
│ │ ├── run_cot_train.sbatch # SLURM CoT job
│ │ ├── run_cot_ablation_k.py # K ablation runner
│ │ ├── run_train.sbatch
│ │ └── logs/
│ ├── evaluation/
│ │ └── spatial_benchmark_eval.py
│ ├── ablation/
│ ├── diagnostic_cot.py # Decode thinking tokens
│ ├── benchmark_cross_platform.py # Latency/RAM benchmark
│ ├── generate_hidden_cot_comparison_figure.py
│ └── generate_training_loss_chart.py
│
├── data/ # Datasets (see Data Preparation)
├── checkpoints/ # Saved models
├── results/
│ └── figures/ # Generated figures
└── configs/
Location: scripts/distillation/student_model.py - VGGTVisionEncoder class
Key Features:
facebook/VGGT-1B), then local installation_apply method keeps VGGT on designated device even when parent model moves to GPUTo fit training on smaller GPUs:
torch.cuda.empty_cache() called every 5 batchesThe real LLaVA-3D teacher:
ChaimZhu/LLaVA-3D-7Bdevice_map={"": device} for compatibilitySymptoms: RuntimeError: CUDA out of memory
Solutions:
vggt_device = 'cpu'device="cpu" in RealLLaVA3DTeachertorch.cuda.empty_cache() callsSymptoms: ModuleNotFoundError: No module named 'vggt'
Solutions:
pip install transformersbash install_vggt.shsys.pathSymptoms: OSError: Can't load tokenizer or download errors
Solutions:
huggingface-cli loginhuggingface-cli download ChaimZhu/LLaVA-3D-7BSymptoms: AssertionError: Input image height X is not a multiple of patch height 14
Solutions:
F.interpolate is being called in _extract_vggt_featuresSymptoms: RuntimeError: Found dtype Double but expected Float
Solutions:
float32: .float() or dtype=torch.float32long: .long() or dtype=torch.longSymptoms: Training is very slow
Solutions:
@misc{distilled-llava3d,
title={Distilling 3D Spatial Reasoning into a Lightweight Vision-Language Model with CoT},
author={Alaa Asfour},
year={2026},
url={https://github.com/alaaasfour/distilled-LLaVA3D-with-CoT}
}
[Contributing guidelines]
Alaa Asfour (alaa.asfour@torontomu.ca)
110 commits
Python
99.9%
Knowledge distillation framework for 3D vision-language models (VLMs): transfer 3D spatial understanding from a 7B-parameter teacher (LLaVA-3D) to a compact 2.29B-parameter student with 8.7× inference speedup and 3× model compression while retaining 54–72% of teacher performance on specialized spatial reasoning. Features VGGT (Visual Geometry Grounded Transformer) as the vision encoder, multi-task distillation with uncertainty-based loss weighting, and Hidden Chain-of-Thought (Hidden CoT)—a latent scratchpad for improved reasoning without chain-of-thought data or interface changes.
Large 3D VLMs like LLaVA-3D excel at spatial reasoning but are too heavy for edge and real-time use. This project:
Outcomes: 8.7× faster inference, 3× smaller model, 54–72% of teacher performance on spatial tasks (68–72% on proximity/contact). Supports ScanNet and 3D-FRONT.
ChaimZhu/LLaVA-3D-7B)facebook/VGGT-1B)scripts/diagnostic_cot.py) for interpretability.torch, torchvisiontransformers (Hugging Face)accelerate, einops, pillow, numpy, scipy, scikit-learn, tqdm, pyyamlultralytics (YOLO), bitsandbytes (8-bit optimizer)cd ~/scratch
git clone <your-repo-url> distilled-llava3d
cd distilled-llava3d
# Create virtual environment
python3.11 -m venv distilled-llava3d-env
# Activate environment
source distilled-llava3d-env/bin/activate
# Upgrade pip
pip install --upgrade pip
# Install PyTorch (adjust CUDA version as needed)
# For CUDA 11.8:
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118
# For CUDA 12.1:
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121
# Install core ML libraries
pip install transformers>=4.35.0
pip install accelerate>=0.24.0
pip install einops
pip install pillow
pip install opencv-python
pip install numpy
pip install scipy
pip install scikit-learn
pip install tqdm
pip install pyyaml
pip install wandb # Optional: for experiment tracking
VGGT can be installed in two ways:
The code will automatically download VGGT from HuggingFace when first used:
# No additional installation needed - transformers library handles it
# Model will be downloaded from: facebook/VGGT-1B
If you prefer to install from source:
# Clone VGGT repository
cd ~/scratch
git clone https://github.com/facebookresearch/vggt.git
cd vggt
# Install VGGT
pip install -e .
# Install additional dependencies
pip install einops
# Return to project directory
cd ~/scratch/distilled-llava3d
Or use the provided installation script:
bash install_vggt.sh
Note: The student model will automatically detect VGGT from either HuggingFace or the local installation.
The teacher model is automatically downloaded from HuggingFace when first used. However, you need to set up the LLaVA-3D source code for proper integration:
# Clone LLaVA-3D repository (for utilities and model loading)
cd ~/scratch
git clone https://github.com/ChaimZhu/LLaVA-3D.git llava-3d
cd llava-3d/LLaVA-3D
# Install LLaVA-3D dependencies
pip install -e .
# Install additional requirements
pip install -r requirements.txt
# Return to project directory
cd ~/scratch/distilled-llava3d
Note: The teacher model (ChaimZhu/LLaVA-3D-7B) will be automatically downloaded from HuggingFace (~14GB) on first use. Ensure you have:
# For depth estimation (DPT)
pip install transformers[vision]
# For object detection (YOLO)
pip install ultralytics
# For 3D data processing
pip install trimesh
pip install open3d # Optional: for advanced 3D processing
Test that all components are properly installed:
# Test VGGT integration
python test_vggt_integration.py
# Test teacher model loading (this will download the model on first run)
python -c "from real_llava3d_teacher import RealLLaVA3DTeacher; teacher = RealLLaVA3DTeacher(device='cpu'); print('✅ Teacher model loaded successfully')"
Training expects a data/ directory under the project root with one or more of:
data/
├── scannet/ # or scannet_real
│ └── <scene_id>/ # e.g. scene0000_00
│ ├── *.jpg # and/or *.png, *.jpeg
│ └── images/ # optional subfolder
├── 3d_front/ # or 3d_front_real
│ └── <scene_id>/
│ └── *.jpg
.jpg, .png, or .jpeg directly in the scene dir or in images/.*_real) and up to 10 images per scene.data/scannet/data/3d_front/Train the student with Hidden CoT (K=8 by default; answer-only loss):
source distilled-llava3d-env/bin/activate
export PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True
# Local
python train_cot.py --data_root data --checkpoint_dir checkpoints
# With options
python train_cot.py --data_root data --checkpoint_dir checkpoints \
--num_thinking_tokens 8 --max_epochs 50
Cluster (SLURM):
# Edit scripts/training/run_cot_train.sbatch: set account, paths, and optionally data_root/checkpoint_dir via env or script.
sbatch scripts/training/run_cot_train.sbatch
Checkpoints: checkpoints/cot_model_best.pt, checkpoints/cot_model_epoch_*.pt. Results summary: checkpoints/cot_training_results.json.
# Train each K in {2,4,8,16} for 3 epochs (quick sweep)
python scripts/training/run_cot_ablation_k.py --k 2 4 8 16 --max_epochs 3 --base_dir checkpoints/cot_ablation_k
# Collect results only (after some runs)
python scripts/training/run_cot_ablation_k.py --collect_only --base_dir checkpoints/cot_ablation_k
fixed_training_pipeline.py, improved_training_pipeline.py: Baseline (non-CoT) distillation.scripts/training/run_train.sbatch, run_train_with_validation.sbatch: SLURM for non-CoT runs.Training depends on real LLaVA-3D teacher (real_llava3d_teacher). If that module is not available, CoT training will fail at import; ensure the teacher is set up as in your environment (e.g. LLaVA-3D repo or a custom wrapper).
python scripts/diagnostic_cot.py --checkpoint checkpoints/cot_model_best.pt \
--image data/3d_front_real/bedroom_000/view_000.jpg \
--question "Describe this 3D scene and identify objects."
python scripts/benchmark_cross_platform.py --checkpoint checkpoints/cot_model_best.pt \
--warmup 3 --iters 20 --output results/cross_platform_results.csv
python scripts/generate_hidden_cot_comparison_figure.py --image data/3d_front_real/.../view_000.jpg --output results/figures/hidden_cot_comparison.pngpython scripts/generate_training_loss_chart.py --output results/figures/training_loss_convergence.pngdistilled-llava3d/
├── README.md
│
├── train_cot.py # Hidden CoT training entry
├── real_llava3d_teacher.py # LLaVA-3D teacher wrapper
├── real_depth_teacher.py # Depth teacher (DPT)
├── object_detection_integration.py # Detection (YOLO)
├── install_vggt.sh # VGGT install helper
│
├── scripts/
│ ├── distillation/
│ │ ├── student_model.py # Student + VGGT + Hidden CoT
│ │ ├── uncertainty_loss.py # Uncertainty-based loss
│ │ ├── dataset_loader.py
│ │ └── ...
│ ├── training/
│ │ ├── run_cot_train.sbatch # SLURM CoT job
│ │ ├── run_cot_ablation_k.py # K ablation runner
│ │ ├── run_train.sbatch
│ │ └── logs/
│ ├── evaluation/
│ │ └── spatial_benchmark_eval.py
│ ├── ablation/
│ ├── diagnostic_cot.py # Decode thinking tokens
│ ├── benchmark_cross_platform.py # Latency/RAM benchmark
│ ├── generate_hidden_cot_comparison_figure.py
│ └── generate_training_loss_chart.py
│
├── data/ # Datasets (see Data Preparation)
├── checkpoints/ # Saved models
├── results/
│ └── figures/ # Generated figures
└── configs/
Location: scripts/distillation/student_model.py - VGGTVisionEncoder class
Key Features:
facebook/VGGT-1B), then local installation_apply method keeps VGGT on designated device even when parent model moves to GPUTo fit training on smaller GPUs:
torch.cuda.empty_cache() called every 5 batchesThe real LLaVA-3D teacher:
ChaimZhu/LLaVA-3D-7Bdevice_map={"": device} for compatibilitySymptoms: RuntimeError: CUDA out of memory
Solutions:
vggt_device = 'cpu'device="cpu" in RealLLaVA3DTeachertorch.cuda.empty_cache() callsSymptoms: ModuleNotFoundError: No module named 'vggt'
Solutions:
pip install transformersbash install_vggt.shsys.pathSymptoms: OSError: Can't load tokenizer or download errors
Solutions:
huggingface-cli loginhuggingface-cli download ChaimZhu/LLaVA-3D-7BSymptoms: AssertionError: Input image height X is not a multiple of patch height 14
Solutions:
F.interpolate is being called in _extract_vggt_featuresSymptoms: RuntimeError: Found dtype Double but expected Float
Solutions:
float32: .float() or dtype=torch.float32long: .long() or dtype=torch.longSymptoms: Training is very slow
Solutions:
@misc{distilled-llava3d,
title={Distilling 3D Spatial Reasoning into a Lightweight Vision-Language Model with CoT},
author={Alaa Asfour},
year={2026},
url={https://github.com/alaaasfour/distilled-LLaVA3D-with-CoT}
}
[Contributing guidelines]
Alaa Asfour (alaa.asfour@torontomu.ca)
110 commits
Python
99.9%