在theano中扫描不同维度的张量
Scanning over different dimensions of tensors in theano
我正在 theano
迈出我的第一步,但我不知道如何解决这个实际上可能非常简单的问题。
我有一个 3 * 4 * 2
张量,如下所示:
[1 1] | [2 2] | [3 3]
[1 1] | [2 2] | [3 3]
[0 0] | [2 2] | [3 3]
[9 9] | [0 0] | [3 3]
所以我有 N=3
个序列,每个序列的长度为 L=4
,其元素是维度为 d=2
的向量。实际上,序列可以有不同的长度,但我可以考虑用 [0 0]
向量填充它们,如上所示。
我想做的是,首先扫描张量的第一个轴,然后对列表中的所有向量求和直到第一个 [0 0] 向量 -- 这就是为什么我在第一个张量切片的末尾添加了 [9 9],以检查总和退出条件 [1]。我应该在 [[2 2], [6 6], [12 12]]
结束。我尝试了很多方法来解决这个问题,在我看来 只是 一个嵌套循环问题...但总是会出现一些奇怪的错误 [2]。
谢谢,
朱利奥
--
[1]:实际问题是为 NLP 目的训练循环神经网络,N
批次的维度,L
批次中句子的最大长度和 d
每个单词表示的维度。我省略了这个问题,以便我可以专注于最简单的编码方面。
[2] 我省略了失败的历史,也许我可以稍后添加。
如果你的序列总是零填充那么你可以沿着感兴趣的轴求和,因为填充区域不会改变总和。但是,如果填充区域可能包含非零值,则有两种方法。
- 使用扫描。这很慢,应尽可能避免。事实上它是可以避免的,因为,
- 创建二进制掩码并乘以填充区域。
下面是一些说明这三种方法的代码。对于允许非零填充区域(v2
和 v3
)的两种方法,计算需要额外的输入:一个向量,给出批次内序列的长度。
import numpy
import theano
import theano.tensor as tt
def v1():
# NOTE: [9, 9] element changed to [0, 0]
# since zero padding must be used for
# this method
x_data = [[[1, 1], [1, 1], [0, 0], [0, 0]],
[[2, 2], [2, 2], [2, 2], [0, 0]],
[[3, 3], [3, 3], [3, 3], [3, 3]]]
x = tt.tensor3()
x.tag.test_value = x_data
y = x.sum(axis=1)
f = theano.function([x], outputs=y)
print f(x_data)
def v2_step(i_t, s_tm1, x, l):
in_sequence = tt.lt(i_t, l).dimshuffle(0, 'x')
s_t = s_tm1 + tt.switch(in_sequence, x[i_t], 0)
return s_t
def v2():
x_data = [[[1, 1], [1, 1], [0, 0], [9, 9]],
[[2, 2], [2, 2], [2, 2], [0, 0]],
[[3, 3], [3, 3], [3, 3], [3, 3]]]
l_data = [2, 3, 4]
x = tt.tensor3()
x.tag.test_value = x_data
l = tt.lvector()
l.tag.test_value = l_data
# Must dimshuffle first because scan can only iterate over first (0'th) axis.
x_hat = x.dimshuffle(1, 0, 2)
y, _ = theano.scan(v2_step, sequences=[tt.arange(x_hat.shape[0])],
outputs_info=[tt.zeros_like(x_hat[0])],
non_sequences=[x_hat, l], strict=True)
f = theano.function([x, l], outputs=y[-1])
print f(x_data, l_data)
def v3():
x_data = [[[1, 1], [1, 1], [0, 0], [9, 9]],
[[2, 2], [2, 2], [2, 2], [0, 0]],
[[3, 3], [3, 3], [3, 3], [3, 3]]]
l_data = [2, 3, 4]
x = tt.tensor3()
x.tag.test_value = x_data
l = tt.lvector()
l.tag.test_value = l_data
indexes = tt.arange(x.shape[1]).dimshuffle('x', 0)
mask = tt.lt(indexes, l.dimshuffle(0, 'x')).dimshuffle(0, 1, 'x')
y = (mask * x).sum(axis=1)
f = theano.function([x, l], outputs=y)
print f(x_data, l_data)
def main():
theano.config.compute_test_value = 'raise'
v1()
v2()
v3()
main()
一般来说,如果您的步进函数依赖于上一步的输出,那么您需要使用 scan
。
如果每个 step/iteration 原则上都可以并发执行(即它们根本不相互依赖),那么通常有一种更有效的方法可以不使用 scan
我正在 theano
迈出我的第一步,但我不知道如何解决这个实际上可能非常简单的问题。
我有一个 3 * 4 * 2
张量,如下所示:
[1 1] | [2 2] | [3 3]
[1 1] | [2 2] | [3 3]
[0 0] | [2 2] | [3 3]
[9 9] | [0 0] | [3 3]
所以我有 N=3
个序列,每个序列的长度为 L=4
,其元素是维度为 d=2
的向量。实际上,序列可以有不同的长度,但我可以考虑用 [0 0]
向量填充它们,如上所示。
我想做的是,首先扫描张量的第一个轴,然后对列表中的所有向量求和直到第一个 [0 0] 向量 -- 这就是为什么我在第一个张量切片的末尾添加了 [9 9],以检查总和退出条件 [1]。我应该在 [[2 2], [6 6], [12 12]]
结束。我尝试了很多方法来解决这个问题,在我看来 只是 一个嵌套循环问题...但总是会出现一些奇怪的错误 [2]。
谢谢,
朱利奥
--
[1]:实际问题是为 NLP 目的训练循环神经网络,N
批次的维度,L
批次中句子的最大长度和 d
每个单词表示的维度。我省略了这个问题,以便我可以专注于最简单的编码方面。
[2] 我省略了失败的历史,也许我可以稍后添加。
如果你的序列总是零填充那么你可以沿着感兴趣的轴求和,因为填充区域不会改变总和。但是,如果填充区域可能包含非零值,则有两种方法。
- 使用扫描。这很慢,应尽可能避免。事实上它是可以避免的,因为,
- 创建二进制掩码并乘以填充区域。
下面是一些说明这三种方法的代码。对于允许非零填充区域(v2
和 v3
)的两种方法,计算需要额外的输入:一个向量,给出批次内序列的长度。
import numpy
import theano
import theano.tensor as tt
def v1():
# NOTE: [9, 9] element changed to [0, 0]
# since zero padding must be used for
# this method
x_data = [[[1, 1], [1, 1], [0, 0], [0, 0]],
[[2, 2], [2, 2], [2, 2], [0, 0]],
[[3, 3], [3, 3], [3, 3], [3, 3]]]
x = tt.tensor3()
x.tag.test_value = x_data
y = x.sum(axis=1)
f = theano.function([x], outputs=y)
print f(x_data)
def v2_step(i_t, s_tm1, x, l):
in_sequence = tt.lt(i_t, l).dimshuffle(0, 'x')
s_t = s_tm1 + tt.switch(in_sequence, x[i_t], 0)
return s_t
def v2():
x_data = [[[1, 1], [1, 1], [0, 0], [9, 9]],
[[2, 2], [2, 2], [2, 2], [0, 0]],
[[3, 3], [3, 3], [3, 3], [3, 3]]]
l_data = [2, 3, 4]
x = tt.tensor3()
x.tag.test_value = x_data
l = tt.lvector()
l.tag.test_value = l_data
# Must dimshuffle first because scan can only iterate over first (0'th) axis.
x_hat = x.dimshuffle(1, 0, 2)
y, _ = theano.scan(v2_step, sequences=[tt.arange(x_hat.shape[0])],
outputs_info=[tt.zeros_like(x_hat[0])],
non_sequences=[x_hat, l], strict=True)
f = theano.function([x, l], outputs=y[-1])
print f(x_data, l_data)
def v3():
x_data = [[[1, 1], [1, 1], [0, 0], [9, 9]],
[[2, 2], [2, 2], [2, 2], [0, 0]],
[[3, 3], [3, 3], [3, 3], [3, 3]]]
l_data = [2, 3, 4]
x = tt.tensor3()
x.tag.test_value = x_data
l = tt.lvector()
l.tag.test_value = l_data
indexes = tt.arange(x.shape[1]).dimshuffle('x', 0)
mask = tt.lt(indexes, l.dimshuffle(0, 'x')).dimshuffle(0, 1, 'x')
y = (mask * x).sum(axis=1)
f = theano.function([x, l], outputs=y)
print f(x_data, l_data)
def main():
theano.config.compute_test_value = 'raise'
v1()
v2()
v3()
main()
一般来说,如果您的步进函数依赖于上一步的输出,那么您需要使用 scan
。
如果每个 step/iteration 原则上都可以并发执行(即它们根本不相互依赖),那么通常有一种更有效的方法可以不使用 scan