Memorization and Privacy in Language Models › Code Implementation: Measuring Memorization
Language AI HandbookAll chapters 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
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)# 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 setPerplexity 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
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()
}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

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.