基于Python+WaveNet+CTC+Tensorflow智能语音识别与方言分类—深度学习算法应用(含全部工程源码)

2023-11-07


在这里插入图片描述

前言

本项目利用语音文件和方言标注文件,提取语音的梅尔倒谱系数特征,并对这些特征进行归一化处理。在基于标注文件的指导下,构建了一个字典来管理数据。接着,我们选择WaveNet机器学习模型进行训练,并对模型的输出进行softmax处理。最终,经过训练后的模型将被保存以备后续使用。

在项目中,我们首先获取语音文件和标注文件,并使用相应的技术来提取梅尔倒谱系数特征。这些特征可以捕捉语音信号的频谱信息,并为后续的模型训练提供输入。

为了准确地将语音文件与标注对应起来,我们根据标注文件建立了一个字典,使得每个语音文件能够与其对应的标注信息关联。

为了训练有效的语音识别模型,我们选择了WaveNet机器学习模型。WaveNet是一种基于深度学习的模型,被广泛用于音频生成和识别任务。我们使用训练数据来训练WaveNet模型,以便它能够学习语音文件与对应标注之间的关联。

最后,在训练完成后,我们将模型的输出通过softmax处理,以得到最终的预测结果。这样的处理可以将输出转换为概率分布,使得模型更容易对语音进行正确的识别。

经过这一系列的步骤,我们的项目能够实现对语音文件的识别,并根据标注信息对方言进行分类。训练好的模型将被保存,以备后续在实际应用中使用。这个项目为语音识别领域的进一步研究和应用提供了可靠的基础。

总体设计

本部分包括系统整体结构图和系统流程图。

系统整体结构图

系统整体结构如图所示。

在这里插入图片描述

系统流程图

语音识别及方言分类流程如图1所示,页面设计流程如图2所示。

在这里插入图片描述

图1 语音识别及方言分类流程图

在这里插入图片描述

图2 页面设计流程图

运行环境

本部分包括 Python 环境和Tensorflow 环境。

Python 环境

需要Python 3.6及以上配置,在Windows环境 下推荐下载Anaconda完成Python所需的配置,下载地址为https://www.anaconda.com/。也可以下载虚拟机在Linux环境下运行代码。

Tensorflow 环境

打开Anaconda Prompt,输入清华仓库镜像:

conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/
conda config -set show_channel_urls yes

创建Python 3.6.5环境,名称为TensorFlow。此时Python版本和后面TensorFlow的版本存在匹配问题,此步选择Python3.x。

conda create -n tensorflow python==3.6.5

有需要确认的地方,都按Y键。
在Anaconda Prompt中激活TensorFlow环境:

conda activate tensorflow

安装与python3.6.5匹配的CPU版本的TensorFlow:

pip install tensorflow==1.9

安装Python和TensorFlow匹配的Keras版本,此处为Keras2.2.0:

pip install Keras==2.2.0

三者版本若不匹配,导入Keras时Kernel将会出现问题。

安装完毕,进行检验,在cmd中输入Python后, 按图所示输入,若成功输出则安装成功。
在这里插入图片描述

模块实现

本项目包括3个模块:方言分类、语音识别和模型测试,下面分别给出各模块的功能介绍及相关代码。

1. 方言分类

本部分包含数据下载及预处理、模型构建、模型训练及保存。

数据下载及预处理

数据集由科大讯飞提供,内有长沙话、上海 话和南昌话3种方言,包含50~300KB的语音数据集19489条,其中17989条训练数据,1500条验证数据,下载地址为http://challenge.xfyun.cn/2019/。下载数据集并导入,训练集、验证集的数据分别命名为train_flesdev_fles。通过使用glob ()函数实现,导入数据代码如下:

#加载pcm文件,其中17989条训练数据,1500条验证数据
#定义训练集
train_files = glob.glob(r'D:\homework\dialect\data\*\train\*\*.pcm')
#定义验证集 
dev_files = glob.glob(r'D:\homework\dialect\data\*\dev\*\*\*.pcm') 
print(len(train_files), len(dev_files),train_files[0])
#打印语音数据集的数量与训练集第一条数据

对下载的语音数据集进行整理分类,为训练集和验证集中的每一条数据打标签。相关代码如下:

labels = {'train': [], 'dev': []}
#对于train_files中的每一条数据
for i in tqdm(range(len(train_files))):
path = train_files[i] #取出路径
label = path.split('\\')[1] #以'\\'划分路径,取出其中对应地区分类的标签
labels['train'].append(label)#以字典进行存储
#对于dev_files中的每一条数据进行如上操作
for i in tqdm(range(len(dev_files))):
path = dev_files[i]
label = path.split('\\')[1]
labels['dev'].append(label)
print(len(labels['train']), len(labels['dev']))
#整理每条语音数据对应的分类标签图

数据集下载后进行预处理。定义处理语音数据、pcm格式转wav格式、可视化语音数据集的3个函数。由于语音片段长短不一,去除少于1s的短片段,并将长片段切分为不超过3s的片段。

a. 处理语音数据

相关代码如下:

