同venv配置运行PyTorch神经网络 一台正常一台报索引越界错误
问题背景
- 环境配置:通过venv创建虚拟环境,基于PyTorch与JupyterLab搭建神经网络训练环境;两台PC均通过Microsoft Store安装Python 3.7.9,通过云服务同步全量
.ipynb代码文件与数据集 - 异常现象:PC1运行代码全程无报错,PC2在模型训练阶段持续抛出
list index out of range错误 - 已尝试的无效排查操作:
- 直接将PC1创建完成的venv虚拟环境通过云同步到PC2,激活后通过jupyter-lab运行对应文件,仍触发相同错误
- 在PC1执行
pip freeze > requirements.txt导出全量依赖清单,在PC2基于该清单创建全新虚拟环境后运行代码,错误依旧存在
完整报错栈
--------------------------------------------------------------------------- IndexError Traceback (most recent call last) ~\AppData\Local\Temp\ipykernel_9608\2329219183.py in <module> 10 val_dl = test_loader, 11 epochs=num_epochs, ---> 12 device='cpu') ~\AppData\Local\Temp\ipykernel_9608\132402798.py in train(model, optimizer, loss_fn, train_dl, val_dl, epochs, device) 27 num_train_examples = 0 28 ---> 29 for batch in train_dl: 30 31 optimizer.zero_grad() d:\<CLOUD>\<SUBFOLDER>\julab\lib\site-packages\torch\utils\data\dataloader.py in __next__(self) 650 # TODO(https://github.com/pytorch/pytorch/issues/76750) 651 self._reset() # type: ignore[call-arg] ---> 652 data = self._next_data() 653 self._num_yielded += 1 654 if self._dataset_kind == _DatasetKind.Iterable and \ d:\<CLOUD>\<SUBFOLDER>\julab\lib\site-packages\torch\utils\data\dataloader.py in _next_data(self) 690 def _next_data(self): 691 index = self._next_index() # may raise StopIteration ---> 692 data = self._dataset_fetcher.fetch(index) # may raise StopIteration 693 if self._pin_memory: 694 data = _utils.pin_memory.pin_memory(data, self._pin_memory_device) d:\<CLOUD>\<SUBFOLDER>\julab\lib\site-packages\torch\utils\data\_utils\fetch.py in fetch(self, possibly_batched_index) 47 def fetch(self, possibly_batched_index): 48 if self.auto_collation: ---> 49 data = [self.dataset[idx] for idx in possibly_batched_index] 50 else: 51 data = self.dataset[possibly_batched_index] d:\<CLOUD>\<SUBFOLDER>\julab\lib\site-packages\torch\utils\data\_utils\fetch.py in <listcomp>(.0) 47 def fetch(self, possibly_batched_index): 48 if self.auto_collation: ---> 49 data = [self.dataset[idx] for idx in possibly_batched_index] 50 else: 51 data = self.dataset[possibly_batched_index] d:\<CLOUD>\<SUBFOLDER>\julab\lib\site-packages\torch\utils\data\dataset.py in __getitem__(self, idx) 288 if isinstance(idx, list): 289 return self.dataset[[self.indices[i] for i in idx]] ---> 290 return self.dataset[self.indices[idx]] 291 292 def __len__(self): ~\AppData\Local\Temp\ipykernel_9608\2122586536.py in __getitem__(self, index) 32 33 def __getitem__(self, index): ---> 34 image_name = os.path.join(self.image_dir, self.image_files[index]) 35 image = PIL.Image.open(image_name) 36 label = self.data[index] IndexError: list index out of range
依赖清单(PC2导出)
anyio==3.6.1 argon2-cffi==21.3.0 argon2-cffi-bindings==21.2.0 attrs==21.4.0 Babel==2.10.3 backcall==0.2.0 beautifulsoup4==4.11.1 bleach==5.0.1 certifi==2022.6.15 cffi==1.15.1 charset-normalizer==2.1.0 colorama==0.4.5 cycler==0.11.0 debugpy==1.6.0 decorator==5.1.1 defusedxml==0.7.1 dill==0.3.5.1 entrypoints==0.4 fastjsonschema==2.15.3 fonttools==4.33.3 idna==3.3 importlib-metadata==4.12.0 importlib-resources==5.8.0 ipykernel==6.15.0 ipython==7.34.0 ipython-genutils==0.2.0 jedi==0.18.1 Jinja2==3.1.2 joblib==1.1.0 json5==0.9.8 jsonschema==4.6.1 jupyter-client==7.3.4 jupyter-core==4.10.0 jupyter-server==1.18.0 jupyterlab==3.4.3 jupyterlab-pygments==0.2.2 jupyterlab-server==2.14.0 kiwisolver==1.4.3 MarkupSafe==2.1.1 matplotlib==3.5.2 matplotlib-inline==0.1.3 mistune==0.8.4 nbclassic==0.4.0 nbclient==0.6.6 nbconvert==6.5.0 nbformat==5.4.0 nest-asyncio==1.5.5 notebook-shim==0.1.0 numpy==1.21.6 packaging==21.3 pandas==1.3.5 pandocfilters==1.5.0 parso==0.8.3 pickleshare==0.7.5 Pillow==9.2.0 prometheus-client==0.14.1 prompt-toolkit==3.0.30 psutil==5.9.1 pycparser==2.21 Pygments==2.12.0 pyparsing==3.0.9 pyrsistent==0.18.1 python-dateutil==2.8.2 pytz==2022.1 pywin32==304 pywinpty==2.0.5 pyzmq==23.2.0 requests==2.28.1 scikit-learn==1.0.2 scipy==1.7.3 Send2Trash==1.8.0 six==1.16.0 sklearn==0.0 sniffio==1.2.0 soupsieve==2.3.2.post1 terminado==0.15.0 threadpoolctl==3.1.0 tinycss2==1.1.1 torch==1.12.0 torchsummary==1.5.1 torchvision==0.13.0 tornado==6.1 traitlets==5.3.0 typing_extensions==4.3.0 urllib3==1.26.9 wcwidth==0.2.5 webencodings==0.5.1 websocket-client==1.3.3 zipp==3.8.0
问题根因
这个错误和Python环境、依赖版本、代码逻辑没有关系,核心是PC2本地的数据集文件和PC1不一致:
- 从报错栈可以直接定位异常触发点:自定义Dataset的
__getitem__方法访问self.image_files[index]时索引越界,说明存储图片文件名的self.image_files列表长度,小于Dataset定义的总样本长度(从代码逻辑看总样本长度是按标注列表self.data的长度返回的) - 最常见的诱因是云盘默认开启「按需同步/文件随选」功能:PC2上的数据集图片没有完全下载到本地磁盘,仅保留了云端占位符,遍历图片目录生成
self.image_files时,实际统计到的有效图片数量远小于PC1本地的数量 - 少数情况是PC2的图片目录下混入了系统自动生成的隐藏文件(如
Thumbs.db、desktop.ini)、云盘临时缓存文件,而代码生成self.image_files时没有做格式过滤,导致列表长度、排序和PC1端不匹配 - 直接跨设备同步venv虚拟环境本身就是错误操作:不同设备的系统路径、底层动态链接库存在差异,同步过来的venv本身就可能存在隐性异常,但不是触发本次索引错误的原因
解决方案
- 第一步:先校验两边数据集一致性,在两台PC的Jupyter中分别运行以下代码,对比输出的文件数是否一致:
import os # 替换为实际的图片目录路径 image_dir = r"你的图片文件夹本地绝对路径" all_files = os.listdir(image_dir) print(f"目录下总文件数:{len(all_files)}") # 过滤指定后缀的图片文件,按需调整后缀列表 image_files = [f for f in all_files if f.lower().endswith(('.png', '.jpg', '.jpeg', '.bmp'))] print(f"有效图片文件数:{len(image_files)}") # 取消注释替换为实际标注变量名,对比标注数量和图片数量是否相等 # print(f"标注样本数:{len(data)}")
- 第二步:修复云同步问题
- 关闭云盘的「按需同步/文件随选」功能,找到数据集对应的本地同步文件夹,右键选择「始终保留在此设备上」,等待所有文件100%下载完成(确认所有图片文件的大小和PC1一致)后再运行代码
- 后续不要跨设备同步venv文件夹,统一通过
requirements.txt在新设备上新建虚拟环境即可
- 第三步:优化Dataset代码逻辑避免同类问题
- 生成
self.image_files列表时增加后缀过滤,只保留合法图片格式的文件,排除系统隐藏文件、临时文件的干扰 - 对
self.image_files列表显式调用.sort()做排序,避免不同设备上os.listdir返回的默认文件排序不一致,导致文件名和标签错位 - 在Dataset的
__init__方法中增加校验:如果len(self.image_files)和标注列表长度不一致,直接抛出明确的错误提示,不用等训练阶段才触发索引越界
- 生成
内容的提问来源于stack exchange,提问作者femonk
相关产品推荐
相关产品推荐

