具有 numpy 和性能的大型 MATVEC 广播
Large MATVEC broadcasting with numpy and performance
我正在尝试实现 float64 数据的这种一次性数据转换:
data_new[i,j,k,l,m,:,c] = matvec( data_orig[i,j,k,l,m,:,c], interp_matrix[:,:] )
哪里
"Shape data_orig: (24,30,12,12,12,1024,2) [20.4 GB]"
"Shape data_new: (24,30,12,12,12,7776,2) [154.8GB]"
"Shape interp_matrix: (1024,7776)"
我的第一个方法已经 运行 了大约一天,仍然在 c=0 项上。
data_new = np.zeros((24,30,12,12,12,7776,2))
for c in range(num_components):
print("starting c=%d"%(c))
data_new[...,c] = numpy.dot( data_orig[...,c], interp_matrix )
撇开内存问题...(主要是。)我现在可以转移到一个有足够 RAM 的盒子。我需要为未来做一些更强大的事情。
如何在最高 "c" 维度上广播操作?
有了这种能力,我想我可以尝试循环遍历主要维度,并希望启用线程。 numpy.show_config()
告诉我这个 Anaconda 发行版是用 mkl_intel_lp64 和 mkl_intel_thread 构建的。我肯定在第一种方法中只使用一个核心。 Google 搜索让我认为我需要设置 OMP_NUM_THREADS 以便将来尝试启用线程。
这里有一个更简洁的例子:
>> np.dot( np.zeros((3,4,32,2))[...,:,0], np.zeros((32,128)) )
#works. :)
>> np.dot( np.zeros((3,4,32,2)), np.zeros((32,128)) )
ValueError: shapes (3,4,32,2) and (32,128) not aligned: 2 (dim 3) != 32 (dim 0)
在爱因斯坦求和符号中,您要的乘积是:
data_new[i,j,k,l,m,a,c] = data_orig[i,j,k,l,m,b,c] * interp_matrix[b,a]
或者在 numpy 中:
data_new = np.einsum('ijklmbc,ba->ijklmac',data_orig, interp_matrix)
一步一步减少这个,每个都相当于最后一个:
data_new = np.einsum('...bc,ba->...ac', data_orig, interp_matrix)
data_new = np.einsum('...bc,ab->...ac', data_orig, interp_matrix.T)
data_new = np.einsum('ab,...bc->...ac', interp_matrix.T, data_orig)
data_new = np.einsum('...ab,...bc->...ac', interp_matrix.T, data_orig)
# ^ This is the summation that matmul performs!
data_new = np.matmul(interp_matrix.T, data_orig)
data_new = interp_matrix.T @ data_orig
我正在尝试实现 float64 数据的这种一次性数据转换:
data_new[i,j,k,l,m,:,c] = matvec( data_orig[i,j,k,l,m,:,c], interp_matrix[:,:] )
哪里
"Shape data_orig: (24,30,12,12,12,1024,2) [20.4 GB]"
"Shape data_new: (24,30,12,12,12,7776,2) [154.8GB]"
"Shape interp_matrix: (1024,7776)"
我的第一个方法已经 运行 了大约一天,仍然在 c=0 项上。
data_new = np.zeros((24,30,12,12,12,7776,2))
for c in range(num_components):
print("starting c=%d"%(c))
data_new[...,c] = numpy.dot( data_orig[...,c], interp_matrix )
撇开内存问题...(主要是。)我现在可以转移到一个有足够 RAM 的盒子。我需要为未来做一些更强大的事情。
如何在最高 "c" 维度上广播操作?
有了这种能力,我想我可以尝试循环遍历主要维度,并希望启用线程。 numpy.show_config()
告诉我这个 Anaconda 发行版是用 mkl_intel_lp64 和 mkl_intel_thread 构建的。我肯定在第一种方法中只使用一个核心。 Google 搜索让我认为我需要设置 OMP_NUM_THREADS 以便将来尝试启用线程。
这里有一个更简洁的例子:
>> np.dot( np.zeros((3,4,32,2))[...,:,0], np.zeros((32,128)) )
#works. :)
>> np.dot( np.zeros((3,4,32,2)), np.zeros((32,128)) )
ValueError: shapes (3,4,32,2) and (32,128) not aligned: 2 (dim 3) != 32 (dim 0)
在爱因斯坦求和符号中,您要的乘积是:
data_new[i,j,k,l,m,a,c] = data_orig[i,j,k,l,m,b,c] * interp_matrix[b,a]
或者在 numpy 中:
data_new = np.einsum('ijklmbc,ba->ijklmac',data_orig, interp_matrix)
一步一步减少这个,每个都相当于最后一个:
data_new = np.einsum('...bc,ba->...ac', data_orig, interp_matrix)
data_new = np.einsum('...bc,ab->...ac', data_orig, interp_matrix.T)
data_new = np.einsum('ab,...bc->...ac', interp_matrix.T, data_orig)
data_new = np.einsum('...ab,...bc->...ac', interp_matrix.T, data_orig)
# ^ This is the summation that matmul performs!
data_new = np.matmul(interp_matrix.T, data_orig)
data_new = interp_matrix.T @ data_orig