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

  1. 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.
  2. 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.
  3. 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.
  4. 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

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


AI-assisted analysis of d2l-ai/d2l-zh@e6b18ccea7 (2026-08-14). Data as JSON: /api/errors/d4d4013635ef6b2d. Report an issue: GitHub.