sábado, 20 de febrero de 2021
AWS in a nutshell 10: Despliegue de una Instancia EC2
sábado, 13 de febrero de 2021
Instalar TensorFlow en un entorno virtual de Windows (Corrige warning is not on PATH)
Hace un tiempo publiqué cómo crear un entorno Virtual para Machine Learning e instalar TensorFlow sobre él.
Pero cuando lo intenté en otro equipo, falló la actualización de pip. Aquí reproduzco un camino alternativo por si la primera opción falla, igual que me sucedió a mi.
Siguiendo las instrucciones iniciales, para actualizar pip a la última versión tecleamos en el editor de Anaconda
Python –m pip install –user –U pip
Pero nos devuelve un warning, si lo ignoramos y continuamos, TensorFlow no se instala correctamente.
Nos devuelve un WARNING diciendo: ‘The scripts pip.exe, pip3.7.exe and pip3.exe are installed in ‘C:\Users\[mi usuario]\AppData\Roaming\Python\Python37\Scripts’ wich is not on PATH’
Para solucionar este warning tenemos que copiar en el portapapeles la dirección indicada
"C:\Users\[mi usuario]\AppData\Roaming\Python\Python37\Scripts"
Vamos al explorador de Windows y pulsamos sobre ‘Este equipo’ con el botón derecho del ratón, nos abre un diálogo y elegimos propiedades y configuración avanzada del sistema.
También podemos acceder desde Panel de control -> Sistema y seguridad -> sistema
Y pulsamos sobre el botón 'Variables de entorno'.
Se nos abre una pantalla con las variables de entorno, en la caja inferior de variables de sistema pulsamos sobre nueva y en la caja de Nombre de variable, pegamos la ruta copiada anteriormente en el portapapeles. Y en el valor de la variable ponemos punto y coma “;”aceptamos y continuamos con el proceso de instalar TensorFlow.
Creamos el Nuevo entorno virtual
Volvemos al entorno con cd..
Antes de traer Tensorflow actualizamos
python.exe -m pip install --upgrade pip
y finalmente instalamos TensorFlow
python -m pip install -U tensorflow
Ya podemos ejecutar un cuaderno Jupyter desde nuestro entorno virtual (tecleamos Jupyter en inicio de windows) para probar si se ha instalado correctamente, nos debe devolver la versión de TensorFlow al escribir
import tensorflow as tf
from tensorflow import keras
tf.__version__
keras.__version__
sábado, 6 de febrero de 2021
AWS in a nutshell 9: Estrategias de desarrollo
9.1 Framework bien diseñado WA de AWS
Un Framework bien diseñado de AWS permite medir cargas de trabajo de software, la arquitectura de nuestras cargas de trabajo, y se encuadra en las buenas prácticas de AWS. La idea es que buscamos una mejora constante. Esto significa analizar la excelencia operativa, la optimización de costos, la confiabilidad, la eficiencia del desempeño y, por supuesto, la seguridad. Las herramientas de AWS bien diseñada, o WA, está disponible directamente en la Consola de administración de AWS para medir las cargas de trabajo de aplicaciones existentes y luego documentarlas. El primer pilar de un marco bien diseñado es la excelencia operativa.
9.2 Aplicaciones web de varios niveles
Una aplicación web de varios niveles es aquella que consta esencialmente de varias capas para cada parte principal de una aplicación. Como ejemplo, si tenemos un dispositivo cliente que se conecta a una aplicación web. Esa conexión podría establecerse con un equilibrador de carga que se encuentra entre el cliente y la aplicación. Lo que seguiría después, es que el balanceador de carga enrute las solicitudes del cliente a un servidor backend activo o receptivo que admita la interfaz de la aplicación. Eso se llamaría el nivel de presentación.
9.3 Integración e implementación continuas
Actualmente la mayoría de las organizaciones tienen algún tipo de presencia en la web, y ahí es donde la integración y entrega continuas, o CI y CD, realmente pueden ayudar, aunque no está vinculado específicamente a una presencia web o una aplicación web para el caso. En realidad, se trata de DevOps, lo que realmente significa que estamos combinando el desarrollo de soluciones de software y el lado operativo, que incluirá la implementación y el parcheo a lo largo del tiempo. Por lo tanto, combina desarrollo de software, operación de software y mantenimiento de software.
9.4 Soluciones AWS CI / CD
Para los desarrolladores, una parte importante de los servicios web de Amazon es saber cuándo utilizar los servicios disponibles para desarrolladores, para eso están las soluciones AWS CI / CD, CI y CD, lo que significa Integración continua e Implementación continua. El principal beneficio de las soluciones CI / CD es un tiempo de comercialización más rápido, por así decirlo, para las soluciones de software, y eso siempre es importante. Tener una solución implementada más temprano que tarde siempre es beneficioso para una organización. La primera solución es AWS CodePipeline, luego tenemos AWS CodeCommit, AWS CodeBuild. y finalmente AWS CodeDeploy.
9.5 API de AWS
Los desarrolladores de software estarán familiarizados con las API o interfaces de programación de aplicaciones. Las API tienen un ciclo de vida específico. El ciclo de vida de la API comienza cuando el desarrollador crea o define una API. Por ejemplo, en Amazon Web Services, un equipo en algún momento tuvo que crear la API de S3 para permitir el acceso programático al entorno de S3. La siguiente fase del ciclo de vida de la API es implementar la solución, lo que generalmente significa ponerla a disposición en un servidor.
9.6 Microservicios y desacoplamiento
El microservicio no es una oferta de servicios de AWS. En cambio, es más un enfoque o estrategia de desarrollo de software. Con microservicios, estamos hablando de desarrollo de software modular. Entonces, en lugar de crear una aplicación gigante, los equipos de desarrollo pueden trabajar juntos para crear funciones específicas de tareas o API, o incluso contenedores aislados que contienen componentes de software específicos. Con un entorno de microservicio, cada módulo o microservicio puede comunicarse con otros a través de la red. También podemos habilitar el acoplamiento suelto. Así es realmente cómo se construye el código.
9.7 Servicio de notificación simple
El servicio de notificación simple, o SNS, en Amazon Web Services proporciona una forma de publicar notificaciones o mensajes. También proporciona una forma para que otros recursos se suscriban a los mensajes que se publican. La forma en que esto funciona con SNS es que permite el desacoplamiento de software, esto significa que se permite el uso de microservicios para suscribirse a mensajes que podrían ser publicados por otros componentes de software. La parte de desacoplamiento significa que los componentes de software, no tienen que estar disponibles en la red al mismo tiempo y no tienen que estar ejecutándose al mismo tiempo necesariamente para intercambiar esos mensajes.
Para acceder a ellos desde la Consola de AWS escribimos
SNS → Escribimos nombre de topic y botón Next
9.8 Servicio de cola simple
En Amazon Web Services, Simple Queue Service, o SQS, se utiliza como mecanismo para microservicios. Ahora no tiene por qué ser así, pero los microservicios se benefician de esto cuando el censo de los microservicios que son software modular o componentes de código, podemos pensar en ellos como fragmentos de código enfocados, que juntos muchos microservicios pueden formar una sola aplicación.
Consola → SQS -> get started now
sábado, 30 de enero de 2021
Construyendo una red neuronal de regresión utilizando la API Sequential de Keras
Vamos a utilizar la API Sequential de Keras para crear una red neuronal, secuencial, entrenarla y evaluarla. Podemos utilizar esta red neuronal de regresión para hacer predicciones. Para poder trabajar tendremos que importar las librerías de tensorflow, numpy y keras.
import tensorflow as tf
import numpy as np
from tensorflow import keras
Antes de nada para tener un dataset de ejemplo sobre el que trabajar vamos a descargar un dataset de Scikit-Learn llamado fetch_california_housing() con datos numéricos de inmuebles de California.
from sklearn.datasets import fetch_california_housing
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
housing = fetch_california_housing()
X_train_full, X_test, y_train_full, y_test = train_test_split(housing.data, housing.target, random_state=42)
X_train, X_valid, y_train, y_valid = train_test_split(X_train_full, y_train_full, random_state=42)
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_valid = scaler.transform(X_valid)
X_test = scaler.transform(X_test)
np.random.seed(42)
tf.random.set_seed(42)
Hacer predicciones con regresión es bastante similar a hacerlo con clasificación, una de las diferencias, es el hecho de que la capa de salida es una única neurona (si sólo deseamos predecir un único valor), otra que utilizamos la función de activación relu, y finalmente que la función de pérdida es el error cuadrático medio. Para este caso, como el dataset tiene bastante ruido, utilizaremos una capa oculta para evitar el sobreentrenamiento.
A continuación la creación de la red neuronal con la API de Keras.
model = keras.models.Sequential([
keras.layers.Dense(30, activation="relu", input_shape=X_train.shape[1:]),
keras.layers.Dense(1)
])
model.compile(loss="mean_squared_error", optimizer=keras.optimizers.SGD(lr=1e-3))
history = model.fit(X_train, y_train, epochs=20, validation_data=(X_valid, y_valid))
mse_test = model.evaluate(X_test, y_test)
X_new = X_test[:3]
y_pred = model.predict(X_new)
Como podemos ver, la API Sequential es bastante fácil de utilizar, pero si queremos crear redes neuronales con topologías más complejas que la secuencial, podemos utilizar la API Functional.
Construyendo redes neuronales complejas utilizando la API Functional de Keras
En este caso construiremos una red neuronal con capas ocultas y un atajo de este estilo.
El código con la API de keras será como este.
entrada = keras.layers.Input(shape=X_train.shape[1:])
oculta1 = keras.layers.Dense(30, activation="relu")(entrada)
oculta2 = keras.layers.Dense(30, activation="relu")(oculta1)
concat = keras.layers.concatenate([entrada, oculta2])
salida = keras.layers.Dense(1)(concat)
model = keras.models.Model(inputs=[entrada], outputs=[salida])
Podemos ver un esquema de la red neuronal creada
model.summary()
Veamos lo que significan las líneas de código
En primer lugar necesitamos crear un objeto entrada, lo creamos especificando el tipo de modelo que queremos, incluyendo su forma y su tipo.
Después creamos una capa oculta densa con 30 neuronas utilizando la activación ReLU y le pasamos su entrada como si fuera una función, en nuestro caso (entrada).
Creamos una segunda capa oculta y la usamos de nuevo como si fuera una función, pasandole la salida de la primera capa oculta.
Después creamos la capa concatenada y una vez más la usamos como si fuera una función, concatenando la entrada y la salida de la segunda capa oculta en los parámetros de la función.
Creamos la capa de salida con una única neurona y sin función de activación y la usamos como una función pasandole como parámetro la salida de la capa de concatenación.
Finalmente creamos el modelo Keras, especificando cuales son sus entradas y sus salidas.
Una vez creado el modelo procedemos como siempre, compilándolo, evaluándolo y utilizándolo para hacer predicciones.
model.compile(loss="mean_squared_error", optimizer=keras.optimizers.SGD(lr=1e-3))
history = model.fit(X_train, y_train, epochs=20,
validation_data=(X_valid, y_valid))
mse_test = model.evaluate(X_test, y_test)
y_pred = model.predict(X_new)
Pero ¿Que sucede si lo que queremos es enviar un subset de datos por el atajo y el otro por el camino habitual? Tal y como se muestra en el esquema.
entrada_A = keras.layers.Input(shape=[5], name="atajo")
entrada_B = keras.layers.Input(shape=[6], name="profunda")
oculta1 = keras.layers.Dense(30, activation="relu")(entrada_B)
oculta2 = keras.layers.Dense(30, activation="relu")(oculta1)
concat = keras.layers.concatenate([entrada_A, oculta2])
salida = keras.layers.Dense(1, name="salida")(concat)
model = keras.models.Model(inputs=[entrada_A, entrada_B], outputs=[salida])
El código es muy similar al anterior, sólo que ahora en las entradas hemos añadido entrada_A y entrada_B ahora vamos a compilarlo, pero en vez de pasarle una sola matriz de entrada X_train le pasaremos dos matrices, X_train_A y X_train_B, igual deberemos hacer con X_valid para la evaluación y X_text para la predcción.
model.compile(loss="mse", optimizer=keras.optimizers.SGD(lr=1e-3))
X_train_A, X_train_B = X_train[:, :5], X_train[:, 2:]
X_valid_A, X_valid_B = X_valid[:, :5], X_valid[:, 2:]
X_test_A, X_test_B = X_test[:, :5], X_test[:, 2:]
X_new_A, X_new_B = X_test_A[:3], X_test_B[:3]
history = model.fit((X_train_A, X_train_B), y_train, epochs=20,
validation_data=((X_valid_A, X_valid_B), y_valid))
mse_test = model.evaluate((X_test_A, X_test_B), y_test)
y_pred = model.predict((X_new_A, X_new_B))
sábado, 23 de enero de 2021
Clasificador de imágenes con una red neuronal Keras
Ya hemos comentado aquí lo que es una red neuronal, ahora vamos a descargar el dataset MNIST de prendas de ropa que contiene 60.000 imágenes de prendas de vestir en escala de grises de 28x28 pixels. El dataset contiene 10 categorías o clases de prendas de vestir. Previamente tendremos instalado en nuestro equipo un entorno virtual de Anaconda con Tensorflow instalado (enlace), o podemos optar también por ejecutar las instrucciones en la nube con Colaboratory.
Hecho esto importamos Tensorflow y Keras
import tensorflow as tf
from tensorflow import keras
Cargamos el dataset de Moda de MNIST
fashion_mnist = keras.datasets.fashion_mnist
(X_train_full, y_train_full), (X_test, y_test) = fashion_mnist.load_data()
Si hacemos
X_train_full.shape
Nos devuelve (60000, 28, 28) lo que significa que contiene 60.000 imágenes de 28 por 28 pixels.
Dividimos el dataset de entrenamiento completo en un dataset de validación y otro de entrenamiento (más pequeño). También escalamos las intensidades de píxeles para dejarlas dentro del rango 0-1, como sus valores van de 0 a 255 las dividimos entre 255, esto hace que pasen a ser valores flotantes.
X_valid, X_train = X_train_full[:5000] / 255, X_train_full[5000:] / 255
y_valid, y_train = y_train_full[:5000], y_train_full[5000:]
X_test = X_test / 255
Vamos a mostrar una imagen del conjunto
plt.imshow(X_train[23], cmap="binary")
plt.axis('off')
plt.show()
En este caso hemos tomado al azar el número 23 que ha resultado ser una bota.
class_names = ["Camiseta", "Pantalones", "Jersey", "Vestido", "Abrigo","Sandalia", "Camisa", "Deportivas", "Bolso", "Bota"]
Por ejemplo elegimos la etiqueta de nuestra imagen 23.
class_names[y_train[23]]
En nuestro caso está clasificada como deportivas.
El dataset de validación contiene 5000 imágenes y el dataset de prueba contiene 10000 imágenes:
X_valid.shape
X_test.shape
Crear un modelo usando la API Secuencial
Ahora vamos a construir una red neuronal con dos capas ocultas
model = keras.models.Sequential()
model.add(keras.layers.Flatten(input_shape=[28, 28]))
model.add(keras.layers.Dense(300, activation="relu"))
model.add(keras.layers.Dense(100, activation="relu"))
model.add(keras.layers.Dense(10, activation="softmax"))
La primera fila crea el modelo secuencial, la segunda línea crea una capa de entrada aplanada (Flatten), su cometido es convertir cada imagen de 28x28 pixels en un array de una dimensión y 784 bits de tamaño, no tiene parámetros simplemente realiza un preprocesamiento.
La siguiente fila, crea una capa densa de 300 neuronas ( o perceptrones) y utilizará la función ReLU como función de activación. Cada capa densa gestiona su propia matriz de pesos y contiene todas las conexiones con la capa de entrada, también gestiona los sesgos de cada neurona (Bias).
La siguiente línea añade una segunda capa de 100 neuronas. Finalmente añadimos una capa de salida de 10 neuronas, una por clase. Y utiliza softmax como función de activación pues las 10 clases son exclusivas.
En vez de añadir las capas una por una, podemos pasar una lista de las capas al crear el modelo secuencial.
model = keras.models.Sequential([
keras.layers.Flatten(input_shape=[28, 28]),
keras.layers.Dense(300, activation="relu"),
keras.layers.Dense(100, activation="relu"),
keras.layers.Dense(10, activation="softmax")
])
Si queremos saber las capas que tiene nuestro modelo podemos hacer
model.layers
También podemos ver un pequeño resumen de nuestra red poniendo
model.summary()
Y para ver un esquema
keras.utils.plot_model(model, "mnist_modelo_prendas_ropa.png", show_shapes=True)
Para obtener el nombre de la primera capa oculta
hidden1 = model.layers[1]
hidden1.name
Esta devuelve true si la capa es oculta
model.get_layer(hidden1.name) is hidden1
Todos los parámetros de una capa pueden ser accedidos utilizando los métodos get_weights() y set_weghts() si la capa es densa, incluye los pesos de las conexiones y los términos de sesgo (bias).
weights, biases = hidden1.get_weights()
weights
weights.shape
biases
biases.shape
Compilando el modelo
Después de crear nuestro modelo necesitamos compilarlo, para ello llamamos al método compile
model.compile(loss="sparse_categorical_crossentropy",
optimizer="sgd",
metrics=["accuracy"])
Para especificar la función de pérdida y el optimizador a utilizar. Opcionalmente podemos especificar una lista de métricas extra para computar durante el entrenamiento y evaluación.
hemos utilizado sparse_categorical_crossentropy porque tenemos etiquetas escasas (una por instancia) y las clases son exclusivas. Respecto al optimizador sgd significa que vamos a entrenar el modelo utilizando Descenso de gradiente estocástico simple (Stochastic Gradient Descent). Finalmente debido a que es un clasificador, es útil medir su exactitud "accuracy" durante su entrenamiento y evaluación.
Entrenando y evaluando el modelo
Ahora el modelo está preparado para ser entrenado, para ello llamamos al método fit().
history = model.fit(X_train, y_train, epochs=30,
validation_data=(X_valid, y_valid))
Para entrenar el modelo, le pasamos las características de entrada X_train y las clases objetivo y_train así como el número de épocas a entrenar, también le pasamos el set de validación aunque esto último es opcional.
Keras mide la perdida y otras métricas del modelo al final de cada época, lo cual es muy útil para ver cómo se va entrenando el modelo.
Para ver los diferentes parámetros del entrenamiento
history.params
print(history.epoch)
history.history.keys()
Si creamos un diccionario con estos valores, podemos visualizar las gráficas del entrenamiento.
import pandas as pd
pd.DataFrame(history.history).plot(figsize=(8, 5))
plt.grid(True)
plt.gca().set_ylim(0, 1)
save_fig("curvas_de_aprendizaje_keras")
plt.show()
Una vez estamos satisfechos con la exactitud del modelo podemos evaluar el set para estimar el error antes de desplegarlo en producción. Podemos hacerlo fácilmente con el método evaluate().
model.evaluate(X_test, y_test)
313/313 [==============================] - 0s 2ms/step
- loss: 0.3364 - accuracy: 0.8812
[0.33643999695777893, 0.8812000155448914]
Utilizando el modelo para hacer predicciones
A continuación utilizaremos el método predict() para hacer predicciones sobre nuevas instancias. Como no tenemos nuevas instancias reales, vamos a utilizar las cuatro primeras instancias del dataset
X_new = X_test[:4]
y_proba = model.predict(X_new)
y_proba.round(2)
array([[0. , 0. ,
0. , 0.
, 0. , 0. , 0. ,
0.01, 0. , 0.99],
[0.
, 0. , 1. , 0. ,
0. , 0.
, 0. , 0. , 0. ,
0. ],
[0.
, 1. , 0. , 0. ,
0. , 0.
, 0. , 0. , 0. ,
0. ],
[0.
, 1. , 0. , 0. ,
0. , 0.
, 0. , 0. , 0. ,
0. ]],
dtype=float32)
Para cada instancia estima una probabilidad por clase entre la 0 y la 9, para la primera instancia ha estimado una probabilidad de 0,99 a la clase 9 que es una bota, y 0,01 para la clase 7 que es deportivas. Lo mismo para el resto de instancias.
Si queremos obtener sólo un valor para la clase de mayor probabilidad, en vez del método predict() utilizaremos np.argmax().
y_pred =np.argmax(model.predict(X_new), axis=-1)
y_pred
array([9, 2, 1, 1])
para ver el significado de cada clase hacemos
np.array(class_names)[y_pred]
array(['Bota', 'Jersey', 'Pantalones', 'Pantalones'], dtype='<U10')
y para ver las imágenes
plt.figure(figsize=(7.2, 2.4))
for index, image in enumerate(X_new):
plt.subplot(1, 4, index + 1)
plt.imshow(image, cmap="binary", interpolation="nearest")
plt.axis('off')
plt.title(class_names[y_test[index]], fontsize=12)
plt.subplots_adjust(wspace=0.2, hspace=0.5)
save_fig('imagenes_predichas', tight_layout=False)
plt.show()