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

Fra*_*ter 1 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
Run Code Online (Sandbox Code Playgroud)

对于以下输入

a1 = ([1, 2, 4], [5, 6, 7])
a2 = ([1, 2, 4], [5, 6, 7])
Run Code Online (Sandbox Code Playgroud)

输出将是:[ 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
Run Code Online (Sandbox Code Playgroud)

nou*_*uiz 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
Run Code Online (Sandbox Code Playgroud)

对于theano代码,这里相当于这个更快的python版本(不需要扫描)

m1 = theano.tensor.matrix()
m2 = theano.tensor.matrix()
f = theano.function([m1, m2], (m1 * m2).sum(axis=0))
Run Code Online (Sandbox Code Playgroud)

要记住这一点的想法是你需要"矢量化"你的代码."向量化"用于NumPy上下文,它意味着使用numpy.ndarray并使用一次处理完整张量的函数.这总是比使用循环(python循环或theano扫描)更快.此外,Theano通过在扫描之外移动计算来优化一些案例,但并不总是如此.