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