一、两个标量相加
在学习theano的开始,首先来感受下它是如何工作的,让我们先来定义一个简单的相加函数:
>>> import theano.tensor as T >>> from theano import function >>> x = T.dscalar('x') >>> y = T.dscalar('y') >>> z = x + y >>> f = function([x, y], z)
现在,我们可以使用之前创建好的函数,然后使用了:
>>> f(2, 3) array(5.0) >>> f(16.3, 12.1) array(28.4)
这里是将上面部分进行分步介绍。首先定义两个符号 (变量)来表示你想要相加的数。注意到从现在开始,我们将会使用变量(Variable)来表示“符号”(换句话说,也就是 x, y, z 都是变量对象)。函数 f 的输出就是一个有着0维的 numpy.ndarray 。
如果你想要输入一个整数,你可能会发现在执行function的时候有轻微的延时。这是因为需要将函数 f 编译成c 代码。
第一步
>>> x = T.dscalar('x') >>> y = T.dscalar('y')
在theano中,所有的符号都必须手动输入。具体来说,T.dscalar 就是我们分配给“doubles类型(d)的0维数组(scalar)”类型。这是一个theano类型 Type.
dscalar 不是一个类,所以 x 和 y 都不是 dscalar的实例。他们是 TensorVariable的实例 。正如下面看到的:
>>> type(x) <class 'theano.tensor.basic.TensorVariable'> >>> x.type TensorType(float64, scalar) >>> T.dscalar TensorType(float64, scalar) >>> x.type is T.dscalar True
通过一个字符串参数来调用 T.dscalar ,可以创建一个变量来表示一个给定名字下的一个浮点标量。如果你不提供参数,该符号将会是未命名的(unnamed)。虽然名字是不是必须的,可是却有助于调试。
更多的可以看看theano的内部结构。同样可以看看 Graph Structures.
第二步
第二步就是结合 x 与y 到它们的和z中
>>> z = x + y
z 是另一个变量用来表示 x 与 y的和. 你可以使用 pp 函数来友好的打印出与z 关联的计算结果。
>>> from theano import pp >>> print pp(z) (x + y)
第三步
最后一步就是创建一个函数,将x 与 y 作为输入,然后通过z 作为输出:
>>> f = function([x, y], z)
function 的第一个参数是变量的列表,用来作为输入提供给函数。第二个参数是一个单一的变量或者一个变量列表。在其他情况下,第二个变参数就是我们想要的输出。然后f 就可以被和普通的python函数一样使用了。
note:作为一个快捷方式,你可以跳过第三步,值使用一个变量的eval() 方法。 eval() 方法没有 function() 这么灵活,不过却能做教程中的任何事情。这是你不需要inport function() 的额外的福利. 下面就是 eval() 工作的过程:
>>> import theano.tensor as T >>> x = T.dscalar('x') >>> y = T.dscalar('y') >>> z = x + y >>> z.eval({x : 16.3, y : 12.1}) array(28.4)
我们给 eval()传递一个词典,将符号theano变量映射成值从而来取代它们,然后对表达式返回数值。
eval() 在第一次调用的时候可能会比较慢,因为它需要调用 function() 来计算场景后面的表达式。之后对 eval() 以同样的变量上的调用将会很快,因为变量已经将编译后的函数进行缓存了。
二、两个矩阵相加
你可能已经猜到如何来做了确实,这里与之前唯一的区别在于你需要实例化x 与y ,然后使用矩阵类型:
>>> x = T.dmatrix('x') >>> y = T.dmatrix('y') >>> z = x + y >>> f = function([x, y], z)
dmatrix 是doubles类型的矩阵,然后我们就能在2D数组上使用新的函数了:
>>> f([[1, 2], [3, 4]], [[10, 20], [30, 40]]) array([[ 11., 22.], [ 33., 44.]])
该变量是一个 NumPy 数组。我们同样可以直接使用NumPy 数组作为输入:
>>> import numpy >>> f(numpy.array([[1, 2], [3, 4]]), numpy.array([[10, 20], [30, 40]])) array([[ 11., 22.], [ 33., 44.]])
计算矩阵加标量、矩阵加向量、向量加标量都是可以的。这些能够得以实现得归功于broadcasting.
下面的类型都是可用的:
- byte: bscalar, bvector, bmatrix, brow, bcol, btensor3, btensor4
- 16-bit integers: wscalar, wvector, wmatrix, wrow, wcol, wtensor3, wtensor4
- 32-bit integers: iscalar, ivector, imatrix, irow, icol, itensor3, itensor4
- 64-bit integers: lscalar, lvector, lmatrix, lrow, lcol, ltensor3, ltensor4
- float: fscalar, fvector, fmatrix, frow, fcol, ftensor3, ftensor4
- double: dscalar, dvector, dmatrix, drow, dcol, dtensor3, dtensor4
- complex: cscalar, cvector, cmatrix, crow, ccol, ctensor3, ctensor4
上面的列表不够详尽,针对使用Numpy数组来兼容所有类型的更详细文档可以看: tensor creation.
note:你,用户(不是系统架构者)不得不选择你的程序为32- 或者 64-bit 的整数 (i 前缀 vs. l 前缀) 和浮点数 (f 前缀 vs. d 前缀).
三、练习
import theano a = theano.tensor.vector() # declare variable out = a + a ** 10 # build symbolic expression f = theano.function([a], out) # compile function print f([0, 1, 2]) # prints `array([0, 2, 1026])`
修改并计算这个表达式的结果: a ** 2 + b ** 2 + 2 * a * b.
下面就是答案:
#!/usr/bin/env python # Theano tutorial # Solution to Exercise in section 'Baby Steps - Algebra' from __future__ import print_function import theano a = theano.tensor.vector() # declare variable b = theano.tensor.vector() # declare variable out = a ** 2 + b ** 2 + 2 * a * b # build symbolic expression f = theano.function([a, b], out) # compile function print(f([1, 2], [4, 5])) # prints [ 25. 49.]
参考资料:
[1] 官网:http://deeplearning.net/software/theano/tutorial/adding.html