Как определить потерю в Tensorflow / Keras для набора данных с несколькими метками в форме словаря?

#python #tensorflow #machine-learning #keras #deep-learning

#python #tensorflow #машинное обучение #keras #глубокое обучение

Вопрос:

У меня есть набор данных с несколькими метками, и я хочу определить потерю, которая зависит от меток. Метки в наборе данных хранятся в виде словаря, например:

 y = tf.data.Dataset.from_tensor_slices({'values': [1, 2, 3], 'symbols': [4, 5, 6]})
  

Затем я хочу определить потери для каждой метки, чтобы позже составить некоторую комбинацию потерь. Я пытаюсь определить потерю следующим образом:

 def model_loss(y, y_):
    return tf.losses.SparseCategoricalCrossentropy(from_logits=False, name='values_xent')(y['values'], y_)

  

Однако это дает мне следующую ошибку, когда я подхожу к модели:

 TypeError: Only integers, slices (`:`), ellipsis (`...`), tf.newaxis (`None`) and scalar tf.int32/tf.int64 tensors are valid indices, got 'values'
  

Похоже, я не могу этого сделать y['values'] . Как я могу получить доступ к этим значениям в потере? Заранее спасибо.

Редактировать

Чего я хочу добиться, это что-то вроде этого:

 import tensorflow as tf
import numpy as np

# samples
ds_x = tf.data.Dataset.from_tensor_slices(np.random.randn(5, 5))

# labels
ds_y = tf.data.Dataset.from_tensor_slices({'l1': np.arange(5), 'l2':np.arange(5)})

# samples   labels
ds = tf.data.Dataset.zip((ds_x, ds_y))

# model
input_ = tf.keras.Input(shape=(5,))
x = tf.keras.layers.Dense(30, activation='relu')(input_)
x1 = tf.keras.layers.Dense(5, activation='softmax')(x)
x2 = tf.keras.layers.Dense(5, activation='softmax')(x)
model = tf.keras.Model(inputs=input_, outputs={'l1':x1, 'l2':x2})

# loss
def model_loss(y, y_):
    res = 3 * tf.losses.SparseCategoricalCrossentropy()(y['l1'], y_['l1'])
    res  = tf.losses.SparseCategoricalCrossentropy()(y['l2'], y_['l2'])
    return res

# compile and train
model.compile(optimizer='adam', loss=model_loss)
model.fit(ds.batch(5), epochs=5)
  

Ответ №1:

В ту минуту, когда вы делаете что-то, что не совсем нормально для Keras, я бы предложил использовать пользовательский цикл обучения. Затем вы можете контролировать каждый отдельный шаг процесса обучения.

Я сделал это, и мне не нужно было изменять вашу функцию потерь.

 import tensorflow as tf
import numpy as np

ds_x = tf.data.Dataset.from_tensor_slices(np.random.randn(5, 5).astype(np.float32))

ds_y = tf.data.Dataset.from_tensor_slices({'l1': np.arange(5), 'l2':np.arange(5)})

ds = tf.data.Dataset.zip((ds_x, ds_y)).batch(2)

input_ = tf.keras.Input(shape=[5])
x = tf.keras.layers.Dense(30, activation='relu')(input_)
x1 = tf.keras.layers.Dense(5, activation='softmax')(x)
x2 = tf.keras.layers.Dense(5, activation='softmax')(x)
model = tf.keras.Model(inputs=input_, outputs={'l1':x1, 'l2':x2})

def model_loss(y, y_):
    res = 3 * tf.losses.SparseCategoricalCrossentropy()(y['l1'], y_['l1'])
    res  = tf.losses.SparseCategoricalCrossentropy()(y['l2'], y_['l2'])
    return res

train_loss = tf.keras.metrics.Mean()
optimizer = tf.keras.optimizers.Adam()

for i in range(25):
    for x, y in ds:
        with tf.GradientTape() as tape:
            out = model(x)
            loss = model_loss(y, out)
            
        gradients = tape.gradient(loss, model.trainable_variables)
        optimizer.apply_gradients(zip(gradients, model.trainable_variables))
        train_loss(loss)
    print(f'Epoch {i} Loss: {train_loss.result():=4.4f}')
    train_loss.reset_states()
  
 Epoch 0 Loss: 6.4170
Epoch 1 Loss: 6.3396
Epoch 2 Loss: 6.2737
Epoch 11 Loss: 5.7191
Epoch 12 Loss: 5.6608
Epoch 19 Loss: 5.2646
Epoch 24 Loss: 4.9896
  

Ответ №2:

Вы должны выполнить итерацию y , прежде чем использовать ключ:

 import tensorflow as tf

y_true = tf.data.Dataset.
    from_tensor_slices({'symbols': tf.one_hot([0, 1, 0], depth=2)})
y_pred = tf.data.Dataset.
    from_tensor_slices({'symbols': tf.random.uniform((3, 2), dtype=tf.float32)})

next(iter(y_true))

for a, b, in zip(y_pred, y_true):
    print(tf.losses.categorical_crossentropy(a['symbols'], b['symbols']))
  
 tf.Tensor(6.5402465, shape=(), dtype=float32)
tf.Tensor(8.697783, shape=(), dtype=float32)
tf.Tensor(2.7932203, shape=(), dtype=float32)
  

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

1. Если это не соответствует вашей проблеме, пожалуйста, создайте воспроизводимый пример, который вызывает ошибку

2. Спасибо, я опубликовал воспроизводимый пример. Я не совсем понимаю, как применить это к моей проблеме.