Theano2.1.1-基础知识之准备工作

来源:http://deeplearning.net/software/theano/tutorial/index.html#tutorial

    这里介绍的是使用theano的一些基础知识,虽然theano是用来dl 的,不过其中的一些函数还是挺有用的,可以用在ml 里面。

    在python或者ipython的交互模式下,可以按照如下形式来import theano:

>>> from theano import *

    这里有几个你需要使用的符号都在theano的tensor这个子包中。让我们首先导入这个子包,并给它赋值一个新的变量名比如 T :

>>> import theano.tensor as T

    如果这一步没报错,那么就可以准备接下来的教程了,不然还是回头去安装好theano吧( Installing Theano),我的安装过程

    在整个教程中,记得有一个术语表( Glossary ,就在该博文下面这个目录的下面)可以用来作为索引和模块链接的。

下面是 theano basic tutorial的目录(其中1、2、23节内容都在本页,其他的另成一页):

  • 1、Python 简单教程,下面是4个网页链接,其中有经典的练习和书籍
  • 2、NumPy 复习
  •     2.1机器学习的矩阵约定
  • 行表示水平方向,列表示竖直方向。每一行就是一个样本。所以inputs[10,5] 就是一个有着10个样本的矩阵,其中每个样本的维度为5。如果这是一个NN的输入,那么从输入到第一层隐藏层的权重就表示为size (5, #hid)的矩阵。

    考虑这样一个数组:

    >>> numpy.asarray([[1., 2], [3, 4], [5, 6]])
    array([[ 1.,  2.],
           [ 3.,  4.],
           [ 5.,  6.]])
    >>> numpy.asarray([[1., 2], [3, 4], [5, 6]]).shape
    (3, 2)

    这是一个3*2的矩阵,即有3行2列。

    访问第3行(row#2)第1列(column #0)的元素:

    >>> numpy.asarray([[1., 2], [3, 4], [5, 6]])[2, 0]
    5.0

    这里需要注意的是,我们是从左到右,从上到下读取的,所以一行是连续的,也就是3行2列。

    2.2广播(Broadcasting)

    Numpy 会在算术操作的时候对不同形状的数组进行广播。也就是说更小的那个数组(或者标量)会广播成对应的那个更大的数组,从而能够进行数学计算。下面就是一个广播的例子:

    >>> a = numpy.asarray([1.0, 2.0, 3.0])
    >>> b = 2.0
    >>> a * b
    array([2., 4., 6.])

    更小的数组b (实际上这里只是个标量, 可以看成是一个0d数组) 在这种情况下,在乘法运算中就会广播成相同的size。该技巧通常用在简化所写的表达式上。 更多有关广播的详细细节请查看numpy user guide.

     

  • 3、Baby Steps - Algebra翻译
  • 4、More Examples翻译
  • 5、Graph Structures翻译
  • 6、Printing/Drawing Theano graphs翻译
  • 7、Derivatives in Theano翻译
  • 8、Configuration Settings and Compiling Modes翻译
  • 9、Loading and Saving翻译
  • 10、Conditions翻译
  • 11、Loop翻译
  • 12、Sparse翻译
  • 13、Using the GPU翻译
  • 14、PyCUDA/CUDAMat/Gnumpy compatibility翻译
  • 15、Understanding Memory Aliasing for Speed and Correctness翻译
  • 16、How Shape Information is Handled by Theano翻译
  • 17、Debugging Theano: FAQ and Troubleshooting翻译
  • 18、Profiling Theano function翻译
  • 19、Extending Theano翻译
  • 20、Extending Theano with a C Op
  • 21、Python Memory Management
  • 22、Multi cores support in Theano翻译
  • 23、Frequently Asked Questions
  •     23.1如何更新权重的子集?

    如果你只想要更新一个权重矩阵的子集(例如某些行,某些列),这种情况在每次迭代的前向传播过程中会遇到。那么cost函数应该被定义成只依赖在这次迭代中当前权重子集的方式才行。

    例如,如果你想要学习一个查找表,例如,在处理词向量(word embedding)的时候,每一行的权重向量用来表示模型从一个单词学到的embedding,在每次迭代中,那些唯一需要更新的行都是在前馈传播中包含着embedding的。这里介绍下theano 函数应该如何来写:

    对查找表定义一个共享变量

    >>> lookup_table = theano.shared(matrix_ndarray).

    通过传递所需要行或者列的整数索引向量来得到这个表的一个子集 (某些行或者某些列) .

    >>> subset = lookup_table[vector_of_indices]

    从现在开始,使用 ‘subset’,而不会再调用 lookup_table[vector_of_indices] 了。这会造成梯度上的问题,因为这会生成新的变量

    定义cost只依赖于subset而不是整个lookup_table:

    >>> cost = something that depends on subset
    >>> g = theano.grad(cost, subset)

    有两种方式来更新这些参数:使用inc_subtensor 或者set_subtensor。推荐使用 inc_subtensor。一些theano是在这两者之间通过转换来进行优化的,不过不是所有情况下都是如此: 

    >>> updates = inc_subtensor(subset, g*lr)
    OR
    >>> updates = set_subtensor(subset, subset + g*lr)

    如果你不使用inc_subtensor或set_subtensor与其他类型的索引,那么我们只需要掌握这里的情况就可以了。

    定义这个theano函数

    >>> f=theano.function(..., updates=updates)

    注意到你可以计算cost函数关于整个lookup_table的梯度, 在前馈传播过程中选取的行中会有非0行的梯度。 如果你使用梯度下降来进行更新这些参数,那么就不会有问题,除了不必要的计算,例如,你可能会使用许多梯度为0的行来更新这个查找表的参数。然而,如果你想要使用一个不同的优化方法比如rmsprop 或者 Hessian-Free 优化,那么就会有问题。在 rmsprop 中,你需要通过平方根除以当前的梯度(whose square root you divide the current gradient,不知道翻译的对不对)来逐部分的逐步重新调整,从而保持一个指数衰减平方梯度(exponentially decaying squared gradient)。如果对应一个罕见单词的查找表行的梯度经常出现0,那么对于这一行来说该梯度的平方将倾向于0,因为该行的衰减倾向于为0;使用Hessian-Free的话,你会得到许多的0行和0列,甚至它们中有些还是不可逆的。通常来说,只计算梯度关于在前馈传播中实际用到的查找表的行会更好。

 Glossary(术语表)

Apply
apply的实例表示从一些输入变量(Variable )到生成一些输出变量( Variable )的操作( Op ) 。就像是数学形式上的函数在输入的参数上的应用.
Broadcasting

广播这个机制允许有着不同数量维度的张量能够应用在逐元素处理的情形下。它通过在缺失的维度的方向上将更小的张量进行复制来实现的。

更详细的,可以看看Broadcasting in Theano vs. Numpy, 和 * SciPy documentation about numpy’s broadcasting * OnLamp article about numpy’s broadcasting

Constant

一个有着不可变值的变量。例如,当你输入如下:

>>> x = tensor.ivector()
>>> y = x + 3

那么在graph中就会创建一个常量3。

See also: gof.Constant

Elementwise

两个张量变量 M 和 N的一个逐元素操作 f 的形式如下:

f(M, N)[i, j] == f(M[i, j], N[i, j])

换句话说,输入矩阵中的每个元素是和其他矩阵对应位置上的元素相结合的。 当元素的坐标[i, j] 没有对应的时候,元素之间是没有依赖关系的,所以逐元素操作就像是在几个维度上的一个标量操作。 在不同维度张量上的逐元素操作可以通过 broadcasting (广播)更小的维度来实现。

Expression
见 Apply
Expression Graph

 Variable 和 用来表示变量之间的符号函数关系的Apply 节点相连可以构成一个有向,无环集合。你可以通过定义表达式图来使用theano,然后用 theano.function来对他们进行编译。

See also VariableOpApply, 和 Type, 或者更多的可以看看 Graph Structures.

Destructive

当计算一个或多个输入需要被重写要不然就会失效,那么该操作 Op (对于某个具体的input[s])就是破坏性的。例如,inplace 操作就是破坏性的。不过破坏性的操作有时候比非破坏性的操作快很多。theano建议用户不要将破坏性的操作放入graph中,然后给  theano.function but 不过却可以可以通过对优化插入破坏性的操作来优化。

破坏性的操作可以通过 destroy_map 的操作属性来指明。 (See gof.Op.

Graph
见 expression graph
Inplace
Inplace计算是会带有破坏它们输入的副作用的。例如,如果你需要对一个矩阵进行迭代,其中的操作是将每个元素乘以2,那么这就是一个inplace操作,因为当你完成的时候,原始的输入已经被重写了。这说明inplace 计算是破坏性的 destructive, 默认情况下它们只能被用来作为优化的插入,而不是用户编写的代码。
Linker
 Mode 函数的一部分,一个用来负责“运行”编译后函数的对象。在其他环境下,linker 决定着计算是用C 还是 Python 的代码。
Mode
一个提供了 optimizer 和 linker 的对象,会被传送给 theano.function. 它可以将一个表达式图如何转换成一个可调用的对象进行参数化
Op

 一个 Apply  的 .op和它的符号输入一起决定着在运行的时候,哪种计算方式会被使用。在theano中,例如加法 (T.add) 和索引 x[i] 这样的数学上的函数都是操作。库文档中大部分都是用来描述不同的操作的,不过你可以自行添加其他的操作。

See also VariableType, 和 Apply, 更详细的可以看 Graph Structures.

Optimizer
 Optimizer,的一个实例,可以提供 optimization (或者 optimizations)。
Optimization
 optimizer 应用的 graph 变换发生在theano.function 对 graph的编译的时候。
Pure
当没有发生破坏性的副作用的时候操作 Op 是纯粹的。
Storage
T用来存储变量值的内存部分。在大多数情况下,存储是与编译后的函数内部相关的,不过在某些情况下 (例如 constant 和 shared variable 的时候,存储就不是内部相关了。
Shared Variable
一个可以在不同的函数之间共享的变量( Variable ) 。可以参考共享和theano.function.
theano.function
将符号表达式图编译成可调用的对象的theano的接口。可以参考 function.function().
Type

 Variable  .type 用来表示哪一种值会在编译后的graph中被计算。继承自Type的实例,用来作为一个变量 Variable.的.type属性。

See also VariableOp, 和 Apply, 更多可以看看Graph Structures.

Variable

这是你使用theano的时候主要用到的数据结构。例如:

>>> x = theano.tensor.ivector()
>>> y = -x**2

x 和 y 都是 Variables, 即,是Variable 这个类的实例。

See also TypeOp, and Apply, 或者更详细的可以看看 Graph Structures.

View

一些张量操作 (例如 Subtensor 和 Transpose) 可以通过简单的对输入重新索引来保持在常量时间内完成。从apply的实例得到输出的这样的操作被称为 Views 是因为它们的存储可能会被其他变量(apply的输入)的存储别名了. 对于theano来说,知道哪些变量是其他变量的views是很重要的,因为这样就可以引入正确的 Destructive 操作.

View 操作是通过一个 view_map 操作属性来表示的。 (See gof.Op.

 

posted @ 2015-06-09 09:45  仙守  阅读(2127)  评论(0编辑  收藏  举报