如何检测语音记录与另一个语音记录的相似程度?

时间:2013-06-09 14:14:48

标签: algorithm machine-learning audio

我想建立一个程序来检测用户的录音与另一个录音的接近程度,以便纠正用户的发音。例如:

  1. 我记录自己说“早上好”
  2. 我让外国学生记录“早上好”
  3. 将他的录音与我的录音比较,看他的发音是否足够好。
  4. 我在一些语言学习工具中看到了这一点(我相信Rosetta Stone会这样做),但它是如何完成的?请注意,我们只处理语音(而不是音乐)。我应该研究哪些算法或库?

8 个答案:

答案 0 :(得分:60)

许多人似乎在暗示某种编辑距离,IMO是一种完全错误的方法,用于确定两种语音模式的相似性,特别是对于OP所暗示的模式。事实上,语音识别所使用的特定算法几乎与您在此处使用的算法相反。语音识别中的问题是将许多相似的发音解析为相同的表示。这里的问题是采用一些略有不同的发音,并在它们之间获得某种有意义的距离。

我已经为大规模数据科学做了相当多的工作,虽然我无法评论专有程序是如何做到的,但我可以评论它是如何完成的。学术界提供一个简单明了的解决方案,为您提供这种方法所需的强大功能和灵活性。

首先:假设您拥有的是一些音频,而不对其进行任何过滤。就像从麦克风那里获得一样。第一步是消除背景噪音。有许多不同的方法,但我会假设你想要的东西能够很好地工作而不会非常难以实现。

  • 使用scipy的过滤模块here过滤音频。麦克风拾取的频率很多,对语音分类根本没用。我建议使用贝塞尔或巴特沃斯滤波器来确保通过滤波来保持波形。日常语音的基本频率通常在800到2000赫兹之间(reference),所以合理的截止频率可能是300到4000赫兹,只是为了确保你不会丢失任何东西。
  • 查找最不活跃的语音部分,并假设它是背景噪音的合理表示。此时,您将要沿着数据运行一系列傅里叶变换(或生成频谱图),并找到平均频率响应最低的语音记录部分。拥有该快照后,您应该从音频样本中的所有其他点中减去它。
  • 此时应该有一个主要只是用户语音的音频文件,并且应该准备好与已经完成此过程的另一个文件进行比较。现在,我们想要实际剪辑声音并将此剪辑与某些主剪辑进行比较。

其次:您想要提出两种语音模式之间的距离指标,有很多方法可以做到这一点,但我要去假设我们有第一部分的输出和一些经过类似处理的主文件。

  • 生成相关音频文件的频谱图(example)。这样的输出最终将是一个可以表示为频率响应值的二维阵列的图像。频谱图基本上是随时间变化的傅立叶变换,其中颜色对应于强度。

  • 使用OpenCV(具有python绑定,example)在您的频谱图上运行blob检测。实际上,这将在谱图中间寻找大的彩色斑点,并给你一些限制。实际上,这应该做的是返回原始2d阵列的一个明显更稀疏的版本,它仅代表所讨论的语音。 (假设您的音频文件在录制的前端和后端都有一些尾随的东西)

  • 将两个blob标准化以解释语音速度的差异。每个人都以不同的速度说话,因此你的blob可能沿着x轴(时间)有不同的大小。这将最终在您的算法中引入一系列您不希望语速的检查。如果您还想确保它们以与主副本相同的速度说话,则不需要此步骤,但我建议您这样做。基本上你想通过将它的时间轴乘以一个常数来延伸较短的版本,该常数只是两个blob的长度比。

  • 您还应该根据最大和最小强度对两个blob进行标准化,以便考虑不同音量的人。同样,这取决于您自己的判断,但为了解决这个问题,您应该找到与您拥有的总强度范围相似的比率以及两个记录的最大强度,并确保这两个值在您的两个值之间匹配二维阵列。

