人工智能における音声品質評価方法とコードの詳細

この記事は約16分で読めます。

1.音声品質評価方法

主観的評価方法:MOS、CMOS、ABXテスト、MUSHRA、PESQ

客観的评价方法:MCD、STOI、F0 RMSE、F0 MSE、E MSE、Dur MSE、mel loss

主観的评价方法

1.1 MOS

MOSは、聴取者の主观的なスコアを通じて音声合成の品質を評価する主観的な評価方法です。

公式ウェブサイト:ITU P.800.1 MOSの平均値が4以上の場合は、良い音声品質とされ、平均MOSが3.6以下の場合は、多くの受信者がその音声品質に満足しないことを示します。

MOSテストの一般的な要求:

  • 結果が統計的に顕著であるように、十分な多様性のサンプル(つまり聴取者と文の数)が必要です。
  • 各聴取者の実験環境と機器を一定に保つ必要があります。
  • 各聴取者は同じ評価基準に従う必要があります。

1.2 CMOS

CMOSは、比較的平均意見スコアの略で、自然音声の論文で提案された概念です。MOSは音声品質の違いを非常に敏感に区別するものではなく、2つのシステムの各文を個別にスコアリングするだけで、相互に比較しません。一方でCMOSでは、2つのシステムの文を比較して並べてスコアリングでき、7段階で違いを評価するため、品質の違いにもっとも敏感です。

1.3 ABXテスト

ABXテストは、2つの音声サンプルのどちらが3番目の参照サンプルに近いかを比較するため常用的の主观評価方法です。参加者は3회의聴覚比較でAやBをXにマッチさせる選択をします。このテストはオーディオコーデック、音声合成システムなどの効果を評価する際に常用されます。

1.4 MUSHRA(MUltiple Stimuli with Hidden Reference and Anchor)

MUSHRAは、複数のオーディオサンプル(評価されるもの)を隠された参照オーディオサンプルと比較するため用の主观評価方法です。評価者は参照オーディオと各サンプルをスコアリングし、どのサンプルが参照オーディオに最も近いかを決定します。

客観的评价方法

1.5 MCD

論文タイトル:Mel-cepstral距離測度による音声品質の客観評価

論文アドレス:IEEE Xplore

Github:MattShannon/mcd

Mel cepstral distortion(MCD)は、2つのmel cepstraの連続性の異なる程度を測る指標です。パラメトリック音声合成システムの品質を評価するのに使用されており、統計的パラメトリック音声合成システムで、合成されたmel cepstral列と自然なmel cepstral列の間のMCDが小さいほど、合成音声が自然な音声を再現するのに近いとされます。完璧な合成品質評価指标ではありませんが、他の指標と組み合わせて使用すると便利な指標になり得ます。

MCDの計算方法は以下の通りです。

  • MFCCの抽出:まず、合成音声と対象音声からMFCCを抽出します。これは音声信号をスペクトル表現に変換し、メルフィルタバンクを適用してcepstral分析を行い、MFCC係数を得ます。
  • 距離の計算:次に、合成音声と対象音声のMFCC係数を比較して距離を計算します。通常はユークリッド距離(Euclidean distance)や動的時間ワープ(Dynamic Time Warping、DTW)などの方法で2つの音声信号間の類似性や違いを測ります。
  • 平均値の取得:すべてのフレーム(または時間帯)の距離を平均し、音声信号全体のMCDスコアを得ます。MCDスコアが低いほど、合成音声と対象音声の違いが小さく、品質が高いことを示します。

MCDは音声合成品質を測るための常用の指標ですが、mel cepstral係数間の距離測定に過ぎず、音声合成品質を完全に代表するものではありません。MCDを使用する際には、それが客観的な評価指標であるため、他の指標や主観的な評価と組み合わせて音声合成システムの性能を全面的に評価する必要があります。

研究では、MCDが人々の主観的に感じる音質との関連性が十分でないと示されています。私が見た几乎所有の論文中では、この方法は使用されていません。

MCD(Mel Cepstral Distortion)の計算過程で、3つのモード(plain、dtw、dtw_sl)は異なる計算方法を示しており、主にメルcepstral距離の計算方法に差があります。

  • Plain(通常モード):このモードでのMCD計算は、mel cepstral係数の直接的なユークリッド距離に基づいています。最も単純で直接的な計算方法で、追加の変換や補正はありません。
  • DTW(動的時間ワープ):動的時間ワープは、2つの系列の類似性を比較する方法で、MCDではDTWを使用して2つの系列をアライメントし、距離を最小化します。時間軸で一定の柔軟性を持ったアライメントが可能で、時間的にわずかにずれた場合にも対応できます。
  • DTW_SL(DTW with Straight-line Constraint、直線制約付きDTW):このモードでは、DTWアライメント時に直線制約が加えられます。これは、アライメントプロセスで全体の類似性をあまり影響しないよう、できるだけ直線を維持するようにし、不要な曲げやずれを減らすことを意味します。

1.6 PESQ(Perceptual Evaluation of Speech Quality)

