tf.keras.losses函数参数(from_logits、label_smoothing...)

tf.keras.losses实例是用来计算真实标签( y_true )和预测标签之间( y_pred )的Loss损失。

参数

from_logits

是否将 y_pred 解释为 logit 值的张量。 默认情况下,假设 y_pred 包含概率(即 [0, 1] 中的值)。即默认情况下from_logits的值为False

解释一下logit值的含义:逻辑回归一般将因变量二分类变量的0-1转变为频率[0,1]也就是分类为1的概率,进而变成优势比odds( odds=P/(1-P) ,[0,+∞] ),然后log一下成为Logit值( 即 Logit=log(odds) ),值域为 [-∞,+∞] ),于是可以理解有时候我们遇到的 y_pred标签值为一些[0,1]之外的无穷大的数。例如:

y_pred = [-18.6, 0.51, 2.94, -12.8]

以P为因变量的Logit函数,反过来求概率P的反函数即为sigmoid函数(sigmoid(x)=1/1+e^(-x) ,即概率P=1/1+e^(-Logit) )。

在二分类中sigmoid函数较为常用,softmax函数常用于多分类任务。

对于多标签输入softmax函数能保证它们的映射之和为1,而sigmoid函数不能保证。
简单来说,from_logits的值为True的 y_pred的标签,首先应该使用sigmoid或者softmax函数计算后,再计算loss损失。

label_smoothing

即标签平滑,是一种正则化方法,用于分类问题,防止模型在训练时过拟合,改善泛化能力差的问题。

那么为什么需要标签平滑呢?以二分类为例,设训练数据为形如(x,y)的集合,其中x为数据,y为真实标签( y_true ),p(x)指预测标签 (y_pred) 即预测的概率,一般情况下真实标签( y_true )已经标注好样本所属类别

y_pred = [0.7, 0.5, 0.6, 0.8]
y_true = [0, 1, 0, 1] #样本0,1,2,3分别属于第0,1,0,1类

以BinaryCrossentropy损失函数为例,N代表样本的大小,如上代码中N=4,loss仅仅指一个中括号 [ ] 中计算的损失:

 Loss=-\frac{1}{N}\sum_{i=1}^{N}y_{i}\cdot ln\left ( p(x_{i}) \right )+(1-y_{i})\cdot ln\left ( 1-p(x_{i}) \right )

在训练期间,对于这些训练数据对应的 y_true 标签不能保证完全正确,如果恰好该样本的 y_true是错的,训练就会对模型产生消极影响。

不做出处理的话,这样的标签计算对于样本而言,无论属于类0还是1,都只计算了一种情况,就是说这样鼓励模型目标类别的概率趋近于1,非目标类别的概率趋近0。但事实上这样做产生的消极影响会模型过分自信的相信原训练数据集,遇到训练数据中没有覆盖的数据时,就无从下手,导致网络过拟合,泛化能力差。

为了处理这种情况,我们以1-α的概率认为原样本是对的,以α的概率认为原样本是错的(即α的概率(x,1-y)是对的)。

1-α的概率与(x,y)相同,即loss计算公式与上相同

 Loss1=-\frac{1}{N}\sum_{i=1}^{N}y\cdot ln\left ( p(x) \right )+(1-y)\cdot ln\left ( 1-p(x) \right )

有α的概率不同(即α的概率(x,1-y)是对的,将1-y取代y代入公式)。则公式为

 Loss2=-\frac{1}{N}\sum_{i=1}^{N}(1-y)\cdot ln\left ( p(x) \right )+(1-(1-y))\cdot ln\left ( 1-p(x) \right )=-\frac{1}{N}\sum_{i=1}^{N}(1-y)\cdot ln\left ( p(x) \right )+y\cdot ln\left ( 1-p(x) \right )

将两个式子进行概率的加权

Loss=(1-\alpha )\cdot Loss1+\alpha \cdot Loss2

