当前位置:   article > 正文

使用BERT进行文本分类

bert文本分类

a1bdee5d0531017b62484b534620e1bc.png

本范例我们微调transformers中的BERT来处理文本情感分类任务。

我们的数据集是美团外卖的用户评论数据集。

模型目标是把评论分成好评(标签为1)和差评(标签为0)。

  1. #安装库
  2. #!pip install datasets 
  3. #!pip install transformers[torch]
  4. #!pip install torchkeras

公众号算法美食屋后台回复关键词 torchkeras, 获取本文源代码和waimai评论数据集。

一,准备数据

准备数据阶段主要需要用到的是datasets.Dataset 和transformers.AutoTokenizer。

1,数据加载

HuggingFace的datasets库提供了类似TensorFlow中的tf.data.Dataset的功能。

  1. import numpy as np 
  2. import pandas as pd 
  3. import torch 
  4. from torch.utils.data import DataLoader 
  5. import datasets
  1. df = pd.read_csv("data/waimai_10k.csv")
  2. ds = datasets.Dataset.from_pandas(df) 
  3. ds = ds.shuffle(42) #打乱顺序
  4. ds = ds.rename_columns({"review":"text","label":"labels"})
ds[0]
{'labels': 0, 'text': '晚了半小时,七元套餐饮料就给的罐装的可乐,真是可以'}
ds[0:4]["text"]
  1. ['晚了半小时,七元套餐饮料就给的罐装的可乐,真是可以',
  2. '很好喝!天天都喝~~',
  3. '东西很少,像半分每次都是这样失望',
  4. '配送比较慢(不是高峰时间点的结果1个多小时才送到);菜品备注了“老人吃请少油少盐”,结果还是很咸很油,哎…失望']

2,文本分词

transformers库使用tokenizer进行文本分词。

  1. from transformers import AutoTokenizer #BertTokenizer
  2. tokenizer = AutoTokenizer.from_pretrained('bert-base-chinese') #需要和模型一致
  3. print(tokenizer)
BertTokenizerFast(name_or_path='bert-base-chinese', vocab_size=21128, model_max_length=512, is_fast=True, padding_side='right', truncation_side='right', special_tokens={'unk_token': '[UNK]', 'sep_token': '[SEP]', 'pad_token': '[PAD]', 'cls_token': '[CLS]', 'mask_token': '[MASK]'}, clean_up_tokenization_spaces=True)
  1. #tokenizer可以使用 __call__,encode,encode_plus,batch_encode_plus等方法编码
  2. #可以使用decode,batch_decode等方法进行解码
  3. text_codes = tokenizer(text = '晚了半小时,七元套餐饮料就给的罐装的可乐,真是可以',
  4.                        text_pair = None,
  5.                        max_length = 100, #为空则默认为模型最大长度,如BERT是512,GPT是1024
  6.                        truncation = True,
  7.                        padding= 'do_not_pad') #可选'longest','max_length','do_not_pad'
  8. #input_ids是编码后的数字,token_type_ids表示来自第1个句子还是第2个句子
  9. #attention_mask在padding的位置是0其它位置是1
  10. print(text_codes)
{'input_ids': [101, 3241, 749, 1288, 2207, 3198, 8024, 673, 1039, 1947, 7623, 7650, 3160, 2218, 5314, 4638, 5380, 6163, 4638, 1377, 727, 8024, 4696, 3221, 1377, 809, 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, 0, 0, 0, 0, 0], '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]}
tokenizer.decode(text_codes["input_ids"][0])
'[CLS]'
tokenizer.batch_decode(text_codes["input_ids"])
  1. ['[CLS]',
  2. '晚',
  3. '了',
  4. '半',
  5. '小',
  6. '时',
  7. ',',
  8. '七',
  9. '元',
  10. '套',
  11. '餐',
  12. '饮',
  13. '料',
  14. '就',
  15. '给',
  16. '的',
  17. '罐',
  18. '装',
  19. '的',
  20. '可',
  21. '乐',
  22. ',',
  23. '真',
  24. '是',
  25. '可',
  26. '以',
  27. '[SEP]']
  1. tokens = tokenizer.tokenize(ds['text'][0])
  2. print("tokens=",tokens)
  3. ids = tokenizer.convert_tokens_to_ids(tokens)
  4. print("ids = ",ids)
  1. tokens= ['晚', '了', '半', '小', '时', ',', '七', '元', '套', '餐', '饮', '料', '就', '给', '的', '罐', '装', '的', '可', '乐', ',', '真', '是', '可', '以']
  2. ids = [3241, 749, 1288, 2207, 3198, 8024, 673, 1039, 1947, 7623, 7650, 3160, 2218, 5314, 4638, 5380, 6163, 4638, 1377, 727, 8024, 4696, 3221, 1377, 809]

3,传入DataLoader

  1. ds_encoded = ds.map(lambda example:tokenizer(example["text"],
  2.                     max_length=50,truncation=True,padding='max_length'),
  3.                     batched=True,
  4.                     batch_size=20,
  5.                     num_proc=2) #支持批处理和多进程map
  1. #转换成pytorch中的tensor 
  2. ds_encoded.set_format(type="torch",columns = ["input_ids",'attention_mask','token_type_ids','labels'])
  3. #ds_encoded.reset_format() 
  4. ds_encoded[0]
  1. #分割成训练集和测试集
  2. ds_train_val,ds_test = ds_encoded.train_test_split(test_size=0.2).values()
  3. ds_train,ds_val = ds_train_val.train_test_split(test_size=0.2).values()
  1. #在collate_fn中可以做动态批处理(dynamic batching)
  2. def collate_fn(examples):
  3.     return tokenizer.pad(examples) #return_tensors='pt'
  4. #以下方式等价
  5. #from transformers import DataCollatorWithPadding
  6. #collate_fn = DataCollatorWithPadding(tokenizer=tokenizer)
  7. dl_train = torch.utils.data.DataLoader(ds_train, batch_size=16, collate_fn = collate_fn)
  8. dl_val = torch.utils.data.DataLoader(ds_val, batch_size=16,  collate_fn = collate_fn)
  9. dl_test = torch.utils.data.DataLoader(ds_test, batch_size=16,  collate_fn = collate_fn)
  1. for batch in dl_train:
  2.     break

二,定义模型

一个完整的模型(Model)包括模型架构(Architecture)和模型权重(Checkpoints/Weights)。

transformers提供了3种指定模型架构的方法。

  • 第1种是指定模型架构(如: from transformers import BertModel)

  • 第2种是自动推断模型架构(如: from transformers import AutoModel)

  • 第3种是自动推断模型架构并自动添加Head (如: from transformers import AutoModelForSequenceClassification )

第1种方案和第2种方案用户可以灵活地根据自己要做的任务设计Head,并且需要对基础模型有一定的了解。

此处我们使用第3种方案。

  1. from transformers import AutoModelForSequenceClassification 
  2. #加载模型 (会添加针对特定任务类型的Head)
  3. model = AutoModelForSequenceClassification.from_pretrained('bert-base-chinese',num_labels=2)
  4. dict(model.named_children()).keys()
dict_keys(['bert', 'dropout', 'classifier'])

我们可以用一个batch的数据去试算一下

output = model(**batch)
output.loss
tensor(0.6762, grad_fn=<NllLossBackward0>)

三,训练模型

下面使用我们的梦中情炉 torchkeras 来实现最优雅的微调训练循环。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/235584
推荐阅读
相关标签