BERT-多标签文本分类实战之五——BERT模型库的挑选与Transformers

Posted 征途黯然.

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BERT-多标签文本分类实战之五——BERT模型库的挑选与Transformers相关的知识,希望对你有一定的参考价值。

·请参考本系列目录:【BERT-多标签文本分类实战】之一——实战项目总览
·下载本实战项目资源:>=点击此处=<

[1] BERT模型库

  从BERT模型一经Google出世,到tensorflowpytorch版本的BERT相继发布,再到不同下游任务的BERT模型被整合到transformers库,到底pip哪个库才能用BERT对于刚入门的同学来说是非常的不友好。

  其实大部分的人的需求都非常地简单:只想用BERT模型替代原始的嵌入层来得到文本表示。大部分的人更在乎的是如何把bert当作和embedding层一样的黑箱,输入文本,得到文本表征向量。

  这里,本项目使用的是Hugging Facetransformers库,因为它整合的太棒啦!transformers库里面有NLP里面很火的大模型,比如BERTALBERTGPTGPT2XLNET等等。本项目只用到了transformers.BERT,其文档地址为:https://huggingface.co/docs/transformers/model_doc/bert

  本篇文章主要还是以实战为导向,简单说一下transformers.BERT要怎么用。想要深入使用,大家仔细看看上面贴的文档,写得非常好。

[2] transformers.BERT的下载

  其实在自己的模型里使用BERT非常简单,并不会像其他教程一样与transformers库耦合的很深,本次在数据集Reuters-21578上进行多标签文本分类的实战项目,就是在之前单标签文本分类任务上改动的。

单标签文本分类实战项目,请参考:【BERT-多标签文本分类实战】之一——实战项目总览


[2.1] 使用BERT前的准备

  使用BERT需要2个前置条件

  1、安装transformers库;
  2、下载预训练参数文件。

  第一点不必赘述。第二点可说的比较多。首先,为什么要下载预训练参数文件?BERT它是预训练模型,有自己的网络结构,而且里面的参数达到上亿级别,BERT在大规模无监督语料上训练得到最终参数之后,是要把参数保存下来,之后有新的数据集要跑的时候,我们需要把这些参数数据载入到模型。除此之外,光有预训练参数文件不够,还需要一个配置文件,来告诉它模型的很多配置是多少(例如词典有多大、隐藏层维度是几等等)。最后还需要一个txt文件来存放词典。

  总结一下,BERT的预训练参数文件里有3个文件:1)参数数据;2)模型配置信息;3)txt词典。


[2.2] 预训练参数文件的挑选与下载

  BERT的参数文件有很多个版本:

  上面框出来的是我比较常用的两个。bert-base-uncased表示不区分大小写的英文模型,bert-base-chinese表示中文模型。

  假设我们要下载bert-base-uncased,我们到页面:https://huggingface.co/bert-base-uncased/tree/main,下载的文件已经在图中框出:

  由于本次实战使用的是pytorch框架,所以最终我们下载下来的文件是:

【注】只下载这三个就够了,其他都可以不下载。


[3] transformers.BERT的测试示例

  我们对BERT模型的需求是,利用它来编码句子。在我们的实战项目中,有一个测试.py文件,里面展示了BERT的基本用法。

  把下载下来的参数文件放在项目下,然后写代码开始测试:

import torch
from transformers import BertModel, BertTokenizer

pretrained_path = 'bert-base-uncased'
# 从文件夹中加载bert模型
model = BertModel.from_pretrained(pretrained_path)
# 从bert目录中加载词典
tokenizer = BertTokenizer.from_pretrained(pretrained_path)

# 输出字典的大小
print(f'vocab size :tokenizer.vocab_size')
# 把'[PAD]'编码
print(tokenizer.encode('[PAD]'))
# 把'[SEP]'编码
print(tokenizer.encode('[SEP]'))

输出:
vocab size :30522
[101, 0, 102]
[101, 102, 102]

  接下来对英文句子进行词典编码,这里主要是把英文句子,按照词典里面的词序进行转化:

# 把句子编码,默认加入了special tokens了,也就是句子开头加入了[CLS] 句子结尾加入了[SEP]
ids = tokenizer.encode("I love you transport", add_special_tokens=True, padding='max_length', truncation='only_first', max_length=6)
print(ids)

输出:
[101, 1045, 2293, 2017, 3665, 102]

