pytorch中六种常用的向量相似度评估方法

2021 年 12 月 9 日 极市平台
↑ 点击 蓝字  关注极市平台

作者丨我爱学习@知乎(已授权)
来源丨https://zhuanlan.zhihu.com/p/442092801
编辑丨极市平台

极市导读

 

本文提供几个pytorch中常用的向量相似度评估方法,并给出其源码实现,供大家参考。 >>加入极市CV技术交流群,走在计算机视觉的最前沿

1. CosineSimilarity

2. DotProductSimilarity

3. ProjectedDotProductSimilarity

4. BiLinearSimilarity

5. TriLinearSimilarity

6. MultiHeadedSimilarity

1、余弦相似度

余弦相似度用向量空间中两个向量夹角的余弦值作为衡量两个个体间差异的大小。余弦值越接近1,就表明夹角越接近0度,也就是两个向量越相似,称为"余弦相似性"

import torch
import torch.nn as nn
import math
class CosineSimilarity(nn.Module):
 
    def forward(self, tensor_1, tensor_2):
        normalized_tensor_1 = tensor_1 / tensor_1.norm(dim=-1, keepdim=True)
        normalized_tensor_2 = tensor_2 / tensor_2.norm(dim=-1, keepdim=True)
        return (normalized_tensor_1 * normalized_tensor_2).sum(dim=-1)

2、DotProductSimilarity

这个相似度函数简单地计算每对向量之间的点积,并使用可选的缩放来减少输出的方差。

class DotProductSimilarity(nn.Module):
 
    def __init__(self, scale_output=False):
        super(DotProductSimilarity, self).__init__()
        self.scale_output = scale_output
 
    def forward(self, tensor_1, tensor_2):
        result = (tensor_1 * tensor_2).sum(dim=-1)
        if self.scale_output:
            # TODO why allennlp do multiplication at here ?
            result /= math.sqrt(tensor_1.size(-1))
        return result

3、ProjectedDotProductSimilarity

这个相似度函数做一个投影,然后计算点积,计算公式为:

计算后的激活函数。默认为不激活。

class ProjectedDotProductSimilarity(nn.Module):
   
    def __init__(self, tensor_1_dim, tensor_2_dim, projected_dim,
                 reuse_weight=False, bias=False, activation=None):
        super(ProjectedDotProductSimilarity, self).__init__()
        self.reuse_weight = reuse_weight
        self.projecting_weight_1 = nn.Parameter(torch.Tensor(tensor_1_dim, projected_dim))
        if self.reuse_weight:
            if tensor_1_dim != tensor_2_dim:
                raise ValueError('if reuse_weight=True, tensor_1_dim must equal tensor_2_dim')
        else:
            self.projecting_weight_2 = nn.Parameter(torch.Tensor(tensor_2_dim, projected_dim))
        self.bias = nn.Parameter(torch.Tensor(1)) if bias else None
        self.activation = activation
 
    def reset_parameters(self):
        nn.init.xavier_uniform_(self.projecting_weight_1)
        if not self.reuse_weight:
            nn.init.xavier_uniform_(self.projecting_weight_2)
        if self.bias is not None:
            self.bias.data.fill_(0)
 
    def forward(self, tensor_1, tensor_2):
        projected_tensor_1 = torch.matmul(tensor_1, self.projecting_weight_1)
        if self.reuse_weight:
            projected_tensor_2 = torch.matmul(tensor_2, self.projecting_weight_1)
        else:
            projected_tensor_2 = torch.matmul(tensor_2, self.projecting_weight_2)
        result = (projected_tensor_1 * projected_tensor_2).sum(dim=-1)
        if self.bias is not None:
            result = result + self.bias
        if self.activation is not None:
            result = self.activation(result)
        return result

4、BiLinearSimilarity

此相似度函数执行两个输入向量的双线性变换。这个函数有一个权重矩阵“W”和一个偏差“b”,以及两个向量之间的相似度,计算公式为:

计算后的激活函数。默认为不激活。

class BiLinearSimilarity(nn.Module):
 
    def __init__(self, tensor_1_dim, tensor_2_dim, activation=None):
        super(BiLinearSimilarity, self).__init__()
        self.weight_matrix = nn.Parameter(torch.Tensor(tensor_1_dim, tensor_2_dim))
        self.bias = nn.Parameter(torch.Tensor(1))
        self.activation = activation
        self.reset_parameters()
 
    def reset_parameters(self):
        nn.init.xavier_uniform_(self.weight_matrix)
        self.bias.data.fill_(0)
 
    def forward(self, tensor_1, tensor_2):
        intermediate = torch.matmul(tensor_1, self.weight_matrix)
        result = (intermediate * tensor_2).sum(dim=-1) + self.bias
        if self.activation is not None:
            result = self.activation(result)
        return result

5、TriLinearSimilarity

此相似度函数执行两个输入向量的三线性变换,计算公式为:

