您的位置:首页 > 其它

Theano---scan函数

2016-05-05 14:36 295 查看
         def scan:

         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中的一个

        步骤。fn描述了迭代的输出结果的公式。传给

        的变量顺序如下所示

        * 第一个sequence

        * 第一个sequence

        * ...

        * 最后一个sequence

        * 第一个output

        * 第二个output

        * ...

        * 最后一个output

        * 所有其他参数 (non_sequence给出)

         sequences的顺序和输入给scan的列表‘sequences’一样

         outputs的顺序“outputs_info”的顺序一样。

         对每个sequence 或者output来说,time slices的顺序和taps里给出的顺序一样

        如下例所示

       

        .. code-block:: python

            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`` 中参数的顺序由上到下所示:

        #. ``Sequence1[t-3]``

        #. ``Sequence1[t+2]``

        #. ``Sequence1[t-1]``

        #. ``Sequence2[t]``

        #. ``Sequence3[t+3]``

        #. ``Output1[t-3]``

        #. ``Output1[t-5]``

        #. ``Output3[t-1]``

        #. ``Argument1``

        #. ``Argument2``

        ``non_sequences``列表也可以包括shared参数,

       但是scan通常直接忽略他们。

        为了方便理解,我们通常显示的把shraed变量传给 scan

        ``scan`` 也可以计算出其他的``non sequences`` (非 shared)

        即使他们没有被传给scan (但被`fn`使用). 如下所示:

        .. code-block:: python

            #是2还是W?

            import theano.tensor as TT

            W   = TT.matrix()

            W_2 = W**2

            def f(x):

                return TT.dot(x,W_2)

        这个函数做了两件事,首先它给出了

        一个ouputs list,其顺序和output_info一致,

        区别在在于对每一个output initial state,只有一

        个output 变量(即使没有是使用tap value),第二,

        `应该返回一个update 字典(定义来怎样在每一

        u次迭代后更新shared变量)。shared 变量可以定义为

        一个元组构成的列表。对这两个列表的顺序并没有

        过多的限制。’fn‘可以返回``(outputs_list, update_dictionary)`` 

        或者仅仅是其中的一个

        

    sequences

        ``sequences`` 是一个theano变量或者字典,它描述了

        进行迭代的对象。如果一个序列是以字典的

        形式给出的,那么会有以下可选的参数信息

        

        

        * ``input`` (*mandatory*) -- 代表了输入序列

          

        * ``taps`` -- 代表本次输入使用来第k个输入

           默,例如[-2,-1]代表使用了x[t-2]和x[t-1],默认值为0,

        

    outputs_info

        ``outputs_info`` 代表了每次outputs的初始状态

        当初始状态为字典时,有以下可选信息

        

        keys:

        * ``initial`` -- 代表了给定output的初始状态

          如果output是循环计算,并且不需要初始

          状态的话,可以忽略。假设fn只用了上一次

         输出,那么初始状态应该和output的形式

          相同,并且不应该对output进行向下的类型

         转换。如果使用了多个time taps,初始

          状态应该包括所以的可能的taps.例如,

         如果使用-5,-2,-1作为past taps,在step0,fn

          应该使用``output[-5]``,``output[-2]`` 和 ``output[-1]``

       作为初始状态

          

* ``taps`` -- 传给fn的output的tap


        ``scan`` 满足下列规则:

        *如果output不是一个字典,那么‘scan’默认你总是使用最后一步输出

         (即 tap=-1)

      

        * 如果你将output放在一个字典里面,提供了初始状态但不提供任何的taps

           那么默认使用tap=-1

          

        * 如果你将output方在一个字典里面,但不提供初始状态,

          默认不使用taps

         

        * 如果使用一个空的字典或者None,默认不使用taps

          

          

        如果``outputs_info`` 是空列表或者None,默认所有的ouputs不使用taps.

        如果只对output的子集提供某些信息,那么将发生错误(因为没有规定如何

        将提供的信息传递给scan

        

    non_sequences

        ``non_sequences`` 描述了非序列的输入(参数),它的值传给fn后面的参数,且每次迭代的A都是不变的。

    n_steps

        ``n_steps`` 迭代次数

   

    返回

    -------

    元组


        outputs, updates)形式的元组或者一个列表

       列表中是scan的输出(和outputs_info)顺序一致

        

        ``updates`` 是一个字典的子集,规定了所有shared变量更新的规则

         在编译的的时候,这个字典将被传递给theano.function

程序示例

import theano
import theano.tensor as T

k = T.iscalar("k")
A = T.vector("A")

# Symbolic description of the result
result, updates = theano.scan(fn=lambda prior_result, A: prior_result * A,
outputs_info=T.ones_like(A),
non_sequences=A,
n_steps=k)

# We only care about A**k, but scan has provided us with A**1 through A**k.
# Discard the values that we don't care about. Scan is smart enough to
# notice this and not waste memory saving them.
final_result = result[-1]

# compiled function that returns A**k
power = theano.function(inputs=[A,k], outputs=final_result, updates=updates)

print(power(range(10),2))
print(power(range(10),4))


结果

[  0.   1.   4.   9.  16.  25.  36.  49.  64.  81.]
[  0.00000000e+00   1.00000000e+00   1.60000000e+01   8.10000000e+01
2.56000000e+02   6.25000000e+02   1.29600000e+03   2.40100000e+03
4.09600000e+03   6.56100000e+03]


        上面程序中 fn是一个匿名函数 给定prior_result 和A 返,回 prior_result * A.参数的顺序是固定的,我们可以看到此时由于output不是一个字典,所以我们默认使用上一步的输出(taps=-1),然后才是所有的non_sequences,即prior_result=outputs[-1],A=non_sequences.

        然后我们初始化output为A和一样的大小,和dtype,所有元素的值为1。

         第1步,初始化output=[1,1,1,1,1,1,1,1,1,1]

                      [1,1,1,1,1,1,1,1,1,1]*[0,1,2,3,4,5,6,7,8,9]=[0,1,2,3,4,5,6,7,8,9]

          第2步[0,1,2,3,4,5,6,7,8,9]*[0,1,2,3,4,5,6,7,8,9]=  【0.   1.   4.   9.  16.  25.  36.  49.  64.  81.]

import numpy

coefficients = theano.tensor.vector("coefficients")
x = T.scalar("x")

max_coefficients_supported = 10000

# Generate the components of the polynomial
components, updates = theano.scan(fn=lambda coefficient, power, free_variable: coefficient * (free_variable ** power),
outputs_info=None,
sequences=[coefficients, theano.tensor.arange(max_coefficients_supported)],
non_sequences=x)
# Sum them up
polynomial = components.sum()

# Compile a function
calculate_polynomial = theano.function(inputs=[coefficients, x], outputs=polynomial)

# Test
test_coefficients = numpy.asarray([1, 0, 2], dtype=numpy.float32)
test_value = 3
print(calculate_polynomial(test_coefficients, test_value))
print(1.0 * (3 ** 0) + 0.0 * (3 ** 1) + 2.0 * (3 ** 2))


19.0
19.0


fn   为lambda函数 coefficient * (free_variable ** power)
根据 scan中参数的默认顺序 test_coefficients=[1, 0, 2] 和 是第一个sequences ,arange(max_coefficients_supported)是第二个sequences,test——value=3 是non_sequences

import numpy as np
import theano
import theano.tensor as T

up_to = T.iscalar("up_to")

# define a named function, rather than using lambda
def accumulate_by_adding(arange_val, sum_to_date):
return sum_to_date + arange_val
seq = T.arange(up_to)

# An unauthorized implicit downcast from the dtype of 'seq', to that of
# 'T.as_tensor_variable(0)' which is of dtype 'int8' by default would occur
# if this instruction were to be used instead of the next one:
# outputs_info = T.as_tensor_variable(0)

outputs_info = T.as_tensor_variable(np.asarray(0, seq.dtype))
scan_result, scan_updates = theano.scan(fn=accumulate_by_adding,
outputs_info=outputs_info,
sequences=seq)
triangular_sequence = theano.function(inputs=[up_to], outputs=scan_result)

# test
some_num = 15
print(triangular_sequence(some_num))
print([n * (n + 1) // 2 for n in range(some_num)])

[  0   1   3   6  10  15  21  28  36  45  55  66  78  91 105]
[0, 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 66, 78, 91, 105]


fn=accumulate_by_adding
初始化output为T.as_tensor_variable(np.asarray(0, seq.dtype)),即[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]

sequences为[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14]

默认taps=-1,则传给fn的第一个参数为outputs[-1],第二个参数为sequences
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: