- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我的问题与此处提出的问题类似: keras combining two losses with adjustable weights
但是,输出具有不同的维度,导致输出无法连接。因此,该解决方案不适用,是否有其他方法可以解决此问题?
问题:
我有一个包含两层的 keras 功能模型,输出 x1 和 x2。
x1 = Dense(1,activation='relu')(prev_inp1)
x2 = Dense(2,activation='relu')(prev_inp2)
我需要使用这些 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])
您经常使用这个进行预测。没有必要编译这个。
现在,让我们为每个分支创建自定义损失函数,一个用于 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)
这些将在训练模型的 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):
#old answer: will always tend to completely ignore the biggest loss
#return (self.weight * firstLoss) + ((1-self.weight)*secondLoss)
#problem: alpha tends to 0 or 1, eliminating the biggest of the two losses
#proposal of working alpha optimization
#return K.square((self.weight * firstLoss) - ((1-self.weight)*secondLoss))
#problem: might not train any of the losses, and even increase one of them
#in order to minimize the difference between the two losses
#new answer - a mix between the two, applying gradients to the right weights
loss1, loss2 = inputs #trainable
static_loss1 = K.stop_gradient(loss1) #non_trainable
static_loss2 = K.stop_gradient(loss2) #non_trainable
a1 = self.weight #trainable
a2 = 1 - a1 #trainable
static_a1 = K.stop_gradient(a1) #non_trainable
static_a2 = 1 - static_a1 #non_trainable
#this trains only alpha to minimize the difference between both losses
alpha_loss = K.square((a1 * static_loss1) - (a2 * static_loss2))
#or K.abs (.....)
#this trains only the original model weights to minimize both original losses
model_loss = (static_a1 * loss1) + (static_a2 * loss2)
return alpha_loss + model_loss
def compute_output_shape(self,inputShape):
return inputShape[0]
请注意,有一个自定义约束将此权重保持在 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}
该模型将以预测模型为基础,在最后加入损失计算和损失权重,只输出损失值。因为它只输出损失,所以我们将使用真实目标作为输入,并使用如下定义的虚拟损失函数:
def ignoreLoss(true,pred):
return pred #this just tries to minimize the prediction without any extra computation
模型输入:
#true targets
trueImg = Input((3,3,1))
trueClass = Input((2,))
#predictions from the prediction model
predImg = predictionModel.outputs[0]
predClass = predictionModel.outputs[1]
模型输出 = 损失:
imageLoss = Lambda(calcImgLoss, name='loss_loc')([trueImg, predImg])
classLoss = Lambda(calcClassLoss, name='loss_cls')([trueClass, predClass])
weightedLoss = LossWeighter(name='weighted_loss')([imageLoss,classLoss])
型号:
trainingModel = Model([predictionModel.input, trueImg, trueClass], weightedLoss)
trainingModel.compile(optimizer='sgd', loss=ignoreLoss)
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)
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
旧答案中使用的公式会使 alpha 始终变为 0 或 1,这意味着只会训练两个损失中最小的那个。 (无用)
一个新的公式导致 alpha 使两个损失具有相同的值。 Alpha 会得到适当的训练,而不是倾向于 0 或 1。但是,损失仍然不会得到适当的训练,因为“增加一个损失以达到另一个损失”对于模型来说是一种可能性,一旦两个损失相等,模型将停止训练。
新的解决方案是上述两个建议的混合,而第一个实际上训练了损失,但 alpha 错误;第二个以错误的损失训练 alpha。混合解决方案将两者相加,但使用 K.stop_gradient
来防止训练的错误部分发生。
这样做的结果是:“最简单”的损失(不是最大的)将比最困难的损失训练得更多。我们可能会使用K.abs
或K.square
,来对比两种损失之间的“mae”或“mse”。最好的选择取决于实验。
请参阅此表比较新旧提案:
但这并不能保证最佳优化!!!
不过,训练最简单的损失并不总是有最好的结果。这可能比仅仅因为它的公式不同而支持巨大的损失更好。但预期结果可能仍需要对损失进行一些手动加权。
我担心这个重量没有自动训练。如果你有一个目标指标,你可以尝试训练这个指标(如果可能的话,但是依赖于排序、获取索引、舍入或任何破坏反向传播的指标可能无法转化为损失)。
关于python - keras 将两个损失与可调权重相结合,其中输出不具有相同的维度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53707199/
这是代码片段。 请说出这种用小内存存储大数据的算法是什么。 public static void main(String[] args) { long longValue = 21474836
所以我使用 imap 从 gmail 和 outlook 接收电子邮件。 Gmail 像这样编码 =?UTF-8?B?UmU6IM69zq3OvyDOtc68zrHOuc67IG5ldyBlbWFpb
很久以前就学会了 C 代码;想用 Scheme 尝试一些新的和不同的东西。我正在尝试制作一个接受两个参数并返回两者中较大者的过程,例如 (define (larger x y) (if (> x
Azure 恢复服务保管库有两个备份配置选项 - LRS 与 GRS 这是一个有关 Azure 恢复服务保管库的问题。 当其驻留区域发生故障时,如何处理启用异地冗余的恢复服务保管库?如果未为恢复服务启
说,我有以下实体: @Entity public class A { @Id @GeneratedValue private Long id; @Embedded private
我有下一个问题。 我有下一个标准: criteria.add(Restrictions.in("entity.otherEntity", getOtherEntitiesList())); 如果我的
如果这是任何类型的重复,我会提前申请,但我找不到任何可以解决我的具体问题的内容。 这是我的程序: import java.util.Random; public class CarnivalGame{
我目前正在使用golang创建一个聚合管道,在其中使用“$ or”运算符查询文档。 结果是一堆需要分组的未分组文档,这样我就可以进入下一阶段,找到两个数据集之间的交集。 然后将其用于在单独的集合中进行
是否可以在正则表达式中创建 OR 条件。 我正在尝试查找包含此类模式的文件名列表的匹配项 第一个案例 xxxxx-hello.file 或者案例二 xxxx-hello-unasigned.file
该程序只是在用户输入行数时创建菱形的形状,因此它有 6 个 for 循环; 3 个循环创建第一个三角形,3 个循环创建另一个三角形,通过这 2 个三角形和 6 个循环,我们得到了一个菱形,这是整个程序
我有一个像这样的查询字符串 www.google.com?Department=Education & Finance&Department=Health 我有这些 li 标签,它们的查询字符串是这样
我有一个带有静态构造函数的类,我用它来读取 app.config 值。如何使用不同的配置值对类进行单元测试。我正在考虑在不同的应用程序域中运行每个测试,这样我就可以为每个测试执行静态构造函数 - 但我
我正在寻找一个可以容纳多个键的容器,如果我为其中一个键值输入保留值(例如 0),它会被视为“或”搜索。 map, int > myContainer; myContainer.insert(make_
我正在为 Web 应用程序创建数据库,并正在寻找一些建议来对可能具有多种类型的单个实体进行建模,每种类型具有不同的属性。 作为示例,假设我想为“数据源”对象创建一个关系模型。所有数据源都会有一些共享属
(1) =>CREATE TABLE T1(id BIGSERIAL PRIMARY KEY, name TEXT); CREATE TABLE (2) =>INSERT INTO T1 (name)
我不确定在使用别名时如何解决不明确的列引用。 假设有两个表,a 和 b,它们都有一个 name 列。如果我加入这两个表并为结果添加别名,我不知道如何为这两个表引用 name 列。我已经尝试了一些变体,
我的查询是: select * from table where id IN (1,5,4,3,2) 我想要的与这个顺序完全相同,不是从1...5,而是从1,5,4,3,2。我怎样才能做到这一点? 最
我正在使用 C# 代码执行动态生成的 MySQL 查询。抛出异常: CREATE TABLE dump ("@employee_OID" VARCHAR(50)); "{"You have an er
我有日期 2016-03-30T23:59:59.000000+0000。我可以知道它的格式是什么吗?因为如果我使用 yyyy-MM-dd'T'HH:mm:ss.SSS,它会抛出异常 最佳答案 Sim
我有一个示例模式,它的 SQL Fiddle 如下: http://sqlfiddle.com/#!2/6816b/2 这个 fiddle 只是根据 where 子句中的条件查询示例数据库,如下所示:
我是一名优秀的程序员,十分优秀!