Oli*_*s_j 6 python loss keras tensorflow
我的问题与此处提出的问题类似: 喀拉拉邦将两个损失与可调整的权重相结合
但是,输出具有不同的维数,导致无法串联输出。因此,该解决方案不适用,是否有另一种方法可以解决此问题?
问题:
我有一个带有输出x1和x2的两层的keras功能模型。
x1 = Dense(1,activation='relu')(prev_inp1)
x2 = Dense(2,activation='relu')(prev_inp2)
Run Code Online (Sandbox Code Playgroud)
我需要在加权损失函数中使用这些x1和x2,就像在所附的图像中一样。将“相同损失”传播到两个分支。Alpha可以灵活地随迭代而变化。
对于这个问题,需要更详尽的解决方案。由于我们将使用可训练的权重,因此我们需要一个自定义图层。
此外,我们也将需要不同形式的培训,因为我们的损失并不像其他人只考虑工作y_true和y_pred,并考虑加入两个不同的输出。
因此,我们将创建同一模型的两个版本,一个用于预测,另一个用于训练,并且训练版本将在编译中使用虚拟keras损失函数来包含损失本身。
让我们使用一个非常基本的模型示例,该示例具有两个输出和一个输入:
#any input your true model takes
inp = Input((5,5,2))
#represents the localization output
outImg = Conv2D(1,3,activation='sigmoid')(inp)
#represents the classification output
outClass = Flatten()(inp)
outClass = Dense(2,activation='sigmoid')(outClass)
#the model
predictionModel = Model(inp, [outImg,outClass])
Run Code Online (Sandbox Code Playgroud)
您可以定期使用此预测。无需编译此代码。
现在,让我们为每个分支创建自定义损失函数,一个分支为LossCls另一个分支LossLoc。
在此处使用虚拟示例,可以根据需要更好地阐述这些损失。最重要的是它们输出形状像(batch,1)或(batch,)的批次。两者输出的形状相同,因此可以在以后进行求和。
def calcImgLoss(x):
true,pred = x
loss = binary_crossentropy(true,pred)
return K.mean(loss, axis=[1,2])
def calcClassLoss(x):
true,pred = x
return binary_crossentropy(true,pred)
Run Code Online (Sandbox Code Playgroud)
这些将Lambda在训练模型的各个层中使用。
现在,让我们用可训练的alpha来衡量损失。可训练的参数需要实现自定义层。
class LossWeighter(Layer):
def __init__(self, **kwargs): #kwargs can have 'name' and other things
super(LossWeighter, self).__init__(**kwargs)
#create the trainable weight here, notice the constraint between 0 and 1
def build(self, inputShape):
self.weight = self.add_weight(name='loss_weight',
shape=(1,),
initializer=Constant(0.5),
constraint=Between(0,1),
trainable=True)
super(LossWeighter,self).build(inputShape)
def call(self,inputs):
firstLoss, secondLoss = inputs
return (self.weight * firstLoss) + ((1-self.weight)*secondLoss)
def compute_output_shape(self,inputShape):
return inputShape[0]
Run Code Online (Sandbox Code Playgroud)
请注意,有一个自定义约束将其权重保持在0到1之间。此约束通过以下方式实现:
class Between(Constraint):
def __init__(self,min_value,max_value):
self.min_value = min_value
self.max_value = max_value
def __call__(self,w):
return K.clip(w,self.min_value, self.max_value)
def get_config(self):
return {'min_value': self.min_value,
'max_value': self.max_value}
Run Code Online (Sandbox Code Playgroud)
该模型将以预测模型为基础,最后添加损失计算和损失加权器,仅输出损失值。因为它仅输出损失,所以我们将使用真实目标作为输入,并使用如下定义的虚拟损失函数:
def ignoreLoss(true,pred):
return pred #this just tries to minimize the prediction without any extra computation
Run Code Online (Sandbox Code Playgroud)
模型输入:
#true targets
trueImg = Input((3,3,1))
trueClass = Input((2,))
#predictions from the prediction model
predImg = predictionModel.outputs[0]
predClass = predictionModel.outputs[1]
Run Code Online (Sandbox Code Playgroud)
模型输出=损失:
imageLoss = Lambda(calcImgLoss, name='loss_loc')([trueImg, predImg])
classLoss = Lambda(calcClassLoss, name='loss_cls')([trueClass, predClass])
weightedLoss = LossWeighter(name='weighted_loss')([imageLoss,classLoss])
Run Code Online (Sandbox Code Playgroud)
模型:
trainingModel = Model([predictionModel.input, trueImg, trueClass], weightedLoss)
trainingModel.compile(optimizer='sgd', loss=ignoreLoss)
Run Code Online (Sandbox Code Playgroud)
inputImages = np.zeros((7,5,5,2))
outputImages = np.ones((7,3,3,1))
outputClasses = np.ones((7,2))
dummyOut = np.zeros((7,))
trainingModel.fit([inputImages,outputImages,outputClasses], dummyOut, epochs = 50)
predictionModel.predict(inputImages)
Run Code Online (Sandbox Code Playgroud)
from keras.layers import *
from keras.models import Model
from keras.constraints import Constraint
from keras.initializers import Constant
from keras.losses import binary_crossentropy #or another you need
Run Code Online (Sandbox Code Playgroud)
无需连接您的输出。要将多个参数传递给损失函数,您可以将其包装如下:
def custom_loss(x1, x2, y1, y2, alpha):
def loss(y_true, y_pred):
return (1-alpha) * loss_cls(y1, x1) + alpha * loss_loc(y2, x2)
return loss
Run Code Online (Sandbox Code Playgroud)
然后将您的功能模型编译为:
x1 = Dense(1, activation='relu')(prev_inp1)
x2 = Dense(2, activation='relu')(prev_inp2)
y1 = Input((1,))
y2 = Input((2,))
model.compile('sgd',
loss=custom_loss(x1, x2, y1, y2, 0.5),
target_tensors=[y1, y2])
Run Code Online (Sandbox Code Playgroud)
注意:未经测试。
| 归档时间: |
|
| 查看次数: |
1897 次 |
| 最近记录: |