guiwf's picture
Re-export: bake softmax/sigmoid into the graph (4 named probability outputs); external-data weights + export manifest
31188dc verified
|
Raw
History Blame Contribute Delete
5.29 kB
---
license: mit
library_name: onnx
tags:
- alignscore
- onnx
- text-classification
- natural-language-inference
- roberta
base_model: yzha/AlignScore
pipeline_tag: text-classification
---
# AlignScore-large (ONNX)
An ONNX export of [**AlignScore-large**](https://huggingface.co/yzha/AlignScore)
(RoBERTa-large with AlignScore's 3-way and regression heads), for in-process
inference without a Python/PyTorch runtime.
## Why this exists
Upstream AlignScore ships only PyTorch Lightning checkpoints built from a custom
`BERTAlignModel` module - no `config.json`, no `safetensors` - so
`optimum-cli export onnx` cannot consume it, and no ONNX build existed. This is
that build, so anyone who wants to experiment with AlignScore-large can, without
standing up a PyTorch runtime or writing a custom export pathway.
It reflects a Familiar Tools belief: a specialized, right-sized model that runs
efficiently and in-process beats reaching for a large, general, resource-hungry
one. Exporting a focused model to ONNX is part of that - it makes the model
cheap to run, easy to embed, and light on dependencies. Custom, deliberately
engineered solutions tend to be more efficient and more resource-aware than
general-purpose defaults.
## What this is
A faithful ONNX export of the encoder + pooler + the two alignment-scoring heads,
with the output activations **baked into the graph** so the model emits the four
probabilities directly:
- a RoBERTa-large encoder with pooling layer (`pooler_output = tanh(dense(h[:,0]))`)
- `tri_layer`: `Linear(hidden, 3)` -> `softmax` -> 3-way probabilities
- `reg_layer`: `Linear(hidden, 1)` -> `sigmoid` -> alignment probability
This is the key difference from the earlier revision of this repo, which emitted
raw `tri_logits` / `reg_logit` and left `softmax`/`sigmoid` to the caller. Baking
the activations in makes the graph self-contained: a single direction scores a
`(context, claim)` pair straight to probabilities, no post-processing.
### Graph I/O
| Tensor | Direction | Type | Shape |
|--------|-----------|------|-------|
| `input_ids` | input | int64 | `[batch, seq]` (dynamic) |
| `attention_mask` | input | int64 | `[batch, seq]` (dynamic) |
| `p_aligned_3way` | output | float32 | `[batch]` (softmax over tri head, aligned) |
| `p_neutral_3way` | output | float32 | `[batch]` (softmax over tri head, neutral) |
| `p_contradict_3way` | output | float32 | `[batch]` (softmax over tri head, contradict) |
| `p_aligned_reg` | output | float32 | `[batch]` (sigmoid over reg head) |
There is no `token_type_ids` input: a sentence pair is encoded into a single
`input_ids` sequence with `</s></s>` separators, exactly as
`AutoTokenizer("roberta-large")(context, claim)` produces. The bundled
`tokenizer.json` is the matching fast tokenizer. Use `max_length=512`.
Opset 17. Weights are stored as ONNX external data in `alignscore-large.onnx.data`
(the `.onnx` is the graph; keep the two files side by side). The
`alignscore-export-manifest.json` records the source checkpoint SHA-256, the
upstream HF revision, the opset, and the exact input/output tensor names.
## Files
- `alignscore-large.onnx` - the model graph (~0.2 MB)
- `alignscore-large.onnx.data` - external weights (~1.4 GB); must sit next to the `.onnx`
- `alignscore-export-manifest.json` - checkpoint SHA-256, HF revision, opset, I/O names
- `tokenizer.json` - roberta-large fast tokenizer with the pair post-processor
## Parity
Verified against the original PyTorch model's scores on a 136-pair corpus:
**max absolute difference 5e-06** on `p_contradict_3way` and **0** on
`p_aligned_reg`, across both directions, with **zero** verdict flips through a
downstream 0.75 bidirectional contradiction gate. The source checkpoint SHA-256
is asserted equal to the reference before export, so these are provably the same
weights.
## Usage (ONNX Runtime, Python)
```python
import numpy as np, onnxruntime as ort
from tokenizers import Tokenizer
tok = Tokenizer.from_file("tokenizer.json")
sess = ort.InferenceSession("alignscore-large.onnx") # loads .onnx.data automatically
def score(context, claim):
enc = tok.encode(context, claim)
ids = np.array([enc.ids], dtype=np.int64)
mask = np.array([enc.attention_mask], dtype=np.int64)
pa, pn, pc, pr = sess.run(
["p_aligned_3way", "p_neutral_3way", "p_contradict_3way", "p_aligned_reg"],
{"input_ids": ids, "attention_mask": mask},
)
return {
"p_aligned_3way": float(pa[0]),
"p_neutral_3way": float(pn[0]),
"p_contradict_3way": float(pc[0]),
"p_aligned_reg": float(pr[0]),
}
```
## License and attribution
Released under the **MIT License**, matching upstream.
- AlignScore: Zha et al., *AlignScore: Evaluating Factual Consistency with a
Unified Alignment Function*, ACL 2023
([arXiv:2305.16739](https://arxiv.org/abs/2305.16739),
[code](https://github.com/yuh-zha/AlignScore)).
- Original weights: [`yzha/AlignScore`](https://huggingface.co/yzha/AlignScore)
(revision `8509e78d25bb914939fc585c626500c9b2944249`).
- Base encoder: RoBERTa-large (Liu et al., 2019).
This repo redistributes a derivative (ONNX export) of the above under the same
MIT terms. No weights were retrained or modified; only the inference graph was
re-expressed.