CNN-LSTM的批次归一化层

时间:2019-12-11 11:43:11

标签: tensorflow keras conv-neural-network lstm batch-normalization

假设我有一个这样的模型(这是时间序列预测的模型):

ipt   = Input((data.shape[1] ,data.shape[2])) # 1
x     = Conv1D(filters = 10, kernel_size = 3, padding = 'causal', activation = 'relu')(ipt) # 2
x     = LSTM(15, return_sequences = False)(x) # 3
x = BatchNormalization()(x) # 4
out   = Dense(1, activation = 'relu')(x) # 5

现在,我想向该网络添加批处理规范化层。考虑到batch normalization doesn't work with LSTM这一事实,我可以在Conv1D层之前添加它吗?我认为在LSTM之后有一个批处理规范化层是合理的。

此外,我可以在此网络的哪里添加Dropout?一样的地方(在批量归一化之前还是之后?)

  • 如何在AveragePooling1DConv1D之间添加LSTM?在这种情况下,是否可以在Conv1DAveragePooling1D之间添加批处理规范化而对LSTM层没有任何影响?

1 个答案:

答案 0 :(得分:3)

BatchNormalization 可以与LSTM一起使用-链接的SO提供了错误的建议;实际上,在我的EEG分类应用中,它占主导地位LayerNormalization。现在您的情况:

  • “能否在Conv1D之前添加它” ?请勿-相反,请事先对数据进行标准化,否则您将使用劣等版本来做同样的事情
  • 同时尝试:在激活之前BatchNormalization和之后都尝试-适用于Conv1DLSTM
  • 如果您的模型与您展示的模型完全相同,则BN之后的LSTM可能会对引入噪声的能力产生反作用,这会使分类器层产生混淆-但这大约是输出之前的一层,不是LSTM
  • 如果您没有在LSTM前面使用return_sequences=True的堆叠return_sequences=False,则可以将Dropout放在任何地方-LSTM之前,之后或两者都< / li>
  • 空间退出:删除单位 / 通道,而不是随机激活(请参阅底部); LeCun, et al(具有适用于RNN的想法)被证明在减少CNN的协同适应方面更有效。可以大大增加收敛时间,但也可以提高性能
  • 对于recurrent_dropout
  • Dropout仍然比LSTM更好-但是,您可以两者都做;只是不要与activation='relu'配合使用,LSTM对于每个错误来说都是不稳定的
  • 对于维度数据,任何类型的Pooling都是多余的,可能会损害性能;与简单的平均运算相比,通过非线性方法可以更好地转换稀缺数据
  • 我强烈建议您在转化后插入SqueezeExcite块;这是一种自我关注的形式-参见paper;我对以下1D的实现
  • 我还建议根据论文Self Normalizing Neural Networks尝试用activation='selu'AlphaDropout初始化'lecun_normal'
  • 免责声明:以上建议可能不适用于NLP和类似嵌入的任务

下面是一个示例模板,您可以将其用作起点;我还建议您阅读以下SO,以供进一步阅读:Regularizing RNNsVisualizing RNN gradients

from keras.layers import Input, Dense, LSTM, Conv1D, Activation
from keras.layers import AlphaDropout, BatchNormalization
from keras.layers import GlobalAveragePooling1D, Reshape, multiply
from keras.models import Model
import keras.backend as K
import numpy as np


def make_model(batch_shape):
    ipt = Input(batch_shape=batch_shape)
    x   = ConvBlock(ipt)
    x   = LSTM(16, return_sequences=False, recurrent_dropout=0.2)(x)
    # x   = BatchNormalization()(x)  # may or may not work well
    out = Dense(1, activation='relu')

    model = Model(ipt, out)
    model.compile('nadam', 'mse')
    return model

def make_data(batch_shape):  # toy data
    return (np.random.randn(*batch_shape),
            np.random.uniform(0, 2, (batch_shape[0], 1)))

batch_shape = (32, 21, 20)
model = make_model(batch_shape)
x, y  = make_data(batch_shape)

model.train_on_batch(x, y)

使用的功能

def ConvBlock(_input):  # cleaner code
    x   = Conv1D(filters=10, kernel_size=3, padding='causal', use_bias=False,
                 kernel_initializer='lecun_normal')(_input)
    x   = BatchNormalization(scale=False)(x)
    x   = Activation('selu')(x)
    x   = AlphaDropout(0.1)(x)
    out = SqueezeExcite(x)    
    return out

def SqueezeExcite(_input, r=4):  # r == "reduction factor"; see paper
    filters = K.int_shape(_input)[-1]

    se = GlobalAveragePooling1D()(_input)
    se = Reshape((1, filters))(se)
    se = Dense(filters//r, activation='relu',    use_bias=False,
               kernel_initializer='he_normal')(se)
    se = Dense(filters,    activation='sigmoid', use_bias=False, 
               kernel_initializer='he_normal')(se)
    return multiply([_input, se])

空间辍学:将noise_shape = (batch_size, 1, channels)传递给Dropout-具有以下效果;有关代码,请参见Git gist