文章目录

  • 简介
  • 1. 数据集
  • 2. 模型预测
  • 3. 模型训练
  • 4. 总结

简介

最近忽然看到不是基于kaldi的ASR代码,尝试了一下发现效果还不错,搬上来记录一下。

源码地址:

https://pan.baidu.com/s/1tFlZkMJmrMTD05cd_zxmAg
提取码:ndrr
数据集需要自行下载。


1. 数据集

数据集使用的是清华大学的thchs30中文数据,data文件夹中包含(.wav文件和.trn文件;trn文件里存放的是.wav文件的文字描述:第一行为词,第二行为拼音,第三行为音素).

2. 模型预测

先直接解释有了训好的模型后如何使用,代码如下:

# -*- coding: utf-8 -*-
from keras.models import load_model
from keras import backend as K
import numpy as np
import librosa
from python_speech_features import mfcc
import pickle
import globwavs = glob.glob('A2_8.wav')
print(wavs)
with open('dictionary.pkl', 'rb') as fr:[char2id, id2char, mfcc_mean, mfcc_std] = pickle.load(fr)mfcc_dim = 13
model = load_model('asr.h5')index = np.random.randint(len(wavs))
print(wavs[index])## 读取数据,并去除掉没说话的起始结束时间
audio, sr = librosa.load(wavs[index])
energy = librosa.feature.rmse(audio)
frames = np.nonzero(energy >= np.max(energy) / 5)
indices = librosa.core.frames_to_samples(frames)[1]
audio = audio[indices[0]:indices[-1]] if indices.size else audio[0:0]
X_data = mfcc(audio, sr, numcep=mfcc_dim, nfft=551)
X_data = (X_data - mfcc_mean) / (mfcc_std + 1e-14)
print(X_data.shape)pred = model.predict(np.expand_dims(X_data, axis=0))
pred_ids = K.eval(K.ctc_decode(pred, [X_data.shape[0]], greedy=False, beam_width=10, top_paths=1)[0][0])
pred_ids = pred_ids.flatten().tolist()
print(''.join([id2char[i] for i in pred_ids]))

3. 模型训练

模型采用了 TDNN 网络结构,并直接通过字符级别来预测,直接根据常见度将字符对应成数字标签。整个流程而言,

  • 先将一个个语音样本变成MFCC特征,即一个样本的维度为time*num_MFCC,time维度将被补齐到batch里最长的time。
  • 将批量样本送入网络,采用1d卷积,仅在时间轴上卷积,一个样本的输出维度为time*(num_words+1),加的1代表预测了空状态。
  • 通过CTC Loss计算损失
