Canalizaciones de datos con velocidades de TPU: tf.data.Dataset y TFRecords

1. Descripción general

Las TPU son muy rápidas, y la transmisión de datos de entrenamiento debe mantenerse a la par con su velocidad de entrenamiento. En este lab, aprenderás a cargar datos de GCS con la API de tf.data.Dataset para alimentar tu TPU.

Este lab es la parte 1 de la serie "Keras en TPU". Puedes hacerlo en el siguiente orden o de forma independiente.

ca8cc21f6838eccc.png

Qué aprenderás

  • Usar la API de tf.data.Dataset para cargar datos de entrenamiento
  • Usar el formato TFRecord para cargar datos de entrenamiento de forma eficiente desde GCS

Comentarios

Si ves algo fuera de lugar en este codelab, avísanos. Se pueden proporcionar comentarios a través de los problemas de GitHub [feedback link].

2. Inicio rápido de Google Colaboratory

Este lab usa Google Colaboratory y no requiere configuración de tu parte. Colaboratory es una plataforma de notebooks en línea con fines educativos. Ofrece capacitación gratuita en CPU, GPU y TPU.

688858c21e3beff2.png

Puedes abrir este notebook de muestra y ejecutar algunas celdas para familiarizarte con Colaboratory.

c3df49e90e5a654f.png Welcome to Colab.ipynb

Selecciona un backend de TPU

8832c6208c99687d.png

En el menú de Colab, selecciona Entorno de ejecución > Cambiar tipo de entorno de ejecución y, luego, TPU. En este codelab, usarás una potente TPU (unidad de procesamiento tensorial) respaldada para el entrenamiento acelerado por hardware. La conexión al entorno de ejecución se realizará automáticamente en la primera ejecución, o bien puedes usar el botón “Conectar” de la esquina superior derecha.

Ejecución del notebook

76d05caa8b4db6da.png

Para ejecutar celdas una a la vez, haz clic en una celda y usa Mayúsculas + Intro. También puedes ejecutar todo el notebook con Runtime > Run all.

Índice

429f106990037ec4.png

Todos los notebooks tienen un índice. Puedes abrirlo con la flecha negra que está a la izquierda.

Celdas ocultas

edc3dba45d26f12a.png

Algunas celdas solo mostrarán el título. Esta es una función de notebook específica de Colab. Puedes hacer doble clic en ellos para ver el código que contiene, pero, por lo general, no es muy interesante. Por lo general, las funciones de asistencia o visualización. Aún debes ejecutar estas celdas para que se definan las funciones que contienen.

Autenticación

cdd4b41413100543.png

Colab puede acceder a tus buckets privados de Google Cloud Storage, siempre que te autentiques con una cuenta autorizada. El fragmento de código anterior activará un proceso de autenticación.

3. [INFO] ¿Qué son las unidades de procesamiento tensorial (TPU)?

En resumen

f88cf6facfc70166.png

El código para entrenar un modelo en TPU en Keras (y recurrir a GPU o CPU si no hay una TPU disponible):

try: # detect TPUs
    tpu = tf.distribute.cluster_resolver.TPUClusterResolver.connect()
    strategy = tf.distribute.TPUStrategy(tpu)
except ValueError: # detect GPUs
    strategy = tf.distribute.MirroredStrategy() # for CPU/GPU or multi-GPU machines

# use TPUStrategy scope to define model
with strategy.scope():
  model = tf.keras.Sequential( ... )
  model.compile( ... )

# train model normally on a tf.data.Dataset
model.fit(training_dataset, epochs=EPOCHS, steps_per_epoch=...)

Hoy usaremos TPU para compilar y optimizar un clasificador de flores a velocidades interactivas (minutos por ejecución de entrenamiento).

688858c21e3beff2.png

¿Por qué usar TPU?