计算后的激活函数。默认为不激活。

class TriLinearSimilarity(nn.Module):

def __init__(self, input_dim, activation=None):
super(TriLinearSimilarity, self).__init__()
self.weight_vector = nn.Parameter(torch.Tensor(3 * input_dim))
self.bias = nn.Parameter(torch.Tensor(1))
self.activation = activation
self.reset_parameters()

def reset_parameters(self):
std = math.sqrt(6 / (self.weight_vector.size(0) + 1))
self.weight_vector.data.uniform_(-std, std)
self.bias.data.fill_(0)

def forward(self, tensor_1, tensor_2):
combined_tensors = torch.cat([tensor_1, tensor_2, tensor_1 * tensor_2], dim=-1)
result = torch.matmul(combined_tensors, self.weight_vector) + self.bias
if self.activation is not None:
result = self.activation(result)
return result

6、MultiHeadedSimilarity

这个相似度函数使用多个“头”来计算相似度。也就是说,我们将输入张量投影到多个新张量中,并分别计算每个投影张量的相似度。这里的结果比典型的相似度函数多一个维度。

class MultiHeadedSimilarity(nn.Module):
 
    def __init__(self,
                 num_heads,
                 tensor_1_dim,
                 tensor_1_projected_dim=None,
                 tensor_2_dim=None,
                 tensor_2_projected_dim=None,
                 internal_similarity=DotProductSimilarity()):
        super(MultiHeadedSimilarity, self).__init__()
        self.num_heads = num_heads
        self.internal_similarity = internal_similarity
        tensor_1_projected_dim = tensor_1_projected_dim or tensor_1_dim
        tensor_2_dim = tensor_2_dim or tensor_1_dim
        tensor_2_projected_dim = tensor_2_projected_dim or tensor_2_dim
        if tensor_1_projected_dim % num_heads != 0:
            raise ValueError("Projected dimension not divisible by number of heads: %d, %d"
                             % (tensor_1_projected_dim, num_heads))
        if tensor_2_projected_dim % num_heads != 0:
            raise ValueError("Projected dimension not divisible by number of heads: %d, %d"
                             % (tensor_2_projected_dim, num_heads))
        self.tensor_1_projection = nn.Parameter(torch.Tensor(tensor_1_dim, tensor_1_projected_dim))
        self.tensor_2_projection = nn.Parameter(torch.Tensor(tensor_2_dim, tensor_2_projected_dim))
        self.reset_parameters()
 
    def reset_parameters(self):
        torch.nn.init.xavier_uniform_(self.tensor_1_projection)
        torch.nn.init.xavier_uniform_(self.tensor_2_projection)
 
    def forward(self, tensor_1, tensor_2):
        projected_tensor_1 = torch.matmul(tensor_1, self.tensor_1_projection)
        projected_tensor_2 = torch.matmul(tensor_2, self.tensor_2_projection)
 
        # Here we split the last dimension of the tensors from (..., projected_dim) to
        # (..., num_heads, projected_dim / num_heads), using tensor.view().
        last_dim_size = projected_tensor_1.size(-1) // self.num_heads
        new_shape = list(projected_tensor_1.size())[:-1] + [self.num_heads, last_dim_size]
        split_tensor_1 = projected_tensor_1.view(*new_shape)
        last_dim_size = projected_tensor_2.size(-1) // self.num_heads
        new_shape = list(projected_tensor_2.size())[:-1] + [self.num_heads, last_dim_size]
        split_tensor_2 = projected_tensor_2.view(*new_shape)
 
        # And then we pass this off to our internal similarity function. Because the similarity
        # functions don't care what dimension their input has, and only look at the last dimension,
        # we don't need to do anything special here. It will just compute similarity on the
        # projection dimension for each head, returning a tensor of shape (..., num_heads).
        return self.internal_similarity(split_tensor_1, split_tensor_2)

如果觉得有用,就请分享到朋友圈吧!

△点击卡片关注极市平台,获取 最新CV干货

公众号后台回复“transformer”获取最新Transformer综述论文下载~


极市干货
课程/比赛: 珠港澳人工智能算法大赛 保姆级零基础人工智能教程
算法trick 目标检测比赛中的tricks集锦 从39个kaggle竞赛中总结出来的图像分割的Tips和Tricks
技术综述: 一文弄懂各种loss function 工业图像异常检测最新研究总结(2019-2020)


CV技术社群邀请函 #

△长按添加极市小助手
添加极市小助手微信(ID : cvmart4)

备注:姓名-学校/公司-研究方向-城市(如:小极-北大-目标检测-深圳)


即可申请加入极市目标检测/图像分割/工业检测/人脸/医学影像/3D/SLAM/自动驾驶/超分辨率/姿态估计/ReID/GAN/图像增强/OCR/视频理解等技术交流群


每月大咖直播分享、真实项目需求对接、求职内推、算法竞赛、干货资讯汇总、与 10000+来自港科大、北大、清华、中科院、CMU、腾讯、百度等名校名企视觉开发者互动交流~



