我正在尝试腌制一个 sklearn 机器学习模型,并将其加载到另一个项目中。该模型被包裹在管道中,该管道执行特征编码、缩放等。当我想在管道中使用自写转换器来执行更高级的任务时,问题就开始了。
假设我有两个项目:
- train_project:它在 src.feature_extraction.transformers.py 中有自定义转换器
- use_project:它在src中有其他东西,或者根本没有src目录
如果在“train_project”中我使用 joblib.dump() 保存管道,然后在“use_project”中使用 joblib.load() 加载它,它将找不到诸如“src.feature_extraction.transformers”之类的内容并抛出异常:
ModuleNotFoundError:没有名为“src.feature_extraction”的模块
我还应该补充一点,我从一开始的意图是简化模型的使用,因此程序师可以像加载任何其他模型一样加载模型,传递非常简单的、人类可读的特征,以及对实际模型的所有“神奇”特征预处理(例如梯度提升)正在内部发生。
我想在两个项目的根目录下创建 /dependencies/xxx_model/ 目录,并在其中存储所有需要的类和函数(将代码从“train_project”复制到“use_project”),这样项目的结构是相同的,并且可以加载转换器。我发现这个解决方案非常不优雅,因为它会强制使用该模型的任何项目的结构。
我想只是在“use_project”中重新创建管道和所有变压器,并以某种方式从“train_project”加载变压器的拟合值。
最好的解决方案是,如果转储文件包含所有需要的信息并且不需要依赖项,我真的很震惊 sklearn.Pipelines 似乎没有这种可能性 - 如果我以后不能加载合适的对象,那么安装管道有什么意义?是的,如果我只使用 sklearn 类而不创建自定义类,它会起作用,但非自定义类没有所有需要的功能。
示例代码:
火车项目
src.feature_extraction.transformers.py
from sklearn.pipeline import TransformerMixin
class FilterOutBigValuesTransformer(TransformerMixin):
def __init__(self):
pass
def fit(self, X, y=None):
self.biggest_value = X.c1.max()
return self
def transform(self, X):
return X.loc[X.c1 <= self.biggest_value]
火车项目
主文件
from sklearn.externals import joblib
from sklearn.preprocessing import MinMaxScaler
from src.feature_extraction.transformers import FilterOutBigValuesTransformer
pipeline = Pipeline([
('filter', FilterOutBigValuesTransformer()),
('encode', MinMaxScaler()),
])
X=load_some_pandas_dataframe()
pipeline.fit(X)
joblib.dump(pipeline, 'path.x')
测试项目
主文件
from sklearn.externals import joblib
pipeline = joblib.load('path.x')
预期的结果是使用可以使用的转换方法正确加载管道。
加载文件时实际结果是异常。