Skip to content

Clasificador de patrones matriciales de letras usando redes neuronales y perceptrón multicapa (MLP). TPI del año 2022 para la asignatura Inteligencia Artificial de la UTN FRRe

Notifications You must be signed in to change notification settings

angelogllrd/TPI-MLP-Multi-Layer-Perceptron

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

68 Commits
 
 
 
 
 
 

Repository files navigation

Análisis MLP (Multi-Layer Perceptron)

Trabajo Práctico Integrador del año 2022 para la asignatura Inteligencia Artificial de la UTN FRRe.

Descarga de la aplicación: Windows / Linux

Portada

Tabla de contenidos

  1. Consigna
  2. Requerimientos para ejecutar el .py
  3. Generación del ejecutable (Windows y Linux)
  4. Estructura de los datasets
  5. Estructura de la red neuronal
  6. Partes de la aplicación
  7. Instrucciones de uso de la aplicación
  8. Estructuración del código
  9. Últimos cambios

Consigna

Objetivos:

  1. Implementar el algoritmo MLP.
  2. Evaluar la precisión (MSE, error de entrenamiento y validación) de una MLP teniendo en cuenta distintas configuraciones: cantidad de capas, cantidad de neuronas, funciones de activación
  3. Elaborar un informe completo en base a las pruebas realizadas.

Descripción del problema:

Este trabajo consiste en implementar el algoritmo MLP que permita, dado un dataset en R2 parametrizar la cantidad de capas, neuronas y funciones de activación con los que se entrenará la red neuronal. La idea es desarrollar una aplicación que defina la arquitectura de la red (con 3 salidas, cada una asociada a un patrón de entrada), tome los datos de diferentes datasets, entrene el modelo y devuelva los resultados de clasificación (MSE, error de entrenamiento y validación).

La implementación deberá contar también con una interfaz de usuario para el ingreso de un patrón distorsionado (determinado por el usuario), que será clasificado según alguno de los patrones aprendidos, mostrando los resultados obtenidos.

Los patrones a detectar y clasificar estarán contenidos en una matriz de 10x10 que contendrán las letras b, d, f como se ve en las siguientes figuras:

Datasets

  • El grupo de trabajo deberá generar 3 datasets que contengan 100, 500 y 1000 ejemplos. El 10% deberán ser patrones sin distorsionar y el resto con una distorsión del 1% al 30%. Los Datasets deberán ser representativos a la hora de definir la distribución de los ejemplos de entrenamiento.

Requerimientos mínimos para el entrenamiento

  • Por cada Dataset deberán construirse tres conjuntos de validación con 10%, 20% y 30% de los ejemplos. El conjunto de validación debe ser representativo del Dataset de entrenamiento.
  • 1 o 2 capas ocultas.
  • De 5 a 10 neuronas por capa.
  • Funciones de activación: lineal y sigmoidal.
  • Coeficiente de aprendizaje entre 0 y 1.
  • Término momento entre 0 y 1.

Requerimientos mínimos para el reconocimiento

  • Patrón distorsionado de 0% a 30% generado de manera automática o manual.

Requerimientos mínimos de pruebas para el informe

  • Se deberán realizar como mínimo las siguientes pruebas para cada uno de los datasets con conjuntos de validación de 10%, 20% y 30% de patrones:
    • 1 capa oculta de 5 neuronas, función de transferencia lineal, coeficiente de aprendizaje 0,5 y término momento 0,5.
    • 1 capa oculta de 10 neuronas, función de transferencia lineal, coeficiente de aprendizaje 0,5 y término momento 0,5.
    • 2 capas ocultas (primera capa de 5 neuronas, segunda capa de 5 neuronas), función de transferencia lineal, coeficiente de aprendizaje 0,5 y término momento 0,5.
    • 2 capas ocultas (primera capa de 10 neuronas, segunda capa de 10 neuronas), función de transferencia lineal, coeficiente de aprendizaje 0,5 y término momento 0,5.
    • Repetir las mismas pruebas con término momento 0,9.

Consideraciones adicionales:

  • Se deberá contar con una interfaz de usuario que permita la total operabilidad de la aplicación.
  • Las interfaces deberán ser amigables (se aceptarán solamente entornos gráficos) e intuitivas (menú contextual de guía).
  • El código debe estar totalmente documentado/comentado.
  • El algoritmo debe ser enteramente desarrollado por los alumnos.
  • Debe ser una aplicación de escritorio.

Requerimientos para ejecutar el .py

  • Python 3
  • pip (ya incluido con el instalador de Windows). En Linux:
    sudo apt update
    sudo apt install python3-pip
    
  • PyQt5 (libreria para la UI)
    pip install PyQt5
    
  • Qt Designer (para abrir y editar la UI)
    • Windows
      • Opción 1: https://build-system.fman.io/qt-designer-download
      • Opción 2: (Si la versión de Python es 3.10, cambiar \Python3xx por \Python310)
        pip install PySide6
        %USERPROFILE%\AppData\Local\Programs\Python\Python3xx\Lib\site-packages\PySide6\designer.exe
        
    • Linux:
      sudo apt-get install qttools5-dev-tools
      designer
      
  • Matplotlib (Para las gráficas de errores vs. épocas)
    pip install matplotlib
    

Generación del ejecutable (Windows y Linux)

Descarga de la aplicación: Windows / Linux

