keras - 连接层改变损失幅度
问题描述
我拟合了一个带有Concatenate 层的 Keras 模型来实现复合损失。但即使我只是忽略了两个合并组件中的一个,我的损失也明显高于单独考虑的其余组件。
或者我的代码中可能有一些错误......
你有什么线索吗?谢谢!
一些上下文
我的真实设置,我有两个输入集(X1,X2)和两个相应的标签集(Y,Z),流经同一个模型。该模型必须最小化 (X1,Y) 上的 binary_crossentropy 并最大化 (X2,Z) 上的条件熵,但要遵守 Y-predictions 的等式约束。为此,我将两条路径 X1-Y 和 X2-Z 与 Concatenate 层合并并定义相应的自定义损失。但即使我只是忽略复合损失中的 Z 部分,与基本的 1-输入/1-输出 (X1-Y) 路径相比,我得到的损失值也非常不同。
这里有一些(简化的)代码来重现问题:
from keras.models import Sequential, Model
from keras.layers import Dense, Dropout, Input, Lambda, concatenate
from keras.optimizers import Adam, SGD
import keras.backend as K
import numpy as np
# Define a stupid custom loss on z-labels
def loss1(z, zhat):
return K.sum(K.square(z-zhat), axis=-1)
# Another stupid custom loss on (y,z)-labels that just ignores y then forward to loss1
def loss2(yz, yzhat):
z=yz[:,1]
zhat=yzhat[:,1]
return loss1(z, zhat)
# Toy dataset
X = np.random.rand(1000,100)
X2 = X
y = 1* X[:,0]>0.5
z = 1* X[:,1]>0.5
# Model
model = Sequential()
model.add(Dense(30, input_shape=[X.shape[1]], activation='relu'))
model.add(Dense(1, activation='sigmoid'))
# 2 inputs (X,X2) , 2 outputs (Y,Z)
inY = Input([X.shape[1]], name="X")
outY = Lambda(lambda x: x, name="Y")(model(inY))
inZ = Input([X2.shape[1]], name="X2")
outZ = Lambda(lambda x: x, name="Z")(model(inZ))
# Take a 3rd output YZ by concatenating Y and Z
full_model = Model(inputs=[inY, inZ], outputs=[outY, outZ, concatenate([outY,outZ], name='YZ'), ])
# Run model with loss1 on Z and loss2 on YZ
full_model.compile(optimizer="adam",
loss={'Y':"binary_crossentropy", 'Z':loss1, 'YZ': loss2},
loss_weights={'Y':1, 'Z':0, 'YZ':0})
full_model.fit([X,X2], [y,z, np.stack((y,z),axis=-1)], batch_size=32, epochs=100, verbose=1)
# Z_loss1 and YZ_loss2 should be equal ! ... ??? but got
# > Z_loss: 0.2542 - YZ_loss: 8.3113
# > Z_loss: 0.2519 - YZ_loss: 8.2832
# > Z_loss: 0.2523 - YZ_loss: 8.2477
# > Z_loss: 0.2598 - YZ_loss: 8.2236
# > ...
Z_loss1 和 YZ_loss2 应该相等
但上面的代码产生
Z_loss:0.2542 - YZ_loss:7.9963
Z_loss:0.2519 - YZ_loss:7.4883
Z_loss:0.2523 - YZ_loss:7.1448
Z_loss:0.2598 - YZ_loss:6.9451
Z_loss:0.2583 - YZ_loss:6.6104
Z_loss:0.2621 - YZ_loss:6.2509
解决方案
使用 2D 张量调用损失函数 - 样本 x 输出。然后损失函数计算批次中每个样本的损失并分别返回。
z=yz[:,1]
- 在这里您将 2D 张量转换为 1D,然后loss1
对整个批次的损失求和,而不是对每个样本的损失求和。
如果保留张量维度:
z=yz[:,1:]
zhat=yzhat[:,1:]
那么 YZ 损失与 Y 损失完全匹配:
Epoch 1/5
1000/1000 [==============================] - 1s 1ms/step - loss: 0.7100 - Y_loss: 0.7100 - Z_loss: 0.2617 - YZ_loss: 0.2617
推荐阅读
- postgresql - 如何配置 Postgres Kubernetes 容器(OSX 和 Minikube)的卷挂载
- ruby-on-rails - Rails - 我的“创建/新建”方法不起作用
- python - 从 Tornado HTTPClient 发送表单数据
- reactjs - 如何选择性地渲染反应表组件?
- python - 特定商店的产品未出现在在线商城中
- php - 如何使用禁止链接 403 来消耗 php
- java - 我无法在 Java 中设置永久路径
- javascript - 从另一个更改一个 Select2 的值会创建递归
- r - 使用 R,如何获取.seed()?
- html - 影响绝对定位元素的不透明度