How to perform a range on a Theano's TensorVariable?
Example:
import theano.tensor as T
from theano import function
constant = T.dscalar('constant')
n_iters = T.dscalar('n_iters')
start = T.dscalar('start')
result = start
for iter in range(n_iters):
result = start + constant
f = function([start, constant, n_iters], result)
print('f(0,2,5): {0}'.format(f(1,2)))
returns the error:
Traceback (most recent call last):
File "test_theano.py", line 9, in <module>
for iter in range(n_iters):
TypeError: range() integer end argument expected, got TensorVariable.
What is the correct way to use a range on a Theano's TensorVariable?
It's not clear what this code is attempting to do because even if the loop worked, it wouldn't compute anything useful: result
will always equal the sum of start
and constant
irrespective of the number of iterations.
I'll assume that the intention was to compute result
like this:
for iter in range(n_iters):
result = result + constant
The problem is that you're mixing symbolic, delayed execution, Theano operations with non-symbolic, immediately executed, Python operations.
range
is a Python function that expects a Python integer parameter but you're providing a Theano symbolic value (n_iters
, which has a double type instead of an integer type but let's assume it's actually an iscalar
instead of a dscalar
). As far as Python is concerned all Theano symbolic tensors are just objects: instances of a class type somewhere within the Theano library; they are most assuredly not integers. Even if you squint and try to pretend a Theano iscalar
looks like a Python integer, it still doesn't work because Python operations execute immediately which means n_iters
needs to have a value immediately. Theano on the other hand doesn't have a value for any iscalar
until one is provided by calling a compiled Theano function (or via eval
).
To create a symbolic range, you can use theano.tensor.arange
which operates just like NumPy's arange
, but symbolically.
Example:
import theano.tensor as T
from theano import function
my_range_max = T.iscalar('my_range_max')
my_range = T.arange(my_range_max)
f = function([my_range_max], my_range)
print('f(10): {0}'.format(f(10)))
outputs:
f(10): [0 1 2 3 4 5 6 7 8 9]
By making n_iters
a symbolic variable you are implicitly saying "I don't know how many iterations there need to be in this loop until a value is provided for n_iters
later". That being the case, you must use a symbolic loop instead of a Python for
loop. In the latter case you must tell Python how many times to iterate now, you can't delay that decision until a value is provided for n_iters
later. To solve this you need to switch to a symbolic loop, which is provided by Theano's scan
operator.
Here's the code changed to use scan
(as well as the other assumed changes).
import theano
import theano.tensor as T
from theano import function
constant = T.dscalar('constant')
n_iters = T.iscalar('n_iters')
start = T.dscalar('start')
results, _ = theano.scan(lambda result, constant: result + constant,
outputs_info=[start], non_sequences=[constant], n_steps=n_iters)
f = function([start, constant, n_iters], results[-1])
print('f(0,2,5): {0}'.format(f(0, 2, 5)))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With