PESQは、音声品質を測るための客観的な評価方法で、元音声と処理(圧縮、エンコーディングなど)された音声の違いを計算して、音声品質のスコアを提供します。この指標は、音声コーデックや通信システムの性能を測るために常用されます。

1.7 STOI(Short-Time Objective Intelligibility)

STOIは、音声の明晰度と理解可能性を測るための客観的な評価方法で、特に音声合成の理解可能性と認識率を測るために適しています。

STOI(Short-Time Objective Intelligibility)は、音声信号の品質を測るための客観的な評価指標です。明晰度と理解可能性の相関を測ることを目的としており、音声信号の品質評価方法です。

STOIは主に以下の手順で行います。

  • 短時間フーリエ変換(STFT):音声信号を短時間に分けてSTFTを行い、信号をスペクトル形式に変換します。
  • スペクトル関連性の計算:元音声と失真/ノイズ音声のスペクトル之间的に関連性を計算します。通常はスペクトルフレーム間の類似度を測ることで行われます。
  • 関連性の平均:すべてのスペクトルフレームの関連性を計算し、平均値を取得して、音声信号全体のSTOIスコアとして扱います。

STOIの結果は0から1の間で、値が1に近いほど音声信号の理解可能性が高いことを示し、0に近いほど低いことを示します。

この評価方法は、音声信号の音質、明晰度、理解可能性に定量的な評価を提供し、音声信号処理分野で特に音声強化、ノイズ低減、コーデック、音声合成などのアプリケーションでアルゴリズムの効果を評価するのに役立ちます。

1.8 LLR(Log Likelihood Ratio)

モデルが生成した音声が与えられた音声分布に属しているかどうかを評価するために使用されます。

2.音声タスクでの使用【詳細コード】

音声合成

音声変換

音声複製

音声合成では主にMOSとCMOSが使用されますが、主観性が大きいため、差異も大きいかもしれません。

2.1 MOS計算

import math
import numpy as np
import pandas as pd
from scipy.linalg import solve
from scipy.stats import t

def calc_mos(data_path: str):
    '''
    MOSを計算します。データ形式:MxN、M個の文、N個の聴取者、data_pathはMOSスコアファイル、内容は
すべての聴取者のスコア
    :param data_path:
    :return:
    '''
    data = pd.read_csv(data_path)
    mu = np.mean(data.values)
    var_uw = (data.std(axis=1) ** 2).mean()
    var_su = (data.std(axis=0) ** 2).mean()
    mos_data = np.asarray([x for x in data.values.flatten() if not math.isnan(x)])
    var_swu = mos_data.std() ** 2

    x = np.asarray([[0, 1, 1], [1, 0, 1], [1, 1, 1]])
    y = np.asarray([var_uw, var_su, var_swu])
    [var_s, var_w, var_u] = solve(x, y)
    M = min(data.count(axis=0))
    N = min(data.count(axis=1))
    var_mu = var_s / M + var_w / N + var_u / (M * N)
    df = min(M, N) - 1  # 可以不减1
    t_interval = t.ppf(0.975, df, loc=0, scale=1)  # t分布の97.5%信頼区間临界値
    interval = t_interval * np.sqrt(var_mu)
    print('{} のMOS95%の信頼区間は:{} ±{} '.format(data_path, round(float(mu), 3), round(interval, 3)))

if __name__ == '__main__':
    data_path = ''
    calc_mos(data_path)

2.2 MCDを使用した計算

単音声比較

from pymcd.mcd import Calculate_MCD

# MCDクラスのインスタンス
# 上記の3つのMCD指標用に3つの異なるモード "plain", "dtw", "dtw_sl" 
mcd_toolbox = Calculate_MCD(MCD_mode="plain")

# 参照(真実)音声と合成音声の2つの入力
# 同じ元音声と生成音声を比較
mcd_value = mcd_toolbox.calculate_mcd("1.wav", "gen_1.wav")
print(mcd_value)

バッチ

from pymcd.mcd import Calculate_MCD
import os
import numpy as np

def batch_calculate_mcd(original_folder, generated_folder):
    mcd_toolbox = Calculate_MCD(MCD_mode="dtw")
    mcd_values = []

    # フォルダ内のファイルリストを取得し、ファイル名でソート
    original_files = sorted(os.listdir(original_folder))
    generated_files = sorted(os.listdir(generated_folder))

    # 音声ファイルを順番に比較
    for orig_file, gen_file in zip(original_files, generated_files):
        orig_path = os.path.join(original_folder, orig_file)
        gen_path = os.path.join(generated_folder, gen_file)

        # MCD値の計算
        mcd_value = mcd_toolbox.calculate_mcd(orig_path, gen_path)
        print(f"MCD value for {orig_file} and {gen_file}: {mcd_value}")
        mcd_values.append(mcd_value)

    # 平均値と分散の計算
    mean_mcd = np.mean(mcd_values)
    variance_mcd = np.var(mcd_values)

    print(f"Mean MCD value: {mean_mcd}")
    print(f"Variance of MCD values: {variance_mcd}")