# -*- coding: utf-8 -*-
#导入相关的库
from keras.models import Model
from keras.layers import Input, Activation, Conv1D, Lambda, Add, Multiply, BatchNormalization
from keras.optimizers import Adam, SGD
from keras import backend as K
from keras.callbacks import ModelCheckpoint, ReduceLROnPlateauimport numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatableimport random
import pickle
import glob
from tqdm import tqdm
import osfrom python_speech_features import mfcc
import scipy.io.wavfile as wav
import librosa
from IPython.display import Audio#读取数据集文件
text_paths = glob.glob('data/*.trn')
total = len(text_paths)
print(total)with open(text_paths[0], 'r', encoding='utf8') as fr:lines = fr.readlines()print(lines)#数据集文件trn内容读取保存到数组中
texts = []
paths = []
for path in text_paths:with open(path, 'r', encoding='utf8') as fr:lines = fr.readlines()line = lines[0].strip('\n').replace(' ', '')texts.append(line)paths.append(path.rstrip('.trn'))print(paths[0], texts[0])#定义mfcc数
mfcc_dim = 13#根据数据集标定的音素读入
def load_and_trim(path):audio, sr = librosa.load(path)energy = librosa.feature.rmse(audio)frames = np.nonzero(energy >= np.max(energy) / 5)indices = librosa.core.frames_to_samples(frames)[1]audio = audio[indices[0]:indices[-1]] if indices.size else audio[0:0]return audio, sr#可视化,显示语音文件的MFCC图
def visualize(index):path = paths[index]text = texts[index]print('Audio Text:', text)audio, sr = load_and_trim(path)plt.figure(figsize=(12, 3))plt.plot(np.arange(len(audio)), audio)plt.title('Raw Audio Signal')plt.xlabel('Time')plt.ylabel('Audio Amplitude')plt.show()feature = mfcc(audio, sr, numcep=mfcc_dim, nfft=551)print('Shape of MFCC:', feature.shape)fig = plt.figure(figsize=(12, 5))ax = fig.add_subplot(111)im = ax.imshow(feature, cmap=plt.cm.jet, aspect='auto')plt.title('Normalized MFCC')plt.ylabel('Time')plt.xlabel('MFCC Coefficient')plt.colorbar(im, cax=make_axes_locatable(ax).append_axes('right', size='5%', pad=0.05))ax.set_xticks(np.arange(0, 13, 2), minor=False);plt.show()return pathAudio(visualize(0))#提取音频特征并存储
features = []
for i in tqdm(range(total)):path = paths[i]audio, sr = load_and_trim(path)features.append(mfcc(audio, sr, numcep=mfcc_dim, nfft=551))print(len(features), features[0].shape)#随机选择100个数据集
samples = random.sample(features, 100)
samples = np.vstack(samples)
#平均MFCC的值为了归一化处理
mfcc_mean = np.mean(samples, axis=0)
#计算标准差为了归一化
mfcc_std = np.std(samples, axis=0)
print(mfcc_mean)
print(mfcc_std)
#归一化特征
features = [(feature - mfcc_mean) / (mfcc_std + 1e-14) for feature in features]#将数据集读入的标签和对应id存储列表
chars = {}
for text in texts:for c in text:chars[c] = chars.get(c, 0) + 1chars = sorted(chars.items(), key=lambda x: x[1], reverse=True)
chars = [char[0] for char in chars]
print(len(chars), chars[:100])char2id = {c: i for i, c in enumerate(chars)}
id2char = {i: c for i, c in enumerate(chars)}data_index = np.arange(total)
np.random.shuffle(data_index)
train_size = int(0.9 * total)
test_size = total - train_size
train_index = data_index[:train_size]
test_index = data_index[train_size:]
#神经网络输入和输出X,Y的读入数据集特征
X_train = [features[i] for i in train_index]
Y_train = [texts[i] for i in train_index]
X_test = [features[i] for i in test_index]
Y_test = [texts[i] for i in test_index]batch_size = 16#定义训练批次的产生,一次训练16个
def batch_generator(x, y, batch_size=batch_size):offset = 0while True:offset += batch_sizeif offset == batch_size or offset >= len(x):data_index = np.arange(len(x))np.random.shuffle(data_index)x = [x[i] for i in data_index]y = [y[i] for i in data_index]offset = batch_sizeX_data = x[offset - batch_size: offset]Y_data = y[offset - batch_size: offset]X_maxlen = max([X_data[i].shape[0] for i in range(batch_size)])Y_maxlen = max([len(Y_data[i]) for i in range(batch_size)])X_batch = np.zeros([batch_size, X_maxlen, mfcc_dim])Y_batch = np.ones([batch_size, Y_maxlen]) * len(char2id)X_length = np.zeros([batch_size, 1], dtype='int32')Y_length = np.zeros([batch_size, 1], dtype='int32')for i in range(batch_size):X_length[i, 0] = X_data[i].shape[0]X_batch[i, :X_length[i, 0], :] = X_data[i]Y_length[i, 0] = len(Y_data[i])Y_batch[i, :Y_length[i, 0]] = [char2id[c] for c in Y_data[i]]inputs = {'X': X_batch, 'Y': Y_batch, 'X_length': X_length, 'Y_length': Y_length}outputs = {'ctc': np.zeros([batch_size])}yield (inputs, outputs)epochs = 50
num_blocks = 3
filters = 128X = Input(shape=(None, mfcc_dim,), dtype='float32', name='X')
Y = Input(shape=(None,), dtype='float32', name='Y')
X_length = Input(shape=(1,), dtype='int32', name='X_length')
Y_length = Input(shape=(1,), dtype='int32', name='Y_length')#卷积1层      # 一维卷积,默认channels_last,即通道维(MFCC特征维)放最后,对时间维进行卷积
def conv1d(inputs, filters, kernel_size, dilation_rate):return Conv1D(filters=filters, kernel_size=kernel_size, strides=1, padding='causal', activation=None,dilation_rate=dilation_rate)(inputs)#标准化函数
def batchnorm(inputs):return BatchNormalization()(inputs)#激活层函数
def activation(inputs, activation):return Activation(activation)(inputs)#全连接层函数
def res_block(inputs, filters, kernel_size, dilation_rate):hf = activation(batchnorm(conv1d(inputs, filters, kernel_size, dilation_rate)), 'tanh')hg = activation(batchnorm(conv1d(inputs, filters, kernel_size, dilation_rate)), 'sigmoid')h0 = Multiply()([hf, hg])ha = activation(batchnorm(conv1d(h0, filters, 1, 1)), 'tanh')hs = activation(batchnorm(conv1d(h0, filters, 1, 1)), 'tanh')return Add()([ha, inputs]), hsh0 = activation(batchnorm(conv1d(X, filters, 1, 1)), 'tanh')
shortcut = []
for i in range(num_blocks):for r in [1, 2, 4, 8, 16]:h0, s = res_block(h0, filters, 7, r)shortcut.append(s)h1 = activation(Add()(shortcut), 'relu')
h1 = activation(batchnorm(conv1d(h1, filters, 1, 1)), 'relu')
#softmax损失函数输出结果
Y_pred = activation(batchnorm(conv1d(h1, len(char2id) + 1, 1, 1)), 'softmax')
sub_model = Model(inputs=X, outputs=Y_pred)#计算损失函数
def calc_ctc_loss(args):y, yp, ypl, yl = argsreturn K.ctc_batch_cost(y, yp, ypl, yl)ctc_loss = Lambda(calc_ctc_loss, output_shape=(1,), name='ctc')([Y, Y_pred, X_length, Y_length])
#加载模型训练
model = Model(inputs=[X, Y, X_length, Y_length], outputs=ctc_loss)
#建立优化器
optimizer = SGD(lr=0.02, momentum=0.9, nesterov=True, clipnorm=5)
#激活模型开始计算
model.compile(loss={'ctc': lambda ctc_true, ctc_pred: ctc_pred}, optimizer=optimizer)checkpointer = ModelCheckpoint(filepath='asr.h5', verbose=0)
lr_decay = ReduceLROnPlateau(monitor='loss', factor=0.2, patience=1, min_lr=0.000)
#开始训练
history = model.fit_generator(generator=batch_generator(X_train, Y_train),steps_per_epoch=len(X_train) // batch_size,epochs=epochs,validation_data=batch_generator(X_test, Y_test),validation_steps=len(X_test) // batch_size,callbacks=[checkpointer, lr_decay])#保存模型
sub_model.save('asr.h5')
#将字保存在pl=pkl中
with open('dictionary.pkl', 'wb') as fw:pickle.dump([char2id, id2char, mfcc_mean, mfcc_std], fw)train_loss = history.history['loss']
plt.plot(np.linspace(1, epochs, epochs), train_loss, label='train')
plt.legend(loc='upper right')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.show()#下面是模型的预测效果,可见main.py
from keras.models import load_model
import picklewith open('dictionary.pkl', 'rb') as fr:[char2id, id2char, mfcc_mean, mfcc_std] = pickle.load(fr)sub_model = load_model('asr.h5')def random_predict(x, y):index = np.random.randint(len(x))feature = x[index]text = y[index]pred = sub_model.predict(np.expand_dims(feature, axis=0))pred_ids = K.eval(K.ctc_decode(pred, [feature.shape[0]], greedy=False, beam_width=10, top_paths=1)[0][0])pred_ids = pred_ids.flatten().tolist()print('True transcription:\n-- ', text, '\n')print('Predicted transcription:\n-- ' + ''.join([id2char[i] for i in pred_ids]), '\n')random_predict(X_train, Y_train)
random_predict(X_test, Y_test)

4. 总结

对比其他的分类任务,语音识别多了个解码过程,这也导致了目前在常见的深度学习框架中还没有很好的ASR框架,目前而言,CTC的应用也导致出现了一些完全端到端的ASR系统,相信以后这也会是个大趋势。

【语音识别】基于keras的简易语音识别相关推荐

  1. 语音识别——基于深度学习的中文语音识别tutorial(代码实践)

    文章目录 利用thchs30为例建立一个语音识别系统 1. 特征提取 2. 数据处理 下载数据 2.1 生成音频文件和标签文件列表 定义函数`source_get`,获取音频文件及标注文件列表 确认相 ...

  2. python语音建模_该系统实现了基于深度框架的语音识别中的声学模型和语言模型建模...

    基于深度学习的中文语音识别系统 如果觉得有用的话,小手给个star吧~ 注意:本人于近期想对该项目进行翻新,tf现在已经将keras作为重要的一部分,因此可能将代码用TensorFlow2来进行修改. ...

  3. 语音识别——基于深度学习的中文语音识别系统框架

    本文搭建一个完整的中文语音识别系统,包括声学模型和语言模型,能够将输入的音频信号识别为汉字. 该系统实现了基于深度框架的语音识别中的声学模型和语言模型建模,其中声学模型包括CNN-CTC.GRU-CT ...

  4. 实战:基于tensorflow 的中文语音识别模型 | CSDN博文精选

    作者 | Pelhans 来源 | CSDN博客 目前网上关于tensorflow 的中文语音识别实现较少,而且结构功能较为简单.而百度在PaddlePaddle上的 Deepspeech2 实现功能 ...

  5. 基于LD3320的嵌入式语音识别系统设计

    摘要:语音交互系统是比较人性化的人机操作界面,它需要语音识别系统的支持.LD3320就是这样一款语音识别芯片.介绍了该芯片的工作原理及应用,给出了LD3320与微处理器的硬件接口电路及软件程序.随着高 ...

  6. 基于STM32的嵌入式语音识别模块设计实现

    介绍了一种以ARM为核心的嵌入式语音识别模块的设计与实现.模块的核心处理单元选用ST公司的基于ARM Cortex-M3内核的32位处理器STM32F103C8T6.本模块以对话管理单元为中心,通过以 ...

  7. 一种基于说话人识别和数字语音识别的身份认证方法与流程

    本发明属于语音处理技术领域,具体涉及到对数字语音序列进行说话人识别和语音识别,确定说话人身份的身份认证方法. 背景技术: 说话人识别也称为声纹识别,可以从说话人发出的声音中提取其个性特征,从而识别出当 ...

  8. 一种基于地图导航的语音识别管理系统的制作方法

    本发明涉及语音识别技术领域,具体为一种基于地图导航的语音识别管理系统. 背景技术: 随着GPS技术的不断发展,给人们的出行带来了很大的便利,人们可以根据GPS导航到达指定的地方. 现有的在对地图资源的 ...

  9. stm32的语音识别_基于STM32的嵌入式语音识别模块设计实现

    介绍了一种以ARM为核心的嵌入式语音识别模块的设计与实现.模块的核心处理单元选用ST公司的基于ARM Cortex-M3内核的32位处理器STM32F103C8T6.本模块以对话管理单元为中心,通过以 ...

  10. 软件包应用分享|基于RT-Thread的百度语音识别(二)

    本期分享来自RT-Thread的社区小伙伴霹雳大乌龙,如果你也有文章愿意分享/希望获得官方的写作指导,可以发送文章/联系方式邮件至邮箱:xuqianqian@rt-thread.com 回顾往期: 软 ...

最新文章

  1. 【C++】google gflags详解
  2. 【Java】反射( reflection)机制 详解
  3. 大型网站的架构演进从一个电商网站开始
  4. 【大数据课堂0006】【oracle】python3/plsql 使用cx_Oracle遇到到的坑
  5. 索尼发布工业设备用SWIR图像传感器 采用5微米像素尺寸
  6. 蓝桥杯 BASIC-30 基础练习 阶乘计算
  7. 一张图学会python应用到excel-简单使用python做excel多文件批量搜索(带图形界面)(已更新)...
  8. c++ time.h 用法
  9. Win 10 下载与安装 Oracle 12c 详细图解 与 Oracle 12c 卸载
  10. 多模态语义分析_学术竞赛 | 冠军方案分享2020科大讯飞AI开发者大赛多模态情感分析赛道...
  11. WordPress主题插件Modown6.1绿色版+Erphpdown11.6等多插件
  12. Yate架构分析概要
  13. 光明顶短信支付:格式详解
  14. 客户个性分析 聚类 大数据
  15. drhf赫夫生医的产品质量怎么样?
  16. matlab 坐标不用科学计数法,matlab不用科学计数法
  17. 实用工具WGestures全局鼠标手势
  18. 测试用例颗粒度实例列举
  19. u盘无响应+开启什么服务器,服务没有及时响应启动或控制请求怎么办?如何解决系统服务没有及时响应启动...
  20. win10时间服务器未运行,win10 Windows License Manager Service服务未运行如何解决

热门文章

  1. 微信小程序 实现带刻尺度滑块
  2. 根轨迹 matlab 怎么画一半儿,现有 1020 个西瓜,第一天卖一半多两个,以后每天都卖剩下的一半多两个,编程计算几天后能把所有西瓜都卖完? 请编程实现_学小易找答案...
  3. http解析库http-parser
  4. rtx web 分级管理系统 二次开发
  5. IP地址、网络号、主机号、网络地址、子网掩码、网关、192.168.0.1/24是什么意思
  6. Apache Pegasus 首次 Meetup 圆满落幕
  7. 差动变压器的振动测量实验 思考题
  8. 从大公司年薪30万,跳槽到小公司月薪8千,是什么体验?
  9. 分时电价模型,削峰填谷,转移24小时一天中用电率,减少谷峰差
  10. glide加载大图片白屏崩溃闪退