介绍在Theano中使用ifelse与switch实现条件判断,通过scan函数构建循环语句。

条件判断

Theano不能直接使用if语句来进行条件设置。

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

  • switch(cond, ift, iff)如果满足条件,则switch既执行ift也执行iff。

  • if cond then ift else iff ifelse只执行ift或者只执行iff 。

案例:

from theano import tensor as T     #导入tensor库
from theano.ifelse import ifelse   #导入ifelse库
import theano,time,numpy           #导入其他第三方库

a,b=T.scalars('a','b')             #a,b两个标量
x,y=T.matrices('x','y')            #x,y两个矩阵

z_switch=T.switch(T.lt(a,b),T.mean(x),T.mean(y))#lt:a < b?  
#如果成立,则对x求平均值、对y求平均值
z_lazy=ifelse(T.lt(a,b),T.mean(x),T.mean(y))  
#如果成立,则对x求平均值;如果不成立,对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.perf_counter() 
for i in range(n_times):  
    f_switch(val1, val2, big_mat1, big_mat2)  
print('time spent evaluating both values %f sec' % (time.perf_counter() - tic))  
# switch计算十次的时间


tic = time.perf_counter() 
for i in range(n_times):  
    f_lazyifelse(val1, val2, big_mat1, big_mat2)  
print('time spent evaluating one value %f sec' % (time.perf_counter() - tic))  
# ifelse计算十次的时间

运行结果:

time spent evaluating both values 0.003092 sec
time spent evaluating one value 0.005061 sec


AttributeError module ‘time‘ has no attribute ‘clock‘ 解决方法
博主的环境是python3.9,time库不再支持time.clock()。用 time.perf_counter() 来替换即可。在程序中以及进行了更正。

循环语句

任何用循环、递归或者跟序列有关的计算,都可以用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: 函数类型,scan的一步执行
  • sequences: scan进行迭代的变量
  • outputs_info: 初始化fn的输出变量,和输出的shape一致。如果初始化值设为None表示这个变量不需要初始值。
  • non_sequences :fn函数用到的其他变量,迭代过程中不可改变
  • n_steps: 迭代次数
  • go_backwards: 是否从后向前遍历

输出为一个元组 (outputs, updates):

  • outputs: 从初始状态开始,每一步 fn 的输出结果
  • updates: 一个字典,用来记录 scan 过程中用到的共享变量更新规则,构造函数的时候,如果需要更新共享变量,将这个变量当作 updates 的参数传入。

下面的例子是对多项式进行求和。思路是先定义函数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()  # 每步变化的值,系数组成的向量,ivector表示int类型的vector
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))

如果有一定的编程基础,应该不会太为难。条件判断循环语句在整个代码中,都是至关重要的部分。


声明:内容来源于吴茂贵老师主编的学习教材《Python深度学习——基于TensorFlow》,本文仅供学习参考,并加入了博主自己的一些理解和操作,并非原汁原味,为了更好的阅读体验和系统性地学习,请购买正版读物进行学习。



博主个人公众号
版权声明 ▶ 本网站名称:陶小桃Blog
▶ 本文链接:https://www.52txr.cn/2022/ifAndScan.html
▶ 本网站的文章部分内容可能来源于网络,仅供大家学习与参考,如有侵权,请联系站长进行核实删除。
▶ 转载本站文章需要遵守:商业转载请联系站长,非商业转载请注明出处!!

最后修改:2022 年 05 月 25 日
如果觉得我的文章对你有用,请随意赞赏