编写一个fasttext自定义转换器

Posted

技术标签:

【中文标题】编写一个fasttext自定义转换器【英文标题】:Write a fasttext customised transformer 【发布时间】:2021-03-25 18:26:04 【问题描述】:

我有一个训练有素的自定义 fasttext 模型(fasttext 是 Facebook 开发的词嵌入算法)。我设法在一个函数中得到了预期的结果,但现在我想将它重写为一个自定义的转换器,以便我可以将它添加到我的 sklearn 管道中,因为它只接受转换器。

该函数接受一个单词并返回该单词的向量:

def name2vector(name=None):
    vec = [np.array(model.get_word_vector(w)) for w in name.lower().split(' ')]
    name_vec = np.sum(vec, axis=0) # If "name" is multiple words, sum the vectors
    return (name_vec)

返回值:

array([-0.01087821,  0.01030535, -0.01402427,  0.0310982 ,  0.08786983,
        -0.00404521, -0.03286128, -0.00842709,  0.03934859, -0.02717219,
         0.01151722, -0.03253938, -0.02435859,  0.03330994, -0.03696496], dtype=float32))

我希望变压器做与函数相同的事情。 我知道我可以使用BaseEstimatorTransformerMixin 通过阅读tutorial 将其重写为变压器,但我仍然坚持这一点。一些建议会很好,谢谢。

【问题讨论】:

请更好地解释您的意图。显示所需的输出... 我更新了问题@StefanoFiorucci-anakin87 【参考方案1】:

假设您使用的是 pandas DataFrame,您可以执行以下操作:

from sklearn.base import BaseEstimator, TransformerMixin
from sklearn.pipeline import Pipeline
from sklearn.linear_model import LogisticRegression



class FastTextTransformer(TransformerMixin, BaseEstimator):
    def __init__(self, model):
        self.model = model
    
    def get_params(self, deep):
        return 'dimension': self.model.get_dimension()
    
    def fit(self, X, y):
        # We assume the FT model was already fit
        return self
    
    def transform(self, X):
        X_copy = X.copy()
        X_copy = X_copy.apply(self.name2vector)
        
        return pd.DataFrame(X_copy.tolist())

    def name2vector(self, name):
        vec = [np.array(self.model.get_word_vector(w)) for w in name.lower().split(' ')]
        name_vec = np.sum(vec, axis=0) # If "name" is multiple words, sum the vectors
        return name_vec
    
    

为了演示用法,让我们加载一个 fasttext 模型和一个亚马逊评论的示例数据集:

import fasttext as ft

ft_model = ft.load_model('amazon_review_polarity.ftz')
amz_df = pd.read_html('https://huggingface.co/datasets/amazon_polarity/viewer/amazon_polarity/test')[0]
amz_df.rename(columns='content (string)': 'content', 'label (class label)': 'label', inplace=True)
amz_df

然后将其用作真正的 scikit-learn 管道。

pipe = Pipeline([
    ('ft', FastTextTransformer(ft_model)),
    ('clf', LogisticRegression()),
])

现在我们可以拟合和预测

pipe.fit(amz_df['content'], amz_df.label)
pipe.predict(pd.Series(['great', 'very cool', 'very disappointed']))

返回

array(['positive', 'positive', 'negative'], dtype=object)

注意如果您想计算句子中单词的平均值,而不是求和,您可以将name2vector 替换为内置方法get_sentence_vector。对于监督模型,它将返回平均值。对于无监督的(CBOW 和 skipgram),它首先将每个向量除以其 L2 范数,然后取平均值。

查看讨论here。

信用:Stefano Fiorucci - anakin87

【讨论】:

【参考方案2】:

compress-fasttext 库(它是 Gensim 的包装器,使 fastText 模型更轻量级)已经有这样一个转换器:

import compress_fasttext
from sklearn.pipeline import make_pipeline
from sklearn.linear_model import LogisticRegression
from compress_fasttext.feature_extraction import FastTextTransformer

small_model = compress_fasttext.models.CompressedFastTextKeyedVectors.load(
    'https://github.com/avidale/compress-fasttext/releases/download/v0.0.4/cc.en.300.compressed.bin'
)

classifier = make_pipeline(
    FastTextTransformer(model=small_model), 
    LogisticRegression()
).fit(
    ['banana', 'soup', 'burger', 'car', 'tree', 'city'],
    [1, 1, 1, 0, 0, 0]
)
classifier.predict(['jet', 'train', 'cake', 'apple'])
# array([0, 0, 1, 1])

在底层,它会找到文本中的所有“单词”(字母数字序列)并平均它们的 fastText 嵌入。

这里是the source code。

【讨论】:

以上是关于编写一个fasttext自定义转换器的主要内容,如果未能解决你的问题,请参考以下文章

Logback - 如何编写自定义异常转换器以将堆栈跟踪折叠成一行

webpack loader自定义编写

webpack loader自定义编写

自定义类型转换器之TypeConverter

QVariant 中的自定义类型转换为空字符串

自定义一个函数itos,将一个整数转换为字符串的功能,并编写主函数调用该函数。