我为我的天真感到抱歉,但我无法理解为什么通过神经网络训练过程(如word2vec)得到的词嵌入实际上是向量。
嵌入是降维的过程,在训练过程中,神经网络将词的1/0数组减少为更小尺寸的数组,这个过程并没有应用向量运算。
所以结果我们得到的只是数组而不是向量。为什么我应该将这些数组视为向量呢?
即使我们得到了向量,为什么每个人都将它们描绘成从原点(0,0)出发的向量呢?
再次,如果我的问题看起来很愚蠢,我感到抱歉。
回答:
什么是嵌入?
词嵌入是自然语言处理(NLP)中一组语言建模和特征学习技术的统称,其中词汇或短语从词汇表中被映射到实数向量。
概念上,它涉及从每个词一个维度的空间到维度远低的连续向量空间的数学嵌入。
(来源:https://en.wikipedia.org/wiki/Word_embedding)
什么是Word2Vec?
Word2vec是一组相关的模型,用于生成词嵌入。这些模型是浅层、两层的神经网络,训练用于重建词的语言环境。
Word2vec以大量文本语料库作为输入,生成一个通常有数百维的向量空间,语料库中的每个唯一词都被分配到这个空间中的相应向量。
词向量在向量空间中定位,使得在语料库中共享共同语境的词在空间中彼此靠近。
(来源:https://en.wikipedia.org/wiki/Word2vec)
什么是数组?
在计算机科学中,数组数据结构,或简称数组,是由一组元素(值或变量)组成的数据结构,每个元素至少由一个数组索引或键标识。
数组的存储方式使得可以通过数学公式从其索引元组计算出每个元素的位置。
最简单的数据结构类型是线性数组,也称为一维数组。
什么是向量/向量空间?
向量空间(也称为线性空间)是一组称为向量的对象的集合,这些对象可以相加并通过称为标量的数字进行乘法(“缩放”)。
标量通常被认为是实数,但也有标量乘法使用复数、有理数,或一般任何域的向量空间。
向量加法和标量乘法操作必须满足某些要求,称为公理,如下所列。
(来源:https://en.wikipedia.org/wiki/Vector_space)
向量和数组有什么区别?
首先,词嵌入中的向量并不是完全等同于编程语言中的数据结构(所以它不仅仅是数组与向量的初步相似性和差异性)。
从编程的角度来看,词嵌入向量是某种实数(即标量)的数组(数据结构)。
从数学的角度来看,任何一个或多个维度上填充了实数的元素都是张量。而向量是单维标量。
回答原帖问题:
为什么词嵌入实际上是向量?
根据定义,词嵌入就是向量(见上文)。
为什么我们用实数向量来表示词?
为了学习词之间的差异,我们必须以某种方式量化这些差异。
想象一下,如果我们为词分配这些“智能”数字:
>>> semnum = semantic_numbers = {'car': 5, 'vehicle': 2, 'apple': 232, 'orange': 300, 'fruit': 211, 'samsung': 1080, 'iphone': 1200}>>> abs(semnum['fruit'] - semnum['apple'])21>>> abs(semnum['samsung'] - semnum['apple'])848
我们可以看到fruit
和apple
之间的距离很近,但samsung
和apple
之间的距离则不然。在这种情况下,词的单一数值“特征”能够捕捉到一些关于词义的信息,但并不完整。
想象一下,我们为每个词分配两个实数值(即向量):
>>> import numpy as np>>> semnum = semantic_numbers = {'car': [5, -20], 'vehicle': [2, -18], 'apple': [232, 1010], 'orange': [300, 250], 'fruit': [211, 250], 'samsung': [1080, 1002], 'iphone': [1200, 1100]}
为了计算差异,我们可以这样做:
>>> np.array(semnum['apple']) - np.array(semnum['orange'])array([-68, 761])>>> np.array(semnum['apple']) - np.array(semnum['samsung'])array([-848, 8])
这并不太有信息量,它返回一个向量,我们无法得到词之间距离的明确度量,所以我们可以尝试一些向量技巧,计算向量之间的距离,例如欧几里得距离:
>>> import numpy as np>>> orange = np.array(semnum['orange'])>>> apple = np.array(semnum['apple'])>>> samsung = np.array(semnum['samsung'])>>> np.linalg.norm(apple-orange)763.03604108849277>>> np.linalg.norm(apple-samsung)848.03773500947466>>> np.linalg.norm(orange-samsung)1083.4685043876448
现在,我们可以看到更多的“信息”,即apple
可能比orange
更接近samsung
。这可能是因为apple
在语料库中与samsung
的共现频率高于orange
。
大问题来了,“我们如何得到这些实数来表示词的向量?”。这就是Word2Vec/嵌入训练算法(最初由Bengio在2003年提出)发挥作用的地方。
绕道
既然为表示词的向量添加更多实数会更有信息量,那么为什么我们不直接添加更多维度(即每个词向量的列数)呢?
传统上,我们通过计算分布式语义学/分布式词汇语义学领域中的词对词矩阵来计算词之间的差异,但如果词之间没有共现,这些矩阵会变得非常稀疏,包含许多零值。
因此,在计算词共现矩阵后,人们投入了大量精力进行降维。在我看来,这就像是从全局角度查看词之间的关系,然后压缩矩阵以获得一个较小的向量来表示每个词。
所以,“深度学习”词嵌入的创建来自于另一种思想流派,它从为每个词随机(有时不是完全随机)初始化一层向量开始,然后学习这些向量的参数/权重,并通过最小化基于某些定义属性的损失函数来优化这些参数/权重。
这听起来有点模糊,但具体来说,如果我们看一下Word2Vec的学习技术,会更清楚,请看
- https://rare-technologies.com/making-sense-of-word2vec/
- http://colah.github.io/posts/2014-07-NLP-RNNs-Representations/
- https://arxiv.org/pdf/1402.3722.pdf(更数学化)
这里有更多关于词嵌入的资源可供阅读:https://github.com/keon/awesome-nlp#word-vectors