基于Tensorflow实现语音识别
安装librosa
librosa是一种用于音频处理的工具包,具有图形处理,特征提取,绘制声音图形。安装命令:
pip install pytest-runner
pip install librosa
安装pyAudio
pyAudio用于提取特征,训练并且使用分类器、语音分割功能、内容关系可视化
具体功能:
特征提取(feature extraction):关于时域信号和频域信号都有所涉及
分类(classification):监督学习,需要用已有的训练集来进行训练。交叉验证也实现了,进行参数优化使用。分类器可以保存在文件中以后使用。
回归(regression):将语音信号映射到一个回归值。
分割(segmenttation):有四个功能被实现了
[x] 固定大小的分割
[x] 静音检测(silence removal)
[x] 语音聚类(speaker diarization)
[x] 语音缩略图(audio thumbnailing)
可视化:给定语音,将内容可视化
安装命令:pip install pyaudio
pydub
用户处理音频的一个库:pip install pudub
训练分类模型
tip1:傅里叶变换(FFT):将音频信号从时域转换到频域
tip2:梅尔频谱:人们对频率的感知不是线性的,并且对低频较高频敏感,例如,我们可以轻松分辨出500 Hz和1000 Hz之间的差异,但是即使之间的距离相同,我们也很难分辨出10,000 Hz和10,500 Hz之间的差异。这是梅尔标度(The Mel Scale)被提出,它是HZ的非线性变换,对于以mel scale为单位的信号,人们可以做到对相同频率的信号感知相同,变换公式为
将音频转换成训练数据最重要使用的是librosa,使用librosa可以很方便地得到音频的梅尔频谱(Mel Spectrogram),使用的API为librosa.feature.melspectrogram(),输出的是numpy值。跟梅尔频谱同样很重要的**梅尔倒谱(MFCCs)**更多用于语音识别中,对应的 API 为 librosa.feature.mfcc()。同样以下的代码,就可以获取到音频的梅尔频谱,其中 duration 参数指定的是截取音频的长度。
y1,sr1=librosa.load(data_path,duration=2.97)
ps=librosa.feature.meispectrogram(y=y1,sr=sr1)
创建训练数据
根据上面的方法,我们创建Tensorflow训练数据,因为分类音频数据小而多,最好的方法就是将这些音频数据文件生成TFRecord文件,加快训练速度,创建!!!creat_data.py!!!,用于生成TFRecode文件
首先需要生成数据列表,用于下一步读取需要,audio_path为音频文件路径,用户需要提前把音频数据集存放在dataset/audio目录下,每个文件夹存放一个类别的音频数据,如dataset/audio/鸟叫声/…每条音频的数据长度大于2.1秒(自行定),audio是数据列表存放的位置,生成数据的格式为 音频路径/音频对应的类别标签
def get_data_list(audio_path, list_path):
sound_sum = 0
audios = os.listdir(audio_path)#返回值是该文件夹下所有的文件路径列表
f_train = open(os.path.join(list_path, 'train_list.txt'), 'w')#用于存放
f_test = open(os.path.join(list_path, 'test_list.txt'), 'w')#用于存放
for i in range(len(audios)):
sounds = os.listdir(os.path.join(audio_path, audios[i]))#处理单独一个类声
for sound in sounds:
sound_path = os.path.join(audio_path, audios[i], sound)
t = librosa.get_duration(filename=sound_path)
# [可能需要修改参数] 过滤小于2.1秒的音频
if t >= 2.1:
if sound_sum % 100 == 0:
f_test.write('%s\t%d\n' % (sound_path, i))
else:
f_train.write('%s\t%d\n' % (sound_path, i))
sound_sum += 1
print("Audio:%d/%d" % (i + 1, len(audios)))
f_test.close()
f_train.close()
if __name__ == '__main__':
get_data_list('dataset/audio', 'dataset')
有了以上的数据列表,就可开始生成 TFRecord 文件了。最终会生成 train.tfrecord 和 test.tfrecord。笔者设置的音频长度为 2.04 秒,不足长度会补 0,如果需要使用不同的音频长度时,需要修改 wav_len 参数值和 len(ps)过滤值,wav_len 参数值为音频长度 16000 * 秒数,len(ps)过滤值为梅尔频谱 shape 相乘。
```python
# 获取浮点数组
def _float_feature(value):
if not isinstance(value, list):
value = [value]
return tf.train.Feature(float_list=tf.train.FloatList(value=value))
# 获取整型数据
def _int64_feature(value):
if not isinstance(value, list):
value = [value]
return tf.train.Feature(int64_list=tf.train.Int64List(value=value))
# 把数据添加到TFRecord中
def data_example(data, label):
feature = {
'data': _float_feature(data),
'label': _int64_feature(label),
}
return tf.train.Example(features=tf.train.Features(feature=feature))
# 开始创建tfrecord数据
def create_data_tfrecord(data_list_path, save_path):
with open(data_list_path, 'r') as f:
data = f.readlines()
with tf.io.TFRecordWriter(save_path) as writer:
for d in tqdm(data):
try:
path, label = d.replace('\n', '').split('\t')
wav, sr = librosa.load(path, sr=16000)
intervals = librosa.effects.split(wav, top_db=20)
wav_output = []
# [可能需要修改参数] 音频长度 16000 * 秒数
wav_len = int(16000 * 2.04)
for sliced in intervals:
wav_output.extend(wav[sliced[0]:sliced[1]])#保留疑问?--盲猜是将np矩阵类型转为列表类型容易操作!
for i in range(5):
# 裁剪过长的音频,过短的补0
if len(wav_output) > wav_len:
l = len(wav_output) - wav_len
r = random.randint(0, l)
wav_output = wav_output[r:wav_len + r]
else:
wav_output.extend(np.zeros(shape=[wav_len - len(wav_output)], dtype=np.float32))
wav_output = np.array(wav_output)
# 转成梅尔频谱
ps = librosa.feature.melspectrogram(y=wav_output, sr=sr, hop_length=256).reshape(-1).tolist()
# [可能需要修改参数] 梅尔频谱shape ,librosa.feature.melspectrogram(y=wav_output, sr=sr, hop_length=256).shape
if len(ps) != 128 * 128: continue#跳过下面的语句继续执行循环体下一条
tf_example = data_example(ps, int(label))
writer.write(tf_example.SerializeToString())#序列化存储
if len(wav_output) <= wav_len:
break
except Exception as e:
print(e)
if __name__ == '__main__':
create_data_tfrecord('dataset/train_list.txt', 'dataset/train.tfrecord')
create_data_tfrecord('dataset/test_list.txt', 'dataset/test.tfrecord')
Urbansound8K 是目前应用较为广泛的用于自动城市环境声分类研究的公共数据集,包含 10 个分类:空调声、汽车鸣笛声、儿童玩耍声、狗叫声、钻孔声、引擎空转声、枪声、手提钻、警笛声和街道音乐声。数据集下载地址:https://zenodo.org/record/1203745/files/UrbanSound8K.tar.gz。以下是针对 Urbansound8K 生成数据列表的函数。如果读者想使用该数据集,请下载并解压到 dataset 目录下,把生成数据列表代码改为以下代码
# 创建UrbanSound8K数据列表
def get_urbansound8k_list(path, urbansound8k_cvs_path):
data_list = []
data = pd.read_csv(urbansound8k_cvs_path)
# 过滤掉长度少于3秒的音频
valid_data = data[['slice_file_name', 'fold', 'classID', 'class']][data['end'] - data['start'] >= 3]
valid_data['path'] = 'fold' + valid_data['fold'].astype('str') +