Я установил модель Keras с Конкатенатным слоем для реализации сложных потерь. Но даже когда я просто игнорирую один из двух объединенных компонентов, моя потеря значительно выше, чем у оставшегося компонента, взятого отдельно.
Или, может быть, в моем коде есть какая-то ошибка ...
Есть ли у вас какие-либо подсказки, пожалуйста?
спасибо!
Некоторый контекст
В моей реальной установке у меня есть два набора входов (X1, X2) с двумя соответствующими наборами меток (Y, Z), проходящими через одну и ту же модель.
Модель должна минимизировать двоичную кросцентропию по (X1, Y) и максимизировать условную энтропию по (X2, Z) при условии ограничения равенства для Y-предсказаний . Для этого я объединяю два пути 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