CNN 后跟用于签名验证的 RNN 的训练和测试准确性不会增加

Training and Testing accuracy not increasing for a CNN followed by a RNN for signature verification

我目前正在进行在线签名验证。数据集具有 (x, 7) 的可变形状,其中 x 是一个人用来签名的点数。我有以下型号:

    model = Sequential()
    #CNN
    model.add(Conv1D(filters=64, kernel_size=3, activation='sigmoid', input_shape=(None, 7)))
    model.add(MaxPooling1D(pool_size=3))
    model.add(Conv1D(filters=64, kernel_size=2, activation='sigmoid'))

    #RNN
    model.add(Masking(mask_value=0.0))
    model.add(LSTM(8))
    model.add(Dense(2, activation='softmax'))

    opt = Adam(lr=0.0001)
    model.compile(optimizer=opt, loss='categorical_crossentropy', metrics=['accuracy'])
    model.summary()

    print(model.fit(x_train, y_train, epochs=100, verbose=2, batch_size=50))

    score, accuracy = model.evaluate(x_test,y_test, verbose=2)
    print(score, accuracy)

我知道它可能不是最好的模型,但这是我第一次构建神经网络。我必须使用 CNN 和 RNN,因为这是我的荣誉项目所必需的。目前,我达到了 0.5142 作为最高训练精度和 0.54 测试精度。我试过增加 epoch 的数量、改变激活函数、添加更多层、移动层、改变学习率和改变优化器。

请分享一些关于更改我的模型或数据集的建议。任何帮助深表感谢。

对于 CNN-RNN,一些有前途的尝试:

  • Conv1D 层activation='relu'kernel_initializer='he_normal'
  • LSTM层activation='tanh',以及recurrent_dropout=.1, .2, .3
  • 优化器Nadamlr=2e-4(Nadam 可能明显优于所有其他 RNN 优化器)
  • batch_size:降低它。除非你总共有200+个批次,否则设置batch_size=32;较低的批量大小更好地利用了优化器的随机机制,并且可以提高泛化能力
  • Dropout:在第二个 Conv1D 之后,比率为 .1, .2 - 或者,在第一个 Conv1D 之后,比率为 .25, .3,但是 如果你使用 SqueezeExcite(见下文),否则 MaxPooling 也不会工作
  • SqueezeExcite:显示可增强 CNN 在各种任务中的性能;您可以在下面使用 Keras 实现
  • BatchNormalization:虽然你的模型不大,但它仍然很深,可能会在第二个之后受益于一个 BN 层 Conv1D
  • L2 weight decay:在firstConv1D上,防止它记忆输入;尝试 1e-5, 1e-4,例如kernel_regularizer=l2(1e-4) # from keras.regularizers import l2
  • 预处理:确保所有数据都已标准化(如果是时间序列则为标准化),并且每个 epoch
  • 对批次进行洗牌
def SqueezeExcite(_input):
    filters = _input._keras_shape[-1]

    se = GlobalAveragePooling1D()(_input)
    se = Reshape((1, filters))(se)
    se = Dense(filters//16,activation='relu',   
               kernel_initializer='he_normal', use_bias=False)(se)
    se = Dense(filters,    activation='sigmoid',
               kernel_initializer='he_normal', use_bias=False)(se)

    return multiply([_input, se])
# Example usage
x = Conv1D(filters=64, kernel_size=4, activation='relu', kernel_initializer='he_normal')(x)
x = SqueezeExcite(x) # place after EACH Conv1D