Para evitar la instalación de las librerias podemos obtener un ejecutable, tanto en Windows como en Linux, usando Auto PY to EXE:

pip install auto-py-to-exe
auto-py-to-exe

O directamente con pyinstaller (lo que usa Auto PY to EXE por detrás):

pip install pyinstaller
pyinstaller --noconfirm --onefile --windowed --icon "path_a_la_carpeta/tpi/icons/icon.ico" --add-data "path_a_la_carpeta/tpi/icons;icons/" --add-data "path_a_la_carpeta/tpi/ui;ui/" --add-data "path_a_la_carpeta/tpi/redes_precargadas;redes_precargadas/" "path_a_la_carpeta/tpi/tpi.py"

En cualquier caso, para no tener problemas con las referencias relativas en el .exe final, el developer de Auto PY to EXE recomienda agregar al código esto, y pasar cada path de los archivos referenciados a la función resource_path(). Por ejemplo, en lugar de:

self.setWindowIcon(QIcon('icons\\icon2.ico'))

quedaría:

self.setWindowIcon(QIcon(resource_path('icons\\icon2.ico')))

Estructura de los datasets

  • Como se pide en la consigna, los datasets se generan cumpliendo el 10% sin distorsión, y el restante 90% distorsionado entre 1% y 30%.
  • Los datasets se representan usando listas de listas, donde cada sublista es un patrón de entrada o fila del dataset con 103 elementos (1s y 0s), donde los primeros 100 corresponden al patrón y los últimos 3 a las clases, una para cada letra (b, d y f).
  • Para asegurar que los conjuntos de test y validación sean representativos, se genera de la siguiente manera, quedando 4 porciones de cada tipo de ejemplo:

  • Los datasets de test y validación se crean incluyendo ejemplos de cada porción, lo mas similares posibles en cantidad.
  • Se estableció que el porcentaje de ejemplos para test debe ser uno que haga divisible por 4 (4 porciones representativas) el número de ejemplos de test para 100, 500 y 1000 ejemplos. Este porcentaje se calculó en un 8%, número que permite que los restantes ejemplos del dataset alcancen para formar todos los conjuntos de validación representativos para los 3 datasets, según los siguientes cálculos:

  • Gráficamente, para un dataset de 1000 ejemplos cuando se toma un 12% para test:

  • La división en los diferentes conjuntos del dataset de 100, 500 o 1000 ejemplos que se genera se puede ilustrar con uno de 100, considerando que siempre tomamos 8% para test y el restante para entrenamiento:

  • En la aplicación, cuando entrenamos, en realidad se llevan a cabo 3 entrenamientos, uno detrás del otro, considerando en cada uno un conjunto de validación distinto:

Estructura de la red neuronal

200857729-afc1c9ad-a962-4396-a839-d6a528fbf9fc

  • La red se representa también usando lista de listas, donde cada sublista es una capa.
  • Cada neurona dentro cada capa se representa mediante un diccionario, cuyos items varían dependiendo de qué capa se trate.
    • Las neuronas de la capa de entrada solamente tienen salida (que son iguales a las entradas).
    • Las neuronas de las capas ocultas y de salida contienen:
      • pesos: Una lista con los pesos de las conexiones entre la unidad actual y todas las unidades de la capa anterior. Por lo tanto, hay tantos pesos como neuronas en la capa anterior.
      • cambiosPeso: Usado para el cálculo del término momento. Se actualizan en cada actualización de pesos.
      • net: Almacena el cálculo del net de la neurona.
      • salida: Almacena el cálculo de la salida de la neurona.
      • delta: Almacena el cálculo del término de error de la neurona.
    • Las neuronas de la capa de salida almacenan, además de lo anterior:
      • salidaDeseada: Valor de uno de los 3 últimos elementos del patrón.

Partes de la aplicación

Descarga de la aplicación: Windows / Linux

La aplicación se divide en 2 pestañas principales: "Entrenamiento y test" y "Probar patrón".

Pestaña "Entrenamiento y test":

  • Sección 1:
    • Se comienza generando un dataset de 100, 500 o 1000 ejemplos, con el botón "Generar".
    • También es posible comenzar cargando el .txt de un dataset guardado previamente, con el botón "Cargar".
    • Es posible "Guardar" el dataset generado, en cuyo caso se crea un .txt con un string de la estructura de lista de listas del dataset (el botón se activa cuando genero o cargo un dataset).
  • Sección 2:
    • Es posible seleccionar una de las arquitecturas de red predefinidas (dadas en la consigna del TPI) y crear la estructura de la red con el botón "Crear red".
    • También es posible ingresar manualmente los parámetros de la red neuronal.
    • Se habilita una vez generado/cargado un dataset.
  • Sección 3:
    • Esta parte corresponde al entrenamiento. Podemos entrenar la red hasta que el error de época resulte aceptablemente pequeño (menor al error aceptable ingresado), o por un número de iteraciones/épocas fijado. En el primer caso, se limita el entrenamiento a 200 épocas, para evitar que siga indefinidamente cuando la red no converge.
    • Una vez terminado el entrenamiento, se presentan los resultados (número de épocas que llevó el entrenamiento, y errores de entrenamiento y de validación de la última época).
    • Las redes y su estado resultante del entrenamiento son guardadas luego del mismo, para poder seleccionarlas más adelante en la etapa de test, o para porbar un patrón.
    • Se habilita una vez creada la red.
  • Sección 4:
    • Esta parte corresponde al testing. Es posible seleccionar una red previamente entrenada con la que probar los patrones del dataset de test y calcular la precisión.
    • Se habilita una vez terminado el entrenamiento.
  • Sección 5:
    • Sección a modo de "consola", que muestra diferentes informaciones a medida que se realiza el proceso.
  • Sección 6:
    • Estos botones permiten visualizar el contenido de la red (botón "Red"), o de los diferentes conjuntos (Botones "Entrenamiento", "Test", "Validación 10%", "Validación 20%", y "Validación 30%") en forma tabular y gráfica:

