来自:http://deeplearning.net/software/theano/tutorial/examples.html

More Examples

现在,是时候开始系统的熟悉theano的基础对象和操作了,可以通过浏览库的部分来详细的了解 Basic Tensor Functionality. 随着这个教程的深入,你可以逐渐的让自己熟悉库的其他相关的部分和文档入口页面的其他相关的主题了。

一、Logistic 函数

这是一个简单的例子,虽然会比两个数值相加要难一些。假设你想要计算一个逻辑曲线,首先得到一个如下的式子:

                                                                              

上图是一个逻辑函数,x轴表示x值,y轴表示s(x)值。

你需要在doubles矩阵上逐元素( elementwise )的计算这个函数,也就是说你是想要在矩阵的每个独立的元素上都使用该函数。代码如下:

[python] view plaincopy
  1. >>> x = T.dmatrix('x')
  2. >>> s = 1 / (1 + T.exp(-x))
  3. >>> logistic = function([x], s)
  4. >>> logistic([[0, 1], [-1, -2]])
  5. array([[ 0.5       ,  0.73105858],
  6. [ 0.26894142,  0.11920292]])

需要逐元素计算是因为它的操作:除法、加法、指数和减法,都是逐元素的操作。在该情况下也是:

我们可以验证从这个可代替的式子上得到的结果是一样的:

  1. >>> s2 = (1 + T.tanh(x / 2)) / 2
  2. >>> logistic2 = function([x], s2)
  3. >>> logistic2([[0, 1], [-1, -2]])
  4. array([[ 0.5       ,  0.73105858],
  5. [ 0.26894142,  0.11920292]])

二、在同一时间对多个操作进行计算

Theano支持函数有着多于一个的输出。例如,我们可以在同一时刻计算两个矩阵a和b 之间的逐元素(elementwise )的差,绝对值的差,平方值的差:

  1. >>> a, b = T.dmatrices('a', 'b')
  2. >>> diff = a - b
  3. >>> abs_diff = abs(diff)
  4. >>> diff_squared = diff**2
  5. >>> f = function([a, b], [diff, abs_diff, diff_squared])

note:dmatrices 生成提供的名字一样数量的输出。这是一个用来分配符号变量的快捷方式,在本教程中会经常用到。

当我们使用函数f 时,它返回三个变量(输出的时候会为了更好的可读性而被重新格式):

  1. >>> f([[1, 1], [1, 1]], [[0, 1], [2, 3]])
  2. [array([[ 1.,  0.],
  3. [-1., -2.]]),
  4. array([[ 1.,  0.],
  5. [ 1.,  2.]]),
  6. array([[ 1.,  0.],
  7. [ 1.,  4.]])]

三、对参数设置默认值

假设你想要定义一个相加两个数的函数,如果你定义完之后,在调用的时候,只提供了一个参数,那么另一个输入可以假设默认为1,可以如下所示:

  1. >>> from theano import Param
  2. >>> x, y = T.dscalars('x', 'y')
  3. >>> z = x + y
  4. >>> f = function([x, Param(y, default=1)], z)
  5. >>> f(33)
  6. array(34.0)
  7. >>> f(33, 2)
  8. array(35.0)

使用的 Param 参数允许你指定你函数的参数有着更详细的值。这里我们通过创建一个Param实例来将y设置其默认值为1。

有着默认值的输入必须在没有默认值的输入的后面(和python的函数一样的顺序)可以对多个输入进行设置莫仍只。这些蚕食可以通过位置或者名称来进行设定,就像标准的python中一样:

  1. >>> x, y, w = T.dscalars('x', 'y', 'w')
  2. >>> z = (x + y) * w
  3. >>> f = function([x, Param(y, default=1), Param(w, default=2, name='w_by_name')], z)
  4. >>> f(33)
  5. array(68.0)
  6. >>> f(33, 2)
  7. array(70.0)
  8. >>> f(33, 0, 1)
  9. array(33.0)
  10. >>> f(33, w_by_name=1)
  11. array(34.0)
  12. >>> f(33, w_by_name=1, y=0)
  13. array(33.0)

note:Param 不知道作为参数传入的局部变量y 和w 的名称。这些符号变量对象都有name属性(和上面例子一样通过dscalars来设置),这些是我们构建的函数中的关键参数的名称。这就是 Param(y, default=1)中的工作机制。在Param(w, default=2, name='w_by_name')的情况下 ,我们用在这个函数中使用过的名字来覆盖符号变量的名字属性。
    你可以看看库中的 Function 来更详细的了解。

