将Binarizer与sklearn模型一起保存

Lat*_*der 4 version-control machine-learning scikit-learn

我正在尝试构建具有2个组件的服务。在第1部分中,我通过创建,使用sklearn训练了机器学习模型Pipeline。该模型使用joblib.dump(真的numpy_pickle.dump)序列化。组件2在云中运行,加载由(1)训练的模型,并使用它来标记作为输入的文本。

我遇到一个问题,在训练期间(组件1),我需要首先对数据进行二值化,因为它是文本数据,这意味着该模型在二值化输入上进行了训练,然后使用由二值化器创建的映射进行预测。当(2)根据模型进行预测时,我需要重新获得此映射,以便可以输出实际的文本标签。

我试图像这样将binarizer添加到管道中,以为模型将具有映射本身:

p = Pipeline([
('binarizer', MultiLabelBinarizer()),
('vect', CountVectorizer(min_df=min_df, ngram_range=ngram_range)), 
('tfidf', TfidfTransformer()), 
('clf', OneVsRestClassifier(clf))
])
Run Code Online (Sandbox Code Playgroud)

但是我收到以下错误:

model = p.fit(training_features, training_tags)
*** TypeError: fit_transform() takes 2 positional arguments but 3 were given
Run Code Online (Sandbox Code Playgroud)

我的目标是确保将二进制化器和模型绑定在一起,以便用户知道如何解码模型的输出。

有哪些现有的范例可以做到这一点?是否应该在我创建的其他对象中将二进制化器与模型一起序列化?还有其他将二进制化器传递给Pipeline我的方法,这样我就不必这样做,如果这样做,我是否能够从模型取回映射?

ril*_*ell 5

您应该将其添加MultiLabelBinarizer到管道的直觉是解决此问题的正确方法。它本来可以工作,除了MultiLabelBinarizer.fit_transform不采用fit_transform(self, X, y=None)方法签名(方法签名现在是sklearn估计器的标准)。相反,它具有fit_transform(self, y)我以前从未注意到的独特签名。由于这种差异的结果,当你调用合适的管道,它会尝试通过training_tags作为第三位置参数的函数有两个位置参数,这是行不通的。

解决此问题的方法很棘手。我能想到的最干净的方法是创建自己的MultiLabelBinarizer,它覆盖fit_transform并忽略其第三个参数。尝试类似以下的方法。

class MyMLB(MultiLabelBinarizer):
    def fit_transform(self, X, y=None):
        return super(MultiLabelBinarizer, self).fit_transform(X)
Run Code Online (Sandbox Code Playgroud)

尝试将其添加到您的管道中,以代替MultiLabelBinarizer,然后看看会发生什么。如果您能够进行fit()管道传输,那么您遇到的最后一个问题是,您的新MyMLB类必须在任何可以取消现有训练的,腌制的管道对象的系统上都可以导入。最简单的方法是将MyMLB其放入自己的模块中,然后将副本放置在将取消剔除并执行模型的远程计算机上。那应该解决它。

我误解了MultiLabelBinarizer工作原理。它是输出的变压器,而不是输入的变压器。这不仅解释了fit_transform()该类的替代方法签名,而且从根本上与包含在单个分类管道中的想法不兼容,后者仅限于转换输入和进行输出预测。但是,一切并没有丢失!

根据您的问题,您已经可以将模型作为.pkl文件的某种形式序列化到磁盘上了。您还应该能够序列化训练有素的MultiLabelBinarizer,然后将其解压缩并使用它来解压缩管道中的输出。我知道您正在使用joblib,但我将在此示例代码中编写该代码,就像您在使用pickle一样。我相信这个想法仍然适用。

X = <training_data>
y = <training_labels>

# Perform multi-label classification on class labels.
mlb = MultiLabelBinarizer()
multilabel_y = mlb.fit_transform(y)

p = Pipeline([
('vect', CountVectorizer(min_df=min_df, ngram_range=ngram_range)), 
('tfidf', TfidfTransformer()), 
('clf', OneVsRestClassifier(clf))
])

# Use multilabel classes to fit the pipeline.
p.fit(X, multilabel_y)

# Serialize both the pipeline and binarizer to disk.
with open('my_sklearn_objects.pkl', 'wb') as f:
    pickle.dump((mlb, p), f)
Run Code Online (Sandbox Code Playgroud)

然后,将.pkl文件运送到远程盒之后...

# Hydrate the serialized objects.
with open('my_sklearn_objects.pkl', 'rb') as f:
    mlb, p = pickle.load(f)

X = <input data> # Get your input data from somewhere.

# Predict the classes using the pipeline
mlb_predictions = p.predict(X)

# Turn those classes into labels using the binarizer.
classes = mlb.inverse_transform(mlb_predictions)

# Do something with predicted classes.
<...>
Run Code Online (Sandbox Code Playgroud)

这是这样做的范例吗?据我所知,是的。不仅如此,而且如果您希望将它们放在一起(我认为这是个好主意),则可以tuple像在上面的示例中一样对它们进行序列化,以便将它们保存在一个文件中。无需序列化自定义对象或类似对象。

通过pickle 等进行模型序列化sklearn批准的方法,可以在运行之间保存估算器,并在计算机之间移动估算器。我以前已经成功地多次使用了此过程,包括在成功的生产系统中。