word embedding是稠密的实数向量。Word embedding是一个词的语义表示,有效地编码了词的语义信息。
one-hot编码
在自然语言处理任务中,我们常常要与词打交道。那么在计算机上,我们怎么表示一个单词呢?一种思路是one-hot编码。假设词汇表为$V$,词汇表大小(vocab_size)为$N_V$。我们可以用向量$N_V$维向量$[1,0,0…,0,0]$来表示第一个词。以此类推,来表示所有的词。
这种方法有致命的弱点。首先是向量维度太大,太稀疏,效率太低。更要命的是,one-hot编码把词与词间看做完全独立的,没有表达出词与词之间的联系和相似性。而这正是我们想要的。
举个例子,我们想要构建一个语言模型。有以下三个句子
- 数学家待在实验室里。
- 物理学家待在实验室里。
- 数学家解决了一个难题。
我们又看到一个新的句子:
- 物理学家解决了一个难题。
我们希望语言模型可以学习到以下特点:
数学家
和物理学家
在一个句子中同样的位置出现。这两个词之间有某种语义上的联系数学家
曾经出现在我们看到的这个新句子中物理学家
出现的位置。
这就是语义相似性想表达的。语义相似性可以将没见过的数据与已经见过的数据联系起来,来解决语言数据的稀疏性问题。这个例子基于一个基本的语义学假设:出现在相似文本中的词汇在语义上是相互联系的。这称为distributional hypothesis
值得一提的是,在分类问题中,one-hot编码很适合用在类别的编码上。
word embedding
我们怎样编码来表达词汇的语义相似性呢?我们考虑词汇的semantic attributes。例如,物理学家和数学家学可能[头发不多,爱喝咖啡,会看论文,会说英语]。我们可以用这四个属性来编码物理学家
和数学家
。$$q_物 = [0.9,0.8,0.98,0.8]$$$$q_数 = [0.91,0.89,0.9,0.85]$$
我们可以衡量这两个词之间的语义相似度:$$similarity(q_物,q_数) = \frac{q_物\cdot q_数}{|q_物| \cdot |q_数|}=cos(\phi) 其中\phi是两个向量之间的夹角。$$
但我们如何选择属性特征,并决定每个属性的值呢?深度学习的核心思想是神经网络学习特征表示,而不用人为指定特征。我们干脆将Word embedding作为神经网络的参数,让神经网络在训练的过程中学习Word embedding。
神经网络学到的Word embedding是潜在语义属性。也就是说,如果两个词在某个维度上都有大的值,我们并不知道这个维度代表了什么属性,这不能人为解释。这就是潜在语义属性的含义。
总的来说,Word embedding是一个词的语义表示,有效地编码了词的语义信息。
PyTorch实现word embedding
代码如下:
1 | import torch |
nn.Embedding()
随机初始化了一个形状为[vocab_size,embedding_dim]的词向量矩阵,是神经网络的参数。
接下来我们查询”dog”这个词的向量表示。
1 | dog_idx = torch.LongTensor([word_to_ix['dog']]) #注意输入应该是一维数组。 |
上述代码中,要访问dog
的词向量,要得到一个Variable。word_embeddings的输入应该是一个一维tensor。
接下来,我们查询一句话的向量表示。
1 | sent = 'The dog ate the apple'.split() |
pytorch加载预训练词向量
之前的方法中,词向量是随机初始化的,作为模型参数在训练过程中不断优化。通常我们要用到预训练的词向量,这样可以节省训练时间,并可能取得更好的训练结果。下面介绍两种加载预训练词向量的方式。
方式一:
1 | import torch |
方式二:
1 | word_embeddings = torch.nn.Embedding(vocab_size,embedding_dim) #创建一个词向量矩阵 |
涉及函数详解
numpy()与from_numpy()
1 | torch.from_numpy(ndarray) $\to$ tensor |
- 作用:numpy桥,将
numpy.ndarray
转换为pytorch的tensor
.返回的张量与numpy.ndarray共享同一内存空间,修改一个另一个也会被修改。
1 | tensor.numpy() |
- 作用:numpy桥,将pytorch的
tensor
转换为numpy.ndarray
.二者共享同一内存空间,修改一个另一个也会被修改。
举个例子:
1 | a = np.arange(5) |
tensor.copy_(src)
- 作用:将
src
中的元素复制到tensor并返回。两个tensor应该有相同数目的元素和形状,可以是不同数据类型或存储在不同设备上。
举个例子:
1 | a = torch.randn(1,5) |