`tf.strided_slice()`做什么?

时间:2016-12-29 12:51:40

标签: python tensorflow

我想知道tf.strided_slice()运营商实际上做了什么 doc说,

  

对于第一个顺序,此操作提取大小结束的切片 - 从从begin指定的位置开始的张量输入开始。切片继续向开始索引添加步幅,直到所有维度都不小于结束。请注意,步幅的组成部分可能是负的,这会导致反向切片。

在样本中,

# 'input' is [[[1, 1, 1], [2, 2, 2]],
#             [[3, 3, 3], [4, 4, 4]],
#             [[5, 5, 5], [6, 6, 6]]]
tf.slice(input, [1, 0, 0], [2, 1, 3], [1, 1, 1]) ==> [[[3, 3, 3]]]
tf.slice(input, [1, 0, 0], [2, 2, 3], [1, 1, 1]) ==> [[[3, 3, 3],
                                                       [4, 4, 4]]]
tf.slice(input, [1, 1, 0], [2, -1, 3], [1, -1, 1]) ==>[[[4, 4, 4],
                                                        [3, 3, 3]]]

所以在我对doc的理解中,第一个样本(tf.slice(input, begin=[1, 0, 0], end=[2, 1, 3], strides=[1, 1, 1])),

  • 结果大小为end - begin = [1, 1, 3]。示例结果显示[[[3, 3, 3,]]],该形状为[1, 1, 3],似乎没问题。
  • 结果的第一个元素位于begin = [1, 0, 0]。示例结果的第一个元素是3,即input[1,0,0],似乎没问题。
  • 切片继续向开始索引添加步幅。因此,结果的第二个元素应为input[begin + strides] = input[2, 1, 1] = 6,但示例显示第二个元素为3

strided_slice()做了什么?

(注:method names in the samples and the last example is incorrect。)

5 个答案:

答案 0 :(得分:17)

我用这种方法进行了一些实验,这给了我一些见解,我认为这些见解可能会有所帮助。让我们说我们有一个张量。

a = np.array([[[1, 1.2, 1.3], [2, 2.2, 2.3], [7, 7.2, 7.3]],
              [[3, 3.2, 3.3], [4, 4.2, 4.3], [8, 8.2, 8.3]],
              [[5, 5.2, 5.3], [6, 6.2, 6.3], [9, 9.2, 9.3]]]) 
# a.shape = (3, 3, 3)

strided_slice()需要4个必需参数input_, begin, end, strides,其中我们将a作为input_参数。  与tf.slice()方法的情况一样,begin参数从零开始,其余的args基于形状。 然而,在文档beginend中,两者都是从零开始的

方法的功能很简单:
它的工作方式类似于循环迭代,其中begin是张量中元素的位置,循环开始于此,end是停止的位置。

tf.strided_slice(a, [0, 0, 0], [3, 3, 3], [1, 1, 1])

# output =  the tensor itself

tf.strided_slice(a, [0, 0, 0], [3, 3, 3], [2, 2, 2])

# output = [[[ 1.   1.3]
#            [ 7.   7.3]]
#           [[ 5.   5.3]
#            [ 9.   9.3]]]

strides就像循环迭代的步骤,这里[2,2,2]使方法产生从(0,0,0),(0,0,2),(0, 2,0 {},(0,2,2),(2,0,0),(2,0,2).....在a张量中。

tf.strided_slice(input3, [1, 1, 0], [2, -1, 3], [1, 1, 1]) 

将产生类似于tf.strided_slice(input3, [1, 1, 0], [2, 2, 3], [1, 1, 1])的输出,因为张量a具有shape = (3,3,3)

答案 1 :(得分:11)

The conceptualization that really helped me understand this was that this function emulates the indexing behavior of numpy arrays.

If you're familiar with numpy arrays, you'll know that you can make slices via input[start1:end1:step1, start2:end2:step2, ... startN:endN:stepN]. Basically, a very succinct way of writing for loops to get certain elements of the array.

(If you're familiar with python indexing, you know that you can grab an array slice via input[start:end:step]. Numpy arrays, which may be nested, make use of the above tuple of slice objects.)

Well, strided_slice just allows you to do this fancy indexing without the syntactic sugar. The numpy example from above just becomes

# input[start1:end1:step1, start2:end2:step2, ... startN:endN:stepN]
tf.strided_slice(input, [start1, start2, ..., startN],
    [end1, end2, ..., endN], [step1, step2, ..., stepN])

The documentation is a bit confusing about this in the sense that:

a) begin - end is not strictly the shape of the return value:

The documentation claims otherwise, but this is only true if your strides are all ones. Examples:

rank1 = tf.constant(list(range(10)))
# The below op is basically:
# rank1[1:10:2] => [1, 3, 5, 7, 9]
tf.strided_slice(rank1, [1], [10], [2])

# [10,10] grid of the numbers from 0 to 99
rank2 = tf.constant([[i+j*10 for i in range(10)] for j in range(10)])
# The below op is basically:
# rank2[3:7:1, 5:10:2] => numbers 30 - 69, ending in 5, 7, or 9
sliced = tf.strided_slice(rank2, [3, 5], [7, 10], [1, 2])
# The below op is basically:
# rank2[3:7:1] => numbers 30 - 69
sliced = tf.strided_slice(rank2, [3], [7], [1]) 

b) it states that "begin, end, and strides will be all length n, where n is in general not the same dimensionality as input"