def load_and_trim(path, sr=16000):
    audio = np.memmap(path, dtype='h', mode='r')  #对大文件分段读取
    audio = audio[2000:-2000]
    audio = audio.astype(np.float32)
    energy = librosa.feature.rms(audio)  #计算能量
    frames = np.nonzero(energy >= np.max(energy) / 5) #最大能量的1/5视为静音
    indices = librosa.core.frames_to_samples(frames)[1]#去除静音
    audio = audio[indices[0]:indices[-1]] if indices.size else audio[0:0]
    slices = []#存储划分为小于3s大于1s的切片
    for i in range(0, audio.shape[0], slice_length):
        s = audio[i: i + slice_length]#切分为3s片段
        if s.shape[0] >= min_length:
            slices.append(s)  #去除小于1s的片段
    return audio, slices

b. pcm转wav函数

相关代码代码如下:

def pcm2wav(pcm_path, wav_path, channels=1, bits=16, sample_rate=sr):
    data = open(pcm_path, 'rb').read()  #读取文件
    fw = wave.open(wav_path, 'wb')  #存储wav路径
    fw.setnchannels(channels)  #设置通道数:单声道
    fw.setsampwidth(bits // 8)  #将样本宽度设置为bits/8个字节
    fw.setframerate(sample_rate)  #设置采样率
    fw.writeframes(data)  #写入data个长度的音频
    fw.close()

c. 可视化语音数据集函数

相关代码如下:

def visualize(index, source='train'):
    if source == 'train':
        path = train_files[index]  #训练集路径
    else:
        path = dev_files[index]  #验证集路径
    print(path)
    audio, slices = load_and_trim(path)  #去除两端静音,并切分为片段
    print('Duration: %.2f s' % (audio.shape[0] / sr))  #打印处理后的长度
    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)  #提取mfcc特征
    print('Shape of MFCC:', feature.shape)  #打印mfcc特征
    fig = plt.figure(figsize=(12, 5))  #图像大小
    ax = fig.add_subplot(111)
    im = ax.imshow(feature, cmap=plt.cm.jet, aspect='auto')  #绘制mfcc
    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()  #绘图展示
    wav_path = r'D:/homework/dialect/example.wav'#wav文件存储路径
    pcm2wav(path, wav_path)  #pcm文件转化为wav文件
    return wav_path

以可视化第3条语音数据为例,结果如图3所示。分别将训练集和验证集的MFCC特征进行归一化处理,相关代码如下:

#对训练集MFCC特征归一化
X_train = [(x - mfcc_mean) / (mfcc_std + 1e-14) for x in X_train] 
#对验证集MFCC特征归一化
X_dev = [(x - mfcc_mean) / (mfcc_std + 1e-14) for x in X_dev] 

在这里插入图片描述

图3 第3条语音数据可视化结果

使用LabelEncoder()将标签处理为整数,并通过to_categorical()函数将训练集和验证集分别转化为向量,再定义迭代器函数,相关代码如下:

le = LabelEncoder()
Y_train = le.fit_transform(Y_train)  #处理训练集标签
Y_dev = le.transform(Y_dev)  #处理验证集标签
num_class = len(le.classes_)  #3个类别
Y_train = to_categorical(Y_train, num_class)  #将训练集转化为向量
Y_dev = to_categorical(Y_dev, num_class)  #将验证集转化为向量

模型构建

数据加载进模型之后,需要定义模型结构,并优化损失函数。

(1) 定义模型结构

模型使用多层因果空洞卷积(Causal Dilated Convolution)处理数据。首先,构建并使用一维卷积层;其次,引入BN (BatchNormalization) 算法、定义batchnorm ()函数进行正则化,用以消除模型的过拟合问题;再次,定义activation ()函数,用于激活神经网络训练;最后,定义res_block () 函数,基础块常用Conv+BN+Relu+Conv+BN侧边分支的模式,达到修复目的。通过GlobalMaxPooling1D ()对整个序列输出进行降维,定义softmax逻辑回归模型。最后一层卷积的特征图个数和字典大小相同,经过softmax函数处理之后,对每一个小片段对应的MFCC都能得到在整个字典上的概率分布。相关代码如下:

#定义多层因果空洞卷积MFCC一维,使用conv1d
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)
#加速神经网络训练BN算法
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])
    #tanh激活函数
    ha = activation(batchnorm(conv1d(h0, filters, 1, 1)), 'tanh')
    hs = activation(batchnorm(conv1d(h0, filters, 1, 1)), 'tanh')
    return Add()([ha, inputs]), hs
#tanh激活函数
h0 = 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)
#Relu激活函数
h1 = activation(Add()(shortcut), 'relu')
h1 = activation(batchnorm(conv1d(h1, filters, 1, 1)), 'relu') 
h1 = batchnorm(conv1d(h1, num_class, 1, 1))
h1 = GlobalMaxPooling1D()(h1)  #通过GlobalMaxPooling1D对整个序列输出进行降维
Y = activation(h1, 'softmax')  #softmax逻辑回归模型

(2) 优化损失函数

确定模型架构,进行编译。这是多类别的分类问题,故使用CTC(Connectionist temporalclassification) 算法计算损失函数。由于所有标签都带有相似的权重,故使用精确度作为性能指标。相关代码如下:

#Adam优化算法
optimizer = Adam(lr=0.01, clipnorm=5)
#模型输入/输出
model = Model(inputs=X, outputs=Y)
#模型损失和准确率
model.compile(loss='categorical_crossentropy', optimizer=optimizer, metrics=['accuracy'])
#模型保存路径
checkpointer = ModelCheckpoint(filepath='D:/homework/dialect/fangyan.h5', verbose=0)
lr_decay = ReduceLROnPlateau(monitor='loss', factor=0.2, patience=1, min_lr=0.000)

