CNN 用于音素识别

数据挖掘 分类 喀拉斯 训练 卷积神经网络 音频识别
2021-09-22 12:50:43

我目前正在研究这篇论文,其中 CNN 用于使用 log mel 滤波器组的视觉表示和有限权重共享方案进行音素识别。

log mel 滤波器组的可视化是一种表示和规范化数据的方式。他们建议将其可视化为具有 RGB 颜色的光谱图,我能想到的最接近的方法是使用matplotlibscolormap绘制它cm.jet他们(作为论文)还建议每个帧都应该与其 [static delta delta_delta] 滤波器组能量堆叠。这看起来像这样:

在此处输入图像描述

的输入由 15 帧的图像补丁集组成 [static delta delta_detlta] 输入形状将是 (40,45,3)

有限的权重共享包括将权重共享限制在特定的滤波器组区域,因为在不同的频率区域中对语音的解释不同,因此作为正常卷积应用的完整权重共享将不起作用。

他们对有限权重共享的实现包括控制与每个卷积层相关的权重矩阵中的权重。所以他们对完整的输入应用卷积。该论文仅应用了一个卷积层,因为使用多个卷积层会破坏从卷积层中提取的特征图的局部性。他们使用滤波器组能量而不是正常的 MFCC 系数的原因是因为 DCT 破坏了滤波器组能量的局部性。

在此处输入图像描述

我没有控制与卷积层相关的权重矩阵,而是选择实现具有多个输入的 CNN。所以每个输入都包含一个(小滤波器组范围,total_frames_with_deltas,3)。因此,例如,论文指出 8 的滤波器大小应该是好的,所以我决定滤波器组的范围为 8。所以每个小图像块的大小为 (8,45,3)。每个小图像块都是用步长为 1 的滑动窗口提取的——因此每个输入之间有很多重叠——每个输入都有自己的卷积层。

在此处输入图像描述

(input_3 , input_3, input3, 应该是 input_1, input_2, input_3 ...)

这样做可以使用多个卷积层,因为局部性不再是问题,因为它应用于滤波器组区域,这是我的理论。

该论文没有明确说明,但我猜他们在多个帧上进行音素识别的原因是有一些左上下文和右上下文,所以只有中间帧被预测/训练。所以在我的例子中,前 7 帧设置为左侧上下文窗口 - 中间帧正在接受训练,最后 7 帧设置为右侧上下文窗口。所以给定多个帧,只有一个音素被识别为中间。

我的神经网络目前看起来像这样:

