tdickson17/Populism_detection
Overall Summary:
I developed a transformer-based model that analyzes political press releases to both summarize content and detect populist rhetoric. I generated true lables using GPT-4o on a dataset of 10,000 releases from 12 European countries, I engineered prompts to label where populist framing occurs—such as “people vs. elites” or anti-institutional language—and to generate concise explanations of why certain phrases qualify as populist. The final model, built on a fine-tuned BART architecture, allows users to quickly identify when populism is present in political discourse and understand the reasoning behind that classification.
Populism Detection & Summarization
This checkpoint is a BART-based, LoRA-fine-tuned model that does two things:
Summarizes party press releases (and, when relevant, explains where populist framing appears), and
Classifies whether the text contains populist language (Is_Populist ∈ {0,1}).
Weights here are the merged LoRA result—no adapters required.
The model was trained on ~10k official party press releases from 12 countries (Italy, Sweden, Switzerland, Netherlands, Germany, Denmark, Spain, UK, Austria, Poland, Ireland, France) that were labeled and summarized via a Palantir AIP Ontology step using GPT-4o.
Model Details
Pretrained Model: facebook/bart-base (seq2seq) fine-tuned with LoRA and then merged. Instruction Framing: Two prefixes:
Summarize: summarize: <original_text>
Classify: classifypopulism: <originaltext> → model outputs 0 or 1 (or you can argmax over first decoder step logits for tokens “0” vs “1”).
Tokenization: BART’s subword tokenizer (Byte-Pair Encoding).
Input Processing: Text is truncated to 1024 tokens; summaries capped at 128 tokens.
Output Generation (summarization): beam search (typically 5 beams), mild length penalty, and no-repeat bigrams to reduce redundancy.
Key Parameters:
Max Input Length: 1024 tokens — fits long releases while controlling memory.
Max Target Length: 128 tokens — concise summaries with good coverage.
Beam Search: ~5 beams — balances quality and speed.
Classification Decoding: read the first generated token (0/1) or take first-step logits for a deterministic argmax.
Generation Process (high level)
Input Tokenization: Convert text to subwords and build the encoder input.
Beam Search (summarize): Explore multiple candidate sequences, pick the most probable.
Output Decoding: Map token IDs back to text, skipping special tokens.
Model Hub: tdickson17/Populism_detection
Repository: https://github.com/tcdickson/Populism.git
Training Details
Data Collection: Press releases were scraped from official party websites to capture formal statements and policy messaging. A Palantir AIP Ontology step (powered by GPT-4o) produced:
Is_Populist (binary) — whether the text exhibits populist framing (e.g., “people vs. elites,” anti-institutional rhetoric).
Summaries/Explanations — concise abstracts; when populism is present, the text explains where/how it appears.
Preprocessing: HTML/boilerplate removal, normalization, and formatting into pairs:
Input: original release text (title optional at inference)
Targets: (a) abstract summary/explanation, (b) binary label
Training Objective: Supervised fine-tuning for joint tasks:
Abstractive summarization (seq2seq cross-entropy)
Binary classification (decoded 0/1 via the same seq2seq head)
Training Strategy:
Base: facebook/bart-base
Method: LoRA on attention/FFN blocks (r=16, α=32, dropout=0.05), then merged into base.
Decoding: beam search for summaries; argmax or short generation for labels.
Evaluation signals: ROUGE for summaries; Accuracy/Precision/Recall/F1 for classification.
This setup lets one checkpoint handle both analysis (populism flag) and explanation (summary) with simple instruction prefixes.
Usage:
There are 2 ways to use this model.
First:
You can run the test_model.ipynb file.
Second:
install dependency (Bash):
then run:
from transformers import AutoTokenizer, AutoModelForSeq2SeqLM
MODELID = "tdickson17/Populismdetection" device = "cuda" if torch.cuda.is_available() else "cpu"
tok = AutoTokenizer.frompretrained(MODELID) model = AutoModelForSeq2SeqLM.frompretrained(MODELID).to(device).eval()
MAXSRC, MAXSUM = 1024, 128 DECSTART = model.config.decoderstarttokenid ID0 = tok("0", addspecialtokens=False)["inputids"][0] ID1 = tok("1", addspecialtokens=False)["inputids"][0]
THRESHOLD = 0.5 # raise for higher precision, lower for higher recall POSITIVEMSG = "This text DOES contain populist sentiment.\n" NEGATIVEMSG = "Populist sentiment is NOT detected in this text.\n"
GENSUM = dict( dosample=False, numbeams=5, maxnewtokens=MAXSUM, minnewtokens=16, lengthpenalty=1.1, norepeatngramsize=3 )
@torch.nograd() def summarize(text: str) -> str: enc = tok("summarize: " + text, returntensors="pt", truncation=True, maxlength=MAXSRC).to(device) out = model.generate(enc, GENSUM) s = tok.decode(out[0], skipspecial_tokens=True).strip() if s.lower().startswith("summarize:"): s = s.split(":", 1)[1].strip() return s
@torch.nograd() def classifypopulismprob(text: str) -> float: enc = tok("classifypopulism: " + text, returntensors="pt", truncation=True, maxlength=MAXSRC).to(device) decinp = torch.tensor([[DECSTART]], device=device) logits = model(**enc, decoderinputids=decinp, use_cache=False).logits[:, -1, :]
two = torch.stack([logits[:, ID0], logits[:, ID1]], dim=-1) p1 = torch.softmax(two, dim=-1)[0, 1].item() return p1
def classifypopulismlabel(text: str, threshold: float = THRESHOLD, includeprobability: bool = True) -> str: p1 = classifypopulismprob(text) msg = POSITIVEMSG if p1 >= threshold else NEGATIVEMSG return f"{msg} Confidence={p1:.3f}%" if includeprobability else msg
Example
text = """<Insert Text here>""" print(classifypopulismlabel(text)) print("\nSummary:\n", summarize(text))
## Citation:
title={Going against the grain: Climate change as a wedge issue for the radical right}, author={Dickson, Zachary P and Hobolt, Sara B}, journal={Comparative Political Studies}, year={2024}, publisher={SAGE Publications Sage CA: Los Angeles, CA} }
