文本匹配是指计算机系统识别和确定两段文本之间关系的任务。这个概念非常广泛,涵盖了各种场景,其中文本之间的关系可以是有相似度、问答、对话、推理等。在不同的应用场景下,文本匹配的具体定义可能会有所不同。
以下是几种常见的文本匹配任务及其特点:
- 文本相似度计算:计算两个文本之间的相似程度,例如判断两个句子是否表达相同或相似的意思。
- 问答匹配:将用户提出的问题与数据库中的答案进行匹配,以提供正确的信息。
- 对话匹配:在对话系统中,识别用户输入的文本与系统回复之间的匹配关系,以确保对话的连贯性和准确性。
- 文本推理 :根据给定的文本内容推断出新的信息或结论。
此外,像抽取式机器阅读理解和多项选择这样的任务,其本质也是文本匹配。在这些任务中,系统需要理解文本内容,并将其与问题或选项进行匹配,以确定正确答案。
总之,文本匹配是自然语言处理中的一个重要概念,广泛应用于信息检索、机器翻译、文本生成、对话系统等多个领域。随着技术的发展,文本匹配的算法和模型也在不断进步,以更准确地理解和匹配文本内容。
本次先介绍最简单的文本相似度计算的任务,后面将其他的信息检索、机器翻译、文本生成、对话系统等任务进行实战。
基本步骤:
1 加载数据集 2 数据预处理 3 创建模型 4 创建评估函数 5 创建训练器 6 训练模型 7 评估 8 预测
1 加载数据集
在hugging face没有找到合适的数据集,所以找了一个资源上传在git上,大家可自取
python
dataset = load_dataset("json", data_files="/kaggle/input/sentence/sentence_pair.json", split="train")
dataset
Dataset({
features: ['sentence1', 'sentence2', 'label'],
num_rows: 10000
})
看下数据格式
python
dataset[10]
{'sentence1': '她是一个非常慷慨的女人,拥有自己的一大笔财产。',
'sentence2': '她有很多钱,但她是个慷慨的女人。',
'label': '1'}
2 数据预处理
python
datasets = dataset.train_test_split(test_size=0.2)
datasets
DatasetDict({
train: Dataset({
features: ['sentence1', 'sentence2', 'label'],
num_rows: 8000
})
test: Dataset({
features: ['sentence1', 'sentence2', 'label'],
num_rows: 2000
})
})
数据格式划分
python
import torch
tokenizer = AutoTokenizer.from_pretrained("bert-base-chinese")
def process_function(examples):
tokenized_examples = tokenizer(examples["sentence1"], examples["sentence2"], max_length=128, truncation=True)
tokenized_examples["labels"] = [int(label) for label in examples["label"]]
return tokenized_examples
tokenized_datasets = datasets.map(process_function, batched=True, remove_columns=datasets["train"].column_names)
tokenized_datasets
原始数据中label是字符串格式,需要int转换下
python
print(tokenized_datasets["train"][0])
{'input_ids': [101, 704, 1286, 1762, 100, 4638, 2207, 2238, 828, 2622, 8024, 4692, 4708, 1920, 6496, 1403, 3777, 6804, 6624, 1343, 511, 102, 1762, 100, 7353, 6818, 3766, 3300, 1920, 6496, 511, 102], 'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], 'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], 'labels': 0}
3 加载模型
python
from transformers import BertForSequenceClassification
model = AutoModelForSequenceClassification.from_pretrained("bert-base-chinese")
4 创建评估函数
python
import evaluate
acc_metric = evaluate.load("accuracy")
f1_metirc = evaluate.load("f1")
def eval_metric(eval_predict):
predictions, labels = eval_predict
predictions = predictions.argmax(axis=-1)
acc = acc_metric.compute(predictions=predictions, references=labels)
f1 = f1_metirc.compute(predictions=predictions, references=labels)
acc.update(f1)
return acc
5 创建训练器
python
train_args = TrainingArguments(output_dir="./cross_model", # 输出文件夹
per_device_train_batch_size=32, # 训练时的batch_size
per_device_eval_batch_size=32, # 验证时的batch_size
logging_steps=10, # log 打印的频率
evaluation_strategy="epoch", # 评估策略
save_strategy="epoch", # 保存策略
save_total_limit=3, # 最大保存数
learning_rate=2e-5, # 学习率
weight_decay=0.01, # weight_decay
metric_for_best_model="f1", # 设定评估指标
report_to=['tensorboard'],
load_best_model_at_end=True) # 训练完成后加载最优模型
train_args
6 开始训练
python
from transformers import DataCollatorWithPadding
trainer = Trainer(model=model,
args=train_args,
train_dataset=tokenized_datasets["train"],
eval_dataset=tokenized_datasets["test"],
data_collator=DataCollatorWithPadding(tokenizer=tokenizer),
compute_metrics=eval_metric)
trainer.train()
python
TrainOutput(global_step=750, training_loss=0.1850536205768585, metrics={'train_runtime': 302.9995, 'train_samples_per_second': 79.208, 'train_steps_per_second': 2.475, 'total_flos': 1552684115443200.0, 'train_loss': 0.1850536205768585, 'epoch': 3.0})
7 评估
python
trainer.evaluate(tokenized_datasets["test"])
{'eval_loss': 0.2481037676334381,
'eval_accuracy': 0.912,
'eval_f1': 0.8894472361809046,
'eval_runtime': 7.6159,
'eval_samples_per_second': 262.61,
'eval_steps_per_second': 8.272,
'epoch': 3.0}
8 预测
python
pipe = pipeline("text-classification", model=model, tokenizer=tokenizer, device=0)
result = pipe({"text": "昨天我做了个梦", "text_pair": "下雨了"})
result
{'label': '不相似', 'score': 0.989981472492218}
补充
上面是用分类的方式进行训练的,这里有个问题就是如果我们呢需要对一个句子去喝多个句子进行匹配找出最相似的句子就不行了,因为上面这种方式的结果没有对比的价值。所以我们需要修改下,使用MSE来计算损失。
需要修改的地方主要是两个,
数据预处理
python
def process_function(examples):
tokenized_examples = tokenizer(examples["sentence1"], examples["sentence2"], max_length=128, truncation=True)
tokenized_examples["labels"] = [float(label) for label in examples["label"]]
return tokenized_examples
计算MSE需要计算损失的具体数值,所以要转换成浮点型
评估函数
python
def eval_metric(eval_predict):
predictions, labels = eval_predict
predictions = [int(p > 0.5) for p in predictions]
labels = [int(l) for l in labels]
# predictions = predictions.argmax(axis=-1)
acc = acc_metric.compute(predictions=predictions, references=labels)
f1 = f1_metirc.compute(predictions=predictions, references=labels)
acc.update(f1)
return acc
预测的是一个具体的数值,不是【0,1】,所以计算准确率时要转换下
模型
python
num_labels=1
num_labels改为一,用回归的形式去预测