热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

五个例子掌握theano.scan函数

一、theano的工作原理在theano编程中,Graph是指导theano如何对变量进行操作的唯一途径,theano变量和theanoOps(操作)是Graph的两个基本构成元素

一、theano的工作原理

    在theano编程中,Graph是指导theano如何对变量进行操作的唯一途径,theano变量和theano Ops(操作)是Graph的两个基本构成元素。Graph只能由theano变量(包括shared变量)或常数组成。如图所示:

Graph

    通常可以按如下步骤构造Graph:首先声明theano变量,theano变量在python文件中的作用范围和普通python变量相同;然后用theano的Ops建立变量之间的联系,如T.sum(a,b);最后用theano.function把变量和变量间关系结合起来,构成一个完整的Graph。

    假设已经创建了一个function,称为fn,fn=theano.function(…)。Graph中的shared变量已经包含了调用fn时需要的数据,而普通theano变量仅仅是一个占位符,需要在function中作为输入,并且在调用fn时给变量赋具体值(如numpy的array或者常数)。

二、scan函数

    scan是theano中构建循环Graph的方法,函数声明如下:

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的一步执行。除了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函数的具体使用方法。

例一、A的k次方

#==============================================================================
# A**k
#==============================================================================
k = T . iscalar('k')
A = T . vector( 'A')

outputs, updates = theano.scan(lambda result, A : result * A,
non_sequences = A, outputs_info=T.ones_like(A), n_steps = k)
result = outputs [-1]
fn_Ak = theano . function([A,k ], result, updates=updates )
print fn_Ak( range(10 ), 2 )

结果:
[ 0. 1. 4. 9. 16. 25. 36. 49. 64. 81.]

    程序输出结果A*A。outputs_info初始化为和A相同大小的全1向量,匿名(lambda)函数的输入依次为outputs_info,non_sequences ,对应于匿名函数的输入result和A。由于scan函数的输出结果会记录每次迭代fn的输出,result = outputs [-1]可以告诉theano只需要取最后一次迭代结果,theano也会对此做相应的优化(不存保存中间几次迭代结果)。

例二、多项式方程

#==============================================================================
# polynomial -- c0*x^0 + c1*x^1 + c2*x^2 + c3*x^3...
#==============================================================================
coefficients=T.vector('coeff')
x = T.iscalar('x')
sum_poly_init = T.fscalar('sum_poly')
result, update = theano.scan(lambda coefficients, power, sum_poly, x: T.cast(sum_poly +
coefficients*(x**power),dtype=theano.config.floatX),
sequences=[coefficients, T.arange(coefficients.size)],
outputs_info=[sum_poly_init],
non_sequences=[x])

poly_fn = theano.function([coefficients,sum_poly_init,x], result, updates=update)

coeff_value = numpy.asarray([1.,3.,6.,5.], dtype=theano.config.floatX)
x_value = 3
poly_init_value = 0.
print poly_fn(coeff_value,poly_init_value, x_value)

结果:
[ 1. 10. 64. 199.]

    这个例子主要演示了T.arange()的作用,scan会在T.arange()生成的list上遍历。例如这段代码中T.arange()生成list=[0,1,2,3],在第i次迭代中,scan把coefficients的第i个元素和list的第i个元素喂给fn作为参数。outputs_info作为第三个参数输入给fn,然后是non_sequences的变量。其中outputs_info的初始化大小和类型都要和fn的返回结果相同。打印结果中包含了4次迭代的输出。

例三、theano.scan_module.until

#==============================================================================
# theano.scan_module.until
#==============================================================================

print 'theano.scan_module.until:'
def prod_2(pre_value, max_value):
return pre_value*2, theano.scan_module.until(pre_value*2 > max_value)

max_value = T.iscalar('max_value')
result, update = theano.scan(prod_2, outputs_info=T.constant(1.),
non_sequences=[max_value], n_steps=100)

prod_fn = theano.function([max_value], result, updates=update)
print prod_fn(400)

结果:
[ 2. 4. 8. 16. 32. 64. 128. 256. 512.]

    theano.scan_module.until必须放在函数的return语句里,当条件满足时,scan停止迭代。

例四、斐波那契数列–taps

    taps在有时间序列的迭代程序中比较有用,例如有如下代码:

scan(fn, sequences = [ dict(input= Sequence1, taps = [-3,2,-1])
, Sequence2
, dict(input = Sequence3, taps = 3) ]
, outputs_info = [ dict(initial = Output1, taps = [-3,-5])
, dict(initial = Output2, taps = None)
, Output3 ]
, non_sequences = [ Argument1, Argument2])

那么fn函数的变量输入顺序是:

    1. Sequence1[t-3]
2. Sequence1[t+2]
3. Sequence1[t-1]
4. Sequence2[t]
5. Sequence3[t+3]
6. Output1[t-3]
7. Output1[t-5]
8. Output3[t-1]
9. Argument1
10. Argument2

其中sequences默认taps=0;outputs_info默认taps=-1,因为taps=0的结果是当前这一步迭代需要计算的。

#==============================================================================
# taps scalar -- Fibonacci sequence
#==============================================================================
Fibo_arr = T.vector('Fibonacci')
k= T.iscalar('n_steps')
result, update = theano.scan(lambda tm2,tm1: tm2 + tm1,
outputs_info=[dict(initial=Fibo_arr, taps=[-2,-1])],
n_steps=k)
Fibo_fn = theano.function([Fibo_arr,k], result, updates=update)
Fibo_init = numpy.asarray([1,1], dtype=theano.config.floatX)
k_value = 12
print Fibo_fn(Fibo_init, k_value)

