【问题标题】:Feeding weight maps into a CNN (UNET network) in keras将权重图输入 keras 中的 CNN(UNET 网络)
【发布时间】:2021-09-08 06:30:30
【问题描述】:

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

【问题讨论】:

    标签: tensorflow keras deep-learning conv-neural-network unity3d-unet


    【解决方案1】:

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

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

    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:您可能需要检查这些:

    【讨论】:

    • 我定义的加权二元交叉熵只是给出一个具有两个值的数组;一个用于 0 类,另一个用于 1 类。我将它直接传递给您提到的损失函数。这不成问题。我的问题是如何使用我提到的那些权重图。他们应该制作像素级权重,以便边界侧的权重高于其他区域。地图与地面实况 y 的长度和高度相同。我的问题来了,我不知道如何进行像素加权。我需要改变我的加权交叉熵吗?如果有怎么办?或者我还应该做什么?
    【解决方案2】:

    我意识到如何使用这些地图。首先,我定义了一个输入(具有与地面实况标签相同的形状)作为我们在输入输入图像时定义输入的方式。类似的东西

    weights = Input(shape=(shape_of_groundtruth_labels))
    

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

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

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

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

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

    【讨论】:

      猜你喜欢
      • 2022-08-04
      • 1970-01-01
      • 1970-01-01
      • 2020-11-03
      • 2020-08-28
      • 2018-12-15
      • 1970-01-01
      • 2017-06-08
      • 1970-01-01
      相关资源
      最近更新 更多