Функция потерь Keras с пользовательской весовой функцией

Вопрос или проблема

Моя LSTM нейронная сеть предсказывает номинальные значения в диапазоне от -1 до 1. Я хотел бы установить пользовательскую функцию потерь в Keras, которая назначает весовую функцию в зависимости от знака предсказания.

Если предсказанный знак положительный, функция весов сигмоиды должна масштабировать ошибки предсказания от 1 (для самой негативной ошибки предсказания) до 2 (для самой позитивной ошибки предсказания). Если предсказанный знак отрицательный, я хотел бы использовать обратную весовую функцию.

Вы можете воспроизвести мою ошибку с помощью следующего фрагмента кода:

import numpy as np
from keras.models import Sequential
from keras.layers import Dense, LSTM
from keras import backend as K

# loss function
def lfunc(true,pred):

    diff = pred - true

    def weight(y_hat, error):
        if y_hat>=0: weight = K.sigmoid(error*100)+1
        else: weight = (-K.sigmoid(error*100)) +2    
        return weight

    scale = weight(pred, diff)

    return K.mean(scale*K.square(diff))

# data
trainset = np.random.uniform(low=-1, high=1, size=(100000,13))
no_variables = 3
lookback = 4
train_x, train_y = trainset[:80000][:, :-1], trainset[:80000][:, -1:]
val_x, val_y = trainset[80000:][:, :-1], trainset[80000:][:, -1:]
train_x = train_x.reshape((train_x.shape[0], lookback, no_variables))
val_x = val_x.reshape((val_x.shape[0], lookback, no_variables))

# model set up
model = Sequential()
model.add(LSTM(2, return_sequences=True,
                input_shape=(lookback, no_variables), dropout=0.3))
model.add(LSTM(1, input_shape=(lookback, no_variables), dropout=0.3))
model.add(Dense(1))
model.compile(loss=lfunc, optimizer="SGD")

#train model
result = model.fit(train_x, train_y, epochs=1, batch_size=2**4, 
                   validation_data=(val_x, val_y), verbose=1, shuffle=False)

Ошибка возникает в команде model.fit. Сообщение об ошибке выглядит следующим образом:

