当前位置:   article > 正文

【Coggle 30 Days of ML】汽车领域多语种迁移学习挑战赛(4)

【Coggle 30 Days of ML】汽车领域多语种迁移学习挑战赛(4)

目录

任务

Just Do It!  

 1.Bert模型入门

1.1前置知识

1.2导入预训练模型

1.3训练数据处理

 1.4数据及读取及模型定义

2.Bert文本分类

2.1开始读取数据集

2.2加载模型

2.3开始训练

 2.4预测


任务

Just Do It!  

 1.Bert模型入门

1.1前置知识

bert模型用的库主要是huggingface的transformers库

目前Transformers 库支持三个最流行的深度学习库(PyTorch、TensorFlow 和 JAX)。

Transformers 库比较重要的有:pipeline、AutoTokenizer、AutoModelForSequenceClassification等等的使用。

Pipeline

pipeline() 的作用是使用预训练模型进行推断,它支持从 这里 下载的所有模型。它将模型的预处理, 后处理等步骤包装起来,使得我们可以直接定义好任务名称后,输出文本,直接得到我们需要的结果。这是一个高级的API,可以让我们领略到transformers 这个库的强大且友好。

使用pipeline的api,可以使用transformers快速完成各种任务.

主要有以下三个步骤被包装起来了:

  1. 输入文本被预处理成机器可以理解的格式
  2. 被处理后的输入被传入模型中
  3. 模型的预测结果经过后处理,得到人类可以理解的结果

eg:

上述是调用pipeline快速使用transformer,上述选择模型部分除了指定model外,还可以使用本地加载。

  1. from transformers import AutoModelForSequenceClassification
  2. from transformers import AutoTokenizer
  3. from transformers import pipeline
  4. model_path = r"ckiplab/bert-base-chinese-ner"
  5. model = AutoModelForSequenceClassification.from_pretrained(model_path)
  6. tokenizer = AutoTokenizer.from_pretrained(model_path)
  7. classifier = pipeline(task='ner',model=model,tokenizer=tokenizer)
  8. text = '我爱自然语言处理技术.我爱北京天安门!'
  9. for entity in generator(text):
  10. print(entity)

AutoTokenizer

这个类是用来自动下载与模型相关联的标记器,并且可以进行实例化。主要是在将数据喂给模型之前,将数据进行预处理(Tokenize、填充、截断等)。

AutoModelForSequenceClassification

主要是用来加载模型的。这个类是用来去下载模型本身。(注意:⚠️如果我们在别的任务上使用这个库,模型的类会发生改变)

我们已经得到了预训练模型,那么下面就要将输入转化为模型能够接受的形式。怎么转化呢?就是把输入的字符串通过刚刚导入的分词器tokenizer进行转化。

  1. inputs = tokenizer(["阿水很帅,我也这样觉得。", "不对啊,你在欺骗我"], truncation=True, max_length=20, padding=True)
  2. inputs
  3. # input_ids:这个字在vocab次序
  4. # token_type_ids:字符是第一个句子的,还是第二个句子的
  5. # attention_mask:字符是不是padding的?

tokenizer后的inputs为字典,包含三个键input_ids、token_type_ids、attention_mask。

inputs_ids:为输入字符串中的每个字对应到词典vocab中的序号。其中每句话的开头结尾都添加了特殊标记,开头的特殊标记经过tokenizer变成了101,结尾的编程102。

token_type_ids:字符是第一个句子的,还是第二个句子的。不同的句子对应的标记值也不一样。

attention_mask:主要输入的几个句子当中最长的一句,如果打开了padding,那他就会把其他比最长的一句用0给填补上。观察上图attention_mask的后面3个0就意味着填补。


前置知识了解的差不多了,下面对应到比赛中,步骤如下:

1.2导入预训练模型

我们要做的第一件事就是导入预训练模型

  1. from transformers import AutoTokenizer, AutoModelForMaskedLM, AutoConfig, BertModel, AutoModel
  2. model = AutoModel.from_pretrained("hfl/chinese-roberta-wwm-ext")
  3. tokenizer = AutoTokenizer.from_pretrained("bert-base-multilingual-cased")
  4. config = AutoConfig.from_pretrained("bert-base-multilingual-cased")