结果:
[ 2. 3. 5. 8. 13. 21. 34. 55. 89. 144. 233. 377.]

    程序段中首先设置scan的output的初始值为Fibo_arr=[1,1]向量,taps -2和-1分别指向Fibo_arr的第一个元素和第二个元素,并作为匿名函数的输入参数tm2和tm1。例如假设scan迭代到[ 2. 3. 5. 8. 13. 21. 34. ]时,taps=-4对应的值为8,taps=-3对应的值为13,taps=-2对应的值为21,taps=-1对应的值为34,那么在当前迭代中tm2=21, tm1=34,当前迭代结果为21+34=55。

    当使用taps时,outputs_info的初始化值中必须包含taps所对应时间点的值。

例五、两个斐波那契数列

#==============================================================================
# taps vector -- two Fibonacci sequences
#==============================================================================
Fibo_mat = T.matrix('Fibo_mat')
k = T.iscalar('n_steps')
result, update = theano.scan(lambda tm2,tm1: tm2 + tm1,
outputs_info=[dict(initial=Fibo_mat, taps=[-2,-1])],
n_steps=k)
Fibo_fn = theano.function([Fibo_mat,k], result, updates=update)
Fibo_init = numpy.asarray([[1,1],[1,2]], dtype=theano.config.floatX)
k_value = 12
print Fibo_fn(Fibo_init, k_value)
结果:
[[ 2. 3.]
[ 3. 5.]
[ 5. 8.]
[ 8. 13.]
[ 13. 21.]
[ 21. 34.]
[ 34. 55.]
[ 55. 89.]
[ 89. 144.]
[ 144. 233.]
[ 233. 377.]
[ 377. 610.]]

    在这段程序中,taps = -2的值为[1,1], taps=-1的值为[1,2],通过迭代求和,得到了两列斐波那契数列。这段代码和例四很相似,只是例四中是标量的迭代,这段代码是向量的迭代,同样可以很容易扩展到矩阵的迭代。

三、参考资料

theano document:http://deeplearning.net/software/theano/library/scan.html#lib-scan-shared-variables


推荐阅读
  • 提升Python编程效率的十点建议
    本文介绍了提升Python编程效率的十点建议,包括不使用分号、选择合适的代码编辑器、遵循Python代码规范等。这些建议可以帮助开发者节省时间,提高编程效率。同时,还提供了相关参考链接供读者深入学习。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • 本文介绍了P1651题目的描述和要求,以及计算能搭建的塔的最大高度的方法。通过动态规划和状压技术,将问题转化为求解差值的问题,并定义了相应的状态。最终得出了计算最大高度的解法。 ... [详细]
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • 深入理解Kafka服务端请求队列中请求的处理
    本文深入分析了Kafka服务端请求队列中请求的处理过程,详细介绍了请求的封装和放入请求队列的过程,以及处理请求的线程池的创建和容量设置。通过场景分析、图示说明和源码分析,帮助读者更好地理解Kafka服务端的工作原理。 ... [详细]
  • 生成式对抗网络模型综述摘要生成式对抗网络模型(GAN)是基于深度学习的一种强大的生成模型,可以应用于计算机视觉、自然语言处理、半监督学习等重要领域。生成式对抗网络 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • VScode格式化文档换行或不换行的设置方法
    本文介绍了在VScode中设置格式化文档换行或不换行的方法,包括使用插件和修改settings.json文件的内容。详细步骤为:找到settings.json文件,将其中的代码替换为指定的代码。 ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • 本文介绍了[从头学数学]中第101节关于比例的相关问题的研究和修炼过程。主要内容包括[机器小伟]和[工程师阿伟]一起研究比例的相关问题,并给出了一个求比例的函数scale的实现。 ... [详细]
  • 本文讨论了使用差分约束系统求解House Man跳跃问题的思路与方法。给定一组不同高度,要求从最低点跳跃到最高点,每次跳跃的距离不超过D,并且不能改变给定的顺序。通过建立差分约束系统,将问题转化为图的建立和查询距离的问题。文章详细介绍了建立约束条件的方法,并使用SPFA算法判环并输出结果。同时还讨论了建边方向和跳跃顺序的关系。 ... [详细]
  • 本文介绍了多因子选股模型在实际中的构建步骤,包括风险源分析、因子筛选和体系构建,并进行了模拟实证回测。在风险源分析中,从宏观、行业、公司和特殊因素四个角度分析了影响资产价格的因素。具体包括宏观经济运行和宏经济政策对证券市场的影响,以及行业类型、行业生命周期和行业政策对股票价格的影响。 ... [详细]
  • Python正则表达式学习记录及常用方法
    本文记录了学习Python正则表达式的过程,介绍了re模块的常用方法re.search,并解释了rawstring的作用。正则表达式是一种方便检查字符串匹配模式的工具,通过本文的学习可以掌握Python中使用正则表达式的基本方法。 ... [详细]
  • 本文讨论了在openwrt-17.01版本中,mt7628设备上初始化启动时eth0的mac地址总是随机生成的问题。每次随机生成的eth0的mac地址都会写到/sys/class/net/eth0/address目录下,而openwrt-17.01原版的SDK会根据随机生成的eth0的mac地址再生成eth0.1、eth0.2等,生成后的mac地址会保存在/etc/config/network下。 ... [详细]
  • 本文介绍了在CentOS上安装Python2.7.2的详细步骤,包括下载、解压、编译和安装等操作。同时提供了一些注意事项,以及测试安装是否成功的方法。 ... [详细]
author-avatar
手机用户2502911283
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有