在Flask应用程序中尝试反序列化模型时出现了ModuleNotFoundError错误。
在Flask应用程序中尝试反序列化模型时出现了ModuleNotFoundError错误。
Python版本:3.6.9
我使用pickle
将机器学习模型存储到文件中,当我尝试使用Flask运行预测时,它失败并显示ModuleNotFoundError: No module named \'predictors\'
。我该如何修复此错误,使其无论是通过Flask还是通过Python命令(例如python predict_edu.py
)运行预测时都能识别我的模型?
这是我的文件结构:
- video_discovery __init__.py - data_science - model - __init__.py - predict_edu.py - predictors.py - train_model.py
这是我的predict_edu.py文件:
import pickle with open('model', 'rb') as f: bow_model = pickle.load(f)
这是我的predictors.py文件:
from sklearn.base import TransformerMixin # Basic function to clean the text def clean_text(text): # Removing spaces and converting text into lowercase return text.strip().lower() # Custom transformer using spaCy class predictor_transformer(TransformerMixin): def transform(self, X, **transform_params): # Cleaning Text return [clean_text(text) for text in X] def fit(self, X, y=None, **fit_params): return self def get_params(self, deep=True): return {}
这是我训练模型的方式:
python data_science/train_model.py
这是我的train_model.py文件:
from predictors import predictor_transformer # pipeline = Pipeline([("cleaner", predictor_transformer()), ('vectorizer', bow_vector), ('classifier', classifier_18p)]) pipeline = Pipeline([("cleaner", predictor_transformer())]) with open('model', 'wb') as f: pickle.dump(pipeline, f)
我的Flask应用程序位于:video_discovery/__init__.py
这是我运行Flask应用程序的方式:
FLASK_ENV=development FLASK_APP=video_discovery flask run
我认为问题可能是我直接运行Python脚本训练模型而不是使用Flask,因此可能存在一些名称空间问题,但我不确定如何解决这个问题。训练我的模型需要一段时间,因此我无法等待HTTP请求。
我可能错过了什么,可能会解决这个问题吗?
来自https://docs.python.org/3/library/pickle.html:
pickle
可以透明地保存和还原类实例,但类定义必须是可导入的,并且与存储该对象时的模块在同一模块中。
当你运行python data_science/train_model.py
并从predictors
导入时,Python将predictors
导入为顶级模块,而predictor_transformer
在该模块中。
然而,当你通过Flask从video_discovery
的父文件夹运行预测时,predictor_transformer
在video_discovery.data_science.predictors
模块中。
使用相对导入和从一致的路径运行
train_model.py:使用相对导入
# from predictors import predictor_transformer # - from .predictors import predictor_transformer # +
训练模型:使用video_discovery
作为顶级模块运行train_model
# python data_science/train_model.py # - python -m video_discovery.data_science.train_model # +
通过Python命令运行预测:使用video_discovery
作为顶级模块运行predict_edu
# python predict_edu.py # - python -m video_discovery.data_science.predict_edu # +
通过Flask运行预测:(无需更改,已使用video_discovery
作为顶级模块运行)
FLASK_ENV=development FLASK_APP=video_discovery flask run
执行predict_edu.py
时出现错误有点奇怪,因为它和predictors.py
在同一个目录下,因此使用绝对导入(如from predictors import predictor_transformer
,没有点.
运算符)通常应该正常工作。但是,如果错误仍然存在,下面是几个你可以尝试的选项。
选项1
在尝试导入模块之前,您可以将predictors
文件的父目录添加到系统的PATH
变量中,如此处所述。这对于较小的项目应该可以正常工作。
import sys from pathlib import Path sys.path.insert(0, str(Path(__file__).resolve().parent)) from predictors import predictor_transformer
选项2
使用相对导入,例如from .predictors import...
,并确保您从包的父目录运行脚本,如下所示。 -m
选项 "搜索sys.path
中命名的模块并将其内容作为__main__
模块执行,而不是作为顶级脚本。在以下参考资料中了解有关-m
选项的更多信息:[1],[2],[3],[4],[5],[6]。在此处了解有关"相对导入"的更多信息:[1],[2],[3],[4]。
python -m video_discovery.data_science.predict_edu
然而,PEP 8样式指南通常建议使用绝对导入。
绝对导入被推荐,因为它们通常更易读,并且在导入系统配置错误的情况下(例如在包中的目录出现在sys.path中时),往往表现更好或给出更好的错误信息。
然而,在某些情况下,绝对导入可能会变得相当冗长,这取决于目录结构的复杂程度,如下所示。另一方面,“相对导入可能会很乱,特别是对于目录结构可能发生变化的共享项目”。它们也“不像绝对导入那样易读,很难确定导入资源的位置”。更多关于Python导入和绝对导入 vs 相对导入的内容。
from package1.subpackage2.subpackage3.subpackage4.module5 import function6
选项3
将包含您的包目录的目录包含在PYTHONPATH
中,并改为使用绝对导入。 PYTHONPATH
用于设置用户定义模块的路径,以便它们可以直接导入Python脚本中。 PYTHONPATH
变量是一个字符串,其中包含需要由Python添加到sys.path
目录列表中的目录列表。这个变量的主要用途是允许用户导入尚未成为可安装Python包的模块。在此处和此处阅读更多关于它的内容。
例如,假设您有一个名为video_discovery
的包(位于/Users/my_user/code/video_discovery
下),并且想要将目录/Users/my_user/code
添加到PYTHONPATH
:
在Mac上
- 打开
Terminal.app
- 在文本编辑器中打开
~/.bash_profile
文件 - 例如atom ~/.bash_profile
- 在末尾添加以下行:
export PYTHONPATH="/Users/my_user/code"
- 保存文件。
- 关闭
Terminal.app
- 重新启动
Terminal.app
以读取新设置,并键入
echo $PYTHONPATH
。 它应该显示类似于/Users/my_user/code
的内容。
在Linux上
- 打开您最喜欢的终端程序
- 在文本编辑器中打开
~/.bashrc
文件 - 例如atom ~/.bashrc
- 在末尾添加以下行:
export PYTHONPATH=/home/my_user/code
- 保存文件。
- 关闭您的终端应用程序。
- 重新开始您的终端应用程序,以读取新设置,并键入
echo $PYTHONPATH
。 它应该显示类似于/home/my_user/code
的内容。
在Windows上
- 打开
This PC
(或计算机
),在内部右键单击并选择属性
。 - 从计算机属性对话框中,在左侧选择
高级系统设置
。 - 从高级系统设置对话框中,选择
环境变量
按钮。 - 在环境变量对话框中,单击
顶部
半部分的新建
按钮,以创建一个新的用户变量
: - 将变量名称设置为
PYTHONPATH
,并在值中添加您的模块目录的路径。 选择确定
和确定
以保存此变量。 - 现在打开一个cmd窗口并键入
echo %PYTHONPATH%
以确认环境变量正确设置。 记得打开一个新的cmd窗口来运行您的Python程序,以便它使用PYTHONPATH
中的新设置。
选项4
另一种解决方案是将包安装为可编辑状态(所有对.py文件所做的编辑将自动包含在安装的包中),如此处和此处所述。 但是,使其正常工作所需的工作量可能会使选项3对您更好。
setup.py
文件的内容应该如下所示,并且安装该包的命令应该是 pip install -e .
(-e
标记代表“可编辑”,.
代表“当前目录”)。
from setuptools import setup, find_packages setup(name='myproject', version='1.0', packages=find_packages())