Memorization and Privacy in Language Models › Code Implementation: Measuring Memorization

Michael BrenndoerferMarch 11, 20266 min read
Language AI HandbookAll chapters
Part 60 of 67Safety and Security
Chapter 463Memorization and Privacy in Language Models › Code Implementation: Measuring Memorization
Reading section 5 of 12 · Code Implementation: Measuring Memorization · 6 minSection 5 of 12 · 6 min

Book contents

Section 5 of 12 · 6 min read

Memorization and Privacy in Language Models › Code Implementation: Measuring MemorizationOne section · Sections in this chapter5 / 12 ↓
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

We can implement a simplified version of memorization measurement. This example demonstrates the core idea: given a sequence and a model, estimate how much more likely the model is to produce the sequence given a natural prefix versus a generic prompt.

Setup

In[6]:
Code
from collections import Counter

import numpy as np

# We simulate a simple character-level language model for demonstration.
# In practice, you would use GPT-2 or similar via HuggingFace transformers.


class NgramLM:
    """Simple n-gram language model for memorization demonstration."""

    def __init__(self, n=3):
        self.n = n
        self.counts = Counter()
        self.total = Counter()

    def train(self, text):
        tokens = list(text)
        for i in range(len(tokens) - self.n + 1):
            gram = tuple(tokens[i : i + self.n])
            context = gram[:-1]
            self.counts[gram] += 1
            self.total[context] += 1

    def log_prob(self, sequence):
        """Compute log probability of a sequence given the model."""
        tokens = list(sequence)
        log_p = 0.0
        for i in range(self.n - 1, len(tokens)):
            gram = tuple(tokens[i - self.n + 1 : i + 1])
            context = gram[:-1]
            if self.total[context] == 0:
                log_p += -10.0  # heavy penalty for unseen context
            else:
                prob = self.counts[gram] / self.total[context]
                log_p += np.log(max(prob, 1e-10))
        return log_p

    def perplexity(self, sequence):
        """Compute perplexity of a sequence."""
        n_tokens = max(len(sequence) - self.n + 1, 1)
        return np.exp(-self.log_prob(sequence) / n_tokens)
In[7]:
Code
# Create a training corpus that contains some private-looking data
training_corpus = """
The quick brown fox jumps over the lazy dog.
The dog barked loudly at the passing cars.
Contact John Smith at john.smith@email.com or call 555-0123.
The fox ran through the forest near the old oak tree.
For billing inquiries, email billing@company.com or call 555-9876.
The lazy dog slept through the afternoon sunshine.
Contact John Smith at john.smith@email.com or call 555-0123.
The quick brown fox jumps over the lazy dog.
Contact John Smith at john.smith@email.com or call 555-0123.
The new policy takes effect on January 1st for all users.
"""

# Repeat the PII line multiple times to simulate training data repetition
repeated_pii = "Contact John Smith at john.smith@email.com or call 555-0123."
unique_fact = "The unique meeting was held at coordinate 47.6062N 122.3321W"

model = NgramLM(n=4)
model.train(training_corpus * 10)  # simulate larger training set
Out[8]:
Console
Perplexity on PII sequence (seen in training):    1.09
Perplexity on random sequence (unseen):          49648.41
Memorization ratio (higher = more memorized):   45522.5x

A much lower perplexity on the PII sequence compared to the random sequence indicates the model has memorized it. The memorization ratio quantifies this: a ratio of 10x means the model assigns 10 times higher probability to the known training sequence compared to an equally long random sequence. Ratios in the hundreds or thousands are common for frequently-repeated training examples in real language models, because the model has had many opportunities to reinforce the association between the prefix and the specific continuation.

The toy n-gram model here illustrates the principle, but the same logic applies to transformer-based language models. The mechanism differs (attention over token embeddings rather than character n-gram counts) but the core signal is identical: training data gets lower perplexity than non-training data, and the gap is larger for more frequently-seen examples.

Counting Repetitions and Memorization Risk

In[9]:
Code
def count_occurrences(corpus, pattern):
    """Count how many times a pattern appears in a corpus."""
    return len(re.findall(re.escape(pattern), corpus))


# Simulate checking memorization risk for different pieces of text
test_sequences = {
    "PII (email + phone)": "john.smith@email.com or call 555-0123",
    "Generic phrase": "The quick brown fox",
    "Unique coordinate": "47.6062N 122.3321W",
    "Generic greeting": "The lazy dog slept",
}

full_corpus = training_corpus * 10
occurrence_counts = {
    name: count_occurrences(full_corpus, seq)
    for name, seq in test_sequences.items()
}
Out[10]:
Console
Occurrence count and memorization risk assessment:
Sequence Type                   Count  Risk Level
-------------------------------------------------------
PII (email + phone)                30  HIGH
Generic phrase                     20  HIGH
Unique coordinate                   0  NONE
Generic greeting                   10  HIGH

Sequences that appear frequently in training data carry the highest memorization risk. The email address and phone number appear many times in this toy corpus and will be reliably reproducible by the model, while the unique coordinate may still be memorized but is harder to extract without the right prompt prefix. In a production audit, you would run this same analysis over your entire training corpus, flagging high-frequency PII patterns for deduplication or redaction before training begins.

Visualizing Memorization by Repetition Count

Out[11]:
Visualization
Line chart showing memorization probability vs repetition count, with PII showing higher rates than generic phrases.
Estimated memorization probability as a function of repetition count in training data. Sequences appearing more frequently are memorized at substantially higher rates, with template-style PII (contact information, addresses appearing in directory listings) showing consistently elevated memorization compared to generic prose due to its formulaic structure. Most of the memorization gain occurs in the range of 1 to 50 repetitions.

The log-scale x-axis reveals that most of the memorization gain occurs as repetition count grows from 1 to 50. After 100 repetitions, memorization probability is already high for both categories. Template PII shows consistently elevated rates because its formulaic structure makes it easier for the model to reproduce precisely. An email address has a fixed structure (local-part@domain.tld) that constrains the generation space. Once the model has seen enough examples, generating the correct email address becomes more probable than generating any alternative string with the same prefix.