使用嵌入进行零样本分类

, ,
2022年3月10日
在 Github 中打开

在本 notebook 中,我们将使用嵌入和零标签数据对评论的情感进行分类!数据集在 Get_embeddings_from_dataset Notebook 中创建。

我们将把 4 星和 5 星评论定义为正面情感,将 1 星和 2 星评论定义为负面情感。3 星评论被认为是中性的,我们不会在本示例中使用它们。

我们将通过嵌入每个类别的描述,然后将新样本与这些类别嵌入进行比较来执行零样本分类。

import pandas as pd
import numpy as np
from ast import literal_eval

from sklearn.metrics import classification_report

EMBEDDING_MODEL = "text-embedding-3-small"

datafile_path = "data/fine_food_reviews_with_embeddings_1k.csv"

df = pd.read_csv(datafile_path)
df["embedding"] = df.embedding.apply(literal_eval).apply(np.array)

# convert 5-star rating to binary sentiment
df = df[df.Score != 3]
df["sentiment"] = df.Score.replace({1: "negative", 2: "negative", 4: "positive", 5: "positive"})

零样本分类

为了执行零样本分类,我们希望在没有任何训练的情况下预测样本的标签。为此,我们可以简单地嵌入每个标签的简短描述,例如正面和负面,然后比较样本嵌入和标签描述之间的余弦距离。

与样本输入最相似的标签是预测标签。我们还可以定义一个预测分数,即到正面标签和到负面标签的余弦距离之差。此分数可用于绘制精确率-召回率曲线,该曲线可用于通过选择不同的阈值来选择精确率和召回率之间的不同权衡。

from utils.embeddings_utils import cosine_similarity, get_embedding
from sklearn.metrics import PrecisionRecallDisplay

def evaluate_embeddings_approach(
    labels = ['negative', 'positive'],
    model = EMBEDDING_MODEL,
):
    label_embeddings = [get_embedding(label, model=model) for label in labels]

    def label_score(review_embedding, label_embeddings):
        return cosine_similarity(review_embedding, label_embeddings[1]) - cosine_similarity(review_embedding, label_embeddings[0])

    probas = df["embedding"].apply(lambda x: label_score(x, label_embeddings))
    preds = probas.apply(lambda x: 'positive' if x>0 else 'negative')

    report = classification_report(df.sentiment, preds)
    print(report)

    display = PrecisionRecallDisplay.from_predictions(df.sentiment, probas, pos_label='positive')
    _ = display.ax_.set_title("2-class Precision-Recall curve")

evaluate_embeddings_approach(labels=['negative', 'positive'], model=EMBEDDING_MODEL)
              precision    recall  f1-score   support

    negative       0.54      0.92      0.68       136
    positive       0.98      0.87      0.92       789

    accuracy                           0.87       925
   macro avg       0.76      0.89      0.80       925
weighted avg       0.92      0.87      0.89       925

image generated by notebook

我们可以看到,这个分类器已经表现得非常好。我们使用了相似性嵌入和最简单的标签名称。让我们尝试通过使用更具描述性的标签名称和搜索嵌入来改进这一点。

evaluate_embeddings_approach(labels=['An Amazon review with a negative sentiment.', 'An Amazon review with a positive sentiment.'])
              precision    recall  f1-score   support

    negative       0.76      0.96      0.85       136
    positive       0.99      0.95      0.97       789

    accuracy                           0.95       925
   macro avg       0.88      0.96      0.91       925
weighted avg       0.96      0.95      0.95       925

image generated by notebook

使用搜索嵌入和描述性名称可以进一步提高性能。

evaluate_embeddings_approach(labels=['An Amazon review with a negative sentiment.', 'An Amazon review with a positive sentiment.'])
              precision    recall  f1-score   support

    negative       0.76      0.96      0.85       136
    positive       0.99      0.95      0.97       789

    accuracy                           0.95       925
   macro avg       0.88      0.96      0.91       925
weighted avg       0.96      0.95      0.95       925

image generated by notebook

如上所示,使用嵌入进行零样本分类可以带来很好的结果,尤其是当标签比简单的单词更具描述性时。