How to use from the
Use from the
Transformers library
# Use a pipeline as a high-level helper
from transformers import pipeline

pipe = pipeline("text-classification", model="MaYiding/EventTwin")
# pip install -U transformers accelerate
# Load model directly
from transformers import AutoTokenizer, AutoModelForCausalLM

tokenizer = AutoTokenizer.from_pretrained("MaYiding/EventTwin")
model = AutoModelForCausalLM.from_pretrained("MaYiding/EventTwin", device_map="auto")
Quick Links

EventTwin v2.6 · 中文同事件判定器

TL;DR (EN) — EventTwin judges whether two Chinese event-mention frames refer to the same real-world event instance (cross-document event coreference for news clustering). v2.6 is a correction release. We found and fixed a training-loss bug present in every 4B version (v2.0–v2.5), re-labelled the benchmark with independent LLM annotators (gold v2), added a separate calibration set for thresholds, and audited the training data. On gold v2 (strict "same instance" labels, full-length input) v2.6 reaches AUROC 0.9966 (v2.5: 0.9824, v2.3: 0.9864). With the published three-way thresholds it auto-merges 94.7% of true pairs and escalates only 3.8% of the stratified hard set, at 1.06% false merges / 1.22% misses (v2.5 under the same protocol: 18.7% escalation, 1.46% / 1.63%). Several headline numbers reported for v2.5 were measurement artefacts and are retracted below. v2.6 changes the input protocol: full-length input, decisions on the logit difference ld, thresholds in eventtwin.json. Older versions remain available as tags. Data: EventTwin-Data v2.6.


这个模型做什么

输入两条中文事件提及(结构化框架文本:类型/阶段/主体/对象/动作/范围/时间 + [类型] + (时间) + 证据引文), 判断它们是否指同一次现实发生(口径 A:只有 SAME_INSTANCE 算同一事件;同一进程的不同阶段、整体与其中一项、 同一进程的先后里程碑都算不同事件)。输出 ld = logit(yes) − logit(no),按发布阈值三路路由:自动并 / 自动拒 / 升级终审。

⚠️ 输入协议(v2.6 变化,必读)

发布阈值只在下面这个协议下成立:

  1. 全长输入,不做字符截断(v2.0–v2.5 每侧截 200 字,会丢掉 57% 提及的证据引文;v2.6 训练与定阈都用全长);
  2. 模板 = Qwen3-Reranker 打分模板,system prompt 见下(yes/no 不加引号),左 padding,max_length=1152, add_special_tokens=False,取末位 yes/no 两个 logit 之差 ld;
  3. 判定看 ld 与 eventtwin.json 里的阈值;校准概率 p = sigmoid(ld / T),T = 0.5045(calibration.json)。
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer

tok = AutoTokenizer.from_pretrained("MaYiding/EventTwin"); tok.padding_side = "left"
model = AutoModelForCausalLM.from_pretrained("MaYiding/EventTwin", dtype=torch.bfloat16).cuda().eval()
SYSTEM = ("Judge whether the Document meets the requirements based on the Query. Only give me the judgment "
          "and do not output any other words or explanations. The judgment should be yes or no.")
TPL = ("<|im_start|>system\n{s}<|im_end|>\n<|im_start|>user\nQuery: {a}\nDocument: {b}\n"
       "Judgment: <|im_end|>\n<|im_start|>assistant\n")
YES, NO = tok("yes", add_special_tokens=False)["input_ids"][0], tok("no", add_special_tokens=False)["input_ids"][0]

@torch.no_grad()
def ld(a: str, b: str) -> float:
    inp = tok(TPL.format(s=SYSTEM, a=a, b=b), return_tensors="pt", truncation=True,
              max_length=1152, add_special_tokens=False).to("cuda")
    la = model(**inp).logits[0, -1].float()
    return float(la[YES] - la[NO])

def route(x: float, auto_merge=-0.28125, auto_reject=-1.8359375) -> str:   # eventtwin.json · default
    return "SAME" if x >= auto_merge else "DIFF" if x <= auto_reject else "ESCALATE"

批量推理、阈值档切换与概率换算:GitHub inference_v2_6.py。

