Path: blob/master/site/es-419/guide/intro_to_graphs.ipynb
25115 views
Copyright 2020 The TensorFlow Authors.
Introduccion a los gráficos y la tf.function
Descripción general
En está guía se explica TensorFlow y Keras en profundidad para demostrar cómo funciona TensorFlow. Si quiere empezar con Keras inmediatamente, vea la colección de las guías de Keras.
En esta guía, aprenderá cómo TensorFlow permite hacer cambios simples en el código para obtener gráficos, cómo se almacenan y representan los gráficos y cómo puede usarlos para acelerar sus modelos.
Nota: Para los que tengan conocimientos solo de TensorFlow 1.x, en esta guía se muestra una perspectiva muy diferente de los gráficos.
Esto es un panorama general que cubre cómo tf.function
permite cambiar de una ejecución eager a una ejecución de gráfico. Para ver todas las especificaciones de tf.function
, vea la Guía para mejorar el rendimiento con tf.function
.
¿Qué son los gráficos?
En las tres guías previas, puede ejecutar TensorFlow de forma eager. Esto quiere decir que las operaciones de TensorFlow se ejecutan con Python, operación por operación, y se devuelven los resultados en Python.
Si bien la ejecución eager tiene muchas ventajas únicas, la ejecución con gráficos permite portabilidad fuera de Python y suele ofrecer un mejor rendimiento. La ejecución de gráfico significa que los cálculos del tensor se ejecutan como gráfico de TensorFlow, a veces denominado tf.Graph
o simplemente "gráfico."
Los gráficos son estructuras de datos que contienen un conjunto de objetos tf.Operation
que representan unidades de cálculos; y objetos tf.Tensor
que representan las unidades de datos que fluyen entre las operaciones. Se definen en un contexto de tf.Graph
. Ya que estos gráficos son estructuras de datos, pueden guardarse, ejecutarse y realmacenarse sin el código original de Python.
Así se ve un gráfico de TensorFlow que representa una red neuronal de dos capas al visualizarse en TensorBoard:
Los beneficios de los gráficos
Con un gráfico, se tiene mucha flexibilidad. Puede usar su gráfico de TensorFlow en entornos que no tengan intérprete de Python, como en aplicaciones móviles, dispositivos incrustados y servidores backend. TensorFlow usa los gráficos como el formato de los modelos guardados cuando se exportan de Python.
Los gráficos también pueden optimizarse fácilmente, lo que permite hacer transformaciones como las siguientes:
Inferir estadísticamente el valor de los tensores al plegar los nodos de constantes en el cálculo ("plegado de constantes").
Separar subpartes de un cálculo que son independientes y dividirlas en subprocesos o dispositivos.
Simplificar las operaciones aritméticas mediante la eliminación de subexpresiones comunes.
Existe un sistema completo de optimización, Grappler, para hacer todo esto y otras aceleraciones.
En resumen, los gráficos son muy útiles y permiten que TensorFlow se ejecute rápido, se ejecute en paralelo y de forma eficiente en diferentes dispositivos.
Sin embargo, todavía es más convenienite definir los modelos de aprendizaje automátivo (o otros cálculos) en Python y después construir los gráficos automáticamente cuando los necesite.
Preparación
Importe algunas de las bibliotecas necesarias:
Aprovechar los gráficos
Creará y ejecutará un gráfico en TensorFlow con tf.function
, ya sea como una llamada directa o como un decorador. tf.function
toma una función regular como entrada y devuelve una Function
. Una Function
es un invocable de Python que construye gráficos de TensorFlow desde la función de Python. La Function
se usa de la misma manera que se usa su equivalente de Python.
Desde afuera, una Function
se parece a una función normal que se escribe con las operaciones de TensorFlow. Internamente, sin embargo, es muy diferente. Una Function
encapsula varios tf.Graph
detrás de una API (vea la sección de Polimorfismo para obtener más información). Es por eso que una Function
le permite disfrutar de los beneficios de la ejecución de gráficos, como la velocidad e implementabilidad (consulte Los beneficios de los gráficos arriba).
tf.function
se aplica a una función y a todas las otras funciones que llama:
Si ya uso TensorFlow 1.x, habrá notado que no hace falta definir un Placeholder
o un tf.Session
.
Convertir las funciones de Python en gráficos
Cualquier función que escriba con TensorFlow tendrá una mezcla de operaciones TF y lógicas de Python integradas, tales como cláusulas if-then
, bucles, break
, return
, continue
y más. Mientras las operaciones de TensorFlow son capturadas fácilmente con tf.Graph
, las lógicas específicas de Python necesitan un paso adicional para ser parte del gráfico. La tf.function
usa una biblioteca llamada AutoGraph (tf.autograph
) para convertir el código de Python en código generador de gráficos.
Si bien es poco probable que necesite ver los gráficos de forma directa, puede inspeccionar las salidas para verificar los resultados exactos. No son fáciles de leer, así que no es necesario mirar con tanta atención.
La mayoría de las veces, la tf.function
funciona sin consideraciones especiales. Sin embargo, hay que tener algunas precauciones y la guía de tf.function
puede ser útil, así como también la referencia completa de AutoGraph.
Polimorfismo: una Function
, muchos gráficos
Un tf.Graph
se especializa en un tipo específico de entradas (por ejemplo, tensores con un dtype
específico u objetos con el mismo id()
).
Cada vez que se invoca una Function
con un conjunto de argumentos que pueden manipularse con cualquiera de sus gráficos existentes (como argumentos con un dtypes
nuevo o formas incompatibles), la Function
crea un nuevo tf.Graph
especializado en los nuevos argumentos. La especificación del tipo de las entradas de un tf.Graph
se conoce como su signatura de entrada o solo signatura. Para obtener más información sobre cuando se genera un tf.Graph
nuevo como controlarlo, vea la sección Reglas de trazado de la guía Mejor rendimiento con tf.function
.
La Function
almacena el tf.Graph
que corresponde a esa signatura en un ConcreteFunction
. Un ConcreteFunction
es un encapsulador del tf.Graph
.
Si la Function
ya fue llamada con esa signatura, la Function
no crea un tf.Graph
nuevo.
Debido a que tiene varios gráficos de respaldo, una Function
es polimórfica. Esto permite que se admitan más tipos de entrada que las que un simple tf.Graph
puede representar y que se optimice cada tf.Graph
para un mejor rendimiento.
Usar tf.function
Hasta este punto ha aprendido a convertir la función de Python en un gráfico de forma simple usando tf.function
como un decorador o encapsulador. Pero en la práctica, hacer que tf.function
funcione de forma correcta puede ser complicado. En la siguiente sección, aprenderá cómo hacer que su código funcione con tf.function
como debe ser.
Ejecución de gráfico versus ejecución eager
Se puede ejecutar el código en una Function
de forma eager y como un gráfico. De forma predeterminada, la Function
ejecuta su código como un gráfico:
Para verificar que el gráfico de Function
realice el mismo cálculo que su función equivalente de Python, puede ejecutarlo en eager con tf.config.run_functions_eagerly(True)
. Este es un cambio que desactiva la capacidad de Function
para crear y ejecutar gráficos, en vez de ejecutar el código normalmente.
Por el contrario, Function
puede comportarse diferente en una ejecución de gráfico o eager. La función print
de Python es un ejemplo de cómo difieren los dos modos. Veamos qué pasa cuando se inserta la declaración print
en su función y la llamamos repetidamente.
Observe lo que se imprime:
¿Le sorprende la salida? get_MSE
solo se imprimió una vez a pesar de haberlo llamado tres veces.
Esto es así, la declaración print
se ejecuta cuando Function
ejecuta el código original para crear un gráfico en un proceso conocido como "trazado" (consulte la sección de Trazado de la guía de tf.function
. El trazado captura las operaciones de TensorFlow en un gráfico y print
no se incluye en el gráfico. Este gráfico luego se ejecuta para las tres llamadas sin tener que ejecutar el código de Python de nuevo.
Para comprobarlo, desactivaremos la ejecución de gráfico para comparar:
print
es un efecto secundario de Python, y hay otras diferencias que debería tener en cuenta al convertir una función en Function
. Puede obtener más información en la sección de Limitaciones de la guía Mejor rendimiento con tf.function
.
Nota: si quiere imprimir valores en ambas ejecuciones, eager y de gráfico, mejor use tf.print
.
Ejecución no estricta
La ejecución de gráfico solo ejecuta las operaciones necesarias para producir los efectos observables, entre ellas se encuentra:
El valor de retorno de la función
Los efectos secundarios más conocidos documentados como:
Las operaciones de entrada o de salida, como
tf.print
Operaciones de depuración, como las funciones de aserción en
tf.debugging
Mutaciones de
tf.Variable
Este comportamiento se conoce normalemente como "ejecución no estricta" y es diferente a la ejecución eager, que recorre paso a paso todas las operaciones del programa, sean necesarias o no.
Particularmente, la verificación del error de tiempo de ejecución no cuenta como efecto obervable. Si se omite una operación porque no es necesaria, no se provoca ningún error en el tiempo de ejecución.
En el siguiente ejemplo, se omite la operación "innecesaria"tf.gather
durante la ejecución de gráfico, por eso no se provoca un error de ejecución InvalidArgumentError
ya que sería en una ejecución eager. No espere que ocurra un error al ejecutar un gráfico.
Mejores prácticas de tf.function
Es posible que lleve un tiempo acostumbrarse al comportamiento de Function
. Para empezar rápidamente, los usuarios que lo usan por primera vez, deberían probar decorando funciones de juguete con @tf.function
para obtener experiencia al cambiar de la ejecución eager a la de gráfico.
Diseñar para tf.function
puede ser lo mejor para escribir programas de TensorFlow que sean compatibles con gráficos. Estas son algunas recomendaciones:
Alterne entre la ejecución eager y de gráfico pronto y con frecuencia con
tf.config.run_functions_eagerly
para identificar cuando difieren, si difieren, los dos modos.Cree unas
tf.Variable
fuera de la función de Python y modifíquelas internamente. Haga lo mismo con los objetos que usantf.Variable
, como lostf.keras.layers
,tf.keras.Model
ytf.keras.optimizers
.Evite escribir funciones que dependan de las variables de Python, excluya la
tf.Variable
y los objetos de Keras. Obtenga más información en la sección *Depender de las variables globales y gratis de Python * de la guía detf.function
.Opte por escribir funciones que tomen tensores y otros tipos de TensorFlow como entrada. También puede pasar otros tipos de objetos pero tenga cuidado. Para obtener más información, vea Depender de objetos de Python de la guía de
tf.function
.Incluya todos los cálculos que pueda en
tf.function
para maximizar la ganancia de rendimiento. Por ejemplo, decore un paso de entrenamiento completo o todo un bucle de entrenamiento.
Observar la aceleración
tf.function
suele mejorar el rendimiento del código, pero la cantidad de aceleración depende del tipo de cálculo que se ejecute. Los calculos pequeños pueden se dominados por la sobrecarga de llamar un gráfico. Puede medir la diferencia en el rendimiento de la siguiente manera:
Generalmente, tf.function
se usa para acelerar los bucles de entrenamiento, y puede obtener más información sobre esto en la sección Acelerar el entrenamiento con tf.function
de la guía Escribir un bucle de entrenamiento desde cero con Keras.
Nota: También puede probar tf.function(jit_compile=True)
para potenciar el rendimiento significativamente, especialmente si su código es pesado en el flujo de control de TensorFlow y usa muchos tensores pequeños. Obtenga más información en la sección Compilación explicita con tf.function(jit_compile=True)
del Resumen de XLA.
Rendimiento y compensaciones
Los gráficos pueden acelerar su código, pero el proceso de creación puede tener algo de sobrecarga. Para algunas funciones, la creación de gráficos lleva más tiempo que la ejecución. Esta inversión suele recuperarse con el potenciador de rendimiento de las ejecuciones posteriores, pero es importante saber que los primeros pasos de cualquier entrenamiento de modelo grande puede ser lento debido al trazado.
No importa el tamaño del modelo, es mejor evitar el trazado frecuente. En la guía de tf.function
se explica cómo establecer especificaciones de entrada y cómo usar argumentos de tensor para evitar el retrazado en la sección Controlar el retrazado. Si nota que los rendimientos son extrañamente malos, sería bueno verificar que no esté retrazando por accidente.
¿Cuándo traza Function
?
Para averiguar si Function
está trazando, agregue una declaración print
en su código. Como regla de oro, Function
ejecutará la declaración print
cada vez que realice un trazado.
Los argumentos nuevos de Python siempre provocan la creación de un gráfico nuevo, y por eso el trazado adicional.
Siguientes pasos
Puede obtener más información sobre tf.function
en la página de referencia de la API si visita la guía de Mejor rendimiento con tf.function
.