CNN-LSTM 的批量归一化层
Batch normalization layer for CNN-LSTM
假设我有这样一个模型(这是一个时间序列预测的模型):
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?一样的地方? (在批量归一化之后还是之前?)
- 在
Conv1D
和LSTM
之间添加AveragePooling1D
怎么样?在这种情况下,是否可以在 Conv1D
和 AveragePooling1D
之间添加批量归一化而不会对 LSTM
层产生任何影响?
Update:我使用的 LayerNormalization 实现是 inter-layer,而不是 recurrent与原始论文一样;后者的结果可能会更好。
BatchNormalization
可以 使用 LSTM - 链接的 SO 给出了错误的建议;事实上,在我的脑电图分类应用中,它占主导地位LayerNormalization
。现在针对您的情况:
- "Can I add it before
Conv1D
"?不要 - 相反,事先标准化您的数据,否则您将使用劣质变体来做同样的事情
- 同时尝试:
BatchNormalization
激活前和激活后 - 适用于 Conv1D
和 LSTM
- 如果您的模型与您展示的完全一样,
LSTM
之后的 BN
引入噪声的能力可能会适得其反,这可能会混淆分类器层 - 但这是关于之前的一层输出,不是 LSTM
- 如果您不在
return_sequences=False
之前使用带有 return_sequences=True
的堆叠 LSTM
,您可以将 Dropout
放置在任何地方 - 在 LSTM
之前、之后或两者
- Spatial Dropout:丢弃 units / channels 而不是随机激活(见底部) ; LeCun, et al 在论文中证明了在减少 CNN 中的协同适应方面更有效,其中包含适用于 RNN 的想法。可以大大增加收敛时间,也可以提高性能
对于 LSTM
,recurrent_dropout
仍然优于 Dropout
- 但是,你可以两者都做;只是不要与 activation='relu'
一起使用,因为 LSTM
根据错误 不稳定
- 对于您维度的数据,任何类型的
Pooling
都是多余的并且可能会损害性能;稀缺数据通过非线性比简单的平均操作更好地转换
- 我强烈建议在您的转化后使用
SqueezeExcite
块;这是一种自我关注的形式 - 请参阅 paper;我对以下 1D 的实现
- 我还建议尝试
activation='selu'
AlphaDropout
和 'lecun_normal'
初始化,每篇论文 Self Normalizing Neural Networks
- 免责声明:以上建议可能不适用于 NLP 和类似嵌入的任务
下面是一个示例模板,您可以将其用作起点;我还推荐以下 SO 以供进一步阅读:Regularizing RNNs, and
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])
Spatial Dropout:将noise_shape = (batch_size, 1, channels)
传递给Dropout
——效果如下;代码见 Git gist:
假设我有这样一个模型(这是一个时间序列预测的模型):
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?一样的地方? (在批量归一化之后还是之前?)
- 在
Conv1D
和LSTM
之间添加AveragePooling1D
怎么样?在这种情况下,是否可以在Conv1D
和AveragePooling1D
之间添加批量归一化而不会对LSTM
层产生任何影响?
Update:我使用的 LayerNormalization 实现是 inter-layer,而不是 recurrent与原始论文一样;后者的结果可能会更好。
BatchNormalization
可以 使用 LSTM - 链接的 SO 给出了错误的建议;事实上,在我的脑电图分类应用中,它占主导地位LayerNormalization
。现在针对您的情况:
- "Can I add it before
Conv1D
"?不要 - 相反,事先标准化您的数据,否则您将使用劣质变体来做同样的事情 - 同时尝试:
BatchNormalization
激活前和激活后 - 适用于Conv1D
和LSTM
- 如果您的模型与您展示的完全一样,
LSTM
之后的BN
引入噪声的能力可能会适得其反,这可能会混淆分类器层 - 但这是关于之前的一层输出,不是LSTM
- 如果您不在
return_sequences=False
之前使用带有return_sequences=True
的堆叠LSTM
,您可以将Dropout
放置在任何地方 - 在LSTM
之前、之后或两者 - Spatial Dropout:丢弃 units / channels 而不是随机激活(见底部) ; LeCun, et al 在论文中证明了在减少 CNN 中的协同适应方面更有效,其中包含适用于 RNN 的想法。可以大大增加收敛时间,也可以提高性能 对于
recurrent_dropout
仍然优于Dropout
- 但是,你可以两者都做;只是不要与activation='relu'
一起使用,因为LSTM
根据错误 不稳定
- 对于您维度的数据,任何类型的
Pooling
都是多余的并且可能会损害性能;稀缺数据通过非线性比简单的平均操作更好地转换 - 我强烈建议在您的转化后使用
SqueezeExcite
块;这是一种自我关注的形式 - 请参阅 paper;我对以下 1D 的实现 - 我还建议尝试
activation='selu'
AlphaDropout
和'lecun_normal'
初始化,每篇论文 Self Normalizing Neural Networks - 免责声明:以上建议可能不适用于 NLP 和类似嵌入的任务
LSTM
,下面是一个示例模板,您可以将其用作起点;我还推荐以下 SO 以供进一步阅读:Regularizing RNNs, and
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])
Spatial Dropout:将noise_shape = (batch_size, 1, channels)
传递给Dropout
——效果如下;代码见 Git gist: