【问题标题】:How to detect how similar a speech recording is to another speech recording?如何检测语音记录与另一个语音记录的相似程度?
【发布时间】:2013-06-05 07:40:39
【问题描述】:

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

  1. 我录下自己说“早上好”
  2. 我让一个外国学生录制“早上好”
  3. 比较他的录音和我的录音,看看他的发音是否足够好。

我在一些语言学习工具中看到了这一点(我相信 Rosetta Stone 会这样做),但它是如何完成的?请注意,我们只处理语音(而不是音乐)。我应该研究哪些算法或库?

【问题讨论】:

标签: algorithm machine-learning audio


【解决方案1】:

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

为了解决类似的问题,我使用 Google Speech Recognized API 来检查所说的内容,并通过视觉比较音量变化的缩放波形来检测节奏差异。

Code & video 的结果。

【讨论】:

    【解决方案2】:

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

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

    首先:假设您拥有的是一些没有经过任何过滤的音频块。就像从麦克风中获取它一样。第一步是消除背景噪音。有许多不同的方法可以做到这一点,但我会假设你想要的东西可以很好地工作而不会非常难以实现。

    • 使用 scipy 的过滤模块here 过滤音频。麦克风拾取的许多频率对于语音分类根本没有用处。我建议使用 Bessel 或 Butterworth 滤波器,以确保您的波形通过滤波得以保留。日常语音的基本频率通常在 800 到 2000 赫兹 (reference) 之间,因此合理的截止频率应该是 300 到 4000 赫兹,以确保您不会丢失任何东西。
    • 寻找语音中最不活跃的部分,并假设这是背景噪音的合理表示。此时,您将要对数据进行一系列傅立叶变换(或生成频谱图),并找到语音记录中具有最低平均频率响应的部分。获得该快照后,您应该从音频样本中的所有其他点中减去它。
    • 此时应该有一个音频文件,主要是您的用户的语音,并且应该准备好与另一个经过此过程的文件进行比较。现在,我们要实际剪辑声音并将此剪辑与某个主剪辑进行比较。

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

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

    • 使用 OpenCV(具有 python 绑定,example)在您的频谱图上运行斑点检测。实际上,这将在你的频谱图中间寻找大的彩色斑点,并给你一些限制。实际上,这应该做的是返回原始二维数组的一个明显更稀疏的版本,该二维数组仅代表有问题的语音。 (假设您的音频文件在录音的前端和后端会有一些尾随内容)

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

    • 您还应该根据最大和最小强度对两个 blob 进行归一化,以说明说话音量不同的人。同样,这取决于您的判断,但要解决此问题,您应该为您拥有的总强度跨度以及两个记录的最大强度找到相似的比率,并确保这两个值在您的二维阵列之间匹配.

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

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

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

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

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

    我希望这会有所帮助,而且我不能向您保证这是公司使用的确切算法,因为该信息是高度专有的并且不向公众开放,但我可以向您保证类似于这些的方法被用在学术界最好的论文中,这些方法将使您在准确性和易于实施之间取得很好的平衡。如果您有任何问题,请告诉我,祝您在未来的数据科学开发中好运!

    【讨论】:

      【解决方案3】:

      您可以按照 roy zhang 的建议使用 Musicg https://code.google.com/p/musicg/。在 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+"");
      

      祝你好运

      【讨论】:

      • 我刚刚测试了api。它不支持语音识别功能。
      【解决方案4】:

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

      HMM 在这里可能会有所帮助(隐藏马尔可夫模型)。 也看这里:http://htk.eng.cam.ac.uk/

      【讨论】:

        【解决方案5】:

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

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

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

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

        【讨论】:

        • 这只是给出两个发音是否相似。 OP 想知道发音的“相似程度”。
        【解决方案6】:

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

        【讨论】:

          【解决方案7】:

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

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

          算法 将一个序列转换为另一个序列所需的插入、删除和替换的最小数量是 Levenshtein 距离。更多信息http://php.net/manual/en/function.levenshtein.php 音素错误率 (PER) 是预测发音与参考发音之间的 Levenshtein 距离除以参考发音中的音素数。 单词错误率(WER)是预测出的至少有一个音素错误的发音占发音总数的比例。

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

          【讨论】:

          • 这当然是假设你已经可以将你的语音解析成音素,音素的所有差异都是相同的,并且你有足够长的语音模式可以从微小的音素变化中得到统计趋势,与OP给出的示例不同。这对基因序列非常有效,主要是因为在这些假设是合理的情况下,这是一个完全不同的问题。
          【解决方案8】:

          musicg apihttps://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();
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-05-18
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-05-27
            相关资源
            最近更新 更多