python - Google Colaboratory 上的 Tensorflow 2.x 自定义损失函数
问题描述
问题
我正在尝试为我的 Tensorflow 2 模型编写自定义损失函数。我编写了以下函数来计算当我手动传入输入和输出张量时我正在寻找的损失。
def on_off_balance_loss(y_true: EagerTensor, y_pred: EagerTensor) -> float:
y_true_array: ndarray = np.asarray(y_true).flatten()
y_predict_array: ndarray = np.asarray(y_pred).flatten()
on_delta: float = 0.999
on_loss: float = 0
off_loss: float = 0
on_count: int = 0
off_count: int = 0
for i in range(len(y_true_array)):
loss: float = cell_loss(y_true_array[i], y_predict_array[i])
if y_true_array[i] > on_delta:
on_count += 1
on_loss = on_loss * ((on_count - 1) / on_count) + (loss / on_count)
else:
off_count += 1
off_loss = off_loss * ((off_count - 1) / off_count) + (loss / off_count)
on_factor: int = 4
return (on_factor * on_loss + off_loss) / (on_factor + 1)
对于上下文,y_true
由 1 和 0 作为浮点数的 2D 矩阵组成,其中 0 更为常见。因此,我的模型通过正确获取大部分 0 来获得良好的损失值,即使 1 的位置是更重要的指标。这种自定义损失更多地强调了 1 的位置。
我改为model.compile(loss="binary_crossentropy")
尝试model.compile(loss=on_off_balance_loss)
使用新的损失函数。这似乎不起作用,因为损失函数应该接收整批数据。所以,我尝试了这样的事情model.compile(loss=on_off_balance_batch_loss)
:
def on_off_balance_batch_loss(y_true, y_pred) -> float:
y_trues: list = tf.unstack(y_true)
y_preds: list = tf.unstack(y_pred)
loss: float = 0
for i in range(0, len(y_trues)):
loss = loss * (i / (i + 1)) + (on_off_balance_loss(y_trues[i], y_preds[i]) / (i + 1))
return loss
这行不通。的形状y_true
是(None, None, None)
, 的形状y_pred
是(None, X, Y)
,其中X
和Y
是 1 和 0 的二维数组的维度。
我在谷歌合作实验室工作。但是,在本地,np.asarray()
似乎以在 Colaboratory 上引发错误的方式工作。所以,我不确定错误是出在我的损失函数中还是在 Colaboratory 中的某些设置上。我确保我在本地和 Colaboratory 上都使用 Tensorflow 2.3.0。
编辑:
我尝试添加run_eagerly=True
和model.compile()
使用.numpy()
而不是np.asarray()
in on_off_balance_loss()
。这将输入的类型on_off_balance_batch_loss
从更改Tensor
为EagerTensor
。这会导致错误ValueError: No gradients provided for any variable: ['lstm_3/lstm_cell_3/kernel:0', 'lstm_3/lstm_cell_3/recurrent_kernel:0', 'lstm_3/lstm_cell_3/bias:0', 'dense_2/kernel:0', 'dense_2/bias:0', 'lstm_4/lstm_cell_4/kernel:0', 'lstm_4/lstm_cell_4/recurrent_kernel:0', 'lstm_4/lstm_cell_4/bias:0', 'dense_3/kernel:0', 'dense_3/bias:0', 'lstm_5/lstm_cell_5/kernel:0', 'lstm_5/lstm_cell_5/recurrent_kernel:0', 'lstm_5/lstm_cell_5/bias:0'].
。如果我使用也会发生同样的错误
def on_off_balance_batch_loss(y_true: EagerTensor, y_pred: EagerTensor) -> float:
y_trues = tf.TensorArray(tf.float32, 1, dynamic_size=True, infer_shape=False).unstack(y_true)
y_preds = tf.TensorArray(tf.float32, 1, dynamic_size=True, infer_shape=False).unstack(y_pred)
loss: float = 0.0
i: int = 0
for tensor in range(y_trues.size()):
elem_loss: float = on_off_balance_loss(y_trues.read(i), y_preds.read(i))
loss = loss * (i / (i + 1)) + (elem_loss / (i + 1))
i += 1
return loss
并省略run_eagerly=True
。甚至在出现错误之前,似乎整个程序的运行速度都比我使用默认损失函数时要慢。
解决方案
好吧,事实证明解决方案比我上面尝试的要简单得多。下面是实现此类功能的样式。我将它与我的原始函数的输出进行了比较on_off_balance_loss
,它匹配。
def on_off_equal_loss(y_true: Tensor, y_pred: Tensor) -> Tensor:
on_delta: float = 0.99
on_mask: Tensor = tf.greater_equal(y_true, on_delta)
off_mask: Tensor = tf.less(y_true, on_delta)
on_loss: Tensor = tf.divide(tf.reduce_sum(tf.abs(tf.subtract(
y_true[on_mask], y_pred[on_mask]
))), tf.cast(tf.math.count_nonzero(on_mask), tf.float32))
off_loss: Tensor = tf.divide(tf.reduce_sum(tf.abs(tf.subtract(
y_true[off_mask], y_pred[off_mask]
))), tf.cast(tf.math.count_nonzero(off_mask), tf.float32))
on_factor: float = 4.0
return tf.divide(tf.add(tf.multiply(on_factor, on_loss), off_loss), on_factor + 1.0)
推荐阅读
- url-rewriting - Weblogic 12.2 + url rewriting = response blocked
- google-drive-api - How to create service account for google drive api for NOT G Suite account?
- javascript - the loop doesnt run on the array's objects
- javascript - Javascript 对象引用了最后一个对象而不是自身
- reactjs - 以常规方法表示法反应 this.setState
- php - 在我的 php 代码中验证和使用 Google 的 BigQuery
- php - 使用 php 以编程方式进行 bigquery 表分区
- numpy - Tensorflow:如何在没有np.where的情况下根据条件随机选择元素?
- java - Java Mockito 与 RestTemplate.exchange 使用泛型
- spring - 我从 Maven 收到一条错误消息,说“有测试失败”,但我没有写任何测试失败