Las GPU modernas se organizan en torno a "núcleos" programables, una arquitectura muy flexible que les permite manejar una variedad de tareas, como renderización 3D, aprendizaje profundo, simulaciones físicas, etcétera. Por otro lado, las TPU combinan un procesador vectorial clásico con una unidad de multiplicación de matrices dedicada y se destacan en cualquier tarea en la que predominan las multiplicaciones de matrices grandes, como las redes neuronales.

8eb3e718b8e2ed08.png

Ilustración: una capa de red neuronal densa como una multiplicación de matrices, con un lote de ocho imágenes procesadas a través de la red neuronal a la vez. Ejecuta una multiplicación de una línea por una columna para verificar que realmente se esté realizando una suma ponderada de todos los valores de píxeles de una imagen. Las capas convolucionales también se pueden representar como multiplicaciones de matrices, aunque es un poco más complicado ( más explicación en la sección 1).

El hardware

MXU y VPU

Un núcleo de TPU v2 consta de una unidad de multiplicación de matrices (MXU) que ejecuta multiplicaciones de matrices y una unidad de procesamiento vectorial (VPU) para todas las demás tareas, como activaciones, softmax, etc. La VPU controla los cálculos de float32 y int32. Por otro lado, la MXU opera en un formato de punto flotante de precisión mixta de 16 a 32 bits.

7d68944718f76b18.png

Punto flotante de precisión mixto y bfloat16

La MXU calcula las multiplicaciones de matrices con entradas bfloat16 y salidas float32. Las acumulaciones intermedias se realizan con precisión float32.

19c5fc432840c714.png

Por lo general, el entrenamiento de redes neuronales es resistente al ruido que genera una precisión reducida de punto flotante. En algunos casos, el ruido incluso ayuda a que el optimizador converja. La precisión de punto flotante de 16 bits se ha utilizado tradicionalmente para acelerar los cálculos, pero los formatos float16 y float32 tienen rangos muy diferentes. Reducir la precisión de float32 a float16 suele generar desbordamientos y desbordamientos negativos. Las soluciones existen, pero normalmente se requiere trabajo adicional para que float16 funcione.

Por eso, Google introdujo el formato bfloat16 en las TPU. bfloat16 es un número de punto flotante truncado con exactamente los mismos bits de exponente y rango que el número de punto flotante. Esto, sumado al hecho de que las TPUs calculan multiplicaciones de matrices con precisión mixta con entradas bfloat16, pero salidas float32, significa que, por lo general, no es necesario realizar cambios en el código para beneficiarse de los aumentos de rendimiento de la precisión reducida.

Array sístole

La MXU implementa multiplicaciones de matrices en hardware con una arquitectura llamada "array sistólica" en la que los elementos de datos fluyen a través de un array de unidades de procesamiento de hardware. (En medicina, "sistólica" se refiere a las contracciones cardíacas y al flujo sanguíneo, en este caso, al flujo de datos).

El elemento básico de una multiplicación de matrices es un producto escalar entre una línea de una matriz y una columna de la otra (consulta la ilustración en la parte superior de esta sección). Para una multiplicación de matrices Y=X*W, un elemento del resultado sería el siguiente:

Y[2,0] = X[2,0]*W[0,0] + X[2,1]*W[1,0] + X[2,2]*W[2,0] + ... + X[2,n]*W[n,0]

En una GPU, se programaría este producto punto en un "núcleo" de GPU y, luego, se ejecutaría en tantos "núcleos" como estén disponibles en paralelo para intentar calcular todos los valores de la matriz resultante a la vez. Si la matriz resultante es de 128 × 128, se requerirían 128 × 128 = 16,000 “núcleos” disponibles, lo que, por lo general, no es posible. Las GPUs más grandes tienen alrededor de 4,000 núcleos. Por otro lado, una TPU usa el mínimo de hardware para las unidades de procesamiento en la MXU: solo bfloat16 x bfloat16 => float32 multiplicadores-acumuladores, nada más. Son tan pequeños que una TPU puede implementar 16,000 de ellos en una MXU de 128 x 128 y procesar esta multiplicación de matrices de una sola vez.

f1b283fc45966717.gif

