基本扫描用法
scan
用于在值列表上多次调用函数,该函数可能包含状态。
scan
语法(截至 theano 0.9):
scan(
fn,
sequences=None,
outputs_info=None,
non_sequences=None,
n_steps=None,
truncate_gradient=-1,
go_backwards=False,
mode=None,
name=None,
profile=False,
allow_gc=None,
strict=False)
乍一看,这可能非常令人困惑。我们将在多个代码示例中解释几个基本但重要的 scan
用法。
以下代码示例假定你已执行导入:
import numpy as np
import theano
import theano.tensor as T
sequences
- 在列表上映射函数
在最简单的情况下,扫描只是将纯函数(没有状态的函数)映射到列表。列表在 sequences
参数中指定
s_x = T.ivector()
s_y, _ = theano.scan(
fn = lambda x:x*x,
sequences = [s_x])
fn = theano.function([s_x], s_y)
fn([1,2,3,4,5]) #[1,4,9,16,25]
注意 scan
有两个返回值,前者是结果列表,后者是状态值的更新,稍后将对此进行说明。
sequences
- 在列表中压缩函数
与上面几乎相同,只需给 sequences
参数列出两个元素。两个元素的顺序应该与 fn
中的参数顺序相匹配
s_x1 = T.ivector()
s_x2 = T.ivector()
s_y, _ = theano.scan(
fn = lambda x1,x2:x1**x2,
sequences = [s_x1, s_x2])
fn = theano.function([s_x], s_y)
fn([1,2,3,4,5],[0,1,2,3,4]) #[1,2,9,64,625]
outputs_info
- 累积列表
累积涉及状态变量。状态变量需要初始值,该值应在 outputs_info
参数中指定。
s_x = T.ivector()
v_sum = th.shared(np.int32(0))
s_y, update_sum = theano.scan(
lambda x,y:x+y,
sequences = [s_x],
outputs_info = [s_sum])
fn = theano.function([s_x], s_y, updates=update_sum)
v_sum.get_value() # 0
fn([1,2,3,4,5]) # [1,3,6,10,15]
v_sum.get_value() # 15
fn([-1,-2,-3,-4,-5]) # [14,12,9,5,0]
v_sum.get_value() # 0
我们将一个共享变量放入 outputs_info
,这将导致 scan
返回更新到我们的共享变量,然后可以将其放入 theano.function
。
non_sequences
和 n_steps
- 物流地图轨道 x -> lambda*x*(1-x)
你可以在 non_sequences
参数中提供在 scan
期间不会发生变化的输入。在这种情况下,s_lambda
是一个不变的变量(但不是常量,因为它必须在运行时提供)。
s_x = T.fscalar()
s_lambda = T.fscalar()
s_t = T.iscalar()
s_y, _ = theano.scan(
fn = lambda x,l: l*x*(1-x),
outputs_info = [s_x],
non_sequences = [s_lambda],
n_steps = s_t
)
fn = theano.function([s_x, s_lambda, s_t], s_y)
fn(.75, 4., 10) #a stable orbit
#[ 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75]
fn(.65, 4., 10) #a chaotic orbit
#[ 0.91000003, 0.32759991, 0.88111287, 0.41901192, 0.97376364,
# 0.10219204, 0.3669953 , 0.92923898, 0.2630156 , 0.77535355]
水龙头 - 斐波那契
状态/输入可能有多个时间步长。这是通过:
-
将
dict(input=<init_value>, taps=<list of int>)
放入sequences
论证中。 -
将
dict(initial=<init_value>, taps=<list of int>)
放入outputs_info
论证中。
在这个例子中,我们使用 outputs_info
中的两个抽头来计算递归关系 x_n = x_{n-1} + x_{n-2}
。
s_x0 = T.iscalar()
s_x1 = T.iscalar()
s_n = T.iscalar()
s_y, _ = theano.scan(
fn = lambda x1,x2: x1+x2,
outputs_info = [dict(initial=T.join(0,[s_x0, s_x1]), taps=[-2,-1])],
n_steps = s_n
)
fn_fib = theano.function([s_x0, s_x1, s_n], s_y)
fn_fib(1,1,10)
# [2, 3, 5, 8, 13, 21, 34, 55, 89, 144]