Theano2.1.18-基础知识之theano的扩展

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

Extending Theano

    该教程覆盖了如何使用新颖的ops来扩展theano。它主要关注哪些能够提供一个python实现的ops。而Extending Theano with a C Op 是基于c的op实现。该教程的第一部分介绍了theano的graphs,因为提供一个新颖的theano op需要对theano graphs有个基本的理解。然后在概括的介绍了定义一个op的最重要的方法。

    正如一个图文说明需要的,该教程会介绍如何编写一个简单的基于python的op,该op是基于double上执行的。同样会介绍如何实现测试来确保之前op的工作的有效性。

note:

该教程不会介绍如何编写得到输入值的视图或者对其修改的op。所以这里介绍的所有ops必须返回新的分配的内存或者重用由函数perform() 的参数output_storage 所提供的内存。 想了解这些过程可以查阅 Views and inplace operations 。

如果你的op返回针对输入的视图或者修改,却不是如介绍的那样实现的,那么theano就还是会运行,并且返回某些graphs的正确的值和其他graphs的错误结果。

强烈建议在DebugMode (Theano flag mode=DebugMode) 下运行你的测试,因为它会验证你的op行为是否正确。

note:查阅 Developer Start Guide 来了解版本框架的信息,即git 和GitHub,和开发工作流程以及如何进行有质量的贡献。

一、Theano Graphs

                                              ../_images/apply_node.png

    Theano会将符号数学化计算表示成graph。这些graph都是二分图 (有2种类型node的图),它们由内连接的Apply 和 Variable 节点组成。 Variable 节点在graph中表示数据,例如:输入、输出或者中间值。所以一个graph的输入和输出也就是theano Variable 节点的列表. Apply 节点通过在这些变量上执行计算来生成新的值。每个 Apply 节点会连接到 Op 的一个实例,从而来表示所执行的计算。该教程详细介绍了如何编写这样一个op实例。关于图结构的更详细信息,查阅: Graph Structures 翻译

 二、Op 结构

       op就是继承自gof.Op的某个python对象。该部分提供了一些方法的概述,可以用来实现一个新的op。。不过没有介绍你可能遇到或者需要的所有可能的情况。不过更详细的可以查阅: Op’s contract.

 

import theano

class MyOp(theano.Op):
    # Properties attribute
    __props__ = ()

    def make_node(self, *inputs):
        pass

    # Python implementation:
    def perform(self, node, inputs_storage, output_storage):
        pass

    # Other type of implementation
    # C implementation: [see theano web site for other functions]
    def c_code(...):
        # ...
        pass
    # Other implementations (pycuda, ...):
    def make_thunk(self, node, storage_map, _, _2):
        pass

    # optional:
    check_input = True

    def __init__(self, ...):
        pass

    def grad(self, inputs, g):
        pass

    def R_op(self, inputs, eval_points):
        pass

    def infer_shape(node, (i0_shapes, ...)):
        pass

op需要执行在gof.Op接口中定义的一些方法。对于op来说,首先需要定义方法make_node()  然后在实现该方法,例如perform()Op.c_code() 或 make_thunk()

 

make_node() 方法生成一个Apply节点来表示在提供的输入上op的应用。该方法需要对下面三个事情负责:

  • 首先检查输入变量类型是否与当前的op兼容。如果在当前输入类型上没法应用,那么必须抛出一个异常 (例如 TypeError).
  • 在theano的符号语言中,它会对*inputs上找到的变量进行操作,从而推断出符号输出变量的类型。并创建一个适合的符号类型的输出变量来作为该操作的输出。
  • 它创建一个有着输入和输出变量的apply实例,然后返回该apply实例。

