Introduction au slicing tensoriel

Voir sur TensorFlow.org Exécuter dans Google Colab Voir la source sur GitHub Télécharger le cahier

Lorsque vous travaillez sur des applications ML telles que la détection d'objets et le NLP, il est parfois nécessaire de travailler avec des sous-sections (tranches) de tenseurs. Par exemple, si l'architecture de votre modèle inclut le routage, une couche peut contrôler quel exemple de formation est acheminé vers la couche suivante. Dans ce cas, vous pouvez utiliser des opérations de découpage de tenseurs pour diviser les tenseurs et les remettre ensemble dans le bon ordre.

Dans les applications NLP, vous pouvez utiliser le découpage du tenseur pour effectuer un masquage de mots pendant l'entraînement. Par exemple, vous pouvez générer des données d'apprentissage à partir d'une liste de phrases en choisissant un index de mots à masquer dans chaque phrase, en retirant le mot comme étiquette, puis en remplaçant le mot choisi par un jeton de masque.

Dans ce guide, vous apprendrez à utiliser les API TensorFlow pour :

  • Extraire des tranches d'un tenseur
  • Insérer des données à des indices spécifiques dans un tenseur

Ce guide suppose une familiarité avec l'indexation du tenseur. Lisez les sections d'indexation des guides Tensor et TensorFlow NumPy avant de commencer avec ce guide.

Installer

import tensorflow as tf
import numpy as np

Extraire des tranches de tenseur

Effectuez un découpage de tenseur de type NumPy à l'aide tf.slice .

t1 = tf.constant([0, 1, 2, 3, 4, 5, 6, 7])

print(tf.slice(t1,
               begin=[1],
               size=[3]))
tf.Tensor([1 2 3], shape=(3,), dtype=int32)

Alternativement, vous pouvez utiliser une syntaxe plus Pythonique. Notez que les tranches de tenseur sont régulièrement espacées sur une plage start-stop.

print(t1[1:4])
tf.Tensor([1 2 3], shape=(3,), dtype=int32)

print(t1[-3:])
tf.Tensor([5 6 7], shape=(3,), dtype=int32)

Pour les tenseurs bidimensionnels, vous pouvez utiliser quelque chose comme :

t2 = tf.constant([[0, 1, 2, 3, 4],
                  [5, 6, 7, 8, 9],
                  [10, 11, 12, 13, 14],
                  [15, 16, 17, 18, 19]])

print(t2[:-1, 1:3])
tf.Tensor(
[[ 1  2]
 [ 6  7]
 [11 12]], shape=(3, 2), dtype=int32)

Vous pouvez également utiliser tf.slice sur des tenseurs de dimension supérieure.

t3 = tf.constant([[[1, 3, 5, 7],
                   [9, 11, 13, 15]],
                  [[17, 19, 21, 23],
                   [25, 27, 29, 31]]
                  ])

print(tf.slice(t3,
               begin=[1, 1, 0],
               size=[1, 1, 2]))
tf.Tensor([[[25 27]]], shape=(1, 1, 2), dtype=int32)

Vous pouvez également utiliser tf.strided_slice pour extraire des tranches de tenseurs en 'marquant' sur les dimensions du tenseur.

Utilisez tf.gather pour extraire des indices spécifiques d'un seul axe d'un tenseur.

print(tf.gather(t1,
                indices=[0, 3, 6]))

# This is similar to doing

t1[::3]
tf.Tensor([0 3 6], shape=(3,), dtype=int32)
<tf.Tensor: shape=(3,), dtype=int32, numpy=array([0, 3, 6], dtype=int32)>

tf.gather ne nécessite pas que les indices soient espacés de manière régulière.

alphabet = tf.constant(list('abcdefghijklmnopqrstuvwxyz'))

print(tf.gather(alphabet,
                indices=[2, 0, 19, 18]))
tf.Tensor([b'c' b'a' b't' b's'], shape=(4,), dtype=string)

Pour extraire des tranches de plusieurs axes d'un tenseur, utilisez tf.gather_nd . Ceci est utile lorsque vous souhaitez rassembler les éléments d'une matrice plutôt que ses lignes ou ses colonnes uniquement.

t4 = tf.constant([[0, 5],
                  [1, 6],
                  [2, 7],
                  [3, 8],
                  [4, 9]])

print(tf.gather_nd(t4,
                   indices=[[2], [3], [0]]))
tf.Tensor(
[[2 7]
 [3 8]
 [0 5]], shape=(3, 2), dtype=int32)

t5 = np.reshape(np.arange(18), [2, 3, 3])

print(tf.gather_nd(t5,
                   indices=[[0, 0, 0], [1, 2, 1]]))
tf.Tensor([ 0 16], shape=(2,), dtype=int64)
# Return a list of two matrices

print(tf.gather_nd(t5,
                   indices=[[[0, 0], [0, 2]], [[1, 0], [1, 2]]]))
tf.Tensor(
[[[ 0  1  2]
  [ 6  7  8]]

 [[ 9 10 11]
  [15 16 17]]], shape=(2, 2, 3), dtype=int64)
# Return one matrix

