如何在 Keras 中使用标量常数来衡量隐藏的标量输出
Posted
技术标签:
【中文标题】如何在 Keras 中使用标量常数来衡量隐藏的标量输出【英文标题】:How can I use a scalar constant for weighting hidden scalar ouptuts in Keras 【发布时间】:2020-11-03 07:15:10 【问题描述】:感谢您的宝贵时间!
我正在尝试构建一个用于回归预测离散值的神经网络,但有一个特殊的 twirk。输入应以两种方式(模型 A 和 B)处理,然后加权组合。输出通过公式 AG + B(1-G) 与 G = 1/(1+exp(-gamma * (input_weighting - c))) 组合。 gamma 和 c 都应该在此过程中学习。 我与变量 gamma 和 c 以及减法 (1-G) 作斗争。我当前的代码在两个不同的地方失败:
# two models for time series (convolutional approach)
input_model_A = keras.Input(shape=(12,))
model_A = Dense(12)(input_model_A)
input_model_B = keras.Input(shape=(12,))
model_B = Dense(24)(input_model_B)
# input for model weighting
input_weighting = keras.Input(shape=[1,], name="vola_input")
# exponent = gamma * (input_weighting - c)
class MyLayer(Layer):
def __init__(self, **kwargs):
super(MyLayer, self).__init__(**kwargs)
def build(self, input_shape=[[1,1],[1,1]]):
self._c = K.variable(0.5)
self._gamma = K.variable(0.5)
self.trainable_weights = [self._c, self._gamma]
super(MyLayer, self).build(input_shape) # Be sure to call this at the end
def call(self, vola, **kwargs):
intermediate = substract([vola, self._c])
result = multiply([self._gamma, intermediate])
return result
def compute_output_shape(self, input_shape):
return input_shape[0]
exponent = MyLayer()(input_weighting)
# G = 1/(1+exp(-exponent))
G = keras.layers.Dense(1, activation="sigmoid", name="G")(exponent)
# output = G*A + (1-G)*B
weighted_A = keras.layers.Multiply(name="layer_A")([model_A.outputs[0], G])
weighted_B = keras.layers.Multiply(name="layer_B")
pseudoinput = Input(shape=[1, 1], name="pseudoinput_input",
tensor=K.variable([1])) ([model_B.outputs[0], keras.layers.Subtract()([pseudoinput, G])])
merge_layer = keras.layers.Add(name="merge_layer")([weighted_A, weighted_B])
output_layer = keras.layers.Dense(units=1, activation='relu', name="output_layer")(merge_layer)
model = keras.Model(inputs=[input_model_A, input_model_B, input_weighting], outputs=[output_layer])
optimizer = SGD(learning_rate=0.01, momentum=0.0, nesterov=False)
model.compile(optimizer=optimizer, loss='mean_squared_error')
-
我的自定义层有一个错误,我不明白输入维度定义的某些地方似乎有问题。
File "...\keras\layers\merge.py", line 74, in build
batch_sizes = [s[0] for s in input_shape if s is not None]
File "...\keras\layers\merge.py", line 74, in <listcomp>
batch_sizes = [s[0] for s in input_shape if s is not None]
IndexError: tuple index out of range
-
我的“1”(在 1-G 中)只是不想工作。我怀疑,我尝试实例化常量张量/图层的方式是错误的。
File "...\keras\backend\tensorflow_backend.py", line 75, in symbolic_fn_wrapper
return func(*args, **kwargs)
File "...\keras\engine\base_layer.py", line 446, in __call__
self.assert_input_compatibility(inputs)
File "...\keras\engine\base_layer.py", line 358, in assert_input_compatibility
str(K.ndim(x)))
ValueError: Input 0 is incompatible with layer c: expected min_ndim=2, found ndim=1
我找到并尝试了这两个建议,但都没有成功: Creating constant value in Keras How to give a constant input to keras
坦率地说,我对我的问题背后的任何一个(或两个)原因都感兴趣,但我更喜欢简单地找到一个提供所描述架构的解决方案。
【问题讨论】:
在您的实现中,我没有看到公式 1/exp(gamma * (input_weighting - c))... 您正在尝试执行 gamma * (input_weighting - c) 和然后与作为密集层的 G 相乘 我使用了那个层的激活函数。 Sigmoid 是 1/(1+exp(-wi-b)),其中 i 是密集层的输入,w 是该输入的权重,b 是偏差。写这篇我意识到,最终真正的 gamma_hat 将是 wgamma。我更正了问题中的formel,因为那个sigmoid正是我想要的公式。 好的,现在很清楚了。如果你有兴趣,我可以向你提供我的建议/实施 嗨,Marco,对不起,我不知何故没有看到您的第二条评论。我还是很感兴趣的!感谢您的提议和提醒! 非常感谢!我会在接下来的 2 天内对其进行检查并投票+接受。 【参考方案1】:这是我对一些 cmets 的建议
input_model_A = Input(shape=(12,))
model_A = Dense(24)(input_model_A)
input_model_B = Input(shape=(12,))
model_B = Dense(24)(input_model_B)
# model_A and model_B must have the same last dimensionality
# otherwise it is impossible to apply Add operation below
# input for model weighting
input_weighting = Input(shape=(1,), name="vola_input")
class MyLayer(Layer):
def __init__(self, **kwargs):
super(MyLayer, self).__init__(**kwargs)
self._c = K.variable(0.5)
self._gamma = K.variable(0.5)
def call(self, vola, **kwargs):
x = self._gamma * (vola - self._c) # gamma * (input_weighting - c)
result = tf.nn.sigmoid(x) # 1 / (1 + exp(-x))
return result
G = MyLayer()(input_weighting) # 1/(1+exp(-gamma * (input_weighting - c)))
weighted_A = Lambda(lambda x: x[0]*x[1])([model_A,G]) # A*G
weighted_B = Lambda(lambda x: x[0]*(1-x[1]))([model_B,G]) # B*(1-G)
merge_layer = Add(name="merge_layer")([weighted_A, weighted_B]) # A*G + B*(1-G)
output_layer = Dense(units=1, activation='relu', name="output_layer")(merge_layer)
model = Model(inputs=[input_model_A, input_model_B, input_weighting], outputs=[output_layer])
model.compile(optimizer='adam', loss='mean_squared_error')
# create dummy data and fit
n_sample = 100
Xa = np.random.uniform(0,1, (n_sample,12))
Xb = np.random.uniform(0,1, (n_sample,12))
W = np.random.uniform(0,1, n_sample)
y = np.random.uniform(0,1, n_sample)
model.fit([Xa,Xb,W], y, epochs=3)
这里是正在运行的笔记本:https://colab.research.google.com/drive/1MA6qs4IK9e41TbBK1mAebtALA2fMcNPY?usp=sharing
【讨论】:
非常感谢您的解决方案!它运作良好。作为旁注,我最初使用的是独立的 Keras。但是,我切换到 tensorflow.keras 以使用您的建议(这可能会带来更多好处)。以上是关于如何在 Keras 中使用标量常数来衡量隐藏的标量输出的主要内容,如果未能解决你的问题,请参考以下文章
Keras:为啥损失函数必须为每个批次项目返回一个标量,而不仅仅是一个标量?