perform() 方法用来定义一个op的python实现。它有以下几个参数:

  • node 是对一个Apply节点的引用,从前面的 Op‘s make_node() 方法获得。它通常不会用在简单的ops中,不过它包含的符号信息需要复杂的ops。
  • inputs 是对数据的引用列表,会被非符号语句所操作(即,python,Numpy中的语句)。
  • output_storage 是存储单元的列表,其中存储的是输出数据。每一个单元存储着op的一个输出。放入 output_storage 的数据必须匹配符号输出的类型。禁止改变output_storage中的列表的长度。函数模式可以允许output_storage 中的元素在执行过程中保持不变,或者将output_storage单元的值重设为None。而且允许对op所需要用到的一些内存进行预分配。该特性允许 perform 重用调用期间的内存,例如,假设在output_storage中预先分配了一些内存,其中有着正确的dtype,不过shape却是错的,而且存在某些stride模式。

perform() 方法必须由输入里决定。也就是说,当用在同一个输入的时候,该方法必须返回相同的输出。

gof.Op 允许使用其他的方法来定义op的实现。例如可以通过定义 Op.c_code() 来提供一个对该op的c实现。查阅 Extending Theano with a C Op 来获得关于 Op.c_code() 和其他相关的c方法更详细的介绍。注意到一个op可以提供c和pythong两种实现。

make_thunk() 方法是另一个可以用来代替 perform()的方法。它返回一个thunk.。该thunk被定义成一个0参数函数,该函数很好的封装了op在对应节点的参数上的计算过程。该方法有以下几个参数:

  • node 是Apply的实例,其中会请求一个thunk。
  • storage_map 是列表的字典,通过将变量映射成一个元素列表(one-element lists)来处理变量的当前的值。这个一元素列表可以作为指向值的指针,可以与其他节点和实例来共享该”指针“。
  • compute_map 同样也是列表的字典。将变量映射成一元素列表来处理布尔值。如果该值是0,那么这个变量就表示还未计算,该值是无效的。如果该值是1,那么这个变量已经被计算过了,那么是有效的。如果该值是2,那么这个变量是已经被垃圾回收了,不再有效,而且无法被这次调用所请求。返回的函数必须确保计算值在compute_map中计算过。

make_thunk() 在你自己想要生成代码和编译的时候是很有用的。例如,这可以让你使用PyCUDA来编译GPU代码。

如果 make_thunk() 被一个op所定义,那么它会被theano所使用来获得该op的实现。 perform() 和 Op.c_code()会被忽略掉。

 

其他通过op定义的可选的方法:

 __str__() 方法对你的op提供了一个有意义的字符串表示。

__eq__() 和 __hash__() 分别定义了两个ops是否相等和计算一个op实例的哈希。它们会在优化阶段被用来融合节点,那些有着相同计算的节点(相同的输入,相同的操作)。两个ops可以通过 __eq__() 来计算是否相等,即在有着相同输入的时候是否有着相同的输出。

 __props__ 列出的属性影响着计算是如何执行的 (通常来说,它们就是你在__init__()中设置的那样). 它必须是一个元组。如果你没有任何属性,那么你应该将这个属性设置成空元组( tuple ())。

__props__ 能够自动的生成合适的 __eq__() 和 __hash__() 给定从__props__生成的方法 __eq__(), 两个ops如果它们对于__props__中列出的所有属性都有有着相同的值,那么这两个ops就是相等的。给定从__props__ 生成的方法 __hash__() ,两个ops如果对于 __props__中列出的所有属性都有着相同的值,那么这两个ops有着相同的hash。 __props__ 同样会对你的op生成一个合适的 __str__() 。这需要theano的版本为 September 1st, 2014 or version 0.7.

 infer_shape() 方法允许在没有实际计算输出的情况下,推断op输出变量的shape。它可以作为输入 node(一个对Apply节点的引用)和theano符号变量的列表 (i0_shapei1_shape, ...)(op输入变量的shape)。 infer_shape() 返回一个列表,其中每个元素都是一个元组,用来标识一个输出的shape。这在当你只需要输出的shape而无需计算实际的输出的时候是很有用的,例如在优化的时候。

 grad() 方法适用于你想要对一些包含你op的表达式的损失函数进行微分的时候。在这个方法中梯度可以具体的符号化。它有两个参数inputs 和 output_gradients ,这两个都是符号的theano变量的列表,必须被theano符号化语言所操作。该grad方法必须返回一个列表,其中对应每个输入都有一个变量。每个返回的变量表示关于输入的梯度,而该梯度是基于关于每个输出的符号化梯度上计算得到的(个人:这句话估计理解有误)。如果输出不是关于一个输入的微分,那么该方法就会被定义成针对这个输入返回一个NullType类型的变量。同样的,如果你没有对某些输入实现grad计算,你需要返回关于这个输入的一个NullType类型的变量。查阅 grad()来得到更详细的说明。

 R_op() 方法当你想要让 theano.tensor.Rop 和你的op一起工作的时候是需要使用的。该函数实现了op表示的函数的R-操作。假设函数为 f ,输入为 x 。使用R-操作,即计算f 的jacobian然后通过v 与其右乘,表达式即: \frac{\partial f}{\partial x} v.

