[C++] 实现余弦相似度分数计算

Posted 栋次大次

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[C++] 实现余弦相似度分数计算相关的知识,希望对你有一定的参考价值。

余弦相似度公式:
两个向量间的余弦值可以通过使用欧几里得点积公式求出:
a ⋅ b = ∥ a ∥ ∥ b ∥ cos ⁡ θ . \\mathbfa \\cdot \\mathbfb=\\|\\mathbfa\\|\\|\\mathbfb\\| \\cos \\theta . ab=a∥∥bcosθ.
给定两个属性向量, A A A B B B ,其余弦相似性 θ \\theta θ 由点积和向量长度给出,如下所示:
 similarity  = cos ⁡ ( θ ) = A ⋅ B ∥ A ∥ ∥ B ∥ = ∑ i = 1 n A i × B i ∑ i = 1 n ( A i ) 2 × ∑ i = 1 n ( B i ) 2 . \\text similarity =\\cos (\\theta)=\\fracA \\cdot B\\|A\\|\\|B\\|=\\frac\\sum_i=1^n A_i \\times B_i\\sqrt\\sum_i=1^n\\left(A_i\\right)^2 \\times \\sqrt\\sum_i=1^n\\left(B_i\\right)^2 .  similarity =cos(θ)=A∥∥BAB=i=1n(Ai)2 ×i=1n(Bi)2 i=1nAi×Bi.
其中 A i , B i A_i, B_i Ai,Bi 分别代表向量 A \\mathrmA A B \\mathrmB B 的各分量。
给出的相似性范围从-1到1,-1意味着两个向量指向的方向正好截然相反,1表示它们的指向是完全相同的,0通常表示它们 乙间是独立的,而在这之间的值则表示中间的相似性或相异性。

声纹识别中常用余弦相似度来判断注册音频和测试音频是否来自同一个说话人,笔者在此实现了两个C++代码,其中一种使用std::inner_product函数。

std::inner_product函数是计算两个向量的内积,在<numeric >头文件中定义。这个函数模板有 4 个参数:前两个参数是定义第 1 个 vector 的输入迭代器,第 3 个参数是确定第 2 个 vector 的开始输入迭代器,第 4 个参数是和的初值。算法会返回 vector 的内积。

代码如下:

float CosineSimilarity(const std::vector<float>& emb1,
                       const std::vector<float>& emb2) 
  CHECK_EQ(emb1.size(), emb2.size());
  float dot = 0.f;
  float emb1_sum = 0.f;
  float emb2_sum = 0.f;
  for (size_t i = 0; i < emb1.size(); i++) 
    dot += emb1[i] * emb2[i];
    emb1_sum += emb1[i] * emb1[i];
    emb2_sum += emb2[i] * emb2[i];
  
  dot /= std::max(std::sqrt(emb1_sum) * std::sqrt(emb2_sum),
                  std::numeric_limits<float>::epsilon());
  return dot;


float InnerCosine(const std::vector<float>& emb1,
                  const std::vector<float>& emb2) 
  CHECK_EQ(emb1.size(), emb2.size());
  float dot = std::inner_product(emb1.begin(), emb1.end(), emb2.begin(), 0.0);
  float emb1_sum = std::inner_product(emb1.begin(), emb1.end(), emb1.begin(), 0.0);
  float emb2_sum = std::inner_product(emb2.begin(), emb2.end(), emb2.begin(), 0.0);
  dot /= std::max(std::sqrt(emb1_sum) * std::sqrt(emb2_sum),
                  std::numeric_limits<float>::epsilon());
  return dot;

以上是关于[C++] 实现余弦相似度分数计算的主要内容,如果未能解决你的问题,请参考以下文章

如何使用已计算的 TFIDF 分数计算余弦相似度

20-余弦相似度及其R实现

余弦相似度计算

余弦计算相似度理解以及计算

Spark笔记(1) :余弦相似度计算

计算两个向量的余弦相似度