Introducción a la API funcional de Keras#

Introducción#

Este es un notebook de Google Colaboratory. Los programas de Python se ejecutan directamente en tu navegador, una gran manera de aprender y utilizar TensorFlow. Para poder seguir este tutorial, ejecuta este notebook en Google Colab. Basado en Tensorflow- quick start expertos

from __future__ import absolute_import, division, print_function

import tensorflow as tf
print('Version de Tensorflow = ', tf.__version__)

# Objetos de la API de Keras
from tensorflow.keras.layers import Dense, Flatten, Conv2D
from tensorflow.keras import Model
from tensorflow.keras.losses import SparseCategoricalCrossentropy
from tensorflow.keras.optimizers import Adam
from tensorflow.keras.utils import plot_model

# datos mnist
from tensorflow.keras.datasets import mnist

# Manejo de datasets como tensores de tf
dataset = tf.data.Dataset.from_tensor_slices

# Métricas para medir pérdida y precisión
loss_metric     = tf.keras.metrics.Mean
accuracy_metric = tf.keras.metrics.SparseCategoricalAccuracy
Version de Tensorflow =  2.9.1

Prepara datos de MNIST#

(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train, x_test = x_train/255.0, x_test/255.0

# Agrega una dimensión para manejo de canales de imágenes en tensorflow
x_train = x_train[...,tf.newaxis]
x_test = x_test[...,tf.newaxis]
x_test.shape
(10000, 28, 28, 1)

Separa lotes de datos y mezclar el conjunto de datos#

Usamos tf.data. Revise cuidadosamente el tutorial tf.data: compila canalizaciones de entrada de TensorFlow

train_ds = dataset((x_train, y_train)).shuffle(10000).batch(32)

test_ds  = dataset((x_test, y_test)).shuffle(10000).batch(32)
test_ds
<BatchDataset element_spec=(TensorSpec(shape=(None, 28, 28, 1), dtype=tf.float64, name=None), TensorSpec(shape=(None,), dtype=tf.uint8, name=None))>

API Funcional de Keras. Sub-clases#

Vamos a derivar nuestro model de la clase Model de la API funcional de Keras.

class MyModel(Model):
    def __init__(self):
        super(MyModel,self).__init__()
        self.conv1 = Conv2D(32, 3, activation='relu')
        self.flatten= Flatten()
        self.d1 = Dense(128, activation='relu')
        self.d2 = Dense(10, activation='softmax')
    
    def call(self,x):
        x = self.conv1(x)
        x = self.flatten(x)
        x = self.d1(x)
        return self.d2(x)

# crea una instancia del modelo
model = MyModel()

Optimizador y función de pérdida#

Usaremos la entropía cruzada con varias clases (10 en este caso) y el optimizador Adam. La función SparseCategoricalCrossentropy recibe como entrada enteros y construye internamente la codificación one-hot. Puede usar la función CategoricalCrossentropy si desea integrar directamente las etiquetas en codificación one-hot.

Asegúrese de entender la entropía cruzada y su relación con la codificación one-hot.

En caso de duda, consulte al instructor.

loss_object = SparseCategoricalCrossentropy()

optimizer = Adam()

Suponga por ejemplo que tiene tres categorías: 1,2,3. Discuta el siguiente fragmento (snippet) de código.

y_true = [1, 2]
y_pred = [[0.05, 0.95, 0], [0.1, 0.8, 0.1]]

loss_object(y_true, y_pred).numpy()
1.1769392

Puede verificar que en este caso el resultado se obtiene de la siguiente forma. Explique por favor.

import numpy as np

-(np.log(0.95) + np.log(0.1))/2
1.176939193690798

O lo que es lo mismo

-(np.log(y_pred[0][y_true[0]]) + np.log(y_pred[1][y_true[1]]))/len(y_pred)
1.176939193690798

Métricas para medir pérdida y precisión#

Escoge métricas para medir la perdida y exactitud del modelo. Estas métricas acumulan los valores cada epoch y después imprimen el resultado total.

train_loss = loss_metric(name='train_loss')
train_accuracy = accuracy_metric(name='train_accuracy')

test_loss = loss_metric(name='test_loss')
test_accuracy = accuracy_metric(name='loss_accuracy')

Función de entrenamiento: diferenciación automática con tf.GradientTape#

La función de entrenamiento es decorada con el decorador @tf.function Este decorado compila la función como un grafo de TensorFlow invocable.

@tf.function
def train_step(images, labels):
    with tf.GradientTape() as tape:
        predictions = model(images)
        loss = loss_object(labels, predictions)
    gradients = tape.gradient(loss, model.trainable_variables)
    optimizer.apply_gradients(zip(gradients, model.trainable_variables))
    
    train_loss(loss)
    train_accuracy(labels, predictions)
    

Función de prueba (test)#

@tf.function
def test_step(images, labels):
    predictions = model(images)
    t_loss = loss_object(labels, predictions)

    test_loss(t_loss)
    test_accuracy(labels, predictions)

Entrena el modelo#

def fit(train_dataset, test_dataset, epochs):
    for epoch in range(epochs):
        for images, labels in train_dataset:
            train_step(images, labels)
        
        for images, labels in test_dataset:
            test_step(images, labels)
        
        template = 'Epoch {}, Pérdida: {}, Exactitud: {}, Pérdida de prueba: {}, Exactitud de prueba {}'
        print(template.format(epoch+1,
                              train_loss.result(),
                              train_accuracy.result(),
                              test_loss.result(),
                              test_accuracy.result()))
        
        # Reinicia las métricas para el siguiente paso
        train_loss.reset_states()
        train_accuracy.reset_states()
        test_loss.reset_states()
        test_accuracy.reset_states()
fit(train_ds, test_ds, epochs = 5)