模型训练及保存

在定义模型架构和编译之后,通过训练集训练模型,使模型进行方言分类。这里将使用训练集和验证集拟合并保存模型。

(1) 模型训练

相关代码如下:

#分批读取数据
history = model.fit_generator(
	#训练集批处理器
    generator=batch_generator(X_train, Y_train),
	#每轮训练的数据量
    steps_per_epoch=len(X_train), 
    epochs=epochs, 
	#测试集批处理器
    validation_data=batch_generator(X_dev, Y_dev), 
    validation_steps=len(X_dev) 
    callbacks=[checkpointer, lr_decay])

其中,一批(batch)就是在一次前向/后向传播过程用到的训练样例数量,即一次用1180条语音数据进行训练,共训练11800条语音数据,如图所示。

在这里插入图片描述
通过观察训练集和测试集的损失函数、准确率的大小评估模型训练程度,制定模型训练的进一步决策。训练集和测试集的损失函数(或准确率)不变且基本相等为模型训练的最佳状态。训练过程中保存的准确率和损失函数以图片的形式显示,方便观察。

train_loss = history.history['loss']#训练集损失函数
valid_loss = history.history['val_loss']#验证集损失函数
#画图
plt.plot(train_loss, label='训练')
plt.plot(valid_loss, label='验证')
plt.legend(loc='upper right')
plt.xlabel('训练次数')
plt.ylabel('损失')
plt.show()
train_acc = history.history['acc']#训练集精确度
valid_acc = history.history['val_acc']#验证集精确度
#画图
mpl.rcParams['font.sans-serif'] = ['SimHei']
plt.plot(train_acc, label='训练')
plt.plot(valid_acc, label='验证')
plt.legend(loc='upper right')
plt.xlabel('训练次数')
plt.ylabel('精确度')
plt.legend()
plt.show()

(2) 模型保存

相关代码如下:

#保存模型
model.save('fangyan.h5') #HDF5文件

模型被保存后,可以被重用,也可以移植到其他环境中使用。为类别预测,将字典保存为.pkl文件,相关代码如下:

#保存字典
with open('resources.pkl', 'wb') as fw:
    pickle.dump([class2id, id2class, mfcc_mean, mfcc_std], fw)

2. 语音识别

本部分包含数据预处理、模型构建、模型训练及模型保存。

数据预处理

数据集来源地址为www.openslr.org/18/,包含100~400KB的语音数据集13388条。下载数据集并导入,通过使用glob ()函数来实现。相关代码如下:

#加载trn,读取语音对应的文本文件
text_paths = glob.glob(r'D:/homework/language/language/data/*.trn')
#导入数据集
total = len(text_paths)  #统计文本个数
print(total)  #打印数据集总数
with open(text_paths[0], 'r', encoding='utf8') as fr:
    lines = fr.readlines()
    print(lines)  #打印第一条数据中内容

语音识别数据集中有表示语音的.wav文件,也有表示标音的.trn文件。打印第一条数据, 输出如图所示。

在这里插入图片描述

对下载的语音数据集进行整理,将文本中的中文保存到texts的列表中、每个音频的路径保存到paths列表中,相关代码如下:

#提取文本内容和语音文件路径,去掉空白格
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'))#除去.trn的文件就是.wav音频文件
print(paths[0], texts[0])#打印语音文件所在路径以及对应的文本内容

下载语音数据集并进行预处理。定义处理语音数据和可视化语音数据集的两个函数。在处理语音数据的函数中,去除语音文件两端的静音部分。处理语音数据部分函数代码如下:

def load_and_trim(path):
    audio, sr = librosa.load(path)  #读取音频
    energy = librosa.feature.rms(audio)  #计算能量
    frames = np.nonzero(energy >= np.max(energy) / 5) #最大能量的1/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
#可视化语音数据集部分函数代码
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')#x轴为时间
    plt.ylabel('Audio Amplitude')  #y轴为音频高度
    plt.show()
    feature = mfcc(audio, sr, numcep=mfcc_dim, nfft=551)  #计算MFCC特征
    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 path

以可视化第一条语音数据为例,结果如图所示。
在这里插入图片描述

将音频文件的MFCC特征进行归一化处理并建立字典,相关代码如下:

features=[(feature-mfcc_mean)/(mfcc_std + 1e-14) for feature in features]
#建立字典
chars = {}
for text in texts:
    for c in text:
        chars[c] = chars.get(c, 0) + 1
chars = sorted(chars.items(), key=lambda x: x[1], reverse=True)
chars = [char[0] for char in chars]
print(len(chars), chars[:100])   #打印随机100段音频中汉字数量
char2id = {c: i for i, c in enumerate(chars)}
id2char = {i: c for i, c in enumerate(chars)}

对数据进行划分,将数据总数的90%作为训练集。定义产生批数据的函数batch_generator()。相关代码如下:

data_index = np.arange(total)
np.random.shuffle(data_index)   #将索引打乱
train_size = int(0.9 * total)   #训练数据占90%
test_size = total - train_size
train_index = data_index[:train_size]            #切分出来训练数据的索引
test_index = data_index[train_size:]             #切分出来测试数据的索引
X_train = [features[i] for i in train_index]   #取出训练音频的MFCC特征
Y_train = [texts[i] for i in train_index]       #取出训练的标签
X_test = [features[i] for i in test_index]      #取出测试音频的MFCC特征
Y_test = [texts[i] for i in test_index]          #取出测试的标签

