在theano中无序列扫描? (模拟范围())
Scanning without sequences in theano? (emulating range())
这里是 Theano 新手。我正在做一些实验以生成可变长度的序列。我从想到的最简单的事情开始:模拟 range()。这是我写的简单代码:
from theano import scan
from theano import function
from theano import tensor as T
X = T.iscalar('X')
STEP = T.iscalar('STEP')
MAX_LENGTH = 1024 # or any othe very large value
def fstep(i, x, t):
n = i * t
return n, until(n >= x)
t_fwd_range, _ = scan(
fn=fstep,
sequences=T.arange(MAX_LENGTH),
non_sequences=[X, STEP]
)
getRange = function(
inputs=[X, Param(STEP, 1, 'step')],
outputs=t_fwd_range
)
getRange(x, step)
print list(f)
assert list(f[:-1]) == list(range(0, x, step))
所以我不得不使用 MAX_LENGTH
作为范围的长度,用作 fstep
theano scan
的输入。所以,我的主要问题是:有没有办法在没有输入序列的情况下使用 scan
?而且,正如我认为答案是 否 ,下一个问题是:这是做我想做的事情的正确(最有效,ecc)方法吗?
无需提供输入序列即可扫描。您可以改为通过扫描的 n_steps
参数指定迭代次数。或者,您还可以通过 theano.scan_module.until
.
指定扫描应提前停止的条件
因此,Python 的 range
函数可以使用 Theano 的 scan
来模拟,而无需指定输入序列,方法是计算出构建请求的序列需要多少次迭代。
下面是基于 Theano 的 scan
的范围函数的实现。唯一复杂的部分是计算需要多少步骤。
import numpy
import theano
import theano.tensor as tt
import theano.ifelse
def scan_range_step(x_tm1, step):
return x_tm1 + step
def compile_theano_range():
tt.arange
symbolic_start = tt.lscalar()
symbolic_stop = tt.lscalar()
symbolic_step = tt.lscalar()
n_steps = tt.cast(
tt.ceil(tt.abs_(symbolic_stop - symbolic_start) / tt.cast(tt.abs_(symbolic_step), theano.config.floatX)),
'int64') - 1
outputs, _ = theano.scan(scan_range_step, outputs_info=[symbolic_start], n_steps=n_steps,
non_sequences=[symbolic_step], strict=True)
outputs = theano.ifelse.ifelse(tt.eq(n_steps, 0), tt.stack(symbolic_start), outputs)
f = theano.function([symbolic_start, symbolic_stop, symbolic_step],
outputs=tt.concatenate([[symbolic_start], outputs]))
def theano_range(start, stop=None, step=1):
assert isinstance(start, int)
assert isinstance(step, int)
if step == 0:
raise ValueError()
if stop is None:
stop = start
start = 0
else:
assert isinstance(stop, int)
if start == stop:
return []
if stop < start and step > 0:
return []
if stop > start and step < 0:
return []
return f(start, stop, step)
return theano_range
def main():
theano_range = compile_theano_range()
python_range = range
for start in [-10, -5, -1, 0, 1, 5, 10]:
for stop in [-10, -5, -1, 0, 1, 5, 10]:
for step in [-3, -2, -1, 1, 2, 3]:
a = theano_range(start, stop, step)
b = python_range(start, stop, step)
assert numpy.all(numpy.equal(a, b)), (start, stop, step, a, b)
main()
显然,这对 do/use 来说确实是一件愚蠢的事情,因为 Theano 已经提供了 Python 的 range
函数的符号版本,即 theano.tensor.arange
。内置实现也比我们的 scan
版本高效得多,因为它不使用 scan
,而是使用自定义操作。
根据经验:您必须 通过range
或n_steps
参数设置最大迭代步数。您可以将它设置为一个非常大的数字,然后在满足停止条件的情况下使用 theano.scan_module.until
在较早的阶段停止迭代。
这里是 Theano 新手。我正在做一些实验以生成可变长度的序列。我从想到的最简单的事情开始:模拟 range()。这是我写的简单代码:
from theano import scan
from theano import function
from theano import tensor as T
X = T.iscalar('X')
STEP = T.iscalar('STEP')
MAX_LENGTH = 1024 # or any othe very large value
def fstep(i, x, t):
n = i * t
return n, until(n >= x)
t_fwd_range, _ = scan(
fn=fstep,
sequences=T.arange(MAX_LENGTH),
non_sequences=[X, STEP]
)
getRange = function(
inputs=[X, Param(STEP, 1, 'step')],
outputs=t_fwd_range
)
getRange(x, step)
print list(f)
assert list(f[:-1]) == list(range(0, x, step))
所以我不得不使用 MAX_LENGTH
作为范围的长度,用作 fstep
theano scan
的输入。所以,我的主要问题是:有没有办法在没有输入序列的情况下使用 scan
?而且,正如我认为答案是 否 ,下一个问题是:这是做我想做的事情的正确(最有效,ecc)方法吗?
无需提供输入序列即可扫描。您可以改为通过扫描的 n_steps
参数指定迭代次数。或者,您还可以通过 theano.scan_module.until
.
因此,Python 的 range
函数可以使用 Theano 的 scan
来模拟,而无需指定输入序列,方法是计算出构建请求的序列需要多少次迭代。
下面是基于 Theano 的 scan
的范围函数的实现。唯一复杂的部分是计算需要多少步骤。
import numpy
import theano
import theano.tensor as tt
import theano.ifelse
def scan_range_step(x_tm1, step):
return x_tm1 + step
def compile_theano_range():
tt.arange
symbolic_start = tt.lscalar()
symbolic_stop = tt.lscalar()
symbolic_step = tt.lscalar()
n_steps = tt.cast(
tt.ceil(tt.abs_(symbolic_stop - symbolic_start) / tt.cast(tt.abs_(symbolic_step), theano.config.floatX)),
'int64') - 1
outputs, _ = theano.scan(scan_range_step, outputs_info=[symbolic_start], n_steps=n_steps,
non_sequences=[symbolic_step], strict=True)
outputs = theano.ifelse.ifelse(tt.eq(n_steps, 0), tt.stack(symbolic_start), outputs)
f = theano.function([symbolic_start, symbolic_stop, symbolic_step],
outputs=tt.concatenate([[symbolic_start], outputs]))
def theano_range(start, stop=None, step=1):
assert isinstance(start, int)
assert isinstance(step, int)
if step == 0:
raise ValueError()
if stop is None:
stop = start
start = 0
else:
assert isinstance(stop, int)
if start == stop:
return []
if stop < start and step > 0:
return []
if stop > start and step < 0:
return []
return f(start, stop, step)
return theano_range
def main():
theano_range = compile_theano_range()
python_range = range
for start in [-10, -5, -1, 0, 1, 5, 10]:
for stop in [-10, -5, -1, 0, 1, 5, 10]:
for step in [-3, -2, -1, 1, 2, 3]:
a = theano_range(start, stop, step)
b = python_range(start, stop, step)
assert numpy.all(numpy.equal(a, b)), (start, stop, step, a, b)
main()
显然,这对 do/use 来说确实是一件愚蠢的事情,因为 Theano 已经提供了 Python 的 range
函数的符号版本,即 theano.tensor.arange
。内置实现也比我们的 scan
版本高效得多,因为它不使用 scan
,而是使用自定义操作。
根据经验:您必须 通过range
或n_steps
参数设置最大迭代步数。您可以将它设置为一个非常大的数字,然后在满足停止条件的情况下使用 theano.scan_module.until
在较早的阶段停止迭代。