我想将一个函数映射到Theano中矢量的每个元素,我可以不使用扫描吗?

时间:2015-12-12 11:08:14

标签: numpy parallel-processing vectorization theano

假设一个函数计算数组每个索引处的1的外观:

import theano
import theano.tensor as T


A = T.vector("A")
idx_range = T.arange(A.shape[0])

result, updates = theano.scan(fn=lambda idx: T.sum(A[:idx+1]), sequences=idx_range)

count_ones = theano.function(inputs=[A], outputs=result)

print count_ones([0,0,1,0,0,1,1,1])
# gives [ 0.  0.  1.  1.  1.  2.  3.  4.]

如上所述here,使用扫描可能效率不高。另外,theano.scan总是在我的机器上产生“运行时警告:numpy.ndarray大小已更改,可能表示来自scan_perform.scan_perform import *的二进制不兼容”。

所以我想知道在Theano中有更好的映射函数的方法吗? 提前谢谢。

编辑:
我刚刚意识到这是一个可怕的例子,显然有一种更有效的方法可以像以下一样循环遍历向量:

result, updates = theano.scan(fn=lambda prior_result, a: prior_result + a,
                              outputs_info=T.alloc(np.int32(0), 1),
                              sequences=A,
                              n_steps=A.shape[0])

然而根据@Daniel Renshaw的回答,自

  

一步计算取决于相同的计算   一些早期的步骤

所以实际上我无法避免在这方面使用扫描,对吗?

编辑:
我想到了一种将其证实为:

的方法
A = T.vector()
in_size = 8
# a matrix with ones at and below the given diagonal and zeros elsewhere
mask = theano.shared(numpy.tri(in_size))  
result = T.dot(mask, A)
count_ones = theano.function(inputs=[A], outputs=result)
print count_ones(numpy.asarray([0,0,1,0,0,1,1,1]))

但是在这种情况下我必须提前知道输入的大小(除非我能像飞行中的矩阵一样制作numpy.tri吗?)。
欢迎大家提出意见。 :)

编辑:
我使用512D输入数组和10000次迭代对三种方法进行了基准测试,得到了以下结果:

  1. 将sum函数映射到每个元素:CPU 16s GPU 140s
  2. 使用扫描循环数组:CPU 13s GPU 32s
  3. 矢量化:CPU 0.8s GPU 0.8s(实际上我不认为theano已经使用GPU来执行此操作

1 个答案:

答案 0 :(得分:3)

在最一般的情况下,如果没有对该功能做出假设,则必须使用扫描。但是,许多(可能是大多数?)有用的功能可以被矢量化,从而不需要扫描。正如问题编辑中指出的那样,示例函数当然可以应用于输入而不使用扫描。

决定是否需要扫描取决于需要应用的功能。肯定需要扫描的情况是指一步中的计算依赖于某个早期步骤中的相同计算的情况。

P.S。可以安全地忽略关于二进制不兼容性的警告。