文本问答是常见的NLP任务,文本介绍了如何使用Bert模型完成文本问答,并给出了各自的步骤。
任务介绍
机器阅读理解和问答任务(QA)指的是给定一个问题和一个或多个文本,训练QA模型可以根据文本找出答案,标准答案一般与文本中的答案完全匹配。

Finetune原理
模型的输入句子对由问题和包含答案的文本组成,并有特殊分隔符[SEP]
分隔。同其他下游任务一样,输入序列的第一个token为特殊分类嵌入[CLS]
,同时输入序列为token embeddings,segmentation embeddings,以及position embedding之和。

步骤1:数据处理
首先读取选中的模型,并利用tokenizer对输入的文本和问题进行处理。
from transformers import BertTokenizerFast, BertForQuestionAnswering
tokenizer = BertTokenizerFast.from_pretrained('hfl/chinese-bert-wwm-ext')
model = BertForQuestionAnswering.from_pretrained('hfl/chinese-bert-wwm-ext')
train_encodings = tokenizer(list(train_df['text'])[:], list(train_df['question_text'])[:],
return_tensors='pt', truncation=True, padding=True,
max_length=512)
生成训练数据中答案的开始/结束位置:
train_encodings['start_positions'] = [train_encodings.char_to_token(idx, x) for idx, x in enumerate(train_df['index_start'].values[:])]
train_encodings['end_positions'] = [train_encodings.char_to_token(idx, x-1) for idx, x in enumerate(train_df['index_end'].values[:])]
步骤2:定义数据集
根据Pytorch框架定义模型数据集,直接传入数据集,对文本和答案的开始/结束位置进行转换即可。
import torch
from torch.utils.data import Dataset, DataLoader, TensorDataset
import torch
class SquadDataset(torch.utils.data.Dataset):
def __init__(self, encodings):
self.encodings = encodings
def __getitem__(self, idx):
return {key: torch.tensor(val[idx]) for key, val in self.encodings.items()}
def __len__(self):
return len(self.encodings.input_ids)
train_dataset = SquadDataset(train_encodings)
步骤3:进行训练
根据定义好的数据集和模型直接进行训练即可,此时模型正向传播需要传入答案的开始/结束位置。
from torch.utils.data import DataLoader
from transformers import AdamW
device = torch.device('cuda') if torch.cuda.is_available() else torch.device('cpu')
model.to(device)
model.train()
train_loader = DataLoader(train_dataset, batch_size=8, shuffle=True)
optim = AdamW(model.parameters(), lr=5e-5)
for epoch in range(3):
for idx, batch in enumerate(train_loader):
optim.zero_grad()
input_ids = batch['input_ids'].to(device)
attention_mask = batch['attention_mask'].to(device)
start_positions = batch['start_positions'].to(device)
end_positions = batch['end_positions'].to(device)
outputs = model(input_ids, attention_mask=attention_mask, start_positions=start_positions, end_positions=end_positions)
loss = outputs[0]
loss.backward()
optim.step()
start_pred = torch.argmax(outputs['start_logits'], dim=1)
end_pred = torch.argmax(outputs['end_logits'], dim=1)
acc1 = ( (start_pred == start_positions).sum() / len(start_pred) ).item()
acc2 = ( (end_pred == end_positions).sum() / len(start_pred) ).item()
if idx % 10 == 0:
print(loss.item(), acc1, acc2)
with codecs.open('log.log', 'a') as up:
up.write('{3}\t{0}\t{1}\t{2}\n'.format(loss.item(), acc1, acc2,
str(epoch) + '/' + str(idx) +'/'+ str(len(train_loader))))
model.eval()


文章转载自Coggle数据科学,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




