Bias Measurement › Embedding Association Tests

Michael BrenndoerferMarch 14, 202618 min read
Language AI HandbookAll chapters
Part 58 of 67Bias and Fairness
Chapter 442Bias Measurement › Embedding Association Tests
Reading section 2 of 8 · Embedding Association Tests · 18 minSection 2 of 8 · 18 min

Book contents

Section 2 of 8 · 18 min read

Bias Measurement › Embedding Association TestsOne section · Sections in this chapter2 / 8 ↓
Reading tools Definitions & inline links

Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.

Article links

Make inline references clickable

Word embeddings and sentence encoders compress language into dense vectors. These vectors encode semantic relationships learned from text, which means they also encode whatever associations existed in that text. If the word "nurse" consistently appeared near words associated with women and "engineer" appeared near words associated with men, the model's vectors will reflect that. Embedding association tests are a family of methods for detecting and quantifying these encoded associations.

The motivation for this approach goes back to early observations about word2vec and GloVe embeddings. Researchers noticed that simple arithmetic in embedding space produced semantically meaningful results: "king" minus "man" plus "woman" pointed toward "queen." This was exciting because it demonstrated that embeddings captured valid semantic relationships. But the same mechanism that encodes "king:queen::man:woman" also encodes stereotypical relationships: "doctor:nurse::man:woman" turns out to approximate the same directional offset in some embedding spaces. If the geometric structure of an embedding space encodes these associations, it becomes possible to measure them quantitatively rather than anecdotally. Embedding association tests formalize exactly this measurement.

The Word Embedding Association Test (WEAT)

The Word Embedding Association Test (WEAT), introduced by Caliskan et al. in 2017, was the first systematic method for measuring bias in word embeddings. The core idea is elegant: bias can be detected by measuring whether two sets of target words (e.g., male names vs. female names) are more strongly associated with one set of attribute words (e.g., career-related words) than the other (e.g., family-related words).

Word Embedding Association Test (WEAT)

A statistical test that measures the differential association between two sets of target words (e.g., male vs. female names) and two sets of attribute words (e.g., career vs. family terms), using cosine similarity in an embedding space as the measure of association.

The design of WEAT was directly inspired by the Implicit Association Test (IAT) from social psychology. The IAT measures the strength of associations in human cognition by measuring response times: people respond faster to pairings that match their implicit associations than to pairings that conflict with them. WEAT adapts this logic to embedding spaces: instead of response times, it uses cosine similarities. If male names are geometrically closer to career words than female names are, the model's embedding space encodes the same association that the IAT might detect in human cognition.

Formally, let XX and YY be two equal-sized sets of target words, and let AA and BB be two sets of attribute words. The association of a target word ww with attribute sets AA and BB is defined as:

s(w,A,B)=meana∈A cos⁡(w⃗,a⃗)−meanb∈B cos⁡(w⃗,b⃗)s(w, A, B) = \text{mean}_{a \in A}\, \cos(\vec{w}, \vec{a}) - \text{mean}_{b \in B}\, \cos(\vec{w}, \vec{b})

where:

  • w⃗\vec{w} is the embedding vector of word ww
  • cos⁡(u⃗,v⃗)\cos(\vec{u}, \vec{v}) is the cosine similarity between two vectors
  • meana∈A\text{mean}_{a \in A} averages over all attribute words in set AA

Intuitively, s(w,A,B)s(w, A, B) measures how much more similar ww is to attribute set AA than to attribute set BB. A positive value means ww leans toward AA. A negative value means ww leans toward BB. A value near zero means no preference. The function ss is computed for every target word in both groups.

The test statistic measures the differential association across the two target groups:

s(X,Y,A,B)=∑x∈Xs(x,A,B)−∑y∈Ys(y,A,B)s(X, Y, A, B) = \sum_{x \in X} s(x, A, B) - \sum_{y \in Y} s(y, A, B)

where:

  • s(x,A,B)s(x, A, B) is the single-target association for one word in XX, as computed above
  • The sum is taken over all words in each target group, not just one

If this value is positive, the targets in XX associate more strongly with attributes in AA than the targets in YY do. The raw statistic is a sum, so its magnitude grows with the size of the word sets, making it hard to compare across different test configurations. WEAT also defines an effect size dd analogous to Cohen's dd that normalizes for this:

