我非常肯定这是微不足道的,但我还没有成功地完全理解scan
。我想迭代地构建一个值矩阵m
,其中
m[i,j] = f(m[k,l]) for k < i, j < l
因此您可以将其视为动态编程问题。但是,我甚至无法通过遍历列表[1..100]生成列表[1..100]并在我去的时候更新共享值。
import numpy as np
import theano as T
import theano.tensor as TT
def test():
arr = T.shared(np.zeros(100))
def grid(idx, arr):
return {arr: TT.set_subtensor(arr[idx], idx)}
T.scan(
grid,
sequences=TT.arange(100),
non_sequences=[arr])
return arr
run = T.function([], outputs=test())
run()
返回
array([ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0.])
答案 0 :(得分:0)
这里有一些指向一些误解的东西。 scan
真的可以成为Theano的一大部分来包围你的头脑!
这是一些更新的代码,可以执行我认为您正在尝试执行的操作,但我不建议您使用此代码。基本问题是您似乎不恰当地使用共享变量。
import numpy as np
import theano as T
import theano.tensor as TT
def test():
arr = T.shared(np.zeros(100))
def grid(idx, arr):
return {arr: TT.set_subtensor(arr[idx], idx)}
_, updates = T.scan(
grid,
sequences=TT.arange(100),
non_sequences=[arr])
return arr, updates
outputs, updates = test()
run = T.function([], outputs=outputs, updates=updates)
print run()
print outputs.get_value()
此代码以两种方式从原始代码更改:
必须捕获(最初丢弃)扫描更新并将其传递给theano.function
的{{1}}参数。如果没有这个,共享变量将根本不会更新。
执行该功能后需要检查共享变量的内容(见下文)。
此代码打印两组值。第一个是Theano函数从执行时的输出。第二个是Theano函数执行后共享变量的内容。 Theano函数返回共享变量,因此您可能认为这两组值应该相同,但您错了!在 计算完所有函数的输出值之后,不会更新共享变量。所以只有在函数执行完之后,我们才会看到共享变量的内容,我们看到了我们原本期望看到的值。
这是在Theano中实现动态编程算法的一个例子。该算法是动态时间扭曲的简化版本,与编辑距离有很多相似之处。
updates
这是高度简化的,我不建议真正使用它。一般来说,Theano在进行动态编程方面非常糟糕,因为import numpy
import theano
import theano.tensor as tt
def inner_step(j, c_ijm1, i, c_im1, x, y):
insert_cost = tt.switch(tt.eq(j, 0), numpy.inf, c_ijm1)
delete_cost = tt.switch(tt.eq(i, 0), numpy.inf, c_im1[j])
match_cost = tt.switch(tt.eq(i, 0), numpy.inf, c_im1[j - 1])
in_top_left = tt.and_(tt.eq(i, 0), tt.eq(j, 0))
min_c = tt.min(tt.stack([insert_cost, delete_cost, match_cost]))
c_ij = tt.abs_(x[i] - y[j]) + tt.switch(in_top_left, 0., min_c)
return c_ij
def outer_step(i, c_im1, x, y):
outputs, _ = theano.scan(inner_step, sequences=[tt.arange(y.shape[0])],
outputs_info=[tt.constant(0, dtype=theano.config.floatX)],
non_sequences=[i, c_im1, x, y], strict=True)
return outputs
def main():
x = tt.vector()
y = tt.vector()
outputs, _ = theano.scan(outer_step, sequences=[tt.arange(x.shape[0])],
outputs_info=[tt.zeros_like(y)],
non_sequences=[x, y], strict=True)
f = theano.function([x, y], outputs=outputs)
a = numpy.array([1, 2, 4, 8], dtype=theano.config.floatX)
b = numpy.array([2, 3, 4, 7, 8, 9], dtype=theano.config.floatX)
print a
print b
print f(a, b)
main()
与本机循环相比速度非常慢。如果你需要通过动态程序传播渐变,那么你可能没有任何选择,但如果你不需要渐变,你应该避免使用Theano进行动态编程。
如果你想要一个更全面的DTW实现来克服一些性能命中,Theano通过并行计算许多比较(即批处理)来强加,那么请看一下:https://github.com/danielrenshaw/TheanoBatchDTW。