Text Classification
PEFT
Safetensors
Portuguese
support-automation
e-commerce
portuguese
ticket-routing
decision-model
multi-task
lora
multi-specialist
Eval Results (legacy)
Instructions to use syvorai/veredicto with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- PEFT
How to use syvorai/veredicto with PEFT:
Task type is invalid.
- Notebooks
- Google Colab
- Kaggle
File size: 8,875 Bytes
8249eac | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 | #!/usr/bin/env python3
"""Avalia checkpoint COMPLETO do Veredicto; T=1, sem calibrar no ouro.
python scripts/avaliar_veredicto.py --checkpoint RUN/checkpoint --base-path SNAPSHOT
Predicoes/logits nao incluem textos de chamados. O split oficial e mantido.
"""
import argparse
from collections import Counter, defaultdict
import hashlib
import json
import math
from pathlib import Path
import random
import sys
ROOT = Path(__file__).resolve().parents[1]
def chave_caso(estado):
return hashlib.md5(estado.encode("utf-8")).hexdigest()
def split_por_caso(exemplos, seed=42):
from veredicto_contrato import identificar_tarefa
estratos = defaultdict(list)
for row in exemplos:
if identificar_tarefa(row) == "categoria":
estratos[row["rotulo"]].append(chave_caso(row["estado"]))
todos = {chave_caso(row["estado"]) for row in exemplos}
com_cat = set().union(*map(set, estratos.values())) if estratos else set()
estratos["sem_categoria"] = sorted(todos - com_cat)
rng, calib, teste = random.Random(seed), set(), set()
for _, keys in sorted(estratos.items(), key=lambda kv: str(kv[0])):
keys = sorted(set(keys))
rng.shuffle(keys)
meio = len(keys) // 2
calib.update(keys[:meio]); teste.update(keys[meio:])
return calib, teste
def _validar(rows):
vistos = set()
if not rows:
raise ValueError("Nenhuma predicao para avaliar")
for row in rows:
key = (row["caso"], row["q"])
if key in vistos:
raise ValueError("Predicao caso/pergunta duplicada")
vistos.add(key)
probs, ops = row["probs"], row["option_ids"]
if len(ops) != len(probs) or not probs or len(set(ops)) != len(ops):
raise ValueError("Opcoes/probabilidades invalidas")
if any(not math.isfinite(x) or x < 0 for x in probs) or abs(sum(probs)-1) > 1e-5:
raise ValueError("Probabilidades invalidas")
if any(type(row[k]) is not int or not 0 <= row[k] < len(ops) for k in ("rotulo", "pred")):
raise ValueError("Indice de predicao/rotulo invalido")
if row["pred"] != max(range(len(probs)), key=probs.__getitem__):
raise ValueError("Predicao diverge do argmax")
def metricas(rows):
_validar(rows)
tarefas, subsets = defaultdict(list), defaultdict(list)
for row in rows:
tarefas[row["q"]].append(row)
for key in (f"{row.get('subset', 'nao_informado')}|{row['q']}",
f"{row.get('subset', 'nao_informado')}|todas"):
subsets[key].append(row)
def acc(group):
return sum(r["pred"] == r["rotulo"] for r in group) / len(group)
por_q = {}
for qid, group in tarefas.items():
bins = defaultdict(list)
for r in group:
confidence = max(r["probs"])
bins[min(14, max(0, math.ceil(confidence * 15) - 1))].append(r)
ece = sum(len(g) / len(group) * abs(sum(max(r["probs"]) for r in g) / len(g) - acc(g))
for g in bins.values())
nll = -sum(math.log(max(r["probs"][r["rotulo"]], 1e-12)) for r in group) / len(group)
brier = sum(sum((p - float(i == r["rotulo"]))**2 for i, p in enumerate(r["probs"]))
for r in group) / len(group)
por_q[qid] = {"n": len(group), "acc": acc(group), "ece": ece, "nll": nll, "brier": brier}
result = {"teste_n": len(rows), "casos": len({r["caso"] for r in rows}),
"acc_geral": acc(rows), "por_pergunta": por_q,
"acc_por_subset": {k: {"n": len(v), "acc": acc(v)} for k,v in subsets.items()},
"temperatura": 1.0, "calibracao_ajustada": False}
classes, conf = defaultdict(lambda: [0, 0, 0]), Counter()
for r in tarefas.get("categoria", []):
real, pred = r["option_ids"][r["rotulo"]], r["option_ids"][r["pred"]]
if real == pred:
classes[real][0] += 1
else:
classes[real][2] += 1; classes[pred][1] += 1
conf[(real, pred)] += 1
if classes:
f1 = {k: 2*v[0]/max(1, 2*v[0]+v[1]+v[2]) for k,v in classes.items()}
result["categoria_macro_f1"] = sum(f1.values())/len(f1)
result["categoria_f1_por_classe"] = f1
result["confusoes"] = [{"real": a, "predita": b, "n": n} for (a,b),n in conf.most_common()]
return result
def bootstrap_pareado(a, b, repeticoes=10000, seed=42):
_validar(a); _validar(b)
if repeticoes < 1:
raise ValueError("repeticoes deve ser positiva")
pa, pb = {(r["caso"],r["q"]): r for r in a}, {(r["caso"],r["q"]): r for r in b}
if set(pa) != set(pb):
raise ValueError("Pares caso/pergunta incompativeis")
grupos = defaultdict(list)
for key, ra in pa.items():
rb = pb[key]
if ra["option_ids"][ra["rotulo"]] != rb["option_ids"][rb["rotulo"]]:
raise ValueError("Rotulos de referencia divergentes")
grupos[key[0]].append(int(ra["pred"] == ra["rotulo"]) - int(rb["pred"] == rb["rotulo"]))
keys, rng, boot = sorted(grupos), random.Random(seed), []
for _ in range(repeticoes):
sample = [grupos[rng.choice(keys)] for _ in keys]
boot.append(sum(map(sum,sample))/sum(map(len,sample)))
boot.sort()
return {"delta": sum(map(sum,grupos.values()))/sum(map(len,grupos.values())),
"ic95": [boot[int(.025*(repeticoes-1))],boot[int(.975*(repeticoes-1))]],
"casos": len(keys), "repeticoes": repeticoes, "seed": seed}
def main():
ap = argparse.ArgumentParser(description=__doc__)
ap.add_argument("--checkpoint", required=True)
ap.add_argument("--base-path", required=True)
ap.add_argument("--gold", default=str(ROOT / "data/processed/ouro_gold.jsonl"))
ap.add_argument("--out", required=True)
ap.add_argument("--device", default="cuda")
ap.add_argument("--seed", type=int, default=42)
ap.add_argument("--comparar-preds")
args = ap.parse_args()
import torch
from veredicto_contrato import construir_caso, alinhar_perguntas, carregar_checkpoint, carregar_codigo_clef
out = Path(args.out); out.mkdir(parents=True, exist_ok=False)
examples = [json.loads(l) for l in Path(args.gold).open()]
_, test = split_por_caso(examples, args.seed)
groups = defaultdict(list)
for idx, row in enumerate(examples):
if chave_caso(row["estado"]) in test:
groups[chave_caso(row["estado"])].append((idx,row))
model, processor, meta = carregar_checkpoint(args.checkpoint,args.device,base_path=args.base_path)
# Loader verified this exact public source and revision before importing it.
clef = carregar_codigo_clef(args.base_path)
model.eval()
predictions = []
with torch.inference_mode():
for case_key, group in groups.items():
case = construir_caso([row for _,row in group], contexto=meta["contexto"])
enc = clef.encode_record(processor.tokenizer,case["record"],processor=processor,**case["contexto"])
batch = clef.collate_records([enc],processor.tokenizer.pad_token_id,torch.device(args.device))
logits = model(batch)[0]
aligned = alinhar_perguntas(case,enc.questions)
if len(logits) != len(aligned):
raise ValueError("Logits/perguntas divergentes")
by_q = {}
from veredicto_contrato import identificar_tarefa
for idx,row in group:
by_q[identificar_tarefa(row)] = (idx,row)
for (qenc,target,_),lg in zip(aligned,logits):
if len(qenc.option_ids) != lg.numel():
raise ValueError("Logits/opcoes divergentes")
idx,row = by_q[qenc.question_id]
probs = lg.float().softmax(-1).cpu().tolist()
predictions.append({"idx":idx,"caso":case_key,"q":qenc.question_id,
"subset":row.get("subset","nao_informado"),"option_ids":list(qenc.option_ids),
"rotulo":target,"pred":max(range(len(probs)),key=probs.__getitem__),
"probs":probs,"logits":lg.float().cpu().tolist()})
result = metricas(predictions)
result.update({"gold_sha256":hashlib.sha256(Path(args.gold).read_bytes()).hexdigest(),
"checkpoint":str(Path(args.checkpoint).resolve()),"manifesto_checkpoint":meta,"seed":args.seed})
if args.comparar_preds:
other = [json.loads(l) for l in Path(args.comparar_preds).open()]
result["comparacao_pareada"] = bootstrap_pareado(predictions,other,seed=args.seed)
(out/"preds.jsonl").write_text("".join(json.dumps(r,ensure_ascii=False)+"\n" for r in predictions))
(out/"relatorio.json").write_text(json.dumps(result,ensure_ascii=False,indent=2)+"\n")
print(json.dumps({"acc_geral":result["acc_geral"],"por_pergunta":result["por_pergunta"]},ensure_ascii=False))
if __name__ == "__main__":
main()
|