=-(1-\alpha )\cdot\left \{ \frac{1}{N}\sum_{i=1}^{N}y\cdot ln\left ( p(x) \right )+(1-y)\cdot ln\left ( 1-p(x) \right )\right \}-\alpha \cdot \left \{ \frac{1}{N}\sum_{i=1}^{N}(1-y)\cdot ln\left ( p(x) \right )+y\cdot ln\left ( 1-p(x) \right ) \right \}

 =-\frac{1}{N}\sum_{i=1}^{N}\left \{ ((1-\alpha )y+\alpha (1-y))\cdot ln\left ( p(x) \right )+((1-\alpha )(1-y)+\alpha y)\cdot ln\left ( 1-p(x) \right ) \right \}

{y}'=(1-\alpha )y+\alpha (1-y)

 Loss=-\frac{1}{N}\sum_{i=1}^{N}\left \{ {y}'\cdot ln\left ( p(x) \right )+(1-{y}')\cdot ln\left ( 1-p(x) \right ) \right \}

可以看到,和原公式相比,仅有 {y}'替换了 y。y的值为0或1,则:

{y}'=\left\{\begin{matrix} \alpha ,y=0\\ 1-\alpha ,y=1 \end{matrix}\right.

即将标签0和1转换为α和1-α,以上是标签平滑的基本思路。未平滑前,模型预测输出尽可能逼近0或1,这个过程可以说是过拟合,正则化就是平滑后的处理,平滑后模型预测输出尽可能逼近α或1-α,逼近后不再向0或1逼近优化,即不再极端化。注意:这里的α并不是label_smoothing值的大小,继续往下看。

在二分类中,计算损失时考虑到了每个样本属于0和1两种类别的情况,即{y}'\cdot ln\left ( p(x) \right )+(1-{y}')\cdot ln\left ( 1-p(x) \right )

前面的{y}'\cdot ln\left ( p(x) \right )是属于一类的情况

