话说真的好久没有更新文章了,这段时间,自己在技术上也发生很大的转变,从原来做直播中台Android相关,后来中台的解散,转到公司的RTC部门做音视频开发,随着元宇宙的热门,又转战Unity数字人相关开发,现在又做AI照片人相关工作,真的好曲折,不过没有办法,现在大环境不好,只能拥抱变化了,下面是最近做的一个音频音素对齐的项目,在使用MFA3.0.0遇到的一些问题总结
项目地址
主页:montreal-forced-aligner.readthedocs.io/en/latest/i...
github: github.com/MontrealCor...
环境搭建:
安装项目主页的安装流程,这个过程没有遇到什么问题
生成字典
这里以中文拼音举例,montreal-forced-aligner.readthedocs.io/en/latest/f... model download g2p mandarin_pinyin_g2p,是下载不下来,据说是github的限制,不过这个模型可以在github.com/MontrealCor...
例如774.lab这个文件的一些拼音没有用空格分割开,这里只能手动fix一下
运行命令生成字典
按照官网的命令
bash
mfa g2p mandarin_pinyin_g2p /path/to/mandarin/dataset /path/to/save/mandarin_dict.txt
mandarin_pinyin_g2p:刚才下载的模型
/path/to/mandarin/dataset:下载的测试数据集
/path/to/save/mandarin_dict.txt:生成字典文件位置
直接编码错误,难道模型或者数据集有不是UTF-8编码的文件,但是对比一下都是UTF-8,没有办法,参考网上怎么解决这种错误,然后改造MFA代码,使用codecs读取
直接再运行,这里不报错了,但是又报下面的错误
找不到model.fst,但是注意到怎么是在我数据集的目录下找这个呢,不是模型目录下?于是跟踪一下MFA这个命令的模型,在接收模型路径的地方输出一下日志
结果
数据集和模型路径刚好相反了,查看官网montreal-forced-aligner.readthedocs.io/en/latest/u... mfa g2p的命令
css
mfa g2p [OPTIONS] INPUT_PATH G2P_MODEL_PATH OUTPUT_PATH
模型和数据集输入顺序刚好相反
调换位置重新执行
bash
mfa g2p /data2/dengqu/mfa/mandarin_example /data2/dengqu/mfa/mandarin_pinyin_g2p.zip /data2/dengqu/mfa/dict/dict.txt
这样就成功了,查看生成的字典也是对的
生成声学模型
按照官网给出的命令
lua
mfa train /path/to/mandarin/dataset /path/to/save/mandarin_dict.txt /path/to/save/output
/
报上面错误,找了一些资料,加上--clean试试
开始训练模型了
成功生成模型
使用生成的声学模型进行对齐
css
mfa align [OPTIONS] CORPUS_DIRECTORY DICTIONARY_PATH ACOUSTIC_MODEL_PATH
OUTPUT_DIRECTORY
CORPUS_DIRECTORY:需要对齐的数据集
DICTIONARY_PATH:字典路径,这里上面生成的字典
ACOUSTIC_MODEL_PATH:声学模型路径,这里填写上面生成的声学模型
OUTPUT_DIRECTORY:对齐结果存储目录
OPTIONS:这个可以参考montreal-forced-aligner.readthedocs.io/en/latest/u...
bash
mfa align /data2/dengqu/mfa/mandarin_example /data2/dengqu/mfa/dict/dict.txt /data2/dengqu/mfa/dict/test_model.zip /data2/dengqu/mfa/dict --clean
成功生成对齐结果
Praat结果查看
具体Praat的使用教程可以自行google
打开wav和textGrid文件,然后选中两个,点击view&Edit
发现不太准,不过毕竟训练的数据量太少了,官网也是这样解析
使用MFA1.0.0现有训练的模型和字典
要使模型精准,需要大量的训练集进行训练,目前这里有份网上训练好的,军富他们也在用,不过MFA的版本是1.0.0的,MFA1.0.0版本下载
训练好的拼音的声学模型:
暂时无法在飞书文档外展示此内容
对应的拼音词典:
暂时无法在飞书文档外展示此内容
解压下载好MFA1.0.0压缩包
其中bin文件夹下就是mfa 执行命名的exe,使用上面的声学模型和词典对齐数据集,window上打开cmd
r
F:\download\montreal-forced-aligner\bin\mfa_align.exe F:\download\montreal-forced-aligner\mandarin_example F:\download\montreal-forced-aligner\pinyin-lexicon-r.txt F:\download\montreal-forced-aligner\aishell_alignment_model.zip F:\download\montreal-forced-aligner\output
进行对齐
数据集
上面进行训练的数据集很少,只有6个,所以训练出来的效果很差,不过有开源的数据集可以自行下载进行训练
THCHS-30 不过下载的数据需要自行提取一下lab内容,原来内容如下:
我们只需要提取第二行拼音,然后保存为.lab文件就行,可以参考如下脚本
py
import os
dir = "/Users/spring/Downloads/data_thchs30/data"
filter=[".trn"] #设置过滤后的文件类型 当然可以设置多个类型
def all_path(dirname):
result = []#所有的文件
for maindir, subdir, file_name_list in os.walk(dirname):
# print("1:",maindir) #当前主目录
# print("2:",subdir) #当前主目录下的所有目录
# print("3:",file_name_list) #当前主目录下的所有文件
for filename in file_name_list:
apath = os.path.join(maindir, filename)#合并成一个完整路径
ext = os.path.splitext(apath)[1] # 获取文件后缀 [0]获取的是除了文件名以外的内容
if ext in filter:
result.append(apath)
return result
all_paths = all_path(dir)
parent_dir = os.path.dirname(dir)
train_data_dir = os.path.join(parent_dir, 'mfaTrainData')
isExists=os.path.exists(train_data_dir) #判断路径是否存在,存在则返回true
if not isExists:
#如果不存在则创建目录
#创建目录操作函数
os.makedirs(train_data_dir)
print('创建成功:' + train_data_dir)
count = all_paths.count
print('data count:' + str(count))
index = 0
for path in all_paths:
#if index == 1:
# break
index = index + 1
index = path.rindex('.')
wav_path = path[0:index]
a = os.path.basename(wav_path)#带后缀的文件名
b = os.path.basename(wav_path).split('.')[0]#不含后缀带路径的文件名
lab_path = os.path.join(train_data_dir, (b + '.lab'))
print('lab_path:' + lab_path)
if os.path.exists(lab_path):
os.remove(lab_path)
copy_wav_file = os.path.join(train_data_dir, a)
print('copy_wav_file:' + copy_wav_file)
if os.path.exists(copy_wav_file):
os.remove(copy_wav_file)
os.popen('cp ' + wav_path + ' ' + copy_wav_file)
#print('cp ' + wav_path + ' to ' + copy_wav_file)
with open(path,'r') as f:
lines=f.readlines()
start = 1
end = len(lines)
with open(lab_path,'w') as t:
t.write(lines[1])
#print(lines[1])
#print('一行数据')
训练好的词典和模型:
貌似上传不了,需要的可以私信我
AISHELL-3数据集是比THCHS-30大很多的数据集,当然其生成的词典和模型就更加完善,同样需要自行提取lab内容
参考脚本
py
import os
import FileUtils
contentPath = "/Users/spring/fsdownload/AISHELL-3/train/content.txt"
wavDir = os.path.join(os.path.dirname(contentPath), 'wav')
print('wavDir:' + wavDir)
dataDir = os.path.join(os.path.dirname(contentPath), 'data')
isExists=os.path.exists(dataDir) #判断路径是否存在,存在则返回true
if not isExists:
#如果不存在则创建目录
#创建目录操作函数
os.makedirs(dataDir)
print('创建成功:' + dataDir)
wavFiles = FileUtils.filterFiles(wavDir, filter=[".wav"])
wavDict = {}
for wavFile in wavFiles:
key = os.path.basename(wavFile)
wavDict[key] = wavFile
print('wavFiles count:' + str(len(wavDict)))
with open(contentPath,'r') as f:
lines=f.readlines()
for line in lines:
wavName = line.split(' ')[0]
wavFile = wavDict[wavName]
a = os.path.basename(wavFile)#带后缀的文件名
copy_wav_file = os.path.join(dataDir, a)
# print('copy_wav_file:' + copy_wav_file)
if os.path.exists(copy_wav_file):
os.remove(copy_wav_file)
os.popen('cp ' + wavFile + ' ' + copy_wav_file)
#print('cp ' + wavFile + ' to ' + copy_wav_file)
b = os.path.basename(wavFile).split('.')[0]#不含后缀带路径的文件名
labPath = os.path.join(dataDir, b + '.lab')
texts = line.split(' ')[1].split(' ')[1::2]
lineText = ' '.join(texts)
#print('wavFile:' + wavFile + ' line:' + lineText)
with open(labPath,'w') as t:
t.write(lineText)
训练好的词典和模型:
貌似上传不了,需要的可以私信我