决策阈值(eventtwin.json)

阈值在定阈集(与金标同一抽样器换种子的 1,000 对,独立代理标注)上按分位数定,在金标 v2(1,000 对)上测:

档 目标(定阈集) 自动并 ld ≥ 自动拒 ld ≤ 金标误并 [CP95] 金标漏并 升级率 真同事件自动并
default FM ≤1%、miss ≤1% −0.281(p 0.364) −1.836(p 0.026) 1.06%(8/755) [0.46, 2.08] 1.22%(3/245) 3.8% 94.7%
conservative FM ≤0.6%、miss ≤1% +0.422(p 0.698) −1.836(p 0.026) 0.79%(6/755)[0.29, 1.72] 1.22% 4.9% 91.0%
  • 默认档的 8 对误并:子事件 4、阶段变体 3、兄弟子事件 1——都是"相关但不是同一次"的结构关系,没有无关事件被并。
  • 金标与定阈集合并后做 300 次分层折半交叉验证(一半定阈、一半测):目标 1% 时测试 FM 1.03%、自动并 93.2%、升级率 3.9%。
  • 两套样本都是生产库分层抽样(难例占比远高于真实流),真实流的类先验不同:上线后请按簇抽检复核阈值; p 阈值只是同一点在 T 下的换算,看起来低(0.364)是因为 FM 按全部负例计、而阈值附近的对本来就难。

版本对比(同一评测协议)

金标 v2 · 口径 A · 全长输入 · 阈值都在定阈集上按 FM ≤1%、miss ≤1% 定(各版本自己的分数):

v2.3(v26) v2.5(v32) v2.6
AUROC 口径 A(只 SAME_INSTANCE 算同一) 0.9864 0.9824 0.9966
AUROC 口径 B(阶段变体也算同一) 0.9945 0.9916 0.9968
金标误并 / 漏并 0.79% / 0.41% 1.46% / 1.63% 1.06% / 1.22%
升级率 19.4% 18.7% 3.8%
真同事件自动并 43.7% 44.9% 94.7%
ECE(T 在定阈集上拟合) 0.297 0.037 0.011

v2.6 − v2.5 = **+0.0143 [+0.0079, +0.0216]**,v2.6 − v2.3 = +0.0103 [+0.0047, +0.0167](配对分层 bootstrap)。 v2.3/v2.5 的训练集与金标/定阈集有 37–39% 的对逐字重叠,它们的数字只会偏乐观;v2.6 的训练集已去掉这些行, 且代理改标从不施加于触及任何评测提及的行(见下文"X 协议")。

撤回与更正(v2.5 及更早的发布说明)

  1. 训练损失有缺陷(v2.0–v2.5 全部受影响):decoder 分支把 log σ(ld) 当 logit 再过一次 BCE(双重 sigmoid), 正例目标不可达、正侧饱和、负侧被钉在不动点。v2.6 用 --loss ce(BCEWithLogits(ld, y),与推理同一函数)。
  2. "v2.5 AUROC/pos 家族纪录""误并最低""ECE 最佳"撤回:它们来自 float32 饱和造成的大量并列分数、 v1 教师标签(不确定带错 28%)、以及 200 字截断。换成金标 v2 + ld 排序 + 全长输入后,v2.5 相对 v2.3 显著退步。
  3. v1 benchmark 的标签不再作为主金标:改用金标 v2(Opus + Sonnet 双盲 + 仲裁,九类关系,κ 0.94)。 注意这是独立 LLM 代理标注,不是人工金标。

