【问题标题】:Efficient dot product dense to sparse高效点积密集到稀疏
【发布时间】:2019-06-24 12:55:45
【问题描述】:

我想仅针对特定索引有效地计算两个低秩矩阵 A 和 B 的点积。通常,A 和 B 的形状为 (100, 10000),我只想获得 A.T @ B 条目的 1%。

我已经尝试使用 Numba 库,但它似乎比计算密集点积 np.dot(A.T, B) 慢得多。

【问题讨论】:

    标签: python numpy scipy


    【解决方案1】:

    你可以使用einsum:

    import numpy as np
    
    def direct():
        return (A.T@B)[iy, ix]
    
    def einsum():
        return np.einsum('ij,ij->j',A[:,iy],B[:,ix])
    
    def make(M,N,p):
        global A,B,iy,ix
        A,B = (np.random.randint(0,10,(M,N)) for _ in "AB")
        iy,ix = np.random.randint(0,N,(2,int(N*N*p)))
    
    from time import time
    
    make(100,10000,0.01)
    T=[]
    T.append(time())
    d = direct()
    T.append(time())
    e = einsum()
    T.append(time())
    print("results equal: ",np.allclose(d,e))
    print("direct {:.6f} einsum {:.6f}".format(*np.diff(T)))
    

    示例运行:

    results equal:  True
    direct 18.463711 einsum 1.947425
    

    【讨论】:

    • 你好。感谢您的帮助,但是我正在寻找的输出不一定是数组。特别是,我可能想计算每行偶数个系数。
    • *每行系数个数不均匀
    • @AdrienVacher 是什么让您认为此解决方案未涵盖此内容?它需要所有可能对的约 1% 随机子集,但您可以使用任何您想要的子集。
    • 是的,对不起,我应该尝试一下。完美运行,谢谢!
    【解决方案2】:

    如果您想要点积的结果数组的子集,只需在使用点之前获取子集。即,如果您想要输出的“左上”10x10 矩阵,只需执行

    np.dot(A.T[:10,:], B[:, :10])
    

    如果你想要一些特定的索引,你可以使用更花哨的索引。例如,如果你想要索引 3、5 和 29,你可以这样做:

    indices = np.array([3, 5, 29]).reshape(-1, 1)
    inner_all = np.arange(A.shape[0]).reshape(-1, 1)
    result = np.dot(A.T[indices, inner_all.T], B[inner_all, indices.T])
    

    如果您只需要第一行的第 1、3 和 5 列:

    rows = np.array([1]).reshape(-1, 1)
    columns = rows = np.array([1, 3, 5]).reshape(-1, 1)
    inner_all = np.arange(A.shape[0]).reshape(-1, 1)
    result = np.dot(A.T[rows, inner_all.T], B[inner_all, columns.T])
    

    【讨论】:

    • 您好,感谢您的回答。但是在我的情况下,输出不是一个数组。例如,在第 0 行,我可能想要计算 3 个系数,而在第 1 行,我可能需要 20 个系数。
    • @AdrienVacher 点积的结果是一个数组。如果您只想要该数组的一个子集,例如第一行中的 3 个系数,那么请查看我的更新答案。
    • 我想为 A 的每一行与 B 的列计算不同数量的点积。实际上,我想有效地计算 A.T@B [mask] 其中 mask 是形状的 2d 掩码(A.shape[1], B.shape[1]) 并且有许多零(稀疏掩码)。涉及许多“未使用”的计算,我正在寻找一种有效的方法来绕过它。
    猜你喜欢
    • 1970-01-01
    • 2015-03-26
    • 2017-05-17
    • 2016-08-15
    • 2014-01-31
    • 2019-09-02
    • 1970-01-01
    • 2010-11-06
    • 2013-01-29
    相关资源
    最近更新 更多