Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save RodolfoFerro/b9d1ed80179bd3ed949f96706c6b7b46 to your computer and use it in GitHub Desktop.
Save RodolfoFerro/b9d1ed80179bd3ed949f96706c6b7b46 to your computer and use it in GitHub Desktop.
Introducción a las redes neuronales convolucionales con TensorFlow y Keras
{
"nbformat": 4,
"nbformat_minor": 0,
"metadata": {
"colab": {
"name": "Introducción a las redes neuronales convolucionales con TensorFlow y Keras",
"provenance": [],
"collapsed_sections": [],
"include_colab_link": true
},
"kernelspec": {
"name": "python3",
"display_name": "Python 3"
},
"accelerator": "GPU"
},
"cells": [
{
"cell_type": "markdown",
"metadata": {
"id": "view-in-github",
"colab_type": "text"
},
"source": [
"<a href=\"https://colab.research.google.com/gist/RodolfoFerro/b9d1ed80179bd3ed949f96706c6b7b46/introducci-n-a-las-redes-neuronales-convolucionales-con-tensorflow-y-keras.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "R6jO_1gISKxk"
},
"source": [
"# Introducción a las redes neuronales convolucionales con TensorFlow y Keras\n",
"\n",
"> **Rodolfo Ferro** <br>\n",
"> Google Dev Expert en ML, 2022.\n",
"\n",
"## Contenidos\n",
"\n",
"#### **Sección III**\n",
"\n",
"1. **Bases:** Aprendizaje de neuronas\n",
"2. **Código:** Entrenamiento de una neurona\n",
"3. **Bases:** Conceptos importantes\n",
"4. **Bases:** Imágenes\n",
"\n",
"#### **Sección IV**\n",
"\n",
"4. **Bases:** El dataset de modas\n",
"5. **Código:** Preparación de datos\n",
"6. **Código:** Creación del modelo multicapa (MLP)\n",
"7. **Código:** Entrenamiento del modelo\n",
"8. **Código:** Evaluación y predicción\n",
"\n",
"#### **Sección V**\n",
"\n",
"9. **Bases:** Convoluciones\n",
"10. **Código:** Creación del modelo convolucional (CNN)\n",
"11. **Código:** Entrenamiento del modelo\n",
"12. **Código:** Evaluación y predicción\n",
"\n",
"\n",
"13. **Cierre:** Sesión de preguntas y respuestas"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "xNVG2PnSEtQN"
},
"source": [
"## **Sección III**"
]
},
{
"cell_type": "markdown",
"source": [
"### Aprendizaje de neuronas\n",
"\n",
"Veamos cómo se puede entrenar una sola neurona para hacer una predicción.\n",
"\n",
"Para este problema construiremos un perceptrón simple, como el propuesto por McCulloch & Pitts, usando la función sigmoide.\n",
"\n",
"#### **Planteamiento del problema:**\n",
"\n",
"Queremos mostrarle a una neurona simple un conjunto de ejemplos para que pueda aprender cómo se comporta una función. El conjunto de ejemplos es el siguiente:\n",
"\n",
"- `(1, 0)` debería devolver `1`.\n",
"- `(0, 1)` debe devolver `1`.\n",
"- `(0, 0)` debería devolver `0`.\n",
"\n",
"Entonces, si ingresamos a la neurona el valor de `(1, 1)`, debería poder predecir el número `1`.\n",
"\n",
"> ¿Puedes adivinar la función?\n",
"\n",
"#### ¿Que necesitamos hacer?\n",
"\n",
"Programar y entrenar una neurona para hacer predicciones.\n",
"\n",
"En concreto, vamos a hacer lo siguiente:\n",
"\n",
"- Construir la clase y su constructor.\n",
"- Definir la función sigmoidea y su derivada\n",
"- Definir el número de épocas para el entrenamiento.\n",
"- Resolver el problema y predecir el valor de la entrada deseada"
],
"metadata": {
"id": "2k4ZBY7drHpQ"
}
},
{
"cell_type": "code",
"source": [
"import numpy as np\n",
"\n",
"\n",
"class sigmoid_neuron():\n",
" def __init__(self, n):\n",
" \"\"\"Constructor of the class.\"\"\"\n",
" np.random.seed(123)\n",
" self.synaptic_weights = None # TODO. Use np.random.random((n, 1)) to gen values in (-1, 1)\n",
"\n",
" def __sigmoid(self, x):\n",
" \"\"\"Sigmoid function.\"\"\"\n",
" # TODO.\n",
" pass\n",
"\n",
" def __sigmoid_derivative(self, x):\n",
" \"\"\"Derivative of the Sigmoid function.\"\"\"\n",
" # TODO.\n",
" pass\n",
"\n",
" def train(self, training_inputs, training_output, iterations):\n",
" \"\"\"Training function.\"\"\"\n",
" for iteration in range(iterations):\n",
" output = self.predict(training_inputs)\n",
" error = training_output.reshape((len(training_inputs), 1)) - output\n",
" adjustment = np.dot(training_inputs.T, error *\n",
" self.__sigmoid_derivative(output))\n",
" self.synaptic_weights += adjustment\n",
"\n",
" def predict(self, inputs):\n",
" \"\"\"Prediction function.\"\"\"\n",
" return self.__sigmoid(np.dot(inputs, self.synaptic_weights))"
],
"metadata": {
"id": "2NKx40hxqmo4"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"source": [
"### Generando las muestras\n",
"\n",
"Ahora podemos generar una lista de ejemplos basados en la descripción del problema."
],
"metadata": {
"id": "Ym_oEzbhxYKT"
}
},
{
"cell_type": "code",
"source": [
"# Training samples:\n",
"input_values = [] # TODO. Define the input values as a list of tuples.\n",
"output_values = [] # TODO. Define the desired outputs.\n",
"\n",
"training_inputs = np.array(input_values)\n",
"training_output = np.array(output_values).T.reshape((3, 1))"
],
"metadata": {
"id": "BYW9aYSCxc1q"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"source": [
"### Entrenando la neurona\n",
"\n",
"Para hacer el entrenamiento, primero definiremos una neurona. De forma predeterminada, contendrá pesos aleatorios (ya que aún no se ha entrenado):"
],
"metadata": {
"id": "DJUYV8H-xf7Y"
}
},
{
"cell_type": "code",
"source": [
"# Initialize Sigmoid Neuron:\n",
"neuron = sigmoid_neuron(2)\n",
"print(\"Initial random weights:\")\n",
"neuron.synaptic_weights"
],
"metadata": {
"id": "cThkcQGMxrX8"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"source": [
"# TODO.\n",
"# We can modify the number of epochs to see how it performs.\n",
"epochs = 0\n",
"\n",
"# We train the neuron a number of epochs:\n",
"neuron.train(training_inputs, training_output, epochs)\n",
"print(\"New synaptic weights after training: \")\n",
"neuron.synaptic_weights"
],
"metadata": {
"id": "WnuCP6eHxtQk"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"source": [
"### Haciendo predicciones"
],
"metadata": {
"id": "7vPb5a65x0bA"
}
},
{
"cell_type": "code",
"source": [
"# We predict to verify the performance:\n",
"one_one = np.array((1, 1))\n",
"print(\"Prediction for (1, 1): \")\n",
"neuron.predict(one_one)"
],
"metadata": {
"id": "SrYM3ODKxwvD"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "Rtpuj0PBqWYc"
},
"source": [
"## **Sección IV**"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "1Z7JrTygMDSx"
},
"source": [
"### El dataset de modas\n",
"\n",
"Comencemos importando TensorFlow."
]
},
{
"cell_type": "code",
"metadata": {
"id": "LPB4nBh8MFDm"
},
"source": [
"import tensorflow as tf\n",
"print(tf.__version__)"
],
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "p65n1ePSMYm8"
},
"source": [
"Los datos de Fashion MNIST están disponibles directamente en la API de conjuntos de datos de `tf.keras`. Los cargas así:"
]
},
{
"cell_type": "code",
"metadata": {
"id": "Wgked3UaMJW4"
},
"source": [
"fashion_mnist = tf.keras.datasets.fashion_mnist"
],
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "UsEGBNwrMSac"
},
"source": [
"Llamar a `load_data` en este objeto nos dará dos conjuntos con los valores de entrenamiento y prueba para los gráficos que contienen las prendas y sus etiquetas."
]
},
{
"cell_type": "code",
"metadata": {
"id": "1XdP6qF1MLR6"
},
"source": [
"(training_images, training_labels), (test_images, test_labels) = fashion_mnist.load_data()"
],
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "6c0eSrlvMs6H"
},
"source": [
"¿Cómo se ven estos valores?\n",
"\n",
"Imprimamos una imagen de entrenamiento y una etiqueta de entrenamiento para ver."
]
},
{
"cell_type": "code",
"metadata": {
"id": "3CdTltfNM0qF"
},
"source": [
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"np.set_printoptions(linewidth=200)\n",
"\n",
"\n",
"# Set index of image to be seen\n",
"img_index = 5999 # 6000 -1\n",
"\n",
"# Plot image\n",
"plt.imshow(training_images[img_index], cmap='gray')\n",
"plt.axis(False)\n",
"\n",
"print(\"Label:\", training_labels[img_index])\n",
"print(\"Matrix:\", training_images[img_index])"
],
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "CxfNdPU3NQge"
},
"source": [
"### Preparación de los datos\n",
"\n",
"Notarás que todos los valores están entre 0 y 255. Si estamos entrenando una red neuronal, por varias razones es más fácil si transformamos los valores para tratar todos con valores entre 0 y 1. Este proceso se llama **normalización**."
]
},
{
"cell_type": "code",
"metadata": {
"id": "vWoPQWCGNdnB"
},
"source": [
"training_images = training_images / 255.0\n",
"test_images = test_images / 255.0"
],
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "32Dx5PzgJ3gK"
},
"source": [
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"np.set_printoptions(linewidth=200)\n",
"\n",
"\n",
"# Set index of image to be seen\n",
"img_index = 3000 # 6000 -1\n",
"\n",
"# Plot image\n",
"plt.imshow(training_images[img_index], cmap='gray')\n",
"plt.axis(False)\n",
"\n",
"print(\"Label:\", training_labels[img_index])\n",
"print(\"Matrix:\", training_images[img_index])"
],
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "6QLVhw7SOCd8"
},
"source": [
"training_images[0].shape"
],
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "bTaT1RjyNjqV"
},
"source": [
"### Creación del modelo\n",
"\n"
]
},
{
"cell_type": "code",
"metadata": {
"id": "g-myY9JWNvtY"
},
"source": [
"mlp_model = tf.keras.models.Sequential([\n",
" tf.keras.layers.Flatten(), \n",
" # TODO. Dense -> 256, ReLU\n",
" # TODO. Dense -> 10, Softmax\n",
"])"
],
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "dwkxtrHdNvHg"
},
"source": [
"### Entrenamiento del modelo"
]
},
{
"cell_type": "code",
"metadata": {
"id": "F9LHH0f6N5Hi"
},
"source": [
"mlp_model.compile(\n",
" optimizer=tf.optimizers.SGD(),\n",
" loss='sparse_categorical_crossentropy',\n",
" metrics=['accuracy']\n",
")"
],
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"source": [
"model.summary()"
],
"metadata": {
"id": "tRaD1lDx7Du5"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "ybq9AzJiN8ZV"
},
"source": [
"mlp_model.fit(training_images, training_labels, epochs=3)"
],
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "cH9mfZMTN8_H"
},
"source": [
"### Evaluación del modelo"
]
},
{
"cell_type": "code",
"metadata": {
"id": "rHCV5BrAN-pq"
},
"source": [
"mlp_model.evaluate(test_images, test_labels)"
],
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "w-hQX4NNOd_D"
},
"source": [
"### Predicción\n"
]
},
{
"cell_type": "code",
"metadata": {
"id": "GaDFuXyROfZY"
},
"source": [
"import random\n",
"\n",
"test_index = random.randint(0, 10000 - 1)\n",
"\n",
"plt.imshow(test_images[test_index], cmap='viridis')\n",
"plt.axis(False)\n",
"\n",
"print(\"Label:\", test_labels[test_index])\n",
"input_image = np.reshape(test_images[test_index], (1, 784))\n",
"prediction = mlp_model.predict(np.expand_dims(input_image, axis=-1))\n",
"print(\"Prediction:\", np.argmax(prediction))"
],
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "RHA0nk24QEVz"
},
"source": [
"prediction"
],
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "3jLJvM0V1edu"
},
"source": [
"## **Sección V**"
]
},
{
"cell_type": "code",
"source": [
"import numpy as np\n",
"from scipy import misc\n",
"import matplotlib.pyplot as plt\n",
"\n",
"\n",
"# We load a sample image\n",
"img = misc.ascent()\n",
"\n",
"plt.imshow(img, cmap='gray')\n",
"plt.grid(False)\n",
"plt.axis('off')\n",
"plt.show()"
],
"metadata": {
"id": "B7Ke46U11KYN"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"source": [
"img_transformed = np.copy(img)\n",
"size_x = img_transformed.shape[0]\n",
"size_y = img_transformed.shape[1]"
],
"metadata": {
"id": "LQQzn0cO2EMW"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"source": [
"# Let's experiment with different values\n",
"\n",
"filter = [[1, 2, 1], [2, 4, 2], [1, 2, 1]]\n",
"# filter = [[-1, -2, -1], [0, 0, 0], [1, 2, 1]]\n",
"# filter = [[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]]\n",
"\n",
"weight = 1/8"
],
"metadata": {
"id": "U6qAVNzF2En4"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"source": [
"for x in range(1, size_x - 1):\n",
" for y in range(1, size_y - 1):\n",
" convolution = 0.0\n",
" convolution = convolution + (img[x - 1, y - 1] * filter[0][0])\n",
" convolution = convolution + (img[x, y - 1] * filter[0][1])\n",
" convolution = convolution + (img[x + 1, y - 1] * filter[0][2])\n",
" convolution = convolution + (img[x - 1, y] * filter[1][0])\n",
" convolution = convolution + (img[x, y] * filter[1][1])\n",
" convolution = convolution + (img[x + 1, y] * filter[1][2])\n",
" convolution = convolution + (img[x - 1, y + 1] * filter[2][0])\n",
" convolution = convolution + (img[x, y + 1] * filter[2][1])\n",
" convolution = convolution + (img[x + 1, y + 1] * filter[2][2])\n",
" convolution = convolution * weight\n",
" \n",
" if convolution < 0:\n",
" convolution = 0\n",
" if convolution > 255:\n",
" convolution = 255\n",
" \n",
" img_transformed[x, y] = convolution"
],
"metadata": {
"id": "D7DtjEm62F4q"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"source": [
"plt.imshow(img_transformed, cmap='gray')\n",
"plt.grid(False)\n",
"plt.axis('off')\n",
"plt.show()"
],
"metadata": {
"id": "SNS6EKJF2HKa"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "omoy_gsr22xe"
},
"source": [
"### Creación del modelo\n",
"\n",
"Para este modelo se agregarán algunas capas convolucionales.\n",
"\n",
"Como inspiración, podemos recrear LeNet5 de Yann LeCun:\n",
"\n",
"<img src=\"https://miro.medium.com/max/4348/1*PXworfAP2IombUzBsDMg7Q.png\">"
]
},
{
"cell_type": "code",
"source": [
"cnn_model = tf.keras.models.Sequential([\n",
" \n",
" # First conv layer + subsampling\n",
" tf.keras.layers.Conv2D(64, (3, 3), activation='relu', input_shape=(28, 28, 1)),\n",
" tf.keras.layers.MaxPooling2D(2, 2),\n",
"\n",
" # Second conv layer + subsampling\n",
" # TODO. Conv2D -> 256, (3, 3), ReLU\n",
" # TODO. MaxPool\n",
"\n",
" # Third layer (flatten)\n",
" tf.keras.layers.Flatten(),\n",
"\n",
" # Fourth layer (dense)\n",
" # TODO. Dense -> 128, ReLU\n",
"\n",
" # Fifth layer (output)\n",
" tf.keras.layers.Dense(10, activation='softmax')\n",
"])"
],
"metadata": {
"id": "Bpg1bC9b2ImO"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "JBoAlg9V27t8"
},
"source": [
"### Entrenamiento del modelo"
]
},
{
"cell_type": "code",
"source": [
"cnn_model.compile(\n",
" optimizer=tf.optimizers.SGD(),\n",
" loss='sparse_categorical_crossentropy',\n",
" metrics=['accuracy']\n",
")"
],
"metadata": {
"id": "V0dlEBI52opy"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"source": [
"model.summary()"
],
"metadata": {
"id": "NjQCtzBM7E0k"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"source": [
"cnn_model.fit(training_images, training_labels, epochs=2)"
],
"metadata": {
"id": "rAzIo2YA2soz"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "f381BSCR2_DQ"
},
"source": [
"### Evaluación del modelo"
]
},
{
"cell_type": "code",
"source": [
"cnn_model.evaluate(test_images, test_labels)"
],
"metadata": {
"id": "uciUKRC12ur5"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "jz-zeSn_3CZk"
},
"source": [
"### Predicción\n"
]
},
{
"cell_type": "code",
"source": [
"import random\n",
"\n",
"test_index = random.randint(0, 10000 - 1)\n",
"\n",
"plt.imshow(test_images[test_index], cmap='viridis')\n",
"plt.axis(False)\n",
"\n",
"print(\"Label:\", test_labels[test_index])\n",
"input_image = np.reshape(test_images[test_index], (1, 28, 28, 1))\n",
"prediction = cnn_model.predict(input_image)\n",
"print(\"Prediction:\", np.argmax(prediction))"
],
"metadata": {
"id": "vY5cgS0E2xBc"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"source": [
"### Explora las siguientes situaciones\n",
"\n",
"- Modifica el número de capas y parámetros de convolución por capa\n",
"- Modifica el número de épocas de entrenamiento\n",
"- Explora resultados con otros conjuntos de datos\n",
"- ¿Exportar modelos entrenados? Ojo: https://www.tensorflow.org/guide/keras/save_and_serialize?hl=es-419"
],
"metadata": {
"id": "BpmIVA0W3-RE"
}
},
{
"cell_type": "code",
"source": [
"# Guardar el Modelo\n",
"model.save('path_to_my_model.h5')\n",
"\n",
"# Recrea exactamente el mismo modelo solo desde el archivo\n",
"new_model = keras.models.load_model('path_to_my_model.h5')"
],
"metadata": {
"id": "Mumt7y0v6-Uz"
},
"execution_count": null,
"outputs": []
}
]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment