问题背景:在多语种语音识别挑战赛上,训练数据包含6000条左右平均时长3s的语音数据,验证集也有6000条左右平均时长3s左右的语音数据,选取Mel Spectrogram + CNN +DNN 作为 baseline, 需要在CNN前端先生成对应定长的语音梅尔频谱图,按照以往的操作一般先遍历语音数据集将语音数据.wav转化为(M,N)维的语音频谱图,再创建一个(n,M,N)的矩阵来存放语音频谱集,但是这样操作存在一个问题就是这样得到的矩阵太大,例如在本次挑战赛,如果选取频谱图尺寸为(128,93),6000条语音数据生成的矩阵就包含(6000,128,93)共计67MB, 而在图像处理过程中,有时候遇到的数据量比这还要大,那么怎么应对这种情境呢?
使用keras 提供的 DataGenerator
不失为一种好办法。
完整框架如下:
1. DataGenerator类
class DataGenerator(keras.utils.Sequence):
def __init__(self,list_IDs,labels,batch_size=32,dim=(128,94),n_channels=1,n_classes=17,shuffle=True):
self.dim=dim
self.batch_size=batch_size
self.labels=labels
self.list_IDs=list_IDs
self.n_channels=n_channels
self.n_classes=n_classes
self.shuffle=shuffle
self.on_epoch_end()
def __len__(self):
return int(np.floor(len(self.list_IDs)/self.batch_size)) ##总共有多少组
def __getitem__(self, index):
indexes=self.indexes[index*self.batch_size:(index+1)*self.batch_size]
list_IDs_temp=[self.list_IDs[k] for k in indexes] ##得到List_IDs的分片范围
X,y=self.__data_generation(list_IDs_temp)
return X,y
def on_epoch_end(self):
self.indexes=np.arange(len(self.list_IDs)) ##indexs=[0,1,2,...,Len(List_IDs)]
if self.shuffle==True:
np.random.shuffle(self.indexes)
def __data_generation(self, list_IDs_temp):
X=np.empty((self.batch_size,*self.dim,self.n_channels))
y=np.empty((self.batch_size),dtype=int) ##根据自己的具体目录更改
for i,ID in enumerate(list_IDs_temp):
x=np.load(r'F:\Coding\Language_Identification\spectrogram\\'+ID+'.npy')
x=x.reshape(*x.shape,1)/(-100)
X[i,]=x
y[i,]=int(self.labels[ID][2:])-1
return X,keras.utils.to_categorical(y,num_classes=self.n_classes)
这个迭代器的流程是:
init函数传参,初始化类中重要的数据成员如:
dim 每张图片的维度,例如本例中dim=(128,93)
batch_size 批处理的数目,一般定2的次方,如64,128
list_IDs,是包含所有训练数据ID的列表,根据存储结构可以调整具体的ID格式,比如:
["train\\L0001-0000.npy","train\\L0001-0001.npy",......]
labels, labels与list_IDs相对应,是每个ID对应图片的标签,如:
{
"train\\L0001-0000.npy":"L0001",
"train\\L0001-0001.npy":"L0001",
...
}
n_channels,图片的通道数,单色图片=1,RGB图片自然就=3
n_classes与labels相对应,是整个训练集包含的分类种类,例如语种识别挑战赛中涉及的语种共计17种,因此n_classes=17。
在data_generation
中就根据n_classes来确定keras.utils.to_categorical(y,num_classes=self.n_classes)
的参数。
2. 类的实例化
有了以上定义,就可以利用DataGenerator
来生成我们的train_data_generator 以及dev_data_generator。
完整代码如下:
params = {'dim': (128,93),
'batch_size': 64,
'n_classes': 17,
'n_channels': 1,
'shuffle': True}
train_generator=DataGenerator(list_IDs=IDs_train,labels=Labels_train,**params)
dev_generator=DataGenerator(list_IDs=IDs_dev,labels=Labels_dev,**params)
##
from keras.models import Sequential
model=Sequential()
model.add(...)
model.add(...)
model.compile(...)
#########################
与常规模型训练不同的是使用datagenerator迭代器的模型训练不是model.fit
#########################
model.fit_generator(generator=train_generator,validation_data=dev_generator,epochs=5)