Laya-Multilingual-MXFP4

This is the Multilingual encoder backbone of convaiinnovations/laya (mmBERT-base (100+ languages), 322M params, 768 hidden size, 22 layers, 1024 token context), quantized to MXFP4 for MLX on Apple Silicon.

What's included -- and what's not

Laya is not a plain encoder: it is mmBERT-base (100+ languages) (this repo) plus a small from-scratch decision head (a 2-layer torch.nn.TransformerEncoder, an option-marker scorer, and an act/escalate head) defined in Laya's own rl_common.py, trained separately with RL (RLCD). Only the shared bidirectional encoder backbone is quantized and published here -- the decision head is a tiny (~15M param) uncompiled torch module that gains nothing from MLX quantization, and porting it to MLX would not make Laya's laya.load(...) / RLAgent API usable anyway (that API expects a torch model directory as-is).

To use Laya's actual decision-making API, keep using the upstream convaiinnovations/laya repo. This repo is for people who want the ModernBERT/mmBERT encoder only (e.g. as a quantized general-purpose feature extractor, or to build a custom MLX head on top) at a fraction of the memory footprint.

  • Size on disk: ~163 MB
  • Architecture: ModernBertModel (via mlx-embeddings)
  • Quantized with: mlx-embeddings (nn.quantize(..., mode="mxfp4"), group size 32)

Other quantizations

Use with mlx-embeddings

pip install mlx-embeddings
import mlx.core as mx
import mlx.nn as nn
from safetensors import safe_open
from transformers import AutoTokenizer
from mlx_embeddings.models.modernbert import ModelArgs, ModernBertModel
import json

mlx_dir = "sahilchachra/Laya-Multilingual-MXFP4"  # or a local snapshot_download() path
with open(f"{mlx_dir}/config.json") as f:
    cfg = json.load(f)
args = ModelArgs(model_type=cfg["model_type"], vocab_size=cfg["vocab_size"], hidden_size=cfg["hidden_size"],
    num_hidden_layers=cfg["num_hidden_layers"], intermediate_size=cfg["intermediate_size"],
    num_attention_heads=cfg["num_attention_heads"], max_position_embeddings=cfg.get("max_position_embeddings"),
    norm_eps=cfg.get("layer_norm_eps", 1e-5), attention_bias=cfg.get("attention_bias", False),
    global_attn_every_n_layers=cfg.get("global_attn_every_n_layers", 3), local_attention=cfg.get("local_attention", 128))
rp = cfg.get("rope_parameters")
if rp:
    args.global_rope_theta = rp["full_attention"]["rope_theta"]
    args.local_rope_theta = rp["sliding_attention"]["rope_theta"]

model = ModernBertModel(args)
weights = {}
with safe_open(f"{mlx_dir}/model.safetensors", framework="numpy") as f:
    for k in f.keys():
        weights[k] = mx.array(f.get_tensor(k))
qcfg = cfg["quantization"]
nn.quantize(model, group_size=qcfg["group_size"], bits=qcfg["bits"], mode=qcfg["mode"],
            class_predicate=lambda p, m: hasattr(m, "to_quantized") and f"{p}.scales" in weights)
model.load_weights(list(weights.items()), strict=True)
mx.eval(model.parameters())

tok = AutoTokenizer.from_pretrained(mlx_dir)
enc = tok("The quick brown fox jumps over the lazy dog.", return_tensors="np")
out = model(mx.array(enc["input_ids"]), attention_mask=mx.array(enc["attention_mask"]))
print(out["last_hidden_state"].shape)

Verification

Verified against the bf16/fp32 torch reference (answerdotai/ModernBERT-large / mmBERT-base weights loaded via the original rl_common.build_model) in two stages:

1. Port correctness (unquantized). The unquantized MLX encoder's last_hidden_state was compared directly to the torch reference on held-out text: max abs diff 0.045, mean abs diff 0.0025 (hidden states have mean abs magnitude ~0.63) -- confirms the mlx-embeddings ModernBERT port itself is numerically correct, independent of quantization.

2. End-to-end decision quality (quantized). The MLX-quantized encoder's last_hidden_state was fed into Laya's original, unmodified torch decision head (same weights, loaded from model.safetensors) and compared against the full torch reference pipeline, on real choice / score / noul-type questions (moderation and sentiment-style prompts):

Metric MXFP4 MXFP8
Encoder hidden-state mean abs diff vs fp32 0.287 0.218
Decision-head logit max abs diff 1.157 0.806
Top-1 answer mismatches (out of 3 test questions) 0/3 0/3

Honest caveat: this is a small (322M), LayerNorm-heavy encoder, not an LLM -- it is noticeably more sensitive to block quantization than modern decoder-only models. Hidden-state drift from MXFP4/MXFP8 is meaningfully larger in relative terms (35-45% mean abs perturbation) than typical MXFP4 LLM quantization (~1-5%), and one of three test questions (a typed-decisions MXFP8 score question with two closely-scored options) flipped its top-1 answer. Top-1 answers matched in 5/6 checkpoint x mode combinations, but if you need calibrated, tie-breaking-sensitive decisions, prefer the original bf16/fp32 encoder or treat quantized confidence scores as directional only, not exact.

LM Studio

Not applicable. Laya is a non-autoregressive encoder + custom scoring head, not a chat/completion model -- there is no generate() path or chat template, so LM Studio (which only runs chat/completion-style models) cannot load or serve this repo.

Downloads last month
149
Safetensors
Model size
0.3B params
Tensor type
F16
ยท
U32
ยท
MLX
Hardware compatibility
Log In to add your hardware

Quantized

Inference Providers NEW
This model isn't deployed by any Inference Provider. ๐Ÿ™‹ Ask for provider support

Model tree for sahilchachra/Laya-Multilingual-MXFP4

Finetuned
(207)
this model

Collection including sahilchachra/Laya-Multilingual-MXFP4