glossary-classifier

English summary. A Chinese sentence-pair classifier that scores glossary candidates extracted from Chinese web novels. Given (term, context) it returns the probability that the term deserves its own glossary entry (a proper name or a story-specific term such as a sect, technique, realm or artifact) rather than being a common word or a broken fragment of a longer term. Fine-tuned from hfl/chinese-roberta-wwm-ext, shipped as ONNX fp32 for CPU inference. Built for novel2epub (a Chinese web-novel to EPUB translation tool), where it powers the "AI score" column on the glossary-candidate review page. ROC-AUC 0.985 on an 800-item gold set from 3 held-out novels.


Bộ phân loại cặp câu tiếng Trung, chấm điểm ứng viên glossary do bộ trích thuật ngữ lấy ra từ truyện mạng Trung Quốc. Với đầu vào (thuật ngữ, ngữ cảnh), model trả về xác suất thuật ngữ đáng có mục glossary riêng:

Nhãn Nghĩa Ví dụ
giữ (keep, chỉ số 1) Tên riêng hoặc thuật ngữ riêng của truyện: nhân vật, địa danh, tông môn, công pháp, cảnh giới, pháp bảo, danh hiệu… 青云宗, 萧炎, 筑基
bỏ (chỉ số 0) Từ thường (common) hoặc mảnh cắt dở của một thuật ngữ dài hơn (fragment) 道理, 占据, 北方, 云宗

Model chỉ dùng để sắp xếp và lọc cho người duyệt, không tự quyết định Nhận/Bỏ.

Nội dung repo

Đường dẫn Mô tả
model.onnx Model ONNX fp32 (~409 MB), đầu ra logits [batch, 2]
tokenizer.json Tokenizer (thư viện tokenizers), WordPiece của chinese-roberta-wwm-ext
meta.json Thông số suy luận (max_len, keep_index) và chỉ số đánh giá
checkpoint/ Bản Hugging Face Transformers (model.safetensors, config.json, tokenizer, report.json) để train tiếp hoặc xuất lại ONNX

Cách dùng

Đầu vào / đầu ra

  • Câu 1: thuật ngữ, ví dụ 青云宗.
  • Câu 2: một đoạn văn quanh một lần xuất hiện của thuật ngữ trong truyện, khoảng 40 ký tự (dữ liệu train: trung bình 39, từ 22 đến 46). Ngắn hơn vẫn chạy được, nhưng ngữ cảnh rất ngắn hoặc trống làm model kém chính xác.
  • Mã hoá dạng cặp câu ([CLS] term [SEP] context [SEP]), token_type_ids = 1 cho câu 2, tối đa 128 token, chỉ cắt phần ngữ cảnh (only_second).
  • Đầu ra logits 2 lớp. Lấy softmax rồi đọc cột keep_index (= 1).

Python (onnxruntime + tokenizers, không cần torch)

pip install onnxruntime tokenizers numpy huggingface_hub
hf download yukihuy99yuki/glossary-classifier --include "model.onnx" "tokenizer.json" "meta.json" --local-dir glossary-classifier
import json
import numpy as np
import onnxruntime as ort
from tokenizers import Tokenizer

d = "glossary-classifier"
meta = json.load(open(f"{d}/meta.json", encoding="utf-8"))
tok = Tokenizer.from_file(f"{d}/tokenizer.json")
tok.enable_truncation(max_length=meta["max_len"], strategy="only_second")
tok.enable_padding()
sess = ort.InferenceSession(f"{d}/model.onnx", providers=["CPUExecutionProvider"])
names = {i.name for i in sess.get_inputs()}

def score(pairs):
    """pairs: [(term, context), ...] -> xác suất 'giữ' cho từng cặp."""
    enc = tok.encode_batch(pairs)
    feed = {
        "input_ids": np.array([e.ids for e in enc], dtype=np.int64),
        "attention_mask": np.array([e.attention_mask for e in enc], dtype=np.int64),
        "token_type_ids": np.array([e.type_ids for e in enc], dtype=np.int64),
    }
    logits = sess.run(["logits"], {k: v for k, v in feed.items() if k in names})[0]
    p = np.exp(logits - logits.max(axis=1, keepdims=True))
    return (p / p.sum(axis=1, keepdims=True))[:, meta["keep_index"]]

