numpy - 使用 numpy 计算二进制掩码 IOU 的最快方法

标签 numpy optimization

我正在寻找最快的方法来计算形状完全相同的 numpy 中两个二进制掩码(1 和 0 的二维数组)的并集(杰卡德索引)的交集。我的计算代码是:

import numpy as np

def binaryMaskIOU(mask1, mask2):
    mask1_area = np.count_nonzero(mask1 == 1)
    mask2_area = np.count_nonzero(mask2 == 1)
    intersection = np.count_nonzero(np.logical_and(mask1==1,  mask2==1))
    iou = intersection/(mask1_area+mask2_area-intersection)
    return iou

所以我有两个只有 1 和 0 的数组(二进制图像掩码),并且:

  • 每个掩码的面积是数组中1的数量
  • 两个掩码的交集是两个掩码都等于 1 的空间位置
  • IOU(交并集)定义为交集除以并集

任何优化提示/见解都值得赞赏,因为在我的代码中,我需要使用大量掩码多次运行此操作,并且我想确保它尽可能快。

最佳答案

我最初发布了一个答案,意识到我把它弄得太复杂了,当我去编辑它时发现时间比原来的函数更糟糕。已删除。

问题中的代码的性能与其他代码接近。
logic_and 中不需要两个 maskN == 1

数据类型可以产生显着的影响。如果是 np.bool,bm1 会快得多,但这取决于对数据执行的其他操作。

如果可以更改数据类型,可能会节省大量时间,否则我看不到太多内容,也许其他人可以。

import numpy as np

def make_arrays( size = ( 5,5 ), dtype = np.int ):
    return ( np.random.randint( 2, size = size, dtype = dtype ),
             np.random.randint( 2, size = size, dtype = dtype ) )

def bm0(mask1, mask2):
    mask1_area = np.count_nonzero(mask1 == 1)       # I assume this is faster as mask1 == 1 is a bool array
    mask2_area = np.count_nonzero(mask2 == 1)
    intersection = np.count_nonzero( np.logical_and( mask1, mask2) )
    iou = intersection/(mask1_area+mask2_area-intersection)
    return iou

def bm1(mask1, mask2):
    mask1_area = np.count_nonzero( mask1 )
    mask2_area = np.count_nonzero( mask2 )
    intersection = np.count_nonzero( np.logical_and( mask1, mask2 ) )
    iou = intersection/(mask1_area+mask2_area-intersection)
    return iou

def binaryMaskIOU(mask1, mask2):   # From the question.
    mask1_area = np.count_nonzero(mask1 == 1)
    mask2_area = np.count_nonzero(mask2 == 1)
    intersection = np.count_nonzero(np.logical_and( mask1==1,  mask2==1 ))
    iou = intersection/(mask1_area+mask2_area-intersection)
    return iou


n = 50
a, b = make_arrays( ( n, n ) )

bm0( a, b )
# 0.3416313559322034

bm1(a,b)
# 0.3416313559322034

binaryMaskIOU(a,b)
# 0.3416313559322034

%timeit bm0( a, b )
#  7.73 µs ± 22.6 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

%timeit bm1( a, b )
# 12.2 µs ± 20.3 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

%timeit binaryMaskIOU( a, b )
# 10.3 µs ± 36.2 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

n = 500
a, b = make_arrays( ( n, n ) )

%timeit bm0( a, b )
#  342 µs ± 1.29 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

%timeit bm1( a, b )
# 1.01 ms ± 514 ns per loop (mean ± std. dev. of 7 runs, 1000 loops each)

%timeit binaryMaskIOU( a, b )
#  419 µs ± 1.11 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

#################  make a and b np.bool arrays  #################
n = 500
a, b = make_arrays( ( n, n), dtype = np.bool )

%timeit bm0( a, b )
# 439 µs ± 406 ns per loop (mean ± std. dev. of 7 runs, 1000 loops each)

%timeit bm1( a, b )
#  63.2 µs ± 174 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

%timeit binaryMaskIOU( a, b )
# 814 µs ± 496 ns per loop (mean ± std. dev. of 7 runs, 1000 loops each)

关于numpy - 使用 numpy 计算二进制掩码 IOU 的最快方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66595055/

相关文章:

Python Pandas 时间戳减法与 Numpy

python - numpy 将 2D Integer Record 转换为 2D floating point Record

mysql - 搜索多个字段mysql的最快方法

c++ - const 条件的分支预测

excel - VBA 代码基准测试

python - Numpy 从重复函数生成数组

Python:for循环内的两个列表迭代for index

arrays - 为什么 numpy 乘法不会将 (5,5) 和 (5,23) 数组相乘

performance - L2 和 L3 缓存中加载了多少数据?

java - JMH 基准测试 - 比较替代实现的运行时间的简洁方法