我正在开发一个构建几何(而不是算术)神经网络的项目。为了构造传递函数,我想使用几何求和而不是算术求和。
为了使事情更清楚,我将在代码中描述:
def arithmetic_matrix_multiplication(matrix1, matrix2):
new_matrix = np.zeros(len(matrix1),len(matrix2[0]))
for i in range(len(matrix1)):
for j in range(len(matrix2[0])):
for k in range(len(matrix2)):
new_matrix[i][j] += matrix1[i][k]*matrix2[k][j]
return new_matrix
def geometric_matrix_multiplication(matrix1, matrix2):
new_matrix = np.ones(len(matrix1),len(matrix2[0]))
for i in range(len(matrix1)):
for j in range(len(matrix2[0])):
for k in range(len(matrix2)):
new_matrix[i][j] *= matrix1[i][k]*matrix2[k][j]
return new_matrix
正如您所看到的,这是一个非常小的变化。唯一的问题是,以同样的方式,我永远不会真正编写和使用上面的算术代码(我会使用numpy.dot
),我真的不想实际使用上面的几何代码。有没有办法利用numpy的矩阵乘法来实现几何结果?我无法想到一个,而且我没有找到任何明显的解决方案,这远远不是最优的。
答案 0 :(得分:6)
你们都在不必要地使事情变得复杂......因为你有一个单一的操作,即可交换的乘法,你可以随意交换你执行它们的顺序,即你不需要乘以{{{{ 1}}使用matrix1
项,并且一旦计算完所有项,就将它们相乘。相反,您可以先将matrix2
的所有相关项目相加,然后将matrix1
的所有相关项目相乘,然后将两个结果值相乘。所以你可以编写你的函数非常简单:
matrix2
它还有一个额外的好处,如果你将形状def fast_geometric_matrix_multiplication(matrix1, matrix2):
return np.prod(matrix1, axis=1)[:, None] * np.prod(matrix2, axis=0)
和(m, k)
的矩阵相乘,你可能需要进行(k, n)
次乘法,而这种方法只需{ {1}},它几乎要比你现在为几乎任何数组形状所做的要小得多。
当然:
m*n*2*k
答案 1 :(得分:4)
In [373]: %paste
x = np.arange(5*5, dtype=np.long).reshape(5,5)
y = np.arange(5*5, 5*5*2, dtype=np.long).reshape(5,5)
xy = geometric_matrix_multiplication(x,y)
xy2 = np.prod(x[:, None, :]*y.T[..., None], axis=2)
np.allclose(xy, xy2)
## -- End pasted text --
Out[373]: True
这种解决方案在它可以处理的形状方面不是很稳定。如果它的工作原理那么好,但如果你的数据大小是可变的,那么你应该长期使用它。
答案 2 :(得分:2)
你的问题是numba非常完美的候选人。您唯一需要添加的是@autojit
。当然,您还可以优化嵌套调用的迭代长度。 numba将range
和xrange
视为简单的for循环(没有创建大型数组的开销)。最后它看起来像这样:
from numba import autojit
@autojit
def geometric_matrix_multiplication(matrix1, matrix2):
new_matrix = np.ones((len(matrix1),len(matrix2[0])))
jlen = len(matrix2[0])
klen = len(matrix2)
for i in range(len(matrix1)):
for j in range(jlen):
for k in range(klen):
new_matrix[i,j] *= matrix1[i,k]*matrix2[k,j]
return new_matrix
通过对此函数使用jit编译,之后应该获得类似C的速度。要了解速度增益:
a = np.random.rand(100*100).reshape((100,100))
b = np.random.rand(100*100).reshape((100,100))
%timeit geometric_matrix_multiplication_org(a,b)
1 loops, best of 3: 4.1 s per loop
%timeit geometric_matrix_multiplication(a,b)
100 loops, best of 3: 5 ms per loop