购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

2.5 条件与循环

编写函数需要经常用到条件语句或循环语句,这节我们就简单介绍Theano如何实现条件判断或逻辑循环。

1.条件判断

Theano是一种符号语言,条件判断不能直接使用Python的if语句。在Theano可以用ifelse和switch来表示判定语句。这两个判定语句有何区别呢?

switch对每个输出变量进行操作,ifelse只对一个满足条件的变量操作。比如对语句:


switch(cond, ift, iff)

如果满足条件,则switch既执行ift也执行iff。而对语句:


if cond then ift else iff

ifelse只执行ift或者只执行iff。

下面通过一个示例进一步说明:


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))#lt:a < b?  
z_lazy=ifelse(T.lt(a,b),T.mean(x),T.mean(y))  

#optimizer:optimizer的类型结构(可以简化计算,增加计算的稳定性)  
#linker:决定使用哪种方式进行编译(C/Python) 
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((1000, 100))  
big_mat2 = numpy.ones((1000, 100))  

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))

打印结果:


time spent evaluating both values 0.005268 sec
time spent evaluating one value 0.007501 sec

2.循环语句

scan是Theano中构建循环Graph的方法,scan是个灵活复杂的函数,任何用循环、递归或者跟序列有关的计算,都可以用scan完成。其格式如下:


theano.scan(fn, sequences=None, outputs_info=None, non_sequences=None, n_steps=None, truncate_gradient=-1, go_backwards=False, mode=None, name=None, profile=False, allow_gc=None, strict=False)

参数说明:

·fn:一个lambda或者def函数,描述了scan中的一个步骤。除了outputs_info,fn可以返回sequences变量的更新updates。fn的输入变量的顺序为sequences中的变量、outputs_info的变量、non_sequences中的变量。如果使用了taps,则按照taps给fn喂变量。taps的详细介绍会在后面的例子中给出。

·sequences:scan进行迭代的变量,scan会在T.arange()生成的list上遍历,例如下面的polynomial例子。

·outputs_info:初始化fn的输出变量,和输出的shape一致。如果初始化值设为None,表示这个变量不需要初始值。

·non_sequences:fn函数用到的其他变量,迭代过程中不可改变(unchange)。

·n_steps:fn的迭代次数。

下面通过一个例子解释scan函数的具体使用方法。

代码实现思路是:先定义函数one_step,即scan里的fn,其任务就是计算多项式的一项,scan函数返回的result里会保存多项式每一项的值,然后我们对result求和,就得到了多项式的值。


import theano
import theano.tensor as T
import numpy as np

# 定义单步的函数,实现a*x^n
# 输入参数的顺序要与下面scan的输入参数对应
def one_step(coef, power, x):
    return coef * x ** power

coefs = T.ivector()  # 每步变化的值,系数组成的向量
powers = T.ivector() # 每步变化的值,指数组成的向量
x = T.iscalar()      # 每步不变的值,自变量

# seq,out_info,non_seq与one_step函数的参数顺序一一对应
# 返回的result是每一项的符号表达式组成的list
result, updates = theano.scan(fn = one_step,
                       sequences = [coefs, powers],
                       outputs_info = None,
                       non_sequences = x)

# 每一项的值与输入的函数关系
f_poly = theano.function([x, coefs, powers], result, allow_input_downcast=True)

coef_val = np.array([2,3,4,6,5])
power_val = np.array([0,1,2,3,4])
x_val = 10

print("多项式各项的值: ",f_poly(x_val, coef_val, power_val))
#scan返回的result是每一项的值,并没有求和,如果我们只想要多项式的值,可以把f_poly写成这样:
# 多项式每一项的和与输入的函数关系
f_poly = theano.function([x, coefs, powers], result.sum(), allow_input_downcast=True)

print("多项式和的值:",f_poly(x_val, coef_val, power_val))

打印结果: 7QUqjdu+Aj2y7WW0dre1TLioTMn9XVJCkJNbINO6zLsJCdRfN2p+sXIud9404Ds0


多项式各项的值:  [ 2   30   400  6000 50000]
多项式和的值: 56432

点击中间区域
呼出菜单
上一章
目录
下一章
×