sábado, 23 de julio de 2022

Introducción a TensorFlow Hub

Una de las cosas que es tan fundamental en el desarrollo de software que es fácil pasar por alto es la idea de un repositorio de código compartido. Como programadores, las bibliotecas nos hacen inmediatamente más efectivos. En cierto sentido, cambian el proceso de resolución de problemas de la programación. Cuando usamos una biblioteca, a menudo pensamos en la programación en términos de bloques de construcción, o módulos, que se pueden unir.

Además de compartir código, también se pueden compartir redes previamente entrenadas. Esto hace posible que un desarrollador pueda personalizarla para su dominio, sin tener acceso a los recursos informáticos o los datos utilizados para entrenar el modelo originalmente disponible. Por ejemplo, NASNet tomó miles de horas de GPU para entrenar. Al compartir los pesos aprendidos, se puede facilitar que otros puedan reutilizar y desarrollar su trabajo.

Introducción a TensorFlow Hub

"Ingredientes" de una red de aprendizaje automático que se puede empaquetar y compartir a través de TensorFlow Hub. En cierto sentido, al compartir una red pre-entrenada también se comparte el tiempo de cómputo y el conjunto de datos utilizados para desarrollar el modelo, además de la arquitectura misma.


TensorFlow Hub es una plataforma para publicar, descubrir y reutilizar partes de módulos de aprendizaje automático en TensorFlow. Por módulo, nos referimos a una pieza autónoma de un gráfico TensorFlow, junto con sus pesos, que se puede reutilizar en otras tareas similares. Al reutilizar un módulo, un desarrollador puede entrenar un modelo usando un conjunto de datos más pequeño, mejorar la generalización o simplemente acelerar el entrenamiento. Veamos un par de ejemplos para hacer esto concreto.

Reentrenamiento de imagen

Como primer ejemplo, veamos una técnica que podemos utilizar para entrenar un clasificador de imágenes, comenzando con solo una pequeña cantidad de datos de entrenamiento. Las redes modernas de reconocimiento de imágenes tienen millones de parámetros y, por supuesto, entrenar una desde cero requiere una gran cantidad de datos etiquetados y potencia informática. Usando una técnica llamada Re-entrenamiento de imagen, podemos entrenar una red utilizando una cantidad de datos mucho menor y mucho menos tiempo de computación. Así es como se ve esto en TensorFlow Hub.

# Download and use NASNet feature vector module.