def model3():

    #stride = 1
    #dim = 40
    #window_height = 8
    #splits = ((40-8)+1)/1 = 33
    next(test_generator())
    next(train_generator(batch_size))

    kernel_number = 200#int(math.ceil(splits))
    list_of_input = [Input(shape = (window_height,total_frames_with_deltas,3)) for i in range(splits)]
    list_of_conv_output = []
    list_of_conv_output_2 = []
    list_of_conv_output_3 = []
    list_of_conv_output_4 = []
    list_of_conv_output_5 = []
    list_of_max_out = []
    for i in range(splits):
        #list_of_conv_output.append(Conv2D(filters = kernel_number , kernel_size = (15,6))(list_of_input[i]))
        #list_of_conv_output.append(Conv2D(filters = kernel_number , kernel_size = (window_height-1,3))(list_of_input[i]))
        list_of_conv_output.append(Conv2D(filters = kernel_number , kernel_size = (window_height,3), activation = 'relu')(list_of_input[i]))
        list_of_conv_output_2.append(Conv2D(filters = kernel_number , kernel_size = (1,5))(list_of_conv_output[i]))
        list_of_conv_output_3.append(Conv2D(filters = kernel_number , kernel_size = (1,7))(list_of_conv_output_2[i]))
        list_of_conv_output_4.append(Conv2D(filters = kernel_number , kernel_size = (1,11))(list_of_conv_output_3[i]))
        list_of_conv_output_5.append(Conv2D(filters = kernel_number , kernel_size = (1,13))(list_of_conv_output_4[i]))
        #list_of_conv_output_3.append(Conv2D(filters = kernel_number , kernel_size = (3,3),padding='same')(list_of_conv_output_2[i]))
        list_of_max_out.append((MaxPooling2D(pool_size=((1,11)))(list_of_conv_output_5[i])))

    merge = keras.layers.concatenate(list_of_max_out)
    print merge.shape
    reshape = Reshape((total_frames/total_frames,-1))(merge)

    dense1 = Dense(units = 1000, activation = 'relu',    name = "dense_1")(reshape)
    dense2 = Dense(units = 1000, activation = 'relu',    name = "dense_2")(dense1)
    dense3 = Dense(units = 145 , activation = 'softmax', name = "dense_3")(dense2)
    #dense4 = Dense(units = 1, activation = 'linear', name = "dense_4")(dense3)


    model = Model(inputs = list_of_input , outputs = dense3)
    model.compile(loss="categorical_crossentropy", optimizer="SGD" , metrics = [metrics.categorical_accuracy])

    reduce_lr=ReduceLROnPlateau(monitor='val_loss', factor=0.1, patience=3, verbose=1, mode='auto', epsilon=0.001, cooldown=0)
    stop  = EarlyStopping(monitor='val_loss', min_delta=0, patience=5, verbose=1, mode='auto')

    print model.summary()

    raw_input("okay?")
    hist_current = model.fit_generator(train_generator(batch_size),
                        steps_per_epoch=10,
                        epochs = 10000,
                        verbose = 1,
                        validation_data = test_generator(),
                        validation_steps=1)
                        #pickle_safe = True,
                        #workers = 4)

所以..现在问题来了..

我一直在训练网络,并且只能获得最高为 0.17 的验证准确度,并且经过很多时期后的准确度最终为 1.0。 在此处输入图像描述 (目前正在制作剧情)

固定框架:

在此处输入图像描述 (情节仍在制作中)

我不知道为什么我没有得到更好的结果。为什么这么高的错误率?我正在使用其他人也使用的 TIMIT 数据集。那为什么我的结果会更糟?

很抱歉这篇长文——希望更多关于我的设计决策的信息会有所帮助——并帮助理解我是如何理解这篇论文的,以及我是如何应用的,这将有助于查明我的错误在哪里。

1个回答

可能是您的网络结构:

该论文指出,他们的实验是使用以下方法完成的:

conv
pool
dense
dense
dense(softmax)

所以对于 fws 来说是这样的:

def fws():
    #Input shape: (batch_size,40,45,3)
    #output shape: (1,15,50)
    # number of unit in conv_feature_map = splitd

    filter_size = 8
    pooling_size = 28
    stride_step = 2
    pool_splits = ((splits - pooling_size)+1)/2
    conv_featur_map = []
    pool_feature_map = []
    print "Printing shapes"


    list_of_input = [Input(shape = (window_height,total_frames_with_deltas,3)) for i in range(splits)]


    #convolution
    shared_conv = Conv2D(filters = 150, kernel_size = (filter_size,45), activation='relu')
    for i in range(splits):
        conv_featur_map.append(shared_conv(list_of_input[i]))

    #Pooling
    input = Concatenate()(conv_featur_map)
    input = Reshape((splits,-1))(input)
    pooled = MaxPooling1D(pool_size = pooling_size, strides = stride_step)(input)

    #reshape = Reshape((3,-1))(pooled)

    #fc
    dense1 = Dense(units = 1000, activation = 'relu',    name = "dense_1")(pooled)
    dense2 = Dense(units = 1000, activation = 'relu',    name = "dense_2")(dense1)
    dense3 = Dense(units = 50 , activation = 'softmax', name = "dense_3")(dense2)

更改 fws 中 for 循环的位置(将其向上移动 2 行)使其变为 lws(加上池化层的一些调整)。