我们已经了解了 PyTorch 的基本操作和功能,现在让我们实践一下。自从 transformer 横空出世以后,在 NLP 领域有”大一统“ 的趋势。但 transformer 的本质是什么?transformer 的本质是一个能够有效提取语义信息的词嵌入生成器,它比前辈 word2vec、GloVe 等等能够更有效地提取词语的语义信息,所以以 transformer 生成的词嵌入可以有 SOTA(state-of-the-art,最高水平)的性能。这等于电脑可以更好地理解文本中每个词语的意思,理解了每个词语的意思自然就可以更好地理解文本的整体意思。所以 transformer 只是取代了以前用的 Embedding 层,根据具体的任务的不同还可以接上 CNN、RNN 等层。
本文及下一篇文章中,我们将使用 PyTorch,TorchText 和 transformers 库里的 Bert 预训练模型来进行一个基本的情感分类任务:IMDB 影片评论的情感分类。
Bert 之类的 transformer 预训练模型虽然性能强大,它也有一个致命的缺点,即资源的消耗非常巨大。简单的模型跑小数据库还可以在个人 PC 上运行,Bert 之类的模型必须用到 GPU。写这篇文章的时候,我是在 Google Colab 上完成模型的训练的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 !nvidia-smi
Wed Jun 10 18:00:42 2020
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 440.82 Driver Version: 418.67 CUDA Version: 10.1 |
|-------------------------------+----------------------+----------------------+
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
|===============================+======================+======================|
| 0 Tesla P100-PCIE... Off | 00000000:00:04.0 Off | 0 |
| N/A 69C P0 48W / 250W | 9149MiB / 16280MiB | 0% Default |
+-------------------------------+----------------------+----------------------+
+-----------------------------------------------------------------------------+
| Processes: GPU Memory |
| GPU PID Type Process name Usage |
|=============================================================================|
+-----------------------------------------------------------------------------+
本文的代码来自 Transformers for Sentiment Analysis。
*注:本文的很多资源可能需要科学上网,不能科学上网的话我也没办法哈。
1. 必要库的加载
首先安装最新版 PyTorch,TorchText 和 transformers。
1
2
3
4
5
6
7
8
9
10
11
12
13
14!pip install -U torchtext
!pip install -U torch
!pip install -U transformers
import torch
import random
SEED = 1234
# 初始化随机种子
random.seed(SEED)
np.random.seed(SEED)
torch.manual_seed(SEED)
torch.backends.cudnn.deterministic = True # 可以加快训练速度一点点
虽然每一步都会加载必需的库,我还是会把完整路径写出来,方便确认从属。
2. 获取数据:
在 Kaggle 上下载数据。
3. 分词器的准备
我们将使用 Bert 预训练模型的分词器。
1 | from transformers import BertTokenizer |
‘uncased’ 意味着这个分词器是不区分大小写的,意味着仅仅处理小写字母。不用担心,分词器会自动把文本转换成小写形式再处理。
1 | 'Hello WORLD how ARE yoU?') # 大小写不敏感的预训练模型会自动转换大小写 tokens = tokenizer.tokenize( |
接下来我们需要指定 4 个特殊的 token:句起始 token,句结束 token,填充 token 和未知词语 token 备用。
1 | # 起始 init_token_idx = tokenizer.cls_token_id |
然后我们还需要获得预训练 Bert 模型的序列长度。
1 | 'bert-base-uncased'] max_input_length = tokenizer.max_model_input_sizes[ |
4. 构建分词器
上一篇文章里说我们可以使用 spacy 作为分词器,这里我们使用 BertTokenizer
。
1 | def tokenize_and_cut(sentence): |
因为预训练 Bert 模型的最长序列为 512,为给数据点加上 [CLS]
和 [EOS]
,我们需要把分词后的序列长度减 2.
5. 定义 field
1 | from torchtext import data |
因为 batch 在第一维,所以我们设定 batch_first = True
。由于我们已经有了单词表(bert 的 embedding),所以需要设置 use_vocab = False
。然后我们在 preprocessing
这里将 token 转换成对应的 id。最后,我需要定义特殊的 token id。
6. 加载数据
1 | from torchtext import datasets |
IMDB
数据库使用 splts
方法创建训练集和测试集,具体参数如下:
1 | splits(text_field, label_field, root='.data', train='train', test='test', **kwargs) |
两个必需参数 text_field
和 label_field
分别对应了文本与标签的 field。
7. 建立标签的词汇表
虽然我们已经在定义 field 的时候定义了 TEXT 的词汇表,我们还需要将 LABEL 转换为数字。
1 | LABEL.build_vocab(train_data) |
8. 创建训练集、验证集和测试集
最后我们使用 BucketIterator
创建训练集、验证集和测试集的迭代器。这里我们使用 128 作为 batch size。
1 | BATCH_SIZE = 128 |
欢迎关注我的微信公众号“花解语 NLP”: