Image-Text-to-Text
MLX
Safetensors
mage_vl
vision-language-model
video-understanding
mage-vl
conversational
custom_code
8-bit precision
Instructions to use mlx-community/Mage-VL-8bit with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- MLX
How to use mlx-community/Mage-VL-8bit with MLX:
# Make sure mlx-vlm is installed # pip install --upgrade mlx-vlm from mlx_vlm import load, generate from mlx_vlm.prompt_utils import apply_chat_template from mlx_vlm.utils import load_config # Load the model model, processor = load("mlx-community/Mage-VL-8bit") config = load_config("mlx-community/Mage-VL-8bit") # Prepare input image = ["http://images.cocodataset.org/val2017/000000039769.jpg"] prompt = "Describe this image." # Apply chat template formatted_prompt = apply_chat_template( processor, config, prompt, num_images=1 ) # Generate output output = generate(model, processor, formatted_prompt, image) print(output) - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- LM Studio
| #!/usr/bin/env python | |
| """Run Mage-VL-Base image or video inference offline or through SGLang.""" | |
| import argparse | |
| import base64 | |
| import mimetypes | |
| from pathlib import Path | |
| def image_url(image: str) -> str: | |
| if image.startswith(("http://", "https://", "data:")): | |
| return image | |
| path = Path(image) | |
| mime = mimetypes.guess_type(path.name)[0] or "image/jpeg" | |
| encoded = base64.b64encode(path.read_bytes()).decode("ascii") | |
| return f"data:{mime};base64,{encoded}" | |
| def sample_video(video: str, num_frames: int): | |
| import cv2 | |
| import numpy as np | |
| from PIL import Image | |
| capture = cv2.VideoCapture(video) | |
| frame_count = int(capture.get(cv2.CAP_PROP_FRAME_COUNT)) | |
| if frame_count <= 0: | |
| capture.release() | |
| raise ValueError(f"Could not read video: {video}") | |
| indices = np.linspace(0, frame_count - 1, min(num_frames, frame_count), dtype=int) | |
| frames = [] | |
| for index in indices: | |
| capture.set(cv2.CAP_PROP_POS_FRAMES, int(index)) | |
| ok, frame = capture.read() | |
| if not ok: | |
| capture.release() | |
| raise ValueError(f"Could not decode frame {index} from: {video}") | |
| frames.append(Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))) | |
| capture.release() | |
| return frames | |
| def run_offline(args): | |
| import os | |
| import torch | |
| from PIL import Image | |
| from transformers import AutoModelForCausalLM, AutoProcessor | |
| model_path = args.model | |
| if args.video and args.video_backend == "codec" and args.codec_engine == "neural": | |
| if not os.path.isdir(model_path): | |
| from huggingface_hub import snapshot_download | |
| model_path = snapshot_download(args.model) | |
| processor = AutoProcessor.from_pretrained(model_path, trust_remote_code=True) | |
| model = AutoModelForCausalLM.from_pretrained( | |
| model_path, trust_remote_code=True, torch_dtype="auto", device_map="auto" | |
| ).eval() | |
| media_type = "image" if args.image else "video" | |
| messages = [{"role": "user", "content": [ | |
| {"type": media_type}, {"type": "text", "text": args.question}, | |
| ]}] | |
| text = processor.apply_chat_template(messages, tokenize=False, add_generation_prompt=True) | |
| if args.image: | |
| inputs = processor( | |
| text=[text], images=[Image.open(args.image).convert("RGB")], return_tensors="pt" | |
| ) | |
| elif args.video_backend == "codec": | |
| codec_config = { | |
| "engine": "hevc" if args.codec_engine == "traditional" else "dcvc-rt", | |
| "target_canvas": args.num_frames, | |
| "patch": 16, | |
| } | |
| if args.codec_engine == "neural": | |
| codec_config["dcvc"] = { | |
| "pkg_dir": os.path.join(model_path, "neural_codec"), | |
| "device": str(model.device), | |
| } | |
| inputs = processor( | |
| text=[text], | |
| videos=[args.video], | |
| video_backend="codec", | |
| max_pixels=args.max_pixels, | |
| codec_config=codec_config, | |
| return_tensors="pt", | |
| padding=True, | |
| ) | |
| else: | |
| inputs = processor( | |
| text=[text], | |
| videos=[sample_video(args.video, args.num_frames)], | |
| return_tensors="pt", | |
| padding=True, | |
| ) | |
| inputs = {k: (v.to(model.device) if hasattr(v, "to") else v) for k, v in inputs.items()} | |
| if "pixel_values" in inputs: | |
| inputs["pixel_values"] = inputs["pixel_values"].to(model.dtype) | |
| with torch.inference_mode(): | |
| output = model.generate(**inputs, max_new_tokens=args.max_new_tokens, do_sample=False) | |
| answer = processor.tokenizer.decode( | |
| output[0, inputs["input_ids"].shape[1]:], skip_special_tokens=True | |
| ) | |
| print(answer.strip()) | |
| def run_online(args): | |
| from openai import OpenAI | |
| if args.image: | |
| content = [{"type": "image_url", "image_url": {"url": image_url(args.image)}}] | |
| else: | |
| content = [ | |
| {"type": "image_url", "image_url": {"url": frame_url(frame)}} | |
| for frame in sample_video(args.video, args.num_frames) | |
| ] | |
| content.append({"type": "text", "text": args.question}) | |
| client = OpenAI(base_url=args.base_url, api_key=args.api_key) | |
| response = client.chat.completions.create( | |
| model=args.model, | |
| messages=[{"role": "user", "content": content}], | |
| max_tokens=args.max_new_tokens, | |
| ) | |
| print(response.choices[0].message.content) | |
| def frame_url(frame) -> str: | |
| import io | |
| buffer = io.BytesIO() | |
| frame.save(buffer, format="JPEG") | |
| encoded = base64.b64encode(buffer.getvalue()).decode("ascii") | |
| return f"data:image/jpeg;base64,{encoded}" | |
| def main(): | |
| parser = argparse.ArgumentParser(description=__doc__) | |
| parser.add_argument("--mode", choices=("offline", "online"), required=True) | |
| media = parser.add_mutually_exclusive_group(required=True) | |
| media.add_argument("--image", help="Local image path") | |
| media.add_argument("--video", help="Local video path") | |
| parser.add_argument("--video-backend", choices=("frames", "codec"), default="frames") | |
| parser.add_argument( | |
| "--codec-engine", choices=("traditional", "neural"), default="traditional" | |
| ) | |
| parser.add_argument("--num-frames", type=int, default=32) | |
| parser.add_argument("--max-pixels", type=int, default=150000) | |
| parser.add_argument("--question", default="Describe this media.") | |
| parser.add_argument("--model", default="microsoft/Mage-VL") | |
| parser.add_argument("--max-new-tokens", type=int, default=256) | |
| parser.add_argument("--base-url", default="http://localhost:30000/v1") | |
| parser.add_argument("--api-key", default="EMPTY") | |
| args = parser.parse_args() | |
| if args.mode == "online" and args.video_backend == "codec": | |
| parser.error("online video inference supports only --video-backend frames") | |
| if args.num_frames <= 0: | |
| parser.error("--num-frames must be positive") | |
| (run_offline if args.mode == "offline" else run_online)(args) | |
| if __name__ == "__main__": | |
| main() | |