Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/337.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何通过Tensorflow2.x中的子类tf.keras.Loss.Loss类自定义损失_Python_Tensorflow_Keras_Tensorflow2.0 - Fatal编程技术网

Python 如何通过Tensorflow2.x中的子类tf.keras.Loss.Loss类自定义损失

Python 如何通过Tensorflow2.x中的子类tf.keras.Loss.Loss类自定义损失,python,tensorflow,keras,tensorflow2.0,Python,Tensorflow,Keras,Tensorflow2.0,当我在Tensorflow的网站上读到这篇文章时,我发现了两种定制损失的方法。第一个是定义损失函数,就像: def基本丢失功能(y_真,y_pred): 返回tf.math.reduce\u mean(tf.abs(y\u true-y\u pred)) 为了简单起见,我们假设批量大小也是1,因此y_true和y_pred的形状都是(1,c),其中c是类的数量。因此,在这种方法中,我们给出了两个向量y_true和y_pred,并返回一个值(scala) 然后,第二种方法是子类化tf.keras

当我在Tensorflow的网站上读到这篇文章时,我发现了两种定制损失的方法。第一个是定义损失函数,就像:

def基本丢失功能(y_真,y_pred):
返回tf.math.reduce\u mean(tf.abs(y\u true-y\u pred))
为了简单起见,我们假设批量大小也是1,因此
y_true
y_pred
的形状都是(1,c),其中c是类的数量。因此,在这种方法中,我们给出了两个向量
y_true
y_pred
,并返回一个值(scala)

然后,第二种方法是子类化
tf.keras.Loss.Loss
class,指南中的代码是:

类加权二进制交叉熵(keras.Loss.Loss):
"""
Args:
pos_weight:影响损失函数正标签的标量。
权重:影响损失函数整体的标量。
from_logits:计算logits损失还是概率。
减少:tf.keras.loss的类型。适用于损失的减少。
名称:损失函数的名称。
"""
def uuu init uuuuuu(自身、位置、重量、来自_logits=False,
减少=keras.Loss.Reducement.AUTO,
name='weighted_binary_crossentropy'):
super()
self.pos\u weight=pos\u weight
自重
self.from\u logits=from\u logits
def调用(self、y_true、y_pred):
ce=tf.loss.binary\u交叉熵(
y_true,y_pred,from_logits=self.from_logits)[:,无]
ce=自重*(ce*(1-y_真)+自重*ce*(y_真))
返回ce
在调用方法中,像往常一样,我们给出两个向量
y_true
y_pred
,但我注意到它返回
ce
,这是一个具有形状(1,c)的向量

那么在上面的玩具示例中有什么问题吗?或者Tensorflow2.x背后有一些魔力?

除了实现之外,两者之间的主要区别在于损失函数的类型。第一个是L1损失(根据定义,绝对差异的平均值,主要用于回归类问题),第二个是二进制交叉熵(用于分类)。它们并不意味着是同一损失的不同实现,这在您链接的指南中有说明

二进制交叉熵在多标签、多类别分类设置中为每个类别输出一个值,就好像它们彼此独立一样

编辑:

在第二个损失函数中,
reduce
参数控制输出的聚合方式,例如,获取元素的总和或对批次求和等。默认情况下,代码使用
keras.loss.reduce.AUTO
,如果您进行检查,则转换为对批次求和。这意味着,最终损失将是一个向量,但还有其他可用的减少,您可以在中检查它们。我相信,即使您没有定义减少以获取损失向量中损失元素的总和,TF优化器也会这样做,以避免反向传播向量时出现错误。向量上的反向传播会在权重处导致问题,这些权重“有助于”每个损失元素。但是,我没有在源代码中检查这一点。:)

除了实现之外,两者之间的主要区别在于损失函数的类型。第一个是L1损失(根据定义,绝对差异的平均值,主要用于回归类问题),第二个是二进制交叉熵(用于分类)。它们并不意味着是同一损失的不同实现,这在您链接的指南中有说明

二进制交叉熵在多标签、多类别分类设置中为每个类别输出一个值,就好像它们彼此独立一样

编辑:


在第二个损失函数中,
reduce
参数控制输出的聚合方式,例如,获取元素的总和或对批次求和等。默认情况下,代码使用
keras.loss.reduce.AUTO
,如果您进行检查,则转换为对批次求和。这意味着,最终损失将是一个向量,但还有其他可用的减少,您可以在中检查它们。我相信,即使您没有定义减少以获取损失向量中损失元素的总和,TF优化器也会这样做,以避免反向传播向量时出现错误。向量上的反向传播会在权重处导致问题,这些权重“有助于”每个损失元素。但是,我没有在源代码中检查这一点。:)

是的,这是两种不同的损失。但是我认为当批处理大小eauals为1时,调用方法是否应该只返回一个scala而不是一个向量?它们是两种不同的损失,这就是为什么输出形状不同。一个按定义返回标量(L1),而另一个按定义为多类设置中的每个类返回标量(c=类数)。即使您没有子类tf.keras.Loss,二进制交叉熵也应该返回一个形状向量(1,c)。或者您可以使用分类交叉熵,它将返回一个标量。非常感谢您的详细解释!但在我看来,由于BP,神经网络的损失应该是单个标量,而不是向量。所以我想知道是否有必要做sum(ce)来获得所有类的总损失,这是正确的,反向传播向量可能会导致问题,因为优化器无法决定使用梯度向量的组件。我更新了关于减少子类损失的答案。有趣的是,我在最初的回答中删除了这一部分。另外,当我指的是“多标签”时,我错误地使用了“多类别分类”。是的,它们是两种不同的损失。但是我认为调用方法是否应该只是r