Views
No views yet
meta-llama/Llama-3.2-1B.
Given an article, the model emits a per-token probability that the token is
inside a funding-acknowledgment span.adapter_config.json # PEFT LoRA config (base: Llama-3.2-1B)
adapter_model.safetensors # LoRA weights (q_proj, v_proj)
classifier.pt # Conv1d head on top of last-4-layer hidden states
README.mdLlama-3.2-1B (frozen base)
+ LoRA(r=32, α=32, target=[q_proj, v_proj], dropout=0.05)
└── concat(hidden_states[-4:], dim=-1) → shape (B, T, 8192)
Conv1d head (classifier.pt, flat nn.Sequential keys 0/2/4):
Conv1d(8192, 512, k=5, padding=2) + GELU
Conv1d( 512, 128, k=3, padding=1) + GELU
Conv1d( 128, 1, k=1)
→ per-token logits (B, T)1import torch
2import torch.nn as nn
3from transformers import AutoModelForCausalLM, AutoTokenizer
4from peft import PeftModel
5from huggingface_hub import hf_hub_download
6
7BASE = "meta-llama/Llama-3.2-1B"
8REPO = "cometadata/funding-parsing-token-probe-Llama-3.2-1B-lora"
9N_HIDDEN_LAYERS = 4
10THRESHOLD = -4.0 # tuned on validation; raise for more precision, lower for more recall
11
12tokenizer = AutoTokenizer.from_pretrained(BASE)
13base = AutoModelForCausalLM.from_pretrained(BASE)
14peft_model = PeftModel.from_pretrained(base, REPO)
15
16class FundingProbe(nn.Module):
17 def __init__(self, peft_model, n_hidden_layers=N_HIDDEN_LAYERS):
18 super().__init__()
19 self.model = peft_model
20 self.n_hidden_layers = n_hidden_layers
21 h = self.model.config.hidden_size
22 input_dim = h * n_hidden_layers
23 self.classifier = nn.Sequential(
24 nn.Conv1d(input_dim, 512, kernel_size=5, padding=2), nn.GELU(),
25 nn.Conv1d(512, 128, kernel_size=3, padding=1), nn.GELU(),
26 nn.Conv1d(128, 1, kernel_size=1),
27 )
28
29 def forward(self, input_ids, attention_mask):
30 outputs = self.model(
31 input_ids=input_ids, attention_mask=attention_mask,
32 output_hidden_states=True,
33 )
34 layers = outputs.hidden_states[-self.n_hidden_layers:]
35 hidden = torch.cat(layers, dim=-1).float()
36 # mask padding BEFORE conv (otherwise it learns padding patterns)
37 hidden = hidden * attention_mask.unsqueeze(-1).float()
38 logits = self.classifier(hidden.transpose(1, 2)).squeeze(1) # (B, T)
39 return logits
40
41model = FundingProbe(peft_model)
42classifier_path = hf_hub_download(repo_id=REPO, filename="classifier.pt")
43model.classifier.load_state_dict(
44 torch.load(classifier_path, map_location="cpu", weights_only=True)
45)
46model.eval()1MAX_LENGTH = 4096
2
3def predict_spans(article_text, threshold=THRESHOLD):
4 enc = tokenizer(
5 article_text, return_offsets_mapping=True,
6 add_special_tokens=False, truncation=False,
7 )
8 input_ids = enc["input_ids"]
9 offsets = enc["offset_mapping"]
10 if len(input_ids) > MAX_LENGTH:
11 input_ids = input_ids[-MAX_LENGTH:]
12 offsets = offsets[-MAX_LENGTH:]
13
14 ids = torch.tensor([input_ids])
15 mask = torch.ones_like(ids)
16 with torch.no_grad():
17 logits = model(ids, mask)[0].cpu().numpy()
18 preds = logits > threshold
19
20 spans, in_span, start_char = [], False, 0
21 for i, (p, (s, e)) in enumerate(zip(preds, offsets)):
22 if p and not in_span:
23 in_span, start_char = True, s
24 elif not p and in_span:
25 spans.append(article_text[start_char:offsets[i-1][1]])
26 in_span = False
27 if in_span:
28 spans.append(article_text[start_char:offsets[-1][1]])
29 return spansextraction_probe/predict_sliding.py
in the source repo).meta-llama/Llama-3.2-1B (frozen)q_proj, v_proj]gamma_neg=4, gamma_pos=0, pos_weight=50, plus a soft-IoU term
(weight 1.0). ASL aggressively down-weights easy negatives; pos_weight
balances the ~1% positive rate.DataParallel caused subtle train/inference
discrepancies on logit magnitudes, so training and inference are both
single-GPU.data/test.jsonl, threshold sweep)| threshold | precision | recall | F1 |
|---|---|---|---|
| −6.0 | 0.660 | 1.000 | 0.795 |
| −5.0 | 0.661 | 0.998 | 0.795 |
| −4.0 | 0.666 | 0.990 | 0.796 |
| −3.0 | 0.666 | 0.964 | 0.788 |
| −2.0 | 0.667 | 0.905 | 0.768 |
| −1.0 | 0.671 | 0.838 | 0.745 |
extraction_probe/ directory of the
funding-statement-identification repo.