我需要将使用游程编码(RLE)压缩的3D数据读入python中的3D numpy数组。在Matlab中,使用嵌套循环大约需要一秒钟。但是在python中需要48秒!
这是我的代码:
# Preallocate 3D voxel grid
vox_size = [200,150,200];
voxelGrid3D = np.zeros([200,150,200], dtype=np.uint32);
# Get values from RLE encoded 3D scene:
# Example:
# 0, (3), 4, (2) --> corresponds to --> 00044
# --> value == [0, 4]
# --> value_reps == [3, 2]
value = labelsRleCompressed[::2];
value_reps = labelsRleCompressed[1::2];
vox_idx = 0;
vox_idx_all = 0;
num_elements = value_reps.size; # Number of elements to convert
for m in np.arange(0,num_elements):
numReps = value_reps[m];
currentValue = value[m];
for l in np.arange(0,numReps):
# Compute respective grid indices
i = (np.floor(vox_idx_all / (vox_size[0] * vox_size[1]) ) % vox_size[2]);
j = (np.floor(vox_idx_all / (vox_size[0]) ) % vox_size[1]);
k = (np.floor(vox_idx_all ) % vox_size[0]);
# Fill grid with label value
voxelGrid3D[i,j,k] = currentValue;
vox_idx_all = vox_idx_all + 1;
即使我删除内部循环并将其替换为预先计算的网格索引+重塑函数,整个过程仍需要10秒钟!
voxelGrid = np.zeros(num_voxels,dtype=np.uint32)
repIter = 0;
numReps = 0;
vox_idx = 0;
for counter in np.arange(0,num_voxels):
if repIter == numReps:
numReps = value_iter[vox_idx];
currentValue = value[vox_idx];
vox_idx = vox_idx + 1;
voxelGrid[counter] = currentValue
repIter = 1;
else:
voxelGrid[counter] = currentValue
repIter = repIter + 1;
voxelGrid3D = np.reshape(voxelGrid,(vox_size[0],vox_size[1],vox_size[2]))
这对我的申请来说太慢了。有谁知道如何让这更快?
答案 0 :(得分:0)
加速循环
首先不要使用np.arange来创建迭代器(这将创建一个迭代的数组)。请改用范围(Python3)或xrange(Python2)。这应该会使性能提高几个百分点,但这不是你真正的瓶颈。
Matlab有一个及时编译器来执行相对良好的循环,CPython默认没有这个。但是有一个及时的编译器叫做numba http://numba.pydata.org/。在文档中,您将找到可以编译为本机机器代码的受支持函数。当使用numba时,我还建议用循环而不是矢量化代码来编写东西,因为这对编译器来说更容易处理。
我稍微修改了你的代码。
def decompress_RLE(labelsRleCompressed,vox_size):
res=np.empty(vox_size[0]*vox_size[1]*vox_size[2],np.uint32)
ii=0
for i in range(0,labelsRleCompressed.size,2):
value=labelsRleCompressed[i]
rep=labelsRleCompressed[i+1]
for j in range(0,rep):
res[ii]=value
ii=ii+1
res=res.reshape((vox_size[0],vox_size[1],vox_size[2]))
return res
创建基准化数据
vox_size=np.array((300,300,300),dtype=int32)
#create some data
labelsRleCompressed=np.random.randint(0, 500,
size=vox_size[0]*vox_size[1]*vox_size[2]/2, dtype=np.uint32)
labelsRleCompressed[1::2]=4
简单地使用生成的数据调用函数会导致 7.5 秒的运行时间,这是一个相当差的性能。
现在让我们使用numba。
import numba
nb_decompress_RLE = numba.jit("uint32[:,:,:](uint32[:],int32[:])",nopython=True)(decompress_RLE) #stick to the datatypes written in the decorator
使用测试数据调用已编译的nb_decompress_RLE会导致 0.0617 秒的运行时间。一个很好的加速119倍!使用np.copy简单复制数组只需要快3倍。