python - Scanning without sequences in theano? (emulating range()) -
theano newbie here. doing experiments in order generate variable length sequences. started simplest thing coming mind: emulating range(). here simple code wrote:
from theano import scan theano import function theano import tensor t x = t.iscalar('x') step = t.iscalar('step') max_length = 1024 # or othe large value def fstep(i, x, t): n = * 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))
so had use max_length
length of range used input of fstep
theano scan
. so, main question this: there way use scan
without input sequence? and, suppose answer no, next question is: correct (most efficient, ecc) way traying do?
there no need provide input sequence scan. can instead specify number of iterations via scan's n_steps
parameter. optionally, can specify condition under scan should stop via theano.scan_module.until
.
so python's range
function can emulated using theano's scan
without specifying input sequence figuring out how many iterations required construct requested sequence.
here's implementation of range function based on theano's scan
. complicated part figuring out how many steps required.
import numpy import theano import theano.tensor 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 none: stop = start start = 0 else: assert isinstance(stop, int) if start == stop: return [] if stop < start , step > 0: return [] if stop > start , step < 0: return [] return f(start, stop, step) return theano_range def main(): theano_range = compile_theano_range() python_range = range start in [-10, -5, -1, 0, 1, 5, 10]: stop in [-10, -5, -1, 0, 1, 5, 10]: step in [-3, -2, -1, 1, 2, 3]: = theano_range(start, stop, step) b = python_range(start, stop, step) assert numpy.all(numpy.equal(a, b)), (start, stop, step, a, b) main()
clearly daft thing do/use real since theano provides symbolic version of python's range
function, i.e. theano.tensor.arange
. built in implementation far more efficient our scan
version because doesn't use scan
, uses custom operation instead.
as rule of thumb: have to set maximum number of iteration steps via range
or the n_steps
argument. can set large number , use theano.scan_module.until
stop iteration @ earlier stage if stop condition met.
Comments
Post a Comment