四、使用共享变量

同样的也可以让函数有一个内部状态。例如,我们想要在开始就设置一个累加器,先初始化为0。那么,在每次的函数调用, 该状态就会被函数的参数递增的。首先定义一个accumulator 函数。然后将参数增加到内部状态上,然后返回增加之前的状态值。

    该代码引入了一些新的概念。 shared 函数构建所谓的 shared variables。这些都是混合符号和非符号变量,他们的值可以在多个函数中共享,就像是由dmatrices(...)返回的对象一样,不过他们同样有着一个内部值,这个值是通过这个在所有函数中使用的符号变量定义的。被称作共享变量是因为它的值在许多函数之间共享的。该值可以被 .get_value() 和 .set_value() 方法所访问和修改。

该代码中另一个新事物就是functionupdates的参数 updates 必须被以(shared-variable, new expression)这种对形式的列表所赋值。它同样可以是一个字典,其中的键是共享变量而值是新表达式。。不管怎么说,它表示“不论什么时候运行,它会将.value的每个共享变量替换成对应的表达式的结果” 。也就是说,我们的累加器会用状态state的和以及递增数来替换状态state的值。

  1. >>> state.get_value()
  2. array(0)
  3. >>> accumulator(1)
  4. array(0)
  5. >>> state.get_value()
  6. array(1)
  7. >>> accumulator(300)
  8. array(1)
  9. >>> state.get_value()
  10. array(301)

可以使用 .set_value() 方法来重置状态state:

  1. >>> state.set_value(-1)
  2. >>> accumulator(3)
  3. array(-1)
  4. >>> state.get_value()
  5. array(2)

正如上面说的,你可以定义超过一个函数来使用相同的共享变量。这些函数都能够更新这个值。

  1. >>> decrementor = function([inc], state, updates=[(state, state-inc)])
  2. >>> decrementor(2)
  3. array(2)
  4. >>> state.get_value()
  5. array(0)

你也许会惊讶为什么这个更新机制会存在。你总可以通过返回一个新的表达式来得到一个相似的结果,然后在NumPy里面使用它们。该更新机制是一个语法上的方便,不过在这里主要是因为效率问题。对共享变量的更新有时候可以使用in-place算法更快的完成(了例如: low-rank矩阵更新).。同样的,theano有着更多有关在哪和如何来分配共享权重的函数,这些都是在需要使用在 GPU上很重要的组成部分.

有时候你想要使用一个共享变量来表示一些公式,却不想要使用它们的值。在这种情况下,你可以使用function函数的givens的参数,这个用来代替这种情况下graph中的特定的节点。

  1. >>> fn_of_state = state * 2 + inc
  2. >>> # The type of foo must match the shared variable we are replacing
  3. >>> # with the ``givens``
  4. >>> foo = T.scalar(dtype=state.dtype)
  5. >>> skip_shared = function([inc, foo], fn_of_state,
  6. givens=[(state, foo)])
  7. >>> skip_shared(1, 3)  # we're using 3 for the state, not state.value
  8. array(7)
  9. >>> state.get_value()  # old state still there, but we didn't use it
  10. array(0)

givens 参数可以用来代替任何符号变量,不只是共享变量。你还可以用来代替常量、表达式。不过要注意,不要让由givens替换的表达式之间有着相互依赖关系,替换的顺序是没法保证的,所以替换之后是有可能以任意顺序来执行的。

在实际中,有关使用givens的一个好的方法就是替换公式的任何部分的时候使用的是不同的表达式,只不过该表达式有着相同shape和dtype的张量而已。

note:Theano 共享变量的广播模式默认情况下对于每个维度来说都是False。共享变量的size可以随着时间变化,所以我们没法使用shape来找到可广播的模式。如果你想要一个不同的模式,只要将它像参数一样传递 theano.shared(..., broadcastable=(True, False))。

五、使用随机数

因为在theano中,你首先会将任何事情进行符号化,然后编译这个表达式来得到函数,然后使用伪随机数不是和Numpy中一样简单的,当然也不会太复杂。

