<p>你在你的<a href="https://stackoverflow.com/a/47271663/3293881">^{<cd1>}</a>中做了很多优化。我想再增加一些(主要是微调)。我将以答案帖子中的获胜者为基础,这似乎是基于<code>numexpr</code>。</p>
<h3>调整1</h3>
<p>首先,<code>np.sum(X ** 2, axis = -1)</code>可以用<code>np.einsum</code>进行优化。虽然这部分不是最大的开销,但是任何优化都不会有什么坏处。所以,这个总和可以表示为-</p>
<pre><code>X_norm = np.einsum('ij,ij->i',X,X)
</code></pre>
<h3>调整2</h3>
<p>其次,我们可以利用Scipy支持的blas函数,如果允许的话,可以使用单精度的dtype来显著提高其性能。因此,<code>np.dot(X, X.T)</code>可以用<a href="https://docs.scipy.org/doc/scipy-0.19.1/reference/generated/scipy.linalg.blas.sgemm.html" rel="nofollow noreferrer">^{<cd6>}</a>来计算,就像-</p>
<pre><code>sgemm(alpha=1.0, a=X, b=X, trans_b=True)
</code></pre>
<p>在用<code>gamma</code>重新排列负号方面,再做一些调整,我们就可以为<code>sgemm</code>提供更多信息。此外,我们将把<code>gamma</code>推入<code>alpha</code>项。</p>
<h3>调整后的实现</h3>
<p>因此,通过这两个优化,我们将拥有<code>numexpr</code>方法的另外两个<em>变体</em>(如果我可以这么说的话),如下所示-</p>
<pre><code>from scipy.linalg.blas import sgemm
def app1(X, gamma, var):
X_norm = -np.einsum('ij,ij->i',X,X)
return ne.evaluate('v * exp(g * (A + B + 2 * C))', {\
'A' : X_norm[:,None],\
'B' : X_norm[None,:],\
'C' : np.dot(X, X.T),\
'g' : gamma,\
'v' : var\
})
def app2(X, gamma, var):
X_norm = -gamma*np.einsum('ij,ij->i',X,X)
return ne.evaluate('v * exp(A + B + C)', {\
'A' : X_norm[:,None],\
'B' : X_norm[None,:],\
'C' : sgemm(alpha=2.0*gamma, a=X, b=X, trans_b=True),\
'g' : gamma,\
'v' : var\
})
</code></pre>
<h3>运行时测试</h3>
<p>从你的回复帖子中找到一个基于Numexpr的-</p>
<pre><code>def app0(X, gamma, var):
X_norm = np.sum(X ** 2, axis = -1)
return ne.evaluate('v * exp(-g * (A + B - 2 * C))', {
'A' : X_norm[:,None],
'B' : X_norm[None,:],
'C' : np.dot(X, X.T),
'g' : gamma,
'v' : var
})
</code></pre>
<p>计时和验证-</p>
<pre><code>In [165]: # Setup
...: X = np.random.randn(10000, 512)
...: gamma = 0.01
...: var = 5.0
In [166]: %timeit app0(X, gamma, var)
...: %timeit app1(X, gamma, var)
...: %timeit app2(X, gamma, var)
1 loop, best of 3: 1.25 s per loop
1 loop, best of 3: 1.24 s per loop
1 loop, best of 3: 973 ms per loop
In [167]: np.allclose(app0(X, gamma, var), app1(X, gamma, var))
Out[167]: True
In [168]: np.allclose(app0(X, gamma, var), app2(X, gamma, var))
Out[168]: True
</code></pre>