从sklearn.externals导入joblib报错及S3模型加载问题求助
解决joblib导入与模型加载的兼容问题
看起来你遇到了sklearn版本更新后joblib依赖变化导致的典型问题,我来一步步帮你搞定:
问题1:from sklearn.externals import joblib 导入失败
原因
在scikit-learn 0.23版本之后,官方已经移除了sklearn.externals.joblib这个模块——joblib现在是一个独立的Python库,不再作为sklearn的外部依赖存在。所以直接从sklearn.externals导入会报错。
解决步骤
- 确保安装了独立的joblib库:
pip install --upgrade joblib - 替换代码中的导入语句:
把原来的
改成from sklearn.externals import joblibimport joblib
问题2:直接导入joblib后,加载模型时出现ModuleNotFoundError: No module named 'sklearn.externals.joblib'
原因
这个问题是因为你保存模型的时候用的是旧版本的sklearn.externals.joblib,模型文件里的pickle数据会记录当时的模块路径。现在加载时,pickle会尝试寻找不存在的sklearn.externals.joblib,所以报错。
解决方法(两种可选)
方法1:临时模块映射(快速修复,无需重新保存模型)
在导入joblib之后,添加一段代码,把sklearn.externals.joblib这个不存在的模块映射到当前的joblib库:
import sys import joblib # 让pickle能找到对应的模块 sys.modules['sklearn.externals.joblib'] = joblib
这样加载模型时,pickle就会用正确的joblib模块来反序列化数据了。
方法2:重新保存模型(长期解决方案)
如果有条件重新访问保存模型的环境,或者能重新训练模型,建议用最新的joblib重新保存一次模型:
import joblib # 在能加载旧模型的环境中执行(比如用旧版本sklearn) old_model = joblib.load('model_d2v_version_002') # 用独立的joblib重新保存 joblib.dump(old_model, 'model_d2v_version_002_new')
之后用新保存的模型文件,就不会再出现模块找不到的问题了。
优化后的完整代码示例
我还帮你重构了原来的load_d2v函数,去掉了重复的代码逻辑:
import pandas as pd import numpy as np import json import subprocess import sqlalchemy import joblib import sys # 解决pickle模块映射问题 sys.modules['sklearn.externals.joblib'] = joblib ENV = 'dev' model_d2v = load_d2v('model_d2v_version_002', ENV) def load_d2v(fname, env): model_name = fname try: # 先尝试本地加载 model = joblib.load(model_name) print(f'已从本地加载模型 {model_name}') return model except FileNotFoundError: # 本地没有则从S3下载 s3_base_path = 's3://sd-flikku/datalake/doc2vec_model' path = f"{s3_base_path}/{model_name}" command = f"aws s3 cp {path} {model_name}".split() print(f'正在从S3下载并加载...{model_name}') subprocess.call(command) model = joblib.load(model_name) return model
这个版本的代码不仅解决了joblib的兼容问题,还简化了逻辑:用try-except统一处理本地文件存在/不存在的情况,避免了重复的if-else分支。
内容的提问来源于stack exchange,提问作者Praneeth Sai
相关产品推荐
相关产品推荐

