d2l-ai/d2l-zh · error · AssertionError
len(centers) == len(contexts) == len(negatives)
Error message
len(centers) == len(contexts) == len(negatives)
What it means
This is an assertion inside PTBDataset.__init__ (d2l/paddle.py:2158) enforcing that the centers, contexts and negatives lists passed to the word2vec-negative-sampling dataset all have the same length. The dataset is indexed positionally (__getitem__ returns the i-th element of each list), so unequal lengths would silently truncate or IndexError during training. The library throws at construction time to fail fast instead of mid-epoch.
Source
Thrown at d2l/paddle.py:2158
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(paddle.io.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 = paddle.io.DataLoader(
dataset, batch_size=batch_size, shuffle=True, return_list=True,
collate_fn=batchify, num_workers=num_workers)
return data_iter, vocab
View on GitHub (pinned to e6b18ccea7)
Solutions
- Check the three lengths right after they are produced (print(len(all_centers), len(all_contexts), len(all_negatives))) to find which list diverges and fix its producer (get_centers_and_contexts must append to centers and contexts in lockstep; get_negatives must yield exactly len(all_contexts) lists).
- If you truncated one list for a quick experiment, apply the same slice to all three: PTBDataset(all_centers[:N], all_contexts[:N], all_negatives[:N]).
- If you wrote a custom negative sampler, make it a generator that runs exactly len(all_contexts) iterations and never breaks out early or swallows exceptions.
- If a stale notebook state is suspected, restart the kernel / re-run the cells from read_ptb() down so all lists are rebuilt consistently.
- If you only need the dataset, use the canonical d2l.load_data_ptb(...) helper from the installed d2l package instead of the hand-inlined class, so the pipeline that produces the three lists stays matched.
Example fix
# before centers, contexts = get_centers_and_contexts(corpus, max_window_size) # custom version, lengths drift negatives = get_negatives(contexts, vocab, counter, num_noise_words) dataset = PTBDataset(centers, contexts, negatives) # AssertionError # after assert len(centers) == len(contexts), 'centers/contexts must be built in lockstep' negatives = get_negatives(contexts, vocab, counter, num_noise_words) # yields exactly len(contexts) items assert len(negatives) == len(contexts) dataset = PTBDataset(centers, contexts, negatives)
Defensive patterns
Strategy: validation
Validate before calling
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), (
f'length mismatch: centers={len(all_centers)} contexts={len(all_contexts)} '
f'negatives={len(all_negatives)}')
dataset = PTBDataset(all_centers, all_contexts, all_negatives) Type guard
def is_aligned_ptb_data(centers, contexts, negatives) -> bool:
return (isinstance(centers, list) and isinstance(contexts, list)
and isinstance(negatives, list)
and len(centers) == len(contexts) == len(negatives))
# usage
assert is_aligned_ptb_data(all_centers, all_contexts, all_negatives), 'rebuild all three lists together' Try / catch
try:
dataset = PTBDataset(all_centers, all_contexts, all_negatives)
except AssertionError:
raise RuntimeError(
f'centers/contexts/negatives out of sync: '
f'{len(all_centers)}/{len(all_contexts)}/{len(all_negatives)}; '
f're-run get_centers_and_contexts and get_negatives from the same corpus') from None Prevention
- Always build centers and contexts in the same loop iteration so they grow in lockstep; never append to one without the other.
- Treat get_negatives as consuming all_contexts: its output length must equal len(all_contexts); add an assert right after the call.
- When subsampling a dataset for experiments, slice all three lists with the same index range.
- After interrupting data-preparation cells, re-run the whole preparation chain rather than reusing partially built lists.
- Keep a single variable holding the (centers, contexts, negatives) tuple once produced instead of rebinding the names separately in notebooks.
When it happens
Trigger: Calling PTBDataset(all_centers, all_contexts, all_negatives) (or the enclosing d2l.load_data_ptb helper) after replacing or modifying get_centers_and_contexts / get_negatives so the returned lists diverge: e.g., a custom get_centers_and_contexts that appends centers without matching contexts, a get_negatives that returns fewer noise-word lists than len(all_contexts) (its while-loop samples K negatives per context, so any early break/exception swallow truncates it), or slicing one list (all_centers[:N]) but not the others.
Common situations: Users editing the book's code to experiment with custom corpora, window sizes, or subsampling; interrupting (Ctrl-C) get_negatives partway and reusing a partially built list; passing subsampled data of a different shape; notebook re-runs where a stale variable of a different length is picked up; upgrading d2l versions where the data-loading helpers changed signature but user code kept the old shape.
Related errors
- len(centers) == len(contexts) == len(negatives)
- train_loss < 0.5
- train_acc <= 1 and train_acc > 0.7
- test_acc <= 1 and test_acc > 0.7
- f"{name} 不存在于 {DATA_HUB}"
AI-assisted analysis of d2l-ai/d2l-zh@e6b18ccea7 (2026-08-14).
Data as JSON: /api/errors/939187cc2d4d3232.
Report an issue: GitHub.