Instructions to use Mike0021/pulpie-orange-small-mlx with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- MLX
How to use Mike0021/pulpie-orange-small-mlx with MLX:
# Download the model from the Hub pip install huggingface_hub[hf_xet] huggingface-cli download --local-dir pulpie-orange-small-mlx Mike0021/pulpie-orange-small-mlx
- Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- LM Studio
Pulpie Orange Small MLX
This repository contains MLX weights for
feyninc/pulpie-orange-small,
a 210M-parameter EuroBERT token-classification model for main-content extraction
from HTML.
The source checkpoint is an encoder-only EuroBERT model with RoPE, RMSNorm,
SwiGLU MLP layers, and a token-classification head. It is not a decoder-only
LLM, so this conversion does not use mlx-lm's standard LLM model classes.
Instead, this repository includes modeling_eurobert_mlx.py, a small MLX
implementation of the source architecture with matching parameter names.
Files
| File | Purpose |
|---|---|
model-bf16.safetensors |
Native 16-bit BF16 MLX weights converted from the source checkpoint. |
model-8bit.safetensors |
MLX affine 8-bit weight-quantized variant. |
model-4bit.safetensors |
MLX affine 4-bit weight-quantized variant. |
modeling_eurobert_mlx.py |
MLX EuroBERT token-classification loader. |
mlx_config.json |
Variant metadata and quantization settings. |
verification_report.json |
Load, numerical, extraction, latency, and compute-cost results. |
scripts/convert_to_mlx.py |
Reproducible conversion script. |
scripts/verify_mlx.py |
Reproducible verification script. |
Usage
Install dependencies:
pip install -r requirements.txt
Run a forward pass:
import sys
import mlx.core as mx
from huggingface_hub import snapshot_download
from transformers import AutoTokenizer
repo_dir = snapshot_download("Mike0021/pulpie-orange-small-mlx")
sys.path.insert(0, repo_dir)
from modeling_eurobert_mlx import load_model
tokenizer = AutoTokenizer.from_pretrained(repo_dir, trust_remote_code=True)
model = load_model(repo_dir, variant="bf16") # "bf16", "8bit", or "4bit"
inputs = tokenizer(
["<h1>Apple MLX conversion</h1><p>Main article text.</p>"],
return_tensors="np",
padding=True,
)
input_ids = mx.array(inputs["input_ids"])
attention_mask = mx.array(inputs["attention_mask"])
logits = model(input_ids, attention_mask)
mx.eval(logits)
print(logits.shape) # batch, tokens, 2
Minimal Pulpie-style extraction:
import numpy as np
import mlx.core as mx
from pulpie.chunker import extract_blocks, pack_chunks, tokenize_blocks
from pulpie.model_utils import extract_item_ids, predictions_to_labels
from pulpie.reconstruct import extract_main_html
from pulpie.simplify import simplify
html = (
"<html><body><article><h1>Apple MLX conversion</h1>"
"<p>This article explains how to convert a EuroBERT content extraction "
"model to MLX format.</p></article></body></html>"
)
simplified, map_html = simplify(html)
blocks = extract_blocks(simplified)
item_ids = extract_item_ids(blocks)
sep_id = tokenizer.convert_tokens_to_ids("<|sep|>")
chunks = pack_chunks(
tokenize_blocks(blocks, tokenizer),
max_tokens=8192,
sep_token_id=sep_id,
bos_token_id=tokenizer.bos_token_id,
eos_token_id=tokenizer.eos_token_id,
)
predictions = [0] * len(blocks)
for chunk_ids, block_indices in chunks:
ids = mx.array([chunk_ids])
mask = mx.ones_like(ids)
logits = model(ids, mask)
mx.eval(logits)
logits_np = np.array(logits.astype(mx.float32))[0]
sep_positions = np.where(np.array(chunk_ids) == sep_id)[0]
preds = logits_np[sep_positions].argmax(axis=-1).tolist()
for i, block_idx in enumerate(block_indices):
predictions[block_idx] = int(preds[i])
labels = predictions_to_labels(item_ids, predictions)
print(extract_main_html(map_html, labels))
Conversion Methodology
- Downloaded
feyninc/pulpie-orange-smallfrom the Hugging Face Hub. - Inspected
config.json,configuration_eurobert.py, andmodeling_eurobert.py. - Confirmed the model is
EuroBertForTokenClassificationwith 12 layers, hidden size 768, 12 attention heads, head dim 64, max length 8192, BF16 source weights, and 2 output labels. - Confirmed current MLX can be installed on Linux with
mlx[cpu], so no cloud Mac was required for conversion or load verification. - Implemented a custom MLX EuroBERT token-classification module with matching state-dict keys and the source architecture behavior.
- Saved the BF16 MLX weights with
mlx.core.save_safetensors. - Created 8-bit and 4-bit variants with
mlx.nn.quantize, using affine weight quantization, group size 64, over MLXLinearandEmbeddingmodules. - Verified each variant with
scripts/verify_mlx.py.
Verification Results
Verification was run on Linux x86_64 using mlx[cpu]. The PyTorch reference was
the original source checkpoint loaded in float32 with eager attention. The BF16
variant is expected to have small dtype-level differences versus that float32
reference; quantized variants have larger differences.
Load Checks
| Variant | Load result | Test logits shape | Test logits dtype |
|---|---|---|---|
| BF16 | Pass | [1, 3, 2] |
mlx.core.bfloat16 |
| 8-bit | Pass | [1, 3, 2] |
mlx.core.bfloat16 |
| 4-bit | Pass | [1, 3, 2] |
mlx.core.bfloat16 |
Numerical Accuracy
Test inputs: ["A", "B", "C"], token shape [3, 2].
| Variant | Max abs diff vs PyTorch fp32 | Mean abs diff | MLX CPU latency |
|---|---|---|---|
| BF16 | 0.0452327728 | 0.0191817340 | 716.88 ms |
| 8-bit | 1.2797489166 | 0.5423613191 | 9380.58 ms |
| 4-bit | 2.2551989555 | 1.1897996664 | 9323.18 ms |
PyTorch fp32 eager latency on the same input was 50.09 ms on this Linux CPU. The quantized MLX CPU path is slow on this host and should not be read as an Apple Silicon benchmark.
End-to-End Extraction
Sample HTML:
<html><body><article><h1>Apple MLX conversion</h1><p>This article explains how to convert a EuroBERT content extraction model to MLX format.</p></article></body></html>
Pulpie preprocessing produced 2 blocks and one 50-token chunk. All variants
loaded, classified both blocks as main, and reconstructed non-empty HTML.
| Variant | Predictions | Non-empty output | MLX CPU extraction latency |
|---|---|---|---|
| BF16 | [1, 1] |
Pass | 5469.05 ms |
| 8-bit | [1, 1] |
Pass | 78333.61 ms |
| 4-bit | [1, 1] |
Pass | 77852.02 ms |
Full machine-readable results are in verification_report.json.
Limitations
- This is a custom MLX encoder/token-classification implementation, not an
mlx-lmdecoder model. - The 8-bit and 4-bit variants are weight-only affine MLX quantizations. They load and pass a small extraction test, but full WebMainBench quality was not re-evaluated.
- Linux CPU quantized latency is poor in this environment. MLX is primarily intended for Apple Silicon GPU execution.
- The source tokenizer currently emits a Transformers regex warning. The
verifier keeps the tokenizer behavior used by the published
pulpiepackage rather than changing token IDs during conversion.
Compute Cost
No paid cloud Mac or hosted GPU was used. Conversion and verification were done
locally on Linux x86_64 with the MLX CPU package. Incremental compute cost:
$0.00.
License
The source model weights are licensed under CC BY-NC 4.0. This converted checkpoint follows the same non-commercial license. The included conversion and loader code is provided for interoperability with the converted weights.
- Downloads last month
- -
Quantized