SetFit 文档

SetFit 用于基于方面的情感分析

Hugging Face's logo
加入 Hugging Face 社区

并获得增强的文档体验

开始使用

SetFit 用于基于方面的情感分析

SetFitABSA 是一个高效的少样本基于方面的情感分析框架,只需少量训练数据即可获得具有竞争力的性能。它由三个阶段组成:

  1. 使用 spaCy 查找潜在的方面候选。
  2. 使用 SetFit 模型过滤这些方面候选。
  3. 使用 SetFit 模型对过滤后的方面候选进行分类。

本指南将向您展示如何训练、预测、保存和加载这些模型。

入门

首先,SetFitABSA 还需要安装 spaCy,所以我们必须安装它。

!pip install "setfit[absa]"
# or
# !pip install spacy

然后,我们必须下载我们打算使用的 spaCy 模型。默认情况下,SetFitABSA 使用 en_core_web_lg,但 en_core_web_smen_core_web_md 也是不错的选择。

!spacy download en_core_web_lg
!spacy download en_core_web_sm

训练 SetFitABSA

首先,我们必须通过 AbsaModel.from_pretrained() 实例化一个新的 AbsaModel。这可以通过为 SetFitABSA 的三个阶段中的每个阶段提供配置来完成:

  1. 提供要用于方面过滤 SetFit 模型的 Sentence Transformer 模型的名称或路径作为第一个参数。
  2. (可选)提供要用于极性分类 SetFit 模型的 Sentence Transformer 模型的名称或路径作为第二个参数。如果未提供,则与方面过滤模型相同的 Sentence Transformer 模型也将用于极性分类模型。
  3. (可选)通过 spacy_model 关键字参数提供要使用的 spaCy 模型。

例如:

from setfit import AbsaModel

model = AbsaModel.from_pretrained(
    "sentence-transformers/all-MiniLM-L6-v2",
    "sentence-transformers/all-mpnet-base-v2",
    spacy_model="en_core_web_sm",
)

或者一个最小示例:

from setfit import AbsaModel

model = AbsaModel.from_pretrained("BAAI/bge-small-en-v1.5")

然后我们必须准备一个训练/测试集。这些数据集必须有 "text""span""label""ordinal" 列。

  • "text":包含方面的完整句子或文本。例如:"But the staff was so horrible to us."
  • "span":来自完整句子中的一个方面。可以是多个单词。例如:"staff"
  • "label":与方面跨度对应的(极性)标签。例如:"negative"
  • "ordinal":如果方面跨度在文本中出现多次,则此序数表示这些出现的索引。通常这只是 0。例如:0

已经符合此格式的两个数据集是 SemEval-2014 Task 4 的这些评论数据集:

from dataset import load_dataset

# The training/eval dataset must have `text`, `span`, `label`, and `ordinal` columns
dataset = load_dataset("tomaarsen/setfit-absa-semeval-restaurants", split="train")
train_dataset = dataset.select(range(128))
eval_dataset = dataset.select(range(128, 256))

我们可以像正常的 SetFit 一样开始训练,但现在使用 AbsaTrainer 代替。

如果需要,您可以通过同时使用 argspolarity_args 关键字参数来为方面模型和极性模型指定单独的训练参数。

from setfit import AbsaTrainer, TrainingArguments
from transformers import EarlyStoppingCallback

args = TrainingArguments(
    output_dir="models",
    num_epochs=5,
    use_amp=True,
    batch_size=128,
    eval_strategy="steps",
    eval_steps=50,
    save_steps=50,
    load_best_model_at_end=True,
)

trainer = AbsaTrainer(
    model,
    args=args,
    train_dataset=train_dataset,
    eval_dataset=eval_dataset,
    callbacks=[EarlyStoppingCallback(early_stopping_patience=5)],
)
trainer.train()
***** Running training *****
  Num examples = 249
  Num epochs = 5
  Total optimization steps = 1245
  Total train batch size = 128
{'aspect_embedding_loss': 0.2542, 'learning_rate': 1.6e-07, 'epoch': 0.0}                                                                                          
{'aspect_embedding_loss': 0.2437, 'learning_rate': 8.000000000000001e-06, 'epoch': 0.2}                                                                            
{'eval_aspect_embedding_loss': 0.2511, 'learning_rate': 8.000000000000001e-06, 'epoch': 0.2}                                                                       
{'aspect_embedding_loss': 0.2209, 'learning_rate': 1.6000000000000003e-05, 'epoch': 0.4}                                                                           
{'eval_aspect_embedding_loss': 0.2385, 'learning_rate': 1.6000000000000003e-05, 'epoch': 0.4}                                                                      
{'aspect_embedding_loss': 0.0165, 'learning_rate': 1.955357142857143e-05, 'epoch': 0.6}                                                                            
{'eval_aspect_embedding_loss': 0.2776, 'learning_rate': 1.955357142857143e-05, 'epoch': 0.6}                                                                       
{'aspect_embedding_loss': 0.0158, 'learning_rate': 1.8660714285714287e-05, 'epoch': 0.8}                                                                           
{'eval_aspect_embedding_loss': 0.2848, 'learning_rate': 1.8660714285714287e-05, 'epoch': 0.8}                                                                      
{'aspect_embedding_loss': 0.0015, 'learning_rate': 1.7767857142857143e-05, 'epoch': 1.0}                                                                           
{'eval_aspect_embedding_loss': 0.3133, 'learning_rate': 1.7767857142857143e-05, 'epoch': 1.0}                                                                      
{'aspect_embedding_loss': 0.0012, 'learning_rate': 1.6875e-05, 'epoch': 1.2}                                                                                       
{'eval_aspect_embedding_loss': 0.2966, 'learning_rate': 1.6875e-05, 'epoch': 1.2}                                                                                  
{'aspect_embedding_loss': 0.0009, 'learning_rate': 1.598214285714286e-05, 'epoch': 1.41}                                                                           
{'eval_aspect_embedding_loss': 0.2996, 'learning_rate': 1.598214285714286e-05, 'epoch': 1.41}                                                                      
 28%|██████████████████████████████████▎                                                                                       | 350/1245 [03:40<09:24,  1.59it/s] 