Pestaña "Probar patrón":

  • Sección 7:
    • En esta parte se selecciona la red previamente entrenada con la que se desea probar los patrones.
  • Sección 8:
    • Esta sección cumple con la parte de la consigna que solicitaba una opción para el ingreso de un patrón distorsionado que debía ser clasificado.
    • Primero se debe seleccionar una letra y la distorsión, y luego presionar el botón "Distorsionar" para habilitar la sección de clasificación de la derecha. Además, la aplicación comprueba si el patrón distorsionado fué usado en el entranamiento (en cuyo caso "¿Patrón usado para entrenar?" dirá que "Si").
    • En la parte derecha, con el botón "Clasificar" se ingresa el patrón a la red seleccionada, se muestra la letra representada por la salida de la red, y las salidas obtenidas por cada neurona de salida (yb, yd, e yf).
  • Sección 9:
    • Parecida a la sección de arriba, pero permite clasificar un cierto número de patrones (de letras aleatorias, con distorsión aleatoria entre 0 y 30%), comprobando que no hayan sido usados para entrenar, y arroja los resultados de precisión.

Instrucciones de uso de la aplicación

Descarga de la aplicación: Windows / Linux

  1. Generar/Cargar dataset o Seleccionar modelo precargado:

    image

    • Generar/Cargar dataset

      • En la Sección 1, seleccionar el tamaño del dataset a generar, y presionar el botón "Generar" (se habilita después de seleccionar un tamaño). También es posible usar el botón "Cargar" para cargar el archivo .txt de un dataset guardado previamente con la aplicación. Opcionalmente, luego de cargar/generar un dataset, se habilita el botón "Guardar", que guarda el dataset en la carpeta "datasets" en la ruta del ejecutable.

        2022-11-07 22_44_46-Window

      • La generación o la carga de un dataset produce la división del mismo en dos partes: entrenamiento y test. A su vez, con ejemplos del dataset de entrenamiento se forman los 3 conjuntos de validación. Por lo tanto, los conjuntos o datasets resultantes son 5.

        2022-11-07 22_29_20-Window

      • Luego, se habilita la Sección 2 para crear una estructura de red, y los botones de la Sección 6 para ver los diferentes conjuntos formados.

        2022-11-07 22_49_43-Window

    • Seleccionar modelo precargado:

      • Alternativamente, podemos ahorrarnos entrenar una red y cargar una red/modelo ya entrenado seleccionando uno de los 72 modelos precargados en la Sección 4 (para hacer test) o en la Sección 7 (para probar patrones). En el primer caso, se habilita el resto de la Sección 4, y en el segundo la Sección 8 y la Sección 9:

        7

      • Seguir por el Paso 4 o el Paso 5.

  2. Crear estructura de red:

    • En la Sección 2 tenemos 2 opciones:

      • Seleccionar arquitectura predefinida de la lista: En cuyo caso los campos de los de parámetros de abajo se rellenan automáticamente con los parámetros de la arquitectura seleccionada.

        2022-11-07 22_54_05-Window

      • Seleccionar parámetros personalizados: Es posible seleccionar otros valores de los parámetros para crear una arquitectura no listada en las predefinidas. Si los valores seleccionados coinciden con los de una arquitectura predefinida, ésta aparace automáticamente seleccionada en la lista. De la misma forma, cuando seleccionamos una arquitectura predefinida, y luego cambiamos alguno de los parámetros, la misma deja de estar seleccionada en la lista.

        2022-11-07 22_54_48-Window

    • Una vez configurada la arquitectura deseada, presionar el botón "Crear red". Luego, se habilita parte de la Sección 3 y el botón "Red actual" de la Sección 6, para ver el contenido de la red creada.

      2022-11-07 22_55_46-Window

    • ACLARACIÓN: En cada momento, hay una "red actual" cargada, con la que se entrena, se testea y se prueban patrones, y es la que se ve con el botón "Red actual". Crear una nueva red o seleccionar una red entrenada guardada previamente de una de las listas, sobreescribe automáticamente esa red actual, pasando la nueva red (creada o seleccionada) a ser la actual.

  3. Entrenar la red creada:

    • En la Sección 3 tenemos 2 opciones para la condición de fin del entrenamiento:

      2022-11-07 22_41_23-Window

      • Seleccionar un error aceptable: El entrenamiento termina cuando el Error de entrenamiento promedio (promedio de los MSE de cada patrón en una época) resulta por debajo del error aceptable ingresado. Opcionalmente, descomentando el código de la primera imágen (dentro de entrenarRed()) y comentando el código de la segunda, el entrenamiento terminará cuando el error de entrenamiento de CADA patrón esté por debajo del error aceptable.

        2022-12-16 11_30_26-Window

        2022-12-16 11_30_52-Window

        Con esta opción de fin, y para evitar que el entrenamiento se prolongue indefinidamente cuando la red no converge (o lo hace muy lento), la aplicación genera una alerta cuando detecta que el error de cierta cantidad de las últimas épocas es el mismo (comparando cierta cantidad de decimales de los errores). La alerta ofrece la opción de Parar el entrenamiento o Seguir con el mismo (hasta detectar la misma situación):

        2022-11-20 21_36_03-Acción requerida

      • Seleccionar un número de épocas/iteraciones fijo: El entrenamiento se hace por un número de épocas fijado, independientemente del Error de entrenamiento como en el caso anterior.

    • Una vez seleccionada una opción, presionar el botón "Entrenar" para comenzar el entrenamiento. En realidad, esto lleva a cabo 3 entrenamientos (considerando en cada uno un conjunto de validación distinto). En cada uno de esos 3 entrenamientos:

      • Se restan o quitan los ejemplos de uno conjunto de validación al dataset de entrenamiento original, y se entrena con el conjunto resultante.
      • Al final de cada época dentro de ese entrenamiento, se resguarda el Error de entrenamiento (promedio de los errores de cada patrón en la época) y el Error de validación (promedio de los errores resultantes al aplicar cada uno de los patrones del conjunto de validación a la red), para poder generar los gráficos de MSE promedio vs. Épocas.
      • Al final, se guarda la red entrenada (con los pesos resultantes), para ser seleccionada en la etapa de test o en la prueba de patrones (segunda pestaña). Por lo tanto, al final de la etapa de entrenamiento quedan guardadas 3 redes entrenadas (misma arquitectura, entrenada considerando 3 conjuntos de validación). Internamente, también se guarda la arquitectura de la red, y los conjuntos de entrenamiento, test y validación asociados (estos últimos porque se los necesita para más adelate y corren el riesgo de ser sobreescritos al crear un nuevo dataset).
    • Al finalizar el entrenamiento, se muestran:

      • Resultados: Épocas que llevó el entrenamiento, Error de entrenamiento de la última época, y Error de validación de la última época.

        2022-12-16 11_33_00-TPI MLP 2022 - Inteligencia Artificial - UTN FRRe

      • Gráficos de MSE promedio vs. Épocas: Cada gráfico representa el Error de entrenamiento y Error de validación por cada época.

        Figure_1

    • Se habilita el botón "Guardar redes", que guarda las 3 redes que se acaban de entrenar como archivos .json en la carpeta "redes_entrenadas" en la ruta del ejecutable.

      image