将随机放入theano的计算中就是将随机变量放到你的graph中。theano将会对每个这样的变量分配一个 NumPy RandomStream 对象 (一个随机生成器) ,然后必要的时候提取出来。我们称这类随机数序列为a random stream. 随机流的核心也是共享变量,所以对共享变量的观察在这里也是一样的。theano的随机对象的定义和实现在 RandomStreams 更低的版本,也就是其父类RandomStreamsBase.

5.1 一个简单的例子

这里是一个简短的例子,构建代码为:

  1. from theano.tensor.shared_randomstreams import RandomStreams
  2. from theano import function
  3. srng = RandomStreams(seed=234)
  4. rv_u = srng.uniform((2,2))
  5. rv_n = srng.normal((2,2))
  6. f = function([], rv_u)
  7. g = function([], rv_n, no_default_updates=True)    #Not updating rv_n.rng
  8. nearly_zeros = function([], rv_u + rv_u - 2 * rv_u)

这里 ‘rv_u’ 表示一个从均匀分布中提取的2*2的矩阵的随机流。同样的, ‘rv_n’ 表示一个从正太分布中提取的2*2矩阵的一个随机流。该分布实现和定义都在 RandomStreams 中,其父类为 raw_random. 他们只在CPU上工作。 Other Implementations 上面有GPU版本的。

现在让我们来使用这些对象。如果我们调用 f(),我们就得到了均匀随机数。 随机数生成器的内部状态是自动进行更新的,所以我们在每个时间上得到的是不同的随机数:

  1. >>> f_val0 = f()
  2. >>> f_val1 = f()  #different numbers from f_val0

当我们增加额外的参数 no_default_updates=True 到 function (as in g),那么随机数生成器状态不会受到返回函数调用的影响。所以,例如,调用g 函数多次,而返回的是同样的数值:

  1. >>> g_val0 = g()  # different numbers from f_val0 and f_val1
  2. >>> g_val1 = g()  # same numbers as g_val0!

一个重要的备注是随机变量在任何单一函数执行中最多被提取一次。所以,即使 rv_u 随机变量在输出表达式中出现了三次,nearly_zero函数可以保证返回的值可以逼近0 (除了舍入导致的错误):

  1. >>> nearly_zeros = function([], rv_u + rv_u - 2 * rv_u)

5.2 Seeding Streams

随机变量可以被独立或集体的被传入种子。你可以只对随机变量通过seeding或者使用.rng.set_value()的.rng 属性来指定传入种子:

  1. >>> rng_val = rv_u.rng.get_value(borrow=True)   # Get the rng for rv_u
  2. >>> rng_val.seed(89234)                         # seeds the generator
  3. >>> rv_u.rng.set_value(rng_val, borrow=True)    # Assign back seeded rng

你同样可以对所有的随机变量通过RandomStreams对象的seed方法来分配种子。该种子将会被用来传递给一个临时随机数生成器,然后对每个随机变量生成种子。

  1. >>> srng.seed(902340)  # seeds rv_u and rv_n with different seeds each

5.3 在函数之间共享流

和通常的共享变量一样,用于随机变量的随机数生成器都是函数中常见的。所以我们的nearly_zeros 函数将会使用上面介绍的函数 f 来更新生成器的状态。例如:

  1. >>> state_after_v0 = rv_u.rng.get_value().get_state()
  2. >>> nearly_zeros()       # this affects rv_u's generator
  3. >>> v1 = f()
  4. >>> rng = rv_u.rng.get_value(borrow=True)
  5. >>> rng.set_state(state_after_v0)
  6. >>> rv_u.rng.set_value(rng, borrow=True)
  7. >>> v2 = f()             # v2 != v1
  8. >>> v3 = f()             # v3 == v1

5.4 在theano graphs之间复制随机状态

在一些使用的情况中,用户有可能想要将所有随机数生成器的“state”从一个给定的theano graph (例如, g1,和下面编译的函数f1一起的) 到另一个 graph (例如 g2,和函数f2一起的).。如果你想要从之前模型的pickled版本的参数中初始化模型的state,那么这个问题就会出现。 theano.tensor.shared_randomstreams.RandomStreams 和 theano.sandbox.rng_mrg.MRG_RandomStreams 可以通过复制state_updates参数的元素来获得

每次从一个RandomStreams对象中得到一个随机变量,一个元组就会被添入到 state_updates 列表中。第一个元素就是一个共享变量,用来表示与这个具体的变量相关联的随机数生成器的状态,第二个元素用来表示对应于随机数生成过程(即RandomFunction{uniform}.0)的theano graph。

