从Theano的扫描中调用一个函数

时间:2015-04-01 00:29:07

标签: theano

我需要通过扫描多次执行theano函数,以便总结成本函数并在梯度计算中使用它。我熟悉这样做的深度学习教程,但是我的数据切片和其他一些复杂性意味着我需要做一些不同的事情。 以下是我试图做的简化版本。

tn = testnet()
cost = tn.single_cost( )
x = theano.shared(numpy.asarray([7.1,2.2,3.4], dtype='float32'))
index = T.lscalar('index')
test_fn = theano.function(inputs=[index], outputs=cost, 
    givens={tn.x:x[index:index+1]} )

def step(curr):
    return T.constant( test_fn( curr ) )
outs,_ = theano.scan(step, T.arange(2))

out_fn = theano.function(inputs=[], outputs=outs)
print out_fn()

在扫描功能中,对test_fn(curr)的调用给出错误... 期望一个类似数组的对象,但是找到了一个变量:也许你试图在一个(可能是共享的)变量而不是数字数组上调用一个函数?')

即使我传入一个值数组而不是将T.arrange(2)放到位,我仍然会得到相同的错误。有没有理由你无法通过扫描调用函数?

一般来说,我想知道是否有办法用一系列索引调用这样的函数,以便输出可以输入T.grad()计算(未显示)。

3 个答案:

答案 0 :(得分:3)

不要制作两个不同的theano.functions

theano.function采用符号关系,对其进行优化并编译。你在这里做的是要求theano.scan(以及out_fn)将编译函数视为符号关系。无论你是否能够技术上让它发挥作用我都不确定,但这违背了Theano的想法。

由于我不知道你的成本函数在这里做了什么,所以我不能给出一个确切的例子,但是这里有一个快速的例子,它可以起作用并且应该与我认为你的'相似重新尝试。

x = theano.shared(np.asarray([7.1,2.2,3.4], dtype = np.float32))

v = T.vector("v")
def fv(v):
    res,_ = theano.scan(lambda x: x ** 2, v)
    return T.sum(res)

def f(i):
    return fv(x[i:i+2])

outs,_ = theano.scan(
    f, 
    T.arange(2)
    )

fn = theano.function(
    [],
    outs,
    )

fn()

答案 1 :(得分:1)

经过一番调查后,我同意从函数调用函数是不正确的。代码面临的挑战是,遵循深度学习教程的基本设计,网络的第一层有一个符号变量,定义为输入,输出传播到更高层,直到从顶部计算最终成本层。教程使用的代码类似于......

class layer1(object):
   def __init__(self):
      self.x = T.matrix()
      self.output = activation(T.dot(self.x,self.W) + self.b)

对我来说,张量变量(layer1.self.x)需要在每次扫描采取步骤以获得新的数据片段时进行更改。函数中的“givens”语句可以做到这一点,但是由于从“扫描”内部调用已编译的theano函数不起作用,我能够找到另外两种解决方案......

1 - 重做网络,使其成本函数基于一系列函数调用而不是传播变量。这在技术上很简单,但需要进行一些重新编码才能在多层网络中正确组织。

2 - 在扫描范围内使用theano.clone。该代码看起来像......

def step(curr):
    y_in = y[curr]
    replaces = {tn.layer1.x : x[curr:curr+1]}
    fn = theano.clone(tn.cost(y_in), replace=replaces)
    return fn
outs,_ = theano.scan(step, sequences=[T.arange(batch_start,batch_end)])

两种方法都返回相同的结果,并以相同的速度执行。

答案 2 :(得分:0)

解决方案

标准方式是OpFromGraph(截至0.8.2)

import theano as th
import theano.tensor as T

x = T.scalar('x')
y = T.scalar('y')
z = x+y
# unlike theano.function, must use list for outputs
op_add = th.OpFromGraph([x,y], [z])

def my_add(x_, y_):
    return op_add(x_, y_)[0]

x_list = T.vector('x_li')
x_sum = th.scan(op_add, sequences=[x_list], outputs_info=[T.constant(0.)])
fn_sum = th.function([x_list], x_sum)
fn([1., 2., 3., 4.]) # 10.

它做什么?

OpFromGraph编译从图形定义的函数,然后将其打包到新的Op中。就像在命令式编程语言中定义函数一样。

优点/缺点

  • [+]它可以在棘手的模型中使用。
  • [+]节省编译时间。您可以将大型模型的常用部分编译为OpFromGraph,然后直接在更大的模型中使用它。最终图表的节点数比直接实现的要少。
  • [ - ]会导致运行时性能下降。调用函数会产生开销,由于编译性质,编译器也无法进行全局优化。
  • [ - ]它过早而且仍处于发展阶段。它的文档不完整。目前不支持updates中的givenstheano.function

注释

在大多数情况下,您应该定义python函数/类来构建模型。如果没有可行的解决方法或者您想节省编译时间,则仅使用OpFromGraph