第三:既然你有二维数组代表你的两个语音事件,理论上它应该包含所有有用的信息,是时候直接比较它们了。幸运的是,比较两个矩阵是一个很好解决的问题,并且有很多方法可以继续前进。

  • 我个人建议使用像Cosine Similarity这样的指标来确定两个blob之间的差异,但这不是唯一的解决方案,而且它会给你一个快速的验证,你可以做得更好。

  • 您可以尝试从另一个矩阵中减去一个矩阵并评估它们之间的差异,这可能比简单的余弦距离更准确。

  • 这可能有点矫枉过正,但你可以假设某些言语区域或多或少对评估blob之间的区别很重要(如果有人使用长i而不是短i,可能无关紧要,但是ag而不是ak可能完全是一个不同的词。对于类似的东西,你想要在上一步中为差异数组开发一个掩码,并将所有值乘以它。

  • 无论您选择哪种方法,现在只需设置一些差异阈值,并确保两个blob之间的差异低于您想要的阈值。如果是,则捕获的语音足够相似以使其正确。否则让他们再试一次。

我希望这有帮助,而且我再也不能向您保证,这是公司使用的确切算法,因为该信息非常专有且不向公众开放,但我可以保证你可以在学术界最好的论文中使用与这些类似的方法,这些方法可以让你在准确性和易于实现方面取得很大的平衡。如果您有任何问题,请告诉我,祝您未来的数据科学成果好运!

答案 1 :(得分:6)

<强>思想: 生物技术学家对齐两种蛋白质序列的方式如下:每个序列在字母表中表示为字符串(A / C / G / T-这些是不同类型的蛋白质,与我们无关),每个字母(这里, ())代表特定的氨基酸。对齐的质量(其得分)是根据每对相应条目的相似性以及需要插入以产生该对齐的空白条目的数量和长度来计算的。

相同的算法(http://en.wikipedia.org/wiki/Needleman-Wunsch_algorithm)可用于发音,来自一组备用发音中的替换频率。然后,您可以计算对齐分数,以对音素之间的差异敏感的方式测量两个发音之间的相似性。这里可以使用的相似度量是Levenshtein距离,音素错误率和单词错误率。

<强>算法 将一个序列转换成另一个序列所需的最小插入,缺失和取代数是Levenshtein距离。更多信息,请访问http://php.net/manual/en/function.levenshtein.php 音素错误率(PER)是预测发音和参考发音之间的Levenshtein距离除以参考发音中的音素数。 字错误率(WER)是预测发音与至少一个音素错误与发音总数的比例。

来源:在威斯康星大学麦迪逊分校实习了吗

答案 2 :(得分:5)

musicg api https://code.google.com/p/musicg/ 有一个音频指纹生成器和记分员 以及源代码,以显示它是如何完成的。

我认为它会查找每个曲目中最相似的点,然后根据它可以匹配的距离进行评分。

它可能看起来像

import com.musicg.wave.Wave
   com.musicg.fingerprint.FingerprintSimilarity
   com.musicg.fingerprint.FingerprintSimilarityComputer
   com.musicg.fingerprint.FingerprintManager

double score =
new FingerprintsSimilarity(
    new Wave("voice1.wav").getFingerprint(),
    new Wave("voice2.wav").getFingerprint() ).getSimilarity();

答案 3 :(得分:2)

精心配置的Levenshtein distance应该可以解决问题。

答案 4 :(得分:1)

你可以使用Musicg https://code.google.com/p/musicg/作为roy zhang的建议。在android中,只需在你的android项目中包含musicg jar文件并使用它。一个经过测试的例子:

import com.musicg.wave.Wave;
import com.musicg.fingerprint.FingerprintSimilarity;


        //somewhere in your code add
        String file1 = Environment.getExternalStorageDirectory().getAbsolutePath();
        file1 += "/test.wav";

        String file2 = Environment.getExternalStorageDirectory().getAbsolutePath();
        file2 += "/test.wav";

        Wave w1 = new Wave(file1);
        Wave w2 = new Wave(file2);


        FingerprintSimilarity fps = w1.getFingerprintSimilarity(w2);
        float score = fps.getScore();
        float sim = fps.getSimilarity();



        Log.d("score", score+"");
        Log.d("similarities", sim+"");
祝你好运

答案 5 :(得分:0)

您必须研究语音识别算法。我知道您不需要将语音翻译成文本(通过语音识别算法完成),但是,在您的情况下,许多算法都是相同的。

可能HMM在这里会有所帮助(隐藏马尔可夫模型)。 另请参阅此处:http://htk.eng.cam.ac.uk/

答案 6 :(得分:0)

如果这只是检查发音[当然有不同的重音],你可以这样做:

第1步:使用一些语音工具[说dragon dictation],您可以随身携带文字。

步骤2:比较字符串或形成的单词,并将其与实际意图发音的字符串进行比较。

步骤3:如果您发现字符串中存在任何差异,则表示该单词拼写不正确。你可以建议正确的发音。

答案 7 :(得分:0)

我知道这个问题已经过时了,但是...

为解决类似的问题,我使用了Google Speech Recognized API来检查说了些什么,然后目视比较音量变化的缩放波形以检测节奏差异。

Codevideo的结果。