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. 提供 Sentence Transformer 模型的名称或路径,作为第一个参数用于方面过滤 SetFit 模型。
  2. (可选)提供 Sentence Transformer 模型的名称或路径,作为第二个参数用于极性分类 SetFit 模型。如果未提供,则与方面过滤模型相同的 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 代替。

如果您愿意,您可以使用 `args` 和 `polarity_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 上更新