【注】不要凌乱! 来总结一下到目前为止说了什么:
第一小节介绍了采用transformers库来使用BERT;
第二小节介绍了使用BERT要下载哪些东西;
第三小节给了一段测试代码,其实是让大家自己试试有没有下载成功,能不能把demo运行起来。


[4] transformers.BERT的实际使用

  第三小节给的代码只是demo。本节将介绍BERT的实际使用,很简单,只需要一个函数tokenizer.encode_plus,但是在写代码前,大家需要了解为什么要这样做。


[4.1] BERT模型的输入格式

  BERT要求我们:

  1、在句子的句首和句尾添加特殊的符号[CLS][SEP]
  2、给句子填充 or 截断,使每个句子保持固定的长度
  3、用 attention mask 来显示的区分填充的tokens和非填充的tokens

  特殊符号:
  [SEP]

  在每个句子的结尾,需要添加特殊的[SEP]符号。

  在以输入为两个句子的任务中(例如:句子 A 中的问题的答案是否可以在句子 B 中找到),该符号为这两个句子的分隔符。

  目前为止还不清楚为什么要在单句中加入该符号,但既然这样要求我们就这么做吧。

  [CLS]

  在分类任务中,我们需要将[CLS]符号插入到每个句子的开头。

  这个符号有特殊的意义,BERT 包含 12 个 Transformer 层,每层接受一组 token 的 embeddings 列表作为输入,并产生相同数目的 embeddings 作为输出(当然,它们的值是不同的)。

  句长 & 注意力掩码(Attention Mask)

  很明显,数据集中句子长度的取值范围很大,BERT该如何处理这个问题呢?

  BERT有两个限制条件:

  1、所有句子必须被填充或截断到固定的长度,句子最大的长度为512个tokens
  2、填充句子要使用[PAD]符号,它在BERT词典中的下标为0。

  下图是最大长度为8个tokens的填充说明:

  Attention Mask是一个只有 0 和 1 组成的数组,标记哪些tokens是填充的,哪些不是的。掩码会告诉 BERT 中的Self-Attention机制不去处理这些填充的符号。


[4.2] BERT模型的最终使用方法

  首先使用tokenizer.encode_plus对文本编码:

from transformers import BertModel, BertTokenizer

# 参数文件地址
pretrained_path = 'bert-base-uncased'
# 加载bert模型
bert = BertModel.from_pretrained(pretrained_path)
# 加载分词器
tokenizer = BertTokenizer.from_pretrained(pretrained_path)

# 对英文文本content进行分词
encoded_dict = config.tokenizer.encode_plus(
                content,  # 输入文本
                add_special_tokens=True,  # 添加 '[CLS]' 和 '[SEP]'
                max_length=pad_size,  # 填充 & 截断长度
                pad_to_max_length=True,
                padding='max_length',
                truncation='only_first',
                return_attention_mask=True,  # 返回 attn. masks.
                return_tensors='pt'  # 返回 pytorch tensors 格式的数据
            )

# 编码后的文本
IDs = torch.squeeze(encoded_dict['input_ids'],0)
# 文本的 attention mask
MASKs = torch.squeeze(encoded_dict['attention_mask'],0)

  函数tokenizer.encode_plus包含以下步骤:

  · 将句子分词为 tokens。
  · 在两端添加特殊符号 [CLS] 和[SEP]。
  · 将 tokens 映射为下标 IDs。
  · 将列表填充或截断为固定的长度。
  · 创建 attention masks,将填充的和非填充 tokens 区分开来。

  更多参数请参考官方文档:https://huggingface.co/docs/transformers/model_doc/bert

  拿到了编码后的文本、文本的attention mask之后,作为输入放入bert模型里面跑:

out = bert(IDs, attention_mask=MASKs)

【注】这里演示的是基本使用方法,比较独立。真正应用在实战项目里,还是配着整体代码食用更佳。

[5] 进行下一篇实战

  【BERT-多标签文本分类实战】之六——数据加载与模型代码

以上是关于BERT-多标签文本分类实战之五——BERT模型库的挑选与Transformers的主要内容,如果未能解决你的问题,请参考以下文章

BERT-多标签文本分类实战之五——BERT模型库的挑选与Transformers

BERT-多标签文本分类实战之一——实战项目总览

BERT-多标签文本分类实战之一——实战项目总览

BERT-多标签文本分类实战之一——实战项目总览

BERT-多标签文本分类实战之二——BERT的地位与名词术语解释

BERT-多标签文本分类实战之二——BERT的地位与名词术语解释