d=meanx∈X s(x,A,B)−meany∈Y s(y,A,B)stdw∈X∪Y s(w,A,B)d = \frac{\text{mean}_{x \in X}\, s(x, A, B) - \text{mean}_{y \in Y}\, s(y, A, B)}{\text{std}_{w \in X \cup Y}\, s(w, A, B)}

where:

  • meanx∈X s(x,A,B)\text{mean}_{x \in X}\, s(x, A, B) is the average single-target association for targets in XX
  • meany∈Y s(y,A,B)\text{mean}_{y \in Y}\, s(y, A, B) is the average single-target association for targets in YY
  • stdw∈X∪Y s(w,A,B)\text{std}_{w \in X \cup Y}\, s(w, A, B) is the standard deviation of all individual target associations, pooled across both sets

The effect size dd ranges roughly from −2-2 to +2+2. A value near 00 indicates no differential association. A value of +1+1 indicates that targets in XX associate with attributes in AA approximately one standard deviation more strongly than targets in YY. Values above 1.01.0 are considered large effects.

The statistical significance of a WEAT result is assessed through a permutation test. The null hypothesis is that the two groups XX and YY are indistinguishable in terms of their association with AA and BB. Under this null, any partition of X∪YX \cup Y into two equal groups should produce a test statistic similar to the observed one. The permutation test computes the fraction of random partitions that produce a statistic larger than or equal to the observed value. This fraction is the one-sided pp-value.

WEAT was validated by showing that its results on word2vec and GloVe embeddings mirrored documented human implicit associations measured by the IAT. Career/family bias along gender lines, pleasantness associations with racial names, and mental health stigma all showed up as significant WEAT effects in embeddings trained on large corpora. The correspondence between WEAT and IAT results was striking: the same stereotypical associations that psychologists had documented in human cognition were legible in the geometric structure of word vectors.

Standard WEAT Tests

Caliskan et al. defined 10 standard test configurations, each chosen to detect a specific type of bias. Each test specifies four word sets: two target groups and two attribute dimensions. The tests include:

  • WEAT 1 and 2: Flower vs. insect names associated with pleasant vs. unpleasant words (a calibration test, confirming the method works)
  • WEAT 3 and 4: European-American vs. African-American names associated with pleasant vs. unpleasant words (racial sentiment bias)
  • WEAT 5: European-American vs. African-American names with positive/negative sentiment (a more recent name list)
  • WEAT 6: Male vs. female names with career vs. family words (gender-career bias)
  • WEAT 7: Math vs. arts words with male vs. female attribute words
  • WEAT 8: Science vs. arts words with male vs. female attribute words
  • WEAT 9: Mental illness vs. physical illness with young/pleasant vs. old/unpleasant attributes
  • WEAT 10: Old vs. young age associations with pleasant vs. unpleasant attributes

Tests 1 and 2 serve as sanity checks: virtually everyone finds flowers more pleasant than insects, so a valid embedding should show this. If the method fails on these calibration tests, something is wrong with the embeddings or implementation. The remaining tests probe socially relevant biases that have been documented in humans.

The inclusion of calibration tests was an important methodological choice. Without tests that should obviously succeed, a large effect size on a gender or race test could mean the embedding space encodes that stereotypical association, or it could mean the cosine-similarity-based measurement approach is producing artifacts. The flower/insect test provides a baseline: if the method can reliably detect the obvious case, then large effects on the socially relevant tests are more credibly interpreted as systematic bias rather than measurement noise.

The Sentence Encoder Association Test (SEAT)

WEAT operates on individual word embeddings. But modern language models rarely produce context-free word vectors. BERT, GPT, and their descendants produce contextualized embeddings where the representation of "bank" depends on the surrounding sentence. For these models, WEAT's single-word approach does not apply.

The Sentence Encoder Association Test (SEAT), introduced by May et al. in 2019, adapts WEAT for sentence encoders. Instead of measuring the cosine similarity of isolated word vectors, SEAT embeds target words in neutral sentence templates and computes cosine similarities between those sentence embeddings.

Sentence Encoder Association Test (SEAT)

An extension of WEAT that wraps target words in sentence templates (e.g., "This is [target].") before embedding them with a sentence encoder, enabling bias measurement in contextualized representations.

