几何矩阵乘法

时间:2014-01-20 20:41:38

标签: python numpy matrix-multiplication

我正在开发一个构建几何(而不是算术)神经网络的项目。为了构造传递函数,我想使用几何求和而不是算术求和。

为了使事情更清楚,我将在代码中描述:

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的矩阵乘法来实现几何结果?我无法想到一个,而且我没有找到任何明显的解决方案,这远远不是最优的。

3 个答案:

答案 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将rangexrange视为简单的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