1.3训练数据处理

我们需要先对训练集做一些处理,把训练集中的标签种类去掉。

  1. for tag in ['intent', 'device', 'mode', 'offset', 'endloc', 'landmark', 'singer', 'song']:
  2. train_ja['槽值1'] = train_ja['槽值1'].str.replace(f'{tag}:', '')
  3. train_ja['槽值2'] = train_ja['槽值2'].str.replace(f'{tag}:', '')
  4. train_cn['槽值1'] = train_cn['槽值1'].str.replace(f'{tag}:', '')
  5. train_cn['槽值2'] = train_cn['槽值2'].str.replace(f'{tag}:', '')
  6. train_en['槽值1'] = train_en['槽值1'].str.replace(f'{tag}:', '')
  7. train_en['槽值2'] = train_en['槽值2'].str.replace(f'{tag}:', '')

然后再将训练集中的中英日文拼接在一起,再使用pd.factorize对训练集进行编码。

pd.factorize简单来说就是将所有输入的字符做一个unique,去掉相同的字,只剩下两两互斥的列表,假设叫list_unique。然后遍历一遍输入的每个字,根据这个字在list_unique中的位置做一个编码。

  1. train_df = pd.concat([
  2. train_ja[['原始文本', '意图', '槽值1', '槽值2']],
  3. train_cn[['原始文本', '意图', '槽值1', '槽值2']].sample(10000),
  4. train_en[['原始文本', '意图', '槽值1', '槽值2']],
  5. ],axis = 0)
  6. train_df = train_df.sample(frac=1.0)
  7. train_df['意图_encode'], lbl_ecode = pd.factorize(train_df['意图'])

 1.4数据及读取及模型定义

定义数据集读取类和模型类

  1. from torch.utils.data import Dataset, DataLoader, TensorDataset
  2. import torch
  3. from torch import nn
  4. # 数据集读取
  5. class XunFeiDataset(Dataset):
  6. def __init__(self, encodings, intent):
  7. self.encodings = encodings
  8. self.intent = intent
  9. # 读取单个样本
  10. def __getitem__(self, idx):
  11. item = {key: torch.tensor(val[idx]) for key, val in self.encodings.items()}
  12. item['label'] = torch.tensor(int(self.intent[idx]))
  13. return item
  14. def __len__(self):
  15. return len(self.intent)
  16. class XunFeiModel(nn.Module):
  17. def __init__(self, num_labels):
  18. super(XunFeiModel,self).__init__()
  19. self.model = model = AutoModel.from_pretrained("bert-base-multilingual-cased")
  20. self.dropout = nn.Dropout(0.1)
  21. self.classifier = nn.Linear(768, num_labels)
  22. def forward(self, input_ids=None, attention_mask=None,labels=None):
  23. outputs = self.model(input_ids=input_ids, attention_mask=attention_mask)
  24. sequence_output = self.dropout(outputs[0]) #outputs[0]=last hidden state
  25. logits = self.classifier(sequence_output[:,0,:].view(-1,768))
  26. return logits

2.Bert文本分类

2.1开始读取数据集

  1. train_encoding = tokenizer(train_df['原始文本'].tolist()[:-500], truncation=True, padding=True, max_length=40)
  2. val_encoding = tokenizer(train_df['原始文本'].tolist()[-500:], truncation=True, padding=True, max_length=40)
  3. train_dataset = XunFeiDataset(train_encoding, train_df['意图_encode'].tolist()[:-500])
  4. val_dataset = XunFeiDataset(val_encoding, train_df['意图_encode'].tolist()[-500:])
  5. # 单个读取到批量读取
  6. train_loader = DataLoader(train_dataset, batch_size=16, shuffle=True)
  7. val_dataloader = DataLoader(val_dataset, batch_size=16, shuffle=False)

2.2加载模型

将模型加载到gpu上(如果有的话),没有gpu就用cpu加载。

  1. model = XunFeiModel(18)
  2. device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
  3. # device = 'cpu'
  4. model = model.to(device)