A typical template looks like "This is [target]." or "[Target] is a person." The target word fills the slot and the full sentence is encoded. This gives the model context to work with while keeping the only varying element the target word itself.

The choice of template is not neutral. "This is John." and "John is a person." produce different sentence embeddings, and the relative associations of those embeddings with career vs. family words may vary depending on the template. May et al. found that effect sizes could differ substantially across templates, raising questions about which template to use and how to report variability. Best practice is to test multiple templates and report both the mean effect size and the range across templates rather than cherry-picking a template that maximizes or minimizes the apparent bias.

For example, to test gender-career bias in a sentence encoder:

  • Target X: Sentences like "This is John." / "This is David." (male names)
  • Target Y: Sentences like "This is Mary." / "This is Sarah." (female names)
  • Attribute A: Career-related words embedded in template sentences
  • Attribute B: Family-related words embedded in template sentences

The test statistic and effect size calculations are then identical to WEAT.

SEAT revealed that several popular sentence encoders, including ELMo and BERT variants, encode gender-career and gender-science biases with large effect sizes, despite their contextualized representations being more sophisticated than static word vectors. This finding was important because it showed that moving to contextualized embeddings does not automatically reduce stereotypical associations. The representations became more powerful, but the biases they encoded from the training data remained.

Implementing WEAT and SEAT

Let's implement WEAT from scratch and then extend it to work with a sentence encoder. We'll use sentence-transformers for the embeddings and scipy for statistical support.

First, install the required packages:

In[3]:
Code
import subprocess

subprocess.run(
    ["uv", "pip", "install", "sentence-transformers", "scipy", "--quiet"],
    check=True,
)

Now define the WEAT scoring functions:

In[4]:
Code
import numpy as np


def cosine_similarity(a, b):
    """Cosine similarity between two vectors."""
    return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))


def mean_cosine(word_vec, attribute_vecs):
    """Mean cosine similarity between one vector and a set of attribute vectors."""
    return np.mean([cosine_similarity(word_vec, av) for av in attribute_vecs])


def single_target_association(target_vec, A_vecs, B_vecs):
    """Association of one target with two attribute sets: s(w, A, B)."""
    return mean_cosine(target_vec, A_vecs) - mean_cosine(target_vec, B_vecs)


def weat_effect_size(X_vecs, Y_vecs, A_vecs, B_vecs):
    """
    Compute WEAT effect size d.

    X_vecs, Y_vecs: target group embeddings
    A_vecs, B_vecs: attribute set embeddings
    """
    s_X = np.array(
        [single_target_association(x, A_vecs, B_vecs) for x in X_vecs]
    )
    s_Y = np.array(
        [single_target_association(y, A_vecs, B_vecs) for y in Y_vecs]
    )
    effect_size = (np.mean(s_X) - np.mean(s_Y)) / np.std(
        np.concatenate([s_X, s_Y])
    )
    return effect_size


def weat_p_value(X_vecs, Y_vecs, A_vecs, B_vecs, n_permutations=5000):
    """
    Compute one-sided p-value via permutation test.
    Tests H0: no differential association between X/Y and A/B.
    """
    s_X = np.array(
        [single_target_association(x, A_vecs, B_vecs) for x in X_vecs]
    )
    s_Y = np.array(
        [single_target_association(y, A_vecs, B_vecs) for y in Y_vecs]
    )
    observed = np.sum(s_X) - np.sum(s_Y)
    all_targets = np.concatenate([s_X, s_Y])
    n_X = len(X_vecs)

    count_extreme = 0
    for _ in range(n_permutations):
        perm = np.random.permutation(all_targets)
        perm_stat = np.sum(perm[:n_X]) - np.sum(perm[n_X:])
        if perm_stat > observed:
            count_extreme += 1
    return count_extreme / n_permutations

Now embed word sets using a sentence encoder and run WEAT test 6 (gender-career):

In[5]:
Code
from sentence_transformers import SentenceTransformer

# Load a lightweight sentence encoder
model = SentenceTransformer("all-MiniLM-L6-v2")