模型构建

数据加载进模型后,需要定义模型结构,并优化损失函数。

(1) 定义模型结构

定义WaveNet网络。使用多层因果空洞卷积处理数据,模型结构使用方法和方言分类部分大致相同。

(2) 损失函数及模型优化
确定模型架构后进行编译。这是多类别的分类问题,故使用CTC ( Connectionist temporalclassification) 算法计算损失函数。相关代码如下:

def calc_ctc_loss(args):  #CTC损失函数
	y, yp, ypl, yl = args
	return 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)

模型训练及保存

在定义模型架构和编译之后,通过训练集训练模型,使模型识别语音。这里,将使用训练集和验证集来拟合并保存模型。

1) 模型训练

相关代码如下:

#分批读取数据
history = model.fit_generator(
	#训练集批处理器
    generator=batch_generator(X_train, Y_train),
	#每轮训练的数据量
    steps_per_epoch=len(X_train), 
    epochs=epochs, 
	#测试集批处理器
    validation_data=batch_generator(X_dev, Y_dev), 
    validation_steps=len(X_dev) 
    callbacks=[checkpointer, lr_decay])

一批(batch) 数据不超过753条,如图所示。

在这里插入图片描述

相关代码如下:

#训练集损失
train_loss = history.history['loss']
#验证集损失
valid_loss = history.history['val_loss']
#绘制损失函数图像
mpl.rcParams['font.sans-serif'] = ['SimHei']  #默认字体黑体
plt.plot(np.linspace(1, epochs, epochs), train_loss, label='训练')
plt.plot(np.linspace(1, epochs, epochs), valid_loss, label='验证')
plt.legend(loc='upper right')
plt.xlabel('训练次数')
plt.ylabel('损失')
plt.legend()
plt.show()

2) 模型保存

为后续图形用户界面设计导入,将模型保存为.h5格式的文件。

相关代码如下:

#模型保存
sub_model.save('asr.h5')

将字典保存为pkl格式文件,相关代码如下:

#字典保存
with open('dictionary.pkl', 'wb') as fw:
    pickle.dump([char2id, id2char], fw)

模型及字典被保存后,可以被重用,也可以移植到其他环境中使用。

3. 模型测试

在设计好的图形用户界面中导入模型,选取语音文件,展示原始波形及MFCC特征图。可选择实现语音识别和方言分类两个功能。图形用户主要包括3个界面:功能选择界面、语言识别功能实现界面和方言识别功能实现界面。

功能选择界面

相关操作如下

(1)设置功能选择界面为根窗体。初始化功能选择界面的各个属性,相关操作如下:

#设置功能选择界面的大小及标题
root = Tk()
root.geometry('300x450')
root.title('语音识别及方言分类')
#界面展示
mainloop()

根窗体是图像化应用程序的根控制器,是Tkinter底层控件的实例。导入Tkinter模块后,调用Tk()函数初始化根窗体实例,用title()函数设置标题文字,用geometry()函数设置窗体大小(以像素为单位)。将根窗体置于主循环中,除非用户关闭,否则程序始终处于运行状态。主循环的根窗体中,可持续呈现其他可视化控件实例,监测事件的发生并执行相应的处理程序。

(2)设置界面需展示的控件及其相应属性和布局,相关操作如下:

#设置文本标签,提示用户欢迎信息   
lb = Label(root, text='欢迎使用!',font=('华文新魏',22))
lb.pack()
#设置文本标签位置
lb.place(relx=0.15, rely=0.2, relwidth=0.75, relheight=0.3)
#设置两个提示按钮及文本字体大小
btn = Button(root, text='语音识别',font=('华文新魏',12),command=asr)
btn.pack()
#设置第一个按钮位置
btn.place(relx=0.3, rely=0.5, relwidth=0.4, relheight=0.1)
btn_btn = Button(root, text='方言分类',font=('华文新魏',12),command = dialect)
btn_btn.pack()
#设置第二个按钮位置
btn_btn.place(relx=0.3, rely=0.65, relwidth=0.4, relheight=0.1)

标签实例lb,按钮实例btn和btn_ btn在父容器root中实例化,设置text (文本)、font (字体)和命令属性;在实例化控件时,实例的属性以“属性=属性值”的形式枚举列出,不区分先后次序。属性值通常用文本形式表示。

按钮主要是为响应鼠标单击事件触发运行程序所设的,除控件共有属性外,命令(command) 是最重要的属性。通常将要触发执行的程序以函数形式预先定义,直接调用函数,参数表达式为“command=函数名”,函数名后面不加括号,不传递参数。故设置命令属性以触发与按钮文本相对应的功能实现界面。

使用place () 方法配合relx、rely和relheight, relwidth参数所得到的界面可自适应根窗体尺寸的大小。

语言识别功能实现界面

相关操作如下:

(1)调用Toplevel () 函数,设置二级界面,用于语音识别功能的实现。

(2)实例化所需文本标签、图像标签、文本及按钮控件。

(3)定义函数用于获取用户输入数字,选取后续进行识别语音文件。

(4) 定义函数读取语音文件,进行一系列处理后,绘制原始波形及MFCC特征两个图像,并保存到本地。

