如何理解Transformers中矩阵点积计算词向量的相似度

2023-05-16  本文已影响0人  神奇博士

如何理解Transformers中矩阵点积计算词向量的相似度

** 先声明,下面的过程都是我自己的理解,可能不一定正确,大家参考,有不对的,欢迎评论区指正。**

最近在看Transformer的原理,其中通过点积计算词向量相似度的逻辑优点懵,思考了许久貌似开窍了,先上计算相似度的代码:

import torch
from math import sqrt
query = key = value = inputs_embeds
dim_k = key.size(-1) # 获得最后一个维度的大小(768)
scores = torch.bmm(query, key.transpose(1,2)) / sqrt(dim_k)
scores.size()
torch.Size([1, 5, 5])

inputs_embeds是词向量矩阵

inputs_embeds = token_emb(inputs.input_ids)
inputs_embeds.size()
torch.Size([1, 5, 768])

key.transpose(1,2) 做了矩阵的转置,也就是把最后两个维度互换了一下,相当于列转行

torch.bmm(query, key.transpose(1,2))是对两个矩阵做点积,计算相似度,而最后除以sqrt(dim_k)则是进行归一化处理

最终这个Score实际上就是自注意力计算词向量相似度的分数,最终得到一个5x5的矩阵,前面的1代表批次可以先不考虑。

那么为什么做个点积就可以计算相似度呢?我们先来看下向量点积的含义:

点积(Dot Product)是一种常见的计算两个向量相似度的方法。当两个向量进行点积操作时,结果的大小可以反映两个向量的相似性。这是因为点积操作考虑了向量的方向和大小。

假设我们有两个向量 A 和 B,它们的点积定义为:

cssCopy code
A . B = |A| * |B| * cos(θ)

其中,|A| 和 |B| 分别是 A 和 B 的长度,θ 是 A 和 B 之间的夹角。

可以看到,当 A 和 B 的方向相同时(即它们的夹角接近0),cos(θ) 接近 1,所以 A . B 较大。这表明 A 和 B 很相似。

反之,当 A 和 B 的方向相反时(即它们的夹角接近180度),cos(θ) 接近 -1,所以 A . B 较小,甚至为负。这表明 A 和 B 不相似。

当 A 和 B 互相垂直时(即它们的夹角为90度),cos(θ) 为 0,所以 A . B 为 0。这表明 A 和 B 没有相似性。

因此,通过计算向量的点积,我们可以得到一个衡量两个向量相似性的标量值。

在深度学习中,尤其是在自然语言处理和推荐系统中,我们经常需要衡量和比较向量(例如,单词嵌入或用户和物品的嵌入)的相似性。在这些情况下,点积是一种简单且有效的方法。

因为词向量表示了一个词的多个方面的属性,比如上面例子中可以理解为每个词定义了768个属性,那么我们用一个例子来类比:

假设有三个人分别是小张、小明和小红,他们有4个属性,分别是:爱好、性别、年龄、籍贯;那么三个人的属性如下

姓名 性别 年龄 籍贯 爱好
小张 青年 浙江 音乐
小明 中年 湖北 绘画
小红 青年 江苏 音乐

那么,我们可以把上面的表格转换为一个矩阵:

[
[男, 青年, 浙江, 音乐],
[男, 中年, 湖北, 绘画],
[女, 青年, 江苏, 音乐],
]

然后我们把这个矩阵转置:

[

[男, 男, 女]

[青年, 中年, 青年]

[浙江, 湖北, 江苏]

[音乐, 绘画, 音乐]

]

当然,我们来看一个简单的例子,以更好地理解矩阵点积(矩阵乘法)的过程。

假设我们有以下两个矩阵 A 和 B:

矩阵A:

Copy code1 2 3
4 5 6

矩阵B:

Copy code7 8
9 10
11 12

这里,矩阵A的形状是(2,3),矩阵B的形状是(3,2)。我们可以进行矩阵乘法,因为A的列数等于B的行数。结果矩阵C的形状将会是(2,2)。

我们如何计算结果矩阵C的每个元素呢?我们来看一个具体的例子,计算结果矩阵C的第一个元素:

C[0,0] = A[0,0]B[0,0] + A[0,1]*B[1,0] + A[0,2]*B[2,0] = 1*7 + 2*9 + 311 = 58

同理,我们可以计算结果矩阵C的其他元素。最终,矩阵C将是:

58 64
139 154

这就是矩阵乘法(或者说矩阵点积)的过程。希望这个例子能帮助你理解矩阵乘法。

所以上面的矩阵点乘后,结果矩阵就变成:

[

[男 * 男 + 青年 * 青年 + 浙江 * 浙江 + 音乐 * 音乐,男 * 男 + 青年 * 中年 + 浙江 * 湖北 + 音乐 * 绘画,男 * 女 + 青年 * 青年 + 浙江 * 江苏 + 音乐 * 音乐],

[男 * 男 + 中年 * 青年 + 湖北 * 浙江 + 绘画 * 音乐,男 * 男 + 中年 * 中年 + 湖北 * 湖北 + 绘画 * 绘画,男 * 女 + 中年 * 青年 + 湖北 * 江苏 + 绘画 * 音乐],

[女 * 男 + 青年 * 青年 + 江苏 * 浙江 + 音乐 * 音乐,女 * 男 + 青年 * 中年 + 江苏 * 湖北 + 音乐 * 绘画,女 * 女 + 青年 * 青年 + 江苏 * 江苏 + 音乐 * 音乐]

]

为了便于计算,我们将值相等的点积值设为1,不相等设为0,于是,整个矩阵就变成了:

[

[4, 1, 2]

[1, 4, 0]

[2, 0, 4]

]

显然这就变成了3 x 3的了,我们可以认为这个矩阵代表了,三个人之间两两的关联度:

小张 小明 小红
小张 4 1 2
小明 1 4 0
小红 2 0 4

于是,当你遇到任何一个人,你都可以说出来他和其他人的相似性。

词向量和这个过程应该是类似的,只不过,它的属性有768个之多。因此在后续的匹配当中,每个词都可以找到与之相似度分数最高的一个关联词。但是,目前还有一个问题,就是这个相似度评分无法解决同意词的问题,同样是“绘画”动词和名词的相似度是一样的。要解决这个问题,就得要通过多层编码器的神经网络来解决了,这也是编码过程要解决的主要问题。
代码的最后把相似度除以了sqrt(dim_k),这一步是为了进行归一化,进行的缩放处理:

/ sqrt(dim_k)
:这是一个缩放操作,将上述计算得到的张量除以 dim_k 的平方根。这是一种常见的归一> 化手段,dim_k 通常是 key 的维度。在 "Scaled Dot-Product Attention" 中,这样的缩放操> 作可以防止点积在维度很高时变得过大。
最后,对相似度进行softmax处理,就转换为了概率:

import torch.nn.functional as F
weights = F.softmax(scores, dim=-1)
weights.sum(dim=-1)

这样就变成了A词和B词的相似度概率,找到和A词最匹配的词就是找概率对打的。

上一篇 下一篇

猜你喜欢

热点阅读