module = hub.Module(

“https://tfhub.dev/google/imagenet/nasnet_large/feature_vector/1")

features = module(my_images)

logits = tf.layers.dense(features, NUM_CLASSES)

probabilities = tf.nn.softmax(logits)

La idea básica es reutilizar una red de reconocimiento de imagenes existente para extraer características de sus imágenes y luego re-entrenar la red. Como podemos ver arriba, los módulos de TensorFlow Hub pueden instanciarse desde una URL (o desde una ruta del sistema de archivos). Hay una variedad de módulos en TensorFlow Hub para elegir, incluidos varios sabores de NASNet, MobileNet (incluido su reciente V2), Inception, ResNet y otros. Para usar un módulo, hay que importar TensorFlow Hub, luego copiar y pegar la URL del módulo en nuestro código.

Reentrenamiento de imagen en TensorFlow Hub

Algunos de los módulos de imagen disponibles en TensorFlow Hub. Cada módulo tiene una interfaz definida que permite utilizarlo de manera reemplazable, con poco o ningún conocimiento de sus componentes internos. En este caso, este módulo tiene un método que puede usar para recuperar el tamaño de imagen esperado. Como desarrollador, solo necesitamos proporcionar un lote de imágenes en la forma correcta y llamar al módulo sobre ellas para recuperar la representación de la característica. Este módulo se encarga de preprocesar nuestras imágenes por nosotros, para que podamos pasar directamente de un lote de imágenes a una representación de características en un solo paso. Desde aquí, podemos entrenar una red u otro tipo de clasificador, además de estos.

En este caso, observaremos que el módulo que estamos utilizando está alojado por Google y está versionado (para que podamos confiar en que el módulo no cambia mientras trabajamos en nuestros experimentos). Los módulos se pueden aplicar como una función Python ordinaria para construir parte del gráfico. Una vez exportados al disco, los módulos son independientes y pueden ser utilizados por otros sin acceso al código y los datos utilizados para crearlo y entrenarlo (aunque, por supuesto, también podemos publicarlos).

Clasificación de texto

Echaremos un vistazo a un segundo ejemplo. Imaginamos que deseamos capacitar a una red para clasificar reseñas de películas como positivas o negativas, comenzando con solo una pequeña cantidad de datos de capacitación (por ejemplo, del orden de varios cientos de críticas de películas positivas y negativas). Como tenemos un número limitado de ejemplos, decidimos aprovechar un conjunto de datos de incrustaciones de palabras, previamente capacitados en un corpus mucho más grande. Así es como se ve esto usando TensorFlow Hub.

# Download a module and use it to retrieve word embeddings.

embed = hub.Module(“https://tfhub.dev/google/nnlm-en-dim50/1")

embeddings = embed([“The movie was great!”])

Como antes, comenzamos seleccionando un módulo. TensorFlow Hub tiene una variedad de módulos de texto para explorar, incluidos las redes de idiomas (EN, JP, DE y ES), así como Word2vec capacitado en Wikipedia y las incrustaciones de NNLM capacitadas en Google News.

Clasificación de texto en TensorFlow

En este caso, utilizaremos un módulo para la inserción de palabras. El código anterior descarga un módulo, lo usa para preprocesar una oración y luego recupera las incrustaciones para cada token. Esto significa que puede pasar directamente de una oración en su conjunto de datos a un formato adecuado para un clasificador en un solo paso. El módulo se encarga de tokenizar la oración y otras lógicas como manejar palabras fuera del vocabulario. Tanto la lógica de preprocesamiento como las incrustaciones están encapsuladas en un módulo, lo que hace que sea más fácil experimentar con varios conjuntos de datos de incrustaciones de palabras o diferentes estrategias de preprocesamiento, sin tener que cambiar sustancialmente nuestro código.

Clasificación de texto en TensorFlow

Codificador de oración universal

A continuación se muestra un ejemplo con un codificador de frases universales. Es un módulo de incrustación a nivel de oración capacitado en una amplia variedad de conjuntos de datos (en otras palabras, "universal"). Algunas de las cosas en las que es bueno son la similitud semántica, la clasificación de texto personalizado y la agrupación.

Codificador de oración universal en Tensor Flow

Este cuaderno de notas muestra cómo entrenar un clasificador de texto binario simple sobre cualquier módulo TF-Hub que podamos incrustar oraciones.

Al igual que en el reentrenamiento de imágenes, se requieren relativamente pocos datos etiquetados para adaptar el módulo a su propia tarea. Probémoslo en reseñas de restaurantes, por ejemplo.


# Use pre-trained universal sentence encoder to build text vector

review = hub.text_embedding_column(

“review”, “https://tfhub.dev/google/universal-sentence-encoder/1")

features = {

“review”: np.array([“this movie is a masterpiece”, “this movie was terrible”, …])

}

labels = np.array([[1], [0], …])

input_fn = tf.estimator.input.numpy_input_fn(features, labels, shuffle=True)

estimator = tf.estimator.DNNClassifier(hidden_units, [review])

estimator.train(input_fn, max_steps=100)

Otros módulos

TensorFlow Hub es más que clasificación de imágenes y texto. En el sitio web, también encontraremos un par de módulos para las características locales profundas de Progressive GAN y Googlemarks.

Consideraciones

Hay un par de consideraciones importantes al utilizar los módulos de TensorFlow Hub. Primero, recordar que los módulos contienen código ejecutable. Conviene utilizar siempre módulos de una fuente confiable. En segundo lugar, como en todo el aprendizaje automático, la imparcialidad es una consideración importante. Los dos ejemplos que mostramos arriba aprovechan grandes conjuntos de datos pre-entrenados. Al reutilizar un conjunto de datos de este tipo, es importante tener en cuenta qué datos contiene (y si existen sesgos allí) y cómo estos podrían afectar el producto que estamos creando y sus usuarios.



sábado, 16 de julio de 2022

Ajuste de redes densas mediante hyperas

Vamos a ver cómo seleccionar y ajustar hiperparámetros para redes neuronales densas usando hiperparámetros.

Antes de comenzar a usar hyperas, debemos comprender la biblioteca de Python llamada hyperopt. Hyperopt proporciona la capacidad de optimizar los espacios de búsqueda de dimensiones reales, valoradas, discretas y condicionales. Hyperas,  es un envoltorio alrededor de hyperopt para una creación de prototipos más rápida utilizando varios modelos de redes neuronales de Keras. Podemos usar hyperas para aprovechar el poder de los hyperopt sin tener que aprender una sintaxis sofisticada.

Definimos un modelo de Keras usando una notación de plantilla simple para definir los hiperparámetros a ajustar para obtener un modelo de red neuronal sintonizado. Es posible que nuestras máquinas tradicionales no puedan proporcionar la potencia informática necesaria para escribir aplicaciones que requieran hardware sofisticado y potencia de procesamiento. Google Colab,  puede incluso fallar cuando queremos trabajar con mecanismos  sofisticados de aprendizaje de redes neuronales.

En tales casos, optamos por un servicio en la nube. Un ejemplo destacado es AWS SageMaker. Podemos utilizar este servicio para definir, construir, entrenar y probar modelos de redes neuronales. Para comenzar a trabajar con  SageMaker, primero debemos iniciar sesión en la consola de administración de AWS desde la URL aws.amazon.com. Hacemos clic en la pestaña Iniciar sesión en la consola que se encuentra en la parte superior derecha de la página. Si no hemos iniciado sesión antes, se nos pedirá que proporcionemos nuestras credenciales de AWS.

 

Ajuste de redes densas mediante hyperas

Podemos usar el campo de búsqueda ubicado justo debajo de Buscar servicios, comenzamos a escribir la palabra SageMaker, y seleccionamos el servicio Amazon SageMaker. Queremos escribir una aplicación Python simple para utilizar las capacidades de hyperas para seleccionar y ajustar hiperparámetros mientras se construye una red neuronal.

Seleccionamos la opción Instancia de Notebook, del  menú izquierdo.

 

Amazon sagemaker

En la página de instancias de Notebook, se nos proporciona cierta información sobre la instancia de Notebook. Como el tipo de instancia, cuándo se creó y el estado actual. Podemos crear una nueva instancia, haciendo clic en el botón Create Notebook Instance. Utilizaremos la instancia existente, por lo que  hacemos clic en Abrir Jupyter en la pestaña Acciones.

 

redes neuronales con AWS Sagemaker

Seleccionamos el entorno Tensorflow que utilizaremos con Keras y en el cuaderno de jupyter escribimos:

! Pip install hyperas

! Pip install hyperopt

Estas dos declaraciones  instalarán hyperas e hyperopt usando el comando pip convencional de Python. Ejecutamos esta celda de código, haciendo clic en el botón de reproducción de radio ubicado justo al lado de la celda de código.

En la siguiente celda de código, importamos las bibliotecas y paquetes necesarios para construir un modelo de red neuronal y trabajar con hiperparámetros.

Estamos importando keras.models, keras.layers, keras.datasets y keras.utils. Este conjunto de importaciones proporcionará los datos junto con las capacidades esenciales de construir modelos de redes neuronales utilizando varios tipos de capas y funciones de activación.

from __future__ import print_function

from hyperopt import trials, STATUS_OK, tpe

from hyperas import optim

from hyperas.distributions import choice, uniform

from keras.models import Sequential

from keras.layers.core import Dense, Dropout, Activation

from keras.datasets import mnist

from keras.utils import np_utils

A veces, podemos obtener un error si TensorFlow no está instalado y configurado correctamente. La siguiente tarea es definir una función para preparar el modelo de datos. Esta función está separada del modelo de red para garantizar que no necesitemos volver a cargar los datos cada vez que queramos evaluar o volver a ejecutar el modelo.

Estamos construyendo conjuntos de datos X_train, Y_train, X_test e Y_test. Estos son los conjuntos de datos de entrenamiento y prueba. Cargamos los datos usando la declaración, mnist.load_data. Es una función de mnist y mnist es un modelo de datos que importamos de Keras en la celda de código anterior.

def data():

    (X_train, y_train), (x_test, y_test) = mnist.load_data ()

A continuación, rellenamos los conjuntos de datos X_train y X_test con los datos de mnist.

      X_train = X_train.reshape (60000, 784)

    X_test = X_test.reshape (10000, 784)

Hemos tomado 60000 y 784 como dimensiones para X_train. Y hemos hecho lo mismo para X_test, donde la dimensión es 10000 y 784. Después vinculamos X_train y X_test con un tipo de datos particular usando la declaración astype float32. usamos la función astype y pasamos el tipo de datos como float32.

       X_train = X_train.astype ('float32')

    X_test = X_test.astype ('float32')

Después factorizamos los datos en los conjuntos de datos de prueba y X_train. dividimos los datos de X_train y los conjuntos de datos de prueba entre 255.  Y especificamos el número de clases para la clasificación.

      X_train /= 255

    X_test /= 255

Suponemos que el número de clases es 10 convertimos Y_train y los conjuntos de datos de prueba en una matriz de clases categórica o binaria pasando los respectivos conjuntos de datos en el número de clases.

Finalmente, devolvemos X_train, Y_train, X_test y Y_test.

       nb_classes = 10

    Y_train = np_utils.to_categorical (y_train, nb_classes)

    Y_test = np_utils.to_categorical (y_test, nb_classes)

    return X_train, Y_train, X_test, Y_test


En conjunto la celda quedará

def data():

    (X_train, y_train), (x_test, y_test) = mnist.load_data ()

    X_train = X_train.reshape (60000, 784)

    X_test = X_test.reshape (10000, 784)

    X_train = X_train.astype ('float32')

    X_test = X_test.astype ('float32')

    X_train /= 255

    X_test /= 255

    nb_classes = 10

    Y_train = np_utils.to_categorical (y_train, nb_classes)

    Y_test = np_utils.to_categorical (y_test, nb_classes)

    return X_train, Y_train, X_test, Y_test

Hemos creado un modelo de datos que podemos usar para construir y entrenar el modelo de red neuronal. El siguiente paso es construir un modelo de red neuronal. El tipo de modelo que estamos construyendo es un modelo secuencial.

def model (X_train, Y_train, X_test, Y_test):

Agregando una capa densa, que es una operación lineal, donde cada entrada se conectará a cada salida con ciertos pesos, y estamos pasando la forma y las dimensiones de la entrada.

  model = Sequential()

Esta será la capa de entrada, y para esta capa estamos usando la función de activación relu.

    model.add (Dense (512, input_shape = (784,)))

    model.add (Activation ('relu'))

A continuación, agregaremos una capa de salida para garantizar que algunos de los elementos se puedan reducir. Después de agregar la capa de entrada, estamos agregando una capa oculta usando la operación lineal densa a la que estamos pasando la opción.

     model.add (Dropout({{uniform (0, 1)}}))

   model.add (Dense({{choice([256, 512, 1024])}}))

   model.add (Activation({{choice(['relu','sigmoid'])}}))

Hemos agregado múltiples capas para construir nuestra red neuronal.

       model.add (Dropout({{uniform (0, 1)}}))

Después de agregar las capas de entrada y ocultas, especificamos una declaración if. Si nuestra elección es cuatro, la declaración agregará otra capa, pero si nuestra elección es tres, usaremos las capas existentes que hemos agregado. También hemos especificado las declaraciones para agregar la cuarta capa, y finalmente estamos agregando la capa de salida utilizando la declaración model.add dense.

if {{choice(['three', 'four'])}} == 'four':

    model.add (Dense (100))

    model.add ({{choice ([Dropout (0.5), Activation ('linear')])}})

    model.add (Activación ('relu'))

    model.add (Dense (10))

Y estamos usando la función de activación softmax para la capa de salida.

model.add (Activación ('softmax'))

Así que hemos definido nuestro modelo de red neuronal que contiene múltiples capas, incluida una capa de entrada y una de salida. La celda completa queda:

def model (X_train, Y_train, X_test, Y_test):

   

    model = Sequential()

    model.add (Dense (512, input_shape = (784,)))

    model.add (Activation ('relu'))

    model.add (Dropout({{uniform (0, 1)}}))

    model.add (Dense({{choice([256, 512, 1024])}}))

    model.add (Activation({{choice(['relu','sigmoid'])}}))

    model.add (Dropout({{uniform (0, 1)}}))

 

if {{choice(['three', 'four'])}} == 'four':

    model.add (Dense (100))

    model.add ({{choice ([Dropout (0.5), Activation ('linear')])}})

    model.add (Activación ('relu'))

    model.add (Dense (10))

    model.add (Activación ('softmax'))

La capa de entrada usa relu como función de activación, la capa de salida usa softmax como función de activación, y las capas ocultas o intermedias usan diferentes funciones de activación. Después de definir las capas para el modelo de red neuronal, la siguiente tarea es compilarlo.

Para compilar el modelo, estamos usando la función del modelo llamada compilar, a la que le estamos pasando la entropía cruzada categórica como función de pérdida, ya que hemos convertido el conjunto de datos en categórico.

model.compile(loss = 'categorical_crossentropy',

          optimizer = {{choice (['rmsprop', 'adam', 'sgd'])}},

          metrics = ['accuracy'])

El segundo argumento es el optimizador. Se utiliza para indicar cómo se debe compilar el modelo o crear una instancia de un objeto. Se especifican tres opciones de optimizador diferentes, rmsprop, adam y sgd, que es la abreviatura de descenso de gradiente estocástico.

El tercer y último argumento que hemos pasado es métrica que le ponemos  precisión. Después de compilar el modelo, la siguiente tarea es ajustar el modelo con los conjuntos de datos de entrenamiento.

Estamos usando la función ajustada a la que estamos pasando los conjuntos de datos X e Y_train. Estamos pasando el tamaño del lote, la elección del tamaño del lote es 64 y 128.

model.fit (X_train, Y_train ,

    batch_size = {{choice ([64, 128])}},

    nb_epoch = 1,

    verbose = 2,

    validation_data = (X_test, Y_test))

Estamos pasando el número de épocas para la propagación hacia adelante y hacia atrás, y estamos configurando el detallado (verbose) en 2. También estamos pasando otro argumento importante en forma de datos de validación, que se utilizarán para validar el modelo de red neuronal. Los datos de validación que hemos especificado son los conjuntos de datos X e Y_test.

Después de validar el modelo, evaluaremos el modelo y el resultado de la evaluación que estamos usando es la puntuación y la precisión. Estamos usando la función evaluar a la que le estamos pasando los conjuntos de datos X e Y_test seguidos por el detallado que se establece en 0.

score, acc = model.evaluate (X_test, Y_test, verbose = 0)

Hemos establecido verbose en 0 ya que no queremos ningún resultado adicional. Finalmente, imprimimos la precisión de la prueba y devolvemos el factor de pérdida, el estado y el modelo.

print ('Exactitud de la prueba:', acc)

return {'loss': -acc, 'status': STATUS_OK, 'model': model}

Tenemos que asegurarnos de que estamos especificando valores adecuados. Por ejemplo, hemos especificado menos precisión –acc para el factor de pérdida, STATUS_OK para el modelo de estado, y model para el nombre de nuestro modelo de red neuronal. 

Hemos definido nuestra red neuronal, hemos compilado el modelo y hemos aplicado los conjuntos de entrenamiento junto con los datos de validación para asegurar que el modelo esté validado y probado.

Para ejecutar el modelo, hyperas proporciona la función optim.minimize.

appropiate_run, appropiate_model = optim.minimize (model = model,

data = data,

max_evals = 10,

algo = tpe.suggest,

notebook_name = 'nombre_notebook_de_jupyter', #ojo, esto es importante

trial = Trials ())

Tenemos que pasar el modelo, los datos, el número máximo de evaluaciones que queremos realizar, y el algoritmo que queremos utilizar, que en este caso se sugiere. También tenemos que pasar el nombre del cuaderno, que es el mismo que el del archivo. Y finalmente, también tenemos que aprobar los ensayos, lo que indica el número de ensayos que se realizarán para el modelo actual, con el fin de proporcionar un modelo adecuado y un resultado de ejecución adecuado.

Tras la ejecución, se nos proporcionan ciertos mensajes de registro de salida. Navegaremos más hacia abajo para explorar los resultados del modelo. Podemos observar que el modelo se entrenó con 60.000 muestras y ha utilizado otras 10.000 muestras para su validación. Se ejecutó una sola iteración y se nos proporciona el tiempo que tomó completar la ejecución, seguido del factor de pérdida, precisión, pérdida de validación y precisión de validación.

El resultado final que obtenemos es la precisión de la prueba. Obtendremos 10 resultados de precisión de prueba diferentes, ya que hemos especificado 10 evaluaciones en la celda de código.

Tenemos que esperar a que se completen las validaciones antes de poder observar el resultado final. Se nos proporciona la precisión de la prueba final, que es de 0,96. Se ejecutaron diez de cada diez épocas de validación.

La salida también incluye el mejor factor de pérdida y el tiempo que tomó completar la validación.

El resultado final es el resultado de la selección de hiperparámetros y el ajuste que facilitamos usando hyperas cuando estábamos ejecutando el modelo de red neuronal. Podemos seleccionar diferentes hiperparámetros o ajustar las selecciones de hiperparámetros existentes. Por ejemplo, podemos cambiar las evaluaciones máximas, podemos cambiar el número de épocas, incluso podemos cambiar el tamaño del lote y ejecutar el modelo. Podemos continuar este proceso hasta q