<meta name="monetization" content="$ilp.uphold.com/EXa8i9DQ32qy">
*Nota: Contactar a Omar Espejel ([email protected]) para cualquier observación. Cualquier error es culpa del autor.
Cuando comenzaba mi viaje por PyTorch buscaba algún post, tutorial, markdown, lo que fuera que me ayudara a entender cómo podía manejarme por el framework. Muchos paquetes, muchas funciones y poco material para entender cómo navegarlas. El objetivo de este texto es precisamente ese, ayudar en la comprensión de PyTorch: para que podamos hacer deep learning antes debemos conocer nuestras herramientas.
En un segundo texto, ya involucrando código, muestro los primeros pasos para hacer deep learning: Manipulación de tensores en PyTorch. ¡El primer paso para el deep learning!
Antes de iniciar el viaje por la programación del deep learning se debe, como con cualquier otro arte/oficio, entender que se cometerán errores. Muchos y muchos errores. Cada día que programo recurro a la documentación de PyTorch, no hay día que no ocurra.
Como dice Brené Brown en su íncreible libro Dare to Lead: no es prepararse por SI se falla (equivoca, en nuestro caso) sino prepararse para CUANDO se falle. La cita es aproximada.
Así es, nos vamos a equivocar y no pasa nada. Para eso tenemos una ríquisima guía: la documentación de PyTorch. Esta será nuestro texto sagrado, nuestro instrumento para el éxito. Pero antes de entrar en la documentación, entendamos un poco más qué es PyTorch.
Pytorch se denomina a sí mismo en GitHub como un paquete de Python que provee dos cualidades: (1) Cálculos con tensores con aceleración de una Graphic Processing Unit (GPU). (2) La construcción de redes neuronales construidas sobre un sistema de autogradiente. Además, PyTorch vive sobre un API backend basado en C++ lo cual le permite contar con mayor velocidad de ejecución.
Para que (1) se pueda llevar a cabo en GPUs, PyTorch nos permite utilizar CUDA. Por el momento, basta con saber que CUDA, plataforma de computación paralela, nos sirve para correr nuestros modelos en GPUs. Esto nos permite que nuestra computación científica se ejecute con mayor velocidad a si operaramos en un Central Processing Unit (CPU).
El punto (2) nos indica, brevemente, que PyTorch puede realizar, si lo activamos, un seguimiento a los tensores después de pasar por múltiples operaciones, que involucran la creación de una red neuronal, de forma que nos pueda retornar la derivada de la última operación con respecto al tensor en cuestión. No te preocupes si algunos conceptos no son claros, en textos siguientes entraremos con mayor profundidad en lo que esto significa.
Cami Williams, lead Developer Advocate for ML/AI en Facebook, explica a la perfección la composición de PyTorch. Dentro del "front-end", en Python, existen tres secciones:
"Torch: paquete que contiene estructuras de datos para tensores multidimensionales y operaciones matemáticas.
Torch.nn: Creación y entrenamiento de redes neuronales. Los datos ingresados en estos módulos se pasan en forma de tensores. Por ejemplo: al entrenar una "red neuronal convolucional" para imágenes puede usar el módulo "nn.conv2D".
Torch.optim: algoritmos de optimización utilizados para entrenar las redes neuronales. Por ejemplo: algoritmos como SGD, para principiantes, o más avanzados, como Adam, utilizados para el entrenamiento" - Cami Williams.
El "back-end", en C++, tiene cinco secciones: Autograd, ATen, TorchScript, C++ Frontend y C++ Extensions. Sin embargo, para fines de este texto introductorio no entraremos en detalle.
Todas estas secciones pueden ser consultadas en la documentación oficial.
Dentro de la documentación, en la barra vertical de la izquierda, encontramos la sección
en la que encontraremos todo lo necesario para construir una red neuronal desde el front-end de PyTorch. Ahí están los "componentes" (como los nombra PyTorch en su GitHub) o "paquetes" (como los nombra en su documentación) torch; torch.nn; torch.nn.functional; torch.Tensor; etc.Python API
Hagamos una revisión de cada uno de los componentes del front-end, más
torch.nn.functional
.torch
Para comprender la documentación de PyTorch, ingresemos primero al paquete/componente Torch.
Para fines introductorios de este texto, enfoquémonos en lo que se encuentra dentro de los subtítulos "Tensors" y "Math operations".
En "Tensors" encontramos operaciones para crear tensores (dentro del subsubtítulo (¿así se dice?) "Creation Ops"), por ejemplo la función tradicional
torch.tensor
:También encontramos funciones para manipular los tensores (dentro del subsubtítulo "Indexing, Slicing, Joining, Mutating Ops"), por ejemplo
torch.cat
:En la subsección "Math Operations" encontramos precisamente eso, operaciones matemáticas que podemos ejercer sobre nuestros tensores.
Valores absolutos:
Sumas:
Funciones techo:
y todo lo que puedas necesitar para operar a "low-level" con tus tensores. Para fines introductorios, no es necesario revisar el código fuente de las operaciones en el paquete
torch
.En mi texto "Manipulación de tensores en PyTorch. ¡El primer paso para el deep learning!" puedes revisar más sobre los tensores.
torch.nn.functional
Este paquete contiene funciones ya construidas por los contribuidores a PyTorch. Las funciones se construyen precisamente con las operaciones en el paquete
. Así vamos construyendo sobre lo que vamos aprendiendo; veremos que torch
torch.nn
construye sobre las funciones definidas en torch.nn.functional
.Dada la frecuencia con la que se utiliza este paquete, en la documentación y código de PyTorch encontraremos muy comunmente la abreviación
en vez de F
. Por ejemplo, torch.nn.functional
torch.nn.functional.conv_transpose2d
significa lo mismo que F.conv_transpose2d
.En la barra vertical de la derecha encontramos subsecciones con los diferentes tipos de función. Pueden ser, por ejemplo, operaciones de convolución (en la subsección "Convolution functions") como:
la operación linear (en la subsección "Linear functions"):
o hasta funciones de pérdida (en la subsección "Loss functions") como la de mean square error:
Si en algún punto te pierdes, como nos pasa a todos, la documentación cuenta con excelentes ejemplos de uso para la mayoría de las operaciones. Por ejemplo, la función
torch.nn.functional.conv2d
:O por ejemplo para la función
torch.nn.functional.avg_pool1d
:En fin, en este paquete encontraremos funciones ya implementadas. Con ellas podremos crear estructuras más grandes como pueden ser las capas de una red neuronal.
torch.nn
Para los que conocen Keras, este paquete hará mucho sentido pues podemos considerarlo como "high-level" en cuanto a la programación necesitada. Podremos acceder a diferentes tipos de capas, crear las nuestras y acomodarlas para formar nuestras redes.
En la barra vertical de la derecha encontramos todo tipo de capas para nuestras redes neuronales "Convolution layers", "Pooling layers", "Transformer layers", "Linear layers", etc. Aquí ya no hablamos de simples funciones, hablamos de capas enteras codificadas como clases de Python.
La mayoría de estas clases vienen con la fórmula de la que se derivan, amplios ejemplos y una opción para ver el código fuente directamente en la documentación.
Por ejemplo, la muy utilizada capa Conv2d (se encuentra en el subtítulo "Convolution layers"):
En la parte derecha de la definición de la clase Conv2D está la opción
[SOURCE]
con la que podemos acceder al código fuente. Al ingresar a este notaremos que que se utilizan funciones del paquete torch.nn.functional
para definirlas. Por ejemplo, claro que vemos F.conv2d
en en el código fuente de la clase torch.nn.Conv2d
:Todo va cuadrando.
En algunas capas, por ejemplo en torch.nn.Transformer (se encuentra en el subtítulo "Transformer layers"), encontramos hasta papers relevantes:
En un escrito posterior incluiré información sobre cómo podemos hacer uso de toda está información para crear nuestras primeras redes neuronales.
También podemos acceder a funciones de pérdida en formato de clase y listas para agregar en nuestra red neuronal.
Nuevamente, vemos como estas clases utilizan código antes escrito en torch.nn.functional; para el caso de la clase MSELoss vemos que utiliza
torch.nn.functional.mse_loss
:Además, el paquete
tiene lo necesario para crear nuestras propias capas utilizando su clase base torch.nn
(en el subtítulo "Containers"):torch.nn.Module
En otro texto veremos cómo hacer nuestras propias clases utilizando esa clase base, por ahora nos basta saber donde encontrarla en la documentación.
Para los usuarios familiarizados con la forma en que se crean los modelos en Keras, PyTorch ofrece una funcionalidad muy similar y de tremenda conveniencia.
(también en el subtítulo "Containers") nos permite crear nuestras redes de manera ordenada y sencilla. Aquí está un pequeño ejemplo en la documentación:torch.nn.Sequential
Hasta aquí sabemos donde se encuentra prácticamente todo lo necesario para diseñar nuestra red neuronal. Ahora veamos la última sección del front-end mencionado por la lead Developer Advocate for ML/AI en Facebook, Cami Williams.
torch.nn.optim
Aquí encontramos algoritmos para optimizar nuestras redes neuronales y las herramients para crearlos.
Para la creación de algoritmos de optimización podemos seguir la clase
(se encuentra en el subtítulo "Algorithms"):torch.optim.Optimizer
También encontramos algoritmos ya implementados por otros. Por ejemplo, el famoso algoritmo Adam:
Dado el carácter introductorio de este texto, no ahondaremos en la creación o implementación de los algoritmos de optimización. Dejemos eso para un siguiente texto.
Para hacer deep learning tenemos que estar preparados para todos los errores que vamos a cometer, sin excepción. Lo importante es que sepamos como atender esos errores y cómo manejarnos dentro de nuestras herramientas.
Lamentablemente, pocos textos abordan cómo leer y entender nuestro framework seleccionado. Este fue precisamente el objetivo de este texto.
De acuerdo a un texto escrito por la lead Developer Advocate for ML/AI en Facebook, Cami Williams, PyTorch cuenta con un fron-ent definido por tres distintas secciones:
torch
, torch.nn
y torch.optim
. Podemos acceder a todas las funciones de cada una de estas secciones en la documentación oficial de PyTorch.En
torch
encontramos operaciones para crear y manipular tensores, así como operaciones matemáticas para ejercer sobre ellos.En
torch.nn.functional
, vital para el entendimiento de PyTorch, encontramos todo tipo de funciones matemáticas.En
torch.nn
podemos acceder a capas ya diseñadas, crear nuestras porpias capas y acomodar las capas para crear nuestra red.Finalmente, en
torch.optim
tenemos acceso a algoritmos de optimización ya creados y a funcionalidades para crear los nuestros.