Ilustración: Array sistólico de MXU. Los elementos de procesamiento son multiplicadores y acumuladores. Los valores de una matriz se cargan en el array (puntos rojos). Los valores de la otra matriz fluyen a través del array (puntos grises). Las líneas verticales propagan los valores hacia arriba. Las líneas horizontales propagan las sumas parciales. Se deja como un ejercicio para que el usuario verifique que, a medida que los datos fluyen a través del array, se obtiene el resultado de la multiplicación de matrices que sale del lado derecho.

Además, mientras los productos escalar se calculan en una MXU, las sumas intermedias simplemente fluyen entre unidades de procesamiento adyacentes. No es necesario que se almacenen y recuperen en la memoria o incluso desde un archivo de registro. El resultado final es que la arquitectura del array sistólico de TPU tiene una ventaja de densidad y potencia significativa, además de una ventaja de velocidad no insignificante en comparación con una GPU, cuando se calculan multiplicaciones de matrices.

Cloud TPU

Cuando solicitas una "Cloud TPU v2" en Google Cloud Platform, obtienes una máquina virtual (VM) que tiene una placa TPU conectada a PCI. La placa de TPU tiene cuatro chips TPU de doble núcleo. Cada núcleo de TPU cuenta con una VPU (unidad de procesamiento vectorial) y una MXU (unidad de multiplicación de matrices) de 128 × 128. Por lo general, esta "Cloud TPU" se conecta a través de la red a la VM que la solicitó. Por lo tanto, la imagen completa se ve de la siguiente manera:

dfce5522ed644ece.png

Ilustración: Tu VM con un acelerador "Cloud TPU" conectado a la red. "La Cloud TPU" en sí está compuesta por una VM con una placa de TPU conectada a PCI con cuatro chips de TPU de doble núcleo.

Pods de TPU

En los centros de datos de Google, las TPU se conectan a una interconexión de procesamiento de alto rendimiento (HPC), lo que puede hacer que aparezcan como un acelerador muy grande. Google los llama pods y pueden abarcar hasta 512 núcleos TPU v2 o 2,048 núcleos TPU v3.

2ec1e0d341e7fc34.jpeg

Ilustración: un pod de TPU v3. Placas y bastidores de TPU conectados a través de una interconexión de HPC.

Durante el entrenamiento, los gradientes se intercambian entre los núcleos de TPU con el algoritmo de reducción total (aquí hay una buena explicación de la reducción total). El modelo que se está entrenando puede aprovechar el hardware entrenando con tamaños de lotes grandes.

d97b9cc5d40fdb1d.gif

Ilustración: sincronización de gradientes durante el entrenamiento con el algoritmo de reducción total en la red HPC de malla toroidal 2D de Google TPU.

El software

Capacitación con un tamaño de lote grande

El tamaño de lote ideal para las TPU es de 128 elementos de datos por núcleo de TPU, pero el hardware ya puede mostrar un buen uso de 8 elementos de datos por núcleo de TPU. Recuerda que una Cloud TPU tiene 8 núcleos.

En este codelab, usaremos la API de Keras. En Keras, el lote que especificas es el tamaño de lote global para toda la TPU. Tus lotes se dividirán automáticamente en 8 y se ejecutarán en los 8 núcleos de la TPU.

da534407825f01e3.png

Para obtener más sugerencias de rendimiento, consulta la Guía de rendimiento de TPU. Para tamaños de lotes muy grandes, es posible que se deba tener especial cuidado en algunos modelos. Consulta LARSOptimizer para obtener más detalles.

Detrás de escena: XLA

Los programas de TensorFlow definen grafos de procesamiento. La TPU no ejecuta directamente el código de Python, sino el grafo de procesamiento definido por tu programa de TensorFlow. En el fondo, un compilador llamado XLA (compilador de álgebra lineal acelerada) transforma el grafo de nodos de procesamiento de TensorFlow en código máquina de TPU. Este compilador también realiza muchas optimizaciones avanzadas en tu código y en el diseño de la memoria. La compilación se realiza automáticamente a medida que el trabajo se envía a la TPU. No tienes que incluir XLA en tu cadena de compilación de forma explícita.

