将Theano.scan与多维数组一起使用

时间:2013-05-29 09:36:14

标签: theano

为了加快我的代码,我正在将多维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

1 个答案:

答案 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通过在扫描范围外移动计算来优化一些案例,但并不总是如此。