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
65
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
(53)
this model

Collection including sahilchachra/Laya-Multilingual-MXFP4