It sounds like dimensionality means rank here - but input does have to be a tensor of at least rank-n; it can't be lower (see rank-2 example above).

N.B. I've said nothing/not really explored the masking feature, but that seems beyond the scope of the question.

答案 2 :(得分:10)

您的论证中的错误是您直接按元素添加列表stridesbegin。这将使该功能不那么有用。相反,它从最后一个维度开始一次增加一个begin列表。

让我们逐个解决第一个例子。 begin = [1, 0, 0]end = [2, 1, 3]。此外,所有strides都是1。从最后一个维度开始向后工作。

从元素[1,0,0]开始。现在仅通过 步幅增加最后一个维度,为您提供[1,0,1]。继续这样做,直到达到极限。像[1,0,2][1,0,3](循环结束)之类的东西。现在,在下一次迭代中,首先将第二个维度递增到最后一个维度并重置最后一个维度[1,1,0]。这里倒数第二个维度等于end[1],所以移到第一个维度(倒数第三个)并重置其余维度,给你[2,0,0]。再次,你处于第一个维度的限制,所以退出循环。

以下代码是我上面描述的递归实现,

# Assume global `begin`, `end` and `stride`
def iterate(active, dim):
    if dim == len(begin):
        # last dimension incremented, work on the new matrix
        # Note that `active` and `begin` are lists
        new_matrix[active - begin] = old_matrix[active]
    else:
        for i in range(begin[dim], end[dim], stride[dim]):
            new_active = copy(active)
            new_active[dim] = i
            iterate(new_active, dim + 1)

iterate(begin, 0)

答案 3 :(得分:2)

tf.strided_slice()用于对张量变量进行numpy样式切片。 它通常有4个参数:input,begin,end,strides。切片继续向开始索引添加stride,直到所有维度都不小于end。例如: 让我们把一个张量常数命名为" sample"尺寸:[3,2,3]

import tensorflow as tf 

sample = tf.constant(
    [[[11, 12, 13], [21, 22, 23]],
    [[31, 32, 33], [41, 42, 43]],
    [[51, 52, 53], [61, 62, 63]]])

slice = tf.strided_slice(sample, begin=[0,0,0], end=[3,2,3], strides=[2,2,2])

with tf.Session() as sess:
    print(sess.run(slice))

现在,输出将是:

[[[11 13]]

 [[51 53]]]

这是因为跨步从[0,0,0]开始并转到[2,1,2],丢弃任何不存在的数据,如:

[[0,0,0], [0,0,2], [0,2,0], [0,2,2],
[2,0,0], [2,0,2], [2,2,0], [2,2,2]]

如果您使用[1,1,1]作为步幅,则只会打印所有值。

答案 4 :(得分:0)

我发现此技术对于调试解决方案很有用。 规则:请始终省略重复模式,并尝试保持步调为(end-1)

t = tf.constant([[[1, 1, 1], [2, 2, 2]],
             [[3, 3, 3], [4, 4, 4]],
             [[5, 5, 5], [6, 6, 6]]])  

# ex 1:
tf.strided_slice(t, [1, 0, 0], [2, 1, 3], [1, 1, 1])

# 3rd position:
1,0,0 > 3     
1,0,1 > 3
1,0,2 > 3
# 2nd and 1st position:satisfies the rule listed above, skipping these.

# ex 2:
tf.strided_slice(t, [1, 0, 0], [2, 2, 3], [1, 1, 1])

# 3rd position:
1,0,0 > 3     
1,0,1 > 3
1,0,2 > 3
# 2nd positon:
1,1,0 > 4
1,1,1 > 4
1,1,2 > 4
# 1st position: satisfies the rule listed above, skipping.

# Ex 3:
tf.strided_slice(t, [1, -1, 0], [2, -3, 3], [1, -1, 1])

# 3rd position:
1,-1,0 > 4
1,-1,1 > 4
1,-1,2 > 4
# 2nd position:
1,-2,0 > 3
1,-2,1 > 3
1,-2,2 > 3
# 1st position:satisfies the rule listed above, skipping.