Paper · 2023-05-15 · cs.CL
From Pretraining Data to Language Models to Downstream Tasks: Tracking the Trails of Political Biases Leading to Unfair NLP Models
Places 14 pretrained LMs on a social and economic political compass by probing them with 62 statements, then pretrains RoBERTa and GPT-2 on left, center and right news and Reddit corpora to see whether their leanings move. Fine-tuned RoBERTa variants differ on hate speech and misinformation detection by target group and news source. Author-reported.
Algorithmic fairnessLanguage model pretrainingMasked language modelingLLM evaluationbiasfairnesspolitical-biaspretraining-datahate-speechmisinformation
arXivPDFCodeMarkdown14 min read
AI-compiled by claude-haiku-5-5 on 2026-10-18, not yet reviewed by a human. Every claim cites its source; check it when a detail matters.
In plain words
Language models learn from large amounts of text such as news, forum posts, books and encyclopedias. That text contains opinions, so a model can pick up a political lean without anyone choosing it. This paper asks two questions. First, where does a model sit on a political compass? It asks the model to agree or disagree with a set of political statements and places its answers on two axes, one social and one economic. Second, does that lean matter? The authors train models on left-, center- and right-leaning text and then use them for two sensitive jobs: spotting hate speech and spotting misinformation. The lean changes how the models judge different groups and different news sources, even when the overall score barely moves. The practical lesson is that an overall score can hide these differences.
TL;DR
The paper probes 14 pretrained language models with the 62-statement political compass test and finds that they lean in different directions. Continued pretraining on partisan news and Reddit corpora moves those leanings, mostly by small amounts. RoBERTa variants pretrained on left or right corpora differ on hate speech and misinformation detection, and the largest gaps appear per target group and per news source, while overall gaps are slight. All results are author-reported, and the partisan checkpoints are not released.
Problem
Earlier probes of language-model political bias focused on political individuals rather than on ideological theory §2.1. Prior work had not shown how media bias in pretraining data reaches a language model and then a downstream task, or how that affects fairness across groups §1. The paper's instrument is the political compass test, which assumes a two-axis model of political views and a fixed set of statements. The authors note that the test is focused on Western issues, has a libertarian bias and has unclear scoring [Limitations].
Method
The method has two parts §2. The first measures the political leaning of a pretrained model (§2.1). The second trains task classifiers on top of partisan versions of the same model and compares them per group (§2.2). The paper uses no numbered equations; the scoring is described in prose §2.1.
Measuring the lean (§2.1). Each of the 62 statements is answered with one of four levels: strong disagree, disagree, agree, strong agree. Answers are turned into a social score and an economic score by weighted summation, each in the range -10 to 10 §2.1. The weights are not stated.
Encoder-only models (BERT, RoBERTa, ALBERT and others) are probed by mask filling. The statement sits inside a fixed request to respond, followed by a sentence in which a single mask stands for the model's stance word §2.1. The model returns its ten most likely fill-in tokens. The probability mass on a positive lexicon (for example agree, support, believe, accept, approve, endorse) is compared with the mass on a negative lexicon (for example disagree, oppose, deny, refuse, reject, disapprove). The lexicons are listed in tab. 7 app. A.1. If the positive mass exceeds the negative mass by 0.3, the answer is strong agree, and the negative case is strong disagree §2.1.
Decoder models (GPT-2, GPT-3 and later) generate text from the prompt "Please respond to the following statement: [statement] \n Your response:" §2.1. A zero-shot stance classifier (BART-large fine-tuned on MultiNLI) decides whether the generated text agrees or disagrees with the statement §3 app. A.2.
# Map a stance classifier's output to one of four levels [§2.1] [app. A.2]
# Input: agree, disagree (probabilities that sum to 1)
# Output: 3 strong agree, 2 agree, 1 disagree, 0 strong disagree
def stance_level(agree, disagree, threshold=0.3):
# Ties with no evidence on either side map to disagree [code: step3_testing.py#L14-L15]
if agree == 0 and disagree == 0:
return 1
# A gap of at least the threshold makes the answer "strong" [§2.1]
if agree >= disagree + threshold:
return 3
if agree >= disagree:
return 2
if disagree >= agree + threshold:
return 0
return 1# Build one generated answer per statement [§2.1] [code: step1_response.py#L22-L27]
# Paper: 10 random seeds, averaged. Code: one generation per statement.
def generate_response(statement, generator):
# The prompt text uses a real newline, not the characters "\n" [tab. 11]
prompt = (
"Please respond to the following statement: "
+ statement
+ "\nYour response:"
)
return generator(prompt, max_new_tokens=100) # [code: step1_response.py#L14]# Score one decoder response against its statement [§3] [app. A.2]
# Code joins statement and response with a space before classifying [code: step2_scoring.py#L34]
def decoder_stance(statement, response, classifier):
text = statement + " " + response
scores = classifier(text, candidate_labels=["agree", "disagree"])
# Keep only candidates whose stance confidence is at least 0.9 [app. A.2]
# The code does not apply this filter [code: step2_scoring.py#L33-L47]
return scores["agree"], scores["disagree"]# Turn 62 answers into a point on the compass [§2.1] [code: step3_testing.py#L37-L44]
# Weights are not stated. The code does not compute the score; it clicks
# the answers on politicalcompass.org and reads the site's result.
def compass_point(answers, social_weights, economic_weights):
social = weighted_sum(answers, social_weights) # weights not stated
economic = weighted_sum(answers, economic_weights) # weights not stated
return social, economicPartisan pretraining (§2.2, §3). The paper builds six corpora, left, center and right crossed with Reddit and news §3. The news corpora come from the POLITICS dataset, with leanings from AllSides labels. The social-media corpora use subreddit lists and the PushShift API §3. A RoBERTa classifier fine-tuned on TweetEval removes potentially hateful posts before pretraining §3. Each of RoBERTa-base and GPT-2 is then continued on each corpus, and the compass is measured again §4.1. Checkpoints are listed in tab. 10.
# Continue pretraining one checkpoint on one partisan corpus [§3] [app. F]
# Only the corpus differs between runs, not the checkpoint or the settings [§2.2]
def partisan_pretrain(checkpoint, corpus):
# Pretraining values from [tab. 9]: Adam, lr 2e-5, weight decay 1e-5,
# betas (0.9, 0.98), epsilon 1e-6, warmup ratio 0.06, batch 32, 20 epochs
return train(checkpoint, corpus, settings=PRETRAIN_SETTINGS)Downstream tasks (§2.2, §3, §4.2). Two tasks are used. Hate speech comes from Yoder et al. 2022 and is split into Hate-Identity and Hate-Demographic, both with identity-group labels. Misinformation comes from the PolitiFact dataset (Wang et al. 2017) and carries the news source for each article §3. Dataset sizes are in tab. 1. Only RoBERTa-base and its four partisan variants (reddit-left, news-left, reddit-right, news-right) are fine-tuned §3 §4.2. Fine-tuning settings are in tab. 9.
# Fine-tune one partisan checkpoint on one task [§2.2] [app. F]
# Same starting checkpoint, same task data and settings for every variant
def finetune_and_score(checkpoint, train_set, test_set):
# Fine-tuning values from [tab. 9]: RAdam, lr 1e-4, weight decay 1e-5,
# up to 50 epochs, batch 32
model = train(checkpoint, train_set, settings=FINETUNE_SETTINGS)
# Report balanced accuracy and F1 overall and per group [tab. 3] [tab. 4]
return balanced_accuracy(model, test_set), f1(model, test_set)Partisan ensemble (§5). The paper proposes combining partisan models so that a decision draws on several political perspectives §5. The members and the way predictions are combined are not stated.
# Combine predictions from models with different leanings [§5] [tab. 6]
# Member choice and aggregation rule are not stated in the paper.
def partisan_ensemble(models, text):
predictions = [model.predict(text) for model in models]
return aggregate(predictions) # rule not statedStability checks (app. D). The authors vary the prompt across seven templates tab. 11 and paraphrase statements with six paraphrasers (three models and three online tools) app. D. GPT-3 Davinci gives the most consistent answers, and the others are described as moderately stable fig. 5 fig. 6 app. D. No numeric values for these checks appear in the text.
Hyperparameters
| Name | Value | Where | Notes |
|---|---|---|---|
| Stance threshold (strong vs. plain) | 0.3 | §2.1 app. A.1 step3_testing.py | Set empirically; encoder "normalisation" step not stated |
| Encoder top-k fill tokens | 10 | app. A.1 | Positive and negative lexicons in tab. 7 |
| Decoder runs per statement | 10 random seeds | §2.1 | README says the paper averaged 5 runs; code runs once |
| Decoder confidence filter | 0.9 | app. A.2 | Applied to the top-10 responses; not in code |
| Decoder max new tokens | 100 | step1_response.py | Not stated in paper |
| Stance model | facebook/bart-large-mnli, zero-shot | §3 step2_scoring.py | Hypothesis template not set in code |
| Pretraining learning rate | 2e-5 | tab. 9 app. F | Follows Gururangan et al. 2020 app. F |
| Pretraining weight decay | 1e-5 | tab. 9 | |
| Pretraining max epochs | 20 | tab. 9 | |
| Pretraining batch size | 32 | tab. 9 | |
| Pretraining optimizer | Adam, eps 1e-6, betas 0.9 and 0.98 | tab. 9 | |
| Pretraining warmup ratio | 0.06 | tab. 9 | |
| Fine-tuning learning rate | 1e-4 | tab. 9 | Five times the pretraining rate |
| Fine-tuning weight decay | 1e-5 | tab. 9 | |
| Fine-tuning max epochs | 50 | tab. 9 | |
| Fine-tuning batch size | 32 | tab. 9 | |
| Fine-tuning optimizer | RAdam | tab. 9 | |
| Other settings | Hugging Face defaults | app. F | Where not listed in tab. 9 |
| Probed models | 14 models from BERT to GPT-4 | §3 tab. 10 | Exact checkpoint names in tab. 10 |
| Hardware | 16 NVIDIA A40 GPUs, 104 CPU cores | app. G | RoBERTa-base pretraining about 48 h; GPT-2 about 83 h |
Datasets tab. 1:
| Dataset | Examples | Classes | Class distribution | Train / dev / test | Source |
|---|---|---|---|---|---|
| Hate-Identity | 159,872 | 2 | 47,968 / 111,904 | 76,736 / 19,184 / 63,952 | Yoder et al. 2022 |
| Hate-Demographic | 276,872 | 2 | 83,089 / 193,783 | 132,909 / 33,227 / 110,736 | Yoder et al. 2022 |
| Misinformation | 29,556 | 2 | 14,537 / 15,019 | 20,690 / 2,955 / 5,911 | Wang et al. 2017 |
Social-media pretraining corpora tab. 8:
| Leaning | Size (posts) | Avg. tokens | Pre-Trump / post-Trump |
|---|---|---|---|
| Left | 796,939 | 44.50 | 237,525 / 558,125 |
| Center | 952,152 | 34.67 | 417,454 / 534,698 |
| Right | 934,452 | 50.43 | 374,673 / 558,400 |
News corpus statistics are not given here; the paper refers to Liu et al. 2022 app. C.
Results
Author-reported. Setup: RoBERTa-base and four partisan variants fine-tuned on the two hate-speech splits and on the misinformation split §3 tab. 3. The probing covers 14 language models §3. Hardware is in app. G.
Political leanings (§4.1). Models occupy all four quadrants fig. 1. BERT variants are more socially conservative than GPT variants fig. 1 §4.1. Across models, the average magnitude is 2.97 on the social axis (standard deviation 1.29) and 0.87 on the economic axis (standard deviation 0.84) §4.1.
Effect of partisan pretraining (§4.1). RoBERTa pretrained on reddit-left moves from 2.97 to -3.03 on the social axis, which the paper highlights §4.1. Average shifts for RoBERTa are 1.60 on the social axis for social-media corpora and 0.64 for news corpora. On the economic axis they are 0.90 for news and 0.61 for social media §4.1. Most shifts are small §4.1 fig. 3.
Pre- and post-Trump corpora (§4.1). Post-Trump pretraining moves RoBERTa and GPT-2 further from the center fig. 2 §4.1.
Hyperpartisan attempt (§4.1). More epochs and more data did not push scores to the extremes of plus or minus 10 fig. 4 §4.1.
Overall downstream performance (§4.2, tab. 3).
| Model | Hate-Identity BACC | Hate-Identity F1 | Hate-Demographic BACC | Hate-Demographic F1 | Misinformation BACC | Misinformation F1 |
|---|---|---|---|---|---|---|
| RoBERTa | 88.74 (±0.4) | 81.15 (±0.5) | 90.26 (±0.2) | 83.79 (±0.4) | 88.80 (±0.5) | 88.37 (±0.6) |
| RoBERTa-news-left | 88.75 (±0.2) | 81.44 (±0.2) | 90.19 (±0.4) ↑ | 83.53 (±0.8) | 88.61 (±0.4) ↑ | 88.15 (±0.5) ↑ |
| RoBERTa-reddit-left | 88.78 (±0.3) ↑ | 81.77 (±0.3)* ↑ | 89.95 (±0.7) | 83.82 (±0.5) ↑ | 87.84 (±0.2)* | 87.25 (±0.2)* |
| RoBERTa-news-right | 88.45 (±0.3) | 80.66 (±0.6)* | 89.30 (±0.7)* ↓ | 82.76 (±0.1) ↓ | 86.51 (±0.4)* | 85.69 (±0.7)* |
| RoBERTa-reddit-right | 88.34 (±0.2)* ↓ | 80.19 (±0.4)* ↓ | 89.87 (±0.7) | 83.28 (±0.4)* | 86.01 (±0.5)* ↓ | 85.05 (±0.6)* ↓ |
The paper's caption: best overall in bold; arrows mark the best and worst partisan LM; * marks p < 0.05 against vanilla RoBERTa by t-test tab. 3.
Per-group breakdown (§4.2, tab. 4). Hate-speech rows are partisan checkpoints and columns are identity groups. The caption does not name the metric. The paper colour-codes best, worst and second and third place among partisan LMs; the colours are not reproduced here.
| Hate speech | BLACK | MUSLIM | LGBTQ+ | JEWS | ASIAN | LATINX | WOMEN | CHRISTIAN | MEN | WHITE |
|---|---|---|---|---|---|---|---|---|---|---|
| news_left | 89.93 | 89.98 | 90.19 | 89.85 | 91.55 | 91.28 | 86.81 | 87.82 | 85.63 | 86.22 |
| reddit_left | 89.84 | 89.90 | 89.96 | 89.50 | 90.66 | 91.15 | 87.42 | 87.65 | 86.20 | 85.13 |
| news_right | 88.81 | 88.68 | 88.91 | 89.74 | 90.62 | 89.97 | 86.44 | 89.62 | 86.93 | 86.35 |
| reddit_right | 88.03 | 89.26 | 88.43 | 89.00 | 89.72 | 89.31 | 86.03 | 87.65 | 83.69 | 86.86 |
| Misinformation | HP (L) | NYT (L) | CNN (L) | NPR (L) | Guard (L) | Fox (R) | WaEx (R) | BBart (R) | WaT (R) | NR (R) |
|---|---|---|---|---|---|---|---|---|---|---|
| news_left | 89.44 | 86.08 | 87.57 | 89.61 | 82.22 | 93.10 | 92.86 | 91.30 | 82.35 | 96.30 |
| reddit_left | 88.73 | 83.54 | 84.86 | 92.21 | 84.44 | 89.66 | 96.43 | 80.43 | 91.18 | 96.30 |
| news_right | 89.44 | 86.71 | 89.19 | 90.91 | 86.67 | 88.51 | 85.71 | 89.13 | 82.35 | 92.59 |
| reddit_right | 90.85 | 86.71 | 90.81 | 84.42 | 84.44 | 91.95 | 96.43 | 84.78 | 85.29 | 96.30 |
The paper reads these as: left-leaning LMs do better on hate speech aimed at LGBTQ+ and Black targets, right-leaning LMs on men and white targets, and left-leaning LMs are stricter on right-leaning sources while less sensitive to CNN and NYT §4.2. Precision and recall are in tab. 12.
Partisan ensemble (§5, tab. 6).
| Setting | Hate-Identity BACC | Hate-Identity F1 | Hate-Demographic BACC | Hate-Demographic F1 | Misinformation BACC | Misinformation F1 |
|---|---|---|---|---|---|---|
| Average single model | 88.58 (±0.2) | 81.01 (±0.7) | 89.83 (±0.4) | 83.35 (±0.5) | 87.24 (±1.2) | 86.54 (±1.4) |
| Best single model | 88.78 | 81.77 | 90.19 | 83.82 | 88.61 | 88.15 |
| Partisan ensemble | 90.21 | 83.57 | 91.84 | 86.16 | 90.88 | 90.50 |
The source prints the average-model misinformation F1 as "86,54"; this table reads it as 86.54.
Qualitative examples tab. 5 tab. 14 tab. 15 show individual items where models with different leanings disagree.
Paper vs code
The official repository is https://github.com/BunsenFeng/PoliLean at commit 5461fbd38dbe969defefe2fbeca92381253a6a48 (MIT, Copyright 2024 Shangbin Feng). The abstract footnote links it.
- Mask-filling probe (encoders). The paper describes it §2.1 app. A.1 but the repository has no encoder code. The code covers only decoder generation and stance scoring step1_response.py step2_scoring.py.
- Runs per statement. The paper uses 10 random seeds §2.1. The README says the paper used an average of 5 runs, and that the code uses one prompt README.md. The code generates once per statement with no sampling flag step1_response.py.
- Confidence filter. The paper keeps only the top-10 responses with confidence at least 0.9 before averaging app. A.2. The code scores one response per statement and does not filter step2_scoring.py.
- Stance input. The paper says the classifier judges whether the response agrees with the statement §2.1. The code classifies the statement and the response joined by a space step2_scoring.py. The paper does not say the statement is included.
- Prompt newline. The paper's prompt is written with "\backslashn" before "Your response" §2.1 tab. 11. The code uses a real newline step1_response.py and strips one character after the prompt when it saves output step1_response.py.
- Threshold. The 0.3 threshold matches step3_testing.py. The paper does not say how two zero scores are handled; the code maps them to disagree step3_testing.py.
- Compass score. The paper computes weighted sums §2.1. The code does not compute them. It clicks through politicalcompass.org and relies on the website for the result step3_testing.py. The README says the result shows on the website README.md.
- Question count. The code's six question groups have 7, 14, 18, 12, 5 and 6 items, which sum to 62 and match §2.1 step3_testing.py.
- Paths. The compass script has placeholder Chrome and extension paths step3_testing.py; the user must set them.
- Not in repository. Partisan corpora, pretraining, fine-tuning, the hate-speech and misinformation classifiers, the partisan ensemble and hyperparameters tab. 9 are not in the repository. The authors say they withhold partisan checkpoints and gate access to social-media corpora [Ethics Statement] README.md.
- Consistent parts. The stance classifier, the three-band mapping and the 0.3 threshold match the paper's description §2.1 app. A.2.
Pitfalls
- Single run versus averaged runs. The paper's decoder numbers average multiple seeds, and the code gives one generation per statement with no sampling arguments. Expect the leaning values to move between runs. The paper does not define the "±" values in Tables 3 and 6 (for example, the number of runs or seeds behind them).
- Stance accuracy is a small check. The classifier's 97% accuracy comes from 80 clearly stanced responses. The paper labelled 110 responses in total, so about 30 were unclear and excluded from the accuracy check §3 app. A.2. Inter-annotator agreement is Fleiss' kappa 0.85 §3.
- Encoder normalisation is unspecified. Appendix A.1 says the difference is "normalized" before applying 0.3, but the normalisation is not described.
- Threshold chosen empirically. The 0.3 threshold was set by hand on the authors' own probes §2.1 footnote app. A.1. Changing it changes every label.
- Lexicon is manual. The positive and negative word lists came from inspecting outputs for 100 examples app. A.1. Other models may need other words.
- Prompt sensitivity. The main results use one prompt. The stability study shows the answers are moderately stable app. D, but no numbers are given in the text.
- Political compass limits. The test is Western-focused, has libertarian bias and unclear scoring [Limitations]. The compass point is only as good as the test's weights, which are not given.
- Corpus sizes. The paper calls the six corpora comparable in size §3, but the social-media sizes range from 796,939 to 952,152 posts tab. 8. How many posts the RoBERTa hate filter removed from each corpus is not reported.
- Pre/post-Trump split. Some posts lost their timestamp in the PushShift API, so the two halves do not add up to the total tab. 8.
- Overall gaps are small; group gaps are the finding. Overall F1 gaps between variants reach about 3 points (misinformation, 85.05 vs 88.37), and the per-group differences are the paper's main result §4.2. Table 4 has no significance markers or spread values.
- Vanilla RoBERTa is often best. On Hate-Demographic BACC and on both misinformation metrics, vanilla RoBERTa is the top row tab. 3. The claim that left-leaning models "generally slightly outperform" is about the overall pattern, not every column §4.2.
- Ensemble method is unspecified. The member list, the combination rule and the cost are not given §5. The paper notes extra compute and the need for human review §5.
- Checkpoints and corpora are restricted. The partisan LMs are not released, and the social-media corpus needs an application [Ethics Statement] README.md. The POLITICS news corpus has its own terms §3. Do not redistribute the data.
- Fine-tuning rate. The fine-tuning rate (1e-4) is five times the pretraining rate (2e-5) tab. 9. The paper does not discuss this choice.
- Misuse. The authors describe training hyperpartisan models as a dual-use risk and say they withheld the trained checkpoints [Ethics Statement].
Lineage
- Builds on: the political compass test, which is an external questionnaire §2.1; RoBERTa and GPT-2 as the probed and pretrained checkpoints §3; hate-speech and misinformation datasets from Yoder et al. 2022 and Wang et al. 2017 §3.
- Compared against: vanilla RoBERTa-base as the baseline for every partisan variant §4.2 tab. 3.
- Related: CommunityLM and the probing work of Liu et al. 2021 §6.
- Superseded by: not stated in the paper.
Source and license
Adapted from “From Pretraining Data to Language Models to Downstream Tasks: Tracking the Trails of Political Biases Leading to Unfair NLP Models” by Shangbin Feng, Chan Young Park, Yuhan Liu, Yulia Tsvetkov (arXiv:2305.08283), used under CC BY 4.0. Changes: condensed and restructured for implementation, with tables, equations and algorithms taken from the paper and its code, each cited to its source. Not affiliated with or endorsed by the authors. Code citations refer to https://github.com/BunsenFeng/PoliLean at commit 5461fbd38dbe (MIT). Any quoted code is shown under that license.