import torch import torch.nn as nn import torch.optim as optim from monai.networks.nets import DenseNet121 from monai.transforms import Compose, LoadImage, EnsureChannelFirst, ToTensor from torch.utils.data import DataLoader, Dataset import os # 设定 CPU 运行 device = torch.device("cpu") train_root = r"E:\dataset\train" test_root = r"E:\dataset\test" # **遍历患者文件夹** class NiftiDataset(Dataset): def __init__(self, data_dir): self.data_files = [] for patient_folder in os.listdir(data_dir): patient_path = os.path.join(data_dir, patient_folder) if os.path.isdir(patient_path): for file in os.listdir(patient_path): if file.endswith(".nii.gz"): self.data_files.append(os.path.join(patient_path, file)) # **修正 LoadImage,确保正确读取 NIfTI** self.transform = Compose([ LoadImage(image_only=True, reader="NibabelReader"), # 指定 NIfTI 读取方式 EnsureChannelFirst(), # 确保 3D 数据格式正确 ToTensor() ]) def __len__(self): return len(self.data_files) def __getitem__(self, idx): img = self.transform(self.data_files[idx]) label = 1 if "positive" in self.data_files[idx] else 0 return img, torch.tensor(label, dtype=torch.long) # **添加 `if __name__ == "__main__":` 保护代码** if __name__ == "__main__": # **加载数据** train_dataset = NiftiDataset(train_root) test_dataset = NiftiDataset(test_root) # **Windows 下 `num_workers=0` 避免多进程问题** train_loader = DataLoader(train_dataset, batch_size=2, shuffle=True, num_workers=0, pin_memory=True) test_loader = DataLoader(test_dataset, batch_size=2, num_workers=0, pin_memory=True) # **定义 3D CNN 模型** model = DenseNet121(spatial_dims=3, in_channels=1, out_channels=2).to(device) # 改为 CPU 运行 criterion = nn.CrossEntropyLoss() optimizer = optim.Adam(model.parameters(), lr=0.001) # **训练 3D CNN** for epoch in range(10): model.train() for images, labels in train_loader: images, labels = images.to(device), labels.to(device) # 确保数据也在 CPU 上 optimizer.zero_grad() outputs = model(images) loss = criterion(outputs, labels) loss.backward() optimizer.step() print(f"✅ Epoch {epoch + 1} Loss: {loss.item():.4f}") # **保存模型** torch.save(model.state_dict(), "3d_cnn_model_cpu.pth") 这个代码出现错误EOFError: Compressed file ended before the end-of-stream marker was reached The above exception was the direct cause of the following exception:
时间: 2025-06-22 16:17:21 浏览: 11
<think>好的,我需要解决用户提出的EOFError问题。首先,用户提供的代码在加载NIfTI文件时遇到了错误。错误信息显示压缩文件在流结束标记之前就终止了,可能意味着文件损坏或者读取方式不正确。
首先,我应该回顾代码中处理数据加载的部分。用户使用了MONAI的LoadImage变换,并指定了NibabelReader来读取.nii.gz文件。这一步看起来是正确的,因为Nibabel支持压缩的NIfTI格式。不过,EOFError通常与文件读取不完整或文件损坏有关。
接下来,我需要检查数据本身是否有问题。用户的数据集路径是E:\dataset\train和test,每个患者文件夹中有.nii.gz文件。可能的文件损坏是导致这个错误的原因。用户可能需要检查这些文件是否能正常解压或用其他软件打开。
另外,代码中遍历患者文件夹的方式可能存在问题。例如,当遍历患者文件夹时,是否每个子目录都正确包含.nii.gz文件?有没有可能某些文件被误放或者命名不符合预期?特别是标签的判断部分,使用"positive"字符串来设定标签,这可能存在文件名不一致的情况,但暂时不影响文件读取的错误。
关于MONAI的LoadImage,虽然指定了reader为NibabelReader,但有时候不同的版本可能有不同的行为。需要确认MONAI和Nibabel的版本是否兼容,或者是否存在已知的bug。此外,用户提到使用CPU运行,排除了GPU相关的问题,但需要确保所有依赖库正确安装。
另一个可能的原因是内存不足,导致读取大文件时失败。但由于用户使用CPU且批处理大小为2,如果单个文件太大,可能会遇到问题。可以尝试减小批处理大小,或者检查是否有特别大的文件存在。
最后,建议用户添加异常处理来捕获具体是哪个文件出错。这可以通过在__getitem__方法中包裹try-except块来实现,当加载某个文件失败时,打印文件名,帮助定位问题。
总结可能的原因和解决步骤:
1. 检查.nii.gz文件是否完整,没有损坏。
2. 确保所有目标文件都在正确的路径下,并且命名符合预期。
3. 确认MONAI和Nibabel的版本兼容性。
4. 添加异常处理,定位具体出错的文件。
5. 尝试减小批处理大小,排除内存问题。
用户需要逐步排查这些可能性,首先从验证数据完整性开始,再检查代码逻辑和环境配置。</think>这个错误通常与读取压缩的NIfTI文件(.nii.gz)时文件损坏或读取方式不当有关。以下是逐步排查和解决方案:
---
### **第一步:检查.nii.gz文件完整性**
```python
# 在遍历文件时添加校验
class NiftiDataset(Dataset):
def __init__(self, data_dir):
self.data_files = []
for patient_folder in os.listdir(data_dir):
patient_path = os.path.join(data_dir, patient_folder)
if os.path.isdir(patient_path):
for file in os.listdir(patient_path):
if file.endswith(".nii.gz"):
file_path = os.path.join(patient_path, file)
# 检查文件是否可读
try:
with open(file_path, "rb") as f:
f.read(1024) # 尝试读取部分内容
except Exception as e:
print(f"❌ 文件损坏: {file_path}, 错误: {e}")
continue
self.data_files.append(file_path)
```
---
### **第二步:确认MONAI和Nibabel版本兼容性**
```bash
# 更新依赖库
pip install --upgrade monai nibabel
```
---
### **第三步:显式指定Nibabel的压缩格式处理**
```python
from monai.config import print_config
print_config() # 检查MONAI的Nibabel支持
# 修改LoadImage参数
self.transform = Compose([
LoadImage(image_only=True, reader="NibabelReader", dtype=np.float32),
EnsureChannelFirst(),
ToTensor()
])
```
---
### **第四步:在数据加载时捕获具体错误文件**
```python
class NiftiDataset(Dataset):
def __getitem__(self, idx):
file_path = self.data_files[idx]
try:
img = self.transform(file_path)
except Exception as e:
print(f"❌ 加载失败的文件: {file_path}")
raise RuntimeError(f"文件 {file_path} 加载失败") from e
label = 1 if "positive" in file_path else 0
return img, torch.tensor(label, dtype=torch.long)
```
---
### **第五步:验证单个文件加载**
```python
# 在代码中单独测试一个文件
test_file = r"E:\dataset\train\patient_001\image.nii.gz"
from monai.data import NibabelReader
reader = NibabelReader()
img = reader.read(test_file) # 手动测试文件是否可读
```
---
### **可能的问题根源**
1. **文件损坏**
检查是否所有.nii.gz文件均能通过`gunzip -t 文件名.nii.gz`验证解压。
2. **路径问题**
确保`patient_folder`和文件的路径拼接正确(尤其注意Windows的路径分隔符`\`是否被正确解析)。
3. **内存不足**
将`batch_size`从2降低到1,观察是否缓解问题。
---
### **最终建议**
优先使用上述**第一步**和**第四步**定位具体损坏文件,再逐步排除其他可能性。
阅读全文
相关推荐









