将权重映射输入 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 中做同样的事情;我给出的权重图与上面结构相同的图像。
我已经实现了 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 中做同样的事情;我给出的权重图与上面结构相同的图像。