我在对象检测中为视网膜网实现了一个keras层AnchorTargets
,它输入了anchors
和annotations
(即真相边界框)。代码的思想是由github中的keras-retinanet激发的。
但是,在labels_shape = (input_shape[0]*input_shape[1], num_classes)
中出现错误,因为input_shape [0]表示批处理大小,这在网络构建期间不可用。关于这个问题有什么建议吗?谢谢。
def batch_anchor_targets_bbox(
anchors,
annotations,
num_classes,
mask_shape=None,
negative_overlap=0.4,
positive_overlap=0.5,
**kwargs):
""" Generate anchor targets for bbox detection.
Args
anchors: np.array of annotations of shape (B, N, 4) for (x1, y1, x2, y2).
annotations: np.array of shape (B, M, 5) for (x1, y1, x2, y2, label).
num_classes: Number of classes to predict.
mask_shape: If the image is padded with zeros, mask_shape can be used to mark the relevant part of the image.
negative_overlap: IoU overlap for negative anchors (all anchors with overlap < negative_overlap are negative).
positive_overlap: IoU overlap or positive anchors (all anchors with overlap > positive_overlap are positive).
Returns
labels: np.array of shape (B, N, num_classes) where a row consists of 0 for negative and 1 for positive for a certain class.
annotations: np.array of shape (B, N, 5) for (x1, y1, x2, y2, label) containing the annotations corresponding to each anchor or 0 if there is no corresponding anchor.
anchor_states: np.array of shape (B, N) containing the state of an anchor (-1 for ignore, 0 for bg, 1 for fg).
"""
# anchor states: 1 is positive, 0 is negative, -1 is dont care
anchors = keras.backend.cast(anchors, 'float32')
annotations = keras.backend.cast(annotations, 'float32')
input_shape = keras.backend.int_shape(anchors)
annos_shape = keras.backend.int_shape(annotations)
overlaps = batch_compute_overlap(anchors, annotations)
argmax_overlaps_inds = keras.backend.argmax(overlaps, axis=2)
max_overlaps = keras.backend.max(overlaps, axis=2)
# assign "dont care" labels
flag_pos = keras.backend.greater_equal(max_overlaps, positive_overlap)
anchor_states = keras.backend.cast(flag_pos, 'float32')
flag = backend.logical_and(keras.backend.greater_equal(max_overlaps, negative_overlap), \
keras.backend.less(max_overlaps, positive_overlap))
anchor_states = anchor_states - keras.backend.cast(flag, 'float32')
# reshape the values and indices of the max output
argmax_overlaps_inds = keras.backend.reshape(argmax_overlaps_inds,(-1,))
flag_pos = keras.backend.reshape(flag_pos,(-1,))
# compute box regression targets
annotations_o = keras.backend.reshape(annotations, (-1, annos_shape[2]))
annotations_o = backend.gather(annotations_o,argmax_overlaps_inds)
annotations = keras.backend.reshape(annotations_o, (-1, input_shape[1],annos_shape[2]))
# compute target class labels
ind_x = backend.where(flag_pos)
ind_y = keras.backend.cast(backend.gather(annotations_o[:,4], ind_x), 'int64')
indices = keras.backend.concatenate([ind_x,ind_y], axis=1)
labels_shape = (input_shape[0]*input_shape[1], num_classes)
values = keras.backend.ones(keras.backend.shape(ind_x)[0])
delta = backend.SparseTensor(indices, values, labels_shape)
labels = backend.sparse_tensor_to_dense(delta)
labels = keras.backend.reshape(labels, (-1, input_shape[1], num_classes))
return indices, annotations, anchor_states
class AnchorTargets(keras.layers.Layer):
def __init__(self, num_classes, negative_overlap=0.4, positive_overlap=0.5, *args, **kwargs):
self.num_classes = num_classes
self.negative_overlap = negative_overlap
self.positive_overlap = positive_overlap
super(AnchorTargets, self).__init__(*args, **kwargs)
def call(self, inputs, **kwargs):
# anchors (batch_size x N x 4): pre-defined anchors
# annotations (batch_size x #gt x 4): gt_bboxes.
anchors, annotations = inputs
# calculate regression and labels
labels, annotations, anchor_states = batch_anchor_targets_bbox(anchors, annotations,
self.num_classes, self.negative_overlap, self.positive_overlap)
anchor_states = keras.backend.expand_dims(anchor_states,axis=2)
labels = keras.backend.concatenate([labels, anchor_states], axis=2)
regressions = keras.backend.concatenate([annotations, anchor_states], axis=2)
return [regressions, labels]
def compute_output_shape(self, input_shape):
return [(input_shape[0][0],input_shape[0][1],input_shape[0][2]+1),\
(input_shape[0][0],input_shape[0][1],self.num_classes+2)]
def get_config(self):
config = super(AnchorTargets, self).get_config()
config.update({
'num_classes': self.num_classes,
'negative_overlap': self.negative_overlap,
'positive_overlap': self.positive_overlap
})
return config
答案 0 :(得分:0)
没关系。我已经知道了。基本思想是避免在call
的{{1}}函数中使用input_shape [0](即批处理大小)。如果有人对此感兴趣,我的实现如下。
keras.layers.Layer