#语音文件初始处理,去除两端静音
        audio, sr = librosa.load(wavs[int(x)]) #读取语音文件
        energy = librosa.feature.rms(audio)     #计算语音文件能量
	    #判定能量小于最大能量1/5为静音
        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] #去除两端静音
        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.savefig('E:/北邮学习/2020课件/信息系统设计/语音识别/原始波形.png')  
        #feature.shape二维数组(切片数量,维度)
        #指定音频文件、采样率、mfcc维度,获取MFCC特征
        feature = mfcc(audio, sr, numcep=mfcc_dim, nfft=551) 
        #绘制MFCC特征图
        fig = plt.figure(figsize=(12, 5))#图像大小
        ax = fig.add_subplot(111) #分块绘图
	    #绘制mfcc特征
        im = ax.imshow(feature, cmap=plt.cm.jet, aspect='auto')
        plt.title('Normalized MFCC') #图像标题
        plt.ylabel('Time') #图像纵坐标
        plt.xlabel('MFCC Coefficient') #图像横坐标
        #右侧colorbar绘制
        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); #图像横坐标值设置
        #保存MFCC特征图像
        plt.savefig('E:/北邮学习/2020课件/信息系统设计/语音识别/mfcc.png')

(5) 定义两个函数,分别用于在界面中展示MFCC特征图和原始波形图。

(6)定义函数,取出语音文件标注的文本,并在界面中展示。

(7)定义函数,加载训练好的模型进行语音识别,将识别结果进行输出展示。

audio, sr = librosa.load(wavs[int(x)]) #读取语音文件
energy = librosa.feature.rms(audio) #计算语音文件能量
#判定能量小于最大能量1/5为静音
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) #获取mfcc特征
X_data = (X_data - mfcc_mean) / (mfcc_std + 1e-14) #mfcc归一化处理
#加载模型进行语音识别
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()
#实例化lb标签,在界面中展示识别文本结果
lb3 = Label(top, text='识别结果:'+''.join([id2char[i] for i in pred_ids]))
lb3.place(relx=0.1, rely=0.96, relwidth=0.75, relheight=0.03)

(8)设置按钮控件的command属性,与上述定义好的函数相联系,确保正确触发与按钮相对应的可实现功能。

方言分类功能实现界面

相关操作如下:

(1) 调用Toplevel () 函数,设置二级界面,用于方言分类功能的实现。

(2) 实例化所需文本标签、图像标签、文本及按钮控件。

(3) 定义函数,随机选取后续进行方言分类的语音文件。

(4) 定义函数,读取语音文件,进行一系列处理后,绘制原始波形及MFCC特征两个图像,并保存到本地。

#定义函数,加载语音文件,去除两端静音,对长语音进行片段切片
    def load_and_trim(path, sr=16000):
        audio = np.memmap(path, dtype='h', mode='r') #对大文件分段读取
        audio = audio[2000:-2000]
        audio = audio.astype(np.float32)
        energy = librosa.feature.rms(audio) #计算能量
	    #最大能量的1/5视为静音
        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] #去除静音后的语音文件
        slices = [] #存储划分为小于3s大于1s的切片
        for i in range(0, audio.shape[0], slice_length):            
            s = audio[i: i + slice_length] #切分为3s片段
            if s.shape[0] >= min_length:
                slices.append(s) #去除小于1s的片段    
        return audio, slices 
#定义函数以读取语音文件,绘制原始波形及MFCC特征两个图像,并保存到本地
    def run2():
	    #从文本框中提取随机选取的语音文件路径
        path = txt1.get("0.0","end")
        path = path.strip("\n").split(" ")[0]
        audio, slices = 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.savefig('E:/北邮学习/2020课件/信息系统设计/原始波形.png') 
        #绘制MFCC特征图像
        feature = mfcc(audio, sr, numcep=mfcc_dim) #提取MFCC特征
        fig = plt.figure(figsize=(12, 5))#图像大小
        ax = fig.add_subplot(111)
        im = ax.imshow(feature, cmap=plt.cm.jet, aspect='auto') #绘制MFCC
        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);#设置横坐标间隔
        #保存mfcc特征图像
        plt.savefig('E:/北邮学习/2020课件/信息系统设计/mfcc.png') 

(5) 定义两个函数,分别用于在界面中展示MFCC特征图和原始波形图。

(6) 定义函数,取出语音文件所属类别并在界面中展示。

(7) 定义函数,加载训练好的模型进行方言分类,将识别结果进行输出展示。

    path = txt1.get("0.0","end")
    path = path.strip("\n").split(" ")[0]
    #去除两端静音,并切分为片段
    audio, slices = load_and_trim(path)
    #获取mfcc特征
    X_data = [mfcc(s, sr, numcep=mfcc_dim) for s in slices] 
    #MFCC归一化处理
    X_data = [(x - mfcc_mean) / (mfcc_std + 1e-14) for x in X_data] 
    maxlen = np.max([x.shape[0] for x in X_data])
    X_data = pad_sequences(X_data, maxlen, 'float32', padding='post', value=0.0)
     #加载模型进行方言分类
    prob = model.predict(X_data)
    prob = np.mean(prob, axis=0)
    pred = np.argmax(prob)
    prob = prob[pred]
    pred = id2class[pred]
    #实例化lb标签,在界面中展示识别预测类别
    lb3 = Label(top1, text='预测类别:'+ pred + '  Confidence:'+ str(prob))
    lb3.place(relx=0.1, rely=0.96, relwidth=0.75, relheight=0.03)

