- 教程
- 深度学习
- 机器学习
【免费下载链接】eat_tensorflow2_in_30_days
Tensorflow2.0 🍎🍊 is delicious, just eat it! 😋😋
在eat_tensorflow2_in_30_days项目第五章(中阶 API)中,5-5,损失函数losses.md 系统讲解了深度学习目标函数的构成、Keras 内置损失函数的选择原则,以及两种自定义损失函数的实现范式。本文以该文档为骨架,结合仓库中 1-1,结构化数据建模流程范例.md、1-3,文本数据建模流程范例.md、1-4,时间序列数据建模流程范例.md、6-2,训练模型的3种方法.md 等章节中的真实调用代码,深入讲解回归、二分类、多分类场景下的损失函数选型,并给出可直接复制运行的 Focal Loss 自定义实现。读完本文,你将掌握:如何在model.compile与自定义训练循环中正确指定损失函数、如何理解正则化项与约束项在目标函数中的作用,以及如何用函数式和类式两种写法实现自己的损失函数。
一、目标函数的构成:损失函数 + 正则化项
监督学习的目标函数一般由损失函数(Loss)和正则化项(Regularization)两部分组成:
Objective = Loss + Regularization其中损失函数衡量模型预测与真实标签之间的差距,是梯度下降优化的直接对象;而正则化项则是对模型复杂度施加的惩罚,用于抑制过拟合。两者共同决定了模型参数的最优方向。
1.1 正则化项在层中指定
对于 Keras 模型,目标函数中的正则化项一般在各层内部指定,而不是在编译阶段传入。以layers.Dense为例,常用的正则化相关参数有:
kernel_regularizer:对权重矩阵 W 施加正则化,如regularizers.l1(0.01)、regularizers.l2(0.01)、regularizers.l1_l2(l1, l2);bias_regularizer:对偏置向量 b 施加正则化;activity_regularizer:对层输出(激活后的值)施加正则化;kernel_constraint/bias_constraint:约束权重或偏置的取值范围,例如constraints.MaxNorm(max_value=2, axis=0)将每个权向量的范数限制在 2 以内。这同样是一种正则化手段,通过在优化迭代中把参数投影回约束域来实现。
以下是原文档给出的完整示例,构造了一个带多种正则化与约束的两层网络,并以binary_crossentropy作为损失函数、AUC作为评估指标完成编译:
import numpy as np import pandas as pd import tensorflow as tf from tensorflow.keras import layers, models, losses, regularizers, constraints tf.keras.backend.clear_session() model = models.Sequential() model.add(layers.Dense(64, input_dim=64, kernel_regularizer=regularizers.l2(0.01), activity_regularizer=regularizers.l1(0.01), kernel_constraint=constraints.MaxNorm(max_value=2, axis=0))) model.add(layers.Dense(10, kernel_regularizer=regularizers.l1_l2(0.01, 0.01), activation="sigmoid")) model.compile(optimizer="rmsprop", loss="binary_crossentropy", metrics=["AUC"]) model.summary()输出(模型结构示意,两个全连接层合计 4810 个可训练参数):
Model: "sequential" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= dense (Dense) (None, 64) 4160 _________________________________________________________________ dense_1 (Dense) (None, 10) 650 ================================================================= Total params: 4,810 Trainable params: 4,810 Non-trainable params: 0 _________________________________________________________________要点:正则化项绑定在层上、随层一起序列化保存;而损失函数则在model.compile(loss=...)时统一指定。二者职责分离,这是 Keras 目标函数设计的基本约定。
1.2 损失函数在编译时指定
损失函数在模型编译(compile)时指定,针对不同任务有明确的选择惯例:
| 任务类型 | 推荐损失函数 | 说明 |
|---|---|---|
| 回归 | mean_squared_error(mse) | 均方误差,衡量预测值与真实值平方差的均值 |
| 二分类 | binary_crossentropy | 二元交叉熵 |
| 多分类(label 为 one-hot 编码) | categorical_crossentropy | 类别交叉熵 |
| 多分类(label 为类别序号编码) | sparse_categorical_crossentropy | 稀疏类别交叉熵 |
多分类任务中,标签编码方式直接决定损失函数的选择:one-hot 编码(如[0,1,0,0])配categorical_crossentropy,整数序号编码(如2)配sparse_categorical_crossentropy,两者计算等价,只是输入形式不同。
二、内置损失函数:类的实现与函数的实现
Keras 内置损失函数一般有类实现和函数实现两种形式。例如CategoricalCrossentropy和categorical_crossentropy都是类别交叉熵,前者是类(tf.keras.losses.CategoricalCrossentropy),后者是函数(tf.keras.losses.categorical_crossentropy)。类实现可以携带状态与配置、支持序列化,通常在自定义训练循环中作为对象调用;函数实现更轻量,适合直接传入compile或低阶 API。
原文档列出的常用内置损失函数整理如下:
| 损失函数 | 用途 | 简写 | 类实现 / 函数实现 |
|---|---|---|---|
mean_squared_error | 回归,均方误差 | mse/MSE | MeanSquaredError |
mean_absolute_error | 回归,平均绝对误差 | mae/MAE | MeanAbsoluteError |
mean_absolute_percentage_error | 回归,平均百分比误差 | mape/MAPE | MeanAbsolutePercentageError |
Huber | 回归,介于 mse 与 mae 之间,对异常值鲁棒 | — | 仅类实现Huber |
binary_crossentropy | 二分类,二元交叉熵 | — | BinaryCrossentropy |
categorical_crossentropy | 多分类(label one-hot) | — | CategoricalCrossentropy |
sparse_categorical_crossentropy | 多分类(label 序号编码) | — | SparseCategoricalCrossentropy |
hinge | 二分类,SVM 经典损失(合页损失) | — | Hinge |
kld | 相对熵(KL 散度),度量两个概率分布差异,常用于 EM 类算法 | — | KLDivergence/KLD |
cosine_similarity | 余弦相似度,可用于多分类 | — | CosineSimilarity |
2.1 仓库中的实际用法印证
这些内置损失在项目各实战章节中均有直接调用,可相互印证:
- 回归:3-3,高阶API示范.md 中
model.compile(optimizer="adam", loss="mse", metrics=["mae"])以字符串形式传入 mse;6-6,使用tensorflow-serving部署模型.md 中线性回归模型同样使用loss="mse"。 - 二分类:1-1,结构化数据建模流程范例.md 中泰坦尼克生存预测使用
loss='binary_crossentropy', metrics=['AUC'],与本文示例配置一致。 - 多分类:6-4,使用多GPU训练模型.md 与 6-5,使用TPU训练模型.md 中均使用类实现
losses.SparseCategoricalCrossentropy(from_logits=True),并显式声明from_logits=True——当网络最后一层是线性输出(未经过 softmax)时,必须开启该参数,让交叉熵在内部完成 softmax 计算,数值上更稳定。
2.2 在自定义训练循环中使用类实现
内置损失函数的类实现可以直接作为对象在tf.GradientTape中调用。1-3,文本数据建模流程范例.md 展示了 IMDb 文本分类中losses.BinaryCrossentropy()的完整用法:
optimizer = optimizers.Nadam() loss_func = losses.BinaryCrossentropy() train_loss = metrics.Mean(name='train_loss') train_metric = metrics.BinaryAccuracy(name='train_accuracy') @tf.function def train_step(model, features, labels): with tf.GradientTape() as tape: predictions = model(features, training=True) loss = loss_func(labels, predictions) gradients = tape.gradient(loss, model.trainable_variables) optimizer.apply_gradients(zip(gradients, model.trainable_variables)) train_loss.update_state(loss) train_metric.update_state(labels, predictions)这里loss_func作为可调用对象接收(labels, predictions)返回标量损失,与metrics.Mean配合在批次间累加平均,构成一个完整的中阶 API 自定义训练循环。
三、自定义损失函数:函数式与类式两种范式
当内置损失无法满足需求时,Keras 支持两种自定义方式,二者的共同接口约定是:接收两个张量y_true和y_pred作为输入,输出一个标量作为损失值。
3.1 函数式定义
直接编写一个接收(y_true, y_pred)、返回标量的函数即可,函数闭包可以捕获超参数:
def focal_loss(gamma=2., alpha=0.75): def focal_loss_fixed(y_true, y_pred): bce = tf.losses.binary_crossentropy(y_true, y_pred) p_t = (y_true * y_pred) + ((1 - y_true) * (1 - y_pred)) alpha_factor = y_true * alpha + (1 - y_true) * (1 - alpha) modulating_factor = tf.pow(1.0 - p_t, gamma) loss = tf.reduce_sum(alpha_factor * modulating_factor * bce, axis=-1) return loss return focal_loss_fixed3.2 类式定义:继承tf.keras.losses.Loss
对tf.keras.losses.Loss进行子类化,重写call方法实现损失计算逻辑,即可得到带配置能力的类实现:
class FocalLoss(tf.keras.losses.Loss): def __init__(self, gamma=2.0, alpha=0.75, name="focal_loss"): self.gamma = gamma self.alpha = alpha def call(self, y_true, y_pred): bce = tf.losses.binary_crossentropy(y_true, y_pred) p_t = (y_true * y_pred) + ((1 - y_true) * (1 - y_pred)) alpha_factor = y_true * self.alpha + (1 - y_true) * (1 - self.alpha) modulating_factor = tf.pow(1.0 - p_t, self.gamma) loss = tf.reduce_sum(alpha_factor * modulating_factor * bce, axis=-1) return loss两种写法计算逻辑完全一致;类式实现额外具备name标识,便于在compile、TensorBoard 与模型保存中区分。
3.3 Focal Loss 的原理与参数含义
Focal Loss 是对binary_crossentropy的一种改进,在样本不均衡且存在大量易分类样本的场景下,相比普通二元交叉熵具有明显优势。它引入两个可调参数:
alpha:主要用于衰减负样本的权重(默认0.75,偏向正样本);gamma:主要用于衰减容易训练样本的权重(默认2.0)。
通过二者配合,模型将注意力聚焦在正样本和困难样本上——这正是 "Focal"(聚焦)名称的由来。其数学定义如下:
$$ focal_loss(y,p) = \begin{cases} -\alpha (1-p)^{\gamma}\log(p) & \text{if y = 1}\ -(1-\alpha) p^{\gamma}\log(1-p) & \text{if y = 0} \end{cases} $$
对照代码理解:p_t表示样本被正确分类的概率(y=1时取p,y=0时取1-p);modulating_factor = (1-p_t)^gamma是调制因子,样本越易分类(p_t越接近 1)其惩罚越小,从而压低易样本的贡献;alpha_factor则按标签类别加权,实现正负样本的平衡。
3.4 仓库中的自定义损失实例:MSPE
自定义损失在仓库中有多处真实应用。1-4,时间序列数据建模流程范例.md 为新冠新增病例预测定义了 MSPE(平均平方百分比误差),并实现了get_config以保证可序列化:
# 自定义损失函数,考虑平方差和预测目标的比值 class MSPE(losses.Loss): def call(self, y_true, y_pred): err_percent = (y_true - y_pred)**2 / (tf.maximum(y_true**2, 1e-7)) mean_err_percent = tf.reduce_mean(err_percent) return mean_err_percent def get_config(self): config = super(MSPE, self).get_config() return config随后以model.compile(optimizer=optimizer, loss=MSPE(name="MSPE"))的方式传入编译(1-4,时间序列数据建模流程范例.md),并在模型加载后(第570行)复用同一损失完成评估。注意其中tf.maximum(y_true**2, 1e-7)的写法是为了防止除零,这是自定义损失函数中常见的数值稳定性处理技巧,与 Focal Loss 中的实现细节异曲同工。
四、损失函数在三种训练范式中的接入方式
结合 6-2,训练模型的3种方法.md 的划分,损失函数在 Keras 的三种训练范式中接入位置不同,本质却一致:
- 内置训练(
model.fit):损失在compile阶段传入,字符串、函数、类实例三者皆可,如 5-4,模型层layers.md 的model.compile(optimizer="sgd", loss="mse", metrics=["mae"]); - 自定义训练循环(
tf.GradientTape):损失作为对象在每一步前向传播中手动计算,如 1-3,文本数据建模流程范例.md 所示; - 中阶 API 方式(
model.loss_func属性):3-2,中阶API示范.md 将losses.mean_squared_error或losses.binary_crossentropy赋值给模型的loss_func属性,在自定义的train_step中调用(第112行、第294行),实现"半内置半自定义"的训练流程。
五、小结与延伸阅读
本仓库的 eat_tf2_ebook.md 收录了全部章节的合订内容(其中 MSPE、SparseCategoricalCrossentropy(from_logits=True)、loss="mse"等用法均与各章节一一对应),english/Chapter5-5.md 提供了本章的英文版本,适合对照阅读。
核心结论回顾:
- 目标函数 = 损失函数 + 正则化项;正则化(
*_regularizer、*_constraint)在层中声明,损失函数在compile时指定; - 选型口诀:回归用
mse,二分类用binary_crossentropy,多分类依据标签编码选择categorical_crossentropy(one-hot)或sparse_categorical_crossentropy(序号); - 内置损失有类/函数双实现,类实现支持状态、配置与序列化,适合自定义训练循环;
- 自定义损失只需实现
(y_true, y_pred) -> scalar,函数式适合快速原型,继承tf.keras.losses.Loss重写call(可选实现get_config)适合正式项目;Focal Loss 通过alpha平衡正负样本、gamma聚焦困难样本,是样本不均衡场景下的首选改造方向。
- 教程
- 深度学习
- 机器学习
【免费下载链接】eat_tensorflow2_in_30_days
Tensorflow2.0 🍎🍊 is delicious, just eat it! 😋😋
相关推荐
awesome-copilot 技能深度解析:使用 Microsoft Fabric Data Factory 将数据接入 Lakehouse 的完整指南
awesome copilot 技能深度解析:使用 Microsoft Fabric Data Factory 将数据接入 Lakehouse 的完整指南 本文
教程深度学习机器学习SuperGradients 损失函数(Loss)完全指南:内置损失、自定义损失与配置化训练
SuperGradients 损失函数(Loss)完全指南:内置损失、自定义损失与配置化训练 导读 在 SuperGradients 中,损失函数(Loss)是
深度学习计算机视觉预训练人工智能D2L.ai损失函数大全:交叉熵、Focal Loss与对比损失
D2L.ai损失函数大全:交叉熵、Focal Loss与对比损失 深度学习中的损失函数是模型训练的核心,它衡量了模型预测与实际标签之间的差异。在D2L.ai这个
文档教程人工智能深度学习NLP计算机视觉强化学习
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考