今天也是热到灵魂出窍的一天Orz,封面和头图来自狼狗~
音素对齐在语音识别,语音合成等领域都可能会用的到,当你不想自己训练个模型来处理对齐任务时,最好的办法是找个工具。
用了一圈下来,发现Montreal-Forced-Aligner(MFA)比较好用,不仅支持汉语(普通话)还支持英语和一堆其他的语言(还可以自己训练声学模型),所以接下来主要写的是MFA的用法。另外还有一个专门处理汉语音素对齐的工具speech-aligner,地址在这里https://github.com/open-speech/speech-aligner 另外专栏为什么不支持插入站外链接,除了不支持代码高亮以外又多了个槽点= =
第一件事是把MFA下载下来https://montreal-forced-aligner.readthedocs.io/en/latest/installation.html
Mac,Linux,Windows都可以用,下载后记得解压缩。
首先在与训练模型找到普通话(Mandarin),链接在这里https://montreal-forced-aligner.readthedocs.io/en/latest/pretrained_models.html
然后找一个字典(可以自己训练,参考这里https://montreal-forced-aligner.readthedocs.io/en/latest/example.html?highlight=mandarin#example-2-generate-mandarin-dictionary),没在文档里面找到现成的,不过逛Github的时候在一个停止维护的项目MTTS里面找到了一份字典https://github.com/Jackiexiao/MTTS/blob/master/misc/mandarin-for-montreal-forced-aligner-pre-trained-model.lexicon
然后处理数据,一个wav文件(采样频率在16k以上,不是的话用sox或其他的转换一下)对应一个lab文件,lab里的内容是wav的拼音
接下来就是对齐啦,大概是这样
bin/mfa_align biaobei mandarin-for-montreal-forced-aligner-pre-trained-model.lexicon mandarin.zip result
biaobei指的是数据所在文件夹路径,因为用的是标贝的数据所以用了这个名字,对齐的时候读者小伙伴们记得自己改路径,不要复制粘贴一气呵成~
mandarin-for-montreal-forced-aligner-pre-trained-model.lexicon 是之前下载的字典文件。
mandarin.zip 是之前下载的普通话声学模型,记得不要解压。
result是输出路径。
正常工作的话大概会是这样:
没有正常工作的话,会输出错误信息。
输出内容是这样的:
oov指的是字典里没有的拼音,对齐文件在biaobei文件夹里。
长这样:
item1是拼音的持续时间
item2是音素的持续时间
然后自己写一个脚本读取就好啦w
3. 常用的语音文本对齐工具
本文重点介绍montreal forced aligner(其他的没有跑通过),它是基于kaldi的工具集开发的。
3.1. 下载及安装
我用的windows版本:
常规可以在http://montreal-forced-aligner.readthedocs.io官网按照步骤安装,但是一直没装成功,而且官网上安装说明了window不支持G2P等
3.2. 语音对齐
解压上面montreal-forced-aligner_win64.zip,进入其bin目录,可以看到对齐的脚本mfa_align.exe,直接执行如下命令即可输出对齐文本:
mfa_align corpus_directory dictionary_path acoustic_model_path output_directory
命令包含有4个参数:
- corpus_directory:待对齐的语音文件目录,我用的清华语音库data_thchs30,但缺少了montreal需要的.lab文件。所以将语音库中.wav.trn中第2行(拼音)单独另存为.lab即可
- dictionary_path:小的字典文件,即corpus_directory所用到的语音和音素的对应关系字典。
用工具中的mfa_generate_dictionary.exe命令,但发现报错。
只能写python脚本生成了小字典,同时也发现清华语音库数据有dirty,有些拼音是错的,无法生成字典。比如兄xiong5,手动将lab文件将xiong5改为xiong4。
楼主生成的如下,这样mfa_align的参数dictionary_path='./tinydictionary.txt'即可:
注:xiong5包含x io5 ng3个音素,解压下面acoustic_model_path中的mandarin.zip,可以看到没有对应的音素io5这个因素,所以不改lab会该工具报错
- acoustic_model_path:语音模型,直接官网下载中文的,记得不要解压(官网也有英文下载)
github.com/MontrealCorpusTools/mfa-models/raw/main/acoustic/mandarin.zip
- output_directory:语音对齐后输出目录,自定义指定(如d:download/tmp/textGrid)
如下图,输出的文件为.TextGrid格式,python可以安装TextGrid解析
例如:A2_1.wav中”ta1”从xmin=0.770秒开始,xmax=0.970秒结束,这样就实现了语音和文本对齐。
附录:
代码片段1:生成lab文件,mfa_align参数corpus_directory下的lab文件生成代码
def trn2lab(trnPath):
"""
trnPath:trn文件所在目录,将.trn文件第2行拼音存为.lab文件
"""
pattern = re.compile('(.*)\.wav\.trn$')
for root, dirs, files in os.walk(trnPath):
for readfile in files:
if not pattern.match(readfile): continue
with open(trnPath+'\\'+readfile.split('.')[0]+'.lab','w') as wf:
line2=''
with open(trnPath+'\\'+readfile,mode='r',encoding='UTF-8') as rf:
next(rf)
line2 = rf.readline() ##读取第2行
rf.close()
wf.writelines(line2)
代码片段2:生成小字典
#全量字典:拼音->音素
dictionary = r'D:\download\tmp\dictionary.txt'
def getDictionary(dictionary = dictionary):
"""
:param dictionary: 字典文件,每一行包含一个拼音及对应的音素,例如 "bao1 b ao1\nbeng1 b e1 ng\n"
:return: 字典:key是拼音,value是拼音及对应的音素,例如 key=bao1,value='bao1 b ao1\n'
"""
word2phone = {}
with open(dictionary, 'r') as f:
line = f.readline()
while line:
key,value = line.split(' ',1)
word2phone[key] = line
line = f.readline()
return word2phone
#生成对齐的小字典
def getTinyDictionaryByFile(corpusPath=r'.\data_thchs30\data',outputFile = 'tinyDictionary.txt'):
"""
inputFilePath:.lab文件。音频文件及对应的拼音文件所在目录,拼音文件一个汉字一个拼音,拼音间空格分隔如“bian4 hua1”。
outputFile: 当前音频文件对应的所有文字的拼音形成的小字典,如“bao1 b ao1\n”
"""
dictionary = getDictionary()
pattern = re.compile(r'(.*)\.lab$') #只从lab文件找所有的拼音
tinyDict = {}
notExistsWord = ''
for root, dirPath, files in os.walk(corpusPath):
for readfile in files: ##遍历inputFilePath目录下的所有文件
if pattern.match(readfile) is not None: #找出.lab文件
with open(root+"\\"+readfile,'r') as rf: #读取出.lab文件中的所有拼音
line = rf.readline()
while line:
wordList = line.split() #读取拼音
for word in wordList:
if word in dictionary.keys():
tinyDict[word] = dictionary[word]
else:notExistsWord += word + ' ' + root+"\\"+readfile+'\n';
line = rf.readline()
with open(outputFile, 'w') as wf:##结果写入outputFile
for key in tinyDict:
wf.write(tinyDict[key])
if notExistsWord !='': print(notExistsWord)
MFA使用了Kaldi的工具集,包括音频特征参数提取,模型构建,训练方法等。据我观测,MFA应该是使用了Kaldi比较早的nnet模型,模型比较小,训练起来非常快。MFA本身已经提供了一些预先训练好的声学模型包括english和mandarin模型,可以直接下载后使用。English的acoustic模型是基于librispeech训练的,用起来已经比较顺手了,比较准确。但是mandarin的声学模型好像数据量不够大,导致对齐效果差。所以就尝试使用自己的数据重新训练一个声学模型,结果还是不错的,见首图。以下为具体步骤(Kaldi和MFA的安装都略去了,大家可以自行按官方的方法进行安装):
首先准备好音频数据和对应的文字,如果文字是中文需要转化为拼音,我使用了pypinyin进行转化,每个中文汉字对应一个拼音,脚本如下,将中文字转为拼音:
# coding:utf8
import os
import sys
import numpy as np
from pypinyin import pinyin, lazy_pinyin, Style
import re
root_dir = "../train/"
pattern = re.compile(r'(.*)\.txt$')
for root, dir, files in os.walk(root_dir):
for filename in files:
#print(filename)
output = pattern.match(filename)
if output is not None:
print(root, filename)
text_file = open(root+"/"+filename)
line = text_file.read().strip()
line = line.replace(",", "")
pinyin = lazy_pinyin(line, style=Style.TONE3, neutral_tone_with_five=True)
pinyinline = ' '.join(pinyin)
print(line)
target_text_file = open(root+"/"+output.group(1)+".lab", "w")
target_text_file.write(pinyinline)
target_text_file.close()
保证音频文件的名字和脚本的文件名仅仅后缀不同,例如:
T0055G0002S0001.wav 和 T0055G0002S0001.lab
其中lab文件内容:yi3 hou4 ni3 shi4 nan2 hai2 zi5 原来的中文为:“以后你是男孩子”
准备好数据之后,使用MFA代的G2P模型生成词典文件:
mfa g2p mandarin_pinyin_g2p ./corpus/tiny/ dict_tiny.txt
其中tiny目录如下:
$ ls tiny
G0002 G0135 G0269 G0326 G0726 G0931 G1492 G1634 G1777 G1889 G1966
$ ls G0002
T0055G0002S0001.lab T0055G0002S0081.lab T0055G0002S0001.wav T0055G0002S0081.wav
$ cat T0055G0002S0001.lab
yi3 hou4 ni3 shi4 nan2 hai2 zi5
dict大概这个样子:
<eps> 0
!sil 1
<unk> 2
an1quan2 3
ba1shi2nian2dai4 4
bao1luo1wan4xiang4 5
有了词典,就可以开始训练自己的模型了:
mfa train --config_path /home/yons/data/mfaligner/Montreal-Forced-Aligner/montreal_forced_aligner/config/basic_train.yaml /media/yons/SSD1T4K/kaldi/kaldi_data/corpus/tiny/ dict_tiny.txt result_tiny
其中config文件中去掉了 lda和sat部分(mfa 2.0版本使用ac model时的一个bug)
这个运行完成后,默认会在路径:
/home/yons/Documents/MFA/tiny/tri_ali
$ ls tri_ali
acoustic_model.zip ali.1 ali.2.scores aligned.2 log nbest.2 phone_ctm.2 word_ctm.0
ali.0 ali.1.scores aligned.0 final.mdl nbest.0 phone_ctm.0 textgrids word_ctm.1
ali.0.scores ali.2 aligned.1 final.occs nbest.1 phone_ctm.1 tree word_ctm.2
下生成一个acoustic_model.zip 的模型文件,就是我们自己的模型了。
使用下面的命令进行对齐我们的音频:
mfa align --config_path /home/yons/data/mfaligner/Montreal-Forced-Aligner/montreal_forced_aligner/config/basic_align.yaml my_example2/ dict_tiny.txt /home/yons/Documents/MFA/tiny/tri_ali/acoustic_model.zip my_result3
一般的错误时beam narrow,意思是搜索的宽度不够没有找到最匹配的点,默认的设置一般不会出现beam narrow,出现了也不用紧张,可以通过调整config文件进行调整,就可以得到textgrid文件了,通过图形化的方式验证对齐是否是正确的。
接下来使用工具Praat进行 textgrid和 wav文件的对比分析,看看是不是准确对齐了。
拔刀相助 对应拼音和音素