Download convert.py from znaat/modernbert-coreml: direct link, hf CLI and curl.
- Browser
- Download file 2.06 kB
-
https://huggingface.co/znaat/modernbert-coreml/resolve/main/convert.py
- Command line
-
hf download hf://znaat/modernbert-coreml/convert.py
-
curl -L -o convert.py https://huggingface.co/znaat/modernbert-coreml/resolve/main/convert.py
2.06 kB
| #!/usr/bin/env python3 | |
| """ModernBERT -> Core ML, at a fixed sequence length. | |
| python convert.py --length 128 [--model ModernBERT-base] | |
| The length is fixed on purpose. A flexible `RangeDim` traced at one token | |
| converts without error and is wrong at every other length — see the README. | |
| Pin the toolchain. transformers 5.x emits `new_ones` in ModernBERT's attention | |
| path and coremltools cannot convert it; the failure also hits BERT and | |
| DistilBERT, so it is the toolchain and not this model. | |
| torch==2.7.0 transformers==4.48.3 coremltools==9.0 | |
| """ | |
| import argparse | |
| import numpy as np | |
| import torch | |
| import coremltools as ct | |
| from transformers import AutoModelForMaskedLM | |
| parser = argparse.ArgumentParser() | |
| parser.add_argument("--model", default="ModernBERT-base") | |
| parser.add_argument("--length", type=int, default=128) | |
| args = parser.parse_args() | |
| class Wrapped(torch.nn.Module): | |
| """The mask stays `ones_like` inside the graph. | |
| Taking `attention_mask` as a second input makes ModernBERT build it with | |
| `new_ones`, which coremltools has no conversion for. The cost is that | |
| padding is attended as if it were text — pick a length close to your | |
| sentences, or convert several. | |
| """ | |
| def __init__(self, name): | |
| super().__init__() | |
| self.model = AutoModelForMaskedLM.from_pretrained(f"answerdotai/{name}") | |
| def forward(self, input_ids): | |
| return self.model( | |
| input_ids=input_ids, attention_mask=torch.ones_like(input_ids) | |
| ).logits | |
| model = Wrapped(args.model).eval() | |
| example = (torch.ones((1, args.length), dtype=torch.int32),) | |
| traced = torch.jit.trace(model, example, strict=False) | |
| mlmodel = ct.convert( | |
| traced, | |
| inputs=[ct.TensorType(name="input_ids", shape=(1, args.length), dtype=np.int32)], | |
| outputs=[ct.TensorType(name="logits")], | |
| minimum_deployment_target=ct.target.macOS15, | |
| ) | |
| mlmodel.short_description = ( | |
| f"{args.model}, masked-LM head, fixed sequence length {args.length}" | |
| ) | |
| out = f"{args.model}-{args.length}.mlpackage" | |
| mlmodel.save(out) | |
| print("wrote", out) | |