Metric评价指标-Embedding Similarity

今天要更新的是Embedding Similarity,这个评价指标呢,是通过嵌入向量来计算相似度的一种方式,我们一起来学习下。

欢迎关注知乎: 世界是我改变的

知乎上的原文链接

一. Embedding Similarity介绍

1. 原理介绍及公式


Embedding Similarity,顾名思义就是通过嵌入向量来计算相似度,这个评价指标在网上的资料比较少,我今天来总结一哈。

相似度度量(Similarity),即计算个体间的相似程度,相似度度量的值越小,说明个体间相似度越小,相似度的值越大说明个体差异越大。

对于多个不同的文本或者短文本对话消息要来计算他们之间的相似度如何,一个好的做法就是将这些文本中词语,映射到向量空间,形成文本中文字和向量数据的映射关系,通过计算几个或者多个不同的向量的差异的大小,来计算文本的相似度。

采用Embedding的方式来进行相似性度量,并返回一个度量相似性的数字。请记住,Embedding只是数字的向量,查找两个向量之间的相似性 A = [a_1,a_2,a_3,...,a_n] 和 B = [b_1,b_2,b_3,...,b_n] ,它主要分为三种相似性指标方式:

  • 欧式距离(Euclidean distance):意义是向量两端之间的距离,公式为 :

                                                                                                                  \,\,\,\,\,\,\,\,\,\,\,\, \sqrt{(a_1 - b_1)^2 + (a_2 - b_2)^2 + ...+(a_N - b_N)^2 } \quad

  • 余弦(Cosine):角度余弦\theta向量之间,公式为:

                                                                                                                                                    \frac {a^Tb}{|a|*|b|} \quad

  • 点积(dot):余弦乘以两个向量的长度,公式为:

                                                                                                                         a_1b_1+a_2b_2+...+a_nb_n = |a||b|cos(\theta)

 

2. 度量方式的选择

与余弦相反,点积与向量长度成正比。这很重要,因为在训练集中经常出现的示例往往具有较大的嵌入向量。示例可能会使相似性指标产生偏差。为了平衡这种偏斜,可以将长度增加到指数 \alpha < 1 计算点积为 |a|^\alpha|b|^\alpha cos(\theta) 。

为了更好地了解向量长度如何改变相似性度量,请将向量长度归一化为1并注意这三个度量变得彼此成比例。

  • 证明:相似度量的比例性

在规范化a和b后,||a|| = 1  和||b|| = 1  ,这三项措施的相关性如下:

  • 欧式距离 = ||a - b || = \sqrt{||a||^2 + ||b||^2 -2a^Tb } \ = \sqrt{2-2cos(\theta_\text{ab})}
  • 点积 = |a||b| cos(\theta_\text{ab}) = 1 * 1 * cos(\theta_\text{ab})= cos(\theta_\text{ab})|a||b| cos(\theta_\text{ab}) = 1 * 1 * cos(\theta_\text{ab})= cos(\theta_\text{ab})
  • 余弦 = cos(\theta_\text{ab})

由此得出:三个相似性度量都是等效的。所以我们用余弦相似度来计算,后面代码也是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] 。

  • 6
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值