print(score([
    ("青云宗", "他拜入青云宗,成为外门弟子。"),
    ("道理", "你说的很有道理。"),
]))  # điểm cao cho 青云宗, thấp cho 道理

Nên chấm theo lô (32–64 cặp). Trên CPU, chỉ dùng 4 luồng, tốc độ khoảng 25 cặp/giây và cần khoảng 400 MB RAM.

Transformers (PyTorch, từ checkpoint/)

import torch
from transformers import AutoModelForSequenceClassification, AutoTokenizer

repo = "yukihuy99yuki/glossary-classifier"
tok = AutoTokenizer.from_pretrained(repo, subfolder="checkpoint")
model = AutoModelForSequenceClassification.from_pretrained(repo, subfolder="checkpoint").eval()

terms = ["青云宗", "道理"]
contexts = ["他拜入青云宗,成为外门弟子。", "你说的很有道理。"]
batch = tok(terms, contexts, truncation="only_second", max_length=128, padding=True, return_tensors="pt")
with torch.no_grad():
    print(torch.softmax(model(**batch).logits, dim=-1)[:, 1])

Ngôn ngữ khác

model.onnx + tokenizer.json dùng được với mọi runtime ONNX: onnxruntime-node / onnxruntime-web (tokenizer qua @huggingface/transformers), C# Microsoft.ML.OnnxRuntime (+ Microsoft.ML.Tokenizers), Java, Rust (ort + tokenizers). Cần giữ đúng mã hoá cặp câu, token_type_ids và max_len như trên, nếu không điểm sẽ lệch.

Trong novel2epub

Đặt 3 file gốc vào models/glossary-classifier/ (hoặc trỏ env N2E_GLOSSARY_CLASSIFIER), cài onnxruntime tokenizers, khởi động app rồi bấm Chấm Điểm AI trên trang Thuật ngữ.

Chọn ngưỡng

Trên tập vàng (800 mục, 183 mục "giữ"):

Ngưỡng Precision (giữ) Recall (giữ) Tỉ lệ mục bị đánh dấu giữ
0.50 0.737 0.978 30.4%
0.70 0.765 0.978 29.2%
0.80 0.775 0.978 28.9%
0.90 0.805 0.967 27.5%
0.95 0.838 0.962 26.3%
  • Muốn không bỏ sót thuật ngữ thật: dùng 0.5 (recall 98%) rồi người duyệt loại phần dư.
  • Muốn ít nhầm hơn: dùng 0.9–0.95, chấp nhận sót khoảng 3–4%.
  • Điểm < 0.1 gần như chắc chắn là từ thường hoặc mảnh cắt, có thể bỏ hàng loạt sau khi xem lướt.

Đánh giá

Tập vàng: 800 ứng viên lấy từ 3 truyện không có trong dữ liệu train, gắn nhãn bằng Codex (OpenAI), tỉ lệ giữ/bỏ khoảng 23% / 77%.

Model ROC-AUC Accuracy F1 (giữ)
Điểm tin cậy của bộ trích thuật ngữ (mốc) 0.580 – –
Xếp theo tần suất xuất hiện (mốc) 0.61 – –
Fine-tune chỉ với nhãn suy từ glossary 0.973 0.877 0.786
Fine-tune chỉ với nhãn Codex 0.984 0.934 0.865
Bản này: nhãn gộp 0.985 0.915 0.840

Ma trận nhầm lẫn ở ngưỡng 0.5: TP 179 · FP 64 · FN 4 · TN 553.

Độ chính xác theo nhóm (nguồn nhãn suy từ glossary → nhãn Codex):

Nhóm Số mục Accuracy
Có trong glossary → giữ 169 0.98
Có trong glossary → từ thường 72 0.46
Mảnh cắt → mảnh cắt 243 0.98
Mảnh cắt → từ thường 69 0.81
Ngoài glossary → từ thường 149 0.99
Ngoài glossary → mảnh cắt 70 1.00

Nhóm yếu nhất là từ thường đã bị người dịch đưa vào glossary (vd. từ chung nhưng được dịch cố định): model thường vẫn cho điểm cao, vì phần lớn nhãn train coi "có trong glossary" là "giữ".