(8) 设置按钮控件的command属性,与上述定义好的函数相联系,确保正确触发与按钮相对应的可实现功能。

系统测试

本部分包括训练准确率、测试效果及模型应用。

1. 训练准确率

语音识别任务,预测模型训练比较成功。随着训练次数的增多,模型在训练数据、测试数据上的损失逐渐收敛,最终趋于稳定,如图所示。

在这里插入图片描述

方言分类中,在训练集上测试准确率超过了98%,意味着这个预测模型训练比较成功。随着训练次数的增多,模型在训练数据上的损失和准确率逐渐收敛,最终趋于稳定;但在测试数据上的损失和准确率不够稳定,有一定波动,如图4和图5所示。

在这里插入图片描述

图4 方言分类模型损失

在这里插入图片描述

图5 方言分类模型准确度

2. 测试效果

对测试集进行测试,识别的文本、分类标签与原始数据进行显示和对比,如下图所示。

在这里插入图片描述

由结果可以看出,模型可以实现语音识别及方言分类。

3. 模型应用

本部分包括图形用户界面使用说明和测试效果。

1. 图形用户界面使用说明

编译及运行.py文件后,初始界面如图所示。

在这里插入图片描述

界面从上至下分别是文本提示语和两个按钮。单击[语音识别]按钮,可以弹出二级界面——语音识别功能实现界面,如图6所示;单击[方言分类]按钮,可以弹出二级界面——方言分类功能实现界面,如图7所示。

界面从上至下分别是文本提示语、输入框、按钮和文本框。在输入框中输入数字,单击[选取对应语音文件]按钮,选择本次进行语音识别的文件,文本框中输出该文件路径;单击[保存对应MFCC特征图及原始波形图]按钮,保存对应图像到本地;单击[MFCC特征图]按钮和[原始波形图]按钮以显示保存到本地的图像;单击[标注文本]按钮,显示对应标注文件的文本;单击[识别结果]按钮,进行预测,显示预测的文本结果。
在这里插入图片描述

图6 语言识别初始界面

界面从上至下分别是文本提示语、按钮和文本框。根据文本提示,单击[选取语音文件]按钮,随机选择本次进行语音识别的文件,文本框中输出该文件路径;单击[保存对应MFCC特征图及原始波形图]按钮,保存对应图像到本地后;单击| [MFCC特征图]和[原始波形图]按钮以显示保存到本地的图像;单击[标注类别]按钮,显示文件对应的所属类别;单击[识别类别]按钮,进行预测,显示预测的类别结果。

在这里插入图片描述

图7 方言分类初始界面

2.测试效果

图形用户界面的语音识别测试结果如图所示。

在这里插入图片描述

图形用户界面的方言分类测试结果如图所示。

在这里插入图片描述

工程源代码下载

详见本人博客资源下载页


其它资料下载

如果大家想继续了解人工智能相关学习路线和知识体系,欢迎大家翻阅我的另外一篇博客《重磅 | 完备的人工智能AI 学习——基础知识学习路线,所有资料免关注免套路直接网盘下载
这篇博客参考了Github知名开源平台,AI技术平台以及相关领域专家:Datawhale,ApacheCN,AI有道和黄海广博士等约有近100G相关资料,希望能帮助到所有小伙伴们。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

