首页 > 解决方案 > tensorflow 获得最大 IOU 的框对,但丢弃全为零的框

问题描述

这个问题是从这个问题构建的:(tensorflow记住计算得到最大框后的索引)。我发现丢弃全为零的盒子特别困难,所以我发布了一个新的。

完整说明:


假设我有两个盒子数组,每个盒子都有形状(?, b1, 4)(?, b2, 4)分别(?视为未知批量大小):

box1: [[[1,2,3,4], [2,3,4,5], [3,4,5,6], [0,0,0,0], [0,0,0,0]...]...]
box2: [[[4,3,2,1], [3,2,5,4], [4,3,5,6]...]...]

(以上数字任意设定)

请注意,末尾可能有box1 也可能没有( )。[0,0,0,0]

我想要:

  1. 在每一个batch中,对于每一个non-fake box A in box1(即不包含全0的boxes),在box2box B中找到与A的IOU(intersection over union)最大的box B (当然是在同一个batch中) ),然后将元组(A, B)附加到列表list_max

  2. 附加到list_nonmax中所有box2没有最大 IOU 的框与任何框box1(当然,按批次分隔)

你可以假设:

  1. b1b2都是 python 变量,而不是 tensorflow 张量。

  2. 计算单个盒子之间或一批盒子之间的 IOU 的方法已经存在并且可以从字面上使用:

    iou_single_box(box1, box2): box1box2都是有形状的(4,)

    iou_multiple_boxes(bbox1, bbox2)bbox1bbox2的形状分别为(b1, 4)(b2, 4)

    iou_batch_boxes(bbbox1, bbbox2)bbbox1bbbox2的形状(?, b1, 4)(?, b2, 4)分别(?视为未知的批量大小)。


大家可以看一下我之前发的问题(tensorflow记住计算得到最大框后的索引)。我只添加一个约束:

  1. 我不希望任何盒子box1与任何盒子相匹配box2。获取list_maxlist_nonmax时

注意,假盒子的数量没有设置。

****:我知道这个问题很复杂。我做所有这些是因为 Tensorflow 无法处理动态长度数组(你必须在运行时有一个确定性b1box1。所以我[0, 0, 0, 0]在末尾填充box1以使长度固定。

标签: tensorflow

解决方案


我相信这很容易用tf.boolean_mask()这样的代码(经过测试)来实现:

from __future__ import print_function
import tensorflow as tf

box1 = tf.reshape( tf.constant( range( 16 ), dtype = tf.float32 ), ( 2, 2, 4 ) )
box1 = tf.concat( [ box1, tf.zeros( ( 2, 2, 4 ) ) ], axis = 1 )
box2 = tf.reshape( tf.constant( range( 2, 26 ), dtype = tf.float32 ), ( 2, 3, 4 ) )
batch_size = box1.get_shape().as_list()[ 0 ]

def dummy_iou_batch_boxes( box1, box2 ):
    b1s, b2s = box1.get_shape().as_list(), box2.get_shape().as_list()
    return tf.constant( [ [ [9.0,8,7], [1,2,3], [ 0, 10, 0 ], [ 0, 0, 0 ],
                            [0  ,1,2], [0,5,0], [ 0, 0, 0 ], [ 0, 0, 0 ] ] ] )

iou = dummy_iou_batch_boxes( box1, box2 )
val, idx = tf.nn.top_k( iou, k = 1 )
idx = tf.reshape( idx, ( batch_size, box1.get_shape().as_list()[ 1 ] ) )
one_hot_idx = tf.one_hot( idx, depth = box2.get_shape().as_list()[ 1 ] )

# for listmax
full_idx = tf.where( tf.equal( 1.0, one_hot_idx ) )
box1_idx = full_idx[ :, 0 : 2 ]
box2_idx = full_idx[ :, 0 : 3 : 2 ]
box12 = tf.gather_nd( box1, box1_idx )
box22 = tf.gather_nd( box2, box2_idx )
list_max_raw = tf.stack( [ box12, box22 ], axis = 1 )
# filter out for a = [ 0, 0, 0, 0 ]
nonzero_mask = tf.reduce_any( tf.not_equal( 0.0, list_max_raw ), axis = 2 )[ :, 0 ]
list_max = tf.boolean_mask( list_max_raw, nonzero_mask )

# for list nonmax
nonzero_mask = tf.cast( tf.reduce_any( tf.not_equal( 0.0, box1 ), axis = 2 ), tf.float32 )[ ..., None ]
filtered_one_hot = one_hot_idx * nonzero_mask
active_box2 = tf.sign( tf.reduce_sum( filtered_one_hot, axis = 1 ) )
nonactive_box2 = 1.0 - active_box2
nonactive_box2_idx = tf.where( tf.equal( 1.0, nonactive_box2 ) )
list_nonmax = tf.gather_nd( box2, nonactive_box2_idx )

with tf.Session() as sess:
    res = sess.run( [ box1, box2, list_max ] )
    print( "Input boxes:  " )
    for v in res[ : 2 ]:
        print( v )
        print( " ", "=" * 40 )
    print( "List max:  " )
    for v in res[ 2 : ]:
        print( v )
        print( " ", "=" * 40 )
    res = sess.run( [ list_nonmax ] )
    print( "List nonmax:  " )
    for v in res:
        print( v )
        print( " ", "=" * 40 )

将输出

输入框:
[[[0.1.2.3.]
[4.5.6.7.]
[0.0.0.0 .][0.0.0.0.
]]

[[ 8. 9. 10. 11.]
[12. 13. 14. 15.]
[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]]]
===================== ===================
[[[ 2. 3. 4. 5.]
[ 6. 7. 8. 9.]
[10. 11. 12. 13.]]

[[14。15. 16. 17.]
[18. 19. 20. 21.]
[22. 23. 24. 25.]]]
========================================
列表最大值:
[[[ 0. 1. 2. 3.]
[ 2. 3. 4. 5.]]

[[ 4. 5. 6. 7.]
[10. 11. 12. 13.]]

[[ 8. 9. 10. 11.]
[22. 23. 24. 25.]]

[[12。13. 14. 15.]
[18. 19. 20. 21.]]]
========================================
列表非最大值:
[[ 6. 7. 8. 9.]
[14. 15. 16. 17.]]
=========================================


推荐阅读