Python 用numpy快速计算批次和时间维度上的空间变换
对于机器学习任务,我必须计算时间序列中每个帧的3D坐标(沿z轴旋转)的空间变换。此外,我还有一批时间序列。我希望尽可能减少for循环的使用 假设我有一个形状的旋转矩阵(batch_size,3,3)和一个形状张量(batch_size,seq_length,n_坐标,3)。我目前正在做的是一个随时间和批次维度的双for循环,并计算每个3D坐标的点积 代码如下:Python 用numpy快速计算批次和时间维度上的空间变换,python,numpy,Python,Numpy,对于机器学习任务,我必须计算时间序列中每个帧的3D坐标(沿z轴旋转)的空间变换。此外,我还有一批时间序列。我希望尽可能减少for循环的使用 假设我有一个形状的旋转矩阵(batch_size,3,3)和一个形状张量(batch_size,seq_length,n_坐标,3)。我目前正在做的是一个随时间和批次维度的双for循环,并计算每个3D坐标的点积 代码如下: #计算转换 对于范围内的t(序号长度): 对于范围内的b(批次尺寸): X[b,t,:,:]=np.dot(旋转z_矩阵[b],X[b,
#计算转换
对于范围内的t(序号长度):
对于范围内的b(批次尺寸):
X[b,t,:,:]=np.dot(旋转z_矩阵[b],X[b,t,:,:].t)
我已经研究了tensordot和einsum函数,但最后,我不想在一个维度上求点积和,我想在两个维度(批次和时间)上叠加点积
是否有有效的等待来编写等效代码
提前谢谢 您可以使用-
另外,在
np.einsum
中将optimize
标志设置为True
以使用BLAS。可以使用广播来完成:
X@rotation_z_matrix.transpose(0,2,1)[:, None, ...]
这(在模拟数据集上)给出了与@Divakar相同的答案
batch_size = 10
seq_length = 8
n_coordinates = 12
X = np.random.randint(0,10,(batch_size, seq_length, n_coordinates, 3))
rotation_z_matrix = np.random.randint(0,10,(batch_size,3,3))
(X@rotation_z_matrix.transpose(0,2,1)[:, None, ...] == np.einsum('ijk,ilmk->ilmj',rotation_z_matrix,X)).all()
# True
但至少在这个例子中,速度要快得多
timeit(lambda: np.einsum('ijk,ilmk->ilmj',rotation_z_matrix,X, optimize=True), number=1000)
# 0.1285447319969535
timeit(lambda: np.einsum('ijk,ilmk->ilmj',rotation_z_matrix,X, optimize=False), number=1000)
# 0.07962286799738649
timeit(lambda: X@rotation_z_matrix.transpose(0,2,1)[:, None, ...], number=1000)
# 0.019039910010178573
请务必注意,设置optimize
标志实际上会降低einsum
的速度。(这种情况在我身上经常发生。)
更新:同一示例,但数据转换为float数据类型
timeit(lambda: np.einsum('ijk,ilmk->ilmj',rotation_z_matrix,X, optimize=True), number=1000)
# 0.12346570500812959
timeit(lambda: np.einsum('ijk,ilmk->ilmj',rotation_z_matrix,X, optimize=False), number=1000)
# 0.07575376800377853
timeit(lambda: X@rotation_z_matrix.transpose(0,2,1)[:, None, ...], number=1000)
# 0.027829282989841886
美好的所以,跳到einsum似乎对性能没有意义,嗯。@Divakar这很难预测,不是吗?顺便问一下,您对
优化有何经验?是的,optimize
一个我认为适用于经历总和缩减的大型轴的方法。但情况似乎并非如此,至少在较新的NumPy版本中是如此。如果我没记错的话,性能数据可以与matmul进行比较。
timeit(lambda: np.einsum('ijk,ilmk->ilmj',rotation_z_matrix,X, optimize=True), number=1000)
# 0.12346570500812959
timeit(lambda: np.einsum('ijk,ilmk->ilmj',rotation_z_matrix,X, optimize=False), number=1000)
# 0.07575376800377853
timeit(lambda: X@rotation_z_matrix.transpose(0,2,1)[:, None, ...], number=1000)
# 0.027829282989841886