近日谷歌的论文SV2TTS(https://arxiv.org/pdf/1806.04558.pdf)在不论是在学术界还是在开源社区都引发热议,SV2TTS号称可以使用低分辨率的原音信息,在短时间内完成转换,生成新的声音。而且最近依据这个算法已经登陆到了github的趋势榜首位置(https://github.com/CorentinJ/Real-Time-Voice-Cloning)。
我们把原语音定义为v1,原语音内容定义为c1,原语音的speaker定义为s1,目标语音定义为v2,目标内容定义为c2。以便下文解释。
SV2TTS定义了三层模型:
模型1:针对s1的声音特征的encoder网络,利用数千个人声样本,只从对于S1语音语调的嵌入工作,生成嵌入向量。至于什么是嵌入之前介绍很多了,具体可参考(https://blog.csdn.net/BEYONDMA/article/details/90114016)这里不加赘述了。
模型2:基于Tacotron 2的合成网络,我们知道Tacotron 2是基于注意力的模型,依据c2与s1的相关特征,生成梅尔(mel)谱图;
模型3:基于自回归波的语音生成网络,将mel谱图数据转换为时域的声音样本
下图是模型图:
其具体的工作原理如下:
1.利用模型1将s1和phoneme sequence(单词发音序列,如我、你等单个字的发音)的合成器进行结合。
2.利用模型2对于模型1的输出结果进行解码。生成梅尔频谱数据。
3.利用模型3将梅尔频谱转化为波型文件。
SV2TTS其实刚刚发布不久,github就已经有程序员大神贴出了实现网址在:https://github.com/CorentinJ/Real-Time-Voice-Cloning,而我初步读了一下,代码质量颇高,值得大家一读。
这里要详细讲一下的是这个文件,属于编码器部分(与模型1对应)的audio部分:https://github.com/CorentinJ/Real-Time-Voice-Cloning/blob/master/encoder/audio.py
import webrtcvad
import librosa
其中用到了两个重要的库webrtcvad和librosa,其中webrtcvad是语音检测的重要库之一,具体在这个项目中是在这里用到的代码及注释如下,他用到的检测模式是3也就是最激进的模式 webrtcvad.Vad(mode=3),然后使用vad.is_speech检测是否为人声。
def trim_long_silences(wav):
"""
Ensures that segments without voice in the waveform remain no longer than a
threshold determined by the VAD parameters in params.py.
:param wav: the raw waveform as a numpy array of floats
:return: the same waveform with silences trimmed away (length <= original wav length)
"""
# Compute the voice detection window size
samples_per_window = (vad_window_length * sampling_rate) // 1000
# Trim the end of the audio to have a multiple of the window size
wav = wav[:len(wav) - (len(wav) % samples_per_window)]
# Convert the float waveform to 16-bit mono PCM
pcm_wave = struct.pack("%dh" % len(wav), *(np.round(wav * int16_max)).astype(np.int16))
# Perform voice activation detection
voice_flags = []
vad = webrtcvad.Vad(mode=3)#将检测模式设为3,也就是最激进的模式
for window_start in range(0, len(wav), samples_per_window):
window_end = window_start + samples_per_window
voice_flags.append(vad.is_speech(pcm_wave[window_start * 2:window_end * 2],
sample_rate=sampling_rate))#检测是否为人声
voice_flags = np.array(voice_flags)
# Smooth the voice detection with a moving average
def moving_average(array, width):
array_padded = np.concatenate((np.zeros((width - 1) // 2), array, np.zeros(width // 2)))
ret = np.cumsum(array_padded, dtype=float)
ret[width:] = ret[width:] - ret[:-width]
return ret[width - 1:] / width
audio_mask = moving_average(voice_flags, vad_moving_average_width)
audio_mask = np.round(audio_mask).astype(np.bool)
# Dilate the voiced regions
audio_mask = binary_dilation(audio_mask, np.ones(vad_max_silence_length + 1))
audio_mask = np.repeat(audio_mask, samples_per_window)
return wav[audio_mask == True]
然后是librosa库,这个是语音识别中最重要的库没有之一。下面重点介绍一下这个库,他的安装十分简单:
pip install librosa
安装完成后,就可以直接import使用了,计算梅尔频谱的代码如下:
import librosa
import librosa.display
import matplotlib.pyplot as plt
y, sr = librosa.load('e:/tts/Explanation.wav', sr=None)
melspec = librosa.feature.melspectrogram(y, sr, n_fft=1024, hop_length=512, n_mels=128)#计算梅尔频谱
logmelspec = librosa.power_to_db(melspec)#计算log-mel
plt.figure()
librosa.display.specshow(logmelspec, sr=sr, x_axis='time', y_axis='mel')
plt.title('Beat wavform')
plt.show()
运行效果如下:
我们知道梅尔(mel)频谱本质是模板人耳的滤波器所以在TTS当中使用非常广泛。
在这个项目中也是同样,直接调用了librosa.feature.melspectrogram方法来计算梅尔频谱:
def wav_to_mel_spectrogram(wav):
"""
Derives a mel spectrogram ready to be used by the encoder from a preprocessed audio waveform.
Note: this not a log-mel spectrogram.
"""
frames = librosa.feature.melspectrogram(
wav,
sampling_rate,
n_fft=int(sampling_rate * mel_window_length / 1000),
hop_length=int(sampling_rate * mel_window_step / 1000),
n_mels=mel_n_channels
)
return frames.astype(np.float32).T
当然其它部分比如https://github.com/CorentinJ/Real-Time-Voice-Cloning/blob/master/synthesizer/models/tacotron.py也有tacotron模型的完整实现,非常推荐大家读一下