如何在 Python 中进行实时语音活动检测?

Posted

技术标签:

【中文标题】如何在 Python 中进行实时语音活动检测?【英文标题】:How can I do real-time voice activity detection in Python? 【发布时间】:2020-07-05 00:23:53 【问题描述】:

我正在对录制的音频文件执行语音活动检测,以检测波形中的语音与非语音部分。

分类器的输出看起来像(突出显示的绿色区域表示语音):

我在这里面临的唯一问题是让它适用于音频输入流(例如:来自麦克风)并在规定的时间范围内进行实时分析。

我知道PyAudio 可用于动态录制来自麦克风的语音,并且有几个波形、频谱、频谱图等的实时可视化示例,但找不到与在一种近乎实时的方式。

【问题讨论】:

pyaudio 的最新版本现在已经 3 岁了 【参考方案1】:

您应该尝试使用 Python 绑定到 webRTC VAD from Google。基于 GMM 建模,它轻量、快速并提供非常合理的结果。由于每帧都提供决策,因此延迟最小。

# Run the VAD on 10 ms of silence. The result should be False.
import webrtcvad
vad = webrtcvad.Vad(2)

sample_rate = 16000
frame_duration = 10  # ms
frame = b'\x00\x00' * int(sample_rate * frame_duration / 1000)
print('Contains speech: %s' % (vad.is_speech(frame, sample_rate))

另外,this 文章可能对您有用。

【讨论】:

不错的发现!我完全忽略了 WebRTC 模块。虽然,我有一个使用 Auditok 的可行解决方案,但我会接受你的解决方案,因为它接近我正在寻找的。​​span> 感谢Auditok。不知道它的存在 感谢您链接到the Google paper。它现在在深度学习方面已经非常老了,但它已经基于 RNN 并且很容易掌握可用的技术,知道这被称为“语音活动检测”(缩写为 VAD)和/或从那篇论文跟进到更新也许是。 My first attempt 在 py-webrtcvad 路由,使用 sounddevice 作为音频输入源。另见***.com/questions/51463146/…【参考方案2】:

我发现LibROSA 可能是解决您问题的方法之一。 Medium有一个使用麦克风流实现实时预测的简单教程。

让我们使用短时傅里叶变换(STFT)作为特征提取器,作者解释:

为了计算 STFT,使用快速傅里叶变换窗口大小(n_fft) 为 512. 根据方程 n_stft = n_fft/2 + 1, 257 频率 bins(n_stft) 是在 512 的窗口大小上计算的。窗口是 移动了 256 的跃点长度以更好地重叠 计算 STFT 的窗口。

stft = np.abs(librosa.stft(trimmed, n_fft=512, hop_length=256, win_length=512))

# Plot audio with zoomed in y axis
def plotAudio(output):
    fig, ax = plt.subplots(nrows=1,ncols=1, figsize=(20,10))
    plt.plot(output, color='blue')
    ax.set_xlim((0, len(output)))
    ax.margins(2, -0.1)
    plt.show()

# Plot audio
def plotAudio2(output):
    fig, ax = plt.subplots(nrows=1,ncols=1, figsize=(20,4))
    plt.plot(output, color='blue')
    ax.set_xlim((0, len(output)))
    plt.show()

def minMaxNormalize(arr):
    mn = np.min(arr)
    mx = np.max(arr)
    return (arr-mn)/(mx-mn)

def predictSound(X):
    clip, index = librosa.effects.trim(X, top_db=20, frame_length=512, hop_length=64) # Empherically select top_db for every sample
    stfts = np.abs(librosa.stft(clip, n_fft=512, hop_length=256, win_length=512))
    stfts = np.mean(stfts,axis=1)
    stfts = minMaxNormalize(stfts)
    result = model.predict(np.array([stfts]))
    predictions = [np.argmax(y) for y in result]
    print(lb.inverse_transform([predictions[0]])[0])
    plotAudio2(clip)

CHUNKSIZE = 22050 # fixed chunk size
RATE = 22050

p = pyaudio.PyAudio()
stream = p.open(format=pyaudio.paFloat32, channels=1, 
rate=RATE, input=True, frames_per_buffer=CHUNKSIZE)

#preprocessing the noise around
#noise window
data = stream.read(10000)
noise_sample = np.frombuffer(data, dtype=np.float32)
print("Noise Sample")
plotAudio2(noise_sample)
loud_threshold = np.mean(np.abs(noise_sample)) * 10
print("Loud threshold", loud_threshold)
audio_buffer = []
near = 0

while(True):
    # Read chunk and load it into numpy array.
    data = stream.read(CHUNKSIZE)
    current_window = np.frombuffer(data, dtype=np.float32)
    
    #Reduce noise real-time
    current_window = nr.reduce_noise(audio_clip=current_window, noise_clip=noise_sample, verbose=False)
    
    if(audio_buffer==[]):
        audio_buffer = current_window
    else:
        if(np.mean(np.abs(current_window))<loud_threshold):
            print("Inside silence reign")
            if(near<10):
                audio_buffer = np.concatenate((audio_buffer,current_window))
                near += 1
            else:
                predictSound(np.array(audio_buffer))
                audio_buffer = []
                near
        else:
            print("Inside loud reign")
            near = 0
            audio_buffer = np.concatenate((audio_buffer,current_window))

# close stream
stream.stop_stream()
stream.close()
p.terminate()

代码来源:Chathuranga Siriwardhana

完整代码可以在here找到。

【讨论】:

【参考方案3】:

我认为这里有两种方法,

    阈值方法 小型、可部署的神经网络。方法

第一个速度很快,可行并且可以实施和测试非常快。而第二个实施起来有点困难。我想你已经对第二个选项有点熟悉了。

在第二种方法的情况下,您将需要一个语音数据集,这些语音数据集以 二元分类 序列(如00000000111111110000000011110000)进行标记。神经网络应该很小并针对在移动设备等边缘设备上运行进行优化。

您可以在 TensorFlow 中查看 this

This 是一个语音活动检测器。我认为这是为了你的目的。

另外,看看这些。

https://github.com/eesungkim/Voice_Activity_Detector

https://github.com/pyannote/pyannote-audio

当然,您应该比较上述工具包和模型的性能和移动设备实施可行性

【讨论】:

【参考方案4】:

音频的比特率通常很低,所以我认为完全用numpypython 编写代码没有任何问题。如果您需要低级数组访问,请考虑numba。还配置您的代码,例如与line_profiler。另请注意,scipy.signal 用于更高级的信号处理。

音频处理通常在样本中进行。因此,您为流程定义样本大小,然后运行一个方法来确定该样本是否包含语音。

import numpy as np

def main_loop():
    stream = <create stream with your audio library>
    while True:
        sample = stream.readframes(<define number of samples / time to read>)
        print(is_speech(sample))

def is_speech(sample):
    audio = np.array(sample)

    < do you processing >

    # e.g. simple loudness test
    return np.any(audio > 0.8):

这应该会让你走得很远。

【讨论】:

我特别喜欢这个答案的 位;-)

以上是关于如何在 Python 中进行实时语音活动检测?的主要内容,如果未能解决你的问题,请参考以下文章

谁有语音端点检测算法程序?如何在matlab中运行?

python进阶——AI视觉实现口罩检测实时语音报警系统

python进阶——AI视觉实现口罩检测实时语音报警系统

VAD的简介

依图在实时音视频中语音处理的挑战丨RTC Dev Meetup

如何检测用户在 iOS 中使用了语音输入?