【问题标题】:Pixel-wise loss weight for image segmentation in KerasKeras中图像分割的像素损失权重
【发布时间】:2018-10-19 16:39:02
【问题描述】:

我目前正在使用 U-Net (https://arxiv.org/pdf/1505.04597.pdf) 的修改版本来分割显微镜图像中的细胞器。由于我使用的是 Keras,所以我从https://github.com/zhixuhao/unet 获取代码。然而,在这个版本中,没有实现权重图来强制网络学习边界像素。

目前我得到的结果是相当不错的,但是网络无法分离彼此靠近的物体。所以我想尝试利用论文中提到的权重图。我已经能够为每个标签图像生成权重图(基于给定的公式),但我无法找到如何使用这个权重图来训练我的网络,从而解决上述问题。

是否必须以某种方式组合权重图和标签图像,或者是否有 Keras 函数可以让我使用权重图?我是生物学家,最近才开始研究神经网络,所以我的理解仍然有限。任何帮助或建议将不胜感激。

【问题讨论】:

    标签: python keras conv-neural-network unet


    【解决方案1】:

    如果它仍然相关:我最近需要解决这个问题。您可以将下面的代码粘贴到 Jupyter 笔记本中,看看它是如何工作的。

    %matplotlib inline
    import numpy as np
    from skimage.io import imshow
    from skimage.measure import label
    from scipy.ndimage.morphology import distance_transform_edt
    import numpy as np
    
    def generate_random_circles(n = 100, d = 256):
        circles = np.random.randint(0, d, (n, 3))
        x = np.zeros((d, d), dtype=int)
        f = lambda x, y: ((x - x0)**2 + (y - y0)**2) <= (r/d*10)**2
        for x0, y0, r in circles:
            x += np.fromfunction(f, x.shape)
        x = np.clip(x, 0, 1)
    
        return x
    
    def unet_weight_map(y, wc=None, w0 = 10, sigma = 5):
    
        """
        Generate weight maps as specified in the U-Net paper
        for boolean mask.
    
        "U-Net: Convolutional Networks for Biomedical Image Segmentation"
        https://arxiv.org/pdf/1505.04597.pdf
    
        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
    
    y = generate_random_circles()
    
    wc = {
        0: 1, # background
        1: 5  # objects
    }
    
    w = unet_weight_map(y, wc)
    
    imshow(w)
    

    【讨论】:

      【解决方案2】:

      我想你想在 Keras 中使用class_weight。如果您已经计算了类权重,这实际上很容易在您的模型中引入。

      1. 使用您的类标签及其相关权重创建一个字典。例如

        class_weight = {0: 10.9,
                1: 20.8,
                2: 1.0,
                3: 50.5}
        
      2. 或者创建一个长度与您的类数相同的一维 Numpy 数组。例如

        class_weight = [10.9, 20.8, 1.0, 50.5]
        
      3. 在您的model.fitmodel.fit_generator 中训练期间传递此参数

        model.fit(x, y, batch_size=batch_size, epochs=num_epochs, verbose=1, class_weight=class_weight)
        

      您可以查看 Keras 文档以了解更多详细信息 here

      【讨论】:

      • 感谢您的回复。在这种情况下,术语类到底指的是什么?是我图像中的标签数量吗?权重图是一个距离图(与输入图像的形状相同,因此它是一个二维数组),其中单元格之间的边界包含更高的像素强度以增加边界像素的权重。尽管如此,我还是尝试了您上面描述的方法,但它给了我一个最终图像,其中测试准确度下降到不到 4%(之前是 80%)。有什么建议吗?
      • 是的,类意味着您要将图像分割成的不同标签。我会再看一遍论文检查并回复你。
      • 您提到的距离图是用于分隔边界的。每个标签类的像素频率分布(论文中w_c)可以通过我在答案中提到的方法来实现。
      猜你喜欢
      • 2017-07-24
      • 2018-09-23
      • 2020-04-18
      • 2018-10-22
      • 2018-05-12
      • 2020-07-28
      • 2018-07-11
      • 2019-09-24
      • 2021-04-29
      相关资源
      最近更新 更多