web-dev-qa-db-fra.com

Que fait tf.strided_slice ()?

Je me demande ce que fait réellement l'opérateur tf.strided_slice().
Le doc dit,

Pour une première commande, cette opération extrait une tranche de taille end-begin à partir d'une entrée tenseur commençant à l'emplacement spécifié par begin. La tranche continue en ajoutant une foulée à l'index de début jusqu'à ce que toutes les dimensions ne soient pas inférieures à la fin. Notez que les composants de stride peuvent être négatifs, ce qui provoque une tranche inversée.

Et dans l'échantillon, 

# '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]]]

Donc, dans ma compréhension de la doc, le premier échantillon (tf.slice(input, begin=[1, 0, 0], end=[2, 1, 3], strides=[1, 1, 1])),

  • la taille résultante est end - begin = [1, 1, 3]. L'exemple de résultat montre [[[3, 3, 3,]]], cette forme est [1, 1, 3], cela semble correct.
  • le premier élément du résultat est à begin = [1, 0, 0]. Le premier élément de l'exemple de résultat est 3, qui est input[1,0,0], cela semble correct.
  • la tranche continue en ajoutant stride à l'index de début. Donc, le deuxième élément du résultat devrait être input[begin + strides] = input[2, 1, 1] = 6, mais l'exemple montre que le deuxième élément est 3.

Quel strided_slice() fait?

(Remarque: les noms de méthodes dans les exemples et le dernier exemple est incorrect .)

16
keisuke

L'erreur dans votre argument est le fait que vous ajoutez directement les listes strides et begin élément par élément. Cela rendra la fonction beaucoup moins utile. Au lieu de cela, il incrémente la liste begin d'une dimension à la fois, à partir de la dernière dimension.

Résouvons le premier exemple partie par partie. begin = [1, 0, 0] et end = [2, 1, 3]. De plus, tous les strides sont 1. Travaillez en arrière, de la dernière dimension.

Commencez avec l'élément [1,0,0]. Maintenant n'augmente la dernière dimension que de sa quantité de foulée, ce qui vous donne [1,0,1]. Continuez comme cela jusqu'à ce que vous atteigniez la limite. Quelque chose comme [1,0,2], [1,0,3] (fin de la boucle). Dans votre prochaine itération, commencez par incrémenter l'avant-dernière dimension et réinitialisez la dernière dimension, [1,1,0]. Ici, l'avant dernière dimension est égale à end[1], passez donc à la première dimension (troisième avant dernière) et réinitialisez le reste en vous donnant [2,0,0] Encore une fois, vous êtes à la limite de la première dimension, alors quittez la boucle.

Le code suivant est une implémentation récursive de ce que j'ai décrit ci-dessus,

# 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)
9
martianwars

J'ai un peu expérimenté cette méthode, ce qui m'a permis de mieux comprendre ce que je pense. Disons que nous avons un tenseur. 

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() nécessite 4 arguments obligatoires input_, begin, end, strides dans lesquels nous donnons notre a sous la forme input_ argument . Comme dans le cas de la méthode tf.slice(), l'argument begin est basé sur zéro et le reste des arguments est basé sur la forme. Cependant, dans les documents begin et end, les deux sont basés sur zéro .

La fonctionnalité de la méthode est assez simple: 
Cela fonctionne comme une itération sur une boucle, où begin est l'emplacement de l'élément dans le tenseur d'où la boucle commence et end est l'endroit où elle s'arrête. 

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 sont comme des étapes sur lesquelles la boucle itère, ici le [2,2,2] crée une méthode pour produire des valeurs commençant à (0,0,0), (0,0,2), (0,2,0), (0,2,2 ), (2,0,0), (2,0,2) ..... dans le tenseur a.

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

produira une sortie similaire à tf.strided_slice(input3, [1, 1, 0], [2, 2, 3], [1, 1, 1]) étant donné que la variable tensora a shape = (3,3,3)

17
Deepank

La conceptualisation qui m'a vraiment aidé à comprendre cela est que cette fonction émule le comportement d'indexation des tableaux numpy.

Si vous êtes familier avec les tableaux numpy, vous saurez que vous pouvez créer des tranches via input[start1:end1:step1, start2:end2:step2, ... startN:endN:stepN]. En gros, une manière très succincte d’écrire des boucles for pour obtenir certains éléments du tableau.

(Si vous connaissez bien l'indexation python, vous savez que vous pouvez récupérer une découpe de tableau via input[start:end:step]. Les tableaux Numpy, qui peuvent être imbriqués, utilisez le tuple d'objets de slice ci-dessus.)

strided_slice vous permet simplement de faire cette indexation sophistiquée sans le sucre syntaxique. L'exemple numpy ci-dessus devient juste

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

La documentation est un peu déroutante à ce sujet en ce sens que:

a) begin - end n'est pas strictement la forme de la valeur de retour :

La documentation prétend le contraire, mais cela n’est vrai que si vos progrès sont tous identiques ..___. Exemples:

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) il est indiqué que "begin, end, et strides seront de longueur n, où n est généralement pas la même dimensionnalité que input"

Cela ressemble à de la dimensionnalité signifie rang ici - mais inputne doit être un tenseur d'au moins rang-n; il ne peut pas être inférieur (voir l'exemple de rang 2 ci-dessus).

N.B. Je n'ai rien dit/pas vraiment exploré la fonctionnalité de masquage, mais cela semble sortir du cadre de la question.

10
jagthebeetle

tf.strided_slice () est utilisé pour découper dans le style numpy d’une variable tenseur . Il a 4 paramètres en général: input, begin, end, strides.La tranche continue en ajoutant stride à l’index de début jusqu’à ce que toutes les dimensions moins que la fin. Par exemple: Prenons une constante de tenseur nommée "échantillon" de dimensions: [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))

Maintenant, le résultat sera:

[[[11 13]]

 [[51 53]]]

En effet, la foulée commence à partir de [0,0,0] et va à [2,1,2] en supprimant les données inexistantes telles que:

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

Si vous utilisez [1,1,1] comme des pas, il affichera simplement toutes les valeurs.

2
Aman pradhan

Je trouve cette technique utile pour déboguer la solution . Règle: omettez toujours les modèles récurrents et essayez de garder step à (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.
0
kiran