Python Keras多输出模型中每个输出的自定义精度/损失
我试图使用Keras为双输出神经网络模型中的每个输出定义自定义损失和精度函数。让我们调用两个输出:A和B 我的目标是:Python Keras多输出模型中每个输出的自定义精度/损失,python,tensorflow,keras,Python,Tensorflow,Keras,我试图使用Keras为双输出神经网络模型中的每个输出定义自定义损失和精度函数。让我们调用两个输出:A和B 我的目标是: 给出其中一个输出名称的精度/损失函数,以便可以在tensorboard中的相同图表上报告它们,与我提供的旧/现有模型的相同对应输出。例如,两个输出网络中输出A的精度和损耗应该可以在tensorboard中的同一个图形中看到,就像我所拥有的一些旧模型的输出A一样。更具体地说,这些旧型号的所有输出都是A_输出acc,val_输出acc,A_输出损耗和val_输出损耗。因此,我希望在
A_输出acc
,val_输出acc
,A_输出损耗
和val_输出损耗
。因此,我希望在这个新模型中,A
输出的相应度量读数也具有这些名称,以便它们在tensorboard中的同一图形上可以查看/比较Modeler
类。有关守则如下
class Modeler(BaseModeler):
def __init__(self, loss=None,accuracy=None, ...):
"""
Returns compiled keras model.
"""
self.loss = loss
self.accuracy = accuracy
model = self.build()
...
model.compile(
loss={ # we are explicit here and name the outputs even though in this case it's not necessary
"A_output": self.A_output_loss(),#loss,
"B_output": self.B_output_loss()#loss
},
optimizer=optimus,
metrics= { # we need to tie each output to a specific list of metrics
"A_output": [self.A_output_acc()],
# self.A_output_loss()], # redundant since it's already reported via `loss` param,
# ends up showing up as `A_output_loss_1` since keras
# already reports `A_output_loss` via loss param
"B_output": [self.B_output_acc()]
# self.B_output_loss()] # redundant since it's already reported via `loss` param
# ends up showing up as `B_output_loss_1` since keras
# already reports `B_output_loss` via loss param
})
self._model = model
def A_output_acc(self):
"""
Allows us to output custom train/test accuracy/loss metrics to desired names e.g. 'A_output_acc' and
'val_A_output_acc' respectively so that they may be plotted on same tensorboard graph as the accuracies from
other models that same outputs.
:return: accuracy metric
"""
acc = None
if self.accuracy == TypedAccuracies.BINARY:
def acc(y_true, y_pred):
return self.binary_accuracy(y_true, y_pred)
elif self.accuracy == TypedAccuracies.DICE:
def acc(y_true, y_pred):
return self.dice_coef(y_true, y_pred)
elif self.accuracy == TypedAccuracies.JACARD:
def acc(y_true, y_pred):
return self.jacard_coef(y_true, y_pred)
else:
logger.debug('ERROR: undefined accuracy specified: {}'.format(self.accuracy))
return acc
def A_output_loss(self):
"""
Allows us to output custom train/test accuracy/loss metrics to desired names e.g. 'A_output_acc' and
'val_A_output_acc' respectively so that they may be plotted on same tensorboard graph as the accuracies from
other models that same outputs.
:return: loss metric
"""
loss = None
if self.loss == TypedLosses.BINARY_CROSSENTROPY:
def loss(y_true, y_pred):
return self.binary_crossentropy(y_true, y_pred)
elif self.loss == TypedLosses.DICE:
def loss(y_true, y_pred):
return self.dice_coef_loss(y_true, y_pred)
elif self.loss == TypedLosses.JACARD:
def loss(y_true, y_pred):
return self.jacard_coef_loss(y_true, y_pred)
else:
logger.debug('ERROR: undefined loss specified: {}'.format(self.accuracy))
return loss
def B_output_acc(self):
"""
Allows us to output custom train/test accuracy/loss metrics to desired names e.g. 'A_output_acc' and
'val_A_output_acc' respectively so that they may be plotted on same tensorboard graph as the accuracies from
other models that same outputs.
:return: accuracy metric
"""
acc = None
if self.accuracy == TypedAccuracies.BINARY:
def acc(y_true, y_pred):
return self.binary_accuracy(y_true, y_pred)
elif self.accuracy == TypedAccuracies.DICE:
def acc(y_true, y_pred):
return self.dice_coef(y_true, y_pred)
elif self.accuracy == TypedAccuracies.JACARD:
def acc(y_true, y_pred):
return self.jacard_coef(y_true, y_pred)
else:
logger.debug('ERROR: undefined accuracy specified: {}'.format(self.accuracy))
return acc
def B_output_loss(self):
"""
Allows us to output custom train/test accuracy/loss metrics to desired names e.g. 'A_output_acc' and
'val_A_output_acc' respectively so that they may be plotted on same tensorboard graph as the accuracies from
other models that same outputs.
:return: loss metric
"""
loss = None
if self.loss == TypedLosses.BINARY_CROSSENTROPY:
def loss(y_true, y_pred):
return self.binary_crossentropy(y_true, y_pred)
elif self.loss == TypedLosses.DICE:
def loss(y_true, y_pred):
return self.dice_coef_loss(y_true, y_pred)
elif self.loss == TypedLosses.JACARD:
def loss(y_true, y_pred):
return self.jacard_coef_loss(y_true, y_pred)
else:
logger.debug('ERROR: undefined loss specified: {}'.format(self.accuracy))
return loss
def load_model(self, model_path=None):
"""
Returns built model from model_path assuming using the default architecture.
:param model_path: str, path to model file
:return: defined model with weights loaded
"""
custom_objects = {'A_output_acc': self.A_output_acc(),
'A_output_loss': self.A_output_loss(),
'B_output_acc': self.B_output_acc(),
'B_output_loss': self.B_output_loss()}
self.model = load_model(filepath=model_path, custom_objects=custom_objects)
return self
def build(self, stuff...):
"""
Returns model architecture. Instead of just one task, it performs two: A and B.
:return: model
"""
...
A_conv_final = Conv2D(1, (1, 1), activation="sigmoid", name="A_output")(up_conv_224)
B_conv_final = Conv2D(1, (1, 1), activation="sigmoid", name="B_output")(up_conv_224)
model = Model(inputs=[input], outputs=[A_conv_final, B_conv_final], name="my_model")
return model
培训效果很好。但是,当我稍后使用上面的load\u model()
函数加载模型进行推断时,Keras抱怨它不知道我给它的自定义度量:
ValueError: Unknown loss function:loss
似乎正在发生的是,Keras将在上述每个自定义度量函数(def loss(…)
,def acc(…)
)中创建的返回函数附加到model.compile()调用的metrics
参数中给定的字典键。
例如,键是A\u output
,我们为它调用自定义精度函数,A\u output\u acc()
,它返回一个名为acc
的函数。因此,结果是A_输出+acc
=A_输出\u acc
。这意味着我无法命名那些返回的函数:acc
/loss
其他一些函数,因为这将打乱报告/图表。
这一切都很好,但我不知道如何使用正确定义的custom_objects
参数编写我的load
函数(或者定义/命名我的自定义度量函数),以便Keras知道每个输出头将加载哪些自定义精度/损失函数
更重要的是,在load\u model()
中,它似乎需要一个如下形式的自定义\u对象
字典(由于明显的原因,它不起作用):
而不是:
custom_objects = {'A_output_acc': self.A_output_acc(),
'A_output_loss': self.A_output_loss(),
'B_output_acc': self.B_output_acc(),
'B_output_loss': self.B_output_loss()}
有什么见解或解决办法吗
谢谢
编辑:
我已经确认上面关于键/函数名连接的推理对于Keras的model.compile()
调用的metrics
参数是正确的。但是,对于model.compile()
中的loss
参数,Keras只是将键与单词loss
连接起来,但在model.load\u model()
的custom\u objects
参数中需要自定义loss函数的名称。请参见图。删除()在你的损失和指标结束时,应该是这样。它将看起来像这样
loss={
"A_output": self.A_output_loss,
"B_output": self.B_output_loss
}
你也可以看看这个问题吗?
loss={
"A_output": self.A_output_loss,
"B_output": self.B_output_loss
}