Вопрос или проблема
Моя 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 betf.bool
scalar, got Tensor*
Если наблюдать вышеприведенные логи (ускоренные),
Мы предполагаем, что y_hat
является скаляром. Поэтому код будет работать для batch_size=1
и выдаёт ошибку выше для batch_size>=2
Вы должны обработать код if y_hat>=0
для Tensor.
Ответ или решение
Создание пользовательской функции потерь в Keras может быть сложной задачей, особенно когда речь идет об использовании логики на уровне тензоров. Ваша задача — создать функцию потерь, которая применяет весовую функцию в зависимости от знака предсказания. Проблема, с которой вы столкнулись, связана с использованием условных операторов для тензоров, что в TensorFlow приводит к ошибке OperatorNotAllowedInGraphError
.
Давайте разберемся с решением этой проблемы, стабилизируя логику внутри пользовательской функции потерь.
Шаги для решения:
-
Избегайте использования операторов
if
для тензоров. TensorFlow не поддерживает использование стандартных операторовif
с тензорами. Вместо этого следует использовать функции, такие какtf.where()
, которые предназначены для работы с логикой на уровне тензоров. -
Правильное использование функций Keras Backend. Используйте функции из
keras.backend
или их аналоги изtensorflow
, чтобы работать с операциями на тензорах. -
Оптимизация функции потерь. Перепишем вашу функцию потерь так, чтобы она корректно обрабатывала отдельные элементы и использовала подходящие методы для работы с тензорами.
Реализация:
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, помогая избежать ошибок во время тренировки модели.