Instructions to use hfvladkon/bert_token_classification_detector with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use hfvladkon/bert_token_classification_detector with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("token-classification", model="hfvladkon/bert_token_classification_detector")# pip install -U transformers accelerate # Load model directly from transformers import AutoTokenizer, AutoModelForTokenClassification tokenizer = AutoTokenizer.from_pretrained("hfvladkon/bert_token_classification_detector") model = AutoModelForTokenClassification.from_pretrained("hfvladkon/bert_token_classification_detector", device_map="auto") - Notebooks
- Google Colab
- Kaggle
File size: 5,132 Bytes
22ca93a | 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 | """Byte-level (ByT5) input for the same Qwen-token dataset.
Qwen3.8 uses byte-level BPE, so every Qwen token id maps to an exact byte string; the answer's
bytes are the concatenation of its tokens' bytes. ByT5 ids are byte + 3 (0 pad, 1 eos, 2 unk).
Labels move from tokens to bytes: a BAD token gives B on its first byte and I on the rest, TAIL
bytes are I, -100 stays -100 (grouped scheme: +2 for grammar classes, as for token models).
For evaluation byte probabilities are averaged back to Qwen tokens, so every metric is computed on
exactly the same Qwen tokens as for the ModernBERT / XLM-R taggers.
"""
from __future__ import annotations
import numpy as np
import torch
from transformers import AutoTokenizer
from modeling import _byte_decoder
PROMPT_BYTES = 200
SEP = "\n### ответ:\n".encode("utf-8")
class QwenBytes:
def __init__(self, qwen_tokenizer_dir: str):
qtok = AutoTokenizer.from_pretrained(qwen_tokenizer_dir, local_files_only=True)
dec = _byte_decoder()
# one get_vocab() call: per-id convert_ids_to_tokens is very slow in some transformers versions
inv = {i: s for s, i in qtok.get_vocab().items()}
self.tb = []
for i in range(248320):
s = inv.get(i)
if s is None or s.startswith("<|") or any(c not in dec for c in s):
self.tb.append(b"")
else:
self.tb.append(bytes(dec[c] for c in s))
def prompt(self, query: str) -> list[int]:
q = query.encode("utf-8")[:PROMPT_BYTES]
return [b + 3 for b in q + SEP]
def answer(self, token_ids, token_labels=None):
"""Returns byte ids, byte labels, and for each token its [start, end) in the byte sequence."""
ids, labs, spans = [], [], []
for k, t in enumerate(token_ids):
bs = self.tb[t]
s = len(ids)
ids.extend(b + 3 for b in bs)
if token_labels is not None:
l = token_labels[k]
if l < 0:
labs.extend([-100] * len(bs))
elif l == 0:
labs.extend([0] * len(bs))
elif l % 2 == 1: # BAD-like: B then I
labs.extend([l] + [l + 1] * (len(bs) - 1))
else:
labs.extend([l] * len(bs))
spans.append((s, len(ids)))
return ids, labs, spans
def byte_windows(n: int, a0: int, max_len: int, stride: int):
span = max_len - a0 - 1 # room for eos
starts, s = [], 0
while True:
starts.append(s)
if s + span >= n:
break
s += span - stride
return [(s, min(n, s + span)) for s in starts]
def expand_windows_bytes(qb: QwenBytes, rows, max_len, stride, synth_weight, labels_fn, include_synth=True,
include_corrected=True):
out = {"input_ids": [], "labels": [], "weight": []}
for r in rows:
v = r["variant"]
if (v.startswith("synthetic") and not include_synth) or (v == "corrected" and not include_corrected):
continue
a0 = r["answer_start"]
lab = labels_fn(r)
ids, blabs, _ = qb.answer(r["input_ids"][a0:], lab[a0:])
if not ids:
continue
p = qb.prompt(r["query"])
w = synth_weight if v.startswith("synthetic") else 1.0
for s, e in byte_windows(len(ids), len(p), max_len, stride):
out["input_ids"].append(p + ids[s:e] + [1])
out["labels"].append([-100] * len(p) + blabs[s:e] + [-100])
out["weight"].append(w)
return out
@torch.no_grad()
def predict_row_bytes(qb: QwenBytes, model, row, max_len, stride, device, batch=8):
a0 = row["answer_start"]
ids, _, spans = qb.answer(row["input_ids"][a0:])
C = model.config.num_labels
n_tok = len(spans)
if not ids:
return np.zeros((n_tok, C), dtype=np.float32)
p0 = qb.prompt(row["query"])
ws = byte_windows(len(ids), len(p0), max_len, stride)
probs = np.zeros((len(ids), C), dtype=np.float32)
best = np.full(len(ids), -1.0)
for b in range(0, len(ws), batch):
chunk = ws[b:b + batch]
seqs = [p0 + ids[s:e] + [1] for s, e in chunk]
L = max(len(x) for x in seqs)
x = torch.zeros((len(seqs), L), dtype=torch.long)
m = torch.zeros((len(seqs), L), dtype=torch.long)
for i, sq in enumerate(seqs):
x[i, :len(sq)] = torch.as_tensor(sq)
m[i, :len(sq)] = 1
logits = model(input_ids=x.to(device), attention_mask=m.to(device)).logits.float()
p = torch.softmax(logits, -1).cpu().numpy()
for i, (s, e) in enumerate(chunk):
pos = np.arange(s, e)
centr = np.minimum(pos - s, e - 1 - pos).astype(float)
upd = centr > best[pos]
probs[pos[upd]] = p[i, len(p0) + (pos[upd] - s)]
best[pos[upd]] = centr[upd]
out = np.zeros((n_tok, C), dtype=np.float32)
for k, (s, e) in enumerate(spans):
if e > s:
out[k] = probs[s:e].mean(0)
else:
out[k, 0] = 1.0 # special tokens have no bytes
return out
|