{"record":{"id":"939187cc2d4d3232","repo":"d2l-ai/d2l-zh","slug":"len-centers-len-contexts-len-negatives-939187","errorCode":null,"errorMessage":"len(centers) == len(contexts) == len(negatives)","messagePattern":"len\\(centers\\) == len\\(contexts\\) == len\\(negatives\\)","errorType":"validation","errorClass":"AssertionError","httpStatus":null,"severity":"error","filePath":"d2l/paddle.py","lineNumber":2158,"sourceCode":"        contexts_negatives), d2l.tensor(masks), d2l.tensor(labels))\n\ndef load_data_ptb(batch_size, max_window_size, num_noise_words):\n    \"\"\"下载PTB数据集，然后将其加载到内存中\n\n    Defined in :numref:`subsec_word2vec-minibatch-loading`\"\"\"\n    num_workers = d2l.get_dataloader_workers()\n    sentences = read_ptb()\n    vocab = d2l.Vocab(sentences, min_freq=10)\n    subsampled, counter = subsample(sentences, vocab)\n    corpus = [vocab[line] for line in subsampled]\n    all_centers, all_contexts = get_centers_and_contexts(\n        corpus, max_window_size)\n    all_negatives = get_negatives(\n        all_contexts, vocab, counter, num_noise_words)\n\n    class PTBDataset(paddle.io.Dataset):\n        def __init__(self, centers, contexts, negatives):\n            assert len(centers) == len(contexts) == len(negatives)\n            self.centers = centers\n            self.contexts = contexts\n            self.negatives = negatives\n\n        def __getitem__(self, index):\n            return (self.centers[index], self.contexts[index],\n                    self.negatives[index])\n\n        def __len__(self):\n            return len(self.centers)\n\n    dataset = PTBDataset(all_centers, all_contexts, all_negatives)\n\n    data_iter = paddle.io.DataLoader(\n        dataset, batch_size=batch_size, shuffle=True, return_list=True,\n        collate_fn=batchify, num_workers=num_workers)\n    return data_iter, vocab\n","sourceCodeStart":2140,"sourceCodeEnd":2176,"githubUrl":"https://github.com/d2l-ai/d2l-zh/blob/e6b18ccea71451a55fcd861d7b96fddf2587b09a/d2l/paddle.py#L2140-L2176","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"# before\ncenters, contexts = get_centers_and_contexts(corpus, max_window_size)  # custom version, lengths drift\nnegatives = get_negatives(contexts, vocab, counter, num_noise_words)\ndataset = PTBDataset(centers, contexts, negatives)  # AssertionError\n\n# after\nassert len(centers) == len(contexts), 'centers/contexts must be built in lockstep'\nnegatives = get_negatives(contexts, vocab, counter, num_noise_words)  # yields exactly len(contexts) items\nassert len(negatives) == len(contexts)\ndataset = PTBDataset(centers, contexts, negatives)","handlingStrategy":"validation","validationCode":"all_centers, all_contexts = get_centers_and_contexts(corpus, max_window_size)\nall_negatives = get_negatives(all_contexts, vocab, counter, num_noise_words)\nassert len(all_centers) == len(all_contexts) == len(all_negatives), (\n    f'length mismatch: centers={len(all_centers)} contexts={len(all_contexts)} '\n    f'negatives={len(all_negatives)}')\ndataset = PTBDataset(all_centers, all_contexts, all_negatives)","typeGuard":"def is_aligned_ptb_data(centers, contexts, negatives) -> bool:\n    return (isinstance(centers, list) and isinstance(contexts, list)\n            and isinstance(negatives, list)\n            and len(centers) == len(contexts) == len(negatives))\n\n# usage\nassert is_aligned_ptb_data(all_centers, all_contexts, all_negatives), 'rebuild all three lists together'","tryCatchPattern":"try:\n    dataset = PTBDataset(all_centers, all_contexts, all_negatives)\nexcept AssertionError:\n    raise RuntimeError(\n        f'centers/contexts/negatives out of sync: '\n        f'{len(all_centers)}/{len(all_contexts)}/{len(all_negatives)}; '\n        f're-run get_centers_and_contexts and get_negatives from the same corpus') from None","preventionTips":["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."],"tags":["assertion","data-validation","word2vec","nlp","paddlepaddle"],"backgroundTag":null,"analyzedSha":"e6b18ccea71451a55fcd861d7b96fddf2587b09a","analyzedAt":"2026-08-14T20:05:26.414Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}