在Flask应用程序中尝试反序列化模型时出现了ModuleNotFoundError错误。

14 浏览
0 Comments

在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请求。

我可能错过了什么,可能会解决这个问题吗?

admin 更改状态以发布 2023年5月24日
0
0 Comments

来自https://docs.python.org/3/library/pickle.html

pickle可以透明地保存和还原类实例,但类定义必须是可导入的,并且与存储该对象时的模块在同一模块中。

当你运行python data_science/train_model.py并从predictors导入时,Python将predictors导入为顶级模块,而predictor_transformer在该模块中。

然而,当你通过Flask从video_discovery的父文件夹运行预测时,predictor_transformervideo_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

0
0 Comments

执行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上

  1. 打开Terminal.app
  2. 在文本编辑器中打开~/.bash_profile文件 - 例如atom ~/.bash_profile
  3. 在末尾添加以下行:export PYTHONPATH="/Users/my_user/code"
  4. 保存文件。
  5. 关闭Terminal.app
  6. 重新启动Terminal.app以读取新设置,并键入
    echo $PYTHONPATH。 它应该显示类似于/Users/my_user/code的内容。

在Linux上

  1. 打开您最喜欢的终端程序
  2. 在文本编辑器中打开~/.bashrc文件 - 例如atom ~/.bashrc
  3. 在末尾添加以下行:export PYTHONPATH=/home/my_user/code
  4. 保存文件。
  5. 关闭您的终端应用程序。
  6. 重新开始您的终端应用程序,以读取新设置,并键入echo $PYTHONPATH。 它应该显示类似于/home/my_user/code的内容。

在Windows上

  1. 打开This PC(或计算机),在内部右键单击并选择属性
  2. 从计算机属性对话框中,在左侧选择高级系统设置
  3. 从高级系统设置对话框中,选择环境变量按钮。
  4. 在环境变量对话框中,单击顶部半部分的新建按钮,以创建一个新的用户变量
  5. 将变量名称设置为PYTHONPATH,并在值中添加您的模块目录的路径。 选择确定确定以保存此变量。
  6. 现在打开一个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())

0