tf.keras快速入门——自定义损失函数(二)

    在上篇tf.keras快速入门——自定义损失函数(一)中提到了函数式和继承tf.keras.losses.Loss以实例化子类式的两种损失函数的自定义方式。但是,在文末我们也提到了,这两种方式其实还有存在很大的局限性,故而在本文中将讨论另一种更加灵活的自定义损失函数的方式。
复杂度&学习率&损失函数一文中,实现了这个过程,这里还是粘贴一个简单的例子:
定义损失函数为一个分段函数。当预测值大于真实值,我们认为对我们模型不利,即:
f ( y ^ , y ) = { 3 ( y ^ − y )      y ^ ⩾ y y − y ^      y ^ ⩽ y f(\hat y, y) = \left\{ \begin{matrix} 3(\hat y - y) \ \ \ \ \hat y \geqslant y \\ y - \hat y \ \ \ \ \hat y \leqslant y \end{matrix} \right. f(y^,y)={ 3(y^y)    y^yyy^    y^y

import tensorflow as tf
x = tf.random.normal([20, 2], mean=2, stddev=1, dtype=tf.float32)
y = [item1 + 2 * item2 for item1, item2 in x]
w = tf.Variable(tf.random.normal([2, 1], mean=0, stddev=1))

epoch = 5000
lr = 0.002
for epoch in range(epoch):
    with tf.GradientTape() as tape:
        y_hat = tf.matmul(x, w)
        loss = tf.reduce_mean(tf.where(tf.greater(y_hat, y), 3*(y_hat - y), y-y_hat))
    w_grad = tape.gradient(loss, w)
    w.assign_sub(lr * w_grad)

print(w.numpy().T) # [[0.73728406 0.83368826]]

这里,我们还是以鸢尾花分类为例,这里对它进行改造。结合前面所讲的自定义ModelLayer等进行。

class MyLayer(tf.keras.layers.Layer):
    def __init__(self, _shape, activation='relu'):
        super(MyLayer, self).__init__()
        self._shape = _shape
        self.activation = activation
    
    def build(self, input_shape):
        self.kernel = self.add_weight("kernel", shape=(int(input_shape[-1]), self._shape),initializer='random_normal',trainable=True)
        self.bias=self.add_weight(shape=(self._shape,),initializer='random_normal',trainable=True)
        
    def call(self, inputs):
        out = tf.matmul(inputs, self.kernel) + self.bias
        if self.activation == 'relu':
            out = tf.nn.relu(out)
        if self.activation == 'softmax':
            out = tf.nn.softmax(out)
        return out                       
import matplotlib.pyplot as plt
%matplotlib inline
import tensorflow as tf
from sklearn.datasets import load_iris
# 训练集和测试集的划分
from sklearn.model_selection import train_test_split

x_data = load_iris().data  # 特征,【花萼长度,花萼宽度,花瓣长度,花瓣宽度】
y_data = load_iris().target # 分类
x_train, x_test, y_train, y_test = train_test_split(x_data, y_data, test_size=0.30, random_state=42)


class MyModel(tf.keras.Model):
    def __init__(self, hidden_shape, output_shape):
        super(MyModel, self).__init__()
        self.layer1 = tf.keras.layers.Dense(hidden_shape, activation='relu')
        self.layer2 = tf.keras.layers.Dense(output_shape, activation='softmax')
        
    def call(self, inputs):
        h1 = self.layer1(inputs)
        out = self.layer2(h1)
        return out

model = MyModel(hidden_shape=4, output_shape=3)

train_loss = tf.keras.metrics.Mean(name='train_loss')
train_acc = tf.keras.metrics.CategoricalAccuracy(name='train_acc')
    
def train():
    with tf.GradientTape() as tape:
        # 1. 前向传播计算y
        out = model(x_train)
        y_train_one_hot = tf.one_hot(y_train, depth=3)
        # 2. 定义Loss
        loss = tf.losses.categorical_crossentropy(y_train_one_hot, out)
    gradients = tape.gradient(loss, model.trainable_variables)  # 反向求导
    tf.optimizers.Adam().apply_gradients(zip(gradients, model.trainable_variables))  # 参数更新
    
    train_loss(loss)  # train_loss.update_state(loss)
    train_acc(y_train_one_hot, out) # train_acc.update_state(y_train_one_hot, out)


history = dict()
for epoch in range(300):
    train_loss.reset_states()
    train_acc.reset_states()
    train()
    try:
        history['epoch'].append(epoch+1)
    except:
        history['epoch'] = [epoch+1]
    try:
        history['loss'].append(train_loss.result())
    except:
        history['loss'] = [train_loss.result()]
    try:
        history['acc'].append(train_acc.result())
    except:
        history['acc'] = [train_acc.result()]
    
    template = 'Epoch {}, loss: {}, acc: {}'
    print (template.format(epoch+1, train_loss.result(), train_acc.result()))

    
for key in history.keys():
    if key != 'epoch':
        plt.plot(history['epoch'], history[key])

在这里插入图片描述
内容参考:TensorFlow2.0 自定义损失函数

猜你喜欢

转载自blog.csdn.net/qq_26460841/article/details/113624428