条件

IfElse和Switch

  • 这两个op在符号变量上构建一个条件。
  • IfElse接收一个布尔条件和两个变量作为输入。
  • Switch接收一个张量作为条件,两个变量作为输入。switch是元素级别的操作,因此比ifelse更通用。
  • switch对两个输出变量都求值,而ifelse是惰性的并且根据条件只求值一个变量。

Example

from theano import tensor as T
from theano.ifelse import ifelse
import theano, time, numpy

a,b = T.scalars('a', 'b')
x,y = T.matrices('x', 'y')

z_switch = T.switch(T.lt(a, b), T.mean(x), T.mean(y))
z_lazy = ifelse(T.lt(a, b), T.mean(x), T.mean(y))

f_switch = theano.function([a, b, x, y], z_switch,
                           mode=theano.Mode(linker='vm'))
f_lazyifelse = theano.function([a, b, x, y], z_lazy,
                               mode=theano.Mode(linker='vm'))

val1 = 0.
val2 = 1.
big_mat1 = numpy.ones((10000, 1000))
big_mat2 = numpy.ones((10000, 1000))

n_times = 10

tic = time.clock()
for i in range(n_times):
    f_switch(val1, val2, big_mat1, big_mat2)
print('time spent evaluating both values %f sec' % (time.clock() - tic))

tic = time.clock()
for i in range(n_times):
    f_lazyifelse(val1, val2, big_mat1, big_mat2)
print('time spent evaluating one value %f sec' % (time.clock() - tic))

In this example, the IfElse op spends less time (about half as much) than Switch since it computes only one variable out of the two.

$ python ifelse_switch.py
time spent evaluating both values 0.6700 sec
time spent evaluating one value 0.3500 sec

如果不使用linker='vm'linker='cvm'ifelse将计算两个变量并花费与switch相同的计算时间。虽然linker当前未默认设置为cvm,但在不久的将来将会设置为它。

没有自动优化将switch替换为使用broadcasted的标量的ifelse,因为这不总是更快。查看这个ticket

Note

If you use test values, then all branches of the IfElse will be computed. 这是正常的,因为使用test_value意味着当我们构建它时,由于Python的贪婪计算和测试值的语义,所有的都将被计算。当我们构建两个分支时,它们都将被执行测试值。This doesn’t cause any changes during the execution of the compiled Theano function.