Bản ONNX fp32 khớp model PyTorch gốc (lệch xác suất tối đa 0.002). Các bản lượng tử int8 đã thử đều lệch nhiều (AUC 0.975 và 0.44), nên không phát hành.

Dữ liệu train

  • Nguồn: 17 truyện mạng tiếng Trung (chủ yếu tiên hiệp, huyền huyễn, đô thị dị năng), tối đa 300 chương mỗi truyện. Ứng viên lấy bằng bộ trích thuật ngữ của novel2epub (n-gram + thống kê, tần suất ≥ 3).
  • Nhãn yếu (13.438 mục): suy từ glossary người dịch đã duyệt của từng truyện. Mục có trong glossary là "giữ"; mảnh cắt của mục glossary và từ lặp nhiều (≥ 8 lần) không vào glossary là "bỏ".
  • Nhãn Codex (~7.000 mục): Codex CLI (OpenAI) gắn nhãn keep / common / fragment kèm độ tin cậy, dựa trên thuật ngữ và ngữ cảnh. Một phần chọn theo active learning (mục model đang phân vân, điểm gần 0.5).
  • Gộp: mỗi mục lấy nhãn theo thứ tự ưu tiên người duyệt > Codex > nhãn suy từ glossary. Tổng 13.918 mục.
  • Chia train/test theo truyện: 3 truyện test không xuất hiện trong train.

Dữ liệu train không được phát hành, vì nó chứa trích đoạn từ các truyện có bản quyền.

Huấn luyện

Tham số Giá trị
Model gốc hfl/chinese-roberta-wwm-ext (102M tham số)
Đầu AutoModelForSequenceClassification, 2 lớp, cross-entropy
Epoch 3
Learning rate 3e-5, AdamW (weight decay 0.01), linear warmup 6%
Batch 32, max 128 token, fp16
Seed 13
Phần cứng RTX 3050 4 GB, ~12 phút

Xuất ONNX bằng torch.onnx.export (opset mặc định), giữ fp32.

Hạn chế

  • Chỉ train trên truyện mạng tiếng Trung giản thể, thiên về tiên hiệp/huyền huyễn. Với thể loại khác (ngôn tình, lịch sử, khoa học viễn tưởng) hay văn bản phồn thể thì nên kiểm tra lại trước khi dùng.
  • Điểm phụ thuộc vào ngữ cảnh: cùng một từ có thể được điểm khác nhau ở các đoạn khác nhau.
  • Nhãn chủ yếu do LLM gắn, nên có thể mang thiên lệch của LLM về ranh giới giữa "thuật ngữ riêng" và "từ chung".
  • Không nhận diện được thực thể chưa từng được bộ trích đưa ra làm ứng viên. Đây là bộ xếp hạng ứng viên, không phải bộ NER.

Giấy phép và ghi công

  • Trọng số: Apache-2.0, kế thừa từ hfl/chinese-roberta-wwm-ext.
  • Model gốc: Cui et al., Pre-Training with Whole Word Masking for Chinese BERT (2019/2021).
@article{cui-etal-2021-pretrain,
  title   = {Pre-Training with Whole Word Masking for Chinese BERT},
  author  = {Cui, Yiming and Che, Wanxiang and Liu, Ting and Qin, Bing and Yang, Ziqing},
  journal = {IEEE/ACM Transactions on Audio, Speech, and Language Processing},
  year    = {2021},
  volume  = {29},
  pages   = {3504--3514}
}
Downloads last month

-

Downloads are not tracked for this model. How to track
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support

Model tree for yukihuy99yuki/glossary-classifier

Quantized
(3)
this model

Evaluation results

  • roc_auc on Codex-labelled gold set (800 candidates, 3 held-out novels)
    self-reported
    0.985
  • f1 on Codex-labelled gold set (800 candidates, 3 held-out novels)
    self-reported
    0.840
  • precision on Codex-labelled gold set (800 candidates, 3 held-out novels)
    self-reported
    0.737
  • recall on Codex-labelled gold set (800 candidates, 3 held-out novels)
    self-reported
    0.978
  • accuracy on Codex-labelled gold set (800 candidates, 3 held-out novels)
    self-reported
    0.915