将python循环翻译成Theano

时间:2018-08-10 18:09:25

标签: python numpy theano theano.scan

我想使用以下公式将P个元素的n向量转换为Z个元素的n+1向量:

enter image description here

我能够使用以下命令在python中做到这一点

import numpy as np

def p_to_Z(p):
    k = len(p)
    Z = np.zeros(k+1)
    Z[0] = p[0]

    Z[1:k] = [p[i] / (1 - sum(p[range(i)])) for i in range(1,k)]
    Z[-1] = 1
    return Z

示例:

p_ex = np.array([0.3,0.4,0.1,0.2])
p_to_Z(p_ex)
output:
array([ 0.3, 0.57142857, 0.33333333,  1. , 1. ])

以及具有以下条件的矩阵:

M = np.array([[0.2, 0.05, 0.1],
                     [0.5, 2.0, 0.2],
                     [0.1, 0.2, 1.0]])

np.apply_along_axis(p_to_Z, 1, M)

array([[ 0.2 , 0.0625 , 0.13333333, 1.],
       [ 0.5 , 4. ,-0.13333333, 1.],
       [ 0.1 , 0.22222222,  1.42857143, 1.]])

我一直试图将其翻译为theano,但是我一直被scan函数所困扰。 有人可以帮我在theano中定义这些功能吗?我将永远感激不已。

编辑:尝试失败

import theano.tensor as tt
import numpy as np
import theano
from theano.compile.ops import as_op

p = tt.vector('p')
results, updates = theano.scan(lambda i: p[i] / (1 - tt.sum(p[:i-1])), sequences=tt.arange(1,N))
fn = theano.function([p,N],results)

p_ex = np.array([0.3,0.4,0.1,0.2])
Z = fn(p_ex,tt.get_vector_length(p_ex))

并带有装饰器:

@as_op(itypes=[tt.dvector],otypes=[tt.dvector])
def p_to_Z_theno(p):
    N = tt.get_vector_length(p)
    Z= theano.scan(lambda i: p[i] / (1 - tt.sum(p[:i - 1])), sequences=tt.arange(1, N))
    fn = theano.function([p, N], results)
    Z[0]=p[0]
    Z[-1]=Z
    return(Z)

第一个显然不会产生预期的结果,而第二个给出:

Traceback (most recent call last):   File "/usr/lib/python3/dist-packages/IPython/core/interactiveshell.py", line 2882, in run_code
    exec(code_obj, self.user_global_ns, self.user_ns)   File "<ipython-input-21-211efc53b449>", line 1, in <module>
    p_to_Z_theno(p_ex)   File "/usr/local/lib/python3.6/dist-packages/theano/gof/op.py", line 615, in __call__
    node = self.make_node(*inputs, **kwargs)   File "/usr/local/lib/python3.6/dist-packages/theano/gof/op.py", line 983, in make_node
    if not all(inp.type == it for inp, it in zip(inputs, self.itypes)):   File "/usr/local/lib/python3.6/dist-packages/theano/gof/op.py", line 983, in <genexpr>
    if not all(inp.type == it for inp, it in zip(inputs, self.itypes)): AttributeError: 'numpy.ndarray' object has no attribute 'type'

1 个答案:

答案 0 :(得分:1)

让我们从向量化操作的角度开始思考。如果我们使用numpy的cumsum函数,则您的初始方程式可以非常简单地写成:

def p2Z_numpy(p):
    Z = np.r_[p, 1]
    Z[1:-1] /= np.cumsum(p[:-1])
    return Z

例如:

>>> p2Z_numpy([0.3, 0.4, 0.1, 0.2])
array([0.3       , 1.33333333, 0.14285714, 0.25      , 1.        ])

之所以重要,是因为Theano可以进行所有相同种类的操作,但是规模更大。因此,让我们在Theano中进行相同的除法,串联和累加总和:

import theano.tensor as tt
import theano.tensor.extra_ops as te
from theano import function

p = tt.vector()
denom = 1 - te.cumsum(p[:-1])
frac = p[1:] / denom
Z = tt.concatentat([p[0:1], frac, [1]])

p2Z = function([p], Z)

对其进行测试:

>>> p2Z([0.3, 0.4, 0.1, 0.2])
array([0.3       , 0.57142857, 0.33333333, 1.        , 1.        ])

虽然我已将功能分解为多个步骤,但实际上您可以将其变成一个丑陋的单线代码:

p = tt.vector()
Z = tt.concatenate([p[0:1], p[1:] / (1 - te.cumsum(p[:-1])), [1]])
p2Z = function([p], Z)

甚至

p2Z = function([p], tt.concatenate([p[0:1], p[1:] / (1 - te.cumsum(p[:-1])), [1]]))