后面的(1-{y}')\cdot ln\left ( 1-p(x) \right )是属于另一类的情况

暂且将这样写,其中F(y',p(x))是不同的Loss函数对应的函数,k指的是类别数目

 {y}'\cdot ln\left ( p(x) \right )+(1-{y}')\cdot ln\left ( 1-p(x) \right )=\sum_{j=1}^{K} {y_{j}}'\cdot ln\left ( p(x_{j}) \right )

损失函数Loss可以表示为

 Loss=-\frac{1}{N}\sum_{i=1}^{N}\sum_{j=1}^{K} F({y_{i}}', p(x_{j}))

你可能会问二元交叉熵对应的概率α是清楚的,那多元的呢?

y_true = [[0, 1, 0], [0, 0, 1]]
y_pred = [[0.05, 0.95, 0], [0.1, 0.8, 0.1]]  #两个样本

#三分类问题,即样本[0, 1, 0]属于第1类(从第0类开始数)

TensorFlow中,官方API这样说:如果 label_smoothing为 0.1,则对非目标标签使用 0.1 / num_classes,对目标标签使用 0.9 + 0.1 / num_classes。这是Szegedy等人提出了inception v2的模型(论文:Rethinking the inception architecture for computer vision.),是以均匀分布为前提,采取的概率公式是这样的:

{y}'=y\cdot (1-\alpha )+\frac{\alpha }{K}

y_true = [[0, 1, 0], [0, 0, 1]]
y_pred = [[0.05, 0.95, 0], [0.1, 0.8, 0.1]]  #两个样本

# label_smoothing=β为0.1时
# y=[0, 1, 0],则y’=y*(1-β)+β/K=[0, 1, 0]*0.9+0.1/3=[0.033333, 0.933333, 0.033333]
# 即以0.033333概率选择类别0,以 0.933333概率选择类别1, 以 0.033333概率选择类别2

同理,也满足二分类的情况,即β=2α时

{y}'=\left\{\begin{matrix} \frac{\beta }{2} ,y=0\\ 1-\frac{\beta }{2},y=1 \end{matrix}\right.

下面用代码实验一下:

#BinaryCrossentropy二分类问题
import tensorflow as tf
import math
ls=0.1   #平滑后类别对应的不再是[0,1],而是[0.05,0.95]

y_true = [0, 1, 0]    #这里是3个样本
y_pred = [0.6, 0.3, 0.6]
bce = tf.keras.losses.BinaryCrossentropy(label_smoothing=ls)
print(bce(y_true, y_pred).numpy())
#输出:0.9845474
a = -0.05*math.log(0.6)-0.95*math.log(1-0.6)
b = -0.95*math.log(0.3)-0.05*math.log(1-0.3)
c = -0.05*math.log(0.6)-0.95*math.log(1-0.6)
print((a+b+c)/3)
#输出:0.9845476214146899,大概因为保留的精度不一致,所以最后1位不同

有兄弟可能会问,在预测标签 y_pred 中第三类[0.05, 0.95, 0]中的0,计算log时怎么办,这个情况似乎是TensorFlow以一个极小的正数代替了0,如使用0.000001(我也不清楚,瞎猜的,代入公式推算是正确的)。

CategoricalCrossentropy计算公式:

Loss=-\sum_{j=1}^{K} y_{j}\cdot ln\left ( p(x_{j}) \right )

#CategoricalCrossentropy多分类问题
import tensorflow as tf
import math
ls=0.1

y_true = [0, 1, 0]  #取三分类,一个样本,第0,1,2类平滑后[0.033333, 0.933333, 0.033333]
y_pred = [0.05, 0.95, 0]
cce = tf.keras.losses.CategoricalCrossentropy(label_smoothing=ls)
print(cce(y_true, y_pred).numpy())  #输出:0.6850014
a1 = -0.1/3*math.log(0.05)
b1 = -(0.9+0.1/3)*math.log(0.95)
c1 = -0.1/3*math.log(0.0000001)
print(a1+b1+c1)   #输出:0.6850013389121242,结果一致,仅有一个样本就没有1-N的求和了

标签平滑后相当于在真实分布中加入了噪声,避免模型对于正确标签过于自信,使得预测正负样本的输出值差别不那么大,从而避免过拟合,提高模型的泛化能力。

axis

计算loss的轴(特征轴)。 默认为 -1(-1表示为最后一个维度)。

reduction

适用于损失的 tf.keras.losses.Reduction 类型。 默认值为AUTO。一共AUTO、NONE、SUM、SUM_OVER_BATCH_SIZE四种值

  • NONE:分别计算每个样本的损失,不进行求和
import tensorflow as tf
import math

y_true = [[0, 1, 0], [0, 0, 1]]  #两个样本 1个batch
y_pred = [[0.05, 0.95, 0], [0.1, 0.8, 0.1]]
cce = tf.keras.losses.CategoricalCrossentropy(reduction=tf.keras.losses.Reduction.NONE)
print(cce(y_true, y_pred).numpy())  
#输出:[0.05129331 2.3025851 ],分开计算每个[](一个小样本)内的Loss
a1 = -0*math.log(0.05)  #未进行平滑
b1 = -1*math.log(0.95)
c1 = -0*math.log(0.0000001)

a2 = -0*math.log(0.1)
b2 = -0*math.log(0.8)
c2 = -1*math.log(0.1)

print(a1+b1+c1,a2+b2+c2)   #输出:0.05129329438755058 2.3025850929940455
  • SUM指加权损失的标量和。
cce = tf.keras.losses.CategoricalCrossentropy(reduction=tf.keras.losses.Reduction.SUM)
print(cce(y_true, y_pred).numpy())  #输出:2.3538785

print(a1+b1+c1+a2+b2+c2)   #输出:2.353878387381596
  • AUTO 表示reduction将由上下文确定。几乎所有情况,默认为 SUM_OVER_BATCH_SIZE一样的操作。 当与 tf.distribute.Strategy 一起使用时,在内置训练循环(例如 tf.keras compile and fit)之外,reduction值为 SUM 或 NONE。 在这种情况下使用 AUTO 会引发错误。 
  • SUM_OVER_BATCH_SIZE:标量 SUM 除以损失中的元素数,也就是所有样本的平均损失。
cce = tf.keras.losses.CategoricalCrossentropy(reduction=tf.keras.losses.Reduction.SUM_OVER_BATCH_SIZE)
print(cce(y_true, y_pred).numpy())  #输出:1.1769392

print((a1+b1+c1+a2+b2+c2)/2)   #输出:1.176939193690798

当与 tf.distribute.Strategy 一起使用时,在 tf.keras compile and fit 等内置训练循环之外,使用 AUTO 或 SUM_OVER_BATCH_SIZE 将引发错误。

name

操作的名称。 即使用的Loss函数名称。

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: tf.keras.utils.image_dataset_from_directory是一个函数,用于从目录中读取图像数据集并返回一个tf.data.Dataset对象。它可以自动将图像数据集划分为训练集和验证集,并对图像进行预处理和数据增强。此函数是TensorFlow Keras API的一部分,用于构建深度学习模型。 ### 回答2: tf.keras.utils.image_dataset_from_directory是一个用于从文件夹中加载图像数据集的实用函数。该函数以指定的文件夹路径作为输入,自动将文件夹中的图像按照类别划分,并生成一个tf.data.Dataset对象,用于训练或评估深度学习模型。 该函数的主要参数包括: - directory:指定的文件夹路径,用于加载图像数据集。 - labels:可选参数,指定是否从文件夹的子文件夹中自动提取类别标签。 - label_mode:可选参数,指定类别标签的返回类型。支持"categorical"、"binary"、"sparse"和"int"四种类型。 - batch_size:指定生成的Dataset对象中每个batch的样本数量。 - image_size:可选参数,指定生成的样本的图像大小。 - validation_split:可选参数,指定用于验证集划分的比例。 当调用该函数时,首先会通过遍历指定路径下的所有图片文件,自动提取所有类别的名称。然后,根据提取的类别信息,将文件夹中的图像按照类别划分,并为每个类别生成一个不同的整数标签。最后,将这些划分好的图像数据转换为tf.data.Dataset对象,并将类别标签与样本数据一一对应。 最终生成的Dataset对象中,每个样本都是一个元组,包含图像数据和对应的类别标签。该Dataset对象可以直接用于训练或评估深度学习模型,并且可以通过设置参数来自动进行数据增强、批处理等操作。 使用tf.keras.utils.image_dataset_from_directory函数,可以方便地加载和处理大量的图像数据集,提高模型训练的效率和准确率。 ### 回答3: tf.keras.utils.image_dataset_from_directory是一个用于从文件目录中加载图像数据集的函数。它基于TensorFlow的Keras API,并提供了一种方便的方式来准备图像数据集进行训练和验证。 该函数能够自动地从文件目录读取图像,并创建一个TensorFlow数据集对象,其中每个图像与其标签关联。使用该函数,可以轻松地从文件夹中加载具有不同类别的图像数据,并自动将其划分为训练集和验证集。可以指定训练集和验证集的比例、图像的大小、批次大小等参数。此外,还可以进行数据预处理操作,如图像放缩、归一化等。 使用该函数的步骤如下: 1. 准备图像数据集:将不同类别的图像按照标签存储在不同的文件夹中。 2. 调用image_dataset_from_directory函数:指定图像文件夹的路径,并设定其他参数如图像大小、批次大小等。 3. 接收返回的数据集对象:该对象包含训练集和验证集。 4. 可以将该数据集对象直接用于模型的训练、评估和推理。 该函数的优点是简单易用,能够快速地加载图像数据集,并且能够与tf.data API无缝集成,方便进行数据增强、数据流水线等高级操作。它减少了手动处理图像数据的工作量,使得图像分类、目标检测等任务更加高效。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值