File size: 6,529 Bytes
b28b22c
 
 
 
eb887dd
b28b22c
 
 
 
 
 
 
 
 
 
 
eb887dd
 
 
 
b84238f
 
 
 
 
eb887dd
b28b22c
b84238f
 
 
 
 
b28b22c
eb887dd
b28b22c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b84238f
 
 
eb887dd
b84238f
 
 
b28b22c
eb887dd
b28b22c
 
b84238f
 
 
 
 
 
b28b22c
eb887dd
b28b22c
 
 
b84238f
b28b22c
b84238f
b28b22c
eb887dd
b28b22c
 
9739570
b84238f
eb887dd
a1ef24f
 
9739570
a1ef24f
eb887dd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9739570
eb887dd
a1ef24f
 
 
9739570
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
---
license: mit
language:
- en
- ja
tags:
- mlx
- token-classification
- named-entity-recognition
- bert
base_model: dslim/bert-base-NER
pipeline_tag: token-classification
---

# bert-base-ner-mlx

[English](#model-summary) | [日本語](#モデルの概要)

## Model Summary

This is an unofficial [MLX](https://github.com/ml-explore/mlx) conversion of
[dslim/bert-base-NER](https://huggingface.co/dslim/bert-base-NER) (a standard
BERT-base with a named-entity-recognition head on top, trained on CoNLL-2003:
PER/ORG/LOC/MISC). All credit for the original model goes to its author.

### This cannot be loaded with mlx-embeddings

`mlx-embeddings` targets pooled embedding/reranker outputs and doesn't
support a per-token classification head. This model was **reimplemented from
scratch for MLX** and requires the bundled `bert_ner_mlx.py`. The
architecture itself is simple: a standard post-norm BERT encoder plus a
linear classification head.

### Usage

```python
import mlx.core as mx
from mlx.utils import tree_unflatten
from transformers import AutoTokenizer

from bert_ner_mlx import BertNerMLX

tokenizer = AutoTokenizer.from_pretrained("dslim/bert-base-NER")
model = BertNerMLX()
weights = mx.load("model.safetensors")
model.update(tree_unflatten(list(weights.items())))
mx.eval(model.parameters())

text = "My name is Wolfgang and I live in Berlin, working at Hugging Face."
inputs = tokenizer(text, return_tensors="np")
input_ids = mx.array(inputs["input_ids"])
attention_mask = mx.array(inputs["attention_mask"])

logits = model(input_ids, attention_mask=attention_mask)  # (1, seq_len, 9)
labels = logits.argmax(-1)[0].tolist()
tokens = tokenizer.convert_ids_to_tokens(inputs["input_ids"][0])
for tok, label_id in zip(tokens, labels):
    print(tok, model.config.id2label[label_id] if hasattr(model, "config") else label_id)
```

Labels are the same as the original model: `{0: "O", 1: "B-MISC", 2: "I-MISC",
3: "B-PER", 4: "I-PER", 5: "B-ORG", 6: "I-ORG", 7: "B-LOC", 8: "I-LOC"}`.

### Accuracy

Compared against the PyTorch fp32 reference on a real sentence containing
person/location/organization entities:

| Precision | Logits cosine sim. | Label agreement |
|---|---|---|
| MLX fp32 | 1.0 | 100% |
| MLX fp16 (this release) | 0.99999994 | 100% |

During fp16 conversion, using an attention-mask value like `-1e9` (which
doesn't fit in fp16) caused `0 * (-inf) = NaN` at unmasked (`mask=1`)
positions. Fixed by switching to `-1e4`, which fits fp16's range (full
details are in the conversion-toolkit repo, not `SECURITY.md`).

### Specs

| Item | Value |
|---|---|
| Base model | `dslim/bert-base-NER` (BERT-base, 108M params) |
| Precision | float16 |
| Framework | MLX (from-scratch `bert_ner_mlx.py`) |

### Notes

- This is a community conversion, not an official release from the original author.
- Security audit uses [model-audit-lite](https://github.com/masahiroid/model-audit-lite)
  (see `SECURITY.md` for details).

### Security

Audited against its upstream with [model-audit-lite](https://github.com/masahiroid/model-audit-lite): weight format, bundled code, and a machine-readable lineage (ML-BOM). Details, checksums and how to reproduce: [SECURITY.md](SECURITY.md).

---

## モデルの概要

[dslim/bert-base-NER](https://huggingface.co/dslim/bert-base-NER)(標準的なBERT-baseに
固有表現抽出ヘッドを乗せたモデル。CoNLL-2003、PER/ORG/LOC/MISCの4種)の
[MLX](https://github.com/ml-explore/mlx)版です。元モデルの著作権はその作者に帰属します。

### mlx-embeddingsでは読み込めません

`mlx-embeddings`はembedding/reranker用のpooling出力をターゲットにしており、トークン単位の
分類ヘッド(各トークンに対して独立にラベルを出す構成)には対応していないため、**MLXでの
実装をゼロから書き起こして**変換しています。同梱の`bert_ner_mlx.py`が必要です。構造自体は
標準的なpost-norm BERTエンコーダー + 線形分類ヘッドとシンプルです。

### 使い方

```python
import mlx.core as mx
from mlx.utils import tree_unflatten
from transformers import AutoTokenizer

from bert_ner_mlx import BertNerMLX

tokenizer = AutoTokenizer.from_pretrained("dslim/bert-base-NER")
model = BertNerMLX()
weights = mx.load("model.safetensors")
model.update(tree_unflatten(list(weights.items())))
mx.eval(model.parameters())

text = "My name is Wolfgang and I live in Berlin, working at Hugging Face."
inputs = tokenizer(text, return_tensors="np")
input_ids = mx.array(inputs["input_ids"])
attention_mask = mx.array(inputs["attention_mask"])

logits = model(input_ids, attention_mask=attention_mask)  # (1, seq_len, 9)
labels = logits.argmax(-1)[0].tolist()
tokens = tokenizer.convert_ids_to_tokens(inputs["input_ids"][0])
for tok, label_id in zip(tokens, labels):
    print(tok, model.config.id2label[label_id] if hasattr(model, "config") else label_id)
```

ラベルは元モデルと同じ: `{0: "O", 1: "B-MISC", 2: "I-MISC", 3: "B-PER", 4: "I-PER",
5: "B-ORG", 6: "I-ORG", 7: "B-LOC", 8: "I-LOC"}`。

### 精度検証

PyTorch fp32リファレンスと、実際の文章1件(人名・地名・組織名を含む)で比較:

| 精度 | Logitsコサイン類似度 | ラベル一致率 |
|---|---|---|
| MLX fp32 | 1.0 | 100% |
| MLX fp16(本リリース) | 0.99999994 | 100% |

fp16変換の際、attention maskのマスク値に`-1e9`のようなfp16で表現できない大きな負数を使うと、
マスクされていない(`mask=1`)位置で`0 * (-inf)`が発生してNaNになる罠があった。
fp16の範囲内に収まる`-1e4`に変更して解消している(詳細は`SECURITY.md`ではなく、変換ノウハウ
リポジトリに記載)。

### Specs

| Item | Value |
|---|---|
| ベースモデル | `dslim/bert-base-NER`(BERT-base、108M params) |
| 精度 | float16 |
| フレームワーク | MLX(ゼロから実装した`bert_ner_mlx.py`) |

### 備考

- 本変換は非公式のコミュニティ版です。
- セキュリティー監査には[model-audit-lite](https://github.com/masahiroid/model-audit-lite)を
  使用しています(詳細は`SECURITY.md`)。

### セキュリティー

[model-audit-lite](https://github.com/masahiroid/model-audit-lite) で変換元と突き合わせて監査済みです(重みの形式、同梱コード、機械可読な系譜=ML-BOM)。詳細・チェックサム・再現方法は [SECURITY.md](SECURITY.md) をご覧ください。