目录
- 前言
- 引言
- 总体设计
- 系统整体结构图
- 系统流程图
- 运行环境
- 模块实现
- 1. 数据预处理
- 1)数据介绍
- 2)数据测试
- 3)数据处理
- 相关其它博客
- 工程源代码下载
- 其它资料下载
前言
博主前段时间发布了一篇有关方言识别和分类模型训练的博客,在读者的反馈中发现许多小伙伴对方言的辨识和分类表现出浓厚兴趣。鉴于此,博主决定专门撰写一篇关于方言分类的博客,以满足读者对这一主题的进一步了解和探索的需求。上篇博客可参考:
《基于Python+WaveNet+CTC+Tensorflow智能语音识别与方言分类—深度学习算法应用(含全部工程源码)》
引言
本项目以科大讯飞提供的数据集为基础,通过特征筛选和提取的过程,选用WaveNet模型进行训练。旨在通过语音的梅尔频率倒谱系数(MFCC)特征,建立方言和相应类别之间的映射关系,解决方言分类问题。
首先,项目从科大讯飞提供的数据集中进行了特征筛选和提取。包括对语音信号的分析,提取出最能代表语音特征的MFCC,为模型训练提供有力支持。
其次,选择了WaveNet模型进行训练。WaveNet模型是一种序列生成器,用于语音建模,在语音合成的声学建模中,可以直接学习采样值序列的映射,通过先前的信号序列预测下一个时刻点值的深度神经网络模型,具有自回归的特点。
在训练过程中,利用语音的MFCC特征,建立了方言和相应类别之间的映射关系。这样,模型能够识别和分类输入语音的方言,并将其划分到相应的类别中。
最终,通过这个项目,实现了方言分类问题的解决方案。这对于语音识别、语音助手等领域具有实际应用的潜力,也有助于保护和传承各地区的语言文化。
总体设计
本部分包括系统整体结构图和系统流程图。
系统整体结构图
系统整体结构如图所示。
系统流程图
系统流程如图所示。
运行环境
本部分包括Python环境、TensorFlow环境、JupyterNotebook环境、PyCharm环境。
详见博客。
模块实现
本项目包括4个模块:数据预处理、模型构建、模型训练及保存、模型生成。下面分别给出各模块的功能介绍及相关代码。
1. 数据预处理
本部分包括数据介绍、数据测试和数据处理。
1)数据介绍
数据集网址为:challenge.xfyun.cn,向用户免费提供了3种方言(长沙话、南昌话、上海话),每种方言包括30人,每人200条数据,共计18000条训练数据,以及10人、每人50条,共计1500条验证数据。数据以pcm格式提供,可以理解为.wav文件去掉多余信息之后仅保留语音数据的格式。
2)数据测试
使用Audition进行语音测试,导出mp3格式进行检测,如图所示。
使用MATLAB得到该语音片段的波形和MFCC特征,相关代码如下:
[x, fs]=audioread('test.mp3');
bank=melbankm(24,256,fs,0,0.4,'m');
%Mel滤波器的阶数为24
%fft变换的长度为256,采样频率为8000Hz
%归一化mel滤波器组系数
bank=full(bank);
bank=bank/max(bank(:));
for k=1:12 %归一化mel滤波器组系数
n=0:23;
dctcoef(k,:)=cos((2*n+1)*k*pi/(2*24));
end
w=1+6*sin(pi*[1:12]./12);%归一化倒谱提升窗口
w=w/max(w);%预加重滤波器
xx=double(x);
xx=filter([1-0.9375],1,xx);%语音信号分帧
xx=enframe(xx,256,80);%对*256点分为一帧
%计算每帧的MFCC参数
for i=1:size(xx,1)
y=xx(i,:);
s=y'.*hamming(256);
t=abs(fft(s));%fft快速傅立叶变换
t=t.^2;
c1=dctcoef*log(bank*t(1:129));
c2=c1.*w';
m(i,:)=c2';
end
%求取差分系数
dtm=zeros(size(m));
for i=3:size(m,1)-2
dtm(i,:)=-2*m(i-2,:)-m(i-1,:)+m(i+1,:)+2*m(i+2,:);
end
dtm=dtm/3;
%合并mfcc参数和一阶差分mfcc参数
ccc=[m dtm];
%去除首尾两帧,因为这两帧的一阶差分参数为0
ccc=ccc(3:size(m,1)-2,:);
subplot(2,1,1)
ccc_1=ccc(:,1);
plot(ccc_1);title('MFCC');ylabel('幅值');
[h,w]=size(ccc);
A=size(ccc);
subplot(212) ;
plot([1,w],A);
xlabel('维数');
ylabel('幅值');
title('维数与幅值的关系')
运行代码,成功得到一段语音的波形片段和MFCC特征,如图1和图2所示。
3)数据处理
本部分包括数据处理过程中的相关代码。
(1)加载库。在实验过程中,通过查找发现Matplotlib包内没有中文字体,加载库之后添加参数设定或者更改Matplotlib默认字体可以解决。相关代码如下:
#-*- coding:utf-8 -*-
import numpy as np
import os
from matplotlib import pyplot as plt
#在实验过程中使用pyplot参数设置,使得图像可打印中文,且中文内容格式应该为u“内容”
plt.rcParams['font.sans-serif']=['SimHei'] #正常显示中文标签
plt.rcParams['axes.unicode_minus']=False
from mpl_toolkits.axes_grid1 import make_axes_locatable
%matplotlib inline
from sklearn.utils import shuffle #导入各种模块
import glob
import pickle
from tqdm import tqdm
from keras.models import Model
from keras.preprocessing.sequence import pad_sequences
from keras.layers import Input, Activation, Conv1D, Add, Multiply, BatchNormalization, GlobalMaxPooling1D, Dropout
from keras.optimizers import Adam
from keras.callbacks import ModelCheckpoint, ReduceLROnPlateau
from python_speech_features import mfcc
import librosa
from IPython.display import Audio
import wave
(2)加载pcm文件,共18000条训练数据,1500条验证数据,相关代码如下:
train_files = glob.glob('data/*/train/*/*.pcm')
dev_files = glob.glob('data/*/dev/*/*/*.pcm')
#glob.glob()用于查找符合特定规则的文件路径名,并返回所有匹配的文件路径列表
#其中“*”为匹配符,匹配多个字符
print(len(train_files), len(dev_files), train_files[0])
#读取代码成功,打印结果
(3)整理每条语音数据对应的分类标签,相关代码如下:
labels = {'train': [], 'dev': []}
#使用dict与list类型嵌套存储分类标签
#tqdm打印进度条,用于观察读取情况
for i in tqdm(range(len(train_files))):
path = train_files[i]
label = path.split('/')[1]
#使用split将path以“/”分隔的字符串进行切片,并选取第1个分片
labels['train'].append(label)
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']))
#读取代码成功,打印结果
(4)定义处理语音、pcm转wav、可视化语音的三个函数,由于语音片段长短不一,所以去除少于1s的短片段,对于长片段则切分为不超过3s的片段。相关代码如下:
mfcc_dim = 13
sr = 16000
min_length = 1 * sr
slice_length = 3 * sr
#语音处理函数
def load_and_trim(path, sr=16000):
audio = np.memmap(path, dtype='h', mode='r')
#使用numpy内的memmap函数读写大文件,返回对象可使用ndarray算法操作
audio = audio[2000:-2000]
audio = audio.astype(np.float32)
#astype实现dataframe类型转换
energy = librosa.feature.rmse(audio)
#librosa为音频处理包,使用feature.rmse求均方根误差
frames = np.nonzero(energy >= np.max(energy) / 5)
#nonzero()函数将布尔数组转为整数数组,用于进行下标运算
#nonzero()返回参数数组中值不为0的元素下标,返回类型是元组
#元组的每个元素均为一个整数数组,值为非零元素下标在对应帧的值
indices = librosa.core.frames_to_samples(frames)[1]
#将样本索引采样转换为帧
audio = audio[indices[0]:indices[-1]] if indices.size else audio[0:0]
slices = []
for i in range(0, audio.shape[0], slice_length):
s = audio[i: i + slice_length]
if s.shape[0] >= min_length:
slices.append(s)
#长度>3s进行切片,<1s过滤
return audio, slices
#文件格式处理,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)
fw.setframerate(sample_rate) #采样率
fw.writeframes(data) #写入
fw.close()
#语音可视化
def visualize(index, source='train'):
#可视化语音,默认可视化训练集内的语音,也可以选择参数“dev”可视化测试集
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))
#使用matplotlob库内的pyplot进行绘图
plt.figure(figsize=(12, 3))
plt.plot(np.arange(len(audio)), audio)
plt.title(u'未处理信号')
plt.xlabel(u'时间')
plt.ylabel(u'信号幅度值')
plt.show()#展示未处理的音频信号
feature = mfcc(audio, sr, numcep=mfcc_dim)
#提取MFCC特征
print('Shape of MFCC:',feature.shape)
#进行画图
fig = plt.figure(figsize=(12, 5))
#figsize指定figure的宽和高,单位为英寸
ax = fig.add_subplot(111)#subplot()为图像分区,参数111表示只有一张图
im = ax.imshow(feature,cmap=plt.cm.jet, aspect='auto')
#imshow热图绘制,通过色差、亮度展示数据的差异
plt.title(u'归一化MFCC')
plt.ylabel('时间')
plt.xlabel('MFCC参数')
plt.colorbar(im,cax=make_axes_locatable(ax).append_axes('right', size='5%', pad=0.05))
#给图配渐变色时,在图旁边把色标(colorbar)标注出来
#其中cax参数表示将要绘制颜色条的轴
ax.set_xticks(np.arange(0,13,2),minor=False);#设置横坐标刻度
plt.show()
wav_path = 'example.wav'
pcm2wav(path,wav_path)
return wav_path
Audio(visualize(2)) #调用函数选取其中一条语音信号进行可视化
读取代码成功可以得到一句长沙话对应的波形和MFCC特征,如图所示。
(5)整理数据,查看语音片段的长度分布,最后得到18890个训练片段,1632个验证片段。相关代码如下:
X_train = [] #参数设置
X_dev = []
Y_train = []
Y_dev = []
lengths = []
for i in tqdm(range(len(train_files))):
path = train_files[i]
audio, slices = load_and_trim(path) #取语音信号
lengths.append(audio.shape[0] / sr) #除以sr(=16000)换算成时间长度
for s in slices: #按照片段进行训练
X_train.append(mfcc(s, sr, numcep=mfcc_dim))
Y_train.append(labels['train'][i])
for i in tqdm(range(len(dev_files))): #输出参数
path = dev_files[i]
audio, slices = load_and_trim(path)
lengths.append(audio.shape[0] / sr)
for s in slices:
X_dev.append(mfcc(s, sr, numcep=mfcc_dim))
Y_dev.append(labels['dev'][i])
print(len(X_train), len(X_dev))
plt.hist(lengths, bins=100)
#matplotlib中的hist()函数,用于可视化生成直方图
plt.show()
读取代码成功,如图所示。
(6)将MFCC特征进行归一化处理,相关代码如下:
#矩阵堆叠,沿竖直方向矩阵堆叠
samples = np.vstack(X_train)
#计算每一列的平均值(axis=0)
mfcc_mean = np.mean(samples, axis=0)
#计算每一列的标准差(axis=0)
mfcc_std = np.std(samples, axis=0)
print(mfcc_mean)
print(mfcc_std)
#归一化处理
X_train = [(x - mfcc_mean) / (mfcc_std + 1e-14) for x in X_train]
X_dev = [(x - mfcc_mean) / (mfcc_std + 1e-14) for x in X_dev]
maxlen = np.max([x.shape[0] for x in X_train + X_dev])
X_train = pad_sequences(X_train, maxlen, 'float32', padding='post', value=0.0)
#pad_sequences对序列进行预处理
#maxlen参数为序列的最大长度,返回类型dtype为float32,“post”表示需要补0时在末尾补
X_dev = pad_sequences(X_dev, maxlen, 'float32', padding='post', value=0.0)
print(X_train.shape, X_dev.shape)
(7)对分类标签进行处理,相关代码如下:
from sklearn.preprocessing import LabelEncoder
from keras.utils import to_categorical
#将标签标准化
le = LabelEncoder()
#为非监督学习
Y_train = le.fit_transform(Y_train) #fit_transform()
Y_dev = le.transform(Y_dev)
print(le.classes_)
class2id = {c: i for i, c in enumerate(le.classes_)}
#enumerate将可遍历数据对象组合为索引序列
id2class = {i: c for i, c in enumerate(le.classes_)}
num_class = len(le.classes_)
Y_train = to_categorical(Y_train, num_class)
#keras内的to_categorical将类别向量转换为二进制矩阵类型表示
Y_dev = to_categorical(Y_dev, num_class)
print(Y_train.shape, Y_dev.shape)
#代码运行,获得分类标签的处理图
(8)定义产生批数据的迭代器,相关代码如下:
batch_size = 16
def batch_generator(x, y, batch_size=batch_size): #批次处理
offset = 0
while True:
offset += batch_size
if offset == batch_size or offset >= len(x):
#将序列的所有元素随机排序
x, y = shuffle(x, y)
offset = batch_size
X_batch = x[offset - batch_size: offset]
Y_batch = y[offset - batch_size: offset]
#yield返回生成器
yield (X_batch, Y_batch)
相关其它博客
基于Python+WaveNet+MFCC+Tensorflow智能方言分类—深度学习算法应用(含全部工程源码)(一)
基于Python+WaveNet+MFCC+Tensorflow智能方言分类—深度学习算法应用(含全部工程源码)(三)
基于Python+WaveNet+MFCC+Tensorflow智能方言分类—深度学习算法应用(含全部工程源码)(四)
工程源代码下载
详见本人博客资源下载页
其它资料下载
如果大家想继续了解人工智能相关学习路线和知识体系,欢迎大家翻阅我的另外一篇博客《重磅 | 完备的人工智能AI 学习——基础知识学习路线,所有资料免关注免套路直接网盘下载》
这篇博客参考了Github知名开源平台,AI技术平台以及相关领域专家:Datawhale,ApacheCN,AI有道和黄海广博士等约有近100G相关资料,希望能帮助到所有小伙伴们。