Stoicheia-code / tests /test_insc_eval_whole.py
Ericu950's picture
Stoicheia: training and evaluation code
5952424 verified
Raw
History Blame Contribute Delete
3.3 kB
"""eval_span_whole: the realistic restoration task ('fill in a blank in an inscription/papyrus
AS EDITED, real lacunae intact elsewhere in the same document') must never place its scored
synthetic gap on top of a real lacuna, and must run cleanly end to end."""
import sys
from pathlib import Path
import numpy as np
import torch
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "insc" / "eval"))
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "insc" / "data"))
from model.char_bert import CharBertConfig, CharBertEncoder
import restore
def _tiny_model():
torch.manual_seed(0)
cfg = CharBertConfig(attn_impl="sdpa", d_model=32, n_heads=4, depth=1, char_window=0)
m = CharBertEncoder(cfg)
m.eval()
return m
def _fake_records_with_lacuna(n, L, seed=0):
rng = np.random.default_rng(seed)
recs = []
for i in range(n):
chars = rng.integers(0, 24, L).astype(np.int64)
boundary = np.zeros(L, np.int64); boundary[4::5] = 1; boundary[-1] = 2
is_real_lacuna = np.zeros(L, dtype=bool)
lac_s = int(rng.integers(10, L - 15))
lac_len = 5
chars[lac_s:lac_s + lac_len] = 24
boundary[lac_s:lac_s + lac_len] = 3
is_real_lacuna[lac_s:lac_s + lac_len] = True
recs.append(dict(chars=chars, boundary=boundary, is_real_lacuna=is_real_lacuna,
region_id=3, century_id=5, _lac=(lac_s, lac_s + lac_len)))
return recs
def test_eval_span_whole_runs_end_to_end():
model = _tiny_model()
recs = _fake_records_with_lacuna(5, 100)
r = restore.eval_span_whole(model, recs, L=3, device=torch.device("cpu"), n=5, beam_width=4)
assert r["n"] > 0
assert 0 <= r["top1"] <= 1 and 0 <= r["top20"] <= 1
def test_eval_span_whole_never_overlaps_real_lacuna():
model = _tiny_model()
recs = _fake_records_with_lacuna(30, 60, seed=1)
seen_gaps = []
orig = restore.beam_restore
def spy(model, chars, gap, bnd_row, device, *args, **kwargs):
seen_gaps.append(list(gap))
return orig(model, chars, gap, bnd_row, device, *args, **kwargs)
restore.beam_restore = spy
try:
r = restore.eval_span_whole(model, recs, L=2, device=torch.device("cpu"), n=30,
beam_width=2)
finally:
restore.beam_restore = orig
assert r["n"] > 0
assert len(seen_gaps) == r["n"]
for gap, rec in zip(seen_gaps, recs):
lac_s, lac_e = rec["_lac"]
assert not any(lac_s <= p < lac_e for p in gap), \
f"synthetic gap {gap} overlaps real lacuna [{lac_s},{lac_e})"
def test_eval_span_whole_skips_records_with_no_valid_position():
"""A record entirely consumed by real lacunae (or too short) has no valid place for the
synthetic gap -- must be skipped, not crash."""
model = _tiny_model()
L = 20
chars = np.zeros(L, np.int64) + 24 # all MASK
boundary = np.full(L, 3, np.int64)
is_real_lacuna = np.ones(L, dtype=bool)
recs = [dict(chars=chars, boundary=boundary, is_real_lacuna=is_real_lacuna,
region_id=3, century_id=5)]
r = restore.eval_span_whole(model, recs, L=3, device=torch.device("cpu"), n=5, beam_width=2)
assert r["n"] == 0