語音信號(hào)處理一般都要進(jìn)行主觀評(píng)價(jià)實(shí)驗(yàn)和客觀評(píng)價(jià)實(shí)驗(yàn)。
- 主觀評(píng)價(jià):邀請(qǐng)測(cè)聽者對(duì)語音進(jìn)行測(cè)聽,給出主觀意見得分
- 客觀評(píng)價(jià):根據(jù)算法來衡量語音質(zhì)量
主觀投票受多種因素影響,如個(gè)體受試者的偏好和實(shí)驗(yàn)的語境(其他條件)。一個(gè)好的客觀質(zhì)量度量應(yīng)該與許多不同的主觀實(shí)驗(yàn)有很高的相關(guān)性
信噪比(SNR)
有用信號(hào)功率與噪聲功率的比(此處功率為平均功率),也等于幅度比的平方
![](http://img.jbzj.com/file_images/article/202105/2021525155749314.png?2021425155831)
其中:$P_{signal}$為信號(hào)功率(平均功率或者實(shí)際功率);$P_{noise}$為噪聲功率;$A_{signal}$為信號(hào)幅度;$A_{noise}$為噪聲幅度值,功率等于幅度值的平方
MATLAB版本代碼
# 信號(hào)與噪聲長(zhǎng)度應(yīng)該一樣
function snr=SNR_singlech(Signal,Noise)
P_signal = sum(Signal-mean(Signal)).^2; # 信號(hào)的能量
P_noise = sum(Noise-mean(Noise)).^2; # 噪聲的能量
snr = 10 * log10(P_signal/P_noise)
tensorflow版本SNR
def tf_compute_snr(labels, logits):
# labels和logits都是三維數(shù)組 (batch_size, wav_data, 1)
signal = tf.reduce_mean(labels ** 2, axis=[1, 2])
noise = tf.reduce_mean((logits - labels) ** 2, axis=[1, 2])
noise = tf.reduce_mean((logits - labels) ** 2 + 1e-6, axis=[1, 2])
snr = 10 * tf.log(signal / noise) / tf.log(10.)
# snr = 10 * tf.log(signal / noise + 1e-8) / tf.log(10.)
snr = tf.reduce_mean(snr, axis=0)
return snr
def Volodymyr_snr(labels, logits):
# labels和logits都是三維數(shù)組 (batch_size, wav_data, 1)
noise = tf.sqrt(tf.reduce_mean((logits - labels) ** 2 + 1e-6, axis=[1, 2]))
signal = tf.sqrt(tf.reduce_mean(labels ** 2, axis=[1, 2]))
snr = 20 * tf.log(signal / noise + 1e-8) / tf.log(10.)
avg_snr = tf.reduce_mean(snr, axis=0)
return avg_snr
Volodymyr Kuleshov論文實(shí)現(xiàn)方法
批注:這里的1e-6和1e-8,目的是為了防止出現(xiàn)Nan值,如果沒有這個(gè)需求可以去除
numpy版本代碼
def numpy_SNR(labels, logits):
# origianl_waveform和target_waveform都是一維數(shù)組 (seq_len, )
# np.sum實(shí)際功率;np.mean平均功率,二者結(jié)果一樣
signal = np.sum(labels ** 2)
noise = np.sum((labels - logits) ** 2)
snr = 10 * np.log10(signal / noise)
return snr
峰值信噪比(PSNR)
表示信號(hào)的最大瞬時(shí)功率和噪聲功率的比值,最大瞬時(shí)功率為語音數(shù)據(jù)中最大值得平方。
![](http://img.jbzj.com/file_images/article/202105/2021525155906691.png?2021425155933)
def psnr(label, logits):
MAX = np.max(label) ** 2 # 信號(hào)的最大平時(shí)功率
MSE = np.mean((label - logits) ** 2)
return np.log10(MAX / MSE)
分段信噪比(SegSNR)
由于語音信號(hào)是一種緩慢變化的短時(shí)平穩(wěn)信號(hào),因而在不同時(shí)間段上的信噪比也應(yīng)不一樣。為了改善上面的問題,可以采用分段信噪比。分段信噪比即是先對(duì)語音進(jìn)行分幀,然后對(duì)每一幀語音求信噪比,最好求均值。
MATLAB版本的代碼
function [segSNR] = Evaluation(clean_speech,enhanced)
N = 25*16000/1000; %length of the segment in terms of samples
M = fix(size(clean_speech,1)/N); %number of segments
segSNR = zeros(size(enhanced));
for i = 1:size(enhanced,1)
for m = 0:M-1
sum1 =0;
sum2 =0;
for n = m*N +1 : m*N+N
sum1 = sum1 +clean_speech(n)^2;
sum2 = sum2 +(enhanced{i}(n) - clean_speech(n))^2;
end
r = 10*log10(sum1/sum2);
if r>55
r = 55;
elseif r -10
r = -10;
end
segSNR(i) = segSNR(i) +r;
end
segSNR(i) = segSNR(i)/M;
end
python代碼
def SegSNR(ref_wav, in_wav, windowsize, shift):
if len(ref_wav) == len(in_wav):
pass
else:
print('音頻的長(zhǎng)度不相等!')
minlenth = min(len(ref_wav), len(in_wav))
ref_wav = ref_wav[: minlenth]
in_wav = in_wav[: minlenth]
# 每幀語音中有重疊部分,除了重疊部分都是幀移,overlap=windowsize-shift
# num_frame = (len(ref_wav)-overlap) // shift
# = (len(ref_wav)-windowsize+shift) // shift
num_frame = (len(ref_wav) - windowsize + shift) // shift # 計(jì)算幀的數(shù)量
SegSNR = np.zeros(num_frame)
# 計(jì)算每一幀的信噪比
for i in range(num_frame):
noise_frame_energy = np.sum(ref_wav[i * shift: i * shift + windowsize] ** 2) # 每一幀噪聲的功率
speech_frame_energy = np.sum(in_wav[i * shift: i * shift + windowsize] ** 2) # 每一幀信號(hào)的功率
SegSNR[i] = np.log10(speech_frame_energy / noise_frame_energy)
return 10 * np.mean(SegSNR)
信號(hào)回聲比 (Signal to echo ratio, SER)
![](http://img.jbzj.com/file_images/article/202105/2021525155952533.png?202142516013)
其中E是統(tǒng)計(jì) 期望操作,$s(n)$是近端語音,$d(n)$是遠(yuǎn)端回聲
def SER(near_speech, far_echo):
"""signal to echo ratio, 信號(hào)回聲比
:param near_speech: 近端語音
:param far_echo: 遠(yuǎn)端回聲
"""
return 10*np.log10(np.mean(near_speech**2)/np.mean(far_echo**2))
回聲損失增強(qiáng) (Echo Return Loss Enhancement, ERLE)
回波損失增強(qiáng)度量(ERLE)通常用于評(píng)估系統(tǒng)在沒有近端信號(hào)的單通話情況下 的回聲減少。ERLE的定義是
![](http://img.jbzj.com/file_images/article/202105/2021525160040895.png?20214251615)
其中E是統(tǒng)計(jì) 期望操作,$y(n)$是麥克風(fēng)信號(hào),$\hat{s}(n)$是估計(jì)的近端語音信號(hào)。
def compute_ERLE(mic_wav, predict_near_end_wav):
"""
:param mic_wav: 麥克風(fēng)信號(hào)(y) = 近端語音(s) + 遠(yuǎn)端語音回聲(s) + 噪聲(v)
:param predict_near_end_wav: 估計(jì)的近端語音信號(hào) \hat{s}
麥克風(fēng)信號(hào)
"""
mic_mear = np.mean(mic_wav**2)
predict_near_end_wav = np.mean(predict_near_end_wav**2)
ERLE = 10 * np.log10(mic_mear/predict_near_end_wav)
return ERLE
為了評(píng)估系統(tǒng)在雙講情況下的性能,通常采用PESQ(語音質(zhì)量感知評(píng)價(jià))或STOI (短時(shí)語音可懂度),他是通過將估計(jì)的近端語音和僅在雙講通話期間真實(shí)的近端語音進(jìn)行比較得到的。PESQ評(píng)分范圍為-0.5 ~ 4.5,分?jǐn)?shù)越高質(zhì)量越好。STOI評(píng)分范圍為0~1,分?jǐn)?shù)越高越好。
對(duì)數(shù)擬然對(duì)比度 (log Likelihood Ratio Measure)
坂倉距離測(cè)度是通過語音信號(hào)的線性預(yù)測(cè)分析來實(shí)現(xiàn)的。ISD基于兩組線性預(yù)測(cè)參數(shù)(分別從原純凈語音和處理過的語音的同步幀得到)之間的差異。LLR可以看成一種坂倉距離(Itakura Distance,IS)但是IS距離需要考慮模型增益。而LLR不需要考慮模型爭(zhēng)議引起的幅度位移,更重視整體譜包絡(luò)的相似度。
語音質(zhì)量感知評(píng)估 (Perceptual Evaluation of Speech Quality, PESQ)
引言:我先做個(gè)簡(jiǎn)要介紹,再講使用。使用之前建議還是詳細(xì)了解一下,不要用錯(cuò)了,導(dǎo)致論文被拒,或者做了偽研究,以下內(nèi)容是我挑重點(diǎn)摘自ITU-T P862建議書,比較權(quán)威,重要的地方我會(huì)加粗。想要進(jìn)一步了解的自行去下載原文。
PESQ是由國(guó)際電信聯(lián)盟(International Telecommunication Union,ITU) 2001年提供的ITU-T P862建議書:語音質(zhì)量的感知評(píng)估(PESQ):窄帶電話網(wǎng)絡(luò)和語音編解碼器的端到端語音質(zhì)量評(píng)估的客觀方法,并提供了ANSI-C語言實(shí)現(xiàn)代碼。真實(shí)系統(tǒng)可能包括濾波和可變延遲,以及由于信道誤差和低比特率編解碼器引起的失真。國(guó)際電聯(lián)電信政策861中描述的PSQM方法僅被推薦用于評(píng)估語音編解碼器,不能適當(dāng)考慮濾波、可變延遲和短時(shí)局部失真。PESQ通過傳遞函數(shù)均衡、時(shí)間校準(zhǔn)和一種新的時(shí)間平均失真算法來解決這些影響。PESQ的驗(yàn)證包括許多實(shí)驗(yàn),這些實(shí)驗(yàn)專門測(cè)試了它在濾波、可變延遲、編碼失真和信道誤差等因素組合下的性能。
建議將PESQ用于3.1kHz(窄帶)手機(jī)電話和窄帶語音編解碼器的語音質(zhì)量評(píng)估。PESQ是屬于客觀評(píng)價(jià),和主觀分?jǐn)?shù)之間的相關(guān)性約為0.935,但PESQ算法不能用來代替主觀測(cè)試。
PESQ算法沒有提供傳輸質(zhì)量的綜合評(píng)估。它只測(cè)量單向語音失真和噪聲對(duì)語音質(zhì)量的影響。響度損失、延遲、側(cè)音、回聲和其他與雙向互動(dòng)相關(guān)的損傷(如中央削波器)的影響不會(huì)反映在PESQ分?jǐn)?shù)中。因此,有可能有很高的PESQ分?jǐn)?shù),但整體連接質(zhì)量很差。
PESQ的感知模型用于計(jì)算原始信號(hào)$X(t)$與退化信號(hào)$Y(t)$之間的距離(PESQ分?jǐn)?shù)),退化信號(hào)$Y(t)$是$X(t)$通過通信系統(tǒng)的結(jié)果。PESQ的輸出是對(duì)受試者在主觀聽力測(cè)試中給予$Y(t)$的感知質(zhì)量的預(yù)測(cè)。取值在-0.5到4.5的范圍內(nèi),得分越高表示語音質(zhì)量越好,盡管在大多數(shù)情況下輸出范圍在1.0到4.5之間。
![](/d/20211017/db27f9dffaffcfb2f93e8c7f8f469bd4.gif)
ITU提供了C語言代碼,下載請(qǐng)點(diǎn)擊這里,但是在使用之前我們需要先編譯C腳本,生成可執(zhí)行文件exe
編譯方式為:在命令行進(jìn)入下載好的文件
- cd\Software\source
- gcc -o PESQ *.c
經(jīng)過編譯,會(huì)在當(dāng)前文件夾生成一個(gè)pesq.exe的可執(zhí)行文件
使用方式為:
- 命令行進(jìn)入pesq.exe所在的文件夾
- 執(zhí)行命令:pesq 采樣率 "原始文件路徑名" "退化文件路徑名”,采樣率必須選擇+8000(窄帶)或+16000(寬帶),
- 回車
- 等待結(jié)果即可,值越大,質(zhì)量越好。
例如:pesq +16000 raw.wav processed.wav
python代碼實(shí)現(xiàn)
參考地址:https://github.com/ludlows/python-pesq
首先我們需要安裝pesq庫:pip install pesq
from scipy.io import wavfile
from pesq import pesq
rate, ref = wavfile.read("./audio/speech.wav")
rate, deg = wavfile.read("./audio/speech_bab_0dB.wav")
print(pesq(rate, ref, deg, 'wb'))
print(pesq(rate, ref, deg, 'nb'))
該python庫返回的是MOS-LQO,屬于pesq的映射,現(xiàn)在用的更多的也是MOS-LQO。如果你硬是想要PESQ得分,你可以自行逆變換回去,公式見下一節(jié)
MOS-LQO
MOS-LQO (Mean Opinion Score – Listening Quality Objective),使用客觀測(cè)量技術(shù)評(píng)估主觀聽力質(zhì)量)與之相對(duì)的還有MOS-LQS(Mean Opinion Score – Listening Quality Subjective),使用樣本的主觀評(píng)分直接衡量聽力質(zhì)量,就是主觀評(píng)價(jià)了。
功能:將P.862原始結(jié)果分?jǐn)?shù)轉(zhuǎn)換為MOS-LQO的映射,P862.1:用于將P.862原始結(jié)果分?jǐn)?shù)轉(zhuǎn)換為MOS-LQO的映射函數(shù).pdf
ITU-TP.862建議書提供的原始分?jǐn)?shù)在-0.5到4.5之間。希望從PESQ (P.862)得分中轉(zhuǎn)換為MOS-LQO (P.862.1)分?jǐn)?shù),從而可以與MOS進(jìn)行線性比較。該建議書介紹了從原始P.862得分到MOS-LQO(P.800.1)的映射函數(shù)及其性能。映射函數(shù)已在代表不同應(yīng)用程序和語言的大量主觀數(shù)據(jù)上進(jìn)行了優(yōu)化,所呈現(xiàn)的性能優(yōu)于原始的PESQ(P862),取值在[1, 4.5]之間,連續(xù)的。公式為:
$$公式1:y=0.999+\frac{4.999-0.999}{1+e^{-1.4945x+4.6607}}$$
![](/d/20211017/385f3c4e5da1c02eda01e98e6919701a.gif)
python實(shí)現(xiàn)
def pesq2mos(pesq):
""" 將PESQ值[-0.5, 4.5]映射到MOS-LQO得分[1, 4.5]上,映射函數(shù)來源于:P.862.1 """
return 0.999 + (4.999 - 0.999) / (1 + np.exp(-1.4945 * pesq + 4.6607))
MATLAB官方實(shí)現(xiàn)請(qǐng)參見:
公式2給出了從MOS-LQO分?jǐn)?shù)到PESQ分?jǐn)?shù)的轉(zhuǎn)換的反映射函數(shù)
![](http://img.jbzj.com/file_images/article/202105/2021525160128798.png?202142516151)
python實(shí)現(xiàn)
def mos2pesq(mos):
""" 將MOS-LQO得分[1, 4.5]映射到PESQ值[-0.5, 4.5]上,映射函數(shù)來源于:P.862.1"""
inlog = (4.999 - mos) / (mos - 0.999)
return (4.6607 - np.log(inlog)) / 1.4945
需要注意的是,所提供的函數(shù)有一些實(shí)際限制:
- 本文提供的映射函數(shù)對(duì)源自所有類型應(yīng)用程序的數(shù)據(jù)庫進(jìn)行了優(yōu)化。僅針對(duì)特定應(yīng)用程序或語言進(jìn)行優(yōu)化的其他映射函數(shù)可能在該特定應(yīng)用程序或語言上比提供的函數(shù)執(zhí)行得更好。
- 雖然訓(xùn)練數(shù)據(jù)庫包含分?jǐn)?shù)較低的MOS區(qū)域中的樣本比例很大,但是在原始P.862分?jǐn)?shù)0.5到1的范圍內(nèi)缺少樣本。在此范圍內(nèi),映射的P.862函數(shù)進(jìn)行插值,因此確定了預(yù)測(cè)誤差Ep和平均殘差Em
PESQ-WB
2007年11.13國(guó)際電聯(lián)公布了PESQ的寬帶版本(ITU-T P862.2,PESQ-WB),P.862建議書的寬帶擴(kuò)展,用于評(píng)估寬帶電話網(wǎng)絡(luò)和語音編解碼器,主要用于寬帶音頻系統(tǒng) (50-7000 Hz),盡管它也可以應(yīng)用于帶寬較窄的系統(tǒng)。例如聽眾使用寬帶耳機(jī)的語音編解碼器。相比之下,ITU-T P.862建議書假設(shè)使用標(biāo)準(zhǔn)的IRS型窄帶電話手機(jī),在300 Hz以下和3100 Hz以上會(huì)強(qiáng)烈衰減。
使用范圍
- 不建議將PESQ-WB用在信號(hào)插入點(diǎn)和信號(hào)捕獲點(diǎn)之間包含噪聲抑制算法的系統(tǒng)。 另外,應(yīng)使用干凈的語音樣本,因?yàn)猷须s的語音樣本,即那些信噪比較差的語音樣本,可能會(huì)導(dǎo)致預(yù)測(cè)錯(cuò)誤。 用戶還應(yīng)注意,寬帶語音主觀實(shí)驗(yàn)中不同失真類別的相對(duì)排名可能會(huì)隨語言種類而略有變化。 特別要注意的是,寬帶擴(kuò)展可能會(huì)高估ITU-T Rec.3建議書的MOS分?jǐn)?shù)。
- 當(dāng)使用PESQ-WB來比較可能對(duì)音頻信號(hào)進(jìn)行頻帶限制的系統(tǒng)的性能時(shí),建議使用一個(gè)寬帶(50-7000 Hz音頻帶寬)版本的信號(hào)作為所有參考信號(hào)。被限制帶寬的測(cè)試系統(tǒng)會(huì)導(dǎo)致語音性能下降,降低輸出分?jǐn)?shù)。這種限制可能會(huì)降低信號(hào)的預(yù)測(cè)精度。不建議存在信號(hào)退化的嚴(yán)重限制,即小于傳統(tǒng)電話帶寬(300- 3400hz) 。
- PESQ-WB是評(píng)估寬帶語音條件的主觀實(shí)驗(yàn)的背景下預(yù)測(cè)主觀意見,即音頻帶寬從50赫茲擴(kuò)展到7000赫茲的信號(hào)。這意味著,由于不同的實(shí)驗(yàn)環(huán)境,無法直接比較寬帶擴(kuò)展產(chǎn)生的分?jǐn)?shù)和基線[ITU-T P862]或[ITU-T P862.1]產(chǎn)生的分?jǐn)?shù)。
基本的P.862模型提供的原始分?jǐn)?shù)在–0.5到4.5之間。 [ITU-T P.862]的PESQ-WB包括一個(gè)映射函數(shù),輸出的也是映射值,該函數(shù)允許與主觀評(píng)價(jià)的MOS得分進(jìn)行線性比較,這些主觀實(shí)驗(yàn)包括音頻帶寬為50-7000 Hz的寬帶語音條件。 這意味著由于實(shí)驗(yàn)環(huán)境的不同,無法直接比較PESQ-WB產(chǎn)生的分?jǐn)?shù)和基線[ITU-T P.862]或[ITU-T P.862.1]產(chǎn)生的分?jǐn)?shù)。PESQ-WB中使用的輸出映射函數(shù)定義如下:
![](http://img.jbzj.com/file_images/article/202105/2021525160230508.png?202142516252)
其中$x$是原模型輸出。
[ITU-T P.862]的附件A中給出了了PESQ-WB的寬帶擴(kuò)展的ANSI-C參考實(shí)現(xiàn)。
感知客觀語音質(zhì)量評(píng)估 (POLQA)
POLQA度量方法授權(quán)給了epticom公司,只有該公司授權(quán)的機(jī)構(gòu)才能使用,我總結(jié)在這就是讓大家了解一下,反正我們都用不了,哈哈
ITU P.863建議書提供了一種客觀評(píng)價(jià)方法:感知客觀語音質(zhì)量評(píng)估 (Perceptual objective listening quality prediction, P.OLQA),ITU-T P.863建議書支持兩種操作模式,一種用于窄帶 (NB, 300Hz-3.4kHz),一種用于全帶 (FB, 20Hz-20kHz)。
可以應(yīng)用到全頻帶語音編解碼器(例如,OPUS,增強(qiáng)語音服務(wù)(EVS))。比較參考信號(hào)X(t)和退化信號(hào)Y(t),其中Y(t)是通過通信系統(tǒng)傳遞X(t)的結(jié)果,人類聽覺系統(tǒng)中音頻信號(hào)的心理物理表征,
ITU-T P.863算法消除了參考信號(hào)中的低水平噪聲,同時(shí)對(duì)退化輸出信號(hào)中的噪聲也進(jìn)行了部分抑制。
一個(gè)好的客觀質(zhì)量測(cè)量應(yīng)該與多個(gè)不同的主觀實(shí)驗(yàn)有很高的相關(guān)性。在實(shí)踐中,使用ITU-T P.863算法,回歸映射通常幾乎是線性的,在日常實(shí)踐中,不需要對(duì)客觀分?jǐn)?shù)進(jìn)行特殊映射,因?yàn)镮TU-T P.863分?jǐn)?shù)已經(jīng)映射到MOS尺度,反映了大量單獨(dú)數(shù)據(jù)集的平均值。
POLQA結(jié)果主要是模型平均意見得分(MOS),涵蓋從1(差)到5(優(yōu)秀)的范圍。在全頻帶模式下得分為MOS-LQO 4.80,在窄帶模式下得分為MOS-LQO 4.5。這反映了一個(gè)事實(shí),即不是所有的主觀測(cè)試參與者都會(huì)給最高的評(píng)級(jí),即使是不降級(jí)的參考。
![](/d/20211017/ca180bdfb6c96f3e7006df1f805e2948.gif)
對(duì)數(shù)譜距離(LSD)
對(duì)數(shù)譜距離Log Spectral Distance,LSD是兩個(gè)頻譜之間的距離度量。也稱為“對(duì)數(shù)譜失真”
![](http://img.jbzj.com/file_images/article/202105/2021525160312359.png?202142516333)
式中,$l$和$m$分別為頻率索引和幀索引,$M$為語音幀數(shù),$L$為頻點(diǎn)數(shù),$\hat{S}(l, m)$和$S(l, m)$分別為估計(jì)音頻和寬帶音頻經(jīng)過短時(shí)短時(shí)傅里葉變換后的頻譜。
numpy版本
# 方法一
def numpy_LSD(labels, logits):
""" labels 和 logits 是一維數(shù)據(jù) (seq_len,)"""
labels_spectrogram = librosa.stft(labels, n_fft=2048) # (1 + n_fft/2, n_frames)
logits_spectrogram = librosa.stft(logits, n_fft=2048) # (1 + n_fft/2, n_frames)
labels_log = np.log10(np.abs(labels_spectrogram) ** 2)
logits_log = np.log10(np.abs(logits_spectrogram) ** 2)
# 先處理頻率維度
lsd = np.mean(np.sqrt(np.mean((labels_log - logits_log) ** 2, axis=0)))
return lsd
# 方法二
def get_power(x):
S = librosa.stft(x, n_fft=2048) # (1 + n_fft/2, n_frames)
S = np.log10(np.abs(S) ** 2)
return S
def compute_log_distortion(labels, logits):
"""labels和logits數(shù)據(jù)維度為 (batch_size, seq_len, 1)"""
avg_lsd = 0
batch_size = labels.shape[0]
for i in range(batch_size):
S1 = get_power(labels[i].flatten())
S2 = get_power(logits[i].flatten())
# 先處理頻率軸,后處理時(shí)間軸
lsd = np.mean(np.sqrt(np.mean((S1 - S2) ** 2, axis=0)), axis=0)
avg_lsd += lsd
return avg_lsd / batch_size
tensorflow版本
def get_power(x):
x = tf.squeeze(x, axis=2) # 去掉位置索引為2維數(shù)為1的維度 (batch_size, input_size)
S = tf.signal.stft(x, frame_length=2048, frame_step=512, fft_length=2048,
window_fn=tf.signal.hann_window)
# [..., frames, fft_unique_bins]
S = tf.log(tf.abs(S) ** 2) / tf.log(10.)
# S = tf.log(tf.abs(S) ** 2 + 9.677e-9) / tf.log(10.)
return S
def tf_compute_log_distortion(labels, logits):
"""labels和logits都是三維數(shù)組 (batch_size, input_size, 1)"""
S1 = get_power(labels) # [..., frames, fft_unique_bins]
S2 = get_power(logits) # [..., frames, fft_unique_bins]
# 先處理頻率維度,后處理時(shí)間維度
lsd = tf.reduce_mean(tf.sqrt(tf.reduce_mean((S1 - S2) ** 2, axis=2)), axis=1)
lsd = tf.reduce_mean(lsd, axis=0)
return lsd
但如果想要numpy版本的值和tensorflow版本的值一樣,可以使用下面的代碼
# numpy版本一:處理一個(gè)batch,(batch, seq_len, 1)
def numpy_LSD(labels, logits):
""" labels 和 logits 是一維數(shù)據(jù)"""
labels_spectrogram = librosa.stft(labels, n_fft=2048, hop_length=512, win_length=2048,
window="hann", center=False) # (1 + n_fft/2, n_frames)
logits_spectrogram = librosa.stft(logits, n_fft=2048, hop_length=512, win_length=2048,
window="hann", center=False) # (1 + n_fft/2, n_frames)
labels_log = np.log10(np.abs(labels_spectrogram) ** 2 + 1e-8)
logits_log = np.log10(np.abs(logits_spectrogram) ** 2 + 1e-8)
original_target_squared = (labels_log - logits_log) ** 2
lsd = np.mean(np.sqrt(np.mean(original_target_squared, axis=0)))
return lsd
# numpy版本二:處理一個(gè)batch,(batch, seq_len, 1)
def get_power1(x):
S = librosa.stft(x, n_fft=2048, hop_length=512, win_length=2048,
window="hann", center=False) # (1 + n_fft/2, n_frames)
S = np.log10(np.abs(S) ** 2 + 1e-8)
return S
def compute_log_distortion(labels, logits):
avg_lsd = 0
batch_size = labels.shape[0]
for i in range(batch_size):
S1 = get_power1(labels[i].flatten())
S2 = get_power1(logits[i].flatten())
# 先處理頻率軸,后處理時(shí)間軸
lsd = np.mean(np.sqrt(np.mean((S1 - S2) ** 2, axis=0)), axis=0)
avg_lsd += lsd
return avg_lsd / batch_size
# tensorflow版本
def get_power(x):
x = tf.squeeze(x, axis=2) # 去掉位置索引為2維數(shù)為1的維度 (batch_size, input_size)
S = tf.signal.stft(x, frame_length=2048, frame_step=512, fft_length=2048,
window_fn=tf.signal.hann_window)
# [..., frames, fft_unique_bins]
S = tf.log(tf.abs(S) ** 2 + 9.677e-9) / tf.log(10.)
return S
def tf_compute_log_distortion(labels, logits):
# labels和logits都是三維數(shù)組 (batch_size, input_size, 1)
S1 = get_power(labels) # [..., frames, fft_unique_bins]
S2 = get_power(logits) # [..., frames, fft_unique_bins]
# 先處理頻率維度,后處理時(shí)間維度
lsd = tf.reduce_mean(tf.sqrt(tf.reduce_mean((S1 - S2) ** 2, axis=2)), axis=1)
lsd = tf.reduce_mean(lsd, axis=0)
return lsd
批注:librosa.stft中center設(shè)為False,和np.log10中加1e-8,目的是為了最終的值和tensorflow版本的lsd值相近,如果沒有這個(gè)需求可以去除。這里tf.log中加9.677e-9是為了和numpy中的值相近,如果沒有這個(gè)需求可以去除
短時(shí)客觀可懂度(STOI)
下載一個(gè) pystoi 庫:pip install pystoi
STOI 反映人類的聽覺感知系統(tǒng)對(duì)語音可懂度的客觀評(píng)價(jià),STOI 值介于0~1 之間,值越大代表語音可懂度越高,越清晰。
from pystoi import stoi
stoi_score = stoi(label, logits, fs_sig=16000)
加權(quán)譜傾斜測(cè)度(WSS)
WSS值越小說明扭曲越少,越小越好,范圍
![](/d/20211017/d505d10cae43587aed75f5431094940e.gif)
參考
【CSDN文章】PESQ語音質(zhì)量測(cè)試
視頻質(zhì)量度量指標(biāo)
度量方法倉庫
【github代碼,內(nèi)涵多種度量方法】pysepm
【python庫】python-pesq
【python庫】pystoi
speechmetrics
Voice quality metrics
以上就是python實(shí)現(xiàn)語音常用度量方法的詳細(xì)內(nèi)容,更多關(guān)于python語音度量方法的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
您可能感興趣的文章:- python3實(shí)現(xiàn)語音轉(zhuǎn)文字(語音識(shí)別)和文字轉(zhuǎn)語音(語音合成)
- python語音識(shí)別指南終極版(有這一篇足矣)
- 使用Python和百度語音識(shí)別生成視頻字幕的實(shí)現(xiàn)
- python 利用pyttsx3文字轉(zhuǎn)語音過程詳解
- Python將文字轉(zhuǎn)成語音并讀出來的實(shí)例詳解