可选的布尔 check_input 属性用来指定你是否想要在你的op中使用这个类型来在c_code中检查它们的输入。它可以用来加速计算,减少开销(特别是在标量上)和减少生成的c文件的数量。

三、Op 例子

  1. import theano  
      
    class DoubleOp(theano.Op):  
        __props__ = ()  
      
        def make_node(self, x):  
            # check that the theano version has support for __props__  
            assert hasattr(self, '_props')  
            x = theano.tensor.as_tensor_variable(x)  
            return theano.Apply(self, [x], [x.type()])  
      
        def perform(self, node, inputs, output_storage):  
            x = inputs[0]  
            z = output_storage[0]  
            z[0] = x * 2  
      
        def infer_shape(self, node, i0_shapes):  
            return i0_shapes  
      
        def grad(self, inputs, output_grads):  
            return [output_grads[0] * 2]  
      
        def R_op(self, inputs, eval_points):  
            # R_op can receive None as eval_points.  
            # That mean there is no diferientiable path through that input  
            # If this imply that you cannot compute some outputs,  
            # return None for those.  
            if eval_points[0] is None:  
                return eval_points  
            return self.grad(inputs, eval_points)   

可以按照如下形式来测试: 

  1. x = theano.tensor.matrix()  
    f = theano.function([x], DoubleOp()(x))  
    import numpy  
    inp = numpy.random.rand(5, 4)  
    out = f(inp)  
    assert numpy.allclose(inp * 2, out)  
    print inp  
    print out  

 四、如何进行测试

      Theano有很多函数来简化测试。这些可以用来测试 infer_shapegrad 和 R_op 方法。将下面的代码放入一个文件中,然后用theano-nose

程序来执行该文件。

4.1 基本的测试

     基本的测试就是通过使用op,然后检查返回的是否正确。如果你检测到一个错误,那么你就需要抛出一个异常。你可以使用关键字assert来自动的抛出一个AssertionError。

  1. from theano.tests import unittest_tools as utt  
    from theano import config  
    class test_Double(utt.InferShapeTester):  
        def setUp(self):  
            super(test_Double, self).setUp()  
            self.op_class = DoubleOp  
            self.op = DoubleOp()  
      
        def test_basic(self):  
            x = theano.tensor.matrix()  
            f = theano.function([x], self.op(x))  
            inp = numpy.asarray(numpy.random.rand(5, 4), dtype=config.floatX)  
            out = f(inp)  
            # Compare the result computed to the expected value.  
            utt.assert_allclose(inp * 2, out)  

    我们调用 utt.assert_allclose(expected_value, value) 来对比NumPy ndarray。这抛出一个有着更多信息的错误消息。同样的,这个默认的容忍可以通过theano flags config.tensor.cmp_sloppy 来改变,其值为0, 1 和 2. 默认的值会有着最严格的比较,而1 和2 就比较不那么严格了。

