使用tensorflow2定义模型时, 损失函数可以使用keras模块提供的损失函数, 也可以自定义损失函数. 以分类问题的损失函数为例, 有以下几种形式.
内置损失函数
# 二元交叉熵
tf.keras.losses.binary_crossentropy
tf.keras.losses.BinaryCrossentropy
#多分类交叉熵
tf.keras.losses.categorical_crossentropy
tf.keras.losses.CategoricalCrossentropy
tf.keras.losses.sparse_categorical_crossentropy
tf.keras.losses.SparseCategoricalCrossentropy
以上3种交叉熵损失函数的不同写法, 其中使用lower_with_under命名风格的是函数形式, 而使用CapWords命名风格的是类形式, 二者实质上没有区别, 仅在使用时有不同. 下面是两种形式的使用:
import numpy as np
import tensorflow as tf
labels = np.array([0, 1, 2], dtype=np.float32)
labels_onehot = tf.keras.utils.to_categorical(labels)
logits = np.array([2.9, .1, .05, .3, 1.9, .1, .05, .05, 1.9],
dtype=np.float32).reshape(-1, 3)
logits_softmax = tf.keras.layers.Softmax()(logits)
print(tf.keras.losses.CategoricalCrossentropy()(labels_onehot, logits_softmax))
print(tf.keras.losses.categorical_crossentropy(labels_onehot, logits_softmax))
# 输出结果为
# tf.Tensor(0.23277493, shape=(), dtype=float32)
# tf.Tensor([0.11212645 0.31276152 0.27343687], shape=(3,), dtype=float32)
以上几种交叉熵损失函数的不同
- categorical_crossentropy要求labels是onehot编码, 因此使用to_categorical函数处理原始labels.
- 以上损失函数不会对logits做归一化, 因此使用softmax处理原始logits.
- sparse_categorical_crossentropy要求labels是序号编码.
自定义损失函数
自定义损失函数通常有两种方法. 直接定义函数作为损失函数, 该函数要求输入两个张量y_true, y_pred作为输入参数, 并输出一个标量作为损失函数值; 对tf.keras.losses.Loss进行子类化, 重写call方法实现损失的计算逻辑, 从而得到损失函数的类的实现.
- 直接定义函数
def categorical_cross_entropy(n_classes):
def _categorical_cross_entropy(labels, logits):
""" Computes cross entropy between labels and logits.
Args:
labels: an array of numpy or a 'Tensor', shape = [?, W, H, n_classes].
logits: output of the model by softmax, shape = [?, W, H, n_classes].
Returns:
The value of the weighted cross entropy.
"""
flat_labels = tf.cast(tf.reshape(labels, [-1, n_classes]), dtype=tf.float32)
flat_logits = tf.cast(tf.reshape(logits, [-1, n_classes]), dtype=tf.float32)
weight_cross_entropy = -tf.reduce_sum(
tf.multiply(flat_labels*tf.math.log(flat_logits), weights),
axis=1)
return tf.reduce_mean(weight_cross_entropy)
return _categorical_cross_entropy
- 自定义复杂的损失函数, tf的模型在compile时需要显示地指定损失函数, 如果自定义损失函数, 只需要声明一个接受两个参数(y_true, y_pred)的函数.
def mask_loss(y_true, y_pred):
"""
y_pred: no scaled by softmax.
"""
y_true = tf.reshape(y_true, [-1, 3])
label = y_true[:, :-1]
mask = y_true[:, -1]
y_pred = tf.reshape(y_pred, [-1, 2])
loss_no_mask = tf.nn.softmax_cross_entropy_with_logits(label, y_pred)
loss_mask = loss_no_mask * mask
return tf.reduce_mean(loss_mask)
网友评论