我无法加载我的模型,因为我无法放置Posix路径。

14
我正在设置一个脚本,需要使用fast-ai包中的一些函数。事实上,我在Windows上定义路径时,fast-ai中名为load_learner的函数无法加载模型。
我尝试将包中的函数更改为: state = pickle.load(open(str(path) + '/' + str(fname), 'rb')) 而不是: state = pickle.load(open(path/fname, 'rb')) 但是我得到了这个错误:
 File "lib\site-packages\fastai\basic_train.py", line 462, in load_learner
    state = pickle.load(open(path/fname, 'rb'))
  File "\lib\pathlib.py", line 1006, in __new__
    % (cls.__name__,))
NotImplementedError: cannot instantiate 'PosixPath' on your system

我的路径定义如下:

folder_path = './models/model1'
fname = 'model.pkl'

我调用函数的方式为:

model = load_learner(folder_path, fname)

在这个函数中,如何使用Windows路径呢?


更新1

之前发布的答案只适用于Linux。我在Windows上仍然存在这个问题。我没有找到在Windows上通过PosixPath的方法。唯一的解决办法是更改我的模块内部包,但这不是解决此类问题的安全方法。


提前感谢您的帮助。


这可能是由于Windows路径分隔符是双反斜杠“\”导致的问题,您可以通过使用os.sep 参见轻松获取所有系统的正确分隔符。尝试将所有“/”替换为Windows格式的分隔符。 - Albo
请发布异常的完整堆栈跟踪。 - Dion
2
首先尝试将您的软件包更新到最新版本。有问题的代码段不在那里,因此这可能会解决您遇到的问题。 - Rob
7个回答

24
只需将PosixPath重定向到WindowsPath即可。
import pathlib
temp = pathlib.PosixPath
pathlib.PosixPath = pathlib.WindowsPath

我也正在加载fastai模型,这个技巧很有效。 重要提示:由于这可能会导致后续问题,请在完成后记得设置pathlib.PosixPath = temp

1
由于这可能会在以后引起问题,请记得在完成后设置 pathlib.PosixPath = temp - Marcus.Luck
您还可以查看我的建议,自动还原 PosixPath(特别是在导入时出现错误):https://dev59.com/31MI5IYBdhLWcg3wBGqC#68796747 - Jean-Francois T.
有时在Linux系统上,我会遇到这个错误,为此我必须使用import pathlib plt = platform.system() if plt == 'Linux': pathlib.WindowsPath = pathlib.PosixPath``` - Bagghi Daku

7
在Windows上工作时,您可以暂时将pathlib.PosixPath设置为WindowsPath。重要的是要恢复到原始值,特别是在加载pickle期间出现异常时。
一个简单的方法是使用try/finally:
posix_backup = pathlib.PosixPath
try:
    pathlib.PosixPath = pathlib.WindowsPath
    learn_inf = load_learner(EXPORT_PATH)
finally:
    pathlib.PosixPath = posix_backup

如果你经常这样做,可以按照以下方式使流程更加顺畅:

  1. 定义一个可以临时进行更改的函数
  2. with块中使用它

你可以在脚本的顶部或者专门的单元格(如果你使用Jupyter)中添加这个函数。

from contextlib import contextmanager
import pathlib

@contextmanager
def set_posix_windows():
    posix_backup = pathlib.PosixPath
    try:
        pathlib.PosixPath = pathlib.WindowsPath
        yield
    finally:
        pathlib.PosixPath = posix_backup

然后,只需像这样使用它:
EXPORT_PATH = pathlib.Path("model.pkl")

with set_posix_windows():
    learn_inf = load_learner(EXPORT_PATH)

同时,还要检查来自sophros的答案:https://dev59.com/31MI5IYBdhLWcg3wBGqC#62836990


使用contextmanager真是太棒了! - Stalin Thomas
1
该解决方案在Azure函数(本地运行于Windows上)中运行load_learner()方法时同样有效。 - CMorgan

3

根据我的问题,我找到了一种使用方法:

from pathlib import Path

folder_path = Path('./models/model1')

更新 1

这个解决方案只能在 Linux 上使用,在 Windows 上我仍然会遇到错误。



嗨,有些人已经提供了在Windows上同样适用的解决方案。请更改已接受的答案。谢谢。 - Jean-Francois T.

1
根据提供的错误信息,您正在使用 pathlib。因此,在此处不需要使用 + '/' +str(path) + '/' + str(fname) / 作为路径分隔符在 Linux/Unix 上有效。
state = pickle.load(open(path / fname, 'rb'))

在Windows上,请使用.joinpath()代替:

state = pickle.load(open(path.joinpath(fname), 'rb'))

如果您不打算使用 pathlib,请使用 os.path.join()。它会自动选择适合您的操作系统的正确格式。

即使我在Windows上使用os.path.join(),仍然会出现以下错误:state = pickle.load(open(path/fname, 'rb')) !! TypeError: unsupported operand type(s) for /: 'str' and 'str'。我正在寻找一种方法来不改变我的软件包脚本。 - Bando

1
问题与Python在处理路径时根据操作系统的不同处理方式有关:
  • PosixPath - 在Linux / Unix上

  • WindowsPath - 在Windows上

使用pickle在一个操作系统(比如说Linux)上存储对象时,它也会持久化类型/类信息(这里是PosixPath)。

现在,当pickle文件被加载时,Python假设它将能够基于先前持久化的类型信息重新创建对象。在这种情况下,它试图重新创建PosixPath类型的对象,但由于pathlib库无法在Windows上实例化,因此被阻止。在Windows上应该使用WindowsPath,但pickle模块无法很好地处理这种依赖于操作系统的逻辑,因此它无助地抛出错误。

理论上,您可以干预pathlib的代码以删除操作系统检查,但没有简单的解决方法,只能避免对依赖于操作系统的对象进行pickling(例如,将路径存储为字符串 - 如os.path所做的那样 - 肯定可以解决此问题)。

还有另一种可能性,即使用一个平台无关的PurePosixPath类来处理路径对象。


1

对于posix路径错误:

当您在Colab/Gradient上训练模型并下载后,在Windows上进行推断。

只需将PosixPath重定向到WindowsPath

import pathlib

temp = pathlib.PosixPath
pathlib.PosixPath = pathlib.WindowsPath

2
欢迎来到stackoverflow。这应该作为对KumaTea答案的评论发布。 - Light_B

0

我正在处理相同的问题- 将fastai模型部署为Web服务器,并且遇到了同样的问题,以下是我所做的事情... 在导出模型时,请使用joblib或pickle来将模型进行pickle,而不是使用learn.export(),并在服务器上使用以下代码。

 __model = pickle.load(open(os.path.join('./artifacts/saved_model.pkl'), 'rb'))

通过这样做,可以解决路径问题,但由于模型是使用GPU训练的,因此会出现错误,要求将存储映射到CPU。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接