Instructions to use SlayerLab/NERGAL with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use SlayerLab/NERGAL with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("token-classification", model="SlayerLab/NERGAL")# pip install -U transformers accelerate # Load model directly from transformers import AutoTokenizer, AutoModelForTokenClassification tokenizer = AutoTokenizer.from_pretrained("SlayerLab/NERGAL") model = AutoModelForTokenClassification.from_pretrained("SlayerLab/NERGAL", device_map="auto") - Notebooks
- Google Colab
- Kaggle
File size: 4,482 Bytes
be6377b | 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 | """FastPDN-PII FP32 ONNX -> model.safetensors for BertForTokenClassification (plan Task 4a Step 2, Review Gate 14 A).
Named initializers keep their torch names. Each linear weight is the MatMul input that feeds the Add or BiasGelu taking
its named bias, transposed from ONNX's [in, out] to torch's [out, in]. Every weight is used once, the state dict loads
strictly, and no unused float tensor is left in the graph; anything else stops. Weights are copied, never changed.
Usage: python convert.py # writes model.safetensors and convert.json here; create-only
"""
from pathlib import Path
import hashlib, json
import numpy as np
from onnx import numpy_helper
HERE = Path(__file__).resolve().parent
REPO, REVISION = 'ArkadiuszPawlak/fastpdn-ner-polish-pii', '636c57fe77b0afad8f065e7c76243dc051437035'
SNAPSHOT = Path.home()/'.cache/huggingface/hub/models--ArkadiuszPawlak--fastpdn-ner-polish-pii/snapshots'/REVISION
ONNX_SHA256 = '11924bfd20eb478ee614e5e1184536825db4747753d341af7c04b940efa84645' # model.onnx, LFS pin at REVISION
CONFIG_SHA256 = '3cef51cd7d184478adbdec9f68730db279386fe145cb32473a0622edea923578'
NAMED = ('bert.', 'classifier.')
BUFFERS = ('bert.embeddings.position_ids',) # non-persistent in transformers: checked, not saved
def sha(path):
h = hashlib.sha256()
with open(path, 'rb') as f:
for block in iter(lambda: f.read(1 << 20), b''):
h.update(block)
return h.hexdigest()
def weights(graph):
"""({torch name: array}, used initializer names)."""
init = {i.name: numpy_helper.to_array(i) for i in graph.initializer}
producer = {o: n for n in graph.node for o in n.output}
state = {k: v for k, v in init.items() if k.startswith(NAMED)}
used = set(state)
for n in graph.node:
bias = [x for x in n.input if x.endswith('.bias') and 'LayerNorm' not in x and x in init]
if n.op_type not in ('Add', 'BiasGelu') or not bias:
continue
(b,), (other,) = bias, [x for x in n.input if x not in bias]
matmul = producer.get(other)
assert matmul is not None and matmul.op_type == 'MatMul' and matmul.input[1] in init, b
w, key = matmul.input[1], b[:-len('bias')] + 'weight'
assert w not in used and key not in state, (w, key)
state[key] = init[w].T.copy()
used.add(w)
return state, used
def leftovers(init, used):
"""Unused float tensors with more than one value: a weight the mapping missed. Scalars and int shapes pass."""
return sorted(k for k, v in init.items() if k not in used and np.asarray(v).dtype.kind == 'f' and np.size(v) > 1)
def main():
import onnx, torch
from safetensors.torch import save_file
from transformers import BertConfig, BertForTokenClassification
out = HERE/'model.safetensors'
assert not out.exists(), 'create-only'
assert sha(SNAPSHOT/'model.onnx') == ONNX_SHA256 and sha(SNAPSHOT/'config.json') == CONFIG_SHA256
graph = onnx.load(SNAPSHOT/'model.onnx').graph
init = {i.name: numpy_helper.to_array(i) for i in graph.initializer}
state, used = weights(graph)
left = leftovers(init, used)
assert not left, f'{len(left)} unused float tensors'
for k in BUFFERS:
v = state.pop(k)
assert np.array_equal(v, np.arange(v.shape[-1]).reshape(v.shape)), k
tensors = {k: torch.from_numpy(np.ascontiguousarray(v)) for k, v in sorted(state.items())}
model = BertForTokenClassification(BertConfig.from_pretrained(SNAPSHOT))
expected = model.state_dict()
assert {k: tuple(v.shape) for k, v in tensors.items()} == {k: tuple(v.shape) for k, v in expected.items()}, 'keys/shapes'
assert all(t.dtype == torch.float32 for t in tensors.values())
model.load_state_dict(tensors, strict=True)
save_file(tensors, out, metadata=dict(source=f'{REPO}@{REVISION}/model.onnx', onnx_sha256=ONNX_SHA256,
note='converted from ONNX, weights unchanged'))
report = dict(repo=REPO, revision=REVISION, onnx_sha256=ONNX_SHA256, config_sha256=CONFIG_SHA256,
initializers=len(init), used=len(used), tensors=len(tensors),
transposed=len(used) - sum(k.startswith(NAMED) for k in used),
unused_constants=len(init) - len(used), safetensors_sha256=sha(out), convert_sha256=sha(__file__))
(HERE/'convert.json').write_text(json.dumps(report, indent=1) + '\n')
return report
if __name__ == '__main__':
print(json.dumps(main()))
|