一个关于如何“random states”可以从一个theano function迁移到另一个的例子如下:

  1. import theano
  2. import numpy
  3. import theano.tensor as T
  4. from theano.sandbox.rng_mrg import MRG_RandomStreams
  5. from theano.tensor.shared_randomstreams import RandomStreams
  6. class Graph():
  7. def __init__(self, seed=123):
  8. self.rng = RandomStreams(seed)
  9. self.y = self.rng.uniform(size=(1,))
  10. g1 = Graph(seed=123)
  11. f1 = theano.function([], g1.y)
  12. g2 = Graph(seed=987)
  13. f2 = theano.function([], g2.y)
  14. print 'By default, the two functions are out of sync.'
  15. print 'f1() returns ', f1()
  16. print 'f2() returns ', f2()
  17. def copy_random_state(g1, g2):
  18. if isinstance(g1.rng, MRG_RandomStreams):
  19. g2.rng.rstate = g1.rng.rstate
  20. for (su1, su2) in zip(g1.rng.state_updates, g2.rng.state_updates):
  21. su2[0].set_value(su1[0].get_value())
  22. print 'We now copy the state of the theano random number generators.'
  23. copy_random_state(g1, g2)
  24. print 'f1() returns ', f1()
  25. print 'f2() returns ', f2()

会有如下的输出:

  1. # By default, the two functions are out of sync.
  2. f1() returns  [ 0.72803009]
  3. f2() returns  [ 0.55056769]
  4. # We now copy the state of the theano random number generators.
  5. f1() returns  [ 0.59044123]
  6. f2() returns  [ 0.59044123]

5.5 其他随机分布

见 other distributions implemented.

5.6 其他实现

这里有2个基于 CURAND 和 MRG31k3p.的两个实现。该RandomStream 只工作在CPU上,而 MRG31k3p 既能在CPU 上也能在GPU上。CURAND 只工作在 GPU上。

5.7 一个真实的例子:逻辑回归

前面的内容会在下面这个更实际的例子中见到,而且该例子会被多次使用。

  1. import numpy
  2. import theano
  3. import theano.tensor as T
  4. rng = numpy.random
  5. N = 400
  6. feats = 784
  7. D = (rng.randn(N, feats), rng.randint(size=N, low=0, high=2))
  8. training_steps = 10000
  9. # Declare Theano symbolic variables声明theano符号变量
  10. x = T.matrix("x")
  11. y = T.vector("y")
  12. w = theano.shared(rng.randn(feats), name="w")
  13. b = theano.shared(0., name="b")
  14. print "Initial model:"
  15. print w.get_value(), b.get_value()
  16. # Construct Theano expression graph构建theano表达式的图
  17. p_1 = 1 / (1 + T.exp(-T.dot(x, w) - b))   # Probability that target = 1
  18. prediction = p_1 > 0.5                    # The prediction thresholded
  19. xent = -y * T.log(p_1) - (1-y) * T.log(1-p_1) # Cross-entropy loss function
  20. cost = xent.mean() + 0.01 * (w ** 2).sum()# The cost to minimize
  21. gw, gb = T.grad(cost, [w, b])             # Compute the gradient of the cost
  22. # (we shall return to this in a
  23. # following section of this tutorial)
  24. # Compile编译
  25. train = theano.function(
  26. inputs=[x,y],
  27. outputs=[prediction, xent],
  28. updates=((w, w - 0.1 * gw), (b, b - 0.1 * gb)))
  29. predict = theano.function(inputs=[x], outputs=prediction)
  30. # Train训练
  31. for i in range(training_steps):
  32. pred, err = train(D[0], D[1])
  33. print "Final model:"
  34. print w.get_value(), b.get_value()
  35. print "target values for D:", D[1]
  36. print "prediction on D:", predict(D[0])

参考资料:

[1]官网:http://deeplearning.net/software/theano/tutorial/examples.html

