我处于一种奇怪的情况下,为了使我的包被正确调用,需要在调用脚本旁边以及在使用该文件的包文件夹中放置一个文件(models.py
)。 为了更清楚一点,这是程序包组织的样子:
-FV_dir
---__init__.py
---F_V.py
---models.py
---utils.py
---service_utils.py
---subModule1_dir
----__init__.py
----detector.py
----utils.py
----subdir1
--- etc
----subdir2
--- etc
----subdir3
整个程序包都放在site-packages中,因此它在整个系统范围内都可用。并且有一个使用此程序包的用户脚本,如下所示:service_client.py
:
from FV.service_utils import ServiceCore
from FV.utils import a_helper_function
def run():
service = ServiceCore()
service.run()
if __name__ == "__main__":
run()
ServiceCore
本身使用F_V.py
,这是这里的主要模块。F_V
模块本身使用它旁边的models.py
和utils.py
: F_V.py
:
from FV.utils import func1, func2
from FV.models import model1, model2, model3
...
现在的问题是,如果models.py
不在客户端代码(service_client.py
)旁边,它只会抱怨找不到模块:这是在这种情况下出现的示例错误:
└─19146 /home/user1/anaconda3/bin/python3 /home/user1/Documents/service_client.py
Mar 17 19:22:54 ubuntu python3[19146]: self.fv = FaceVerification(\*cfg['Face_Verification']['ARGS'])
Mar 17 19:22:54 ubuntu python3[19146]: File "/home/user1/anaconda3/lib/python3.7/site-packages/FV/F_V.py", line 58, in __init__
Mar 17 19:22:54 ubuntu python3[19146]: self._init_model()
Mar 17 19:22:54 ubuntu python3[19146]: File "/home/user1/anaconda3/lib/python3.7/site-packages/FV/F_V.py", line 80, in _init_model
Mar 17 19:22:54 ubuntu python3[19146]: checkpoint = torch.load(self.model_checkpoint_path, map_location=torch.device('cpu'))
Mar 17 19:22:54 ubuntu python3[19146]: File "/home/user1/anaconda3/lib/python3.7/site-packages/torch/serialization.py", line 529, in
Mar 17 19:22:54 ubuntu python3[19146]: return _legacy_load(opened_file, map_location, pickle_module, \*pickle_load_args)
Mar 17 19:22:54 ubuntu python3[19146]: File "/home/user1/anaconda3/lib/python3.7/site-packages/torch/serialization.py", line 702, in
Mar 17 19:22:54 ubuntu python3[19146]: result = unpickler.load()
Mar 17 19:22:54 ubuntu python3[19146]: ModuleNotFoundError: No module named 'models'
如果我删除F_V.py旁边的models.py,显然F_V.py会抱怨,因为它直接使用它:
└─19216 /home/user1/anaconda3/bin/python3 /home/user1/Documents/fv_service_linux.py
Mar 17 19:27:33 ubuntu systemd[1532]: Started FV Service.
Mar 17 19:27:34 ubuntu python3[19216]: Traceback (most recent call last):
Mar 17 19:27:34 ubuntu python3[19216]: File "/home/user1/Documents/fv_service_linux.py", line 83, in <module>
Mar 17 19:27:34 ubuntu python3[19216]: from FV.service_utils import ServiceCore
Mar 17 19:27:34 ubuntu python3[19216]: File "/home/user1/anaconda3/lib/python3.7/site-packages/FV/service_utils.py", line 21, in <mod
Mar 17 19:27:34 ubuntu python3[19216]: from FV.F_V import FaceVerification
Mar 17 19:27:34 ubuntu python3[19216]: File "/home/user1/anaconda3/lib/python3.7/site-packages/FV/F_V.py", line 17, in <module>
Mar 17 19:27:34 ubuntu python3[19216]: from FV.models import resnet18, resnet50, resnet101
Mar 17 19:27:34 ubuntu python3[19216]: ModuleNotFoundError: No module named 'FV.models'
因此,使它起作用的唯一方法是在客户端代码旁边也要有“ models.py”。我不明白为什么会这样,因为客户端代码甚至没有直接与models.py
交互。 我在这里想念什么?
在F_V.py
中,我使用Pytorch
并加载一个预训练的模型。我认为这无关紧要,关于Python的包装我做错了,但是事实证明,这确实是罪魁祸首。阅读答案以获取更多信息。
问题来源:stackoverflow
实际上恰好是一个与Pytorch相关的问题,其中整个问题是由在F_V.py中加载模型时通过此简单命令引起的:
if self.device == 'cpu':
checkpoint = torch.load(self.model_checkpoint_path, map_location=torch.device('cpu'))
else:
checkpoint = torch.load(self.model_checkpoint_path)
# the culprit!
self.model = checkpoint['model'].module
这种存储和加载模型的方式非常糟糕,预先训练的模型最初是由nn.DataParallel和保存它们的人包装的,它是这样的:
def save_checkpoint(epoch, epochs_since_improvement, model, metric_fc, optimizer, acc, is_best):
print('saving checkpoint ...')
state = {'epoch': epoch,
'epochs_since_improvement': epochs_since_improvement,
'acc': acc,
'model': model,
'metric_fc': metric_fc,
'optimizer': optimizer}
# filename = 'checkpoint_' + str(epoch) + '_' + str(loss) + '.tar'
filename = 'checkpoint.tar'
torch.save(state, filename)
# If this checkpoint is the best so far, store a copy so it doesn't get overwritten by a worse checkpoint
if is_best:
torch.save(state, 'BEST_checkpoint.tar')
如您所见,他在state_dict中使用了整个模型('model':model)并将其保存下来。他应该使用过state_dict()。 这很不好,因为在要使用此模型的任何地方,必须始终保留相同的文件/目录结构层次结构/所有内容。 正如您所看到的,我们受到了这一影响。所有的客户端服务都依赖于
models.py`,并且需要它们在它们甚至不使用的情况下与它们相邻。 因此,起初我认为为了解决该问题,我们必须自己实例化模型,然后手动加载权重。
if self.model_name == 'r18':
self.model = resnet18(pretrained=False, use_se=use_se)
elif self.model_name == 'r50':
self.model = resnet50(pretrained=False, use_se=use_se)
elif self.model_name == 'r101':
self.model = resnet101(pretrained=False, use_se=use_se)
else:
raise Exception(f"Model name: '{self.model_name}' is not recognized.")
# load the model weights
self.model.load_state_dict(checkpoint['model'].module.state_dict())
注意,由于该模型最初是nn.DataParallel模型,因此为了访问模型本身,我们使用.module属性,然后使用state_dict()模型初始化模型,并希望这可以解决问题。 但是,似乎并非如此,并且由于以这种方式保存了模型,因此似乎没有办法以这种方式摆脱这种依赖性。而是将模型转换为割炬脚本,然后保存模型。 这样,您就可以摆脱所有的麻烦。
尝试将模型转换为“火炬脚本”,然后改用它:
def convert_model(model, input=torch.tensor(torch.rand(size=(1,3,112,112)))):
model = torch.jit.trace(self.model, input)
torch.jit.save(model,'/home/Rika/Documents/models/model.tjm')
然后加载此版本:
# load the model
self.model = torch.jit.load('/home/Rika/Documents/models/model.tjm')
只需再次保存模型的state_dict()并使用它即可:我自己最终做了:
self.model = checkpoint['model'].module
# create the new checkpoint based on what you need
torch.save({'state_dict' : self.model.state_dict(), 'use_se':True},
'/home/Rika/Documents/BEST_checkpoint_r18_2.tar')
and started using the new checkpoint and so far everything has been good
回答来源:stackoverflow
版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。