Traceback (most recent call last):

  File "C:\Users\chris\OneDrive\Dokumente\GitHub\LSTM\data\untitled0.py", line 38, in <module>

  File "C:\Users\chris\.conda\envs\snowflake\lib\site-packages\keras\engine\training.py", line 1158, in fit
    tmp_logs = self.train_function(iterator)

  File "C:\Users\chris\.conda\envs\snowflake\lib\site-packages\tensorflow\python\eager\def_function.py", line 889, in __call__
    result = self._call(*args, **kwds)

  File "C:\Users\chris\.conda\envs\snowflake\lib\site-packages\tensorflow\python\eager\def_function.py", line 933, in _call
    self._initialize(args, kwds, add_initializers_to=initializers)

  File "C:\Users\chris\.conda\envs\snowflake\lib\site-packages\tensorflow\python\eager\def_function.py", line 763, in _initialize
    self._stateful_fn._get_concrete_function_internal_garbage_collected(  # pylint: disable=protected-access

  File "C:\Users\chris\.conda\envs\snowflake\lib\site-packages\tensorflow\python\eager\function.py", line 3050, in _get_concrete_function_internal_garbage_collected
    graph_function, _ = self._maybe_define_function(args, kwargs)

  File "C:\Users\chris\.conda\envs\snowflake\lib\site-packages\tensorflow\python\eager\function.py", line 3444, in _maybe_define_function
    graph_function = self._create_graph_function(args, kwargs)

  File "C:\Users\chris\.conda\envs\snowflake\lib\site-packages\tensorflow\python\eager\function.py", line 3279, in _create_graph_function
    func_graph_module.func_graph_from_py_func(

  File "C:\Users\chris\.conda\envs\snowflake\lib\site-packages\tensorflow\python\framework\func_graph.py", line 999, in func_graph_from_py_func
    func_outputs = python_func(*func_args, **func_kwargs)

  File "C:\Users\chris\.conda\envs\snowflake\lib\site-packages\tensorflow\python\eager\def_function.py", line 672, in wrapped_fn
    out = weak_wrapped_fn().__wrapped__(*args, **kwds)

  File "C:\Users\chris\.conda\envs\snowflake\lib\site-packages\tensorflow\python\framework\func_graph.py", line 986, in wrapper
    raise e.ag_error_metadata.to_exception(e)

OperatorNotAllowedInGraphError: in user code:

    C:\Users\chris\.conda\envs\snowflake\lib\site-packages\keras\engine\training.py:830 train_function  *
        return step_function(self, iterator)
    C:\Users\chris\.conda\envs\snowflake\lib\site-packages\keras\engine\training.py:813 run_step  *
        outputs = model.train_step(data)
    C:\Users\chris\.conda\envs\snowflake\lib\site-packages\keras\engine\training.py:771 train_step  *
        loss = self.compiled_loss(
    C:\Users\chris\.conda\envs\snowflake\lib\site-packages\keras\engine\compile_utils.py:201 __call__  *
        loss_value = loss_obj(y_t, y_p, sample_weight=sw)
    C:\Users\chris\.conda\envs\snowflake\lib\site-packages\keras\losses.py:142 __call__  *
        losses = call_fn(y_true, y_pred)
    C:\Users\chris\.conda\envs\snowflake\lib\site-packages\keras\losses.py:246 call  *
        return ag_fn(y_true, y_pred, **self._fn_kwargs)
    C:\Users\chris\OneDrive\Dokumente\GitHub\LSTM\data\untitled0.py:16 lfunc  **

    C:\Users\chris\OneDrive\Dokumente\GitHub\LSTM\data\untitled0.py:12 weight

    C:\Users\chris\.conda\envs\snowflake\lib\site-packages\tensorflow\python\framework\ops.py:900 __bool__
        self._disallow_bool_casting()
    C:\Users\chris\.conda\envs\snowflake\lib\site-packages\tensorflow\python\framework\ops.py:503 _disallow_bool_casting
        self._disallow_when_autograph_enabled(
    C:\Users\chris\.conda\envs\snowflake\lib\site-packages\tensorflow\python\framework\ops.py:489 _disallow_when_autograph_enabled
        raise errors.OperatorNotAllowedInGraphError(

    OperatorNotAllowedInGraphError: using a `tf.Tensor` as a Python `bool` is not allowed: AutoGraph did convert this function. This might indicate you are trying to use an unsupported feature.

Есть ли у кого-либо предложения, как реализовать эту проблему с помощью Keras backend?

if y_hat>=0: weight = K.sigmoid(error100)+1

cond = _verify_tf_condition(cond, ‘if statement’)

verify_tf_condition ‘; {}’.format(tag, cond, extra_hint))

ValueError: condition of if statement expected to be tf.bool scalar, got Tensor*

Если наблюдать вышеприведенные логи (ускоренные),

Мы предполагаем, что y_hat является скаляром. Поэтому код будет работать для batch_size=1 и выдаёт ошибку выше для batch_size>=2

Вы должны обработать код if y_hat>=0 для Tensor.

Ответ или решение

Создание пользовательской функции потерь в Keras может быть сложной задачей, особенно когда речь идет об использовании логики на уровне тензоров. Ваша задача — создать функцию потерь, которая применяет весовую функцию в зависимости от знака предсказания. Проблема, с которой вы столкнулись, связана с использованием условных операторов для тензоров, что в TensorFlow приводит к ошибке OperatorNotAllowedInGraphError.

Давайте разберемся с решением этой проблемы, стабилизируя логику внутри пользовательской функции потерь.

Шаги для решения:

  1. Избегайте использования операторов if для тензоров. TensorFlow не поддерживает использование стандартных операторов if с тензорами. Вместо этого следует использовать функции, такие как tf.where(), которые предназначены для работы с логикой на уровне тензоров.

  2. Правильное использование функций Keras Backend. Используйте функции из keras.backend или их аналоги из tensorflow, чтобы работать с операциями на тензорах.

  3. Оптимизация функции потерь. Перепишем вашу функцию потерь так, чтобы она корректно обрабатывала отдельные элементы и использовала подходящие методы для работы с тензорами.

Реализация:

import numpy as np
from keras.models import Sequential
from keras.layers import Dense, LSTM
from keras import backend as K
import tensorflow as tf

# Потеря
def lfunc(true, pred):
    diff = pred - true

    # Использование tf.where для справедливой весовой коррекции
    scale = tf.where(tf.greater_equal(pred, 0),
                     K.sigmoid(diff * 100) + 1,
                     -K.sigmoid(diff * 100) + 2)

    return K.mean(scale * K.square(diff))

# Данные
trainset = np.random.uniform(low=-1, high=1, size=(100000,13))
no_variables = 3
lookback = 4
train_x, train_y = trainset[:80000][:, :-1], trainset[:80000][:, -1:]
val_x, val_y = trainset[80000:][:, :-1], trainset[80000:][:, -1:]
train_x = train_x.reshape((train_x.shape[0], lookback, no_variables))
val_x = val_x.reshape((val_x.shape[0], lookback, no_variables))

# Модель
model = Sequential()
model.add(LSTM(2, return_sequences=True, input_shape=(lookback, no_variables), dropout=0.3))
model.add(LSTM(1, input_shape=(lookback, no_variables), dropout=0.3))
model.add(Dense(1))
model.compile(loss=lfunc, optimizer="SGD")

# Обучение модели
result = model.fit(train_x, train_y, epochs=1, batch_size=2**4, 
                   validation_data=(val_x, val_y), verbose=1, shuffle=False)

Объяснение:

  • tf.where: Эта функция создает условное выражение, которое позволяет нам применять разные весовые коэффициенты в зависимости от того, является ли предсказание положительным или отрицательным.
  • Сигмовидная функция: Вы продолжаете использовать её для масштабирования, но применяете её к каждому элементу, избегая тем самым использования недопустимых условий if.
  • K.mean: Эта функция используется для вычисления среднего значения модифицированных ошибок, чтобы управлять корректировкой через градиенты.

Этот подход гарантирует корректное выполнение задачи с учётом всех ограничений, установленных TensorFlow и Keras, помогая избежать ошибок во время тренировки модели.

Оцените материал
Добавить комментарий

Капча загружается...