4.2 测试infer_shape

     当一个类继承自 InferShapeTester 类,那么就可以通过 self._compile_and_check 来测试op的 infer_shape方法。在当只需要输出的shape而无需计算实际的输出的时侯,用来测试该op在graph中的优化情况。另外,它通过优化后的graph计算得到的shape与实际计算的输出的shape进行对比来检查当前的shape是否正确。      self._compile_and_check 会编译一个theano函数。它会将输入和输出的theano变量的列表作为参数(正如theano.function那样),然后将真实值传递给编译后的函数。 它同样会将op类作为一个参数,来保证在优化后的shape graph中没有实例出现。

    如果有错误,那么该函数抛出一个异常。如果你想要看错误的时候的行为,可以使用一个非正常的 infer_shape.

    在测试的时候,如果在不同的维度上shape的值相同 (例如,一个方阵或者有着shape为 (n, n, n),或(m, n, m)的tensor3 ),那么就没法检测。例如,如果 infer_shape 使用矩阵的 width来作为它的height,那么在方阵的情况下就没法检测是否出错了。这就是为什么 self._compile_and_check 在这种情况下会输出一个警告的原因。如果你的操作只在这种矩阵下工作,那么就可以通过 warn=False 参数来禁用该警告。

  1. from theano.tests import unittest_tools as utt  
    from theano import config  
    class test_Double(utt.InferShapeTester):  
        # [...] as previous tests.  
        def test_infer_shape(self):  
            x = theano.tensor.matrix()  
            self._compile_and_check([x],  # theano.function inputs  
                                    [self.op(x)],  # theano.function outputs  
                                    # Always use not square matrix!  
                                    # inputs data  
                                    [numpy.asarray(numpy.random.rand(5, 4),  
                                                   dtype=config.floatX)],  
                                    # Op that should be removed from the graph.  
                                    self.op_class)  

4.3 测试梯度

    函数 verify_grad 用来验证一个op或者theano graph的梯度。它通过对比分析梯度 (通过符号计算得到的)梯度和数值梯度 (通过有限的微分方法得到的)。

    如果出错了,那么该函数抛出一个异常。如果你想要看出错的情况,你可以执行一个错误的梯度 (例如,移除前面的2)。

 
  1. def test_grad(self):  
        theano.tests.unittest_tools.verify_grad(self.op,  
                                                [numpy.random.rand(5, 7, 2)])  

4.4 测试Rop

     类 RopLop_checker 定义了函数RopLop_checker.check_mat_rop_lop()RopLop_checker.check_rop_lop() 和RopLop_checker.check_nondiff_rop(). 这些函数可以用来测试一个具体的op的Rop方法的实现。

例如,为了验证DoubleOp的Rop方法,你可以如下来测试:

 
  1. import numpy  
    import theano.tests  
    from theano.tests.test_rop import RopLop_checker  
    class test_DoubleRop(RopLop_checker):  
        def setUp(self):  
            super(test_DoubleRop, self).setUp()  
        def test_double_rop(self):  
            self.check_rop_lop(DoubleRop()(self.x), self.in_shape)  
     

4.5 测试 GPU Ops

    在GPU上执行的Ops应该继承自 theano.sandbox.cuda.GpuOp 而不是 theano.Op。这可以给theano区分它们的机会。目前,我们使用这个在GPU上的和约间代码来测试NVIDIA驱动是否正确工作。

五、运行你的测试

   为了执行你的测试程序,你需要选择下面的某种方法 :

5.1 theano-nose

    选择要进行测试的方法就是运行 theano-nose. 在常规的theano安装中,后面的参数会读取操作系统的path,然后直接访问其中的文件夹。而且它也可以在Theano/bin文件夹中被访问。对应于不同的目的,可以使用下面不同的命令: 

  • theano-nose --theano: 运行任何在theano的path上找到的测试。
  • theano-nose folder_name: 运行任何在文件夹folder_name内找到的测试。
  • theano-nose test_file.py: 运行任何在文件test_file.py内的测试。

下面的命令对于开发者来说特别有用,因为它们可以针对具体的类或者具体的测试被调用

  • theano-nose test_file.py:test_DoubleRop: 运行在类 test_DoubleRop中的测试。
  • theano-nose test_file.py:test_DoubleRop.test_double_op: 只运行在类test_DoubleRop中的测试test_double_op 。