Loading best SentenceTransformer model from step 100.
{'train_runtime': 226.7429, 'train_samples_per_second': 702.822, 'train_steps_per_second': 5.491, 'epoch': 1.41}
***** Running training *****
  Num examples = 39
  Num epochs = 5
  Total optimization steps = 195
  Total train batch size = 128
{'polarity_embedding_loss': 0.2267, 'learning_rate': 1.0000000000000002e-06, 'epoch': 0.03}                                                                        
{'polarity_embedding_loss': 0.1038, 'learning_rate': 1.6571428571428574e-05, 'epoch': 1.28}                                                                        
{'eval_polarity_embedding_loss': 0.1946, 'learning_rate': 1.6571428571428574e-05, 'epoch': 1.28}                                                                   
{'polarity_embedding_loss': 0.0116, 'learning_rate': 1.0857142857142858e-05, 'epoch': 2.56}                                                                        
{'eval_polarity_embedding_loss': 0.2364, 'learning_rate': 1.0857142857142858e-05, 'epoch': 2.56}                                                                   
{'polarity_embedding_loss': 0.0059, 'learning_rate': 5.142857142857142e-06, 'epoch': 3.85}                                                                         
{'eval_polarity_embedding_loss': 0.2401, 'learning_rate': 5.142857142857142e-06, 'epoch': 3.85}                                                                    
100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 195/195 [00:54<00:00,  3.58it/s]
Loading best SentenceTransformer model from step 50.
{'train_runtime': 54.4104, 'train_samples_per_second': 458.736, 'train_steps_per_second': 3.584, 'epoch': 5.0}

评估也像正常一样,尽管您现在可以分别从方面模型和极性模型中获得结果。

metrics = trainer.evaluate(eval_dataset)
print(metrics)
***** Running evaluation *****
{'aspect': {'accuracy': 0.7130649876321116}, 'polarity': {'accuracy': 0.7102310231023102}}

请注意,方面准确性是指将 spaCy 模型中的方面候选跨度分类为真实方面与否的准确性,而极性准确性是指仅将过滤后的方面候选跨度分类到正确类别的准确性。

保存 SetFitABSA 模型

训练完成后,我们可以使用熟悉的 AbsaModel.save_pretrained()AbsaTrainer.push_to_hub()/AbsaModel.push_to_hub() 方法来保存模型。但是,与通常不同的是,保存 AbsaModel 涉及保存两个独立的模型:方面 SetFit 模型和极性 SetFit 模型。因此,我们可以提供两个目录或 repo_id

model.save_pretrained(
    "models/setfit-absa-model-aspect",
    "models/setfit-absa-model-polarity",
)
# or
model.push_to_hub(
    "tomaarsen/setfit-absa-bge-small-en-v1.5-restaurants-aspect",
    "tomaarsen/setfit-absa-bge-small-en-v1.5-restaurants-polarity",
)

但是,您也可以只提供一个目录或 repo_id,并且会自动添加 -aspect-polarity。因此,以下代码与之前的代码片段等效:

model.save_pretrained("models/setfit-absa-model")
# or
model.push_to_hub("tomaarsen/setfit-absa-bge-small-en-v1.5-restaurants")

加载 SetFitABSA 模型

加载训练好的 AbsaModel 涉及调用 AbsaModel.from_pretrained(),并提供 SetFitABSA 三个阶段的详细信息:

  1. 提供用于方面过滤模型的已训练 SetFit ABSA 模型的名称或路径作为第一个参数。
  2. 提供用于极性分类模型的已训练 SetFit ABSA 模型的名称或路径作为第二个参数。
  3. (可选)通过 spacy_model 关键字参数提供要使用的 spaCy 模型。建议使其与训练期间使用的模型匹配。默认值为 "en_core_web_lg"

例如:

from setfit import AbsaModel

model = AbsaModel.from_pretrained(
    "tomaarsen/setfit-absa-bge-small-en-v1.5-restaurants-aspect",
    "tomaarsen/setfit-absa-bge-small-en-v1.5-restaurants-polarity",
    spacy_model="en_core_web_lg",
)

我们现在已成功从以下位置加载了 SetFitABSA 模型:

使用 SetFitABSA 模型进行推理

要使用训练好的 AbsaModel 执行推理,我们可以使用 AbsaModel.predict()

preds = model.predict([
    "Best pizza outside of Italy and really tasty.",
    "The food variations are great and the prices are absolutely fair.",
    "Unfortunately, you have to expect some waiting time and get a note with a waiting number if it should be very full."
])
print(preds)
# [
#     [{'span': 'pizza', 'polarity': 'positive'}],
#     [{'span': 'food variations', 'polarity': 'positive'}, {'span': 'prices', 'polarity': 'positive'}],
#     [{'span': 'waiting number', 'polarity': 'negative'}]
# ]

挑战

如果你愿意,我挑战你根据此文档训练并上传一个用于笔记本电脑评论的 SetFitABSA 模型。

< > 在 GitHub 上更新