损失函数旨在计算模型在训练期间应尽量减小的量。
请注意,所有损失函数都可以通过类句柄和函数句柄获得。类句柄允许您将配置参数传递给构造函数(例如 loss_fn = CategoricalCrossentropy(from_logits=True)
),并且在单独使用时默认执行归约(详见下文)。
Loss
类keras.losses.Loss(name=None, reduction="sum_over_batch_size", dtype=None)
损失函数基类。
这是用于创建新的自定义损失函数时应继承的类。
参数
"sum_over_batch_size"
。支持的选项包括 "sum"
、"sum_over_batch_size"
、"mean"
、"mean_with_sample_weight"
或 None
。"sum"
对损失求和,"sum_over_batch_size"
和 "mean"
对损失求和并除以样本大小,而 "mean_with_sample_weight"
对损失求和并除以样本权重的总和。"none"
和 None
不执行聚合。默认为 "sum_over_batch_size"
。None
,这意味着使用 keras.backend.floatx()
。keras.backend.floatx()
除非通过 keras.backend.set_floatx()
设置为其他值,否则为 "float32"
。如果提供了 keras.DTypePolicy
,则将使用 compute_dtype
。由子类实现
call()
: 包含使用 y_true
、y_pred
计算损失的逻辑。子类实现示例
class MeanSquaredError(Loss):
def call(self, y_true, y_pred):
return ops.mean(ops.square(y_pred - y_true), axis=-1)
compile()
和 fit()
中使用损失函数损失函数是编译 Keras 模型所需的两个参数之一
import keras
from keras import layers
model = keras.Sequential()
model.add(layers.Dense(64, kernel_initializer='uniform', input_shape=(10,)))
model.add(layers.Activation('softmax'))
loss_fn = keras.losses.SparseCategoricalCrossentropy()
model.compile(loss=loss_fn, optimizer='adam')
所有内置损失函数也可以通过其字符串标识符传递
# pass optimizer by name: default parameters will be used
model.compile(loss='sparse_categorical_crossentropy', optimizer='adam')
损失函数通常通过实例化损失类来创建(例如 keras.losses.SparseCategoricalCrossentropy
)。所有损失函数也作为函数句柄提供(例如 keras.losses.sparse_categorical_crossentropy
)。
使用类可以在实例化时传递配置参数,例如
loss_fn = keras.losses.SparseCategoricalCrossentropy(from_logits=True)
损失函数是一个可调用对象,其参数为 loss_fn(y_true, y_pred, sample_weight=None)
(batch_size, d0, ... dN)
。对于稀疏损失函数,例如稀疏分类交叉熵,形状应为 (batch_size, d0, ... dN-1)
(batch_size, d0, .. dN)
。sample_weight
作为按样本损失的归约加权系数。如果提供标量,则损失函数简单地按给定值缩放。如果 sample_weight
是大小为 [batch_size]
的张量,则批次中每个样本的总损失将按 sample_weight
向量中对应的元素重新缩放。如果 sample_weight
的形状为 (batch_size, d0, ... dN-1)
(或可以广播到此形状),则 y_pred
的每个损失元素都将按 sample_weight
的对应值缩放。(关于 dN-1
的说明:所有损失函数都会沿一个维度(通常是 axis=-1
)进行归约。)默认情况下,损失函数会为批次维度中的每个输入样本返回一个标量损失值,例如
>>> from keras import ops
>>> keras.losses.mean_squared_error(ops.ones((2, 2,)), ops.zeros((2, 2)))
<Array: shape=(2,), dtype=float32, numpy=array([1., 1.], dtype=float32)>
但是,损失类实例具有一个 reduction
构造函数参数,该参数默认为 "sum_over_batch_size"
(即平均)。允许的值为 "sum_over_batch_size"、"sum" 和 "none"
>>> loss_fn = keras.losses.MeanSquaredError(reduction='sum_over_batch_size')
>>> loss_fn(ops.ones((2, 2,)), ops.zeros((2, 2)))
<Array: shape=(), dtype=float32, numpy=1.0>
>>> loss_fn = keras.losses.MeanSquaredError(reduction='sum')
>>> loss_fn(ops.ones((2, 2,)), ops.zeros((2, 2)))
<Array: shape=(), dtype=float32, numpy=2.0>
>>> loss_fn = keras.losses.MeanSquaredError(reduction='none')
>>> loss_fn(ops.ones((2, 2,)), ops.zeros((2, 2)))
<Array: shape=(2,), dtype=float32, numpy=array([1., 1.], dtype=float32)>
请注意,这是函数式损失函数(例如 keras.losses.mean_squared_error
)和默认损失类实例(例如 keras.losses.MeanSquaredError
)之间的重要区别:函数版本不执行归约,但类实例默认执行归约。
>>> loss_fn = keras.losses.mean_squared_error
>>> loss_fn(ops.ones((2, 2,)), ops.zeros((2, 2)))
<Array: shape=(2,), dtype=float32, numpy=array([1., 1.], dtype=float32)>
>>> loss_fn = keras.losses.MeanSquaredError()
>>> loss_fn(ops.ones((2, 2,)), ops.zeros((2, 2)))
<Array: shape=(), dtype=float32, numpy=1.0>
使用 fit()
时,此差异无关紧要,因为归约由框架处理。
以下是如何在简单训练循环中使用损失类实例
loss_fn = keras.losses.CategoricalCrossentropy(from_logits=True)
optimizer = keras.optimizers.Adam()
# Iterate over the batches of a dataset.
for x, y in dataset:
with tf.GradientTape() as tape:
logits = model(x)
# Compute the loss value for this batch.
loss_value = loss_fn(y, logits)
# Update the weights of the model to minimize the loss value.
gradients = tape.gradient(loss_value, model.trainable_weights)
optimizer.apply_gradients(zip(gradients, model.trainable_weights))
任何具有 loss_fn(y_true, y_pred)
签名并返回损失数组(输入批次中每个样本一个损失)的可调用对象都可以作为损失函数传递给 compile()
。请注意,任何此类损失函数都自动支持样本加权。
以下是一个简单示例
from keras import ops
def my_loss_fn(y_true, y_pred):
squared_difference = ops.square(y_true - y_pred)
return ops.mean(squared_difference, axis=-1) # Note the `axis=-1`
model.compile(optimizer='adam', loss=my_loss_fn)
add_loss()
API应用于模型输出的损失函数并非创建损失的唯一方式。
在编写自定义层或子类化模型的 call
方法时,您可能需要计算在训练期间想要最小化的标量值(例如正则化损失)。您可以使用 add_loss()
层方法来跟踪此类损失项。
以下是一个层的示例,它基于输入的 L2 范数添加一个稀疏性正则化损失
from keras import ops
class MyActivityRegularizer(keras.layers.Layer):
"""Layer that creates an activity sparsity regularization loss."""
def __init__(self, rate=1e-2):
super().__init__()
self.rate = rate
def call(self, inputs):
# We use `add_loss` to create a regularization loss
# that depends on the inputs.
self.add_loss(self.rate * ops.sum(ops.square(inputs)))
return inputs
通过 add_loss
添加的损失值可以在任何 Layer
或 Model
的 .losses
列表属性中检索到(它们会从每个底层递归检索)
from keras import layers
from keras import ops
class SparseMLP(layers.Layer):
"""Stack of Linear layers with a sparsity regularization loss."""
def __init__(self, output_dim):
super().__init__()
self.dense_1 = layers.Dense(32, activation=ops.relu)
self.regularization = MyActivityRegularizer(1e-2)
self.dense_2 = layers.Dense(output_dim)
def call(self, inputs):
x = self.dense_1(inputs)
x = self.regularization(x)
return self.dense_2(x)
mlp = SparseMLP(1)
y = mlp(ops.ones((10, 10)))
print(mlp.losses) # List containing one float32 scalar
这些损失会在每个前向传播开始时由顶层清除 - 它们不会累积。因此 layer.losses
始终只包含上一次前向传播期间创建的损失。在编写训练循环时,您通常会在计算梯度之前通过对这些损失求和来使用它们。
# Losses correspond to the *last* forward pass.
mlp = SparseMLP(1)
mlp(ops.ones((10, 10)))
assert len(mlp.losses) == 1
mlp(ops.ones((10, 10)))
assert len(mlp.losses) == 1 # No accumulation.
使用 model.fit()
时,此类损失项会自动处理。
编写自定义训练循环时,应手动从 model.losses
中检索这些项,如下所示
loss_fn = keras.losses.CategoricalCrossentropy(from_logits=True)
optimizer = keras.optimizers.Adam()
# Iterate over the batches of a dataset.
for x, y in dataset:
with tf.GradientTape() as tape:
# Forward pass.
logits = model(x)
# Loss value for this batch.
loss_value = loss_fn(y, logits)
# Add extra loss terms to the loss value.
loss_value += sum(model.losses)
# Update the weights of the model to minimize the loss value.
gradients = tape.gradient(loss_value, model.trainable_weights)
optimizer.apply_gradients(zip(gradients, model.trainable_weights))
有关更多详细信息,请参阅 add_loss()
文档。