语音识别技能总结
总结常见问题
import warnings warnings.filterwarnings('ignore')
基础知识
Attention-注意力机制
原则:当人们说话或读单词时,他们根据一个关键字或多个关键字来判断一些句子或说话内容的含义。也就是说,通过增加上下文内容的不同权重,我们可以更加关注本地内容。
语音识别工具常用
安装相关包 pip install pygame SpeechRecognition playsound librosa
读取音频数据
speech_recognition
import speech_recognition as sr print(sr.__version__) r = sr.Recognizer() harvard = sr.AudioFile('audio_files\harvard.wav') with harvard as source: audio = r.record(source) # 调用api识别 text = r.recognize_google(audio)
librosa
详细教程:https://minux.blog.csdn.net/article/details/108684589?spm=1001.2101.3001.6650.5&utm_medium=distribute.pc_relevant.none-task-blog-2~default~BlogCommendFromBaidu~Rate-5.pc_relevant_default&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2~default~BlogCommendFromBaidu~Rate-5.pc_relevant_default&utm_relevant_index=10
''' >> LibROSA - 是用於 音乐和音频 分析的 python 软件包 >> LibROSA - is a python package for music and audio analysis >> pip install librosa >> https://librosa.github.io/librosa/ >> librosa.feature.mfcc >> https://librosa.github.io/librosa/generated/librosa.feature.mfcc.html '''
librosa不易使用,不支持mp3格式音频读取
import IPython.display as ipd import librosa # 返回数组数据和采样率 # 回来的是一个numpy的数组 采样率 y1, sr1 = librosa.load('audio_files\eng.mp3') # 报错 # 播放语音 ipd.Audio(y1, rate=sr1)
播放音频
Playsound
''' >> Playsound - 播放音频的工具包 playsound >> playsound - contains only one thing - the function (also named) playsound >> pip install playsound >> https://github.com/TaylorSMarks/playsound >> 播放音频 - Playing Audio >> IPython.display.Audio-播放音频 >> IPython.display.Audio-play the audio >> 支持 mp3 或 WMA 格式 >> support mp3 or a WMA format '''
最好用这个播放音频
import playsound from playsound import playsound playsound('audio_files\eng.mp3')
'''
>> gtts
>> pip install gTTS==1.1.8
>> Create an mp3 file from spoken text via the Google TTS (Text-to-Speech) API
>> https://pypi.org/project/gTTS/
>> pygame
>> pip install pygame
>> Pygame is a Python wrapper module for the SDL multimedia library.
>> It contains python functions and classes
>> that will allow you to use SDL’s support for playing cdroms, audio and video output
>> and keyboard, mouse and joystick input.
>> https://pypi.org/project/pygame/
'''
pygame
from pygame import mixer
mixer.init()
mixer.music.load('Audio課程3\hello1.mp3')
mixer.music.play()
TTS
text to speach
pip install gtts
可视化音频
显示波形图
''' >> 可視化音頻 - Visualizing Audio File >> 波形 - Waveform >> librosa.display.waveplot - 繪製音頻數組 - plot the audio array >> 波形的幅度 >> Amplitude of a Waveform '''
# %matplotlib inline
import sklearn
import matplotlib.pyplot as plt
import librosa.display
plt.figure(figsize=(14, 5))
librosa.display.waveshow(x, sr=sr) # librosa=0.6.0
显示频谱图
''' >> 频谱图 - Spectrogram >> librosa.display.specshow - Display Spectrogram - 显示频谱图 '''
# 短时傅里叶变换
X = librosa.stft(x)
Xdb = librosa.amplitude_to_db(abs(X))
plt.figure(figsize=(14, 5))
librosa.display.specshow(Xdb, sr=sr, x_axis='time', y_axis='hz')
plt.colorbar()
显示对数频谱图
- 可以使低频率的数据显示的更清楚
''' >> 對數頻率軸 - Log Frequency axis '''
librosa.display.specshow(Xdb, sr=sr, x_axis='time', y_axis='log')
plt.colorbar()
CMVN
# 特征缩放
# 每个新书的均值
# 单位方差为0
mfccs = sklearn.preprocessing.scale(mfccs, axis=1)
print(mfccs.mean(axis=1))
print(mfccs.var(axis=1))
librosa.display.specshow(mfccs, sr=sr, x_axis='time')
色度频率
''' >> 色度频率 - Chroma Frequencies '''
# Loadign the file
x, sr = librosa.load('Audio/simple_loop.wav')
ipd.Audio(x, rate=sr)
hop_length = 512
chromagram = librosa.feature.chroma_stft(x, sr=sr, hop_length=hop_length)
plt.figure(figsize=(15, 5))
librosa.display.specshow(chromagram, x_axis='time', y_axis='chroma', hop_length=hop_length, cmap='coolwarm')
绘制频谱
可视化-计算时间 变量
''' >> 光谱质心 - Spectral Centroid >> librosa.feature.spectral_centroid '''
spectral_centroids = librosa.feature.spectral_centroid(x, sr=sr)[0]
spectral_centroids.shape
frames = range(len(spectral_centroids))
t = librosa.frames_to_time(frames)
def normalize(x, axis=0):
return sklearn.preprocessing.minmax_scale(x, axis=axis)
质心-波形
谱质心(Spectral Centroid)是描述音色属性的重要物理参数之一,是频率成分的重心,是在一定频率范围内通过能量加权平均的频率,其单位是Hz。它是声音信号的频率分布和能量分布的重要信息。在主观感知领域,谱质心描述了声音的明亮度,具有阴暗、低沉品质的声音倾向有较多低频内容,谱质心相对较低,具有明亮、欢快品质的多数集中在高频,谱质心相对较高。该参数常用于对乐器声色的分析研究。
# 质心 - 波形 - Plotting the Spectral Centroid - waveform
librosa.display.waveplot(x, sr=sr, alpha=0.4)
plt.plot(t, normalize(spectral_centroids), color='r')
频谱滚降
# 滚降
spectral_rolloff = librosa.feature.spectral_rolloff(x+0.01, sr=sr)[0]
# 绘制频谱 波形
librosa.display.waveplot(x, sr=sr, alpha=0.4)
plt.plot(t, normalize(spectral_rolloff), color='r')
plt.grid()
提取音频特征
''' >> 梅尔频率倒谱系数 >> MFCC - Mel Frequency Cepstral Coefficents '''
x, fs = librosa.load('Audio/simple_loop.wav')
librosa.display.waveplot(x, sr=sr)
mfccs = librosa.feature.mfcc(x, sr=sr)
print(mfccs.shape)
librosa.display.specshow(mfccs, sr=sr, x_axis='time')
放大波形图
# 加载音频
x, sr = librosa.load('Audio/T08-violin.wav')
# 播放音频
ipd.Audio(x, rate=sr)
# 绘制信号
plt.figure(figsize=(14, 5))
librosa.display.waveplot(x, sr=sr)
# 放大 - Zooming in
n0 = 9000
n1 = 9100
plt.figure(figsize=(14, 5))
plt.plot(x[n0:n1])
plt.grid()
#
创建音频信号
''' >> 创建音频信号- audio signal >>创建一个 220Hz的 音频信号 >> 音频信号 audio signal >> 是一个 -Numpy 数组 - Numpy array, '''
import numpy as np
sr = 22050 # 采样率 -sample rate
T = 2.5 # 秒 - seconds
t = np.linspace(0, T, int(T*sr), endpoint=False) # 时间变量 time variable
x = 0.5*np.sin(2*np.pi*220*t)# 正弦波 - sine wave - 220 Hz
ipd.Audio(x, rate=sr) # load a NumPy array
保存音频数据
librosa.output.write_wav('Audio/tone_440.wav', x, sr)
录制语音数据
''' >> 錄製語音檔 - Audio File >> Audio Recorder >> pyaudio >> 跨平台音頻輸入/輸出 函式庫 >> cross-platform audio input/output stream library >> https://pypi.org/project/PyAudio/ >> pip install pyaudio >> Wave >> https://pypi.org/project/Wave/ >> pip install Wave '''
import pyaudio
import wave
CHUNK = 1024
FORMAT = pyaudio.paInt16 # paInt8
CHANNELS = 2
RATE = 44100 #採樣率 -sample rate
RECORD_SECONDS = 4
WAVE_OUTPUT_FILENAME = "Audio/output10.wav"
p = pyaudio.PyAudio()
stream = p.open(format=FORMAT,
channels=CHANNELS,
rate=RATE,
input=True,
frames_per_buffer=CHUNK) # buffer
print("* recording")
frames = []
for i in range(0, int(RATE / CHUNK * RECORD_SECONDS)):
data = stream.read(CHUNK)
frames.append(data) # 2 bytes(16 bits) per channel
print("* done recording")
stream.stop_stream()
stream.close()
p.terminate()
wf = wave.open(WAVE_OUTPUT_FILENAME, 'wb')
wf.setnchannels(CHANNELS)
wf.setsampwidth(p.get_sample_size(FORMAT))
wf.setframerate(RATE)
wf.writeframes(b''.join(frames))
wf.close()
去除静音
aa ,bb = librosa.effects.trim(samples, top_db=30)
语音识别工具包
'''
>> adjust_for_ambient_noise()方法
>> 讀取文件流的第一秒並將識別器校準到音頻的噪聲水平
>> file stream and calibrates
>> 因此,在調用record()捕獲數據之前
>> 將消耗該部分流 stream
>> adjust_for_ambient_noise()
>> 使用duration- keyword argument 關鍵字 參數
>> 調整用於分析的時間範圍
>> 此參數採用以秒為單位的數值,默認設置為1
>> 嘗試將此值降低到0.5
'''
import librosa
import IPython.display as ipd
y1, sr1 = librosa.load('audio_files\jackhammer.wav')
ipd.Audio(y1, rate=sr1)
with jackhammer as source:
r.adjust_for_ambient_noise(source, duration=0.5)
audio = r.record(source)
r.recognize_google(audio)
'''
>> 嘈雜的文件時,查看實際的API響應會很有幫助
>> show_all關鍵字參數設置為True
>> 來執行此recognize_google()操作
>> noisy files, it can be helpful to see the actual API response. Most APIs return a JSON string containing many possible transcriptions
>> recognize_google() 返回一個字典,其中的鍵
>> recognize_google() returns a dictionary with the key
'''
示例代码
import time
import librosa
# 计算音频之间的距离
from dtw import dtw
import librosa.display
from scipy.spatial.distance import cdist
import numpy
print(numpy.__version__)
import IPython.display as ipd
import matplotlib.pyplot as plt
x, sr = librosa.load('./sounds/10.wav')
ipd.Audio(x, rate=sr)
# 显示声谱图
plt.figure(figsize=(15, 5))
librosa.display.waveshow(x,sr,alpha=0.8)
# 显示频谱图,得到mfcc
plt.subplot(1, 2, 1)
mfcc1 = librosa.feature.mfcc(x, sr)
librosa.display.specshow(mfcc1)
语音处理阶段
获取音频数据
kaldi框架中内置的训练样本
小型数据,TIMIT
中型数据,WSJ
大型数据,Librispeech
获取音频数据对应的文本数据:OpenSLR网站下载数据
查看音频
查看音频
import librosa
audio_path = 'Audio/T08-violin.wav'
x , sr = librosa.load(audio_path)
# x
array([-0.00202265, -0.00320533, -0.00137628, ..., 0.00089052,
0.00087279, 0.0009666 ], dtype=float32)
# sr 采样点个数
22050
播放音频
import IPython.display as ipd
ipd.Audio(audio_path)
数据预处理
去除噪音
去除静音
提取特征
MFCC
FBank
Linear
CMVN
数据增强
噪声增强
使用噪声音频文件,添加到原音频文件中,使得音频文件有噪声背景。
偏移增强
对音频的前端部分或后端部分进行裁剪补0,类似图片随机裁剪。
语速增强
通过对音频的语速调整来达到增强的效果。
SpecAugment
一种新提出的针对音频特征做数据增强的方法,有效提高了模型的鲁棒性。
音量增强
通过改变音频的语速来达到增强的效果。
数据分集
- 训练数据
- 用于训练模型的参数
- 开发数据
- 用于直到训练配置参数和调节解码配置参数,以便优化模型训练过程和配置解码器
- 测试数据
- 测试数据则用于测试模型的性能
一般会按照8 1 1 或者 8.5 1 0.5 来划分
数据质量比较高:初始化
数据质量比较差:更接近实际应用,适合模型调优
数据下载和解压
# 设置保存原始数据的位置
data=/path/to/data/storage
# 定义数据下载的网址,默认使用OpenSLR的官网
data_url=http://www.openslr.org/12
lm_url=http://www.openslr.org/11
# 下载之前要判断是否已经存在下载好的资源
# 如果存在则判断资源是否完整
# 否则,才开始下载
# 下载指定dev-clean子集
local/download_and_untar.sh ${data} ${data_url} dev-clean
数据预处理
作用:将原始数据转为kaldi通用脚本可以处理的格式。
因为格式不同的数据库原始格式不同,所以要给每个数据库单独写预处理脚本
# 将原始数据转为kaldi数据文件夹
# 遍历每个数据文件夹:dev test train
for part in dev-clean test-clean dev-other test-other train-clean-100;do
# 开始处理每个文件
# todo 参数:数据下载的路径 数据处理后文件存储的目录:数据文件夹,符合Kaldi通用脚本规范
done
环境检查
# 在处理之前要检查必要的工具是否安装、目标文件和文件夹是否存在,依赖文件是否存在
if !which flac >&/dev/null; then
echo "Please install 'flac' on All worker nodes! "
exit 1
fi
[ ! -d $src ] && echo "$0: no such directory $src " && exit 1;
[ ! -d $spc_file ] && echo "$0: no such directory $spc_file " && exit 1;
生成表单文件
标准文件
text
utt2spk
spk2utt
wav.scp
# 还有更多的
spk2gender
utt2dur
数据检查
utils/validate_data_dir.sh
语言文件准备
exp # 生成声学模型的文件 HCLG.fst
mfcc # 经过cmvn后的,生成声学特征的文件夹
dev # 生成声学模型需要的文件
lang # 生成L.fst
lang_test # 生成G.fst的文件夹
local # 存放本地需要准备的文件,保存dict,以及kaldi标准文件,语言模型需要准备的文件
test # 生成声学模型需要的文件
train # 生成声学模型需要的文件
# local文件夹下
├── dict # 音素词典文件夹
│ ├── extra_questions.txt
│ ├── lexiconp.txt
│ ├── lexicon.txt
│ ├── nonsilence_phones.txt
│ ├── optional_silence.txt
│ └── silence_phones.txt
├── lang #
│ ├── align_lexicon.txt
│ ├── lexiconp_disambig.txt
│ ├── lexiconp.txt
│ ├── lex_ndisambig
│ └── phone_map.txt
├── lm # 语言模型
│ ├── 3gram-mincount
│ │ ├── config.0
│ │ ├── ...
│ │ ├── config.diff_1
│ │ ├── ...
│ │ ├── config.get_ngrams
│ │ ├── configs
│ │ │ ├── config.1.0.0
│ │ │ ├── config.1.-0.25
│ │ │ ├── config.1.0.35
│ │ │ ├── ...
│ │ ├── heldout_ngrams.gz
│ │ ├── lm_unpruned.gz # 语言模型
│ │ ├── ngrams_disc.gz
│ │ ├── ngrams.gz
│ │ ├── perplexities
│ │ │ ├── 1.0.0
│ │ │ ├── ...
│ │ │ ├── alpha.1
│ │ │ ├── ...
│ │ ├── perplexity
│ │ └── tmpdir
│ │ ├── 391220.2.gz
│ │ └── 391220.3.gz
│ ├── text.no_oov
│ ├── train.gz
│ ├── unigram.counts
│ ├── word.counts
│ ├── wordlist.mapped
│ └── word_map
└── train # kaldi标准文件夹
├── spk2utt
├── text
├── transcripts.txt
├── utt2spk
├── utt2spk_all
├── utt.list
├── wav.flist
├── wav.scp
└── wav.scp_all
生成音素图L.fst
准备dict文件夹
├── extra_questions.txt
├── lexiconp.txt
├── lexicon.txt
├── nonsilence_phones.txt
├── optional_silence.txt
└── silence_phones.txt
需要脚本
local/aishell_prepare_dict.sh ./wavdata/resource_aishell/lexicon.txt
生成L.fst
utils/prepare_lang.sh data/local/dict "<SPOKEN_NOISE>" data/local/lang data/lang
├── L_disambig.fst
├── L.fst # 音素图 或者 phone图
├── oov.int # 集外词索引
├── oov.txt # 集外词
├── phones
│ ├── align_lexicon.int
│ ├── align_lexicon.txt
│ ├── context_indep.csl
│ ├── context_indep.int
│ ├── context_indep.txt
│ ├── disambig.csl
│ ├── disambig.int
│ ├── disambig.txt
│ ├── extra_questions.int
│ ├── extra_questions.txt
│ ├── nonsilence.csl
│ ├── nonsilence.int
│ ├── nonsilence.txt
│ ├── optional_silence.csl
│ ├── optional_silence.int
│ ├── optional_silence.txt
│ ├── roots.int
│ ├── roots.txt
│ ├── sets.int
│ ├── sets.txt
│ ├── silence.csl
│ ├── silence.int
│ ├── silence.txt
│ ├── wdisambig_phones.int
│ ├── wdisambig.txt
│ ├── wdisambig_words.int
│ ├── word_boundary.int
│ └── word_boundary.txt
├── phones.txt
├── topo
└── words.txt
生成单词图G.fst
准备环境
# 安装srilm
ngram
# 安装kaldi_lm
/root/data/kaldi/tools/kaldi_lm/train_lm.sh
# 需要把kaldi_lm添加到系统环境中,可以修改env.sh文件进行配置。
准备文件
text=data/local/train/text
lexicon=data/local/dict/lexicon.txt
# 通过 local/aishell_data_prep.sh ./wavdata/data_aishell/wav ./wavdata/data_aishell/transcript 生成
生成文件
lm_unpruned.gz
需要脚本
local/aishell_train_lms.sh
生成G.fst
utils/format_lm.sh data/lang data/local/lm/3gram-mincount/lm_unpruned.gz \
data/local/dict/lexicon.txt data/lang_test
├── G.fst
├── L_disambig.fst
├── L.fst
├── oov.int
├── oov.txt
├── phones
│ ├── align_lexicon.int
│ ├── align_lexicon.txt
│ ├── context_indep.csl
│ ├── context_indep.int
│ ├── context_indep.txt
│ ├── disambig.csl
│ ├── disambig.int
│ ├── disambig.txt
│ ├── extra_questions.int
│ ├── extra_questions.txt
│ ├── nonsilence.csl
│ ├── nonsilence.int
│ ├── nonsilence.txt
│ ├── optional_silence.csl
│ ├── optional_silence.int
│ ├── optional_silence.txt
│ ├── roots.int
│ ├── roots.txt
│ ├── sets.int
│ ├── sets.txt
│ ├── silence.csl
│ ├── silence.int
│ ├── silence.txt
│ ├── wdisambig_phones.int
│ ├── wdisambig.txt
│ ├── wdisambig_words.int
│ ├── word_boundary.int
│ └── word_boundary.txt
├── phones.txt
├── topo
└── words.txt
生成上下文相关图C.fst
合成CLG.fst
生成HMM图H.fst
准备文件
utt2spk
spk2utt
wav.scp
text
需要脚本,生成kaldi标准文件夹
local/aishell_data_prep.sh ./wavdata/data_aishell/wav \
./wavdata/data_aishell/transcript
提取声学特征
特征类型有mfcc、fbank,增加基频声学特征提取的mfcc_pitch、fbank_pitch
# 需要conf文件夹
# 需要脚本
# 在steps/文件夹下
steps/make_fbank_pitch.sh.sh data/train
CMVN倒谱均值方差归一化
需要脚本
steps/compute_cmvn_stats.sh data/train exp/make_mfcc/train mfcc
# 检测文件
utils/fix_data_dir.sh data/train
合成HCLG.fst
需要脚本
模型训练阶段
解码器
ctc_greedy(贪心解码策略) 贪婪搜索为CTC解码算法中,最简单的一种解码方式。贪心解码策略是在每一步选择概率最大的输出值,然后删除连续相同的字符,这样就可以得到最终解码的输出序列,接着使用词汇表查找字符,把序列转换为字符,得到最终语音识别结果。
ctc_ beam_search(集束搜索解码)
贪心解码策略的性能非常受限,这种方法忽略了一个输出可能对应多个结果,只能找出概率最大的路径。通常情况下,有些读音相近的错误字符,却得到最大的概率值。这种情况下的话,集束解码策略利用概率相近的字符,求出多个候选解码路径,后续可以利用语言模型来进一步优化搜索的结果,最终得到一个更优的识别结果。.
环境部署阶段
关键词搜索与唤醒
常用框架-kaldi
kaldi环境配置
下载
git clone --depth 1 https://github.com/kaldi-asr/kaldi.git
git clone https://github.com/kaldi-asr/kaldi.git
安装编译依赖库
cd kaldi
tools/extras/check_dependencies.sh
注意:根据提示安装相关依赖工具
make -j 10
安装第三方工具
- OpenFst:
- kaldi使用FST作为状态图的表现形式,期待吗依赖OpenFst中定义的FST结构及一些基本操作,因此OpenFst对于Kaldi的编译是不可或缺的,安装方法如下
- 需要g++ 11
cd tools
make openfst
- cub:
- cub是NVIDIA官方提供的CUDA核函数开发库,是目前Kaldi编译的必选工具,安装方法如下
cd tools
make cub
- Sph2pipe:
- 这个工具是用来对SPH音频格式进行转换的,使用LDC数据的示例都要用到这个工具
cd tools
make sph2pipe
- ITSTLM/SRILM/Kaldi_lm:
- 这是三个不同的语言模型工具,不同的示例使用不同的语音模型工具
cd tools
extras/install_irstlm.sh
extras/install_srilm.sh
extras/install_kaldi_lm.sh
-
其中安装SRILM时有两点需要注意:
-
第一,SRILM用于商业用途不是免费的,需要到SRILM网站注册、接收许可协议,并需要命名为srilm.tgz,放到tools文件夹下
-
第二,STILM的安装依赖lbfgs库,这个库的安装方法是
-
cd tools extras/install_liblbfgs.sh
-
-
OpenBLAS/MKL
-
kaldi的最新版本已经选用MKL作为默认的矩阵运算库,如果需要手工安装OpenBLAS或者MKL,方法如下
-
cd tools extras/install_openblas.sh
-
编译kaldi
cd src
./configure --help # 查看相关配置
# 如果编译目的实在服务器上搭建训练环境,推荐使用编译方式
./configure --shared
make #单线程编译
make -j 4 # 多线程编译
# 如果只有cpu运算,则需要在配置时加入如下选项
./configure --share --use-cuda=no
# 如果ARMv8交叉编译,则使用如下编译方式,前提是armv-8-rpi3-linux-gnueabihf工具链是可用的,同时要求OpenFst和ATLAS使用armv8-rpi3-linux-gnueabihf工具链编译并安装到/opt/cross/armv8hf
./configure --static --fst-root=/opt/cross/armv8hf --atlas-root=/opt/cross/armv8hf -host=armv8-rpi3-linux-gnueabihf
# 如果为ARM架构的Android编译,则需要加上--android-includes这个选项,因为Android NDK提供的工具链可能没有吧C++的stdlib头文件加入交叉编译路径中
./configure --static --openblas-root=/opt/cross/arm-linux-androideabi --fst-root=/opt/cross/arm-linux-androideabi --fst-version=1.4.1 --android-incdir=/opt/cross/arm-linux-androideabi/sysroot/usr/include --host=arm-linux-androideabi
运行配置工具会在src文件夹在生成kaldi.mk文件,这个文件在编译过程中会被各个子目录的编译文件引用。
使用GPU要指定cuda的版本所在路径
./configure --shared --cudatk-dir=/usr/local/cuda-11.6
make -j clean depend; make -j <NCPU>