Introducción al corte de tensor

Ver en TensorFlow.org Ejecutar en Google Colab Ver fuente en GitHub Descargar cuaderno

Cuando se trabaja en aplicaciones de ML como la detección de objetos y la PNL, a veces es necesario trabajar con subsecciones (cortes) de tensores. Por ejemplo, si la arquitectura de su modelo incluye enrutamiento, donde una capa podría controlar qué ejemplo de entrenamiento se enruta a la siguiente capa. En este caso, puede usar operaciones de corte de tensor para dividir los tensores y volver a unirlos en el orden correcto.

En las aplicaciones de PNL, puede utilizar la división de tensor para realizar enmascaramiento de palabras durante el entrenamiento. Por ejemplo, puede generar datos de entrenamiento a partir de una lista de oraciones eligiendo un índice de palabras para enmascarar en cada oración, sacando la palabra como una etiqueta y luego reemplazando la palabra elegida con un símbolo de máscara.

En esta guía, aprenderá a usar las API de TensorFlow para:

  • Extraer rodajas de un tensor
  • Insertar datos en índices específicos en un tensor

Esta guía asume que está familiarizado con la indexación de tensores. Lea las secciones de indexación de los Tensor y TensorFlow NumPy guías antes de empezar con esta guía.

Configuración

import tensorflow as tf
import numpy as np

Extraer cortes de tensor

Realizar NumPy similar a rebanar tensor usando 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)

Alternativamente, puede usar una sintaxis más Pythonic. Tenga en cuenta que los cortes de tensor están espaciados uniformemente en un rango de inicio y fin.

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)

Para tensores bidimensionales, puede usar algo como:

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)

Puede utilizar tf.slice en los tensores de dimensiones superiores también.

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)

También puede utilizar tf.strided_slice a rodajas de extracto de tensores por 'caminando' sobre las dimensiones del tensor.

Utilice tf.gather a los índices extracto específico de un solo eje de un tensor.

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 no requiere índices para estar espaciados de manera uniforme.

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)

Para extraer las rebanadas de varios ejes de un tensor, el uso tf.gather_nd . Esto es útil cuando desea recopilar los elementos de una matriz en lugar de solo sus filas o columnas.

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)

Insertar datos en tensores

Uso tf.scatter_nd para insertar datos en rebanadas / índices específicos de un tensor. Tenga en cuenta que el tensor en el que inserta valores se inicializa en cero.

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)

Métodos como tf.scatter_nd que requieren cero-inicializado tensores son similares a escaso tensor inicializadores. Puede utilizar tf.gather_nd y tf.scatter_nd para imitar el comportamiento de las operaciones tensor dispersos.

Considere un ejemplo en el que construye un tensor disperso utilizando estos dos métodos en conjunto.

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

Esto es similar a:

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)

Para insertar datos en un tensor con los valores pre-existentes, el uso 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)

Del mismo modo, el uso tf.tensor_scatter_nd_sub para restar los valores de un tensor con los valores pre-existentes.

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

Uso tf.tensor_scatter_nd_min para copiar los valores mínimos elemento a elemento de un tensor a otro.

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)

Del mismo modo, el uso tf.tensor_scatter_nd_max para copiar valores máximos elemento a elemento de un tensor a otro.

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)

Más lecturas y recursos

En esta guía, aprendió a usar las operaciones de corte de tensor disponibles con TensorFlow para ejercer un control más preciso sobre los elementos de sus tensores.