每个目标具有多个输入序列的 RNN
RNN with multiple input sequences for each target
标准的 RNN 计算图如下所示(在我的例子中,回归到单个标量值 y
)
我想构建一个接受输入 m
序列 X_1...X_m
(其中 m
和序列长度都不同)的网络,在每个序列上运行 RNN X_i
以获得表示向量 R_i
,对表示进行平均,然后运行全连接网络来计算输出 y_hat
。计算图应如下所示:
问题
这可以(最好)在 Keras 中实现吗?否则在 TensorFlow 中?如果有人能指出这个或类似东西的有效实现,我将不胜感激。
没有直接的 Keras 实现,因为 Keras 强制输入和输出层的批处理轴(样本维度,维度 0)固定(但 不是 所有层in-between) - 而你试图通过平均来折叠它。但是,有一个解决方法 - 见下文:
import tensorflow.keras.backend as K
from tensorflow.keras.layers import Input, Dense, GRU, Lambda
from tensorflow.keras.layers import Reshape, GlobalAveragePooling1D
from tensorflow.keras.models import Model
from tensorflow.keras.utils import plot_model
import numpy as np
def make_model(batch_shape):
ipt = Input(batch_shape=batch_shape)
x = Lambda(lambda x: K.squeeze(x, 0))(ipt)
x, s = GRU(4, return_state=True)(x) # s == last returned state
x = Lambda(lambda x: K.expand_dims(x, 0))(s)
x = GlobalAveragePooling1D()(x) # averages along axis1 (original axis2)
x = Dense(32, activation='relu')(x)
out = Dense(1, activation='sigmoid')(x)
model = Model(ipt, out)
model.compile('adam', 'binary_crossentropy')
return model
def make_data(batch_shape):
return (np.random.randn(*batch_shape),
np.random.randint(0, 2, (batch_shape[0], 1)))
m, timesteps = 16, 100
batch_shape = (1, m, timesteps, 1)
model = make_model(batch_shape)
model.summary() # see model structure
plot_model(model, show_shapes=True)
x, y = make_data(batch_shape)
model.train_on_batch(x, y)
以上假定任务是二元分类,但您可以轻松地将其适应任何其他任务 - 主要任务通过将 m
个样本作为 1
来欺骗 Keras,其余层可以自由选择取 m
代替,因为 Keras 不强制执行 1
那里。
但是请注意,我不能保证它会按以下预期工作:
- Keras 将批处理轴上的所有条目视为 独立,而您的样本声称为 依赖
- 根据 (1),主要关注点是 反向传播:我不太确定梯度将如何随着所有维数改组的进行而流动。
- (1) 对于 有状态 RNNs 也是必然的,因为 Keras 构造了
batch_size
个独立状态,它们仍然可能像预期的那样表现是保持记忆,但仍然值得充分理解 - 参见
(2) 是 "elephant in the room",但除此之外,该模型符合您的确切描述。很有可能,如果你已经计划了前向传播并且所有暗淡都同意代码,它会按预期工作 - 否则,为了完整性检查,我建议打开另一个问题来验证你想要的梯度流他们按照上面的代码。
model.summary()
:
Layer (type) Output Shape Param #
=================================================================
input_1 (InputLayer) [(1, 32, 100, 1)] 0
_________________________________________________________________
lambda (Lambda) (32, 100, 1) 0
_________________________________________________________________
gru (GRU) [(32, 16), (32, 16)] 864
_________________________________________________________________
lambda_1 (Lambda) (1, 32, 16) 0
_________________________________________________________________
global_average_pooling1d (Gl (1, 16) 0
_________________________________________________________________
dense (Dense) (1, 8) 136
_________________________________________________________________
dense_1 (Dense) (1, 1) 9
关于 LSTM:将 return 两个 最后状态,一个用于细胞状态,一个用于隐藏状态 - 见 source code;如果你要使用它,你应该明白这到底意味着什么。如果这样做,您将需要 concatenate
:
from tensorflow.keras.layers import concatenate
# ...
x, s1, s2 = LSTM(return_state=True)(x)
x = concatenate([s1, s2], axis=-1)
# ...
标准的 RNN 计算图如下所示(在我的例子中,回归到单个标量值 y
)
我想构建一个接受输入 m
序列 X_1...X_m
(其中 m
和序列长度都不同)的网络,在每个序列上运行 RNN X_i
以获得表示向量 R_i
,对表示进行平均,然后运行全连接网络来计算输出 y_hat
。计算图应如下所示:
问题
这可以(最好)在 Keras 中实现吗?否则在 TensorFlow 中?如果有人能指出这个或类似东西的有效实现,我将不胜感激。
没有直接的 Keras 实现,因为 Keras 强制输入和输出层的批处理轴(样本维度,维度 0)固定(但 不是 所有层in-between) - 而你试图通过平均来折叠它。但是,有一个解决方法 - 见下文:
import tensorflow.keras.backend as K
from tensorflow.keras.layers import Input, Dense, GRU, Lambda
from tensorflow.keras.layers import Reshape, GlobalAveragePooling1D
from tensorflow.keras.models import Model
from tensorflow.keras.utils import plot_model
import numpy as np
def make_model(batch_shape):
ipt = Input(batch_shape=batch_shape)
x = Lambda(lambda x: K.squeeze(x, 0))(ipt)
x, s = GRU(4, return_state=True)(x) # s == last returned state
x = Lambda(lambda x: K.expand_dims(x, 0))(s)
x = GlobalAveragePooling1D()(x) # averages along axis1 (original axis2)
x = Dense(32, activation='relu')(x)
out = Dense(1, activation='sigmoid')(x)
model = Model(ipt, out)
model.compile('adam', 'binary_crossentropy')
return model
def make_data(batch_shape):
return (np.random.randn(*batch_shape),
np.random.randint(0, 2, (batch_shape[0], 1)))
m, timesteps = 16, 100
batch_shape = (1, m, timesteps, 1)
model = make_model(batch_shape)
model.summary() # see model structure
plot_model(model, show_shapes=True)
x, y = make_data(batch_shape)
model.train_on_batch(x, y)
以上假定任务是二元分类,但您可以轻松地将其适应任何其他任务 - 主要任务通过将 m
个样本作为 1
来欺骗 Keras,其余层可以自由选择取 m
代替,因为 Keras 不强制执行 1
那里。
但是请注意,我不能保证它会按以下预期工作:
- Keras 将批处理轴上的所有条目视为 独立,而您的样本声称为 依赖
- 根据 (1),主要关注点是 反向传播:我不太确定梯度将如何随着所有维数改组的进行而流动。
- (1) 对于 有状态 RNNs 也是必然的,因为 Keras 构造了
batch_size
个独立状态,它们仍然可能像预期的那样表现是保持记忆,但仍然值得充分理解 - 参见
(2) 是 "elephant in the room",但除此之外,该模型符合您的确切描述。很有可能,如果你已经计划了前向传播并且所有暗淡都同意代码,它会按预期工作 - 否则,为了完整性检查,我建议打开另一个问题来验证你想要的梯度流他们按照上面的代码。
model.summary()
:
Layer (type) Output Shape Param #
=================================================================
input_1 (InputLayer) [(1, 32, 100, 1)] 0
_________________________________________________________________
lambda (Lambda) (32, 100, 1) 0
_________________________________________________________________
gru (GRU) [(32, 16), (32, 16)] 864
_________________________________________________________________
lambda_1 (Lambda) (1, 32, 16) 0
_________________________________________________________________
global_average_pooling1d (Gl (1, 16) 0
_________________________________________________________________
dense (Dense) (1, 8) 136
_________________________________________________________________
dense_1 (Dense) (1, 1) 9
关于 LSTM:将 return 两个 最后状态,一个用于细胞状态,一个用于隐藏状态 - 见 source code;如果你要使用它,你应该明白这到底意味着什么。如果这样做,您将需要 concatenate
:
from tensorflow.keras.layers import concatenate
# ...
x, s1, s2 = LSTM(return_state=True)(x)
x = concatenate([s1, s2], axis=-1)
# ...