# WEAT Test 6: Gender-career bias
# Target X: male names; Target Y: female names
male_names = ["John", "Paul", "Mike", "Kevin", "Steve", "Greg", "Jeff", "Bill"]
female_names = ["Amy", "Joan", "Lisa", "Sarah", "Diana", "Kate", "Ann", "Donna"]

# Attribute A: career; Attribute B: family
career_words = [
    "executive",
    "management",
    "professional",
    "corporation",
    "salary",
    "office",
    "business",
    "career",
]
family_words = [
    "home",
    "parents",
    "children",
    "family",
    "cousins",
    "marriage",
    "wedding",
    "relatives",
]


def encode_with_template(words, template="This is {}."):
    """Encode words in a neutral sentence template (SEAT approach)."""
    sentences = [template.format(w) for w in words]
    return model.encode(sentences, normalize_embeddings=True)


X_vecs = encode_with_template(male_names)
Y_vecs = encode_with_template(female_names)
A_vecs = encode_with_template(career_words)
B_vecs = encode_with_template(family_words)
Out[6]:
Console
WEAT Test 6 (Gender-Career Bias)
  Effect size (d): +1.145
  p-value (one-sided): 0.0092

Interpretation: large effect. Male names associate more strongly with career words.

The effect size quantifies the direction and magnitude of the bias. A positive value means male names associate more strongly with career terms than female names do, which reflects the gender-career stereotype documented in human psychology. The p-value tells you whether the effect is statistically significant or could arise from chance.

Let's run WEAT across multiple test configurations to compare effect sizes:

In[7]:
Code
weat_tests = {
    "Gender-Career (T6)": {
        "X": ["John", "Paul", "Mike", "Kevin", "Steve", "Greg", "Jeff", "Bill"],
        "Y": ["Amy", "Joan", "Lisa", "Sarah", "Diana", "Kate", "Ann", "Donna"],
        "A": [
            "executive",
            "management",
            "professional",
            "corporation",
            "salary",
            "office",
            "business",
            "career",
        ],
        "B": [
            "home",
            "parents",
            "children",
            "family",
            "cousins",
            "marriage",
            "wedding",
            "relatives",
        ],
    },
    "Gender-Science (T8)": {
        "X": ["John", "Paul", "Mike", "Kevin", "Steve", "Greg", "Jeff", "Bill"],
        "Y": ["Amy", "Joan", "Lisa", "Sarah", "Diana", "Kate", "Ann", "Donna"],
        "A": [
            "science",
            "technology",
            "physics",
            "chemistry",
            "einstein",
            "nasa",
            "experiment",
            "astronomy",
        ],
        "B": [
            "poetry",
            "art",
            "shakespeare",
            "dance",
            "literature",
            "novel",
            "symphony",
            "drama",
        ],
    },
    "Gender-Math (T7)": {
        "X": ["male", "man", "boy", "brother", "he", "him", "his", "son"],
        "Y": [
            "female",
            "woman",
            "girl",
            "sister",
            "she",
            "her",
            "hers",
            "daughter",
        ],
        "A": [
            "math",
            "algebra",
            "geometry",
            "calculus",
            "equations",
            "computation",
            "numbers",
            "addition",
        ],
        "B": [
            "poetry",
            "art",
            "dance",
            "literature",
            "novel",
            "symphony",
            "drama",
            "sculpture",
        ],
    },
    "Age Valence (T10)": {
        "X": [
            "young",
            "youth",
            "adolescent",
            "teenager",
            "child",
            "kid",
            "baby",
            "infant",
        ],
        "Y": [
            "old",
            "elderly",
            "aged",
            "senior",
            "ancient",
            "mature",
            "elder",
            "geriatric",
        ],
        "A": [
            "joy",
            "love",
            "peace",
            "wonderful",
            "pleasure",
            "beautiful",
            "happy",
            "lucky",
        ],
        "B": [
            "agony",
            "terrible",
            "horrible",
            "nasty",
            "evil",
            "war",
            "awful",
            "failure",
        ],
    },
}

results = {}
for test_name, word_sets in weat_tests.items():
    X = encode_with_template(word_sets["X"])
    Y = encode_with_template(word_sets["Y"])
    A = encode_with_template(word_sets["A"])
    B = encode_with_template(word_sets["B"])
    results[test_name] = weat_effect_size(X, Y, A, B)