edce61112cd57972.png

Ilustración: Para ejecutarse en TPU, el grafo de procesamiento definido por tu programa de TensorFlow primero se traduce a una representación de XLA (compilador de álgebra lineal acelerada) y, luego, XLA lo compila en código máquina de TPU.

Cómo usar TPUs en Keras

A partir de TensorFlow 2.1, las TPU son compatibles con la API de Keras. La compatibilidad con Keras funciona en TPU y pods de TPU. A continuación, te mostramos un ejemplo que funciona con TPU, GPU y CPU:

try: # detect TPUs
    tpu = tf.distribute.cluster_resolver.TPUClusterResolver.connect()
    strategy = tf.distribute.TPUStrategy(tpu)
except ValueError: # detect GPUs
    strategy = tf.distribute.MirroredStrategy() # for CPU/GPU or multi-GPU machines

# use TPUStrategy scope to define model
with strategy.scope():
  model = tf.keras.Sequential( ... )
  model.compile( ... )

# train model normally on a tf.data.Dataset
model.fit(training_dataset, epochs=EPOCHS, steps_per_epoch=...)

En este fragmento de código:

  • TPUClusterResolver().connect() encuentra la TPU en la red. Funciona sin parámetros en la mayoría de los sistemas de Google Cloud (trabajos de AI Platform, Colaboratory, Kubeflow y VMs de aprendizaje profundo creadas a través de la utilidad "TextView up"). Estos sistemas saben dónde está su TPU gracias a una variable de entorno TPU_NAME. Si creas una TPU de forma manual, configura la variable de entorno TPU_NAME en la VM desde la que la estás usando o llama a TPUClusterResolver con parámetros explícitos: TPUClusterResolver(tp_uname, zone, project)
  • TPUStrategy es la parte que implementa la distribución y el algoritmo de sincronización de gradientes “all-reduce”.
  • La estrategia se aplica a través de un alcance. El modelo se debe definir dentro del alcance de la estrategia().
  • La función tpu_model.fit espera un objeto tf.data.Dataset como entrada para el entrenamiento de TPU.

Tareas comunes de portabilidad de TPU

  • Si bien hay muchas formas de cargar datos en un modelo de TensorFlow, para las TPU, se requiere el uso de la API de tf.data.Dataset.
  • Las TPU son muy rápidas y, a menudo, la transferencia de datos se convierte en el cuello de botella cuando se ejecutan en ellas. En la Guía de rendimiento de TPU, encontrarás herramientas que puedes usar para detectar cuellos de botella de datos y otras sugerencias de rendimiento.
  • Los números int8 o int16 se tratan como int32. La TPU no tiene hardware de números enteros que funcione en menos de 32 bits.
  • Algunas operaciones de TensorFlow no son compatibles. Consulta la lista aquí. La buena noticia es que esta limitación solo se aplica al código de entrenamiento, es decir, la propagación hacia adelante y atrás en el modelo. Puedes seguir usando todas las operaciones de TensorFlow en tu canalización de entrada de datos, ya que se ejecutará en la CPU.
  • tf.py_func no es compatible con TPU.

4. Cargar datos

c0ecb860e4cad0a9.jpeg cc4781a7739c49ae.jpeg 81236b00f8bbf39e.jpeg 961e2228974076bb.jpeg 7517dc163bdffcd5.jpeg 96392df4767f566d.png

Trabajaremos con un conjunto de datos de imágenes de flores. El objetivo es aprender a categorizarlas en 5 tipos de flores. La carga de datos se realiza con la API de tf.data.Dataset. Primero, conozcamos la API.

Práctica

Abre el siguiente notebook, ejecuta las celdas (Mayúsculas + Intro) y sigue las instrucciones donde veas la etiqueta “TRABAJO NECESARIO”.

c3df49e90e5a654f.png Fun with tf.data.Dataset (playground).ipynb

Información adicional