Theano2.1.3-基础知识之更多的例子的更多相关文章

  1. C# 基础知识系列- 9 字符串的更多用法(一)

    0. 前言 在前面的文章里简单介绍了一下字符串的相关内容,并没有涉及到更多的相关内容,这一篇将尝试讲解一下在实际开发工作中会遇到的字符串的很多操作. 1. 创建一个字符串 这部分介绍一下如何创建一个字 ...

  2. selenium自动化基础知识

    什么是自动化测试? 自动化测试分为:功能自动化和性能自动化 功能自动化即使用计算机通过编码的方式来替代手工测试,完成一些重复性比较高的测试,解放测试人员的测试压力.同时,如果系统有不份模块更改后,只要 ...

  3. Python开发【第二篇】:Python基础知识

    Python基础知识 一.初识基本数据类型 类型: int(整型) 在32位机器上,整数的位数为32位,取值范围为-2**31-2**31-1,即-2147483648-2147483647 在64位 ...

  4. 学习 shell脚本之前的基础知识

    转载自:http://www.92csz.com/study/linux/12.htm  学习 shell脚本之前的基础知识 日常的linux系统管理工作中必不可少的就是shell脚本,如果不会写sh ...

  5. LLDB基础知识

    LLDB基础知识 LLDB控制台 Xcode中内嵌了LLDB控制台,在Xcode中代码的下方,我们可以看到LLDB控制台. LLDB控制台平时会输出一些log信息.如果我们想输入命令调试,必须让程序进 ...

  6. Oracle数据库基础知识

    oracle数据库plsql developer   目录(?)[-] 一     SQL基础知识 创建删除数据库 创建删除修改表 添加修改删除列 oracle cascade用法 添加删除约束主键外 ...

  7. 基础知识漫谈(2):从设计UI框架开始

    说UI能延展出一丢丢的东西来,光java就有swing,swt/jface乃至javafx等等UI toolkit,在桌面上它们甚至都不是主流,在web端又有canvas.svg等等. 基于这些UI工 ...

  8. java中文乱码解决之道(二)-----字符编码详解:基础知识 + ASCII + GB**

    在上篇博文(java中文乱码解决之道(一)-----认识字符集)中,LZ简单介绍了主流的字符编码,对各种编码都是点到为止,以下LZ将详细阐述字符集.字符编码等基础知识和ASCII.GB的详情. 一.基 ...

  9. C++ 顺序容器基础知识总结

    0.前言 本文简单地总结了STL的顺序容器的知识点.文中并不涉及具体的实现技巧,对于细节的东西也没有提及.一来不同的标准库有着不同的实现,二来关于具体实现<STL源码剖析>已经展示得全面细 ...

随机推荐

  1. 【JSP】JSP基础学习记录(二)—— JSP的7个动作指令

    2.JSP的7个动作指令: 动作指令与编译指令不同,编译指令是通知Servlet引擎的处理消息,而动作指令只是运行时的动作.编译指令在将JSP编译成Servlet时起作用:而处理指令通常可替换成JSP ...

  2. (转,有改动)测试网页响应时间的shell脚本[需要curl支持]

    用法及返回结果如下: [root@myserver01 tmp]# sh test_web.sh -n500 http://www.baidu.com Request url: http://www. ...

  3. Redisd VS Memcached

    Redis也常常被当作 Memcached的挑战者被提到桌面上来.关于Redis与Memcached的比较更是比比皆是.然而,Redis真的在功能.性能以及内存使用效率上都超越了Memcached吗? ...

  4. 2. Docker - 安装

    一.Docker介绍 1. Docker是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上, 也可以实现虚拟化. 容器时完全使用沙 ...

  5. Linux mke2fs 硬盘格式化

    [root@whp6 ~]# cat /etc/filesystems ext4 ext3 ext2 nodev proc nodev devpts iso9660 vfat hfs hfsplus ...

  6. if_nametoindex可以检查网卡名称是否有效

    NAME if_nametoindex, if_indextoname, if_nameindex, if_freenameindex - convert interface index to nam ...

  7. WD硬盘型号信息

    买硬盘的时候有时候分不清 既然找到了就发上来吧

  8. java报表工具FineReport常用函数的用法总结(数学和三角函数)

    ABS ABS(number):返回指定数字的绝对值.绝对值是指没有正负符号的数值. Number:需要求出绝对值的任意实数. 示例: ABS(-1.5)等于1.5. ABS(0)等于0. ABS(2 ...

  9. nodejs入门

    一.Nodejs介绍 简单的说 Node.js 就是运行在服务端的 JavaScript的代码解析器. 首先要清楚Node不是一个Web服务器,这十分重要.它本身并不能做任何事情.它无法像Apache ...

  10. Guava中Predicate的常见用法

    Guava中Predicate的常见用法 1.  Predicate基本用法 guava提供了许多利用Functions和Predicates来操作Collections的工具,一般在 Iterabl ...