使用BERT模型生成token级向量

本文默认读者有一定的Transformer基础,如果没有,请先稍作学习Transormer以及BERT。

相信网上有很多方法可以生成BERT向量,最有代表性的一个就是bert as service,用几行代码就可以生成向量,但是这样生成的是句向量,也就是说,正确的做法是输入一句句子:

我是一个中国人,我热爱着中国的每一个城市。

输出的是这句句子的向量,一个768维的向量(google预训练是这么做的),这个向量是具有上下文信息的,详细参考Transformer结构。但是网上有一些做法是用bert as service来生成词级向量,例如输入[‘我’,‘是’,‘一个’, ‘中国’, ‘人’],得到5个768维的向量,用来作为词向量,但这样做是错误的!具体原因参照我前面的描述,既然思想是错误的,也就不奇怪效果不好了,所以在这种情况下,请先别着急说BERT预训练模型不work。

BERT生成token级别的向量,这两篇文章理解的比较准确(我的代码有一部分参考第二篇博客):

https://blog.csdn.net/u012526436/article/details/87697242

https://blog.csdn.net/shine19930820/article/details/85730536

为什么说是token级别的向量呢?因为Transformer结构所决定其输入和输出的长度相等的,而且对于中文预训练模型,做法是将中文拆成一个个的字来做学习的,因此每一个token就是一个字。对于一句话,我们会在其头上加[cls]在尾部加[SEP],并且BERT是一个多任务的预训练过程,现在假设text_a是我们需要获取向量的句子,text_b为空,那么,输入:

我是一个中国人,我热爱着中国的每一个城市。

处理后:

[CLS]我是一个中国人,我热爱着中国的每一个城市。[SEP]

通常我们会用第一个字符[CLS]的输出向量(768维)作为整个句子的向量表示,用来接全连接、softmax层做分类,现在我打算获取这样一个句子中每一个字符的向量表示,并存储下来,以备下游任务,如果我只用[CLS]的向量来做分类,那么就只取第一个向量,如果用所有token的向量来做卷积,那么就舍弃一头一尾的向量,取中间的向量来做卷积,这样下游任务不用改太多代码,把这样的信息存储在文件里,下游任务用起来比较灵活。

存储ndarray

要能够把词向量存储下来供下次使用,就肯定要知道怎么存储ndarray,因为拿到的词向量是shape为(N, seq_len, 768)的ndarray,N代表有多少个句子,seq_len代表句子的长度(加上头尾),768即向量的维度。这里我使用h5py存储ndarray,当然也有一些别的方法。

import h5py
# shape a: (3, 4, 5)
a = np.array([[[1,0.5,1,0.3,-1],[1,0.5,1,0.3,-1],[1,0.5,1,0.3,-1],[1,0.5,1,0.3,-1]],
              [[1,0.

你可能感兴趣的:(NLP&图像,深度学习&神经网络,python,tensorflow,深度学习,机器学习,java)