Acerca del conjunto de datos "flores"

El conjunto de datos está organizado en 5 carpetas. Cada carpeta contiene un tipo de flores. Las carpetas se llaman girasoles, margaritas, dientes de león, tulipanes y rosas. Los datos están alojados en un bucket público en Google Cloud Storage. Extracto:

gs://flowers-public/sunflowers/5139971615_434ff8ed8b_n.jpg
gs://flowers-public/daisy/8094774544_35465c1c64.jpg
gs://flowers-public/sunflowers/9309473873_9d62b9082e.jpg
gs://flowers-public/dandelion/19551343954_83bb52f310_m.jpg
gs://flowers-public/dandelion/14199664556_188b37e51e.jpg
gs://flowers-public/tulips/4290566894_c7f061583d_m.jpg
gs://flowers-public/roses/3065719996_c16ecd5551.jpg
gs://flowers-public/dandelion/8168031302_6e36f39d87.jpg
gs://flowers-public/sunflowers/9564240106_0577e919da_n.jpg
gs://flowers-public/daisy/14167543177_cd36b54ac6_n.jpg

¿Por qué usar tf.data.Dataset?

Keras y Tensorflow aceptan conjuntos de datos en todas sus funciones de entrenamiento y evaluación. Una vez que cargas datos en un conjunto de datos, la API ofrece todas las funciones comunes que son útiles para los datos de entrenamiento de redes neuronales:

dataset = ... # load something (see below)
dataset = dataset.shuffle(1000) # shuffle the dataset with a buffer of 1000
dataset = dataset.cache() # cache the dataset in RAM or on disk
dataset = dataset.repeat() # repeat the dataset indefinitely
dataset = dataset.batch(128) # batch data elements together in batches of 128
AUTOTUNE = tf.data.AUTOTUNE
dataset = dataset.prefetch(AUTOTUNE) # prefetch next batch(es) while training

Puedes encontrar sugerencias de rendimiento y prácticas recomendadas para conjuntos de datos en este artículo. La documentación de referencia se encuentra aquí.

Conceptos básicos de tf.data.Dataset

Los datos suelen estar en varios archivos, aquí, imágenes. Para crear un conjunto de datos de nombres de archivos, llama a lo siguiente:

filenames_dataset = tf.data.Dataset.list_files('gs://flowers-public/*/*.jpg')
# The parameter is a "glob" pattern that supports the * and ? wildcards.

Luego, “asignas” una función a cada nombre de archivo, que, por lo general, cargará y decodificará el archivo en datos reales en la memoria:

def decode_jpeg(filename):
  bits = tf.io.read_file(filename)
  image = tf.io.decode_jpeg(bits)
  return image

image_dataset = filenames_dataset.map(decode_jpeg)
# this is now a dataset of decoded images (uint8 RGB format)

Para iterar en un conjunto de datos, haz lo siguiente:

for data in my_dataset:
  print(data)

Conjuntos de datos de tuplas

En el aprendizaje supervisado, un conjunto de datos de entrenamiento suele estar formado por pares de datos de entrenamiento y respuestas correctas. Para permitirlo, la función de decodificación puede mostrar tuplas. Luego, se mostrará un conjunto de datos de tuplas y tuplas cuando iteres en él. Los valores que se muestran son tensores de TensorFlow listos para que los consuma tu modelo. Puedes llamar a .numpy() en ellos para ver los valores sin procesar:

def decode_jpeg_and_label(filename):
  bits = tf.read_file(filename)
  image = tf.io.decode_jpeg(bits)
  label = ... # extract flower name from folder name
  return image, label

image_dataset = filenames_dataset.map(decode_jpeg_and_label)
# this is now a dataset of (image, label) pairs 

for image, label in dataset:
  print(image.numpy().shape, label.numpy())

Conclusión: ¡cargar imágenes una por una es lento!

A medida que iteres en este conjunto de datos, verás que puedes cargar algo como 1 o 2 imágenes por segundo. ¡Es demasiado lento! Los aceleradores de hardware que usaremos para el entrenamiento pueden mantener muchas veces esta tasa. Pasa a la siguiente sección para ver cómo lo lograremos.

