Я попытался создать пользовательскую функцию потерь, используя numba
jit-совместимую функцию, как описано здесь для алгоритма регрессии. Вроде работает как метри c, но у меня странная ошибка при использовании в качестве потери. У меня есть игрушечная функция, которая здесь воспроизводит проблему:
@njit
def test_del(y_true, y_pred):
cols = y_true.shape[1]
out = 0
for i in range(y_true.shape[1]):
true_dam = np.abs(y_true[:, i]).max() #toy
pred_dam = np.abs(y_pred[:, i]).max() #toy
out += np.mean(np.abs(np.log(pred_dam / true_dam))**2)
return out/cols
(да, я знаю, что эту игрушечную задачу можно оптимизировать, чтобы сделать ее более векторизованной, но она соответствует структуре моих реальных функций, чего не может быть, поэтому я оставляю это)
Тогда у меня есть функция потерь / метри c:
def del_loss(y_true, y_pred):
return tf.numpy_function(test_del, [y_true, y_pred], tf.float64) +\
K.cast(tf.keras.losses.mean_squared_error(y_true, y_pred), tf.float64)
Теперь, если я скомпилирую модель с del_loss
в качестве метри c (пока я использую его как float64
, что странно, но неважно), он работает нормально. Но если я использую это как потерю, я получаю эту странную строку ошибок:
Traceback (most recent call last):
#removed my chain of objects resulting in a `model.compile(loss = del_loss)` call
File "C:\ProgramData\Anaconda3\envs\MLEnv\lib\site-packages\keras\backend\tensorflow_backend.py", line 75, in symbolic_fn_wrapper
return func(*args, **kwargs)
File "C:\ProgramData\Anaconda3\envs\MLEnv\lib\site-packages\keras\engine\training.py", line 229, in compile
self.total_loss = self._prepare_total_loss(masks)
File "C:\ProgramData\Anaconda3\envs\MLEnv\lib\site-packages\keras\engine\training.py", line 692, in _prepare_total_loss
y_true, y_pred, sample_weight=sample_weight)
File "C:\ProgramData\Anaconda3\envs\MLEnv\lib\site-packages\keras\losses.py", line 73, in __call__
losses, sample_weight, reduction=self.reduction)
File "C:\ProgramData\Anaconda3\envs\MLEnv\lib\site-packages\keras\utils\losses_utils.py", line 166, in compute_weighted_loss
losses, None, sample_weight)
File "C:\ProgramData\Anaconda3\envs\MLEnv\lib\site-packages\keras\utils\losses_utils.py", line 76, in squeeze_or_expand_dimensions
elif weights_rank - y_pred_rank == 1:
TypeError: unsupported operand type(s) for -: 'int' and 'NoneType'
Теперь, если я попытаюсь отследить этот последний шаг, я получаю squeeze_or_expand_dimensions
и понимаю, что нахожусь в if
блок, который должен срабатывать, только если у меня есть sample_weight
- у меня нет. В любом случае код перед ним:
y_pred_rank = K.ndim(y_pred)
weights_rank = K.ndim(sample_weight)
if weights_rank != 0:
if y_pred_rank == 0 and weights_rank == 1:
y_pred = K.expand_dims(y_pred, -1)
elif weights_rank - y_pred_rank == 1:
sample_weight = K.squeeze(sample_weight, -1)
elif y_pred_rank - weights_rank == 1:
sample_weight = K.expand_dims(sample_weight, -1)
Не должно быть никакого способа для y_pred_rank
или weights_rank
закончиться None
(и даже если weights
будет установлено на 1
ранее (как кажется в compute_weighted_loss
), weights_rank
должно закончиться 0), но, по-видимому, это так. И как это связано с моей новой функцией потерь, я не понимаю