将权重映射输入 keras 中的 CNN(UNET 网络)

Feeding weight maps into a CNN (UNET network) in keras

我已经实现了 here

中描述的 UNET 网络

网络运行良好,但在论文中,他们提到将加权图添加到网络中以实现更好的边界分离。据我了解,权重图是这样计算的

def unet_weight_map(y, wc=None, w0 = 10, sigma = 5):

"""

Parameters
----------
mask: Numpy array
    2D array of shape (image_height, image_width) representing binary mask
    of objects.
wc: dict
    Dictionary of weight classes.
w0: int
    Border weight parameter.
sigma: int
    Border width parameter.

Returns
-------
Numpy array
    Training weights. A 2D array of shape (image_height, image_width).
"""

labels = label(y)
no_labels = labels == 0
label_ids = sorted(np.unique(labels))[1:]

if len(label_ids) > 1:
    distances = np.zeros((y.shape[0], y.shape[1], len(label_ids)))

    for i, label_id in enumerate(label_ids):
        distances[:,:,i] = distance_transform_edt(labels != label_id)

    distances = np.sort(distances, axis=2)
    d1 = distances[:,:,0]
    d2 = distances[:,:,1]
    w = w0 * np.exp(-1/2*((d1 + d2) / sigma)**2) * no_labels
else:
    w = np.zeros_like(y)
if wc:
    class_weights = np.zeros_like(y)
    for k, v in wc.items():
        class_weights[y == k] = v
    w = w + class_weights
return w

到这里一切都很好。但是,我的问题是如何在网络中使用这些权重图。我有一个加权二元交叉熵损失定义如下

def weighted_binary_crossentropy( y_true, y_pred, weight=[1.,2.]):
y_true = K.clip(y_true, K.epsilon(), 1-K.epsilon())
y_pred = K.clip(y_pred, K.epsilon(), 1-K.epsilon())
logloss = -(y_true * K.log(y_pred) * weight[0] + (1 - y_true) * K.log(1 - y_pred)*weight[1])
return K.mean( logloss, axis=-1)

但是,这里我将权重作为 [a, b] 数组放入 class 权重的损失中,然后在编译时将此损失提供给网络。我的问题是我应该将这些地图输入到这个定制的损失函数中吗?如果是这样,如何?如果没有,我可以在 Keras 中使用什么其他方式?请帮忙。我已经阅读了许多与此问题相关的堆栈溢出问题,但我无法得到答案。如果需要,我可以提供有关我的网络的任何信息。

为了将您自己的参数传递给自定义损失函数,您有两种方法。您应该将损失子类化,或者使用包装函数。

例如,您可以像这样设置包装函数:

def wrapper_loss(weights=[1.,2.]):
  def weighted_binary_crossentropy(y_true, y_pred):
    y_true = K.clip(y_true, K.epsilon(), 1-K.epsilon())
    y_pred = K.clip(y_pred, K.epsilon(), 1-K.epsilon())
    logloss = -(y_true * K.log(y_pred) * weight[0] + (1 - y_true) * K.log(1 - y_pred)*weight[1])
    return K.mean(logloss, axis=-1)
  return weighted_binary_crossentropy

然后,像这样将它传递给 model.compile()

model.compile(loss=wrapper_loss(weights=[1.,2.]), optimizer=...)

P.S:您可能需要检查这些:

我知道了如何使用那些地图。首先,我定义了一个输入(与真实标签具有相同的形状),就像我们在输入图像时定义输入的方式一样。像

weights = Input(shape=(shape_of_groundtruth_labels))

我定义的自定义损失与上面定义的wrapper_loss结构相同;这次使用权重图,而不是 class 权重 [1, 2]。然后,在定义需要输入和输出的模型时。我将输入作为输入图像和输入权重。类似于:

model = Model(inputs=[images, weights], outputs=...)

其中权重是我在输入层中定义的权重。在 model.compile() 中,我将损失作为自定义损失的名称 (wrapper_loss) 和输入权重。像

model.compile(optimizer=..., loss=wrapper_loss(weight = weights), ...)

其中第二个 'weights' 是在输入层中定义的那个。 现在,最后要做的是在 model.fit 中做同样的事情;我给出的权重图与上面结构相同的图像。