Solución

Este es el notebook de la solución. Puedes usarla si no puedes avanzar.

c3df49e90e5a654f.png Fun with tf.data.Dataset (solution).ipynb

Temas abordados

  • 🤔 tf.data.Dataset.list_files
  • 🤔 tf.data.Dataset.map
  • 🤔 Conjuntos de datos de tuplas
  • 😀 iterando a través de conjuntos de datos

Tómate un momento para revisar esta lista de verificación en tu cabeza.

5. Carga de datos rápida

Los aceleradores de hardware de la unidad de procesamiento tensorial (TPU) que usaremos en este lab son muy rápidos. A menudo, el desafío es proporcionarles datos lo suficientemente rápido como para mantenerlos ocupados. Google Cloud Storage (GCS) es capaz de mantener una capacidad de procesamiento muy alta, pero, al igual que con todos los sistemas de almacenamiento en la nube, iniciar una conexión cuesta algunos intercambios de red. Por lo tanto, almacenar nuestros datos como miles de archivos individuales no es lo ideal. Los agruparemos en una cantidad menor de archivos y usaremos la potencia de tf.data.Dataset para leer de varios archivos en paralelo.

Lectura

En el siguiente notebook, se encuentra el código que carga archivos de imagen, les cambia el tamaño a un tamaño común y, luego, los almacena en 16 archivos TFRecord. Léela rápidamente. No es necesario ejecutarlo, ya que se proporcionarán datos con formato TFRecord correctamente para el resto del codelab.

c3df49e90e5a654f.png Flower pictures to TFRecords.ipynb

Diseño de datos ideal para una capacidad de procesamiento óptima de GCS

El formato de archivo TFRecord

El formato de archivo preferido de Tensorflow para almacenar datos es el formato TFRecord basado en protobuf. Otros formatos de serialización también funcionan, pero puedes cargar un conjunto de datos desde archivos TFRecord directamente escribiendo lo siguiente:

filenames = tf.io.gfile.glob(FILENAME_PATTERN)
dataset = tf.data.TFRecordDataset(filenames)
dataset = dataset.map(...) # do the TFRecord decoding here - see below

Si deseas obtener un rendimiento óptimo, se recomienda usar el siguiente código más complejo para leer desde varios archivos TFRecord a la vez. Este código leerá de N archivos en paralelo y no tendrá en cuenta el orden de los datos en favor de la velocidad de lectura.

AUTOTUNE = tf.data.AUTOTUNE
ignore_order = tf.data.Options()
ignore_order.experimental_deterministic = False

filenames = tf.io.gfile.glob(FILENAME_PATTERN)
dataset = tf.data.TFRecordDataset(filenames, num_parallel_reads=AUTOTUNE)
dataset = dataset.with_options(ignore_order)
dataset = dataset.map(...) # do the TFRecord decoding here - see below

Hoja de referencia de TFRecord

En TFRecords se pueden almacenar tres tipos de datos: cadenas de bytes (lista de bytes), enteros de 64 bits y flotantes de 32 bits. Siempre se almacenan como listas; un solo elemento de datos será una lista de tamaño 1. Puedes usar las siguientes funciones auxiliares para almacenar datos en TFRecords.

escritura de cadenas de bytes

# warning, the input is a list of byte strings, which are themselves lists of bytes
def _bytestring_feature(list_of_bytestrings):
  return tf.train.Feature(bytes_list=tf.train.BytesList(value=list_of_bytestrings))

escribir números enteros

def _int_feature(list_of_ints): # int64
  return tf.train.Feature(int64_list=tf.train.Int64List(value=list_of_ints))

escritura de números de punto flotante

def _float_feature(list_of_floats): # float32
  return tf.train.Feature(float_list=tf.train.FloatList(value=list_of_floats))

escribir un TFRecord, con los asistentes anteriores

