在 CNN 的 keras 自定义损失函数中处理数据
Manipulating data in keras custom loss function for CNN
我正尝试在 Keras 中为我正在处理的 CNN 编写自定义损失函数。 Y_true 和 Y_pred 都是灰度图像的张量,所以我希望形状为 [a, x, y, 1]
,其中 x 和 y 是图像的尺寸,a 是批量大小。
计划是:
- 根据平均像素强度
对Y_true的每个图像进行阈值处理
- 使用此掩码的非零元素从 Y_true 和 Y_pred
中获取像素值数组
- 测量这些数组的余弦相似度(使用内置的 Keras 损失函数)和return batch 的平均结果作为损失
我的主要问题是如何有效地实施这个过程?
cosine_similarity
函数是否适用于一维数组?
我知道我应该避免 for 循环以保持效率,但这是我能想到的实现此功能的唯一方法。有没有更有效的方法使用Keras后端或numpy来实现这个功能?
编辑
使用该函数编译模型时的基本实现和意外错误:
def masked_cosine_similarity(y_true, y_pred):
loss = 0
for i in range(y_true.shape[0]):
true_y = y_true[i,:,:,0]
pred_y = y_pred[i,:,:,0]
mask = true_y > np.mean(true_y)
elements = np.nonzero(mask)
true_vals = np.array([true_y[x,y] for x, y in zip(elements[0], elements[1])])
pred_vals = np.array([pred_y[x,y] for x, y in zip(elements[0], elements[1])])
loss += cosine_similarity(true_vals, pred_vals)
return loss / y_true.shape[0]
错误信息:
64 loss = 0
---> 65 for i in range(y_true.shape[0]):
66 true_y = y_true[i,:,:,0]
67 pred_y = y_pred[i,:,:,0]
TypeError: 'NoneType' object cannot be interpreted as an integer
Keras/TF中张量的形状通常是[None, height, width, channels]
。
这是由于支持任意批量大小,您不想构建仅适用于特定批量大小的模型。因此,您的代码崩溃于:
for i in range(y_true.shape[0]):
因为 y_true.shape[0] == None
.
为什么要遍历批处理?你不需要这样做。
例如,给定一些元素大小的损失函数(MSE/cosine 损失等)你可以这样做:
def my_loss(y_true, y_pred):
mask = tf.keras.backend.cast(y_true >= tf.math.reduce_mean(y_true, axis=[1,2], keepdims=True), 'float32')
masked_loss = K.sum(mask * elementwize_loss(y_true, y_pred), axis=-1)
num_valid_pixels = K.maximum(1.0, K.cast(K.sum(mask), 'float32'))
return masked_loss / num_valid_pixels
我正尝试在 Keras 中为我正在处理的 CNN 编写自定义损失函数。 Y_true 和 Y_pred 都是灰度图像的张量,所以我希望形状为 [a, x, y, 1]
,其中 x 和 y 是图像的尺寸,a 是批量大小。
计划是:
- 根据平均像素强度 对Y_true的每个图像进行阈值处理
- 使用此掩码的非零元素从 Y_true 和 Y_pred 中获取像素值数组
- 测量这些数组的余弦相似度(使用内置的 Keras 损失函数)和return batch 的平均结果作为损失
我的主要问题是如何有效地实施这个过程?
cosine_similarity
函数是否适用于一维数组?
我知道我应该避免 for 循环以保持效率,但这是我能想到的实现此功能的唯一方法。有没有更有效的方法使用Keras后端或numpy来实现这个功能?
编辑
使用该函数编译模型时的基本实现和意外错误:
def masked_cosine_similarity(y_true, y_pred):
loss = 0
for i in range(y_true.shape[0]):
true_y = y_true[i,:,:,0]
pred_y = y_pred[i,:,:,0]
mask = true_y > np.mean(true_y)
elements = np.nonzero(mask)
true_vals = np.array([true_y[x,y] for x, y in zip(elements[0], elements[1])])
pred_vals = np.array([pred_y[x,y] for x, y in zip(elements[0], elements[1])])
loss += cosine_similarity(true_vals, pred_vals)
return loss / y_true.shape[0]
错误信息:
64 loss = 0
---> 65 for i in range(y_true.shape[0]):
66 true_y = y_true[i,:,:,0]
67 pred_y = y_pred[i,:,:,0]
TypeError: 'NoneType' object cannot be interpreted as an integer
Keras/TF中张量的形状通常是[None, height, width, channels]
。
这是由于支持任意批量大小,您不想构建仅适用于特定批量大小的模型。因此,您的代码崩溃于:
for i in range(y_true.shape[0]):
因为 y_true.shape[0] == None
.
为什么要遍历批处理?你不需要这样做。 例如,给定一些元素大小的损失函数(MSE/cosine 损失等)你可以这样做:
def my_loss(y_true, y_pred):
mask = tf.keras.backend.cast(y_true >= tf.math.reduce_mean(y_true, axis=[1,2], keepdims=True), 'float32')
masked_loss = K.sum(mask * elementwize_loss(y_true, y_pred), axis=-1)
num_valid_pixels = K.maximum(1.0, K.cast(K.sum(mask), 'float32'))
return masked_loss / num_valid_pixels