针对于 theano-nose 的用法和功能的详细介绍,可以使用带有参数为 --help (-h)的命令。(个人:在windows下运行theano-nose会显示找不到该命令,在ubuntu下没问题,即该教程的所有命令其实都是基于linux的,而非windows的。)

5.2 nosetests

    命令 nosetests 也是很有用的。虽然它缺少和 theano-nose 提供的信息, nosetests 的用法和theano-nose 相似,可以测试任何在python的路径上的文件夹:

nosetests [suffix similar to the above].

更多有关 nosetests 的资料,可查阅: nosetests.

5.3 In-file

   可以增加一块代码在文件的最后,然后运行该文件。在这个例子中,在类test_double_op中的测试 test_DoubleRop 会运行的。

  1. if __name__ == '__main__':  
       t = test_DoubleRop("test_double_rop")  
       t.setUp()  
       t.test_double_rop()  

我们建议如果在运行一个文件的时候,最好运行那个文件中所有的测试,这可以通过在测试文件的最后加上如下的代码:

  1. if __name__ == '__main__':  
        unittest.main()  

六、练习

    运行上面的 DoubleOp e例子的代码。

   修改并执行: x * y.

    修改并执行: x + y and x - y.

    你可以省略Rop函数。 试着实现上面的测试过程。

(注意到当前的theano的逐元素风格的优化只能用在涉及到单一输出的情况下。所以,为了解决这个问题,需要在代码中对这两个操作进行联合的显式优化。)

七、as_op

    as_op是一个pythong修饰符,用来将一个python函数转换成一个基础theano op,该op会在执行的时候调用所提供的函数。

    不推荐用该方法来建立一个op,不过这却是一个快速实现的方法。

    它有一个可选的 infer_shape() 参数,该参数必须有如下的形式:

  1. def infer_shape(node, input_shapes):  
         # ...  
         return output_shapes  
  • input_shapes 和 output_shapes 是元组列表,用来表示对应的输入/输出的shape。

note:不提供 infer_shape方法是为了防止对这个op的相关的shape优化 。例如, your_op(inputs, ...).shape 会需要执行该op从而得到shape。

note:没有grad被定义,也就是不能对包含该op的路径中的函数进行微分。

note:它将python函数转换成可调用的对象,该对象的输入是已经声明过的theano变量。

 7.1 as_op 例子

 
  1. import theano  
    import numpy  
    from theano.compile.ops import as_op  
      
    def infer_shape_numpy_dot(node, input_shapes):  
        ashp, bshp = input_shapes  
        return [ashp[:-1] + bshp[-1:]]  
     
    @as_op(itypes=[theano.tensor.fmatrix, theano.tensor.fmatrix],  
           otypes=[theano.tensor.fmatrix], infer_shape=infer_shape_numpy_dot)  
    def numpy_dot(a, b):  
       return numpy.dot(a, b)  

如下进行测试: 

  1. x = theano.tensor.fmatrix()  
    y = theano.tensor.fmatrix()  
    f = function([x, y], numpy_dot(x, y))  
    inp1 = numpy.random.rand(5, 4)  
    inp2 = numpy.random.rand(4, 7)  
    out = f(inp1, inp2)  

7.2 练习

    运行上的numpy_dot 例子的代码。

    修改并执行: numpy.add 和 numpy.subtract.

    修改并执行: x + y和 x - y.

八、测试中的随机数

    测试错误可重复在实际中是非常具有说服力的,为了让测试可以重复,就需要得到相同的随机树。你可以通过对Numpy的随机数生成器传入相同的种子来得到。

    更方便的方法就是使用类 InferShapeTester 和 RopLop_checker 。如果你实现了自己的 setUp 函数,别忘了调用其父类的setUp函数。

更多信息请查阅: Using Random Values in Test Cases.

