lucataco commited on
Commit
c4b62ef
·
verified ·
1 Parent(s): a1cc3c6

Card: zero-shot-classification tag, RAM guide for all variants, limitations, pinned mlx-vlm; clef_mlx: warn on untested mlx-vlm/mlx-lm versions

Browse files
Files changed (2) hide show
  1. README.md +30 -2
  2. clef_mlx.py +24 -0
README.md CHANGED
@@ -3,7 +3,7 @@ license: apache-2.0
3
  library_name: mlx
4
  base_model: Cloudflare/clef
5
  base_model_relation: quantized
6
- pipeline_tag: image-text-to-text
7
  tags:
8
  - mlx
9
  - clef
@@ -25,12 +25,26 @@ probability for every allowed option, in a single forward pass. **It is not a ch
25
  meaningless text. Use the bundled `clef_mlx.py` loader, which runs the backbone and the
26
  joint schema head.
27
 
 
 
 
 
 
 
 
 
 
 
 
28
  ## Usage
29
 
30
  ```bash
31
- pip install mlx-vlm huggingface_hub # no torch needed
32
  ```
33
 
 
 
 
34
  ```python
35
  import sys
36
  from huggingface_hub import snapshot_download
@@ -69,6 +83,20 @@ model.predict({
69
 
70
  See the [original model card](https://huggingface.co/Cloudflare/clef) for the input format, question types, and benchmarks.
71
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
  ## Conversion
73
 
74
  - Backbone: `mlx_vlm.convert -q --q-bits 4 --q-group-size 64` (vision tower kept in bf16).
 
3
  library_name: mlx
4
  base_model: Cloudflare/clef
5
  base_model_relation: quantized
6
+ pipeline_tag: zero-shot-classification
7
  tags:
8
  - mlx
9
  - clef
 
25
  meaningless text. Use the bundled `clef_mlx.py` loader, which runs the backbone and the
26
  joint schema head.
27
 
28
+ ## Which variant fits your Mac?
29
+
30
+ | Variant | Base | Download | Peak memory (1k / 4k / 16k tokens) | Latency (1k / 16k tokens) | Minimum Mac RAM |
31
+ |---|---|---|---|---|---|
32
+ | [clef-flash-4bit](https://huggingface.co/mlx-community/clef-flash-4bit) | 9B | 6.2 GB | 7.0 / 7.2 / 8.6 GB | 0.31 s / 7.0 s | 16 GB |
33
+ | [clef-flash-8bit](https://huggingface.co/mlx-community/clef-flash-8bit) | 9B | 10.7 GB | 11.4 / 11.6 / 13.0 GB | 0.34 s / 7.7 s | 24 GB (16 GB for short prompts) |
34
+ | **clef-4bit (this repo)** | 27B | 16.3 GB | 17.1 / 17.5 / 19.6 GB | 1.4 s / 26.0 s | 32 GB |
35
+ | [clef-8bit](https://huggingface.co/mlx-community/clef-8bit) | 27B | 29.8 GB | 30.5 / 30.8 / 33.0 GB | 1.5 s / 32.0 s | 48 GB |
36
+
37
+ Measured on an M5 Max with text input. macOS lets the GPU use only about 70–75% of RAM by default, so the minimum RAM is higher than the peak. The 9B variants are much faster; the 27B variants score higher (see the quality check below).
38
+
39
  ## Usage
40
 
41
  ```bash
42
+ pip install "mlx-vlm>=0.7.4,<0.8" huggingface_hub # no torch needed
43
  ```
44
 
45
+ Tested with mlx 0.32.3, mlx-lm 0.32.0 and mlx-vlm 0.7.4. `clef_mlx.py` uses mlx-vlm internals, so it
46
+ warns if you load it with an untested mlx-vlm minor version.
47
+
48
  ```python
49
  import sys
50
  from huggingface_hub import snapshot_download
 
83
 