基于Python+WaveNet+CTC+Tensorflow智能语音识别与方言分类—深度学习算法应用(含全部工程源码) 的相关文章

  • 保存为 HDF5 的图像未着色

    我目前正在开发一个将文本文件和 jpg 图像转换为 HDF5 格式的程序 用HDFView 3 0打开 似乎图像仅以灰度保存 hdf h5py File Sample h5 img Image open Image jpg data np
  • Django 的内联管理:一个“预填充”字段

    我正在开发我的第一个 Django 项目 我希望用户能够在管理中创建自定义表单 并向其中添加字段当他或她需要它们时 为此 我在我的项目中添加了一个可重用的应用程序 可在 github 上找到 https github com stephen
  • 如何使用 opencv.omnidir 模块对鱼眼图像进行去扭曲

    我正在尝试使用全向模块 http docs opencv org trunk db dd2 namespacecv 1 1omnidir html用于对鱼眼图像进行扭曲处理Python 我正在尝试适应这一点C 教程 http docs op
  • Python getstatusoutput 替换不返回完整输出

    我发现了这个很棒的替代品getstatusoutput Python 2 中的函数在 Unix 和 Windows 上同样有效 不过我觉得这个方法有问题output被构建 它只返回输出的最后一行 但我不明白为什么 任何帮助都是极好的 def
  • 将 python2.7 与 Emacs 24.3 和 python-mode.el 一起使用

    我是 Emacs 新手 我正在尝试设置我的 python 环境 到目前为止 我已经了解到在 python 缓冲区中使用 python mode el C c C c将当前缓冲区的内容加载到交互式 python shell 中 显然使用了什么
  • 使用Python请求登录Google帐户

    在多个登录页面上 需要谷歌登录才能继续 我想用requestspython 中的库以便让我自己登录 通常这很容易使用requests库 但是我无法让它工作 我不确定这是否是由于 Google 做出的一些限制 也许我需要使用他们的 API 或
  • 我可以在我的机器上同时安装 python 2.7 和 3.5 的tensorflow吗?

    目前我通过 Anaconda 在我的机器 MAC OX 上安装了 Python 2 7 Python 3 5 Tensorflow for Python 3 5 我也想在我的机器上安装 Tensorflow for Python 2 7 当
  • 如何使用 Pandas、Numpy 加速 Python 中的嵌套 for 循环逻辑?

    我想检查一下表的字段是否TestProject包含了Client端传入的参数 嵌套for循环很丑陋 有什么高效简单的方法来实现吗 非常感谢您的任何建议 def test parameter a list parameter b list g
  • Python beautifulsoup 仅限 1 级文本

    我看过其他 beautifulsoup 得到相同级别类型的问题 看来我的有点不同 这是网站 我正试图拿到右边那张桌子 请注意表的第一行如何展开为该数据的详细细分 我不想要那个数据 我只想要最顶层的数据 您还可以看到其他行也可以展开 但在本例
  • 从Python中的字典列表中查找特定值

    我的字典列表中有以下数据 data I versicolor 0 Sepal Length 7 9 I setosa 0 I virginica 1 I versicolor 0 I setosa 1 I virginica 0 Sepal
  • Python,将函数的输出重定向到文件中

    我正在尝试将函数的输出存储到Python中的文件中 我想做的是这样的 def test print This is a Test file open Log a file write test file close 但是当我这样做时 我收到
  • 如何使用 Mysql Python 连接器检索二进制数据?

    如果我在 MySQL 中创建一个包含二进制数据的简单表 CREATE TABLE foo bar binary 4 INSERT INTO foo bar VALUES UNHEX de12 然后尝试使用 MySQL Connector P
  • 在 Sphinx 文档中*仅*显示文档字符串?

    Sphinx有一个功能叫做automethod从方法的文档字符串中提取文档并将其嵌入到文档中 但它不仅嵌入了文档字符串 还嵌入了方法签名 名称 参数 我如何嵌入only文档字符串 不包括方法签名 ref http www sphinx do
  • Numpy - 根据表示一维的坐标向量的条件替换数组中的值

    我有一个data多维数组 最后一个是距离 另一方面 我有距离向量r 例如 Data np ones 20 30 100 r np linspace 10 50 100 最后 我还有一个临界距离值列表 称为r0 使得 r0 shape Dat
  • pip 列出活动 virtualenv 中的全局包

    将 pip 从 1 4 x 升级到 1 5 后pip freeze输出我的全局安装 系统 软件包的列表 而不是我的 virtualenv 中安装的软件包的列表 我尝试再次降级到 1 4 但这并不能解决我的问题 这有点类似于这个问题 http
  • 仅第一个加载的 Django 站点有效

    我最近向 stackoverflow 提交了一个问题 标题为使用mod wsgi在apache上多次请求后Django无限加载 https stackoverflow com questions 71705909 django infini
  • 如何使用原始 SQL 查询实现搜索功能

    我正在创建一个由 CS50 的网络系列指导的应用程序 这要求我仅使用原始 SQL 查询而不是 ORM 我正在尝试创建一个搜索功能 用户可以在其中查找存储在数据库中的书籍列表 我希望他们能够查询 书籍 表中的 ISBN 标题 作者列 目前 它
  • 如何在 pygtk 中创建新信号

    我创建了一个 python 对象 但我想在它上面发送信号 我让它继承自 gobject GObject 但似乎没有任何方法可以在我的对象上创建新信号 您还可以在类定义中定义信号 class MyGObjectClass gobject GO
  • 在本地网络上运行 Bokeh 服务器

    我有一个简单的 Bokeh 应用程序 名为app py如下 contents of app py from bokeh client import push session from bokeh embed import server do
  • Pandas 每周计算重复值

    我有一个Dataframe包含按周分组的日期和 ID df date id 2022 02 07 1 3 5 4 2022 02 14 2 1 3 2022 02 21 9 10 1 2022 05 16 我想计算每周有多少 id 与上周重

