今天要更新的是Embedding Similarity,这个评价指标呢,是通过嵌入向量来计算相似度的一种方式,我们一起来学习下。
欢迎关注知乎: 世界是我改变的
一. Embedding Similarity介绍
1. 原理介绍及公式
Embedding Similarity,顾名思义就是通过嵌入向量来计算相似度,这个评价指标在网上的资料比较少,我今天来总结一哈。
相似度度量(Similarity),即计算个体间的相似程度,相似度度量的值越小,说明个体间相似度越小,相似度的值越大说明个体差异越大。
对于多个不同的文本或者短文本对话消息要来计算他们之间的相似度如何,一个好的做法就是将这些文本中词语,映射到向量空间,形成文本中文字和向量数据的映射关系,通过计算几个或者多个不同的向量的差异的大小,来计算文本的相似度。
采用Embedding的方式来进行相似性度量,并返回一个度量相似性的数字。请记住,Embedding只是数字的向量,查找两个向量之间的相似性 和
,它主要分为三种相似性指标方式:
- 欧式距离(Euclidean distance):意义是向量两端之间的距离,公式为 :
- 余弦(Cosine):角度余弦
向量之间,公式为:
- 点积(dot):余弦乘以两个向量的长度,公式为:
2. 度量方式的选择
与余弦相反,点积与向量长度成正比。这很重要,因为在训练集中经常出现的示例往往具有较大的嵌入向量。示例可能会使相似性指标产生偏差。为了平衡这种偏斜,可以将长度增加到指数 计算点积为
。
为了更好地了解向量长度如何改变相似性度量,请将向量长度归一化为1并注意这三个度量变得彼此成比例。
-
证明:相似度量的比例性
在规范化a和b后, 和
,这三项措施的相关性如下:
- 欧式距离 =
- 点积 =
- 余弦 =
由此得出:三个相似性度量都是等效的。所以我们用余弦相似度来计算,后面代码也是CosineSimilarity。
二. CosineSimilarity的MindSpore代码实现
好了,原理已经讲完,话不多说,我们开始上代码。使用的是MindSpore框架实现的代码。
-
MindSpore代码实现
"""CosineSimilarity."""
import numpy as np
from mindspore._checkparam import Validator as validator
from .metric import Metric
class CosineSimilarity(Metric):
def __init__(self, similarity='cosine', reduction='none', zero_diagonal=True):
super().__init__()
similarity_list = ['dot', 'cosine']
reduction_list = ['none', 'sum', 'mean']
similarity = validator.check_value_type("similarity", similarity, [str])
# 度量方式有两种,dot和cosine
self.similarity = validator.check_string(similarity, similarity_list, "similarity")
# reduction有三种,none', 'sum', 'mean'
reduction = validator.check_value_type("reduction", reduction, [str])
self.reduction = validator.check_string(reduction, reduction_list, "reduction")
self.zero_diagonal = validator.check_value_type("zero_diagonal", zero_diagonal, [bool])
self.clear()
def clear(self):
"""清除历史数据"""
self.sqr_mtx_res = 0
self._is_update = False
def update(self, *inputs):
"""
更新输入数据,输入为1个
"""
# 输入必须是一个tensor,numpy或者list
input_data = self._convert_data(inputs[0])
# 选择使用的度量方式
if self.similarity == 'cosine':
data = np.linalg.norm(input_data, ord=2, axis=1)
input_data = input_data / np.expand_dims(data, 1)
self.sqr_mtx_res = np.dot(input_data, input_data.transpose(1, 0))
self._is_update = True
def eval(self):
"""
计算cosine similarity,返回的是一个矩阵
"""
if not self._is_update:
raise RuntimeError('Call the update method before calling eval.')
if self.zero_diagonal:
np.fill_diagonal(self.sqr_mtx_res, 0)
if self.reduction == 'mean':
self.sqr_mtx_res = np.mean(self.sqr_mtx_res, axis=-1)
if self.reduction == 'sum':
self.sqr_mtx_res = np.sum(self.sqr_mtx_res, axis=-1)
return self.sqr_mtx_res
使用方法如下:
import numpy as np
from mindspore.nn.metrics import CosineSimilarity
test_data = np.array([[5, 8, 3, 2], [5, 8, 3, 2], [4, 2, 3, 4]])
metric = CosineSimilarity()
metric.clear()
metric.update(test_data)
square_matrix = metric.eval()
print(square_matrix)
np.array([[0, 1, 0.78229315], [1, 0, 0.78229315], [0.78229315, 0.78229315, 0]])
-
补充说明
这里说明一下,通常计算相似度都是有两个输入,比如A和B,通过Embedding similarity来计算两个输入的相似度,结果是一个数值。我们这里使用的是将A、B、C放到了一个矩阵里,比如 np.array([[5,8,3,2],[5,8,3,2],[4,2,3,4]]),
A为embedding之后的[5,8,3,2],
B为embedding之后的[5,8,3,2],
C为embedding之后的[4,2,3,4]。
得到的结果是np.array([[0, 1, 0.78229315], [1, 0, 0.78229315], [0.78229315, 0.78229315, 0]]),结果可表示为如下表格:
表格说明(上面每一个格对应着下面对应位置的格):
这样看结果就很清晰明了了吧,也是解释为什么输入数量为1了。不同于网上其他资料的直接两个输入x和y,拿x和y直接比的出来一个结果。这样写的原因是对于大量数据来说,更加方便。
哦,对了,一般结果的取值范围是 [-1, 1] 。