Toxicity-Lens / compare_with_perspective.py
prann-ab's picture
Toxicity-Lens v1.0
115e6b1 verified
Raw History Blame Contribute Delete
2.82 kB
"""Check Toxicity-Lens against Perspective scores you already logged, before you switch.
Input: a CSV or JSONL file with a `text` column and one column per Perspective attribute you logged, named TOXICITY, INSULT, ...
(or perspective_TOXICITY, ...). For each attribute it prints rank agreement and, at your threshold, how many of Perspective's
flags this model keeps, how many extra texts it flags, and the threshold that flags the same share of texts as Perspective did.
Run: python compare_with_perspective.py logged.csv [--model abacusai/Toxicity-Lens] [--backend onnx] [--threshold 0.7]
"""
import argparse
import csv
import json
import numpy as np
from server import ATTRS, Scorer
def rank(x):
r = np.empty(len(x))
r[np.argsort(x, kind="stable")] = np.arange(len(x))
return r
def main():
ap = argparse.ArgumentParser()
ap.add_argument("file")
ap.add_argument("--model", default="abacusai/Toxicity-Lens")
ap.add_argument("--backend", default="onnx", choices=["onnx", "torch"])
ap.add_argument("--threshold", type=float, default=0.5, help="the threshold you use with Perspective")
a = ap.parse_args()
with open(a.file, encoding="utf-8", newline="") as f:
rows = [json.loads(line) for line in f if line.strip()] if a.file.endswith(".jsonl") else list(csv.DictReader(f))
scorer = Scorer(a.model, a.backend)
ours = [s for i in range(0, len(rows), 256) for s, _ in scorer([str(r["text"]) for r in rows[i:i + 256]])]
t = a.threshold
print(f"{len(rows)} texts, threshold {t}\n{'attribute':<18}{'n':>7}{'spearman':>10}{'persp flags':>13}{'our flags':>11}"
f"{'kept':>8}{'extra':>8}{'same-rate threshold':>21}")
for attr in ATTRS:
col = next((c for c in (attr, f"perspective_{attr}", attr.lower(), f"perspective_{attr.lower()}") if c in rows[0]), None)
keep = [i for i, r in enumerate(rows) if col and r.get(col) not in (None, "")]
if len(keep) < 2:
continue
p = np.array([float(rows[i][col]) for i in keep])
o = np.array([ours[i][attr] for i in keep])
flag = p >= t
rho = np.corrcoef(rank(p), rank(o))[0, 1]
kept = f"{(o[flag] >= t).mean():.1%}" if flag.any() else "-"
extra = f"{(o[~flag] >= t).mean():.1%}" if (~flag).any() else "-"
same = f"{np.quantile(o, 1 - flag.mean()):.3f}" if 0 < flag.mean() < 1 else "-"
print(f"{attr:<18}{len(keep):>7}{rho:>10.3f}{flag.mean():>13.1%}{(o >= t).mean():>11.1%}{kept:>8}{extra:>8}{same:>21}")
print("\nkept = share of Perspective's flags this model also flags; extra = share of texts Perspective left below the threshold "
"that this model flags; same-rate threshold = the threshold at which this model flags as many texts as Perspective did.")
if __name__ == "__main__":
main()