print(tf.gather_nd(t5,
                   indices=[[0, 0], [0, 2], [1, 0], [1, 2]]))
tf.Tensor(
[[ 0  1  2]
 [ 6  7  8]
 [ 9 10 11]
 [15 16 17]], shape=(4, 3), dtype=int64)

Insérer des données dans des tenseurs

Utilisez tf.scatter_nd pour insérer des données à des tranches/indices spécifiques d'un tenseur. Notez que le tenseur dans lequel vous insérez des valeurs est initialisé à zéro.

t6 = tf.constant([10])
indices = tf.constant([[1], [3], [5], [7], [9]])
data = tf.constant([2, 4, 6, 8, 10])

print(tf.scatter_nd(indices=indices,
                    updates=data,
                    shape=t6))
tf.Tensor([ 0  2  0  4  0  6  0  8  0 10], shape=(10,), dtype=int32)

Les méthodes telles que tf.scatter_nd qui nécessitent des tenseurs initialisés à zéro sont similaires aux initialiseurs de tenseurs clairsemés. Vous pouvez utiliser tf.gather_nd et tf.scatter_nd pour imiter le comportement des opérations de tenseur clairsemées.

Prenons un exemple où vous construisez un tenseur creux en utilisant ces deux méthodes en conjonction.

# Gather values from one tensor by specifying indices

new_indices = tf.constant([[0, 2], [2, 1], [3, 3]])
t7 = tf.gather_nd(t2, indices=new_indices)

# Add these values into a new tensor

t8 = tf.scatter_nd(indices=new_indices, updates=t7, shape=tf.constant([4, 5]))

print(t8)
tf.Tensor(
[[ 0  0  2  0  0]
 [ 0  0  0  0  0]
 [ 0 11  0  0  0]
 [ 0  0  0 18  0]], shape=(4, 5), dtype=int32)

Ceci est similaire à :

t9 = tf.SparseTensor(indices=[[0, 2], [2, 1], [3, 3]],
                     values=[2, 11, 18],
                     dense_shape=[4, 5])

print(t9)
SparseTensor(indices=tf.Tensor(
[[0 2]
 [2 1]
 [3 3]], shape=(3, 2), dtype=int64), values=tf.Tensor([ 2 11 18], shape=(3,), dtype=int32), dense_shape=tf.Tensor([4 5], shape=(2,), dtype=int64))
# Convert the sparse tensor into a dense tensor

t10 = tf.sparse.to_dense(t9)

print(t10)
tf.Tensor(
[[ 0  0  2  0  0]
 [ 0  0  0  0  0]
 [ 0 11  0  0  0]
 [ 0  0  0 18  0]], shape=(4, 5), dtype=int32)

Pour insérer des données dans un tenseur avec des valeurs préexistantes, utilisez tf.tensor_scatter_nd_add .

t11 = tf.constant([[2, 7, 0],
                   [9, 0, 1],
                   [0, 3, 8]])

# Convert the tensor into a magic square by inserting numbers at appropriate indices

t12 = tf.tensor_scatter_nd_add(t11,
                               indices=[[0, 2], [1, 1], [2, 0]],
                               updates=[6, 5, 4])

print(t12)
tf.Tensor(
[[2 7 6]
 [9 5 1]
 [4 3 8]], shape=(3, 3), dtype=int32)

De même, utilisez tf.tensor_scatter_nd_sub pour soustraire des valeurs d'un tenseur avec des valeurs préexistantes.

# Convert the tensor into an identity matrix

t13 = tf.tensor_scatter_nd_sub(t11,
                               indices=[[0, 0], [0, 1], [1, 0], [1, 1], [1, 2], [2, 1], [2, 2]],
                               updates=[1, 7, 9, -1, 1, 3, 7])

print(t13)
tf.Tensor(
[[1 0 0]
 [0 1 0]
 [0 0 1]], shape=(3, 3), dtype=int32)

Utilisez tf.tensor_scatter_nd_min pour copier les valeurs minimales par élément d'un tenseur à un autre.

t14 = tf.constant([[-2, -7, 0],
                   [-9, 0, 1],
                   [0, -3, -8]])

t15 = tf.tensor_scatter_nd_min(t14,
                               indices=[[0, 2], [1, 1], [2, 0]],
                               updates=[-6, -5, -4])

print(t15)
tf.Tensor(
[[-2 -7 -6]
 [-9 -5  1]
 [-4 -3 -8]], shape=(3, 3), dtype=int32)

De même, utilisez tf.tensor_scatter_nd_max pour copier les valeurs maximales par élément d'un tenseur à un autre.

t16 = tf.tensor_scatter_nd_max(t14,
                               indices=[[0, 2], [1, 1], [2, 0]],
                               updates=[6, 5, 4])

print(t16)
tf.Tensor(
[[-2 -7  6]
 [-9  5  1]
 [ 4 -3 -8]], shape=(3, 3), dtype=int32)

Lectures complémentaires et ressources

Dans ce guide, vous avez appris à utiliser les opérations de découpage des tenseurs disponibles avec TensorFlow pour exercer un contrôle plus précis sur les éléments de vos tenseurs.