Tensorflow Keras сохраняет потерю каждого пакета

#python #tensorflow #keras

#питон #tensorflow #keras

Вопрос:

Я ищу советы / примеры для наилучшей практики при построении моей архитектуры модели keras.

Я возился с различными итерациями подкласса Model() и Функциональной модели, но не смог соединить все точки.

Модель должна иметь пользовательские показатели и связанные с ними потери где-по: Во время обучения показатели вычисляются для каждого пакета, а в конце каждой эпохи итоговые показатели / потери вычисляются из среднего значения вычислений пакета.

На мой взгляд, мне понадобился бы a Custom_Batch_Metric() , который поддерживал бы список показателей для каждой партии, в дополнение к a Custom_Final_Metric() , который усреднял бы результаты из каждой партии. Я не уверен, как это реализовать.

Например… Для каждой партии я хотел бы сгенерировать metric и loss для корреляции y_true, y_pred. В конце моей эпохи я хотел бы затем усреднить (или найти максимальное значение) пакетных корреляций.

Был бы очень признателен за любое чтение, на которое кто-нибудь мог бы указать мне относительно такого рода архитектуры.

Ответ №1:

Простым решением является подкласс tf.keras.callbacks.Callback и определение on_train_batch_end (или тестирование). А затем также on_epoch_end .

 class SaveBatchLoss(tf.keras.callbacks.Callback):
    def on_train_batch_end(self, batch, logs=None): 
        batch_end_loss.append(logs['loss'])
 
 import tensorflow as tf
from tensorflow.keras.layers import Dense
from sklearn.datasets import load_iris
import numpy as np

X, y = load_iris(return_X_y=True)
X = X.astype(np.float32)

ds = tf.data.Dataset.from_tensor_slices((X, y)).shuffle(25).batch(8)

model = tf.keras.Sequential([
    Dense(16, activation='relu'),
    Dense(32, activation='relu'),
    Dense(3, activation='softmax')])

model.compile(loss='sparse_categorical_crossentropy', optimizer='adam', 
              metrics=['accuracy'])

batch_end_loss = list()

class SaveBatchLoss(tf.keras.callbacks.Callback):
    def on_train_batch_end(self, batch, logs=None):
        batch_end_loss.append(logs['loss'])

history = model.fit(ds, epochs=10, callbacks=SaveBatchLoss())

batch_end_loss[::20]
 
 [1.2742226123809814,
 0.9069833755493164,
 0.9728888869285583,
 0.9536505937576294,
 0.8957988023757935,
 0.8624499440193176,
 0.7952101826667786,
 0.7765023112297058,
 0.7615134716033936,
 0.7278715968132019]
 

В качестве более сложного подхода добавьте значения потерь в список в конце каждой партии и в другой список в конце каждой операции. Вот так:

 train_loss_per_train_batch = list()
train_loss_per_train_epoch = list()

for epoch in range(1, 25   1): 
    train_loss = tf.metrics.Mean()
    train_acc = tf.metrics.SparseCategoricalAccuracy()
    test_loss = tf.metrics.Mean()
    test_acc = tf.metrics.SparseCategoricalAccuracy()

    for x, y in train:
        loss_value, grads = get_grad(model, x, y)
        optimizer.apply_gradients(zip(grads, model.trainable_variables))
        train_loss.update_state(loss_value)
        train_acc.update_state(y, model(x, training=True))
        train_loss_per_train_batch.append(loss_value.numpy())
    
    train_loss_per_train_epoch.append(train_loss.result())
 

Полный обучающий сценарий, реализующий это, будет:

 import tensorflow as tf
import tensorflow_datasets as tfds

ds = tfds.load('iris', split='train', as_supervised=True)

train = ds.take(125).shuffle(16).batch(4)
test = ds.skip(125).take(25).shuffle(16).batch(4)

class MyModel(tf.keras.Model):
    def __init__(self):
        super(MyModel, self).__init__()
        self.d1 = tf.keras.layers.Dense(16, activation='relu')
        self.d2 = tf.keras.layers.Dense(32, activation='relu')
        self.d3 = tf.keras.layers.Dense(3, activation='softmax')

    def call(self, x, training=None, **kwargs):
        x = self.d1(x)
        x = self.d2(x)
        x = self.d3(x)
        return x

model = MyModel()

loss_object = tf.losses.SparseCategoricalCrossentropy(from_logits=False)


def compute_loss(model, x, y, training):
  out = model(x, training=training)
  loss = loss_object(y_true=y, y_pred=out)
  return loss


def get_grad(model, x, y):
    with tf.GradientTape() as tape:
        loss = compute_loss(model, x, y, training=True)
    return loss, tape.gradient(loss, model.trainable_variables)


optimizer = tf.optimizers.Adam()

verbose = "Epoch {:2d} Loss: {:.3f} TLoss: {:.3f} Acc: {:.2%} TAcc: {:.2%}"

train_loss_per_train_batch = list()
train_loss_per_train_epoch = list()

for epoch in range(1, 25   1):
    train_loss = tf.metrics.Mean()
    train_acc = tf.metrics.SparseCategoricalAccuracy()
    test_loss = tf.metrics.Mean()
    test_acc = tf.metrics.SparseCategoricalAccuracy()

    for x, y in train:
        loss_value, grads = get_grad(model, x, y)
        optimizer.apply_gradients(zip(grads, model.trainable_variables))
        train_loss.update_state(loss_value)
        train_acc.update_state(y, model(x, training=True))
        train_loss_per_train_batch.append(loss_value.numpy())

    train_loss_per_train_epoch.append(train_loss.result())

    for x, y in test:
        loss_value, _ = get_grad(model, x, y)
        test_loss.update_state(loss_value)
        test_acc.update_state(y, model(x, training=False))

    print(verbose.format(epoch,
                         train_loss.result(),
                         test_loss.result(),
                         train_acc.result(),
                         test_acc.result()))
 

Комментарии:

1. Спасибо. Все очень полезно. Я собираюсь потратить некоторое время на работу с вашими предложениями. Использование обратных вызовов кажется более чистым, однако мои пакеты специфичны и различаются по длине, поэтому я не думаю, что смогу использовать метод .fit() . Если только нет какого-то способа гарантировать, что .fit() получает правильную группу пакетов.