En este momento podemos elegir realizar el test, o bien ir a la segunda pestaña para probar patrones distorsionados

  1. Realizar el test:

    • En la Sección 4 seleccionar, en primer lugar, el tipo de modelo a cargar:

      • Uno de los 72 modelos precargados,
      • Una de las redes que se entrenaron desde el inicio de la aplicación:

      image

    • Luego seleccionar el modelo en la segunda lista (esto habilita el resto de la sección):

      image

    • Presionar el botón "Hacer test". Esto inserta los patrones del dataset de test guardado en la red seleccionada, en dicha red. Luego calcula las salidas, detecta la letra representada por las salidas y la compara con la salida deseada, obteniendo el número de clasificaciones correctas.

    • Se muestran los resultados (Clasificaciones correctas, números de casos de prueba, y la precisión, calculada a partir de los dos primeros), junto con el gráfico de los Errores por cada patrón.

      image

      image

  2. Probar patrones (segunda pestaña):

    • En la Sección 7 seleccionar, en primer lugar, el tipo de modelo a cargar:

      • Uno de los 72 modelos precargados,
      • Una de las redes que se entrenaron desde el inicio de la aplicación:

      image

    • Luego seleccionar el modelo en la segunda lista. Esto carga la red seleccionada como red actual, junto con los datasets guardados con la misma (los datasets de entrenamiento y validación guardados en la red seleccionada se usan para comprobar si un patrón aleatorio fué usado en el entrenamiento de esa red), y habilita la Sección 8 y la Sección 9:

      image

    • Luego, tenemos 2 opciones:

      • Sección 8: Generar y clasificar un patrón con distorsión aleatoria

        image

        • Seleccionar una letra con uno de los 3 botones (se muestra la letra en la matriz de pixeles).
        • Seleccionar la distorsión a generar. ACLARACIÓN: El programa comprueba si el patrón distorsionado resultante es uno de los patrones usados para entrenar la red. Si lo fué, se muestra "Si" en el label "¿Patrón usado para entrenar?", mientras que si no, se muestra "No".
        • Presionar el botón "Distorsionar" (se muestra la letra distorsionada en la matriz de pixeles). Esto habilita la parte derecha de la Sección 8, donde clasificamos la letra distorsionada.
        • Presionar el botón "Clasificar". Se muestra la letra que representa la salida de la red al insertar el patrón distorsionado, junto con los valores de salida que se usaron para clasificar la letra.
      • Sección 9: Generar y clasificar un número dado de patrones con distoriones aleatorias:

        image

        • Ingresar el número de patrones distorsionados a generar.
        • Presionar el botón "Probar patrones". Se muestra a la izquierda la matriz de pixeles con cada patrón generado, junto con la letra clasificada a la derecha. ACLARACIÓN: Al igual que en la Sección 8, se comprueba si cada patrón generado fué usado en el entrenamiento de la red, y solamente se usan aquellos que no lo fueron.
        • Se muestran los resultados de precisión.