2.3开始训练

  1. from torch.nn import CrossEntropyLoss
  2. from torch.optim import AdamW
  3. loss_fn = CrossEntropyLoss() # ingore index = -1
  4. optim = AdamW(model.parameters(), lr=5e-5)
  5. def train():
  6. model.train()
  7. total_train_loss = 0
  8. iter_num = 0
  9. total_iter = len(train_loader)
  10. for batch in train_loader:
  11. # 正向传播
  12. optim.zero_grad()
  13. input_ids = batch['input_ids'].to(device)
  14. attention_mask = batch['attention_mask'].to(device)
  15. label = batch['label'].to(device)
  16. pred = model(
  17. input_ids,
  18. attention_mask
  19. )
  20. loss = loss_fn(pred, label)
  21. # 反向梯度信息
  22. loss.backward()
  23. torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0)
  24. # 参数更新
  25. optim.step()
  26. iter_num += 1
  27. if(iter_num % 100 == 0):
  28. print("iter_num: %d, loss: %.4f, %.2f%% %.4f" % (
  29. iter_num, loss.item(), iter_num/total_iter*100,
  30. (pred.argmax(1) == label).float().data.cpu().numpy().mean(),
  31. ))
  32. def validation():
  33. model.eval()
  34. label_acc = 0
  35. for batch in val_dataloader:
  36. with torch.no_grad():
  37. input_ids = batch['input_ids'].to(device)
  38. attention_mask = batch['attention_mask'].to(device)
  39. label = batch['label'].to(device)
  40. pred = model(
  41. input_ids,
  42. attention_mask
  43. )
  44. label_acc += (pred.argmax(1) == label).float().sum().item()
  45. label_acc = label_acc / len(val_dataloader.dataset)
  46. print("-------------------------------")
  47. print("Accuracy: %.4f" % (label_acc))
  48. print("-------------------------------")
  49. for epoch in range(2):
  50. train()
  51. validation()

 2.4预测

  1. def prediction():
  2. model.eval()
  3. test_label = []
  4. for batch in test_dataloader:
  5. with torch.no_grad():
  6. input_ids = batch['input_ids'].to(device)
  7. attention_mask = batch['attention_mask'].to(device)
  8. pred = model(input_ids, attention_mask)
  9. test_label += list(pred.argmax(1).data.cpu().numpy())
  10. return test_label
  11. test_encoding = tokenizer(test_en['原始文本'].tolist(), truncation=True, padding=True, max_length=40)
  12. test_dataset = XunFeiDataset(test_encoding, [0] * len(test_en))
  13. test_dataloader = DataLoader(test_dataset, batch_size=16, shuffle=False)
  14. test_en_intent = prediction()
  15. test_encoding = tokenizer(test_ja['原始文本'].tolist(), truncation=True, padding=True, max_length=40)
  16. test_dataset = XunFeiDataset(test_encoding, [0] * len(test_ja))
  17. test_dataloader = DataLoader(test_dataset, batch_size=16, shuffle=False)
  18. test_ja_intent = prediction()
  19. test_ja['意图'] = [lbl_ecode[x] for x in test_ja_intent]
  20. test_en['意图'] = [lbl_ecode[x] for x in test_en_intent]
  21. test_en['槽值1'] = np.nan
  22. test_en['槽值2'] = np.nan
  23. test_ja['槽值1'] = np.nan
  24. test_ja['槽值2'] = np.nan
  25. writer = pd.ExcelWriter('submit.xlsx')
  26. test_en[['意图', '槽值1', '槽值2']].to_excel(writer, sheet_name='英文_testA', index=None)
  27. test_ja[['意图', '槽值1', '槽值2']].to_excel(writer, sheet_name='日语_testA', index=None)
  28. writer.save()
  29. writer.close()


参考内容:

transformers库的使用【一】——pipeline的简单使用_桉夏与猫的博客-CSDN博客_transformers库使用

Transformers 库的基本使用_空杯的境界的博客-CSDN博客_transformers库

https://www.wpsshop.cn/w/小丑西瓜9/article/detail/548760

推荐阅读
相关标签
  

闽ICP备14008679号