你的直觉是正确的,将
MultiLabelBinarizer
添加到流水线中是解决这个问题的正确方法。这应该有效,但是
MultiLabelBinarizer.fit_transform
不接受现在成为sklearn评估器标准的
fit_transform(self, X, y=None)
方法签名。相反,它有一个独特的
fit_transform(self, y)
签名,我以前从未注意过。由于这种差异,当你在流水线上调用fit时,它会尝试将
training_tags
作为第三个位置参数传递给一个只有两个位置参数的函数,这不起作用。
解决这个问题比较棘手。我能想到的最干净的方法是创建自己的MultiLabelBinarizer,覆盖fit_transform并忽略它的第三个参数。尝试以下代码:
class MyMLB(MultiLabelBinarizer):
def fit_transform(self, X, y=None):
return super(MultiLabelBinarizer, self).fit_transform(X)
尝试将这个方法添加到你的管道中,取代MultiLabelBinarizer,看看会发生什么。如果你可以适应这个管道,你最后可能会遇到的问题是,你的新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)
然后,在将.pkl文件发送到远程计算机后...
with open('my_sklearn_objects.pkl', 'rb') as f:
mlb, p = pickle.load(f)
X = <input data>
mlb_predictions = p.predict(X)
classes = mlb.inverse_transform(mlb_predictions)
<...>
这是做这件事的典范吗?据我所知,是的。不仅如此,如果你想把它们放在一起(我认为这是个好主意),你可以像上面的例子一样将它们序列化为 tuple
,让它们保持在一个文件中。不需要序列化自定义对象或类似的东西。
通过 pickle
et al. 进行模型序列化是 sklearn 所推荐的保存评估器的方式,可以在运行之间移动它们以及在计算机之间传输。我以前成功地多次使用过这个过程,包括在生产系统中。
*** AttributeError: 'numpy.ndarray' object has no attribute 'lower'
的错误。我认为最后一行应该以fit_transform(y)
结束,因为我想转换标签,而不是输入文本,但即使我修复了它,由于_pre_transform
的编写方式(标签最终覆盖了Xt = transform.fit_transform(Xt, y, **fit_params_steps[name])
中的训练数据),我仍然会遇到相同的错误。也许我还是漏掉了什么? - LateCoder