Estructuración del código

  • Importación de librerias necesarias (PyQt5, sys, os, random, time, math, json, matplotlib, numpy).
  • resource_path(): Función para no tener problemas con las rutas en la conversion a .exe. Todos los paths que referencian a archivos externos se pasan a esta función.
  • FUNCIONES PARA LA CREACIÓN E IMPRESIÓN DE PATRONES Y DATASETS:
    • inicializarPatrones(): Devuelve los patrones de las 3 letras, en forma de listas de 100 elementos con 1 y 0, usando las posiciones ocupadas por cada letra, considerando la matriz como una lista de 100 elementos (del 0 al 99).
    • imprimirMatriz(): Recibe un patrón e imprime la matriz de pixeles con * en cada pixel pintado. Se la usa solamente para pruebas en generarDataset().
    • generarDistorsion(): Distorsiona el patron pasado un porc% (cambia "porc" veces 0 por 1, y 1 por 0).
    • generarDataset(): Retorna el dataset completo, y los conjuntos de entrenamiento, test, y validación generados como se explica más arriba.
    • cargarDataset(): Se usa en la 1ra pestaña, con el boton "Cargar". Toma un dataset completo (con los 100, 500 o 1000 ejemplos) y extrae los demás datasets usando la misma lógica que generarDataset().
    • imprimirDatasetGraficoConAsteriscos(): Imprime el dataset en forma gráfica (matrices de los patrones) con * en cada pixel pintado, dispuesto en "cant_filas" filas de "patrones_por_fila" patrones.
    • imprimirDatasetGraficoConPosiciones(): Imprime el dataset en forma gráfica (matrices de los patrones) con la posición en cada pixel pintado, dispuesto en "cant_filas" filas de "patrones_por_fila" patrones.
    • imprimirDatasetTabular(): Imprime el dataset en forma tabular.
    • restarDatasets(): Quita de un dataset filas de otro. Se lo usa en entrenarRed() para restar al conjunto de entrenamiento los de validación, y en comprobarPatron() para obtener los ejemplos usados en el entrenamiento de una red y comprobar si un patrón fue usado para el entrenamiento.
  • CREACIÓN DE LA RED Y DE FUNCIONES PARA EL ALGORITMO:
    • crearRed(): Crea la estructura de la red, con sus capas y neuronas en cada capa, tal como se describe más arriba.
    • imprimirRed(): Muestra el contenido de la red en su estado actual, por cada capa.
    • dibujarTituloCapa(): Usado en imprimirRed(). Dibuja el título recuadrado de una capa.
    • inicializarPesos(): Corresponde al Paso 1. Inicializa los pesos de la red con valores pequeños aleatorios (entre -0.5 y 0.5)
    • aplicarPatronDeEntrada(): Corresponde al Paso 2. Presenta un patrón de entrada del dataset, copiándolo a la salida de las neuronas de la capa de entrada. También inserta las salidas deseadas (3 últimos elementos del patrón) en las salidas deseadas de las neuronas de salida.
    • calcularSalidasRed(): Corresponde al Paso 3. Propaga las entradas y calcula las salidas de la red.
    • calcularNetNeurona(): Calcula el net de cada neurona. Usado en calcularSalidasRed().
    • calcularSalidaNeurona(): Calcula la salida de cada neurona, dependiendo de la capa y la función de transferencia asociada. Usado en calcularSalidasRed().
    • funcionLineal(): Recibe el net y devuelve el resultado de la función lineal.
    • funcionSigmoidal(): Recibe el net y devuelve el resultado de la función sigmoidal. Además, trata los casos cuando el net pasado es menor a -709.78271, lo que provoca un overflow en la representación en coma flotante.
    • calcularTerminosErrorRed(): Corresponde al Paso 4. Calcula los términos de error para neuronas de salida y ocultas, comenzando por las de salida (propagación de errores hacia atrás).
    • calcularTerminoError(): Determina un termino de error en base a la capa actual, la neurona actual, y el numero de esa neurona. Usada en calcularTerminosErrorRed().
    • derivadaFuncionSigmoidal(): Calcula la derivada de la función sigmoidal. Usada en calcularTerminoError().
    • actualizarPesosRed(): Corresponde al Paso 5. Actualiza los pesos de la red.
    • calcularMSE(): Corresponde al Paso 6. Calcula el error cuadrático medio entre la salida obtenida y la deseada.
  • OTRAS FUNCIONES:
    • convertirErrorAString(): Convierte un error (flotante) a un string del mismo, considerando que puede estar en notación científica. Se usa porque el formateo de strings para tomar cierta cantidad de cifras decimales redondea la última cifra de acuerdo a los valores siguientes. Por ejemplo, f'{0.123456789:.8f}' quedaría '0.12345679', cuando debería ser '0.12345678'. El redondeo ocasiona que la comparación de las cifras decimales para verificar errores repetidos no se haga correctamente.
  • UI, DEFINICIÓN DE CLASES, ATRIBUTOS Y MÉTODOS:
    • class UI(): Clase correspondiente a la ventana principal.
      • uic.loadUi(): Carga el archivo .ui de la ventana principal.
      • initUI(): Hace inicializaciones como: poner nombre a la ventana, centrarla, mostrar en el panel de la derecha la instrucción inicial, colocar el ícono a la ventana, y mostrar la ventana.
      • ATRIBUTOS, ACCIONES DISPARADAS, INICIALIZACIONES, DESACTIVACIONES:
        • "Labels": Se crea listas con los objetos label de cada matriz de pixeles de la segunda pestaña. Más adelante, recorrer estas listas es lo que permite pintar los patrones en la matriz.
        • "Acciones disparadas por pushbuttons": Se define a qué métodos llama cada pushbutton cuando es presionado.
        • "Acciones disparadas por spinboxes": Se define el método llamado cuando cambia el valor de un spinbox.
        • "Acciones disparadas por radiobuttons": Se define el método llamado cuando se selecciona un radiobutton.
        • "Acciones disparadas por sliders": Se define el método llamado cuando se mueve un slider.
        • "Acciones disparadas por comboboxes": Se define el método llamado cuando se selecciona un elemento de la lista de un combobox.
        • "Desactivaciones iniciales de sección Arquitectura de la red": Desactivaciones necesarias de elementos de la Sección 2.
        • "Desactivaciones iniciales de sección Entrenamiento": Desactivaciones necesarias de elementos de la Sección 3.
        • "Desactivaciones iniciales de sección Test": Desactivaciones necesarias de elementos de la Sección 4.
        • "Desactivación inicial del label y botones para mostrar red y datasets": Desactivaciones necesarias de elementos de la Sección 6.
        • "Desactivaciones iniciales de la segunda pestaña": Desactiva necesarias de elementos de la Sección 8 y Sección 9.
        • "Inicializaciones varias": de los atributos letraIngresada (más adelante sirve para saber si ya se presionó o no alguno de los botones de las letras de la segunda pestaña), funcionDeActivacionSal (define queé función de transferencia se usa en las neuronas de la capa de salida), listaRedesEntrenadas (guarda las redes que entrenamos desde el inicio de la aplicación), y listaRedesPrecargadas (guarda las redes/modelos ya entrenados que se cargan al inicio de la aplicación).
        • "Definición de arquitecturas predefinidas": Se define una tupla de diccionarios con las características de las arquitecturas dadas en el TPI.
        • "Inicialización de combobox de arquitecturas predefinidas": Para cada arquitectura listada en el combobox de la Sección 2 se carga por detrás los datos de su estructura, definidos en el ítem anterior.
        • "Carga de redes precargadas": Se encarga de cargar, al inicio de la aplicación, las redes precargadas en el 2do combobox de las secciónes 4 y 7.
      • MÉTODOS DE CLASE:
        • center(): Sirve para centrar la ventana en la pantalla. Llamado en initUI().
        • mostrarPorConsola(): Concatena un string al contenido ya existente en el panel negro de la derecha.
        • desactivarEsto(): Recibe una tupla de cosas de la interfaz para desactivar.
        • activarEsto(): Recibe una tupla de cosas de la interfaz para activar.
        • generarAlerta(): Genera una alerta cuando se detecta que el entrenamiento produjo el mismo error (considerando cierta cantidad de dígitos decimales) durante cierta cantidad de décadas, brindando la opción de "Parar" o "Seguir" el entrenamiento. Su función es brindar al usuario la opción de parar el entrenamiento cuando el error no baja, o baja muy lentamente.
        • animarEsto(): Muestra una animación resaltando una sección cuando la misma se activa.
        • MÉTODOS PARA LA PRIMERA PESTAÑA:
          • generarDataset(): Verifica si alguno de los radio buttons (100, 500 o 1000) se seleccionó y genera los datasets correspondientes. Llamado por el botón "Generar". Activa el botón "Guardar", la sección de "Arquitectura de la red" y los botones para ver los datasets de Entrenamiento, Test, Validación 10%, Validación 20%, y Validación 30%.
          • guardarDataset(): Guarda el dataset generado/cargado como un .txt dentro de la carpeta "datasets" en la misma ruta del ejecutable. Llamado por el botón "Guardar".
          • cargarDataset(): Carga un .txt de un dataset guardado previamente con la aplicación, y genera los datasets correspondientes. Llamado por el botón "Cargar". Activa el botón "Guardar", la sección de "Arquitectura de la red" y los botones para ver los datasets de Entrenamiento, Test, Validación 10%, Validación 20%, y Validación 30%.
          • desactivarSeñales(): Bloquea las señales producidas por cambios de valores en los parámetros de la Sección 2 (cambios en spinboxes, combobox de función de transferencia, textedit de alfa y beta), para que los cambios en dichos valores producidos automáticamente por la aplicación cuando se selecciona una arquitectura predefinida de la lista del combobox de dicha Sección 2 no dispare la detección que se hace al cambiar dichos valores manualmente (dicha detección pretende detectar si la configuración manual de la arquitectura coincide con una predefinida y seleccionarla en la lista), lo que generaría resultados no deseados. De esta manera, la detección solamente se produce cuando los cambios de parámetros son manuales.
          • tratarArquitecturaPredefinida(): Carga automáticamente los parámetros de la arquitectura predefinida seleccionada en el combobox de la Sección 2. Usa desactivarSeñales() para desactivar la detección del cambio de valor en los parámetros, cambia los valores, y vuelve a activar las señales.
          • tratarCambioParametrosArq(): Por un lado comprueba, ante un cambio de parámetro de la Sección 2, si los parametros coinciden con los de una arquitectura predefinida, y la selecciona en la lista del combobox. Por el otro, activa o desactiva el spinbox de tamaño de capa oculta 2 y su label, llamando a tratarSpinBoxCapaOculta2().
          • tratarSpinBoxCapaOculta2(): Activa o desactiva el spinbox de tamaño de capa oculta 2 y su label, dependiendo del número de capas ocultas.
          • crearRed(): Toma los parámetros seleccionados para la red, y crea la estructura. Activa parte de la Sección 3 (Entrenamiento) y el botón de la esquina inferior derecha "Red actual" para ver el contenido de la red.
          • entrenarRed(): Realiza 3 entrenamientos, en cada uno considerando un conjunto de validación diferente. De acuerdo a la condición de fin seleccionada, realiza cada entrenamiento hasta que el Error de entrenamiento o Error global (MSE promedio de una época) sea menor que el error aceptable ingresado, o durante un número fijo de épocas o iteraciones. Dentro de cada entrenamiento y por cada época también se calcula el Error de validación. Una vez finalizados los 3 entrenamientos, arroja los resultados por cada uno (épocas que consumió, Error de entrenamiento y Error de validación de la última época). Llamada por el botón "Entrenar". Activa el botón "Guardar redes" de la misma sección.
          • mostrarErrorEpoca(): Usado dentro de entrenarRed(). Muestra por la consola de la aplicación el error de entrenamiento al terminar una época.
          • guardarRedEntrenada(): Guarda una red entrenada para poder usarla en la etapa de test o para probar patrones distorsionados, y la lista en el 2do combobox de las Secciones 4 y 7. Para listarla, comprueba si tiene una arquitectura predefinida. Si la tiene, busca el ítem de dicha arquitectura en el combobox de la Sección 2 y obtiene el texto que la describe. Si no, forma la descripción. Además de la red, guarda su estructura (para actualizar atributos de clase cuando la cargo), el dataset de test, de entrenamiento y el conjunto de validación correspondiente al entrenamiento, de manera de poder usarlos en cualquier momento. Llamada dentro de entrenarRed().
          • tratarComboboxTipoModelo(): Es llamada cuando seleccionamos una de las 2 opciones del 1er. combobox de las Secciones 4 y 7, y se encarga de cargar la lista de redes precargadas o recién entrenadas en el 2do combobox de dichas secciones.
          • esArquitecturaPredefinida(): Comprueba si la red actual tiene una arquitectura predefinida. Si la tiene, retorna el string que la describe, tal como está en el combobox de la Sección 2. Si no, retorna string vacío. En ambos casos, retorna en segundo lugar la estructura de la arquitectura (necesaria par actualizar atributos al cargar una red). Llamada dentro de guardarRedEntrenada().
          • finalizarEntrenamiento(): Agrupa operaciones comunes a los entrenamientos con las dos condiciones de fin, para evitar repetición de código. Llamada dentro de entrenarRed().
          • guardarRedesEntrenadas(): Guarda las últimas redes entrenadas en la Sección 3 (las 3 redes entrenadas, cada una con un conjunto de validación distinto), y los datasets de entrenamiento, test y validación asociados en archivos .json dentro de la carpeta "redes_entrenadas" en el directorio del ejecutable.
          • vaciarRed(): Asigna al atributo "red" una estructura de red vacía. Se usa para resetear la red en cada entrenamiento. Llamado dentro de entrenarRed().
          • probarDataset(): Calcula las clasificaciones correctas de los patrones de un dataset, la precisión, el error promedio y obtiene la lista de errores o MSEs, y retorna esos cuatro elementos. Llamada dentro de hacerTest(), probarPatrones(), y entrenarRed().
          • probarPatron(): Presenta un patrón a la red, calcula la salida, comprueba si la salida obtenida es igual a la deseada, y devuelve 1 o 0 dependiendo de la coincidencia, el error, y las salidas obtenidas convertidas a binario, y sin convertir. Llamada dentro de probarDataset(), y clasificarPatron().
          • graficarErrores(): Genera 3 gráficos, uno por cada uno de los 3 entrenamientos que se hacen al presionar el botón "Entrenar", comparando Errores de entrenamiento y Validación contra las épocas. Llamado por entrenarRed().
          • hacerTest(): Toma del 2do combobox de la Sección 4 la red seleccionada, prueba el dataset de test en ella, muestra resultados de precisión, y el gráfico de error de test. Llamada por el botón "Hacer test".
          • tratarComboboxTest(): Llamada cuando se selecciona del 2do combobox de la Sección 4 una red entrenada o precargada. Activa el resto de la sección "Test", carga como red actual la red seleccionada en el combobox, y resguarda el dataset de test correspondiente al entrenamiento de la red cargada para poder usarlo en la etapa de test.
          • cargarRedSeleccionada(): Llamada cuando se selecciona del 2do combobox de la Sección 4 o de la Sección 7 una red entrenada. Carga como red actual la red seleccionada en el combobox pasado, y retorna los datasets de entrenamiento, test y validación usados en el entrenamiento de la red cargada. Llamada en tratarComboboxTest() y en tratarComboboxProbarpatron().
        • MÉTODOS PARA LA SEGUNDA PESTAÑA:
          • tratarComboboxProbarpatron(): Llamada cuando se selecciona del 2do. combobox de la Sección 7 una red entrenada o precargada. Activa nuevas funciones de la pestaña "Probar patrón", carga como red actual la red seleccionada en el combobox, y resguarda los datasets de entrenamiento y validación correspondiente al entrenamiento de la red cargada para poder usarlos en comprobarPatron().
          • tratarLineEditSlider(): Traslada el valor del slider al line edit de la derecha, a medida que se lo mueve.
          • tratarLetra(): Llamado al presionar el botón de alguna de las letras (botones "b", "d", y "f"). Hace que se muestre por "consola" la letra seleccionada, que se muestre en la matriz de pixeles, y guarda dicha letra en su respectivo atributo.
          • setLetraIngresada: Guarda la letra seleccionada. Llamada en tratarLetra().
          • getLetraIngresada(): Devuelve la letra seleccionada previamente. Llamada por generarDistorsion().
          • mostrarLetra(): Pinta una matriz de pixeles de acuerdo al patrón pasado. Llamada por tratarLetra(), generarDistorsion(), y probarPatrones().
          • borrarLetra(): Pone en blanco una matriz de pixeles. Llamada por mostrarLetra().
          • generarDistorsion(): Muestra la letra distorsionada en la 1ra matriz. Llamado al presionar el botón "Distorsionar" y por probarPatrones().
          • copiarPatron(): Devuelve una copia del patrón sin distorsionar de la letra pasada. Llamada por generarDistorsion() y por probarPatrones().
          • guardarPatronDistorsionado(): Guarda una copia del patrón distorsionado en su correspondiente atributo, para que esté disponible a la hora de clasificar. Llamada por generarDistorsion().
          • comprobarPatron(): Comprueba si un patrón fue usado para el entrenamiento. Llamada por generarDistorsion() y probarPatrones().
          • clasificarPatron(): Presenta un patrón a la red y muestra la letra que representa la salida de la misma. Llamado por el botón "Clasificar" y por probarPatrones().
          • probarPatrones(): Clasifica un número dado de patrones aleatorios y muestra la precisión resultante. Llamado con el botón "Probar patrones".
        • MÉTODOS PARA VER CONTENIDO DE LA RED Y DE DATASETS:
          • verDataset: Abre una ventana con el dataset pasado mostrado en forma tabular y gráfica, usando imprimirDataset1() e imprimirDataset2().
          • verRed(): Abre una ventana que muestra la estructura y contenido actual de la red, usando imprimirRed2().
    • class UI_dialog_dataset(): Clase correspondiente a la ventana de visualización de los datasets.
    • class UI_dialog_red(): Clase correspondiente a la ventana de visualización de la red.
  • PROGRAMA PRINCIPAL:
    • Se inicializan los patrones de cada letra.
    • Se inicializa la app

