Moondream2 is available on Ollama as a roughly 1.7GB local vision-model package. The published moondream:v2 tag accepts both text and images with a 2K context window. It is a practical option for short visual questions, not a guarantee of accurate OCR or long-document reasoning.1
If you have limited free unified memory and want to test local image analysis on a Mac, moondream:v2 is a sensible starting point. For OCR, complex diagrams, multiple images, or long documents, compare it with a larger model early.
What Moondream2 Is
The figures below describe Ollama’s published moondream:v2 package, not the full memory needed at runtime.1 The project documentation explains how its vision encoder and language model work together.
| Component | Listing |
|---|---|
| Language model | Phi-2, 1.42 billion parameters, Q4_0 |
| Vision projector | CLIP, 454 million parameters, F16 |
| Package size | 1.7 GB |
| License | Apache 2.0 |
| Model class | vision-language model for edge devices |
The model connects a compact text decoder with a vision projector. It can turn visual input into text answers without calling a cloud API.
Typical jobs include:
- describing a photo or screenshot,
- answering questions about visible objects,
- roughly locating elements,
- recognizing short UI text or obvious states,
- pre-sorting images in a local workflow.1
Its small size is also the main limitation. Moondream2 has less capacity for fine detail, complex instructions, and long visual investigations than models with 7, 12, or more billion parameters.
Install with Ollama
You need:
- an Apple Silicon Mac or supported Intel Mac,
- a current Ollama installation,
- about 2 GB of free storage for the package,
- internet for the download; local use can work offline afterward.
Download the model:
ollama pull moondream:v2
Start it:
ollama run moondream:v2
For the first test, use an image with a result you can verify. Give a specific task rather than asking only “What do you see?”:
Describe the visible controls.
Then list three pieces of text you can read confidently.
Mark uncertain readings explicitly.
This makes it easier to notice when the model read a detail versus generating a plausible one.
Send Images from Python
First install the Python client with python3 -m pip install ollama. Ollama must be running locally and moondream:v2 must already be downloaded. The client accepts a local image path in a chat message:
from ollama import chat
response = chat(
model="moondream:v2",
messages=[{
"role": "user",
"content": "Describe this image and mark uncertain details.",
"images": ["/path/to/image.jpg"],
}],
)
print(response.message.content)
For production processing, also:
- restrict file type and size,
- normalize images before inference,
- do not treat free-form model output as reliable OCR,
- log errors and timeouts,
- explicitly disable cloud features for sensitive material.
Reproducible local vision test: keep the image on loopback
Ollama’s documented POST /api/chat endpoint expects base64-encoded image data in the images array. The Python SDK shown above can accept a file path, while direct REST calls require you to encode the image first. The Vision docs explain the difference. The listed moondream:v2 tag has a 2K / 2,048-token context window. Its 1.7GB file size is download size, not a runtime memory measurement.
Start Ollama, run ollama pull moondream:v2 and save a non-sensitive image as ./example.png. The example validates PNG, JPEG and WebP file signatures and limits files to 10 MiB. This is a self-imposed safety limit, not Ollama’s published image restriction. By default, DRY_RUN=1 verifies the file and JSON payload without sending an HTTP request.
IMAGE_PATH=./example.png DRY_RUN=1 python3 - <<'PY'
import base64, json, os, time
from pathlib import Path
from urllib.error import HTTPError, URLError
from urllib.request import Request, urlopen
endpoint = "http://127.0.0.1:11434/api/chat"
image = Path(os.getenv("IMAGE_PATH", "./example.png")).expanduser()
dry_run = os.getenv("DRY_RUN", "1")
if dry_run not in ("0", "1"):
raise SystemExit("DRY_RUN must be 0 or 1")
if not image.is_file():
raise SystemExit("Image not found: " + str(image))
size = image.stat().st_size
if size == 0 or size > 10 * 1024 * 1024:
raise SystemExit("Image must be 1 byte to 10 MiB (example safety cap)")
raw = image.read_bytes()
if not (raw.startswith(b"\x89PNG\r\n\x1a\n") or
raw.startswith(b"\xff\xd8\xff") or
(raw.startswith(b"RIFF") and raw[8:12] == b"WEBP")):
raise SystemExit("Expected a PNG, JPEG or WebP image")
payload = {"model": "moondream:v2", "messages": [{
"role": "user",
"content": "Describe visible objects. Flag uncertain text.",
"images": [base64.b64encode(raw).decode("ascii")],
}], "stream": False, "options": {"num_ctx": 2048}, "keep_alive": 0}
if dry_run == "1":
print("DRY_RUN: file and payload validated; no HTTP request sent")
print("Endpoint:", endpoint, "Model:", payload["model"], "Bytes:", size)
else:
req = Request(endpoint, data=json.dumps(payload).encode("utf-8"),
headers={"Content-Type": "application/json"}, method="POST")
started = time.perf_counter()
try:
with urlopen(req, timeout=120) as resp:
answer = json.load(resp)
except (HTTPError, URLError, TimeoutError) as exc:
raise SystemExit("Local Ollama request failed: " + str(exc))
print(answer.get("message", {}).get("content", "No answer returned"))
elapsed = time.perf_counter() - started
print("Wall time (s):", round(elapsed, 2))
print("Output tokens:", answer.get("eval_count", "not reported"))
output_tokens, decode_ns = answer.get("eval_count"), answer.get("eval_duration")
if isinstance(output_tokens, int) and isinstance(decode_ns, int) and decode_ns > 0:
print("Decode tokens/s (Ollama):", round(output_tokens * 1_000_000_000 / decode_ns, 2))
PY
Only after a successful dry run should you set DRY_RUN=0 for actual local inference. The script posts exclusively to http://127.0.0.1:11434/api/chat, never a cloud endpoint. It uses a 2,048-token context and prints the reported output-token count on a real response. The dry run does not print encoded image contents.
Interpreting measurements: The new Wall time (s) output measures the full request, including image processing and any model load. Decode tokens/s (Ollama) uses only Ollama’s reported eval_duration and eval_count; it excludes prompt prefill and image processing. Compare cold and warm runs separately. No Mac throughput is claimed without a real test.
Disable Ollama Cloud: The official FAQ documents {"disable_ollama_cloud": true} in ~/.ollama/server.json or OLLAMA_NO_CLOUD=1. For the macOS app, set launchctl setenv OLLAMA_NO_CLOUD 1, restart Ollama and verify Ollama cloud disabled: true in its logs. Keep the API bound to 127.0.0.1 by default; OLLAMA_HOST=0.0.0.0 unnecessarily expands network access for this test.
An evidence protocol, not invented Mac benchmarks
Use ten images you can inspect yourself: ordinary photos, UI screenshots and a few difficult charts. Record exact tag, Ollama version, image size, prompt, correct/incorrect/uncertain objects, total latency and macOS memory pressure. For tiny labels, compare with a dedicated OCR engine. ollama ps shows models loaded in memory; it does not establish visual accuracy.
If the localhost request returns Connection refused, check that Ollama is running. For model not found, inspect ollama list and the exact tag. Neither 2K context nor a 1.7GB download establishes measured tokens/s or OCR quality. Reported figures reflect package specifications rather than on-device Mac benchmarks.
Memory Guidance on Mac
The package is small, but it is not the only memory consumer. macOS, Ollama, the image, chat history, and other apps share unified memory.
| Mac configuration | Practical guidance |
|---|---|
| 8 GB unified memory | basic single-image tasks are possible; close large apps |
| 16 GB | more comfortable for screenshots and short image conversations |
| 24–32 GB | plenty of headroom; larger vision models become more attractive |
| 48 GB+ | Moondream2 is rarely the memory limit; compare stronger models |
On an 8 GB Mac, Moondream2’s small size is its main advantage. On a 32 or 64 GB system, test whether a larger model delivers better quality without becoming too slow for the workflow.
Diagnose a bad image answer
Instead of repeating two generic evaluation checklists, diagnose the failure:
| Observation | Next experiment |
|---|---|
| Text is invented | Enlarge the text region and compare with a dedicated OCR engine |
| An object is missing | Crop the image and repeat the same question |
| Numbers are transposed | Verify against the original; do not feed unverified values into a workflow |
| High response latency | Inspect Wall time, separate cold from warm runs and watch macOS memory pressure |
This is a test protocol, not a measured error rate. Record the image, ground truth, Ollama version and Mac configuration.
When a Larger Vision Model Is Better
| Task | Moondream2 | Larger vision model |
|---|---|---|
| describe one photo | good fit | also suitable |
| categorize a UI screenshot | often sufficient | better with many details |
| read a long document page | limited | much better starting point |
| tables and small numbers | error-prone | usually better, still verify |
| compare several images | limited | stronger starting point |
| local test on 8 GB | very attractive | often too large |
Possible next tests in Ollama:
llama3.2-visionfor a larger general vision workflow,gemma3for text and image in several sizes,qwen2.5vlfor documents, tables, and UI screenshots.
Tags, package sizes, and runtime support change. Check the current Ollama page and free memory before downloading.
Privacy: Keep the Whole Path Local
A downloaded Ollama model can run inference locally. That does not automatically make the entire workflow offline. A frontend, agent, or additional tool may still contact external services.
For a local-first setup:2
- disable cloud features in Ollama,
- do not enable web search or external tools,
- do not expose the local server directly to the internet,
- account for logs and temporary image files,
- test whether the client opens network connections.
Moondream2 can be useful for sensitive screenshots when the entire execution path (model, API client, storage, and post-processing) stays strictly local.
Moondream2 vs Moondream3 Preview: Different Models and Licenses
Moondream2 is available as Ollama’s moondream:v2 package with a roughly 1.7 GB download, a compact image projector, and an Apache 2.0 license. Those facts apply to this specific v2 tag, not automatically to later releases.13
Moondream3 Preview is a different architecture. Its model card describes a 9B-total / 2B-active mixture-of-experts model and 32K usable context. Some published inference examples assume CUDA and are not a drop-in Mac/Ollama setup. The preview is not a compatible replacement tag for moondream:v2.4
Commercial use: “other” is a metadata label, not the actual license
The Hugging Face model card lists the preview’s license simply as “other.” The repository’s current LICENSE.md spells out Business Source License 1.1 (BSL 1.1) with an Additional Use Grant:
- Internal production use within an organization and personal/research uses are permitted under the stated conditions.
- Some commercial third-party products are permitted. However, the additional grant restricts paid competing hosted or embedded offerings that substantially overlap with M87 Labs’ paid products.
- The license provides for a later switch to Apache 2.0. Until then, the current BSL terms also govern derivatives and redistribution.
Read the actual license text rather than inferring Apache-2.0 rights from a generic metadata label. Do not transfer Moondream2’s Apache 2.0 license to Moondream3 Preview. If shipping a commercial product or external API, examine the terms and your distribution model with qualified legal advice; this is not legal advice.5
For simple image questions on a memory-constrained Mac, the established Ollama v2 tag is still the simpler starting point. Evaluate the preview’s runtime, memory and license separately.
Test it with your own images
For a reproducible start, download the listed Ollama tag and inspect its metadata:
ollama pull moondream:v2
ollama show moondream:v2
ollama ps
The last command only shows currently loaded models, so an empty result is normal until inference has started. Launch ollama run moondream:v2 and try three inputs: a clear everyday photo, a screenshot containing small text and a complex chart.
Score more than whether it produced an answer. Note hallucinated objects, inaccurate text reproduction and missing visual details. The 1.7GB number is the download size, not a complete runtime-memory measurement. Dedicated OCR is often a better baseline when text extraction must be reliable.
For full local setup instructions, see the Ollama guide.
Sources and Status
Status: October 12, 2026. The v2 package size and 2K context follow Ollama’s listing; Moondream3 licensing was checked against its current LICENSE.md. Review license revisions before production use.
Footnotes
Frequently Asked Questions
What is Moondream2?
Moondream2 is a compact vision-language model for image descriptions, visual questions and object detection. The Ollama package combines a 1.42B Phi-2 language model with a 454M CLIP projector and is about 1.7 GB.
Does Moondream2 run on an 8 GB Mac?
The 1.7 GB package is small enough for basic single-image tasks on many 8 GB Apple Silicon Macs. Open apps, image size and longer chats reduce available memory; 16 GB is more comfortable.
How do I install Moondream2 with Ollama?
Install Ollama and run `ollama pull moondream:v2`. Start it with `ollama run moondream:v2`. Applications can send images through the local Ollama API or Python package.
Can Moondream2 replace cloud vision models?
Not generally. Moondream2 is useful for simple local image questions, but reaches its limits sooner on dense text, complex diagrams, fine OCR and multi-image reasoning.
Can I use Moondream2 commercially?
The current Hugging Face page and Ollama package list Moondream2 under Apache 2.0. For a product, still verify the exact model version and every component in the deployment.