How to Load a Model and Processor in MLX-VLM: A Complete Guide
To load a model and processor in MLX-VLM, call mlx_vlm.utils.load(path_or_hf_repo) which returns a tuple of (model, processor) ready for inference.
The MLX-VLM library provides a unified loading pipeline that orchestrates model weights, configuration files, image processors, and tokenizers through a single entry point. Whether you are pulling a multimodal model from the Hugging Face Hub or loading a fine-tuned checkpoint from local storage, understanding the internal loading mechanism ensures efficient memory usage and correct processor initialization.
The load Entry Point
The primary interface for loading models is the load function defined in mlx_vlm/utils.py (lines 363‑379). This helper abstracts four distinct operations: path resolution, model instantiation, image processor construction, and tokenizer assembly.
from mlx_vlm.utils import load
model, processor = load(
path_or_hf_repo="Qwen/Qwen2-VL-Chat",
adapter_path=None,
lazy=False,
quantize_activations=False
)
The function accepts either a local directory path or a Hugging Face repository identifier. It returns a tuple containing the instantiated model and a fully configured processor object that handles both text tokenization and image preprocessing.
Step-by-Step Loading Pipeline
Understanding the internal pipeline helps debug loading errors and optimize performance for large vision-language models.
Path Resolution and Model Weights
First, load invokes get_model_path to resolve the input argument to a concrete directory on disk. It then calls load_model (lines 160‑188 in mlx_vlm/utils.py) to:
- Read the model configuration JSON
- Locate
.safetensorsweight files - Instantiate the appropriate model class
- Optionally quantize weights
- Evaluate parameters eagerly unless
lazy=True
The lazy parameter controls whether model parameters are materialized immediately (lazy=False, default) or loaded on-demand during the first forward pass (lazy=True).
Image Processor Construction
MLX-VLM supports vision models with specialized image or video preprocessing requirements. The load_image_processor function (lines 459‑479) inspects the model class for a dedicated ImageProcessor or VideoProcessor implementation and constructs it if present. This component handles resizing, normalization, and tensor conversion for visual inputs.
Tokenizer and Processor Assembly
Finally, load_processor (lines 482‑514) builds a Hugging Face AutoProcessor or model-specific subclass. This step wires up:
- The tokenizer and detokenizer
- Stopping criteria for generation
- The eos_token_id extracted from the model configuration
If an image processor was created in the previous step, it is attached via processor.image_processor = image_processor before the function returns.
Optional LoRA Adapters
For parameter-efficient fine-tuning, MLX-VLM supports loading LoRA adapters alongside base models. When the adapter_path parameter is provided, load invokes apply_lora_layers (lines 404‑407 in mlx_vlm/utils.py) after instantiating the base model. The adapter weights are automatically merged into the model parameters during this phase.
model, processor = load(
"base-model-repo",
adapter_path="/path/to/lora/adapter",
lazy=False
)
Lazy vs Eager Loading
The lazy parameter offers a trade-off between startup time and initial latency:
lazy=False(default) – Callsmx.evalon all parameters immediately after loading. This guarantees the model resides fully in memory before returning, eliminating compilation delays during the first inference call.lazy=True– Defers weight materialization until the first forward pass. This reduces initial memory pressure for very large models but may cause a noticeable pause when processing the first request.
The lazy evaluation logic appears in mlx_vlm/utils.py within the load_model implementation.
Practical Code Examples
Loading from Hugging Face Hub
Load a Qwen2-VL model directly from the Hugging Face repository with eager initialization:
from mlx_vlm.utils import load
model, processor = load(
"Qwen/Qwen2-VL-Chat",
revision="main",
lazy=False
)
prompt = "Describe this image: <image>"
outputs = model.generate(processor(prompt))
print(processor.decode(outputs[0]))
Loading Local Checkpoints
For locally saved models or custom fine-tunes, provide the absolute path to the directory containing config.json and .safetensors files:
from pathlib import Path
from mlx_vlm.utils import load
checkpoint_dir = Path("/home/user/models/my-vlm-checkpoint")
model, processor = load(str(checkpoint_dir), lazy=True)
# Parameters will materialize on first use
response = model.generate(processor("What is shown in this picture? <image>"))
Loading with LoRA Adapters
Combine a base model with task-specific LoRA weights:
model, processor = load(
"mlx-community/Qwen2-VL-7B-Instruct",
adapter_path="/home/user/checkpoints/lora-vision",
lazy=False
)
result = model.generate(processor("Explain the chart data. <image>"))
print(processor.decode(result[0]))
Inspecting Processor Components
Verify that the image processor and tokenizer loaded correctly:
print(type(processor.image_processor))
# Output: <class 'mlx_vlm.models.qwen2_vl.processing_qwen2_vl.AutoImageProcessor'>
print(type(processor.tokenizer))
# Output: <class 'transformers.Qwen2TokenizerFast'>
Summary
- The
mlx_vlm.utils.loadfunction serves as the single entry point for model and processor initialization, handling both local directories and Hugging Face repositories. - The loading pipeline explicitly separates concerns into
load_model(weights),load_image_processor(vision preprocessing), andload_processor(tokenization). - Set
lazy=Trueto defer weight materialization and reduce startup memory for large models, or uselazy=False(default) for immediate readiness. - Pass
adapter_pathto automatically merge LoRA adapters into the base model during loading. - Source implementations reside primarily in
mlx_vlm/utils.pywith specific line ranges for each sub-operation.
Frequently Asked Questions
How do I load a model from a local directory instead of Hugging Face?
Pass the absolute path to the directory containing your config.json and weight files as the first argument to load. For example: load("/path/to/local/model", lazy=False). The function detects local paths automatically and skips remote resolution.
What is the difference between the processor and the model in MLX-VLM?
The model object contains the neural network weights and forward logic, while the processor handles input preparation (tokenizing text, preprocessing images) and output decoding. The processor typically wraps a Hugging Face tokenizer and may include a custom image processor attached at processor.image_processor.
Can I use lazy loading with LoRA adapters?
Yes. When you specify both lazy=True and adapter_path, the base model loads lazily while the LoRA weights are still applied correctly. However, note that the first forward pass will incur the combined overhead of materializing base parameters and merging adapter layers.
Where does MLX-VLM store downloaded Hugging Face models?
The library uses standard Hugging Face Hub caching mechanisms. When you provide a repository ID like "Qwen/Qwen2-VL-Chat", the get_model_path helper downloads files to the HF cache directory (typically ~/.cache/huggingface/hub) and returns the local path for subsequent loading operations.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →