使用joblib加载含自定义稠密数组转换步骤的Pipeline时触发AttributeError问题求助
使用joblib加载含自定义稠密数组转换步骤的Pipeline时触发AttributeError问题求助
这个问题我之前碰到过,本质是joblib序列化自定义函数时的依赖逻辑导致的:当你用joblib保存Pipeline时,它并不会把to_dense这个自定义函数的代码完整存下来,只是记录了它的名字和所属模块。等你重新加载模型时,当前运行环境的__main__模块里没有这个函数的定义,自然就触发找不到属性的报错了。
给你几个可行的解决办法,你可以根据场景选择:
方案一:把自定义函数放到独立模块(最稳妥的长期方案)
如果你之后还要维护这个模型,建议把相关工具函数抽出来放到单独的Python文件里,比如新建一个model_utils.py,把to_dense和to_dense_array的定义都移进去:# model_utils.py import numpy as np from sklearn.preprocessing import FunctionTransformer def to_dense(x): return np.asarray(x.todense()) to_dense_array = FunctionTransformer(to_dense, accept_sparse=True)不管是训练还是加载模型,都从这个模块导入转换组件:
训练时的代码:from sklearn.pipeline import make_pipeline from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.ensemble import HistGradientBoostingClassifier from model_utils import to_dense_array import joblib import os model = make_pipeline( TfidfVectorizer(), to_dense_array, HistGradientBoostingClassifier() ) est = model.fit(texts, y) save_path = os.path.join(os.getcwd(), "VAT_estimator.pkl") joblib.dump(est, save_path)加载时的代码:
import joblib from model_utils import to_dense_array # 确保函数所在模块被导入,命名空间中存在to_dense model = joblib.load("VAT_estimator.pkl")方案二:加载模型前重新定义完全一致的函数
如果只是临时测试不想新建模块,那你必须在调用joblib.load()之前,在当前脚本里写出和训练时丝毫不差的to_dense函数——函数名、参数、内部逻辑都不能改:import joblib import numpy as np from sklearn.preprocessing import FunctionTransformer # 必须和训练时的定义完全一致 def to_dense(x): return np.asarray(x.todense()) # 先定义函数,再加载模型 model = joblib.load("VAT_estimator.pkl")
你之前尝试加载后补转换步骤没用,是因为joblib在加载模型的瞬间就会解析所有Pipeline组件的依赖,包括FunctionTransformer绑定的to_dense函数,必须在加载动作发生前就让这个函数在当前命名空间里存在才行。
备注:内容来源于stack exchange,提问作者JCF
相关产品推荐
相关产品推荐

