繁体   English   中英

使用NumPy将ubyte [0,255]数组转换为float数组[-0.5,+0.5]的最快方法

[英]Fastest way to convert ubyte [0, 255] array to float array [-0.5, +0.5] with NumPy

问题在标题中,非常简单。

我有一个文件f ,正在读取一个ubyte数组:

arr = numpy.fromfile(f, '>u1', size * rows * cols).reshape((size, rows, cols))
max_value = 0xFF  # max value of ubyte

目前,我正在通过3次传递对数据进行规范化,如下所示:

arr = images.astype(float)
arr -= max_value / 2.0
arr /= max_value

由于阵列有些大,因此需要花费很短的时间。
如果我可以在1或2次传递数据中做到这一点,那就太好了,因为我认为这样会更快。

我可以通过某种方式执行“复合”矢量运算来减少通过次数吗?
或者,我还有其他方法可以加快速度吗?

我做了:

ar = ar - 255/2.
ar *= 1./255

似乎更快:)

不,我没有定时,它在我的系统上大约快两倍。 看来ar = ar - 255/2. 快速进行减法和类型转换。 另外,似乎没有对标量进行除法优化:一次除法然后对数组进行一堆乘法会更快。 尽管额外的浮点运算可能会增加舍入误差。

如评论中所述, numexpr可能是实现这一目标的真正快速而简单的方法。 在我的系统上,这是另一个快两倍的因素,但这主要是由于numexpr使用了多个内核,而不是因为它只对数组执行了一次传递。 码:

import numexpr
ar = numexpr.evaluate('(ar - 255.0/2.0) / 255.0')

该查询表可能比重复计算要快一点:

table = numpy.linspace(-0.5, 0.5, 256)
images = numpy.memmap(f, '>u1', 'r', shape=(size, rows, cols))
arr = table[images]

在我的系统上,与您的系统相比,它节省了10%到15%的时间。

我自己找到了一个更好的解决方案(速度提高了约25%):

arr = numpy.memmap(f, '>u1', 'r', shape=(size, rows, cols))
arr = arr / float(max_value)
arr -= 0.5

我很好奇是否可以改善。

我使用cython.parallel.prange和下面的代码,对大型数组的速度提高了50%(对一维数组,但很容易扩展); 我想速度的提高取决于CPU内核的数量:

pilot.pyx文件:

cimport cython
from cython.parallel import prange
import numpy as np
cimport numpy as np
from numpy cimport float64_t, uint8_t, ndarray

@cython.boundscheck(False)
@cython.wraparound(False)
def norm(np.ndarray[uint8_t, ndim=1] img):
    cdef:
        Py_ssize_t i, n = len(img)
        np.ndarray[float64_t, ndim=1] arr = np.empty(n, dtype='float64')
        float64_t * left = <float64_t *> arr.data
        uint8_t * right = <uint8_t *> img.data

    for i in prange(n, nogil=True):
        left[i] = (right[i] - 127.5) / 255.0

    return arr

setup.py文件,用上述代码构建C扩展模块:

from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext

ext_module = Extension(
    'pilot',
    ['pilot.pyx'],
    extra_compile_args=['-fopenmp'],
    extra_link_args=['-fopenmp'],
)

setup(
    name = 'pilot',
    cmdclass = {'build_ext': build_ext},
    ext_modules = [ext_module],
)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM