Conceptos básicos de personalización: tensores y operaciones

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

Este es un tutorial introductorio de TensorFlow que muestra cómo:

  • Importar el paquete requerido
  • Crear y usar tensores
  • Usar aceleración de GPU
  • Demostrar tf.data.Dataset

Importar TensorFlow

Para comenzar, importe el módulo tensorflow . A partir de TensorFlow 2, la ejecución ansiosa está activada de forma predeterminada. Esto permite una interfaz más interactiva para TensorFlow, cuyos detalles discutiremos mucho más adelante.

import tensorflow as tf

tensores

Un tensor es una matriz multidimensional. Al igual que los objetos NumPy ndarray , los objetos tf.Tensor tienen un tipo de datos y una forma. Además, tf.Tensor s puede residir en la memoria del acelerador (como una GPU). TensorFlow ofrece una rica biblioteca de operaciones ( tf.add , tf.matmul , tf.linalg.inv , etc.) que consumen y producen tf.Tensor s. Estas operaciones convierten automáticamente los tipos nativos de Python, por ejemplo:

print(tf.add(1, 2))
print(tf.add([1, 2], [3, 4]))
print(tf.square(5))
print(tf.reduce_sum([1, 2, 3]))

# Operator overloading is also supported
print(tf.square(2) + tf.square(3))
tf.Tensor(3, shape=(), dtype=int32)
tf.Tensor([4 6], shape=(2,), dtype=int32)
tf.Tensor(25, shape=(), dtype=int32)
tf.Tensor(6, shape=(), dtype=int32)
tf.Tensor(13, shape=(), dtype=int32)

Cada tf.Tensor tiene una forma y un tipo de datos:

x = tf.matmul([[1]], [[2, 3]])
print(x)
print(x.shape)
print(x.dtype)
tf.Tensor([[2 3]], shape=(1, 2), dtype=int32)
(1, 2)
<dtype: 'int32'>

Las diferencias más obvias entre los arreglos NumPy y los tf.Tensor son:

  1. Los tensores pueden estar respaldados por memoria aceleradora (como GPU, TPU).
  2. Los tensores son inmutables.

Compatibilidad NumPy

Convertir entre un TensorFlow tf.Tensor s y un NumPy ndarray es fácil:

  • Las operaciones de TensorFlow convierten automáticamente NumPy ndarrays en Tensores.
  • Las operaciones NumPy convierten automáticamente los tensores en ndarrays NumPy.

Los tensores se convierten explícitamente en NumPy ndarrays utilizando su método .numpy() . Estas conversiones suelen ser económicas ya que la matriz y tf.Tensor comparten la representación de memoria subyacente, si es posible. Sin embargo, no siempre es posible compartir la representación subyacente, ya que tf.Tensor puede estar alojado en la memoria de la GPU, mientras que las matrices NumPy siempre están respaldadas por la memoria del host, y la conversión implica una copia de la GPU a la memoria del host.

import numpy as np

ndarray = np.ones([3, 3])

print("TensorFlow operations convert numpy arrays to Tensors automatically")
tensor = tf.multiply(ndarray, 42)
print(tensor)


print("And NumPy operations convert Tensors to numpy arrays automatically")
print(np.add(tensor, 1))

print("The .numpy() method explicitly converts a Tensor to a numpy array")
print(tensor.numpy())
TensorFlow operations convert numpy arrays to Tensors automatically
tf.Tensor(
[[42. 42. 42.]
 [42. 42. 42.]
 [42. 42. 42.]], shape=(3, 3), dtype=float64)
And NumPy operations convert Tensors to numpy arrays automatically
[[43. 43. 43.]
 [43. 43. 43.]
 [43. 43. 43.]]
The .numpy() method explicitly converts a Tensor to a numpy array
[[42. 42. 42.]
 [42. 42. 42.]
 [42. 42. 42.]]

Aceleración de GPU

Muchas operaciones de TensorFlow se aceleran mediante la GPU para el cálculo. Sin anotaciones, TensorFlow decide automáticamente si usar la GPU o la CPU para una operación, copiando el tensor entre la memoria de la CPU y la GPU, si es necesario. Los tensores producidos por una operación generalmente están respaldados por la memoria del dispositivo en el que se ejecutó la operación, por ejemplo:

x = tf.random.uniform([3, 3])

print("Is there a GPU available: "),
print(tf.config.list_physical_devices("GPU"))

print("Is the Tensor on GPU #0:  "),
print(x.device.endswith('GPU:0'))
Is there a GPU available: 
[PhysicalDevice(name='/physical_device:GPU:0', device_type='GPU')]
Is the Tensor on GPU #0:  
True

Nombres de dispositivos

La propiedad Tensor.device proporciona un nombre de cadena completamente calificado del dispositivo que aloja el contenido del tensor. Este nombre codifica muchos detalles, como un identificador de la dirección de red del host en el que se ejecuta este programa y el dispositivo dentro de ese host. Esto es necesario para la ejecución distribuida de un programa TensorFlow. La cadena termina con GPU:<N> si el tensor se coloca en la N -ésima GPU en el host.

Colocación explícita de dispositivos

En TensorFlow, la ubicación se refiere a cómo las operaciones individuales se asignan (colocan en) un dispositivo para su ejecución. Como se mencionó, cuando no se proporciona una guía explícita, TensorFlow decide automáticamente en qué dispositivo ejecutar una operación y copia los tensores en ese dispositivo, si es necesario. Sin embargo, las operaciones de TensorFlow se pueden colocar explícitamente en dispositivos específicos utilizando el administrador de contexto tf.device , por ejemplo:

import time

def time_matmul(x):
  start = time.time()
  for loop in range(10):
    tf.matmul(x, x)

  result = time.time()-start

  print("10 loops: {:0.2f}ms".format(1000*result))

# Force execution on CPU
print("On CPU:")
with tf.device("CPU:0"):
  x = tf.random.uniform([1000, 1000])
  assert x.device.endswith("CPU:0")
  time_matmul(x)

# Force execution on GPU #0 if available
if tf.config.list_physical_devices("GPU"):
  print("On GPU:")
  with tf.device("GPU:0"): # Or GPU:1 for the 2nd GPU, GPU:2 for the 3rd etc.
    x = tf.random.uniform([1000, 1000])
    assert x.device.endswith("GPU:0")
    time_matmul(x)
On CPU:
10 loops: 91.47ms
On GPU:
10 loops: 388.16ms

conjuntos de datos

Esta sección utiliza la API tf.data.Dataset para crear una canalización para alimentar datos a su modelo. La API tf.data.Dataset se utiliza para crear canalizaciones de entrada complejas y de alto rendimiento a partir de piezas simples y reutilizables que alimentarán los bucles de evaluación o entrenamiento de su modelo.

Crear un conjunto de Dataset de origen

Cree un conjunto de datos de origen usando una de las funciones de fábrica como Dataset.from_tensors , Dataset.from_tensor_slices o usando objetos que leen archivos como TextLineDataset o TFRecordDataset . Consulte la guía del conjunto de datos de TensorFlow para obtener más información.

ds_tensors = tf.data.Dataset.from_tensor_slices([1, 2, 3, 4, 5, 6])

# Create a CSV file
import tempfile
_, filename = tempfile.mkstemp()

with open(filename, 'w') as f:
  f.write("""Line 1
Line 2
Line 3
  """)

ds_file = tf.data.TextLineDataset(filename)

Aplicar transformaciones

Utilice las funciones de transformación como map , batch y shuffle para aplicar transformaciones a registros de conjuntos de datos.

ds_tensors = ds_tensors.map(tf.square).shuffle(2).batch(2)

ds_file = ds_file.batch(2)

Iterar

Los objetos tf.data.Dataset admiten la iteración para recorrer los registros:

print('Elements of ds_tensors:')
for x in ds_tensors:
  print(x)

print('\nElements in ds_file:')
for x in ds_file:
  print(x)
Elements of ds_tensors:
tf.Tensor([1 9], shape=(2,), dtype=int32)
tf.Tensor([16  4], shape=(2,), dtype=int32)
tf.Tensor([25 36], shape=(2,), dtype=int32)

Elements in ds_file:
tf.Tensor([b'Line 1' b'Line 2'], shape=(2,), dtype=string)
tf.Tensor([b'Line 3' b'  '], shape=(2,), dtype=string)