> _先用世界上所有的文本得到共现矩阵,
> 然后确定好参数也就是想做成几维,之后给每个词一个初始 embedding,
> 再通过随机梯度下降移动这些 embedding,直到两个 embedding 的点积等于最初共生矩阵里的数的对数
大体上可以这么理解,**GloVe** 确实是基于全局共现信息来训练词向量的。
1. **GloVe 与传统"共现矩阵 + SVD"思路的关系**
- GloVe 的核心思想是:词和词在全球范围内(整个语料)的共现频次 (co-occurrence frequency),能提供一个比较稳定的全局统计信息。
- 它会构建一个反映词之间"共现关系" (co-occurrence) 的目标函数,然后进行迭代式的优化训练,得到每个词的向量表示。
- 表面上看,GloVe 也和"共现矩阵 + 降维 (SVD)"的思路接近,但是 **GloVe 并不是简单地先显式构造一个完整 `N×N` 的共现矩阵再去做 SVD**,而是利用了一个针对共现频次的损失函数(以及权重函数)来直接训练出词向量。对比简单的 "共现矩阵 + SVD",GloVe 的训练目标会更灵活,也能避免储存超大矩阵的问题。
2. **预训练好的 GloVe 词向量**
- 你在实验中用的 "GloVe 数据库" 或者官方提供的 "GloVe 预训练词向量"(如 `glove.6B`, `glove.42B`, `glove.840B` 等),确实是作者在**大规模语料**(比如维基百科、Common Crawl、Gigaword 等)上,按照 GloVe 的算法训练好后发布的。
- 这就好比他们在非常大的文本上做了全局的"共现统计 + 训练",得到了一套"通用" (general) 的词向量空间。我们可以直接拿过来用,不需要自己在本地再做"从头训练"。
3. **为什么成为"General 的向量空间"**
- 因为他们的语料库覆盖面很广,包含新闻、百科等各种领域,学到的词向量能够在较多一般场景下表现得不错。
- 如果你的任务或领域非常特殊,也可以考虑自己在专业语料上重新训练(或者在通用 GloVe 上做微调),但最常见的方式是直接用这些预训练好的向量做初始化或做特征,帮助下游 NLP 任务。
因此,用你的话来说,**"GloVe数据库"可以理解为:他们(GloVe 的作者 / 维护者)在非常大规模的文本上做了'共现统计'以及对应的目标优化,最终得到一个通用的词向量空间**。我们下载后就可以直接使用它来进行相似度计算、类比、下游模型的 embedding 初始化等。
1. 首先构建共现矩阵X:
```Java
假设窗口大小=2,统计得到的共现次数是:
cat dog pet
cat 2 3 5
dog 3 1 4
pet 5 4 2
```
2. 对共现矩阵取对数log(X):
```Java
cat dog pet
cat 0.69 1.10 1.61
dog 1.10 0 1.39
pet 1.61 1.39 0.69
(注:这里是自然对数ln,保留两位小数)
```
3. 开始训练GloVe模型:
假设我们想要学习2维的词向量(实际应用中通常是50-300维)。
初始随机化词向量和偏置项:
```Java
# 随机初始化的词向量(wi):
cat = [0.2, -0.5]
dog = [0.1, 0.3]
pet = [-0.3, 0.4]
# 随机初始化的偏置项(bi):
cat_bias = 0.1
dog_bias = -0.2
pet_bias = 0.3
```
1. 计算一个具体的预测值:
以cat和dog为例:
```Java
# 计算 cat·dog + b_cat + b_dog:
cat·dog = (0.2 × 0.1) + (-0.5 × 0.3) = -0.13
预测的值 = 词向量相似度(点积) + 第一个词的偏好 + 第二个词的偏好
预测值 = -0.13 + 0.1 + (-0.2) = -0.23
# 与实际的log值比较:
真实值 = 1.10
误差 = -0.23 - 1.10 = -1.33
```
2. 更新向量(使用梯度下降):
```Java
learning_rate = 0.1
# 更新cat的向量:
new_value = old_value - learning_rate × gradient × error
# 原值 = 0.2
# learning_rate = 0.1
# error = -1.33
# gradient = dog[0] = 0.1
cat[0] = 0.2 + 0.1 × (-1.33) × dog[0] = 0.187
cat[1] = -0.5 + 0.1 × (-1.33) × dog[1] = -0.54
# 更新dog的向量:
dog[0] = 0.1 + 0.1 × (-1.33) × cat[0] = 0.075
dog[1] = 0.3 + 0.1 × (-1.33) × cat[1] = 0.37
# 更新偏置项:
cat_bias = 0.1 + 0.1 × (-1.33) = -0.033
dog_bias = -0.2 + 0.1 × (-1.33) = -0.333
```
3. 重复这个过程:
- 对所有词对重复这个计算过程
- 多次迭代整个数据集
- 直到词向量收敛
最终得到的词向量会使得:
```Java
cat·dog + b_cat + b_dog ≈ log(3)
cat·pet + b_cat + b_pet ≈ log(5)
dog·pet + b_dog + b_pet ≈ log(4)
```
这样,通过最小化这些预测值与实际log共现值之间的差异,我们就得到了能够捕捉词语语义关系的词向量。这些词向量的几何关系会反映词语之间的语义关系。
所以GloVe:
- ✓ 确实使用了全局的共现统计
- ✗ 但不是简单地分析共现矩阵
- ✓ 而是训练了一个模型来学习词向量
- ✓ 使词向量能够捕捉词之间的语义关系
这就是为什么它叫"Global Vectors":
- Global:使用全局统计信息
- Vectors:通过模型学习获得的向量表示
这种方法的优势是:
1. 保留了全局统计信息
2. 同时通过模型学习得到更好的语义表示
3. 词向量具有良好的线性代数性质