随机推荐

  • 前端工程化详解——理解与实践前端工程化

    前言 前端工程化一直是一个老生常谈的问题 不管是面试还是我们在公司做基建都会经常提到前端工程化 那么为什么经常会说到前端工程化 并没有听过后端工程化 Java工程化或者Python工程化呢 我们理解的前端工程化是不是一直都是Webpack的
  • 回望2001年的雪鸟城:引发全球软件革命的“敏捷宣言”是如何诞生的?

    将人们置于流程之上 专注于开发可以工作的软件 而不是软件的文档 和你的客户一起工作 而不是为一份合同而争吵 在此过程中 要对改变持开放态度 编者按 敏捷 Agile 这个对于开发真来说不在陌生的概念 已经提出了近17年了 其背后的哲学理念也
  • [CSDN竞赛]第五期参赛回顾

    CSDN竞赛 第五期参赛回顾 体验感想 第一次参加 本来有点小期待 那天还起晚了 结果登录不上去 发现大家都有问题 对我来说反而是好事 本来早上没有下午晚上更加精神 下面是提的建议 上次的登录问题 希望官方下次不要再出现 一定要准备充足 为
  • Unity Shader:用几何着色器实现复联3灭霸的终极大招灰飞烟灭

    图1 正常渲染 图2 几何着色器粒子化特效进行中 图3 几何着色器粒子化特效进行中 1 用几何着色器进行图元转换 在OpenGL渲染管线中 几何着色器Geometry Shader有一个独一无二的功能 既是图元转换 可简单理解为对基本图元点
  • 微信小程序默认下拉刷新和自定义下拉刷新的方式

    1 默认下拉刷新 在指定页面对应的 json配置文件中加入 enablePullDownRefresh true backgroundTextStyle dark 在对应的 js文件中 写入onPullDownRefresh 如果存在则替换
  • 手把手教你做一套“能源管理系统” A

    hello 大家好 我是CC 今天让CC来手把手教大家设计一套 能源管理系统 上个视频咱们有说到 能源管理系统 的范围很广 可以粗分为面向供给侧和面向消费侧 其中面向消费侧又可以分为 家庭能源管理系统HEMS 社区 园区能源管理系统CEMS
  • EQ频响曲线绘制和DRC特性曲线绘制

    目录 1 EQ 系数计算和频响曲线绘制 1 1 基本流程 1 2 EQ参数输入 1 3 滤波器系数计算 1 4 频率响应计算 1 5 曲线绘制 2 DRC特性曲线绘制 2 1 基本流程 2 2 参数输入 2 3 增益计算 2 4 静态特性曲
  • Java学习书籍推荐(步步为营)

    概述 本文只要介绍 Java学习的书籍 进阶之路 始于行动 编程重在理解加多实践 在当今快速发展的时代 要学会站在巨人的肩膀上 吸取经验 看书就是最快与最低成本的进阶之路 史上没有最好的书籍 只有适合自己的书籍 小伙伴们开始行动吧 Java
  • Qt5.14.2中使用QCamera实现切换相机、分辨率和图像捕获功能

    demo中主要涉及的Qt类有 相机类QCamera 取景器类QCameraViewfinder 图像捕获类QCameraImageCapture 因此添加模块multimedia multimediawidgets QT core gui
  • 在 uni-app 中使用 webview 打开本地文件,打开不成功

    在 uni app 中使用 webview 打开本地文件 打开不成功出现套娃现象的解决方案 小程序仅支持加载网络网页 不支持本地html 排查本地文件是否按照官方给出的路径建立的 uni app 项目根目录 gt hybrid gt htm
  • 全民奇迹修复云服务器跨服,越过服务器来打你 全民奇迹跨服战玩法全面解析...

    在全民奇迹当中 玩家与玩家之间的PK往往是解决问题最好的方法 一言不合就开打才是所有奇迹勇士的特点 本篇全民奇迹跨服战玩法全面解析 973手游网小编就来为大家说说跨服战 全民奇迹 16人的对决 幻影寺院 实力的对决 在幻影寺院中 玩家被分为
  • bluez——dbus接口api

    bluez dbus接口api bluez的api接口的说明文档在 doc 路径下 我这先重点分析下adapter agent和device这几个文件 这里面包含的是常用的api 1 agent c 这里现在注册的几个dbus方法 void
  • Winform SplitContainer控件可调整大小

    IsSpliterFixed属性设为False FixedPannel属性设为Pannel1 要固定的面板的名称 之后鼠标移动到控件中间的分隔线 就可以调整大小了
  • 多项式加法

    多项式的加法 一 创建链表 二 初始化链表 三 打印链表 四 打印结点 五 添加数据 六 相加 七 测试代码 八 测试结果 一 创建链表 typedef struct LinkNode int coefficient int exponen
  • MIT6.824分布式系统lecture1笔记:Intro,MapReduce

    lecture1先对分布式系统的设计进行了概述 然后介绍了MapReduce的案例 Intro 为什么要使用分布式系统 1 追求高性能 通过分布式系统进行并行计算 2 使系统具有容错性 一台计算机计算错误 可以转移到另一台计算机 3 一些问
  • Docker部署Redis单机版

    1 拉取镜像 docker pull redis latest 2 创建挂载目录 mkdir r home egn redis conf mkdir r home egn redis data 3 修改配置文件 新建redis conf 节
  • 关于java.lang.NoClassDefFoundError: Could not initialize class xxx错误的原因和处理办法

    关于NoClassDefFoundError错误出现的原因有多种 网上其他博主也给出各种答案 但说的都比较广泛 这里博主说一下由于初始化失败而造成的NoClassDefFoundError错误 博主在一个Test这个类中使用了静态代码块 类
  • C#集合总结

    1 为什么引入集合 因为数组长度是固定的 为了建立一个动态的 数组 所以引入了集合 2 为什么引入ArrayList 非泛型集合 ArrayList可以填补数组的不足 进行元素的动态维护 数组的长度是固定的 而ArrayList的容量可以根
  • Android WebSocket状态管理框架 - WebSocketGo

    阅读本文需要 Integer MAX VALUE 分钟 故事背景 笔者所在的公司主营业务是智能家居 笔者在公司负责的Android端App的开发 关于智能家居 估计现在百分之八九十的童鞋都听过 但真正了解或者使用过的估计就不占多数了 本文不
  • 基于Python+WaveNet+CTC+Tensorflow智能语音识别与方言分类—深度学习算法应用(含全部工程源码)

    目录 前言 总体设计 系统整体结构图 系统流程图 运行环境 Python 环境 Tensorflow 环境 模块实现 1 方言分类 数据下载及预处理 模型构建 模型训练及保存 2 语音识别 数据预处理 模型构建 模型训练及保存 3 模型测试