d2l-ai/d2l-zh · error · AssertionError
len(centers) == len(contexts) == len(negatives)
Error message
len(centers) == len(contexts) == len(negatives)
What it means
An AssertionError raised in the PTBDataset constructor for the word2vec (skip-gram with negative sampling) data pipeline. It verifies that the centers, contexts, and negatives lists produced by get_centers_and_contexts and get_negatives are element-aligned: every center word index i must have a matching contexts[i] and negatives[i]. Because negatives are generated per-context by sampling from the corpus counter with a population equal to the number of context words, any mismatch means the data-generation steps were not run against the same corpus/vocab or were manually edited out of sync.
Source
Thrown at d2l/torch.py:2149
contexts_negatives), d2l.tensor(masks), d2l.tensor(labels))
def load_data_ptb(batch_size, max_window_size, num_noise_words):
"""下载PTB数据集,然后将其加载到内存中
Defined in :numref:`subsec_word2vec-minibatch-loading`"""
num_workers = d2l.get_dataloader_workers()
sentences = read_ptb()
vocab = d2l.Vocab(sentences, min_freq=10)
subsampled, counter = subsample(sentences, vocab)
corpus = [vocab[line] for line in subsampled]
all_centers, all_contexts = get_centers_and_contexts(
corpus, max_window_size)
all_negatives = get_negatives(
all_contexts, vocab, counter, num_noise_words)
class PTBDataset(torch.utils.data.Dataset):
def __init__(self, centers, contexts, negatives):
assert len(centers) == len(contexts) == len(negatives)
self.centers = centers
self.contexts = contexts
self.negatives = negatives
def __getitem__(self, index):
return (self.centers[index], self.contexts[index],
self.negatives[index])
def __len__(self):
return len(self.centers)
dataset = PTBDataset(all_centers, all_contexts, all_negatives)
data_iter = torch.utils.data.DataLoader(
dataset, batch_size, shuffle=True,
collate_fn=batchify, num_workers=num_workers)
return data_iter, vocab
View on GitHub (pinned to e6b18ccea7)
Solutions
- Regenerate all three arrays in one pass: centers, contexts = get_centers_and_contexts(corpus, max_window_size) then negatives = get_negatives(contexts, vocab, counter, num_noise_words) so they stay aligned.
- If building the dataset manually, verify lengths before construction: assert len(all_centers) == len(all_contexts) == len(all_negatives) in your own code with a descriptive message.
- If you modified get_centers_and_contexts (e.g. custom window logic), audit get_negatives: it must append num_noise_words samples once per context token, keeping the per-center nesting.
- Check that you did not flatten negatives: each element of all_negatives must itself be a list whose total count equals len(all_contexts[i]) * num_noise_words.
Example fix
// before (manual construction, lists out of sync) dataset = PTBDataset(all_centers, all_contexts, all_negatives) # AssertionError // after (regenerate together, then construct) all_centers, all_contexts = get_centers_and_contexts(corpus, max_window_size) all_negatives = get_negatives(all_contexts, vocab, counter, num_noise_words) assert len(all_centers) == len(all_contexts) == len(all_negatives) dataset = PTBDataset(all_centers, all_contexts, all_negatives)
Defensive patterns
Strategy: validation
Validate before calling
centers, contexts = get_centers_and_contexts(corpus, max_window_size)
negatives = get_negatives(contexts, vocab, counter, num_noise_words)
if not (len(centers) == len(contexts) == len(negatives)):
raise ValueError(
f'misaligned arrays: centers={len(centers)} '
f'contexts={len(contexts)} negatives={len(negatives)}')
dataset = PTBDataset(centers, contexts, negatives) Type guard
def is_aligned_ptb(centers, contexts, negatives) -> bool:
return (isinstance(centers, list) and isinstance(contexts, list)
and isinstance(negatives, list)
and len(centers) == len(contexts) == len(negatives)) Prevention
- Always generate centers/contexts/negatives in one code path from the same corpus and vocab; never mix arrays across runs.
- When customizing get_negatives, keep one nested list per center (len(negatives[i]) == num_noise_words * len(contexts[i])).
- Add your own length check with a descriptive ValueError before constructing PTBDataset so the failure names the mismatched lengths.
When it happens
Trigger: Calling load_data_ptb (the function containing PTBDataset) after the upstream arrays got out of sync: passing all_contexts from one corpus run but all_negatives from another; custom re-implementations of get_negatives that return a flat list of K negatives instead of one list per center; calling PTBDataset(all_centers, all_contexts, all_negatives) directly with hand-built lists of different lengths.
Common situations: Users copying the sec_word2vec-training notebook code into their own scripts and mutating all_contexts (e.g. filtering rare tokens) without regenerating negatives; changing max_window_size or num_noise_words between runs while reusing cached arrays; a subclass of PTBDataset that slices one list but not the others.
Related errors
- f"{name} 不存在于 {DATA_HUB}"
- f"{name} 不存在于 {DATA_HUB}"
- train_loss < 0.5
- train_acc <= 1 and train_acc > 0.7
- test_acc <= 1 and test_acc > 0.7
AI-assisted analysis of d2l-ai/d2l-zh@e6b18ccea7 (2026-08-14).
Data as JSON: /api/errors/d4d4013635ef6b2d.
Report an issue: GitHub.