損失函數的目的是計算模型在訓練期間應尋求最小化的量。
請注意,所有損失都可以透過類別控制代碼和函數控制代碼取得。類別控制代碼讓您可以將組態引數傳遞給建構子 (例如 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()
為 "float32"
,除非設定為不同的值 (透過 keras.backend.set_floatx()
)。如果提供 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
的注意事項:所有損失函數都會縮減 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()
文件。