- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在尝试扩展 numpy“tensordot”这样的东西:K_ijklm = A_ki * B_jml
可以这样写得更清晰:K = mytensordot(A,B,[2,0],[1,4,3])
据我了解,numpy 的 tensordot(带有可选参数 0)将能够执行如下操作:K_kijml = A_ki * B_jml
,即保持索引的顺序。因此,我将不得不执行多次 np.swapaxes()
以获得矩阵“K_ijklm”,在复杂的情况下,这可能是一个容易出错的来源(可能很难调试)。
问题是我的实现速度很慢(比 tensordot 慢 10 倍[编辑:实际上比那个慢很多]),即使在使用 numba 时也是如此。我想知道是否有人对可以做些什么来提高我的算法的性能有一些见解。
import numpy as np
import numba as nb
import itertools
import timeit
@nb.jit()
def myproduct(dimN):
N=np.prod(dimN)
L=len(dimN)
Product=np.zeros((N,L),dtype=np.int32)
rn=0
for n in range(1,N):
for l in range(L):
if l==0:
rn=1
v=Product[n-1,L-1-l]+rn
rn = 0
if v == dimN[L-1-l]:
v = 0
rn = 1
Product[n,L-1-l]=v
return Product
@nb.jit()
def mytensordot(A,B,iA,iB):
iA,iB = np.array(iA,dtype=np.int32),np.array(iB,dtype=np.int32)
dimA,dimB = A.shape,B.shape
NdimA,NdimB=len(dimA),len(dimB)
if len(iA) != NdimA: raise ValueError("iA must be same size as dim A")
if len(iB) != NdimB: raise ValueError("iB must be same size as dim B")
NdimN = NdimA + NdimB
dimN=np.zeros(NdimN,dtype=np.int32)
dimN[iA]=dimA
dimN[iB]=dimB
Out=np.zeros(dimN)
indexes = myproduct(dimN)
for nidxs in indexes:
idxA = tuple(nidxs[iA])
idxB = tuple(nidxs[iB])
v=A[(idxA)]*B[(idxB)]
Out[tuple(nidxs)]=v
return Out
A=np.random.random((4,5,3))
B=np.random.random((6,4))
def runmytdot():
return mytensordot(A,B,[0,2,3],[1,4])
def runtensdot():
return np.tensordot(A,B,0).swapaxes(1,3).swapaxes(2,3)
print(np.all(runmytdot()==runtensdot()))
print(timeit.timeit(runmytdot,number=100))
print(timeit.timeit(runtensdot,number=100))
True
1.4962144780438393
0.003484356915578246
最佳答案
你遇到了a known issue . numpy.zeros
requires a tuple创建多维数组时。如果你传递元组以外的东西,它有时会起作用,但这只是因为 numpy
首先将对象转换为元组很聪明。
问题是numba
目前不支持 conversion of arbitrary iterables into tuples .因此,当您尝试在 nopython=True
中编译它时,这一行失败了模式。 (其他几个也失败了,但这是第一次。)
Out=np.zeros(dimN)
理论上你可以调用np.prod(dimN)
,创建一个由零组成的平面数组,并对其进行整形,但随后您遇到了同样的问题:reshape
numpy
的方法|数组需要一个元组!
这对于 numba
来说是一个相当棘手的问题--我以前没有遇到过。我真的怀疑我找到的解决方案是否正确,但它是一个可行的解决方案,允许我们在 nopython=True
中编译一个版本模式。
核心思想是通过直接实现一个跟在strides
之后的索引器来避免使用元组进行索引。数组的:
@nb.jit(nopython=True)
def index_arr(a, ix_arr):
strides = np.array(a.strides) / a.itemsize
ix = int((ix_arr * strides).sum())
return a.ravel()[ix]
@nb.jit(nopython=True)
def index_set_arr(a, ix_arr, val):
strides = np.array(a.strides) / a.itemsize
ix = int((ix_arr * strides).sum())
a.ravel()[ix] = val
这允许我们在不需要元组的情况下获取和设置值。
我们也可以避免使用reshape
通过将输出缓冲区传递给 jitted 函数,并将该函数包装在辅助函数中:
@nb.jit() # We can't use nopython mode here...
def mytensordot(A, B, iA, iB):
iA, iB = np.array(iA, dtype=np.int32), np.array(iB, dtype=np.int32)
dimA, dimB = A.shape, B.shape
NdimA, NdimB = len(dimA), len(dimB)
if len(iA) != NdimA:
raise ValueError("iA must be same size as dim A")
if len(iB) != NdimB:
raise ValueError("iB must be same size as dim B")
NdimN = NdimA + NdimB
dimN = np.zeros(NdimN, dtype=np.int32)
dimN[iA] = dimA
dimN[iB] = dimB
Out = np.zeros(dimN)
return mytensordot_jit(A, B, iA, iB, dimN, Out)
由于助手不包含循环,因此它会增加一些开销,但开销非常小。这是最终的 jitted 函数:
@nb.jit(nopython=True)
def mytensordot_jit(A, B, iA, iB, dimN, Out):
for i in range(np.prod(dimN)):
nidxs = int_to_idx(i, dimN)
a = index_arr(A, nidxs[iA])
b = index_arr(B, nidxs[iB])
index_set_arr(Out, nidxs, a * b)
return Out
不幸的是,这并没有像我们希望的那样产生加速。在较小的阵列上,它比 tensordot
慢大约 5 倍;在更大的阵列上,它仍然慢 50 倍。 (但至少它没有慢 1000 倍!)回想起来这并不奇怪,因为 dot
和 tensordot
都在后台使用 BLAS,如@hpaulj reminds us .
完成这段代码后,我看到了 einsum
解决了你真正的问题——很好!
但是您最初的问题所指向的潜在问题——在 jitted 代码中不可能使用任意长度的元组进行索引——仍然令人沮丧。所以希望这对其他人有用!
关于python - 在 numba 中实现的 tensordot 算法比 numpy 慢得多,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54633946/
作为脚本的输出,我有 numpy masked array和标准numpy array .如何在运行脚本时轻松检查数组是否为掩码(具有 data 、 mask 属性)? 最佳答案 您可以通过 isin
我的问题 假设我有 a = np.array([ np.array([1,2]), np.array([3,4]), np.array([5,6]), np.array([7,8]), np.arra
numpy 是否有用于矩阵模幂运算的内置实现? (正如 user2357112 所指出的,我实际上是在寻找元素明智的模块化减少) 对常规数字进行模幂运算的一种方法是使用平方求幂 (https://en
我已经在 Numpy 中实现了这个梯度下降: def gradientDescent(X, y, theta, alpha, iterations): m = len(y) for i
我有一个使用 Numpy 在 CentOS7 上运行的项目。 问题是安装此依赖项需要花费大量时间。 因此,我尝试 yum install pip install 之前的 numpy 库它。 所以我跑:
处理我想要旋转的数据。请注意,我仅限于 numpy,无法使用 pandas。原始数据如下所示: data = [ [ 1, a, [, ] ], [ 1, b, [, ] ], [ 2,
numpy.random.seed(7) 在不同的机器学习和数据分析教程中,我看到这个种子集有不同的数字。选择特定的种子编号真的有区别吗?或者任何数字都可以吗?选择种子数的目标是相同实验的可重复性。
我需要读取存储在内存映射文件中的巨大 numpy 数组的部分内容,处理数据并对数组的另一部分重复。整个 numpy 数组占用大约 50 GB,我的机器有 8 GB RAM。 我最初使用 numpy.m
处理我想要旋转的数据。请注意,我仅限于 numpy,无法使用 pandas。原始数据如下所示: data = [ [ 1, a, [, ] ], [ 1, b, [, ] ], [ 2,
似乎 numpy.empty() 可以做的任何事情都可以使用 numpy.ndarray() 轻松完成,例如: >>> np.empty(shape=(2, 2), dtype=np.dtype('d
我在大型 numpy 数组中有许多不同的形式,我想使用 numpy 和 scipy 计算它们之间的边到边欧氏距离。 注意:我进行了搜索,这与堆栈中之前的其他问题不同,因为我想获得数组中标记 block
我有一个大小为 (2x3) 的 numpy 对象数组。我们称之为M1。在M1中有6个numpy数组。M1 给定行中的数组形状相同,但与 M1 任何其他行中的数组形状不同。 也就是说, M1 = [ [
如何使用爱因斯坦表示法编写以下点积? import numpy as np LHS = np.ones((5,20,2)) RHS = np.ones((20,2)) np.sum([ np.
假设我有 np.array of a = [0, 1, 1, 0, 0, 1] 和 b = [1, 1, 0, 0, 0, 1] 我想要一个新矩阵 c 使得如果 a[i] = 0 和 b[i] = 0
我有一个形状为 (32,5) 的 numpy 数组 batch。批处理的每个元素都包含一个 numpy 数组 batch_elem = [s,_,_,_,_] 其中 s = [img,val1,val
尝试为基于文本的多标签分类问题训练单层神经网络。 model= Sequential() model.add(Dense(20, input_dim=400, kernel_initializer='
首先是一个简单的例子 import numpy as np a = np.ones((2,2)) b = 2*np.ones((2,2)) c = 3*np.ones((2,2)) d = 4*np.
我正在尝试平均二维 numpy 数组。所以,我使用了 numpy.mean 但结果是空数组。 import numpy as np ws1 = np.array(ws1) ws1_I8 = np.ar
import numpy as np x = np.array([[1,2 ,3], [9,8,7]]) y = np.array([[2,1 ,0], [1,0,2]]) x[y] 预期输出: ar
我有两个数组 A (4000,4000),其中只有对角线填充了数据,而 B (4000,5) 填充了数据。有没有比 numpy.dot(a,b) 函数更快的方法来乘(点)这些数组? 到目前为止,我发现
我是一名优秀的程序员,十分优秀!