# input data in my_img_bytes, my_class, my_height, my_width, my_floats
with tf.python_io.TFRecordWriter(filename) as out_file:
  feature = {
    "image": _bytestring_feature([my_img_bytes]), # one image in the list
    "class": _int_feature([my_class]),            # one class in the list
    "size": _int_feature([my_height, my_width]),  # fixed length (2) list of ints
    "float_data": _float_feature(my_floats)       # variable length  list of floats
  }
  tf_record = tf.train.Example(features=tf.train.Features(feature=feature))
  out_file.write(tf_record.SerializeToString())

Para leer datos de TFRecords, primero debes declarar el diseño de los registros que almacenaste. En la declaración, puedes acceder a cualquier campo con nombre como una lista de longitud fija o una lista de longitud variable:

Leer de TFRecords

def read_tfrecord(data):
  features = {
    # tf.string = byte string (not text string)
    "image": tf.io.FixedLenFeature([], tf.string), # shape [] means scalar, here, a single byte string
    "class": tf.io.FixedLenFeature([], tf.int64),  # shape [] means scalar, i.e. a single item
    "size": tf.io.FixedLenFeature([2], tf.int64),  # two integers
    "float_data": tf.io.VarLenFeature(tf.float32)  # a variable number of floats
  }

  # decode the TFRecord
  tf_record = tf.io.parse_single_example(data, features)

  # FixedLenFeature fields are now ready to use
  sz = tf_record['size']

  # Typical code for decoding compressed images
  image = tf.io.decode_jpeg(tf_record['image'], channels=3)

  # VarLenFeature fields require additional sparse.to_dense decoding
  float_data = tf.sparse.to_dense(tf_record['float_data'])

  return image, sz, float_data

# decoding a tf.data.TFRecordDataset
dataset = dataset.map(read_tfrecord)
# now a dataset of triplets (image, sz, float_data)

Fragmentos de código útiles:

leer elementos de datos únicos

tf.io.FixedLenFeature([], tf.string)   # for one byte string
tf.io.FixedLenFeature([], tf.int64)    # for one int
tf.io.FixedLenFeature([], tf.float32)  # for one float

leyendo listas de elementos de tamaño fijo

tf.io.FixedLenFeature([N], tf.string)   # list of N byte strings
tf.io.FixedLenFeature([N], tf.int64)    # list of N ints
tf.io.FixedLenFeature([N], tf.float32)  # list of N floats

Leer una cantidad variable de elementos de datos

tf.io.VarLenFeature(tf.string)   # list of byte strings
tf.io.VarLenFeature(tf.int64)    # list of ints
tf.io.VarLenFeature(tf.float32)  # list of floats

Un VarLenFeature muestra un vector disperso y se requiere un paso adicional después de decodificar el TFRecord:

dense_data = tf.sparse.to_dense(tf_record['my_var_len_feature'])

También es posible tener campos opcionales en TFRecords. Si especificas un valor predeterminado cuando lees un campo, se muestra el valor predeterminado en lugar de un error si falta el campo.

tf.io.FixedLenFeature([], tf.int64, default_value=0) # this field is optional

Temas abordados

  • 🤔 Fragmentación de archivos de datos para un acceso rápido desde GCS
  • límites para escribir TFRecords. (¿Ya olvidaste la sintaxis? Está bien, agregue esta página a favoritos como hoja de referencia).
  • 🤔 cargando un conjunto de datos de TFRecords con TFRecordDataset

Tómate un momento para revisar esta lista de verificación en tu cabeza.

6. ¡Felicitaciones!

Ahora puedes alimentar una TPU con datos. Continúa con el siguiente lab

TPUs en la práctica

Las TPU y las GPU están disponibles en AI Platform de Cloud:

Por último, nos encanta recibir comentarios. Infórmanos si notas algún error en este lab o si crees que deberíamos mejorar. Se pueden proporcionar comentarios a través de los problemas de GitHub [feedback link].

HR.png

ID de Martin Görner small.jpg
El autor: Martin Görner
Twitter: @martin_gorner