Views
No views yet
| file | what it is |
|---|---|
model.safetensors | the weights (fp32, 1.6 GB) |
config.json | encoder architecture |
meld_config.json | scoring head, thresholds |
tokenizer.json, tokenizer_config.json, special_tokens_map.json | tokenizer |
pip install torch transformers safetensorspipeline(),
AutoModelForSequenceClassification and AutoModel do not work here. They
load without an error, discard every weight in this repository, and return
numbers from a randomly initialised model.MODEL_DIR at it, and run:1import json
2
3import torch
4import torch.nn as nn
5from safetensors.torch import load_file
6from transformers import AutoConfig, AutoModel, AutoTokenizer
7
8MODEL_DIR = "meld" # the folder you downloaded this repo into
9
10
11class Meld(nn.Module):
12 def __init__(self, model_dir):
13 super().__init__()
14 self.cfg = json.load(open(f"{model_dir}/meld_config.json"))
15 r, H = self.cfg["style_rank"], self.cfg["backbone_hidden_size"]
16 self.backbone = AutoModel.from_config(
17 AutoConfig.from_pretrained(model_dir), attn_implementation="sdpa"
18 )
19 self.style_proj = nn.Linear(H, r, bias=False)
20 self.style_ln = nn.LayerNorm(r)
21 self.human_anchors = nn.Parameter(torch.zeros(self.cfg["n_human_anchors"], r))
22 self.family_protos = nn.Parameter(torch.zeros(self.cfg["n_families"], r))
23 self.family_bias = nn.Parameter(torch.zeros(self.cfg["n_families"]))
24 self.log_tau = nn.Parameter(torch.zeros(()))
25 self.op_protos = nn.Parameter(torch.zeros(self.cfg["n_ops"], r))
26 self.op_bias = nn.Parameter(torch.zeros(self.cfg["n_ops"]))
27 self.load_state_dict(load_file(f"{model_dir}/model.safetensors"), strict=True)
28 self.eval()
29
30 @torch.no_grad()
31 def score(self, texts, tokenizer, device="cpu"):
32 """Returns P(AI) in [0, 1], one per text."""
33 enc = tokenizer(texts, return_tensors="pt", padding=True, truncation=True,
34 max_length=self.cfg["max_length"],
35 return_special_tokens_mask=True).to(device)
36 valid = enc["attention_mask"].bool() & ~enc["special_tokens_mask"].bool()
37 h = self.backbone(input_ids=enc["input_ids"],
38 attention_mask=enc["attention_mask"]).last_hidden_state.float()
39
40 u = self.style_ln(self.style_proj(h)) # style coordinates
41 tau = self.log_tau.clamp(-4.0, 4.0).exp()
42
43 def sqdist(u, p): # (B, L, P)
44 return ((u * u).sum(-1, keepdim=True) - 2.0 * u @ p.t()
45 + (p * p).sum(-1).view(1, 1, -1))
46
47 human = torch.logsumexp(-tau * sqdist(u, self.human_anchors), -1, keepdim=True)
48 family = -tau * sqdist(u, self.family_protos) + self.family_bias.view(1, 1, -1)
49 per_token = (self.cfg["tau_agg"] * torch.logsumexp(
50 (family - human).clamp(-30.0, 30.0) / self.cfg["tau_agg"], dim=-1))
51
52 # document score = mean of the most machine-like rho fraction of tokens
53 x = per_token.masked_fill(~valid, torch.finfo(per_token.dtype).min)
54 x, _ = x.sort(dim=1, descending=True)
55 k = (valid.sum(1).clamp(min=1) * self.cfg["rho"]).ceil().clamp(min=1).long()
56 keep = torch.arange(x.shape[1], device=x.device).unsqueeze(0) < k.unsqueeze(1)
57 s = torch.where(keep, x, torch.zeros_like(x)).sum(1) / k.float()
58 return torch.sigmoid(s).tolist(), s.tolist()
59
60
61device = "cuda" if torch.cuda.is_available() else "cpu"
62model = Meld(MODEL_DIR).to(device)
63tokenizer = AutoTokenizer.from_pretrained(MODEL_DIR)
64
65texts = ["Paste the document you want to check here."]
66probs, scores = model.score(texts, tokenizer, device)
67
68# Flag at the threshold shipped in meld_config.json: it is the score below
69# which 99% of human texts fell on our validation set (a 1% false-positive rate).
70threshold = model.cfg["score_offsets"]["overall"]["fpr_0.01"]
71for text, p, s in zip(texts, probs, scores):
72 print(f"P(AI) = {p:.3f} flagged = {s > threshold}")P(AI) to a round number like 0.5 or 0.1.
Human writing does not sit near zero; on human academic prose the average
document scores around 0.2, so a fixed absolute cut will flag almost everything
or nothing depending on the number you pick.meld_config.json stores score_offsets.
Compare the raw score s (not P(AI)) to score_offsets["overall"]["fpr_0.01"]
for a 1% false-positive rate, or fpr_0.05 / fpr_0.1 for looser settings.
score_offsets["strata"] has separate values for academic, web, wiki,
reviews, creative, and QA text.