觉得有用麻烦给个在看啦~   
登录查看更多
22

相关内容

【AAAI 2022】用于文本摘要任务的序列级对比学习模型
专知会员服务
24+阅读 · 2022年1月11日
专知会员服务
32+阅读 · 2021年10月4日
专知会员服务
88+阅读 · 2021年6月29日
专知会员服务
17+阅读 · 2021年4月24日
专知会员服务
32+阅读 · 2021年2月12日
【字节跳动-李航】一种按序列进行对话状态跟踪的方法
专知会员服务
29+阅读 · 2020年11月25日
【干货书】机器学习速查手册,135页pdf
专知会员服务
125+阅读 · 2020年11月20日
基于改进卷积神经网络的短文本分类模型
专知会员服务
25+阅读 · 2020年7月22日
pytorch提取参数及自定义初始化
极市平台
0+阅读 · 2022年4月13日
Pytorch中的RNN及变种模型与变长序列的处理
极市平台
1+阅读 · 2022年1月17日
PyTorch | 优化神经网络训练的17种方法
极市平台
3+阅读 · 2021年12月30日
pytorch学习 | 提取参数及自定义初始化
极市平台
0+阅读 · 2021年12月21日
实践教程 | 浅谈 PyTorch 中的 tensor 及使用
极市平台
1+阅读 · 2021年12月14日
让你的模型acc更上一层楼:优化调参总结
极市平台
0+阅读 · 2021年11月18日
让PyTorch训练速度更快,你需要掌握这17种方法
机器之心
1+阅读 · 2021年1月17日
百闻不如一码!手把手教你用Python搭一个Transformer
大数据文摘
18+阅读 · 2019年4月22日
计算文本相似度常用的四种方法
论智
33+阅读 · 2018年5月18日
【干货】基于Keras的注意力机制实战
专知
59+阅读 · 2018年5月4日
国家自然科学基金
2+阅读 · 2016年12月31日
国家自然科学基金
0+阅读 · 2015年12月31日
国家自然科学基金
1+阅读 · 2015年12月31日
国家自然科学基金
0+阅读 · 2013年12月31日
国家自然科学基金
0+阅读 · 2012年12月31日
国家自然科学基金
0+阅读 · 2011年12月31日
国家自然科学基金
0+阅读 · 2009年12月31日
国家自然科学基金
0+阅读 · 2008年12月31日
Arxiv
0+阅读 · 2022年4月18日
VIP会员
相关VIP内容
【AAAI 2022】用于文本摘要任务的序列级对比学习模型
专知会员服务
24+阅读 · 2022年1月11日
专知会员服务
32+阅读 · 2021年10月4日
专知会员服务
88+阅读 · 2021年6月29日
专知会员服务
17+阅读 · 2021年4月24日
专知会员服务
32+阅读 · 2021年2月12日
【字节跳动-李航】一种按序列进行对话状态跟踪的方法
专知会员服务
29+阅读 · 2020年11月25日
【干货书】机器学习速查手册,135页pdf
专知会员服务
125+阅读 · 2020年11月20日
基于改进卷积神经网络的短文本分类模型
专知会员服务
25+阅读 · 2020年7月22日
相关资讯
pytorch提取参数及自定义初始化
极市平台
0+阅读 · 2022年4月13日
Pytorch中的RNN及变种模型与变长序列的处理
极市平台
1+阅读 · 2022年1月17日
PyTorch | 优化神经网络训练的17种方法
极市平台
3+阅读 · 2021年12月30日
pytorch学习 | 提取参数及自定义初始化
极市平台
0+阅读 · 2021年12月21日
实践教程 | 浅谈 PyTorch 中的 tensor 及使用
极市平台
1+阅读 · 2021年12月14日
让你的模型acc更上一层楼:优化调参总结
极市平台
0+阅读 · 2021年11月18日
让PyTorch训练速度更快,你需要掌握这17种方法
机器之心
1+阅读 · 2021年1月17日
百闻不如一码!手把手教你用Python搭一个Transformer
大数据文摘
18+阅读 · 2019年4月22日
计算文本相似度常用的四种方法
论智
33+阅读 · 2018年5月18日
【干货】基于Keras的注意力机制实战
专知
59+阅读 · 2018年5月4日
相关基金
国家自然科学基金
2+阅读 · 2016年12月31日
国家自然科学基金
0+阅读 · 2015年12月31日
国家自然科学基金
1+阅读 · 2015年12月31日
国家自然科学基金
0+阅读 · 2013年12月31日
国家自然科学基金
0+阅读 · 2012年12月31日
国家自然科学基金
0+阅读 · 2011年12月31日
国家自然科学基金
0+阅读 · 2009年12月31日
国家自然科学基金
0+阅读 · 2008年12月31日
Top
微信扫码咨询专知VIP会员