# ## Profesores
# 1. Alvaro Mauricio Montenegro Díaz, ammontenegrod@unal.edu.co
# 2. Daniel Mauricio Montenegro Reyes, dextronomo@gmail.com
# 3. Campo Elías Pardo Turriago, cepardot@unal.edu.co
# ## Asesora Medios y Marketing digital
#
# 4. Maria del Pilar Montenegro, pmontenegro88@gmail.com
# ## Asistentes
# 5. Oleg Jarma, ojarmam@unal.edu.co
# 6. Laura Lizarazo, ljlizarazore@unal.edu.co
# ## Contenido
# * [Introducción](#Introducción)
# * [Importa módulos](#Importa-módulos)
# * [Funciones de activación](#Funciones-de-activación)
# * [El conjunto de datos Iris](#El-conjunto-de-datos-Iris)
# * [Lectura de datos](#Lectura-de-datos)
# * [Preprocesamiento](#Preprocesamiento)
# * [Crea el modelo usando la API funcional](#Crea-el-modelo-usando-la-API-funcional)
# * [Compila](#Compila)
# * [Entrena](#Entrena)
# * [Evaluación del modelo](#Evaluación-del-modelo)
# * [Predicciones](#Predicciones)
# * [Matriz de confusión](#Matriz-de-confusión)
#
#
# ## Introducción
# Eeta lección está dedicada a un modelo de clasificación con mútliples categorías, que corresponde a la generalización natural del modelo logístico.
#
# * Practicaremos la codificación *one-hot* para los datos de salida.
# * También usaremos la API funcional de tf.keras, que es una forma de programación maś flexible y poderosa que el modelo Sequential
# * Usaremos las funciones *relu* para capas intermedias y entrada y la función de activación *softmax* para la salida, debido a que se tienen varias clases.
# ## Importa módulos
# Usaremos las bibliotecas
# * *seaborn* para gráficas un poco más elegantes
# * *sklearn* para utilidades de estandarizacion de datos y matriz de confusión
#
# Puede usar las siguientes instrucciones para isntalr desde la consola.
# In[199]:
# !conda install -c anaconda seaborn
# !conda install -c intel scikit-learn
# In[200]:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import tensorflow as tf
#
from tensorflow.keras.models import Model
#
from tensorflow.keras.layers import Dense, Input, Activation, Dropout
#
from tensorflow.keras.utils import to_categorical
from tensorflow.keras.utils import plot_model
#
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import confusion_matrix
#
#from sklearn import KFold
print("Versión de Tensorflow:", tf.__version__)
# ## Funciones de activación
# ### Relu
# Dada la salida del sumador digamos $y=\mathbf{w}'\mathbf{x} +b$, la función de activación *relu* esta definida por
#
# $$
# \text{relu}(y) = \begin{cases} &0, \text{ si } y\le 0,\\
# &y, \text{ en otro caso } \end{cases}
# $$
#
#
# ### Softmax
#
# Dados los valores $x_1,\ldots, x_n$ la función *softmax * es definida por
#
# $$
# \text{softmax}(x_i) = \frac{e^{x_i}}{\sum_{j=1}^{n} e^{x_j}}
# $$
#
# Es decir, *softmax* transforma los valores en un función de probabilidad.
# ## El conjunto de datos Iris
#
# Este conjunto de datos fue introducido por sir [Ronald Fisher]()
# ## Lectura de datos y primera vista de los datos
# Bajamos los datos de Internet usando *tf.keras.utils* y luego los cargamos en dataframes de Python.
# In[201]:
# nombres de las columnas de los datos
col_names = ['SepalLength', 'SepalWidth', 'PetalLength', 'PetalWidth', 'Species']
target_dimensions = ['Setosa', 'Versicolor', 'Virginica']
# lee los datos
training_data_path = tf.keras.utils.get_file("iris_training.csv", "https://storage.googleapis.com/download.tensorflow.org/data/iris_training.csv")
test_data_path = tf.keras.utils.get_file("iris_test.csv", "https://storage.googleapis.com/download.tensorflow.org/data/iris_test.csv")
training = pd.read_csv(training_data_path, names=col_names, header=0)
test = pd.read_csv(test_data_path, names=col_names, header=0)
test.head()
# ## Pre-procesamiento
# La variable objetivo (target) tiene tres categorías. Usaremos la codificación one-hot para transformar las codificaciones en vectors binarios.
# ### Codificación one-hot
# In[202]:
y_train= pd.DataFrame(to_categorical(training.Species))
y_train.columns = target_dimensions
y_test = pd.DataFrame(to_categorical(test.Species))
y_test.columns = target_dimensions
# In[203]:
y_test
# ### Elimina columna Species del dataframe
# In[204]:
y_train_species = training.pop('Species')
#test.drop(['Species'], axis=1, inplace=True)
y_test_species = test.pop('Species') # extrae la columna y la coloca en y_test_species
#
#Si necesita subir al dataframe la recodificación use estas líneas
#training = training.join(y_train )
#test = test.join(y_test)
# ### Normaliza los features
# #### StandardScaler
# In[205]:
# crea el objeto StandardScaler
scaler = StandardScaler()
# Ajusta los parámetros del scaler
scaler.fit(training)
print (scaler.mean_)
# escala training y test
x_train = scaler.transform(training)
x_test = scaler.transform(test)
# labels ( no requieren escalación)
# ## Crea el modelo usando la API funcional
# La API funcional de Keras es bastante más flexible y poderosa que el modelo Sequential
# In[266]:
# Con la API funcion se requiere la capa Input que transforma la entrada
# en un tensor de tensorflow directamente
#
inputs = Input(shape=(4,),name='capa_entrada')
#
# vamos construyendo capa por capa
x = Activation('relu')(inputs)
x = Dense(8, activation='relu',name='primera_capa_oculta')(x)
x = Dropout(0.2)(x)
x = Dense(16, activation='relu', name='segunda_capa_oculta')(x)
x = Dropout(0.2)(x)
outputs = Dense(3, activation='softmax', name='capa_salida')(x)
# Creamos ahora el modelo
model_iris = Model(inputs=inputs, outputs=outputs)
model_iris.summary()
plot_model(model_iris, to_file='../Imagenes/iris_model.png',
show_shapes=True)
# ## Compila
# In[267]:
model_iris.compile(optimizer='adam',
loss='categorical_crossentropy',
metrics=['accuracy']
)
# ## Entrena
# In[268]:
class PrintDot(tf.keras.callbacks.Callback):
def on_epoch_end(self, epoch, logs):
print('.', end='')
epochs = 200
# In[269]:
history = model_iris.fit(x_train, y_train,
batch_size= 16,
epochs= epochs,
validation_split=0.1, verbose=0,
callbacks=[PrintDot()])
print('\nHecho')
print('Resultados finales de pérdida y exactitud\n')
# presenta la última parte de la historia
hist = pd.DataFrame(history.history)
hist['epoch'] = history.epoch
hist.tail()
# ## Evaluación del modelo
# In[270]:
def plot_history(history):
hist = pd.DataFrame(history.history)
hist['epoch'] = history.epoch
plt.figure()
plt.xlabel('Epoch')
plt.ylabel('Pérdida')
plt.plot(hist['epoch'], hist['loss'],
label='Pérdida entrenamiento')
plt.plot(hist['epoch'], hist['val_loss'],
label = 'Pérdida validación')
plt.ylim([0,2])
plt.legend()
plt.figure()
plt.xlabel('Epoch')
plt.ylabel('Exactitud')
plt.plot(hist['epoch'], hist['accuracy'],
label='Exactitud entrenamiento')
plt.plot(hist['epoch'], hist['val_accuracy'],
label = 'Exactitud Validación')
plt.ylim([0,1])
plt.legend()
plt.show()
plot_history(history)
# ## Predicciones
# In[271]:
# Predicting the Test set results
y_pred = model_iris.predict(x_test)
y_pred_c = np.argmax(y_pred, axis=1)
# ## Matriz de confusión
# In[272]:
cm = confusion_matrix(y_test_species, y_pred_c)
# In[273]:
print("Our accuracy is {}%".format(((cm[0][0] + cm[1][1]+ cm[2][2])/y_test_species.shape[0])*100))
# In[274]:
sns.heatmap(cm,annot=True)
plt.savefig('h.png')
# [Regresar al inicio](#Contenido)
# ## Exploración interna de la red
# ### Cálculo de la salida de los datos de entrenamiento
# In[275]:
inputs = x_train
outputs = model_iris(inputs)
outputs.numpy().round(2)[:10]
# ### Extrae la segunda capa oculta para estos datos
# In[217]:
# modelo Sequential
#layer_2 = tf.keras.models.Model(
# inputs=model_iris.inputs,
# outputs=model_iris.get_layer(name='segunda_capa_oculta').output,
#)
# In[276]:
# API funcional
# 1. crea un nuevo modelo
# 2. Compila
# 3. Predice
inputs = x_train
model = Model(model_iris.input, model_iris.get_layer(name='segunda_capa_oculta').output)
model.compile()
output = model.predict(inputs)
# In[277]:
output.shape
# ### Crea tabla de datos para hacer un gráfico tsne
# In[278]:
plot_data = np.hstack([output, np.array(y_train_species).reshape(y_train_species.shape[0],1)])
plot_data = pd.DataFrame(plot_data)
# In[279]:
plot_data
# ### Crea gráfico tsne
# In[280]:
from sklearn.manifold import TSNE
# reduce dimensionalidad con t-sne
tsne = TSNE(n_components=2, verbose=1, perplexity=50, n_iter=1000, learning_rate=200)
tsne_results = tsne.fit_transform(output)
# In[251]:
labels = [target_dimensions[i] for i in y_train_species]
#['Setosa', 'Versicolor', 'Virginica']
# In[281]:
# visualiza con seaborn
df_tsne = pd.DataFrame(tsne_results, columns=['x', 'y'])
df_tsne['label'] = labels
sns.lmplot(x='x', y='y', data=df_tsne, hue='label', fit_reg=False)
# ### Ejercicio
# 1. Reescriba y reentren la red en Pytorch.
# 1. Investigue como extraer la capa oculta en Pytorch
# 1. Haga un gráfico TSNE para los datos originales
# 1. Haga un reducción ACP y haga el correspondiente gráfico
#
# ¿Cuáles son sus conclusiones?