在 Keras 中构建自定义损失
Building a custom loss in Keras
我一直在尝试在 Keras 中构建自己的自定义损失,但遇到了一些错误。
我的需求如下:我想在一个稳定的时间序列上构建一个分类器:它必须决定曲线是上升还是下降趋势,这意味着如果导数对于 2 或 3 个时间步长为负,则它必须保持 "ascendant" 分类,而不是在短时间内切换到后代。输入数据是上下文数据,可以帮助神经网络检测当前时间序列方向的变化是否可能持续。
为此,我设想构建一个自定义损失函数,该函数会为高于或低于参考值的每次分类更改增加惩罚。
我首先想在预测张量和参考张量上使用 np.where,但我知道浏览论坛这是不可能的,因为损失函数使用占位符张量。我必须留在 keras 后端的功能 space 内。
出于这个原因,我使用了我在这个论坛上找到的一些代码来构建以下损失函数:
import keras.backend as kb
def roll_reg(x):
length = kb.int_shape(x)[0]
x_tile = kb.tile(x, [2, 1])
x_roll = x_tile[length - 1:-1]
return kb.sum(kb.abs(x - x_roll))
def custom_loss(y_actual,y_predicted):
posact=kb.flatten(y_actual)
pospred=kb.flatten(y_predicted)
na=roll_reg(posact)
np=roll_reg(pospred)
loss_cust=kb.mean(((y_actual-y_predicted)**2)**0.5/(kb.max(y_actual)-kb.min(y_actual)))+abs(na-np)/kb.int_shape(posact)*10
return loss_cust
但我仍然收到此错误:
ValueError: Shape must be rank 1 but is rank 2 for
'loss_9/dense_25_loss/Tile' (op: 'Tile') with input shapes: [?], [2].
我将其解释为我的操作无法在占位符张量上进行……而我正在尝试为此类张量使用专用函数。
有谁知道我可以做些什么来改进此代码以获得我的损失函数 运行?
关于这个问题的一些更新。我在互联网上找到了这个页面:https://medium.com/@j.ali.hab/on-custom-loss-functions-in-keras-3af88cf59e48 使用 tf.math 库解决了同样的问题。
所以我将代码更新为:
def custom_loss(y_actual,y_predicted):
na=kb.tf.math.cumsum(y_actual,axis=0)
np=kb.tf.math.cumsum(y_predicted,axis=0)
penalty=kb.abs(kb.sum(np-na))/118319#/kb.int_shape(y_actual)[0]
loss_nico=penalty
return loss_nico
现在代码正在编译,但我在每个纪元的最后得到一个 Nan 作为损失函数。当然,神经网络不会因此学习任何东西。
有人知道我做错了什么吗?
好的,我终于明白了!
问题出在 kb.abs() 中:不需要它,因为 kb.sum() returns 是一个标量。
所以最终有效的代码是:
def custom_loss(y_actual,y_predicted):
na=kb.tf.math.cumsum(y_actual,axis=0)
np=kb.tf.math.cumsum(y_predicted,axis=0)
penalty=abs(kb.sum(na-np))
loss_nico=kb.sum(((y_actual-y_predicted)))/1000+penalty/1000
return loss_nico
这编译并使 RN 能够实际学习一些东西。它仍然不完美,因为 "non penalty" 部分应该改进,但它仍然有效。
我一直在尝试在 Keras 中构建自己的自定义损失,但遇到了一些错误。
我的需求如下:我想在一个稳定的时间序列上构建一个分类器:它必须决定曲线是上升还是下降趋势,这意味着如果导数对于 2 或 3 个时间步长为负,则它必须保持 "ascendant" 分类,而不是在短时间内切换到后代。输入数据是上下文数据,可以帮助神经网络检测当前时间序列方向的变化是否可能持续。
为此,我设想构建一个自定义损失函数,该函数会为高于或低于参考值的每次分类更改增加惩罚。
我首先想在预测张量和参考张量上使用 np.where,但我知道浏览论坛这是不可能的,因为损失函数使用占位符张量。我必须留在 keras 后端的功能 space 内。
出于这个原因,我使用了我在这个论坛上找到的一些代码来构建以下损失函数:
import keras.backend as kb
def roll_reg(x):
length = kb.int_shape(x)[0]
x_tile = kb.tile(x, [2, 1])
x_roll = x_tile[length - 1:-1]
return kb.sum(kb.abs(x - x_roll))
def custom_loss(y_actual,y_predicted):
posact=kb.flatten(y_actual)
pospred=kb.flatten(y_predicted)
na=roll_reg(posact)
np=roll_reg(pospred)
loss_cust=kb.mean(((y_actual-y_predicted)**2)**0.5/(kb.max(y_actual)-kb.min(y_actual)))+abs(na-np)/kb.int_shape(posact)*10
return loss_cust
但我仍然收到此错误:
ValueError: Shape must be rank 1 but is rank 2 for 'loss_9/dense_25_loss/Tile' (op: 'Tile') with input shapes: [?], [2].
我将其解释为我的操作无法在占位符张量上进行……而我正在尝试为此类张量使用专用函数。
有谁知道我可以做些什么来改进此代码以获得我的损失函数 运行?
关于这个问题的一些更新。我在互联网上找到了这个页面:https://medium.com/@j.ali.hab/on-custom-loss-functions-in-keras-3af88cf59e48 使用 tf.math 库解决了同样的问题。
所以我将代码更新为:
def custom_loss(y_actual,y_predicted):
na=kb.tf.math.cumsum(y_actual,axis=0)
np=kb.tf.math.cumsum(y_predicted,axis=0)
penalty=kb.abs(kb.sum(np-na))/118319#/kb.int_shape(y_actual)[0]
loss_nico=penalty
return loss_nico
现在代码正在编译,但我在每个纪元的最后得到一个 Nan 作为损失函数。当然,神经网络不会因此学习任何东西。
有人知道我做错了什么吗?
好的,我终于明白了!
问题出在 kb.abs() 中:不需要它,因为 kb.sum() returns 是一个标量。
所以最终有效的代码是:
def custom_loss(y_actual,y_predicted):
na=kb.tf.math.cumsum(y_actual,axis=0)
np=kb.tf.math.cumsum(y_predicted,axis=0)
penalty=abs(kb.sum(na-np))
loss_nico=kb.sum(((y_actual-y_predicted)))/1000+penalty/1000
return loss_nico
这编译并使 RN 能够实际学习一些东西。它仍然不完美,因为 "non penalty" 部分应该改进,但它仍然有效。