v2.6 训练方法

  • 基座:Qwen/Qwen3-Reranker-4B,decoder 式 yes/no 打分; LoRA r=32 / α=64(q/k/v)、R-Drop 2.0、EMA、标签平滑 0.05、软标签裁剪 [0.05, 0.95]、lr 1e-4、1 epoch、max_len 768; 损失 = ce(修复后的 BCEWithLogits(ld, y))。
  • 数据(63,563 个训练样本,EventTwin-Data v2.6): v2.5 的短句对换成补全证据 / [类型] / ISO 时间的部署格式框架;删去与评测对逐字相同的 761 行; 1,465 行教师标签被代理定稿替换(四轮:教师不确定带、置信学习、阶段字段定向复核、折外置信学习;Opus + Sonnet 双盲, 分歧交 GLM 第三票);其中真实数据通道、两侧"阶段"字段不同的 426 行对比样本复制为 4 份。
  • X 协议:代理定稿只施加于两侧提及都不在任何评测对中的训练行——模型从未在评测提及上见过代理标签, 改标收益只能来自泛化,不能来自记忆。
  • 权重平均(model soup):同配方两种子(20261012 / 20261013)各自合并 LoRA 后逐参数平均,发布的是平均后的完整权重。 三个种子相对同种子的对照配方(不含后两轮定稿与阶段加权)AUROC 都显著更高(+0.0014 / +0.0018 / +0.0018); 三种子 soup 与两种子 soup 无差别;复制份数 ×2 / ×4 / ×8 中 ×4 的阈值迁移最稳。
  • 温度:T = 0.5045,在定阈集上最小化 NLL 拟合;金标 ECE 0.0106(T=1 时 0.0886)。

评测与可信度

  • 金标 v2:1,000 对分层样本(簇内 210 / 转载 90 / 同类型负 200 / 跨类型负 200 / 灰带 300); 需要复核的 345 对由 Opus + Sonnet 拆问式双盲 + Opus 仲裁,其余置信带对沿用教师标签(抽检 0/100 分歧)。
  • 定阈集:同一抽样器换种子的 1,000 对,Opus + Sonnet 双盲 + GLM 第三票(口径 A κ 0.965),只用于定阈与拟合温度。
  • 真实决策回放(独立的回放实验,2026-10-01 库快照,763 条有候选的生产决策、27,702 对):自动并 93.8%、升级 5.2%; 545 对裁决中,与现网决策一致的自动并对口径 A 假并 2.1%(口径 B 0%)。回放对有 61% 出现在训练集中,仅作参考。
  • 统计口径:配对分层 bootstrap;工作点比较一律两种子以上或 soup——单种子的阈值与"显著"都不可靠。

局限(如实)

  • 金标与定阈集都是 LLM 代理标注,不是人工金标;代理之间可能共享先验。
  • 剩余误并集中在子事件与阶段变体(同一进程的不同阶段、整体公告与其中一项)。若下游把阶段变体视为同一事件(口径 B), 同阈值下误并约 0.7%。
  • "阶段字段不同"这一加权规则是在评测集上发现的,评测收益可能偏乐观;上线前请在真实流上按簇抽检。
  • 输入是事件抽取器产出的框架文本;长文原文、其他语言、非企业新闻域未验证。4B 权重 8 GB,需要 GPU。

选型

  • v2.6(main):默认之选。
  • v2.5 / v2.4 / v2.3 / v2.2 / v2.1 / v2.0 / v1.x:tag 保留用于复现;它们的发布阈值基于 v1 标签与 200 字截断协议, 不建议新接入。

版本说明

公开版本与内部代号解耦:v1.0 = v8 / v1.1 = v9 / v1.2 = v10a / v2.0 = v15_4b / v2.1 = v23b / v2.2 = v24b / v2.3 = v26 / v2.4 = v29 / v2.5 = v32 / v2.6 = rcsx_soup(ab_loss_rcsx_s12 + ab_loss_rcsx_s13)。注意 v2.6 ≠ 内部 v26。

引用

@misc{eventtwin-2026,
  title  = {EventTwin: A Calibrated Chinese Cross-Encoder Family for Same-Event Judgment},
  author = {Ma, Yiding},
  year   = {2026},
  url    = {https://huggingface.co/MaYiding/EventTwin},
  note   = {v2.6: loss fix, LLM-annotated gold v2, calibration-set thresholds, stage-contrast reweighting, 2-seed soup}
}

许可

Apache 2.0(基座 Qwen3-Reranker-4B 为 Apache 2.0)。训练与评测数据见 EventTwin-Data(CC BY-NC 4.0,含新闻摘录)。

Downloads last month
155
Safetensors
Model size
4B params
Tensor type
BF16
·
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support

Model tree for MaYiding/EventTwin

Finetuned
(12)
this model
Quantizations
1 model