Out[8]:
Console
WEAT Effect Sizes Across Tests
Test                      Effect Size (d)  Interpretation
------------------------------------------------------------
Gender-Career (T6)                 +1.145  large
Gender-Science (T8)                +0.892  large
Gender-Math (T7)                   -0.019  small
Age Valence (T10)                  +0.669  medium
Out[9]:
Visualization
Horizontal bar chart showing WEAT effect sizes across four standard bias tests.
WEAT effect sizes for four standard bias tests measured using the all-MiniLM-L6-v2 sentence encoder. Positive values indicate that the first target group (e.g., male names) associates more strongly with the first attribute set (e.g., career words) than the second target group. The dashed lines at plus and minus 0.8 mark the large-effect threshold from Cohen's conventions.

Each bar represents one WEAT test. The dashed gray lines mark the threshold for a large effect (∣d∣>0.8|d| > 0.8). Tests that cross this threshold indicate that the sentence encoder has internalized strong stereotypical associations from its training data.

To understand what drives the effect size, it helps to visualize the underlying cosine similarity matrix between target words and attribute words. The WEAT effect size is ultimately derived from the differences in these cosine values across rows:

Out[10]:
Visualization
Heatmap of cosine similarities between male names and career or family words.
Cosine similarities between male names (rows) and career vs. family words (columns). Warmer colors indicate higher similarity. A bias pattern appears as systematically warmer colors in the career half of the matrix.
Heatmap of cosine similarities between female names and career or family words.
Cosine similarities between female names (rows) and the same career vs. family words. Comparing the two heatmaps reveals the asymmetry that produces the positive WEAT effect size: male names show stronger geometric affinity with career words.

The two heatmaps show the cosine similarity matrix for male names (left) and female names (right). The white vertical line separates career words from family words. Comparing the left half (career) to the right half (family) across each heatmap shows the differential association pattern that WEAT quantifies.

Key Parameters

The key parameters for a WEAT/SEAT evaluation are:

  • n_permutations: Number of random permutations for the permutation test. More permutations yield more accurate p-values. Values of 5,000 to 10,000 are typical for publication-quality results.
  • normalize_embeddings: Whether to L2-normalize sentence embeddings before cosine similarity. This should always be True for cosine-based tests, as it ensures similarity values fall in [−1,1][-1, 1].
  • Sentence template: The template used to wrap target words for SEAT (e.g., "This is {}."). The choice of template can influence results; it is best to test multiple templates and report variability.
  • Effect size threshold: By convention, ∣d∣>0.8|d| > 0.8 is considered a large effect, ∣d∣>0.5|d| > 0.5 medium, and ∣d∣<0.5|d| < 0.5 small (following Cohen's conventions).

Interpreting WEAT and SEAT Results

A few cautions apply when interpreting association test results.

Effect size vs. statistical significance: A test can be statistically significant with a tiny effect size if the word sets are large. Conversely, a large effect size may not reach significance with small word sets. Always report both, and weight the effect size more heavily for practical interpretation.

The word list problem: WEAT results depend heavily on the chosen word lists. Different lists of "male names" or "career words" can yield different effect sizes. There is no canonical word list, so published results across papers are often not directly comparable. When running your own tests, document your word lists explicitly.

Effect size does not equal harm: A large WEAT effect size means the model's embedding space encodes an association. It does not tell you whether that association causes harm in a downstream task. A model could show strong gender-career WEAT effects but still assign credit scores fairly. Bias measurement is diagnostic, not automatically prescriptive.

Cosine similarity limitations: Cosine similarity measures the angle between vectors. In high-dimensional spaces, all vectors tend to have similar cosine similarities (a phenomenon called the concentration of measure), which can attenuate WEAT effect sizes. Newer embedding evaluation methods sometimes use other distance measures or operate in projected subspaces.

Representational vs. allocational harm: WEAT and SEAT measure representational harm, which refers to how a model represents groups in its internal geometry. This is distinct from allocational harm, which refers to concrete decisions that disadvantage certain groups. A model can show large WEAT effects without causing allocational harm if the biased associations are never activated in a way that affects downstream decisions. Conversely, allocational harm can occur in a classifier whose embedding associations look balanced but whose decision boundary happens to be poorly calibrated for one demographic.