为什么这个最小的 RNN 代码会针对从未使用过的类型抛出类型错误?

Why does this minimal RNN code throw a type error for a type never used?

我正在尝试在 theano 中实现一个最小的递归神经网络示例。我希望以下 python 脚本打印一个表示隐藏状态序列的 10×20 矩阵。

# import packages/functions
from theano import shared, scan, function, tensor as T
import numpy as np

# declare variables
X = T.dmatrix("X")
Wx = shared(np.random.uniform(-1.0, 1.0, (10, 20)))
Wh = shared(np.random.uniform(-1.0, 1.0, (20, 20)))
b = shared(np.random.uniform(-1.0, 1.0, (1, 20)))

# define recurrence function
def recurrence(x_t, h_tm1):
    return T.nnet.sigmoid(T.dot(h_tm1, Wh) + T.dot(x_t, Wx) + b)

# compute hidden state sequence with scan
ht, _ = scan(fn = recurrence, sequences = X,
             outputs_info = np.zeros((1, 20)))

# define function producing hidden state sequence
fn = function([X], ht)reshape((1,3))

# test function
print fn(np.eye(10))

相反,它 returns 错误: TypeError: Cannot convert Type TensorType(float64, 3D) (of Variable IncSubtensor{Set;:int64:}.0) into Type TensorType(float64, (False, True, False)). You can try to manually convert IncSubtensor{Set;:int64:}.0 into a TensorType(float64, (False, True, False)).

这特别令人困惑,因为据我所知,我的 none 个变量是 3 张量!

问题代码的代码中存在语法错误:fn = 末尾的 reshape((1,3)) 无效,似乎添加有误。当该行的这个元素被简单删除时,代码就会运行。此答案的其余部分假定编辑是按照问题作者的意图进行的。

我没有重现所述错误。这可能是因为我使用的是 Theano 的最新版本。很有可能在最新版本的代码中更改了针对这种情况的错误消息。然而,上面代码中的语法错误暗示了另一种可能性:问题代码实际上并不是粘贴到问题中产生错误的代码。

使用编辑过的代码和最新版本的 Theano,出现错误

TypeError: ('The following error happened while compiling the node', forall_inplace,cpu,scan_fn}(Shape_i{0}.0, Subtensor{int64:int64:int8}.0, IncSubtensor{InplaceSet;:int64:}.0, , , ), '\n', "Inconsistency in the inner graph of scan 'scan_fn' : an input and an output are associated with the same recurrent state and should have the same type but have type 'TensorType(float64, row)' and 'TensorType(float64, matrix)' respectively.")

这在本质上与问题的错误相似,但指的是矩阵和行向量之间的不匹配;没有提到 3 张量。

避免此错误的最简单更改是更改 b 共享变量的形状。

而不是

b = shared(np.random.uniform(-1.0, 1.0, (1, 20)))

使用

b = shared(np.random.uniform(-1.0, 1.0, (20,)))

我还建议对 h_tm1 的初始值执行相同的操作。

而不是

outputs_info = np.zeros((1, 20))

使用

outputs_info = np.zeros((20,))

问题是因为 theano 将 output_info 包装到不合适的变量中。例如 outputs_info = np.zeros((3, 20)) 将被包装成 TensorType(float64, matrix)。但是对于 dim 等于 1,theano 自动广播 dim,因此 outputs_info = np.zeros((1, 20)) 将是 TensorType(float64, row) 因为第一个 dim 被推断为可广播。

一个解决方案是outputs_info = T.unbroadcast(T.zeros((1,20)), 0)),这确保它包装成矩阵。

# import packages/functions
from theano import shared, scan, function, config, tensor as T
import numpy as np

# declare variables
X = T.tensor3("X")
Wx = shared(np.asarray(np.random.uniform(-1.0, 1.0, (10, 20)), dtype=config.floatX))
Wh = shared(np.asarray(np.random.uniform(-1.0, 1.0, (20, 20)), dtype=config.floatX))
b = shared(np.asarray(np.random.uniform(-1.0, 1.0, (1, 20)), dtype=config.floatX))

# define recurrence function
def recurrence(x_t, h_tm1):
    print h_tm1.type, x_t.type
    return T.nnet.sigmoid(T.dot(h_tm1, Wh) + T.dot(x_t, Wx) + b)

# compute hidden state sequence with scan
ht, _ = scan(fn = recurrence, sequences = X,
             outputs_info = T.unbroadcast(T.zeros((1,20)), 0))

# define function producing hidden state sequence
fn = function([X], ht)

# test function
print fn(np.eye(10,10,dtype=config.floatX).reshape(10,1,10))