我目前正在解决一个问题,即我提供了一个输入变量 a 的神经网络,另一个输入 x 这是N个数字的单调递增序列。
所以我的网络基本上看起来像这样:
a_input = Input(shape=[1], name='a')
x_input = Input(shape=[N], name='x')
nn = concatenate([a_input, x_input])
nn = Dense(100, activation='relu')(nn)
nn = Dense(N, activation='relu')(nn)
model = Model(inputs=[a_input, x_input], outputs=[nn])
model.compile(loss='mean_squared_error', optimizer="adam")
我对输入空间执行回归(每个 a ,序列 x 是唯一的) ,我希望网络为每组输入输出一个单调递增的(非负) N 数字序列 a 和 X 即可。
现在,我注意到到目前为止我的输出并不严格地说单调,但如果你'缩小',它们看起来就像它们一样。我的意思是,对于给定的 a 和 x 的选择,如果我希望我的输出数组看起来喜欢:
[0, 0.5, 0.51, 0.7, 0.75, 0.9, 1.],
我可能会得到:
[0.001, 0.5, 0.48, 0.7, 0.75, 0.9, 1.].
因此,我想知道Keras中是否存在标准方法或特定工具,以限制模型仅输出单调增加的序列?
答案 0 :(得分:1)
要强制执行非负输出,请在输出图层中使用非负激活,例如ReLU或sigmoid。
我不知道任何神经方法在输出中强制单调性,但在我看来,一种明智的方法是改变输出表示,使网络预测两个连续元素之间的差异。例如,您可以转换输出数组:
a=[0, 0.5, 0.51, 0.7, 0.75, 0.9, 1.]
为:
b=[0, 0.5, 0.01, 0.19, 0.05, 0.15, 0.1]
b[0] = a[0]
和b[i] = a[i]-a[i-1]
i>0
。在此上下文中,使用循环层作为输出层是有意义的,因为现在每个输出单元都依赖于先前的输出单元。对于a[0] = b[0]
,您的原始表示可以轻松恢复为a[i] = b[i]+a[i-1]
和i>0
,并且生成的序列将单调递增,因为每个输出b[i]
都是非负数。
更新1 。 LSTM应返回完整序列。您可以尝试按如下方式构建模型:
a_input = Input(shape=[1], name='a')
x_input = Input(shape=[N], name='x')
nn = concatenate([a_input, x_input])
nn = Dense(100, activation='relu')(nn)
nn = Dense(N, activation='relu')(nn)
nn = Lambda(lambda x: x[..., None])(nn) # Output shape=(batch_size, nb_timesteps=N, input_dim=1)
nn = LSTM(1, return_sequences=True, activation='relu')(nn) # Output shape=(batch_size, nb_timesteps=N, output_dim=1)
nn = Lambda(lambda x: keras.backend.squeeze(x, axis=-1))(nn) # Output shape=(batch_size, N)
model = Model(inputs=[a_input, x_input], outputs=[nn])
model.compile(loss='mean_squared_error', optimizer="adam")
更新2 。具有一个隐藏单元的LSTM可能不够强大。我不确定这是否会有所帮助,但您可以尝试在最后一个之前添加另一个LSTM图层(即10个):
...
nn = Lambda(lambda x: x[..., None])(nn) # Output shape=(batch_size, nb_timesteps=N, input_dim=1)
nn = LSTM(10, return_sequences=True)(nn) # Output shape=(batch_size, nb_timesteps=N, output_dim=10)
nn = LSTM(1, return_sequences=True, activation='relu')(nn) # Output shape=(batch_size, nb_timesteps=N, output_dim=1)
nn = Lambda(lambda x: keras.backend.squeeze(x, axis=-1))(nn) # Output shape=(batch_size, N)
...