答案(Solution 

  1. #!/usr/bin/env python  
    # Theano tutorial  
    # Solution to Exercise in section 'Extending Theano'  
    import unittest  
      
    import theano  
      
      
    # 1. Op returns x * y  
      
    class ProdOp(theano.Op):  
        def __eq__(self, other):  
            return type(self) == type(other)  
      
        def __hash__(self):  
            return hash(type(self))  
      
        def __str__(self):  
            return self.__class__.__name__  
      
        def make_node(self, x, y):  
            x = theano.tensor.as_tensor_variable(x)  
            y = theano.tensor.as_tensor_variable(y)  
            outdim = x.ndim  
            output = (theano.tensor.TensorType  
                      (dtype=theano.scalar.upcast(x.dtype, y.dtype),  
                          broadcastable=[False] * outdim)())  
            return theano.Apply(self, inputs=[x, y], outputs=[output])  
      
        def perform(self, node, inputs, output_storage):  
            x, y = inputs  
            z = output_storage[0]  
            z[0] = x * y  
      
        def infer_shape(self, node, i0_shapes):  
            return [i0_shapes[0]]  
      
        def grad(self, inputs, output_grads):  
            return [output_grads[0] * inputs[1], output_grads[0] * inputs[0]]  
      
      
    # 2. Op returns x + y and x - y  
      
    class SumDiffOp(theano.Op):  
        def __eq__(self, other):  
            return type(self) == type(other)  
      
        def __hash__(self):  
            return hash(type(self))  
      
        def __str__(self):  
            return self.__class__.__name__  
      
        def make_node(self, x, y):  
            x = theano.tensor.as_tensor_variable(x)  
            y = theano.tensor.as_tensor_variable(y)  
            outdim = x.ndim  
            output1 = (theano.tensor.TensorType  
                      (dtype=theano.scalar.upcast(x.dtype, y.dtype),  
                          broadcastable=[False] * outdim)())  
            output2 = (theano.tensor.TensorType  
                      (dtype=theano.scalar.upcast(x.dtype, y.dtype),  
                          broadcastable=[False] * outdim)())  
            return theano.Apply(self, inputs=[x, y], outputs=[output1, output2])  
      
        def perform(self, node, inputs, output_storage):  
            x, y = inputs  
            z1, z2 = output_storage  
            z1[0] = x + y  
            z2[0] = x - y  
      
        def infer_shape(self, node, i0_shapes):  
            return [i0_shapes[0], i0_shapes[0]]  
      
        def grad(self, inputs, output_grads):  
            og1, og2 = output_grads  
            if og1 is None:  
                og1 = theano.tensor.zeros_like(og2)  
            if og2 is None:  
                og2 = theano.tensor.zeros_like(og1)  
            return [og1 + og2, og1 - og2]  
      
      
    # 3. Testing apparatus  
      
    import numpy  
    from theano.gof import Op, Apply  
    from theano import tensor, function, printing  
    from theano.tests import unittest_tools as utt  
      
      
    class TestProdOp(utt.InferShapeTester):  
      
        rng = numpy.random.RandomState(43)  
      
        def setUp(self):  
            super(TestProdOp, self).setUp()  
            self.op_class = ProdOp  # case 1  
      
        def test_perform(self):  
            x = theano.tensor.matrix()  
            y = theano.tensor.matrix()  
            f = theano.function([x, y], self.op_class()(x, y))  
            x_val = numpy.random.rand(5, 4)  
            y_val = numpy.random.rand(5, 4)  
            out = f(x_val, y_val)  
            assert numpy.allclose(x_val * y_val, out)  
      
        def test_gradient(self):  
            utt.verify_grad(self.op_class(), [numpy.random.rand(5, 4),  
                                    numpy.random.rand(5, 4)],  
                            n_tests=1, rng=TestProdOp.rng)  
      
        def test_infer_shape(self):  
            x = tensor.dmatrix()  
            y = tensor.dmatrix()  
      
            self._compile_and_check([x, y], [self.op_class()(x, y)],  
                                    [numpy.random.rand(5, 6),  
                                     numpy.random.rand(5, 6)],  
                                    self.op_class)  
      
      
    class TestSumDiffOp(utt.InferShapeTester):  
      
        rng = numpy.random.RandomState(43)  
      
        def setUp(self):  
            super(TestSumDiffOp, self).setUp()  
            self.op_class = SumDiffOp  
      
        def test_perform(self):  
            x = theano.tensor.matrix()  
            y = theano.tensor.matrix()  
            f = theano.function([x, y], self.op_class()(x, y))  
            x_val = numpy.random.rand(5, 4)  
            y_val = numpy.random.rand(5, 4)  
            out = f(x_val, y_val)  
            assert numpy.allclose([x_val + y_val, x_val - y_val], out)  
      
        def test_gradient(self):  
            def output_0(x, y):  
                return self.op_class()(x, y)[0]  
      
            def output_1(x, y):  
                return self.op_class()(x, y)[1]  
      
            utt.verify_grad(output_0, [numpy.random.rand(5, 4),  
                                    numpy.random.rand(5, 4)],  
                            n_tests=1, rng=TestSumDiffOp.rng)  
            utt.verify_grad(output_1, [numpy.random.rand(5, 4),  
                                    numpy.random.rand(5, 4)],  
                            n_tests=1, rng=TestSumDiffOp.rng)  
      
        def test_infer_shape(self):  
            x = tensor.dmatrix()  
            y = tensor.dmatrix()  
      
            # adapt the choice of the next instruction to the op under test  
      
            self._compile_and_check([x, y], self.op_class()(x, y),  
                                    [numpy.random.rand(5, 6),  
                                     numpy.random.rand(5, 6)],  
                                    self.op_class)  
      
      
    # as_op exercice  
    import theano  
    import numpy  
    from theano.compile.ops import as_op  
      
      
    def infer_shape_numpy_dot(node, input_shapes):  
        ashp, bshp = input_shapes  
        return [ashp[:-1] + bshp[-1:]]  
     
     
    @as_op(itypes=[theano.tensor.fmatrix, theano.tensor.fmatrix],  
           otypes=[theano.tensor.fmatrix], infer_shape=infer_shape_numpy_dot)  
    def numpy_add(a, b):  
        return numpy.add(a, b)  
      
      
    def infer_shape_numpy_add_sub(node, input_shapes):  
        ashp, bshp = input_shapes  
        # Both inputs should have that same shape, so we just return one of them.  
        return [ashp[0]]  
     
     
    @as_op(itypes=[theano.tensor.fmatrix, theano.tensor.fmatrix],  
           otypes=[theano.tensor.fmatrix], infer_shape=infer_shape_numpy_add_sub)  
    def numpy_add(a, b):  
        return numpy.add(a, b)  
     
     
    @as_op(itypes=[theano.tensor.fmatrix, theano.tensor.fmatrix],  
           otypes=[theano.tensor.fmatrix], infer_shape=infer_shape_numpy_add_sub)  
    def numpy_sub(a, b):  
        return numpy.sub(a, b)  
      
      
    if __name__ == "__main__":  
        unittest.main()  
    View Code

九、文档

Documentation Documentation AKA Meta-Documentation中更详细的介绍了如何生成文档。

下面这个例子介绍如何将docstring加到一个类中: 

  1. import theano  
      
    class DoubleOp(theano.Op):  
    """ Double each element of a tensor. 
     
    :param x: input tensor. 
     
    :return: a tensor of the same shape and dtype as the input with all 
        values doubled. 
     
    :note: 
        this is a test note 
     
    :seealso: 
        You can use the elemwise op to replace this example. 
        Just execute `x * 2` with x being a Theano variable. 
     
    .. versionadded:: 0.6 
    """  
下面就是在库文档中的说明形式:
class theano.misc.doubleop.DoubleOp(use_c_code='/usr/bin/g++')

Double each element of a tensor.

Parameters: x – input tensor.
Returns: a tensor of the same shape and dtype as the input with all values doubled.
Note : this is a test note
Seealso : You can use the elemwise op to replace this example. Just execute x * 2 with x being a Theano variable.
 

在0.6版本中新加入的特性。

十、最后的笔记

    这部分更深的讨论可以查阅高级教程: Extending Theano.

 Other ops 介绍了下面这几个特殊情况:

 

参考资料:

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

posted @ 2015-06-23 09:10  仙守  阅读(1811)  评论(1编辑  收藏  举报