问题背景:在多语种语音识别挑战赛上,训练数据包含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)
Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