84
  See the [original model card](https://huggingface.co/Cloudflare/clef) for the input format, question types, and benchmarks.
85
 
86
+ ## Limitations
87
+
88
+ - **Not a chat model.** Text generation tools (`mlx_lm.generate`, `mlx_vlm.generate`, LM Studio, Ollama) load
89
+ the backbone but give meaningless output. Only `clef_mlx.py` runs the decision head.
90
+ - **Long inputs are truncated by default**, exactly like the reference implementation: the state is cut so
91
+ the whole prompt fits in 16,384 tokens. Pass `truncate=False` to `predict()`/`systemone()` to get a
92
+ `clef_mlx.ContextTooLong` error instead, or raise `max_length` (the head was trained at 16k).
93
+ - **One record per call.** There is no batching; requests run one after another.
94
+ - **Images or videos, not both in one record.** Several images, or several videos, are fine.
95
+ - **Speed depends heavily on the chip.** Latencies above are from an M5 Max; long prompts on base
96
+ M-series chips will be several times slower.
97
+ - **Custom code.** Like the original release, this repo ships Python (`clef_mlx.py`) that you import and run.
98
+ Read it before use if that matters in your environment.
99
+
100
  ## Conversion
101
 
102
  - Backbone: `mlx_vlm.convert -q --q-bits 4 --q-group-size 64` (vision tower kept in bf16).
clef_mlx.py CHANGED
@@ -27,11 +27,34 @@ SYSTEM_PROMPT = (
27
  )
28
  QUESTION_TYPES = {"noul": 0, "choice": 1, "score": 2}
29
 
 
 
 
 
30
 
31
  class ContextTooLong(ValueError):
32
  pass
33
 
34
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
  # --------------------------------------------------------------------------- encoding
36
  # Mirrors joint_schema_model.encode_record (text-only path) exactly.
37
 
@@ -533,6 +556,7 @@ def load(path: str | Path, head_dtype=mx.bfloat16, backend: str = "auto") -> Cle
533
  if backend == "auto":
534
  backend = "vlm" if _has_vision_weights(path) else "lm"
535
  processor = None
 
536
  if backend == "vlm":
537
  from mlx_vlm import load as vlm_load
538
 
 
27
  )
28
  QUESTION_TYPES = {"noul": 0, "choice": 1, "score": 2}
29
 
30
+ # This loader uses mlx-vlm internals (get_input_embeddings, inputs_embeds/position_ids on the
31
+ # text model), which can change between minor releases. Tested: mlx 0.32.3, mlx-lm 0.32.0, mlx-vlm 0.7.4.
32
+ TESTED_VERSIONS = {"mlx-vlm": (0, 7), "mlx-lm": (0, 32)}
33
+
34
 
35
  class ContextTooLong(ValueError):
36
  pass
37
 
38
 
39
+ def _check_versions(packages: tuple[str, ...]) -> None:
40
+ import importlib.metadata
41
+ import warnings
42
+
43
+ for name in packages:
44
+ try:
45
+ version = importlib.metadata.version(name)
46
+ except importlib.metadata.PackageNotFoundError:
47
+ continue
48
+ major_minor = tuple(int(p) for p in version.split(".")[:2] if p.isdigit())
49
+ major, minor = TESTED_VERSIONS[name]
50
+ if major_minor != (major, minor):
51
+ warnings.warn(
52
+ f"clef_mlx was tested with {name} {major}.{minor}.x but {version} is installed; "
53
+ f'if loading fails or results look wrong, run: pip install "{name}>={major}.{minor},<{major}.{minor + 1}"',
54
+ stacklevel=3,
55
+ )
56
+
57
+
58
  # --------------------------------------------------------------------------- encoding
59
  # Mirrors joint_schema_model.encode_record (text-only path) exactly.
60
 
 
556
  if backend == "auto":
557
  backend = "vlm" if _has_vision_weights(path) else "lm"
558
  processor = None
559
+ _check_versions(("mlx-vlm",) if backend == "vlm" else ("mlx-lm",))
560
  if backend == "vlm":
561
  from mlx_vlm import load as vlm_load
562