我有一批'图像',通常是128个,最初被读入一个尺寸为128x360x640x3的numpy数组。我需要将每个图像从NHWC转换到NCHW,因此操作ndarray.transpose(2,0,1)
并将像素标准化为[0,1]范围,因此我需要将数组除以255.此批处理操作将是可能会定期重复一百次左右。最简单的实现如下:
for i in range(128):
batchImageDataNew[i,:,:] = batchImageData[i,:,:].transpose(2,0,1)/255.
batchImageDataNew的类型为np.float32,而batchImageData的类型为np.uint8。我试图尽可能地加快这个过程。我以为ndarray.transpose
只重新排列了步幅而没有实际接触到内存,但我看到每张图像只有大约1毫秒的转置(总共120毫秒)。另一方面,同时进行转置和分割会使总时间达到约350ms。尽可能加快速度的最佳方法是什么? Cython和多线程(线程?)处理的组合会有帮助吗?我正在Ubuntu上工作,我也可以访问OpenMP。
def preprocess(i):
batchImageDataNew[i,:,:] = batchImageData[i,:,:].transpose(2,0,1)/255.
pool = multiprocessing.Pool(8)
pool.map(preprocess, range(128))
答案 0 :(得分:1)
虚假数据
a = np.array([[[1,1]],[[2,2]],[[3,3]]])
b = a + 10
c = b + 10
d = c + 10
e = np.stack((a,b,c,d))
如果可以并且对整个数组进行操作,通常最好避免for循环
f = np.transpose(e, (0,3,1,2))
g = f / 255
>>> e.shape
(4, 3, 1, 2)
>>> f.shape
(4, 2, 3, 1)
或np.moveaxis
代替transpose
f = np.moveaxis(e, 3, 1)
f = np.moveaxis(e, (1,2,3), (2,3,1))
通过预先创建数组以接受分割结果,可以实现轻微约25%的改进(在我的机器上):
a = np.array(np.random.rand(128,360,640,3)*255,dtype=np.uint8)
b = np.zeros((128,3,360,640), dtype=np.float32)
np.divide(np.moveaxis(a, (1,2,3), (2,3,1)), 255, out=b)
答案 1 :(得分:1)
您的问题是高度内存和缓存依赖。最佳解决方案取决于您的处理器和RAM速度。这是使用Numba的解决方案,但你可以使用cython做一个非常相似的方法。
示例强>
import numba as nb
import numpy as np
import time
def tran_scal(batchImageData):
s=batchImageData.shape
batchImageDataNew=np.empty((s[0],s[3],s[1],s[2]),dtype=np.float32)
for i in range(batchImageData.shape[0]):
batchImageDataNew[i,:,:] = batchImageData[i,:,:].transpose(2,0,1)/255.
return batchImageDataNew
@nb.njit()
def tran_scal_nb(batchImageData):
s=batchImageData.shape
batchImageDataNew=np.empty((s[0],s[3],s[1],s[2]),dtype=np.float32)
for i in range(batchImageData.shape[0]):
for j in range(batchImageData.shape[1]):
for k in range(batchImageData.shape[2]):
for l in range(batchImageData.shape[3]):
batchImageDataNew[i,l,j,k] = batchImageData[i,j,k,l]*(1/255.)
return batchImageDataNew
@nb.njit(parallel=True)
def tran_scal_nb_p(batchImageData):
s=batchImageData.shape
batchImageDataNew=np.empty((s[0],s[3],s[1],s[2]),dtype=np.float32)
for i in nb.prange(batchImageData.shape[0]):
for j in range(batchImageData.shape[1]):
for k in range(batchImageData.shape[2]):
for l in range(batchImageData.shape[3]):
batchImageDataNew[i,l,j,k] = batchImageData[i,j,k,l]*(1/255.)
return batchImageDataNew
<强>计时强>
Core i7-4xxx
#Test data
data=np.array(np.random.rand(128,360,640,3)*255,dtype=np.uint8)
Your solution: 550ms
@wwii(transpose): 379ms
tran_scal_nb: 190ms
tran_scal_nb_p: 100ms
在第一次调用时,编译开销大约为0.5秒,但未包含在时序中。