deepopen-banking77-sam13-v1 / verify_release.py
c41's picture
Release frozen model, inference and evaluation evidence
67b50ae verified
Raw History Blame Contribute Delete
4.94 kB
"""Check frozen predictions through the downloaded release; never select models."""
import argparse
import csv
import hashlib
import json
from pathlib import Path
import os
import sys
os.environ['USE_TF'] = '0'
os.environ['HF_HUB_OFFLINE'] = '1'
os.environ['TRANSFORMERS_OFFLINE'] = '1'
def compare(rows, gold, predictions, expected_correct):
assert len(rows) == len(gold) == len(predictions)
assert [int(r['artifact_row_index']) for r in rows] == list(range(len(rows)))
assert [r['gold_label'] for r in rows] == gold, 'Dataset row order or labels differ'
assert all(int(r['correct']) == int(r['gold_label'] == r['predicted_label']) for r in rows)
mismatches = sum(p != r['predicted_label'] for p, r in zip(predictions, rows))
correct = sum(p == y for p, y in zip(predictions, gold))
result = {'n': len(rows), 'correct': correct, 'accuracy_percent': correct / len(rows) * 100,
'prediction_mismatches': mismatches, 'expected_correct': expected_correct,
'passed': mismatches == 0 and correct == expected_correct,
'scope': 'Frozen retrospective reproduction; no tuning or model selection'}
return result
def main():
parser = argparse.ArgumentParser()
parser.add_argument('--package', required=True, choices=['banking_sam13', 'clinc_single', 'clinc_ensemble'])
parser.add_argument('--checkpoint', type=Path, required=True)
parser.add_argument('--data', type=Path, required=True)
parser.add_argument('--output', type=Path, required=True)
args = parser.parse_args()
folder = args.checkpoint.resolve()
sys.path.insert(0, str(folder))
rows = list(csv.DictReader((folder / 'evaluation/predictions.csv').open(encoding='utf-8-sig')))
if args.package == 'banking_sam13':
import torch
from transformers import AutoTokenizer, AutoModelForSequenceClassification, DataCollatorWithPadding
from torch.utils.data import DataLoader
torch._dynamo.config.disable = True
torch.set_num_threads(4)
data = [json.loads(line) for line in args.data.read_text().splitlines()]
gold = [r['label_text'] for r in data]
assert len(data) == 3080 and len(set(gold)) == 77
model = AutoModelForSequenceClassification.from_pretrained(folder, local_files_only=True,
attn_implementation='sdpa').cuda().eval()
tok = AutoTokenizer.from_pretrained(folder, local_files_only=True)
tokens = tok([r['text'] for r in data], truncation=True, max_length=128)
items = [{k: v[i] for k, v in tokens.items()} for i in range(len(data))]
predictions = []
with torch.inference_mode():
for batch in DataLoader(items, batch_size=32, collate_fn=DataCollatorWithPadding(tok)):
logits = model(**{k: v.cuda() for k, v in batch.items()}).logits.float()
assert torch.isfinite(logits).all()
predictions.extend(model.config.id2label[i] for i in logits.argmax(-1).tolist())
expected = 2899
else:
data = json.loads(args.data.read_text())['test']
gold = [y for _, y in data]
assert len(data) == 4500 and len(set(gold)) == 150
if args.package == 'clinc_single':
import torch
from safetensors.torch import load_file
from transformers import PreTrainedTokenizerFast
from torch.utils.data import DataLoader
from train_clinc import IntentModel, TextData, infer
expected = 4399
cfg = json.loads((folder / 'config.json').read_text())
assert json.loads((folder / 'inference_config.json').read_text())['variant'] == 'classifier_only'
tok = PreTrainedTokenizerFast.from_pretrained(folder / 'base/tokenizer', local_files_only=True)
model = IntentModel(str(folder / 'base'))
model.load_state_dict(load_file(str(folder / 'model.safetensors')), strict=True)
model.cuda().eval()
loader = DataLoader(TextData(data, cfg['labels'], tok, cfg['max_len']), batch_size=64)
logits, _, _ = infer(model, loader)
assert torch.isfinite(logits).all()
answers = [{'intent': cfg['labels'][i]} for i in logits.argmax(-1).tolist()]
else:
from infer_hybrid import predict
expected = 4411
answers = predict(str(folder), [t for t, _ in data])
predictions = [r['intent'] for r in answers]
result = compare(rows, gold, predictions, expected)
result['input_sha256'] = hashlib.sha256(args.data.read_bytes()).hexdigest()
args.output.write_text(json.dumps(result, indent=2) + '\n')
print(json.dumps(result), flush=True)
if not result['passed']:
raise SystemExit('Frozen predictions differ: publication stopped; do not tune on this test')
if __name__ == '__main__':
main()