armaniii/WIBA-Detect-V1
WIBA Argument Detection (Llama-3-8B LoRA)
Binary argument detection model: given a sentence or passage, it classifies the text as `Argument` or `NoArgument`. An argument is defined as text containing a claim supported by at least one premise (evidence or reasoning).
This is Stage 1 of the WIBA (What Is Being Argued?) argument mining pipeline:
- ๐ Paper: WIBA: What Is Being Argued? A Comprehensive Approach to Argument Mining
- ๐ป Code: github.com/Armaniii/WIBA
- ๐ Platform: wiba.dev
What this repo contains (adapter, not a full model)
This repo is a PEFT LoRA adapter (~190 MB, float32), not standalone model weights. It must be loaded on top of the gated base model `meta-llama/Meta-Llama-3-8B` โ request access to the base model and huggingface-cli login before use.
Because the trained score head ships inside the adapter file, loading this adapter restores the complete classifier โ the base model's randomly-initialized head is replaced at load time.
Checkpoint format note: the adapter was originally trained and saved with PEFT 0.7.1, whosescore-head layout cannot be loaded by modern PEFT (โฅ0.10 raisesKeyError: 'base_model.model.score.weight'). The files onmainwere converted to the modern format (trained head merged asbase_layer + (alpha/r)ยทBยทA) and verified logit-equivalent to the original within 1e-4. If you are on a 2024-era stack (peft 0.7.1 / transformers 4.38), load the original layout instead withrevision="69bff7d70a27f9255f5c373ff53cff8ad0a517cb".
Before you start: get access to the gated Meta base model (one-time, ~10 minutes)
This adapter repo is freely downloadable, but the Meta base model it sits on is gated โ Meta requires you to accept their license before you can download it. Step by step:
- Create a Hugging Face account (free): go to huggingface.co/join, sign up, and verify your email.
- Request access to the base model: while logged in, open meta-llama/Meta-Llama-3-8B. At the top of the page is a box saying you need to share your contact information to access the model. Fill in the short form, accept the license, and submit.
- Wait for the approval email โ usually minutes to a few hours. When the box on the model page changes to "You have been granted access", you're in.
- Create an access token: click your avatar (top right) โ Settings โ Access Tokens โ Create new token โ type Read โ create, and copy the token (it looks like
hf_...). Treat it like a password. - Log in on your computer: in a terminal run
pip install -U "huggingface_hub[cli]"
huggingface-cli login and paste the token when prompted (nothing is shown as you paste โ that's normal). Verify with huggingface-cli whoami, which should print your username.
This is once per computer. From then on, the code below downloads everything it needs automatically โ you'll see progress bars for each file on the first run (~16.3 GB total), after which everything is cached in ~/.cache/huggingface and loads from disk.
Hardware requirements โ pick your setup
One-time download for any setup: ~16.3 GB (base model + adapter).
Quickstart โ GPU
pip install torch transformers peft accelerateimport torch
from transformers import AutoTokenizer, AutoModelForSequenceClassification
from peft import PeftModel
ADAPTER = "armaniii/llama-3-8b-argument-detection"
BASE = "meta-llama/Meta-Llama-3-8B"
tokenizer = AutoTokenizer.from_pretrained(ADAPTER) # use the repo's tokenizer, not the base's
# The repo tokenizer's [UNK] pad token has id 128256, which is OUTSIDE the base
# model's 128256-token embedding table โ padding with it crashes batched
# inference. Use eos as the pad token instead:
tokenizer.pad_token = tokenizer.eos_token
base = AutoModelForSequenceClassification.from_pretrained(
BASE, num_labels=2, dtype=torch.float16, device_map="auto"
) # transformers 4.x: use torch_dtype=torch.float16
base.config.pad_token_id = tokenizer.pad_token_id
model = PeftModel.from_pretrained(base, ADAPTER)
model.eval()Low VRAM? Load the base 4-bit instead (โ6 GB VRAM, the production setting โ needs pip install bitsandbytes):
from transformers import BitsAndBytesConfig
bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_use_double_quant=False,
bnb_4bit_compute_dtype=torch.float16,
)
base = AutoModelForSequenceClassification.from_pretrained(
BASE, num_labels=2, device_map="auto", quantization_config=bnb_config
)Quickstart โ CPU (no GPU)
Identical to the GPU code, except load the base in float32 on the CPU:
base = AutoModelForSequenceClassification.from_pretrained(
BASE, num_labels=2, dtype=torch.float32, device_map="cpu"
)Expect ~90 s to load and ~20 s per prediction on a 16-core machine (verified). Make sure you have ~35 GB of free RAM before starting โ on machines without swap, overshooting RAM can freeze the system.
Prompt format (must match training)
The model was trained with the Llama-2-style instruction wrapper below (kept verbatim in the WIBA implementation, including the chain-of-thought "transition network" system prompt):
SYSTEM_PROMPT = """Premise: A statement that provides evidence, reasons, or support.
Conclusion: A statement that is being argued for or claimed based on the premises.
Argument/NoArgument Transition Network:
Start State --Token matches Premise Definition--> Premise State Augmentation (Premise sub-network) --Token matches Conclusion definition--> Conclusion State Augmentation (Conclusion sub-network) ----> Argument State ----> End State
Start State --Token matches Conclusion definition--> Conclusion State Augmentation (Conclusion sub-network) ----> Premise State Augmentation (Premise sub-network) ----> Argument State ----> End State
Start State --Token matches Premise Definition--> Premise State Augmentation (Premise sub-network) --Token does not match Conclusion Definition--> NoArgument State -> End State
Start State --Token matches Conclusion definition--> Conclusion State Augmentation (Conclusion sub-network) --Token does not match Premise Definition--> NoArgument State ----> End State
Start State ----> NoArgument State ----> End State
Start State --Token does not match Premise Definition--> NoArgument State ----> End State
Start State --Token does not match Conclusion Definition--> NoArgument State ----> End State
Premise State Augmentation (Premise sub-network) ----> Premise Content State ----> Premise Conjunction State ----> Premise State ----> Premise End State
Conclusion State Augmentation (Premise sub-network) ----> Conclusion Content State ----> Conclusion Conjunction State ----> Conclusion State ----> Conclusion End State
Argument State ----> Action: Classify as Argument ----> Argument State
NoArgument State ----> Action: Classify as NoArgument ----> NoArgument State
Follow this chain of thought reasoning and apply the transition network rules and systematically determine whether a given sentence is an argument or not, based on the presence or absence of premises and claims.
If the sentence is an argument, output only 'Argument' and your task is finished.
If the sentence is not an argument, output only 'NoArgument' and your task is finished."""
import string
def detect_argument(text: str) -> str:
if text and text[-1] not in string.punctuation: # original implementation adds a final period
text = text + "."
prompt = f"[INST] <<SYS>>\n{SYSTEM_PROMPT}\n<</SYS>>\n\nText: '{text}' [/INST] "
enc = tokenizer(prompt, return_tensors="pt", truncation=True, max_length=2048).to(model.device)
with torch.no_grad():
logits = model(**enc).logits
return ["NoArgument", "Argument"][int(logits.argmax(-1))]
print(detect_argument("We should ban assault weapons because they enable mass shootings."))
# -> Argument
print(detect_argument("The weather is nice today."))
# -> NoArgument(Outputs above are actual verified predictions, not illustrations.)
Label mapping
Batch processing many texts (with a progress bar)
Model downloads show progress bars automatically; inference doesn't, so wrap batches in tqdm (installed with transformers) exactly as the original WIBA serving code does. The eos pad-token override from the Quickstart must be in place:
from tqdm import tqdm
from transformers import pipeline
clf = pipeline("text-classification", model=model, tokenizer=tokenizer,
padding=True, truncation=True, max_length=2048)
texts = ["...", "..."] # your data
prompts = [f"[INST] <<SYS>>\n{SYSTEM_PROMPT}\n<</SYS>>\n\nText: '{t}' [/INST] " for t in texts]
labels = ["Argument" if out["label"] == "LABEL_1" else "NoArgument"
for out in tqdm(clf(prompts, batch_size=4), total=len(prompts))]Tested configurations
Logits agree across the two stacks/layouts to ~1e-4.
How it's used in the WIBA implementation
In the WIBA serving code, this model backs the /api/detect endpoint at wiba.dev: each input text is wrapped in the prompt above, run through the classifier, and LABEL_1 is mapped to Argument. Texts classified as Argument are then passed downstream to topic extraction and stance classification.
Citation
@article{irani2024wiba,
title={WIBA: What Is Being Argued? A Comprehensive Approach to Argument Mining},
author={Irani, Arman and Park, Ju Yeon and Esterling, Kevin and Faloutsos, Michalis},
journal={arXiv preprint arXiv:2405.00828},
year={2024}
}Framework versions
- Trained with PEFT 0.7.1; checkpoint on
mainre-saved in modern PEFT format (verified with PEFT 0.19.1) - Built on
meta-llama/Meta-Llama-3-8B(Llama 3 license applies)