Últimos cambios

Cambios posteriores a la entrega del 9/11

  • Agregados tooltips a todos los botones y comboboxes.

  • Cambiada la presentación de resultados:
    • Los resultados ya no se muestran con notación científica.

    • Los errores en los resultados del entrenamiento se muestran con una precisión de hasta 8 dígitos decimales.
    • Los valores de precisión se muestran en forma de porcentaje con 2 dígitos decimales.

    • Al clasificar un patrón, las salidas de las neuronas de salida se muestran en forma de porcentaje con 2 dígitos decimales.

  • Se dejó de usar el corte automático a las 200 épocas, que prolongaba demasiado el entrenamiento para datasets muy grandes (500 y 100 ejemplos), y, en cambio, se agregó una ventana de alerta cuando el entrenamiento produce el mismo error (considerando cierta cantidad de cifras decimales en el error) durante cierta cantidad de épocas, a fin de ofrecer la opción de cortar el entrenamiento cuando la red no converge (o converge muy lento).

  • Los errores repetidos y la cantidad de cifras consideradas para comparar los errores se puede modificar en las siguientes líneas:

  • Mejorada la representación de las informaciones mostradas por la consola de la aplicación. Se agregó espaciado entre renglones y ahora se listan los errores producidos por cada época durante el entrenamiento.

  • Se mejoró la representación del contenido de la red (botón "Red actual"). Se organizaron matricialmente las neuronas de entrada (para evitar una lista larga de 100 neuronas) y se agregó un recuadro a cada capa para distinguir mejor cuando comienza cada una.

  • Se agregó una animación de resaltado para distinguir cuando se activa una sección nueva en la aplicación.

  • Se quitaron los "ticks" fijos del eje x en el gráfico de Errores vs Épocas, lo que provocaba que cuando las épocas eran muchas (>100), los números quedaran muy juntos. Ahora, matplotlib los genera automáticamente. Lo que antes era la época 1, ahora se indica con 0, y lo que era la época n ahora es la época n-1. Lo mismo para el gráfico de error de test.

  • Ahora se permite hacer las inferencias con modelos precargados, sin obligarme a entrenarlos antes. Dichos modelos se cargan al inicio de la aplicación, y son los 72 modelos generados en las 72 pruebas solicitadas en la consigna:

    7

About

Clasificador de patrones matriciales de letras usando redes neuronales y perceptrón multicapa (MLP). TPI del año 2022 para la asignatura Inteligencia Artificial de la UTN FRRe

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages