为了加快我的代码,我正在将多维sumproduct函数从Python转换为Theano。我的Theano代码达到了相同的结果,但是一次只计算一个维度的结果,因此我必须使用Python for循环来获得最终结果。我认为这会使代码变慢,因为Theano无法在多个函数调用之间优化内存使用和传输(对于gpu)。或者这是一个错误的假设?
那么如何更改Theano代码,以便在一个函数调用中计算sumprod?
原始的Python函数:
def sumprod(a1, a2):
"""Sum the element-wise products of the `a1` and `a2`."""
result = numpy.zeros_like(a1[0])
for i, j in zip(a1, a2):
result += i*j
return result
对于以下输入
a1 = ([1, 2, 4], [5, 6, 7])
a2 = ([1, 2, 4], [5, 6, 7])
输出为:[ 26. 40. 65.]
即1 * 1 + 5 * 5,2 * 2 + 6 * 6和4 * 4 + 7 * 7
Theano版本的代码:
import theano
import theano.tensor as T
import numpy
a1 = ([1, 2, 4], [5, 6, 7])
a2 = ([1, 2, 4], [5, 6, 7])
# wanted result: [ 26. 40. 65.]
# that is 1*1 + 5*5, 2*2 + 6*6 and 4*4 + 7*7
Tk = T.iscalar('Tk')
Ta1_shared = theano.shared(numpy.array(a1).T)
Ta2_shared = theano.shared(numpy.array(a2).T)
outputs_info = T.as_tensor_variable(numpy.asarray(0, 'float64'))
Tsumprod_result, updates = theano.scan(fn=lambda Ta1_shared, Ta2_shared, prior_value:
prior_value + Ta1_shared * Ta2_shared,
outputs_info=outputs_info,
sequences=[Ta1_shared[Tk], Ta2_shared[Tk]])
Tsumprod_result = Tsumprod_result[-1]
Tsumprod = theano.function([Tk], outputs=Tsumprod_result)
result = numpy.zeros_like(a1[0])
for i in range(len(a1[0])):
result[i] = Tsumprod(i)
print result
答案 0 :(得分:7)
首先,有更多的人会在theano邮件列表上回答你的问题然后在stackoverflow上。但我在这里:))
首先,您的功能不适合GPU。即使一切都经过了很好的优化,将输入传输到gpu只是为了添加和求和结果将花费更多的时间来运行python版本。
你的python代码很慢,这里的版本应该更快:
def sumprod(a1, a2):
"""Sum the element-wise products of the `a1` and `a2`."""
a1 = numpy.asarray(a1)
a2 = numpy.asarray(a2)
result (a1 * a2).sum(axis=0)
return result
对于theano代码,这里相当于这个更快的python版本(不需要扫描)
m1 = theano.tensor.matrix()
m2 = theano.tensor.matrix()
f = theano.function([m1, m2], (m1 * m2).sum(axis=0))
要记住这一点的想法是你需要“矢量化”你的代码。 “向量化”用于NumPy上下文,它意味着使用numpy.ndarray并使用一次处理完整张量的函数。这总是比使用循环(python循环或theano扫描)更快。此外,Theano通过在扫描范围外移动计算来优化一些案例,但并不总是如此。