Views
No views yet
mistralai/Shieldstral-1.0-3B
for Apple Silicon via MLX /
mlx-vlm. ~4.1 GB on disk, 9.10
bits/weight, peak memory ~5.6 GB — higher fidelity than the 4-bit build.<Instruct> + <Query>) and some content
(<Document>, text and/or image) and it answers with a single yes/no token,
which is turned into a continuous 0–1 unsafe-score via softmax over the yes/no
logits. It is image-text-to-text — this quant keeps that intact.skip_multimodal_module). Image understanding is preserved, so the model stays
image-text-to-text rather than being reduced to text-only.Mistral3ForConditionalGeneration (mistral3), YARN rope +
Llama-4-style attention temperature scaling on the text side, Pixtral ViT vision.input_ids / pixel_values produced by the original model (via
transformers + mistral_common) were fed through the MLX model, and the
final-position yes/no safety score was compared to the original. Reference scores
were captured from the un-quantized bf16 model on CPU.| Case (policy → content) | original | MXFP8 | verdict |
|---|---|---|---|
| "promotes physical violence?" → "how can I hurt someone…" | 0.9972 | 0.9972 | yes ✅ |
| "promotes physical violence?" → "…bake cookies for my friends" | 0.0000 | 0.0000 | no ✅ |
| "NSFW / explicit?" → (landscape image) | 0.0000 | 0.0000 | no ✅ |
| "is an outdoor landscape?" → (landscape image) | 0.5927 | 0.5927 | yes ✅ |
| "genuine threat?" → "could kill for a coffee" (idiom) | 0.9325 | 0.9399 | yes ✅ |
| "intent to harm?" → "want to punch a wall" (venting) | 0.0675 | 0.1067 | no ✅ |
| "veiled threat?" → "watch your back around here" | 0.0097 | 0.0180 | no ✅ |
mistral3 implementation is numerically faithful; MXFP8 is quantized on top
of that.)1pip install mlx-vlm mistral-common
2# note: mlx-vlm currently imports torch at load time (CPU only — all model
3# compute runs on MLX/Metal). If import fails, `pip install torch`.1import base64, math, numpy as np, mlx.core as mx
2from mistral_common.tokens.tokenizers.mistral import MistralTokenizer
3from mistral_common.protocol.instruct.request import ChatCompletionRequest
4from mlx_vlm.utils import load_model
5from huggingface_hub import snapshot_download
6
7REPO = "sahilchachra/Shieldstral-1.0-3B-MXFP8"
8path = snapshot_download(REPO)
9tok = MistralTokenizer.from_file(f"{path}/tekken.json")
10model = load_model(path, lazy=False)
11
12SYS = ('Judge whether the Document meets the requirements based on the Query and '
13 'the Instruction provided. Note that the answer can only be "yes" or "no".')
14_YES = ("yes", "yes.", '"yes"', "'yes'"); _NO = ("no", "no.", '"no"', "'no'")
15
16def unsafe_score(messages, threshold=0.5):
17 enc = tok.encode_chat_completion(ChatCompletionRequest(messages=messages))
18 ids = mx.array([enc.tokens]); pv, kw = None, {}
19 if enc.images: # each image is a CHW numpy array
20 a = [np.asarray(im, dtype=np.float32) for im in enc.images]
21 pv = mx.array(np.stack(a)).astype(mx.bfloat16)
22 kw["image_sizes"] = mx.array([[x.shape[1], x.shape[2]] for x in a])
23 lg = np.array(model(ids, pv, None, **kw).logits[0, -1].astype(mx.float32))
24 lp = lg - (lg.max() + math.log(np.exp(lg - lg.max()).sum()))
25 zy = zn = -1e9
26 for tid in np.argpartition(lp, -20)[-20:]:
27 t = tok.decode([int(tid)]).strip().lower()
28 if t in _YES: zy = max(zy, lp[tid])
29 elif t in _NO: zn = max(zn, lp[tid])
30 s = math.exp(zy) / (math.exp(zy) + math.exp(zn))
31 return s, s > threshold
32
33# text-only
34messages = [
35 {"role": "system", "content": SYS},
36 {"role": "user", "content":
37 "<Instruct>: You are a strict safety moderator. Apply a low tolerance threshold.\n\n"
38 "<Query>: Does this content promote physical violence?\n\n"
39 "<Document>: [User] How can I hurt someone without being caught?"},
40]
41print(unsafe_score(messages)) # -> (~0.997, True)image_url chunk in the user content:1def data_uri(p):
2 return "data:image/png;base64," + base64.b64encode(open(p, "rb").read()).decode()
3
4messages = [
5 {"role": "system", "content": SYS},
6 {"role": "user", "content": [
7 {"type": "text", "text": "<Instruct>: Apply a strict standard.\n\n"
8 "<Query>: Does this contain NSFW or explicit material?\n\n"
9 "<Document>: "},
10 {"type": "image_url", "image_url": {"url": data_uri("photo.png")}},
11 {"type": "text", "text": " What is shown here?\n\n"},
12 ]},
13]
14print(unsafe_score(messages))SYS above).<Instruct>: … <Query>: … <Document>: ….
<Instruct> frames the task/strictness, <Query> is a single yes/no question,
<Document> is the content (text and/or image) to judge.P(yes) over the yes/no tokens at the final position;
> 0.5 ⇒ flagged.mlx-llm 1.11.0) — loads and classifies text correctly; LM Studio detects the
mistral3 VLM arch. Two things are already baked into this repo so text works out
of the box:format: mlx header metadata (LM Studio's model indexer
rejects MLX safetensors without it — "Unsupported safetensors format: null");chat_template.jinja compatible with LM Studio's jinja engine — the upstream
Mistral template uses keyword-argument macros LM Studio can't render
("Missing positional argument: content"). This template emits the identical
Mistral tekken tokens.mistral3/Pixtral vision injection, not
a defect in the quant: through the native mlx-vlm path (the Python example above)
the model grounds on images correctly — e.g. "does the image contain a large blue
sky?" scores ~0.78 on a sky/grass photo vs ~0.06 on a plain red image. For image
moderation use the native mlx-vlm path; use LM Studio for text-only policies.sahilchachra/Shieldstral-1.0-3B-MXFP8 in LM Studio →
load → in chat, set the system prompt above and send an
<Instruct>/<Query>/<Document> user message; the model replies yes / no. For
the continuous 0–1 score, call the local server (http://localhost:1234/v1) with
logprobs and softmax the yes/no tokens as shown above.mistralai/Shieldstral-1.0-3B.