original_folder_path = './original_data'
generated_folder_path = './gen_data'

batch_calculate_mcd(original_folder_path, generated_folder_path)

2.3 STOI

単音声比較

# pip install scipy numpy

import numpy as np
from scipy.io import wavfile
from scipy.signal import stft

def stoi(x, y, fs):
    win_len = int(fs * 0.025)  # 窓長は25ms
    hop_len = int(fs * 0.010) # 窓移動は10ms

    _, _, Pxo = stft(x, fs=fs, nperseg=win_len, noverlap=hop_len)
    _, _, Pyo = stft(y, fs=fs, nperseg=win_len, noverlap=hop_len)

    # 時間周波数上的STOIを計算
    stoi_values = []
    for i in range(Pxo.shape[1]):
        Pxo_i = np.abs(Pxo[:, i])
        Pyo_i = np.abs(Pyo[:, i])

        Rxy = np.sum(Pxo_i * Pyo_i) / np.sqrt(np.sum(Pxo_i ** 2) * np.sum(Pyo_i ** 2))
        stoi_values.append(Rxy)

    return np.mean(stoi_values)

# 元音声と生成音声を読み込む
rate_orig, orig_audio = wavfile.read('original_data/1.wav')
rate_gen, gen_audio = wavfile.read('gen_data/gen_1.wav')

if rate_orig != rate_gen:
    print("元音声と生成音声のサンプリングレートが異なる場合は、生成音声のサンプリングレートを元音声のサンプリングレートに調整してください。")

# STOI値を計算
stoi_value = stoi(orig_audio, gen_audio, rate_orig)
print("stoi value:", stoi_value)

バッチ比較

import os
import numpy as np
from scipy.io import wavfile
from scipy.signal import stft

def stoi(x, y, fs):
    win_len = int(fs * 0.025)  # 窓長は25ms
    hop_len = int(fs * 0.010)  # 窓移動は10ms

    _, _, Pxo = stft(x, fs=fs, nperseg=win_len, noverlap=hop_len)
    _, _, Pyo = stft(y, fs=fs, nperseg=win_len, noverlap=hop_len)

    stoi_values = []
    for i in range(Pxo.shape[1]):
        Pxo_i = np.abs(Pxo[:, i])
        Pyo_i = np.abs(Pyo[:, i])

        # 周波数間の関連性を計算
        Rxy = np.sum(Pxo_i * Pyo_i) / np.sqrt(np.sum(Pxo_i ** 2) * np.sum(Pyo_i ** 2))
        stoi_values.append(Rxy)

    return np.mean(stoi_values)

def calculate_stoi_for_files(original_folder, generated_folder):
    original_files = os.listdir(original_folder)
    generated_files = os.listdir(generated_folder)

    for orig_file, gen_file in zip(original_files, generated_files):
        orig_path = os.path.join(original_folder, orig_file)
        gen_path = os.path.join(generated_folder, gen_file)

        rate_orig, orig_audio = wavfile.read(orig_path)
        rate_gen, gen_audio = wavfile.read(gen_path)

        # サンプリングレート調整...
        # 必要に応じてサンプリングレート調整を実施...

        # STOI値を計算
        stoi_value = stoi(orig_audio, gen_audio, rate_orig)
        print(f"STOI値 - {orig_file} vs {gen_file}: {stoi_value}")

# 元音声と生成音声のフォルダパス
original_folder_path = 'path_to_original_audio_folder'
generated_folder_path = 'path_to_generated_audio_folder'

# STOI値を計算
calculate_stoi_for_files(original_folder_path, generated_folder_path)

3.テストの概要

3.1 MCDテストの概要

話者の3つの異なるモードの音声スコアをテストし、plain/dtwモードを使用しました。

最初のものは実際の生成で、他の3つは異なる文です。これより、MCDの値が音声生成結果の良し悪しを完全に代表するわけではないことがわかります!

3.2 STIOテストの概要

データ比較時にnanやindexインデックス問題が容易出现で、注意が必要です。

aiスピーキング

ドルフィンAIは言語学習アプリケーションのためのプロフェッショナルな発音評価API(pronunciation assessment api)ソリューションを提供します。音素、単語、文章、チャプター、発音矯正、単語矯正、クイズ、フリーダイアログ、多肢選択問題など幅広く提供しています。当社の発音評価製品(pronunciation assessment)は、英語と中国語、クラウドAPI、オンプレミス、オフラインデバイスの展開をサポートしています。当社の発音評価API(pronunciation assessment api)は、正確性、流暢性、完全性、リズムの次元をカバーする豊富な評価指標を提供し、音素、単語、文の異なるレベルの評価スコアも提供します。また、音素、単語、文の異なるレベルでの評価スコアも提供します。数千万人のユーザーに安定した効率的で安全なサービスを提供しています。ドルフィンAIの発音評価製品(pronunciation assessment)を試してみませんか?

タイトルとURLをコピーしました