Python中Multiprocessing freeze_support()错误求助(PyCharm运行深度学习代码)
问题
本人是深度学习新手,此前一直使用Google Colab运行深度学习模型。近期在PyCharm中运行项目名为model、文件名为model.py的代码时,出现Multiprocessing freeze_support()错误。代码未定义main函数,直接运行,相关代码及报错信息如下:
运行代码
from __future__ import print_function, division import torch import torch.nn as nn import torch.optim as optim from torch.optim import lr_scheduler import torch.backends.cudnn as cudnn import numpy as np import torchvision from torchvision import datasets, models, transforms import matplotlib.pyplot as plt import time import os import copy cudnn.benchmark = True plt.ion() # interactive mode data_transforms = { 'train': transforms.Compose([ transforms.RandomResizedCrop(224), transforms.RandomHorizontalFlip(), transforms.ToTensor(), transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) ]), 'val': transforms.Compose([ transforms.Resize(256), transforms.CenterCrop(224), transforms.ToTensor(), transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) ]), } data_dir = '.\hymenoptera_data' image_datasets = {x: datasets.ImageFolder(os.path.join(data_dir, x), data_transforms[x]) for x in ['train', 'val']} dataloaders = {x: torch.utils.data.DataLoader(image_datasets[x], batch_size=4, shuffle=True, num_workers=4) for x in ['train', 'val']} dataset_sizes = {x: len(image_datasets[x]) for x in ['train', 'val']} class_names = image_datasets['train'].classes device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") ##visualize the model def imshow(inp, title=None): """Imshow for Tensor.""" inp = inp.numpy().transpose((1, 2, 0)) mean = np.array([0.485, 0.456, 0.406]) std = np.array([0.229, 0.224, 0.225]) inp = std * inp + mean inp = np.clip(inp, 0, 1) plt.imshow(inp) if title is not None: plt.title(title) plt.pause(0.001) # pause a bit so that plots are updated inputs, classes = next(iter(dataloaders['train'])) out = torchvision.utils.make_grid(inputs) imshow(out, title=[class_names[x] for x in classes])
报错信息
(venv) PS C:\Users\prasa\PycharmProjects\model> python model.py Traceback (most recent call last): File "<string>", line 1, in <module> File "C:\python 39\lib\multiprocessing\spawn.py", line 116, in spawn_main exitcode = _main(fd, parent_sentinel) File "C:\python 39\lib\multiprocessing\spawn.py", line 125, in _main prepare(preparation_data) File "C:\python 39\lib\multiprocessing\spawn.py", line 236, in prepare _fixup_main_from_path(data['init_main_from_path']) File "C:\python 39\lib\multiprocessing\spawn.py", line 287, in _fixup_main_from_path main_content = runpy.run_path(main_path, File "C:\python 39\lib\runpy.py", line 268, in run_path return _run_module_code(code, init_globals, run_name, File "C:\python 39\lib\runpy.py", line 97, in _run_module_code ... The "freeze_support()" line can be omitted if the program is not going to be frozen to produce an executable.
疑问
- 直接运行无main函数的Python代码是否合规?
- 该如何解决这个错误?
解答
1. 无main函数的Python代码是否合规?
完全合规。Python允许直接执行脚本里的顶层代码,不需要强制定义main函数。但这种写法在涉及多进程、模块导入等场景时容易出现问题,比如你遇到的多进程启动错误,因此推荐用if __name__ == '__main__':包裹顶层执行代码,这是Python社区的最佳实践,既能避免模块被导入时重复执行代码,也能解决多进程在Windows系统下的启动问题。
2. 解决Multiprocessing freeze_support()错误的方法
这个错误出现在Windows系统下,原因是Windows的多进程通过spawn方式创建子进程时,会重新导入主模块并执行所有顶层代码,导致重复初始化甚至死锁。有两种解决方法:
方法一:用if __name__ == '__main__':包裹执行代码
把所有需要直接运行的代码(除了导入、函数定义、变量初始化等不会触发执行的部分)放到这个判断里,同时可以加上freeze_support()(非打包场景可省略,但加上更稳妥)。修改后的代码如下:
from __future__ import print_function, division import torch import torch.nn as nn import torch.optim as optim from torch.optim import lr_scheduler import torch.backends.cudnn as cudnn import numpy as np import torchvision from torchvision import datasets, models, transforms import matplotlib.pyplot as plt import time import os import copy from multiprocessing import freeze_support # 导入freeze_support cudnn.benchmark = True plt.ion() # interactive mode data_transforms = { 'train': transforms.Compose([ transforms.RandomResizedCrop(224), transforms.RandomHorizontalFlip(), transforms.ToTensor(), transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) ]), 'val': transforms.Compose([ transforms.Resize(256), transforms.CenterCrop(224), transforms.ToTensor(), transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) ]), } def imshow(inp, title=None): """Imshow for Tensor.""" inp = inp.numpy().transpose((1, 2, 0)) mean = np.array([0.485, 0.456, 0.406]) std = np.array([0.229, 0.224, 0.225]) inp = std * inp + mean inp = np.clip(inp, 0, 1) plt.imshow(inp) if title is not None: plt.title(title) plt.pause(0.001) # pause a bit so that plots are updated if __name__ == '__main__': freeze_support() # Windows下多进程必备 data_dir = '.\hymenoptera_data' image_datasets = {x: datasets.ImageFolder(os.path.join(data_dir, x), data_transforms[x]) for x in ['train', 'val']} dataloaders = {x: torch.utils.data.DataLoader(image_datasets[x], batch_size=4, shuffle=True, num_workers=4) for x in ['train', 'val']} dataset_sizes = {x: len(image_datasets[x]) for x in ['train', 'val']} class_names = image_datasets['train'].classes device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") # 可视化部分 inputs, classes = next(iter(dataloaders['train'])) out = torchvision.utils.make_grid(inputs) imshow(out, title=[class_names[x] for x in classes])
方法二:临时关闭多进程加载数据
如果不想修改代码结构,可以把DataLoader里的num_workers设为0,这样就不会启用多进程加载数据,自然不会触发这个错误:
dataloaders = {x: torch.utils.data.DataLoader(image_datasets[x], batch_size=4, shuffle=True, num_workers=0) # num_workers改为0 for x in ['train', 'val']}
但这种方法会降低数据加载速度,仅适合临时调试,不推荐在训练大模型时使用。
内容的提问来源于stack exchange,提问作者Prasanjeet Panda
相关产品推荐
相关产品推荐

