Kaggle从零到实践:Bert中文多项选择
机器阅读理解最大的挑战就是回答需要外部先验知识的问题,文本将使用Bert模型来完成C3(中文多项选择题)。
C3数据集一共有13369篇文章和19577个问题,其中的60%用是训练集,20%是开发集,20%是测试集。

步骤1:查看数据样例
C3数据集的案例如下,模型需要对对话和问题进行理解,最后从待选选项中识别出正确的答案。
对话:
男:你今天晚上有时间吗?我们一起去看电影吧?
女:你喜欢恐怖片和爱情片,但是我喜欢喜剧片,科幻片一般。
问题:女的最喜欢哪种电影?
可选择项:['恐怖片', '爱情片', '喜剧片', '科幻片']
正确答案:喜剧片
步骤2:定义数据读取格式
接下来完成具体的数据读取格式转换,首先读取Bert Tokenizer。
import torchfrom transformers import BertTokenizertokenizer = BertTokenizer.from_pretrained('bert-base-chinese', num_choices=4)
然后定义具体的batch数据处理,需要将问题和待选项进行处理。
def collate_fn(data): #将文章问题选项拼在一起后,得到分词后的数字id,输出的size是(batch, n_choices, max_len)
input_ids, attention_mask, token_type_ids = [], [], []
for x in data:
text = tokenizer(x[1], text_pair=x[0], padding='max_length', truncation=True,
max_length=128, return_tensors='pt')
input_ids.append(text['input_ids'].tolist())
attention_mask.append(text['attention_mask'].tolist())
token_type_ids.append(text['token_type_ids'].tolist())
input_ids = torch.tensor(input_ids)
attention_mask = torch.tensor(attention_mask)
token_type_ids = torch.tensor(token_type_ids)
label = torch.tensor([x[-1] for x in data])
return input_ids, attention_mask, token_type_ids, label
最后定义Dataset,需要将多选项转为单个选择和问题的匹配过程。
import torchfrom torch.utils.data import Dataset, DataLoader, TensorDataset
class TextDataset(Dataset): def __init__(self, data, labels): self.data = data self.labels = labels
def __getitem__(self, idx): label = self.labels[idx] question = self.data[idx][1][0]['question'] content = '。'.join(self.data[idx][0]) choice = self.data[idx][1][0]['choice'] if len(choice) < 4: #如果选项不满四个,就补“不知道” for i in range(4-len(choice)): choice.append('不知道')
content = [content for i in range(len(choice))] pair = [question + ' ' + i for i in choice]
return content, pair, label
def __len__(self): return len(self.labels)
train_dataset = TextDataset(train, train_label)test_dataset = TextDataset(val, val_label)
步骤3:定义Bert模型
这里可以直接使用BertForMultipleChoice
来完成Finetune过程。
import torch
from transformers import BertForMultipleChoice, AdamW, get_linear_schedule_with_warmup
model = BertForMultipleChoice.from_pretrained('bert-base-chinese')
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model.to(device)
步骤4:模型训练与验证
当定义好数据集、模型后,接下来是万年不变的模型正向传播和反向传播代码。
from tqdm import tqdm
def train(): model.train() total_train_loss = 0 iter_num = 0 total_iter = len(train_loader) for idx, (input_ids, attention_mask, token_type_ids, labels) in enumerate(train_loader): optim.zero_grad()
input_ids = input_ids.to(device) attention_mask = attention_mask.to(device) labels = labels.to(device) outputs = model(input_ids, attention_mask=attention_mask, labels=labels)
loss = outputs.loss
if idx % 20 == 0: with torch.no_grad(): print((outputs[1].argmax(1).data == labels.data).float().mean().item(), loss.item())
total_train_loss += loss.item() loss.backward() torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0) optim.step() scheduler.step()
iter_num += 1 if(iter_num % 100 ==0): print('epoth: %d, iter_num: %d, loss: %.4f, %.2f%%' % (epoch, iter_num, loss.item(), iter_num/total_iter*100))
print('Epoch: %d, Average training loss: %.4f'%(epoch, total_train_loss/len(train_loader)))
def validation(): model.eval() total_eval_accuracy = 0 total_eval_loss = 0 for (input_ids, attention_mask, token_type_ids, labels) in test_dataloader: with torch.no_grad(): input_ids = input_ids.to(device) attention_mask = attention_mask.to(device) labels = labels.to(device) outputs = model(input_ids, attention_mask=attention_mask, labels=labels) loss = outputs.loss logits = outputs[1]
total_eval_loss += loss.item() logits = logits.detach().cpu().numpy() label_ids = labels.to('cpu').numpy() total_eval_accuracy += (outputs[1].argmax(1).data == labels.data).float().mean().item()
avg_val_accuracy = total_eval_accuracy / len(test_dataloader) print('Accuracy: %.4f' % (avg_val_accuracy)) print('Average testing loss: %.4f'%(total_eval_loss/len(test_dataloader))) print('-------------------------------')
for epoch in range(4): print('------------Epoch: %d ----------------' % epoch) validation() train()
通过上述代码运行完成,可以在C3数据集上取得60%+的精度,妈妈再也不用担心我不会多项选择了!

AINLP
一个有趣有AI的自然语言处理公众号:关注AI、NLP、机器学习、推荐系统、计算广告等相关技术。公众号可直接对话双语聊天机器人,尝试自动对联、作诗机、藏头诗生成器,调戏夸夸机器人、彩虹屁生成器,使用中英翻译,查询相似词,测试NLP相关工具包。
331篇原创内容
公众号
赞 (0)