PROYECTO – Inteligencia Artificial y cáncer cérvico uterino –

Consultores estratégicos en Ciencia de Datos

Contenido Ocultar

INTRODUCCION y JUSTIFICACION

El presente proyecto es una Alianza entre: La Fundación Costa Rica para el Desarrollo Sostenible ( entebbe) y el Hospital Clínico de Barcelona.

Resultado de imagen de hospital clinico barcelona logo

Antecedentes

Epidemiología

El cáncer cervico uterino sigue siendo el cáncer mas prevenible que se haya identificado, pero todavía en los países en vias de desarrollo, ocupa el tercer puesto entre las causa de muerte en mujeres , al contrario en países desarrollados como se pudo de ver anteriormente este tipo de cáncer ya ocupa el lugar número 9 o 10, lo que pone en evidencia que hay que trabajar un poco más en Costa Rica y los paises en desarrollo en educación y prevención.

Esto no significa que se haya hecho poco nada, en realidad la cantidad de casos ha venido disminuyendo de forma importante gracias a las politicas públicas y a los programa de extensión de cobertura principalmente. Sin embargo las cifras de mortalidad permanecen muy similares en las últimas dos décadas.

Laboratorio Nacional de Citologías -CCSS-  

La Citología Vaginal, el elemento nuclear del Proyecto

Veamos las fortalezas y debilidades de la técnica. Empecemos analizando estadisticamente dos elementos fundamentales:

 

Sensibilidad y Especificidad

La sensibilidad y la especificidad son dos indicadores que nos permiten conocer la capacida de nuestro sistema para detectar personas sanas y enfermas y poder distinguirlos sin error y clasificarlos en su grupoadecuadamente . Además de esto, es importante conocer que son los Falsos positivos y los Falsos Negativos ya que tienen un impacto directo en la prueba y en las pacientes.SENSIBILIDAD Y ESPECIFICIDAD

Falsos negativos y falsos positivos

Capacidad Predictiva

Como se mide la capacidad predictiva de estas prueba ? Veámoslo con un ejemplo

Ahora, utilizando la misma fórmula , reemplazamos los valores de sebsibilidad y especificidad reportados

y tomando una incidencias del 3.3%, obtenemos dos indicadores muy valiosos : valor Predictivo Positivo VPP y el Valor Predictivo Negativo VPN.

En el siguiente cuadro hacemos una comparación entre la citología vaginal y la colposcopía que también es un método de evaluación con gran SENSIBILIDAD.

Ambas pruebas tienen un valor predictivo negativo ALTO, sin embargo la citología por su parte posee un VPP de apenas un 61%. Al final esto, se traduce como se dijo con anterioridad con un % de Falsos negativos que se reporta entre el 8 y el 45% dependiendo de los autores y de las técnicas utilizadas.

Este gran margen de recorrido del valor muestra que hay mucho espacio para mejorar y es ahi donde surge el presente Proyecto

Debilidades

En los últimos años la técnica de la prueba se ha ido mejorando introduciendo la tecnología “líquida” con lo cual mejora la capacida de identificar el VPH , responsable del 70% de los cánceres.

Epidemiología en España

En España como se mencionó al inicio, el Cáncer cervico uterino ha venido ocupando un segundo o tercer lugar en INCIDENCIA, por debajo del cáncer de MAMA. Sin embargo la Mortalidad ha bajado gracias a los programas prevetivos y actualmente ocupa el décimo lugar.

 

RESUMEN OPERATIVO DEL PROYECTO

Objetivo General y Objetivos específicos

Es importante considerar que se trata de un proyecto académico sin fines de lucro en donde se tratará de promover la participación de estudiantes y profesores de diversos centros alrededor del mundo por tratarse de un proyecto con un gran contenido e impacto social. Por eso dentro de los objetivos específicos encontraremos objetivos orientados a:

  • Las Alianzas académicas y comerciales. Favorecer la participación docente , el intercambio de experiencias
  • La participación variada de empresas tecnológicas para la creación de herramientas “apropiadas”
  • Evaluación de herramientas tecnologicas del mundo de la Inteligencia Artificial
  • Favorecer un modelo de autosostenibilidad de la iniciativa, pero con un enfoque “sin fines de lucro”

Instituciones Participantes

El proyecto es un proyecto de investigación en el que presumiblemente participen una variedad de Organizaciones cada una con sus aportes diferentes e individuales ( en especie, en efectivo o con sus propios recursos humanos ) es de esperar que lo montos que se presentan a continuación que podrian verse muy modestos, son apenas las contrapartes iniciales de las Organizaciones Participantes a modo de “capital semilla” . La Fundación del Hospital Clinico contrará a la Fundación Costa Rica para el Desarrollo Sostenible , quien tendrá a su la Ejecución tecnica del Proyecto, sin embargo la Fdundación de Hospital Clinico contribuiría con los recursos de acompañamiento al proyecto. Conforme el proyecto avance los roles podrán irse modificando a conveniencia y acuerdo entre las partes.

Recursos

Actividades y Cronograma

Ahora profundizemos en la tecnología y en las herramientas que utilizará el proyecto:

INTELIGENCIA ARTIFICIAL CON APRENDIZAJE PROFUNDO

En la coyuntura tecnologica y epidemiológica donde surge este proyecto, se pretende  unir las enormes capacidades que ofrece la Inteligencia Artificial en la medicina , junto con las mejores prácticas diagnósticas y los avances que los profesionales especializados del Hospital Clinico de Barcelona junto con la experiencia de profesionales costarricenses, quieren  desarrollar en conjunto, dotando de èstas herramientas para Costa Rica y para los países en desarrollo.

Veámos algunas definiciones relacionadas con la tecnología que se quiere utilizar en el proyecto.

 

Machine Learning

Es una disciplina científica del ámbito de la Inteligencia Artificial, que crea sistemas que aprenden automáticamente. Aprender en este contexto quiere decir identificar patrones complejos dentro de los datos . La máquina que realmente aprende es un algoritmo que revisa los datos y es capaz de predecir comportamientos futuros. Automáticamente, también en este contexto, implica que estos sistemas se mejoran de forma autónoma con el tiempo, sin intervención humana.

El Machine Learning ha sido considerado una revolución en el procesamiento de imágenes y es el responsable de los sistemas de reconocimiento facial que muchos Gobiernos utilizan dentro de sus politicas de seguridad, y como toda herramienta de seguridad se busca que funcione perfecto o casi perfecto.

El Machine Learning en general tiene un ciclo de vida que incluye: analizar y preparar los datos, escoger un algoritmo, dividir los datos en: datos para entrenar el modelo(aprendizaje/entrenamiento) y datos para validarlo (validación entre los datos entrenados y datos previamente clasificados , evaluar el modelo, ajustar parámetros y predecir con el base en un modelo entrenado. Veamos este ciclo en detalle:

 

El machine learning como proceso de imágenes varia un poco con respecto al esquemaanterior. Incorpora otra serie de transformaciones y capas que se explican en detalle, mas adelante en éste capítulo.

Para este proyecto y tratándose de procesamiento de imágenes, inicialmente estaremos haciendo un plan piloto con el algoritmo conocido como:

Las CNN o Redes Neuronales Convolucionales.

este tipo de algoritmo utiliza una clase de aprendizaje conocido como Aprendizaje Supervisado, ya que para el proceso de entrenamiento conoceremos de previo los resultados, en este caso las citologias con las que se va a entrenar el modelo, ya sabremos si son positivas o negativas por cáncer y eventualmente , el estadío (si se trata de un cancer inicial, intermedio, avanzado o muy avanzado. de acuerdo a las clasificaciones vigentes). El proceso de aprendizaje es anónimo , o sea que no sabemos de que paciente se trata excepto si es positivo o negativo

DEFINICION

Las Redes neuronales convolucionales (CNN) son un tipo de redes neuronales artificiales donde las “neuronas” vienen a corresponder a los llamados campos receptivos de nuestra corteza cerbral en la zona llamada corteza visual primaria (V1). Este tipo de red neuronal es una variación de un perceptrón multicapa, sin embargo, debido a que su aplicación es realizada en matrices bidimensionales, son muy efectivas para tareas de visión artificial, como en la clasificación y segmentación de imágenes, entre otras aplicaciones. Y esto es lo que el proyecto quiere experimentar logrando conocer la capacidad predictiva de las redes contra los metodos manuales tradicionales. A futuro se pretende que los esfuerzos manuales se enfoquen a la disminución de los falsos negativos , dandole asi a la prueba un impacto preventivo mayor. Y acá de lo que se trata es de aumentar la prevención para disminuir la mortalidad .

 

Semejanzas de las CNN con el cerebro humano

El trabajo realizado por Hubel y Wiesel en 1959​ jugó un papel importante en la comprensión sobre cómo funciona la corteza visual, particularmente las células responsables de la selectividad de orientación y detección de bordes en los estímulos visuales dentro de la corteza visual primaria V1. Dos tipos de células se identificaron debido a que tenían campos receptivos alargados, con lo cual se sabe que tienen una mejor respuesta a los estímulos visuales alargados como las líneas y los bordes. Estas se denominan células simples y células complejas.

Las células simples tienen regiones excitadoras e inhibitorias, ambas forman patrones elementales alargados en una dirección, posición y tamaño en particular en cada célula. Si un estímulo visual llega a la célula con la misma orientación y posición, de tal manera que ésta se alinea perfectamente con los patrones creados por las regiones excitadoras y al mismo tiempo se evita activar regiones inhibitorias. De esta forma la célula es activada y emite una señal.

Las células complejas operan de una manera similar. Como las células simples, éstas tienen una orientación particular sobre la cual son sensibles. Sin embargo, éstas no tienen sensibilidad a la posición. Por ello, un estimulo visual necesita llegar únicamente en la orientación correcta para que esta célula sea activada.

 

Cómo estan construidas las CNN y cómo funcionan

Las redes neuronales convolucionales consisten en múltiples capas de filtros convolucionales de una o más dimensiones. Después de cada capa, por lo general se añade una función para realizar un mapeo causal no-lineal.

Como cualquier red empleada para clasificación, al principio estas redes tienen una fase de extracción de características, compuesta de las llamadas neuronas convolucionales , luego se lleva a cabo un proceso de eficiencia por reducción y r muestreo y al final tendremos neuronas de perceptrón mas sencillas, para realizar mejor la clasificación final sobre las características extraídas.

La fase de extracción de características se asemeja al proceso estimulante en las células de la corteza visual. Esta fase se compone de capas alternas de neuronas convolucionales y neuronas de reducción de muestreo. Según progresan los datos a lo largo de esta fase, se disminuye su dimensionalidad, siendo las neuronas en capas lejanas mucho menos sensibles a perturbaciones en los datos de entrada, pero al mismo tiempo son activadas por características cada vez más complejas. (profundidad)

 

Como logramos que una red convolucional aprenda

Las Redes neuronales Convolucionales, CNN aprenden a reconocer una diversidad de objetos dentro de imágenes , pero para ello necesitan “entrenarse” de previo con una cantidad importante de “muestras” -lease más de 10.000, de ésta forma las neuronas de la red van a poder captar las características únicas -de cada objeto- y a su vez, poder generalizarlo – a esto es lo que se le conoce como el proceso de “aprendizaje de un algoritmo ” .

Nuestra red va a poder reconocer por ejemplo un cierto tipo de célula porque ya la ha “visto” anteriormente muchas veces, pero no sòlo buscará cèlulas semejantes sino que podrá inferir imáagenes que aún no ha vsto pero que relaciona y en donde encuebtra similitudes . Esta es la parte inteligente del reconocimiento.

Veámoslo mas en detalle:

 

Todo comienza con un Pixel

Pixeles y neuronas

Para comenzar, la red toma como entrada los pixeles de una imagen. Si tenemos una imagen con apenas 28×28 pixeles de alto y ancho, esTo equivale a utilizar 784 neuronas. Y eso es si sólo tenemos 1 color (escala de grises). Si tuviéramos una imagen a color, necesitaríamos 3 canales RGB (red, green, blue) y entonces usaríamos 28x28x3 = 2352 neuronas Estas neuronas constituyen nuestra capa de entrada.

 

Pre-procesamiento

Antes de alimentar la red, recuerda que como entrada nos conviene convertir los valores entre 0 y 1 uy por tanto tedremos quedividirlos todosentre 255 . Este 255 es por que los colores de los pixeles tienen valores que van del 0 al 255, .

Convoluciones

Ahora comienza el «procesado distintivo» de las Redes neuronales convolucionales, es decir, haremos las llamadas «convoluciones»: Estas consisten en tomar «grupos de pixeles cercanos» de la imagen de entrada e ir operando matemáticamente (producto escalar) contra una pequeña matriz que se llama kernel. Ese kernel supongamos que tiene un tamaño de de 3×3 pixels y con ese tamaño logra «visualizar» todas las neuronas de entrada (de izquierda-derecha, de arriba-abajo) y asi logra generar una nueva matriz de salida, que en definitiva será nuestra nueva capa de neuronas ocultas.

NOTA: si la imagen fuera a color, el kernel realmente sería de 3x3x3 es decir: un filtro con 3 kernels de 3×3; luego esos 3 filtros se suman (y se le suma una unidad bias) y conformarán 1 salida (cómo si fuera 1 solo canal).

El kernel tomará inicialmente valores aleatorios(1) y se irán ajustando mediante backpropagation. (1)Una mejora es hacer que siga una distribución normal siguiendo simetrías, pero sus valores son aleatorios.

Filtro: conjunto de kernels

No aplicaremos 1 sólo kernel, si no que tendremos muchos kernel (al conjunto de Kernels se les llama filtros). Por ejemplo en esta primer convolución podríamos tener 32 filtros, con lo cual realmente obtendremos 32 matrices de salida (este conjunto se conoce como «feature mapping»), cada una de esta salidas tendria una dimnión de 28x28x1 lo que nos da un total del 25.088 neuronas para nuestra PRIMER CAPA OCULTA de neuronas, y que segunb nuestro ejemplo solo esta analiza una pequeñisima imagen cuadrada de apenas 28 pixeles.

Imaginen cuántas neuronas se necesitran siutilizamos una imagen de entrada de 224x224x3 (que aún es considerado todavía un tamaño pequeño)…

 

 

Aquí vemos al kernel realizando el producto matricial con la imagen de entrada y desplazando de a 1 pixel de izquierda a derecha y de arriba-abajo y va generando una nueva matriz que compone al mapa de features

A medida que vamos desplazando el kernel, vamos obteniendo una «nueva imagen» filtrada.

En ésta primer convolución y siguiendo con el ejemplo anterior, es como si obtuviéramos 32 «imágenes filtradas nuevas». Estas imágenes nuevas lo que están «leyendo » son ciertas características de la imagen original. Esto es lo que nos ayudará en el futuro a poder distinguir un objeto de otro (por ej. una celula normal de unacelula mitótica o con cambios sugestivos de cáncer).

La función de Activación

Adicionalmente usaremos una función de activación. La más utilizada para este tipo de redes neuronales es la llamada ReLu por sus siglas “Rectifier Linear Unit” y consiste en una función del tipo: f(x)=max(0,x).

 

 

La imagen realiza una convolución con un kernel y aplica la función de activación, en este caso ReLu

Muestreo (subsampling)

Con el fin de ahorrar recuso informatico antes de pasar a una nueva convluciòn haremos un proceso de muestreo  utilizando las  neuronas mas representativas.

¿Que tan necesario es muestrear  ? Antes vimos que con imagen blanco y negro de 28×28 pixels tenemos una primer capa de entrada de 784 neuronas y luego de la primer convolución obtenemos una capa oculta de 25.088 neuronas -que realmente son nuestros 32 mapas de características de 28×28 ((28 x 28 ) x 32)

Si hiciéramos una nueva convolución a partir de esta capa, el número de neuronas de la próxima capa requeriría un poder computacional “muy importante”. Por ello y para reducir el tamaño de la próxima capa de neuronas hacemos este muestreo especializado, donde presevaremos las características más importantes que detectó cada filtro.

Hay diversos tipos de muestreo (ò subsampling) , El “«más conocido es” Max-Pooling

 

Muestreo con Max-Pooling

El paso siguiente sería utilizar la tecnica de “Max-pooling” con un tamaño de 2×2. Esto quiere decir que recorreremos cada una de las 32 imágenes de características obtenidas anteriormente de 28x28px de izquierda-derecha, arriba-abajo PERO en vez de tomar de a 1 pixel, tomaremos de «2×2» (2 de alto por 2 de ancho = 4 pixeles) e iremos preservando el valor «más alto» de entre esos 4 pixeles (por eso lo de «Max»). En este caso, usando 2×2, la imagen resultante es reducida «a la mitad»y quedará de 14×14 pixeles. Luego de este proceso de submuestreo nos quedarán 32 imágenes de 14×14, pasando de 25.088 neuronas a 6272, las cuales son bastantes menos y que -en teoría- deberían seguir almacenando la información más importante para detectar características deseadas.

La imagen superior representa esa primera convolución: consiste de una entrada, un conjunto de filtros, generamos un mapa de características y hacemos el submuestreo. Con lo cual, en el ejemplo de imágenes de 1 sólo color tendremos:

PRIMERA CONVOLUCION 2)Aplico Kernel 3)Obtengo Feature Mapping 4)Aplico Max-Pooling 5)Obtengo «Salida» de la 1era Convolución
28x28x1 = 784 neuronas 32 filtros de 3×3 28x28x 32 kernel = 25.088 neuronas de 2×2 14x14x32 = 6.272 neuronas

La primer convolución es capaz de detectar características primitivas como lineas ó curvas. A medida que hagamos más capas con las convoluciones, los mapas de características serán capaces de reconocer formas más complejas, y el conjunto total de capas de convoluciones podrá «reconocer».

 

Convoluciones subsecuentes

Pues ahora deberemos hacer una Segunda convolución que será:

SEGUNDA CONVOLUCION 2)Aplico Kernel 3)Obtengo Feature Mapping 4)Aplico Max-Pooling 5)Obtengo «Salida» de la Convolución
14x14x32= 6272 neuronas 64 filtros de 3×3 14x14x64 = 12544 neuronas de 2×2 7x7x64 = 3136 neuronas

La 3er convolución comenzará en tamaño 7×7 pixels y luego del max-pooling quedará en 3×3 con lo cual podríamos hacer sólo 1 convolución más. En este ejemplo empezamos con una imagen de 28x28px e hicimos 3 convoluciones. Si la imagen inicial hubiese sido mayor (de 224x224px) aún hubiéramos podido seguir haciendo convoluciones.

TERCERA CONVOLUCION 2)Aplico Kernel 3)Obtengo Feature Mapping 4)Aplico Max-Pooling 5)Obtengo «Salida» de la Convolución
7x7x64= 3.136 neuronas 128 filtros de 3×3 7x7x128= 6272 neuronas de 2×2 3x3x128 = 768 neuronas

y con esto hemos llegado a la última convuloción

 

Conectando con una red neuronal «tradicional».

Para terminar, tomaremos la última capa oculta a la que hicimos subsampling, que se dice que es «tridimensional» por tomar la forma -en nuestro ejemplo- 3x3x128 (alto,ancho,mapas) y la «aplanamos», esto es que deja de ser tridimensional, y pasa a ser una capa de neuronas «tradicionales», y con ello aplanamos (y conectamos) una nueva capa oculta de neuronas tipo feedforward.

Entonces, a esta nueva capa oculta «tradicional», le aplicamos una función llamada Softmax que conecta contra la capa de salida final que tendrá la cantidad de neuronas correspondientes con las clases que estamos clasificando. Si clasificamos muestras positivas y negativas serán 2 neuronas. Si clasificamos anomalías 1, 2 y 3 por ej, se necesitarán 3, etc.

Las salidas al momento del entrenamiento tendrán el formato conocido como «one-hot-encoding» en el que para muestras positivas y negativas serían: [1,0] y [0,1], para anomalías tipo 1, 2 y 3 serían [1,0,0]; [0,1,0];[0,0,1].

Y la función de Softmax se encarga de pasar a probabilidad (entre 0 y 1) a las neuronas de salida. Por ejemplo una salida [0,2 0,8] nos indica 20% probabilidades de que sea positivo y 80% de que sea negativo, según este ejemplo.

 

Las CNN y el modelo matematico de Backpropagation de las redes neuronales

El proceso es similar al de las redes tradicionales en las que tenemos una entrada y una salida esperada (por eso le llamamos aprendizaje supervisado) y mediante ese procesamiento de ajuste hacia adelante y hacias atras, vamos mejorando el valor de los pesos de las interconexiones entre las capas de las neuronas y a medida que iteramos esos pesos se ajustan hasta ser óptimos.

En el caso de la CNN, deberemos ajustar el valor de los pesos de los distintos kernels. Esto es una gran ventaja al momento del proceso de aprendizaje pues como vimos cada kernel es de un tamaño reducido, en nuestro ejemplo en la primer convolución es de tamaño de 3×3, eso son sólo 9 parámetros que debemos ajustar en 32 filtros que nos dan un total de 288 parámetros. En comparación con los pesos entre dos capas de neuronas «tradicionales»: una de 748 y otra de 6272 en donde están TODAS interconectarlas con TODAS y eso equivaldría a tener que entrenar y ajustar más de 4,5 millones de pesos (sólo para 1 capa).

 

Comparativa entre una red neuronal «tradicional» y una red neural convolucional

En este cuadro se resumen las diferencias entre las redes Fully connected y las redes Convolutional Neural Networks.

CARACTERISTISTICAS Red «tradicional» Feedforward multicapa Red Neuronal Convolucional CNN
Datos de entrada en la Capa Inicial Las características que analizamos. Por ejemplo: ancho, alto, grosor, etc. Pixeles de una imagen. Si es color, serán 3 capas para rojo,verde,azul
Capas ocultas elegimos una cantidad de neuronas para las capas ocultas. Tenemos de tipo:
* Convolución (con un tamaño de kernel y una cantidad de filtros)
* Subsampling
Capa de Salida La cantidad de neuronas que queremos clasificar. Para «comprar» ó «alquilar» serán 2 neuronas. Debemos «aplanar» la última convolución con una (ó más) capas de neuronas ocultas «tradicionales» y hacer una salida mediante SoftMax a la capa de salida que clasifica «perro» y «gato» serán 2 neuronas.
Aprendizaje Supervisado Supervisado
Interconexiones Entre capas, todas las neuronas de una capa con la siguiente. Son muchas menos conexiones necesarias, pues realmente los pesos que ajustamos serán los de los filtros/kernels que usamos.
Significado de la cantidad de capas ocultas Realmente es algo desconocido y no representa algo en sí mismo. Las capas ocultas son mapas de detección de características de la imagen y tienen jerarquía: primeras capas detectan lineas, luego curvas y formas cada vez más elaboradas.
Backpropagation Se utiliza para ajustar los pesos de todas las interconexiones de las capas Se utiliza para ajustar los pesos de los kernels.

Arquitectura básica (RESUMEN)

  • Entrada: Serán los pixeles de la imagen. Serán alto, ancho y profundidad será 1 sólo color o 3 para Red,Green,Blue.
  • Capa De Convolución: procesará la salida de neuronas que están conectadas en «regiones locales» de entrada (es decir pixeles cercanos), calculando el producto escalar entre sus pesos (valor de pixel) y una pequeña región a la que están conectados en el volumen de entrada. Aquí usaremos por ejemplo 32 filtros o la cantidad que decidamos y ese será el volumen de salida.
  • «CAPA RELU» aplicará la función de activación en los elementos de la matriz.
  • MUESTREO ó SUBSAMPLING: Hará una reducción en las dimensiones alto y ancho, pero se mantiene la profundidad.
  • CAPA «TRADICIONAL» red de neuronas feedforward que conectará con la última capa de subsampling y finalizará con la cantidad de neuronas que queremos clasificar.

PROTOTIPO INFORMÁTICO PRELIMINAR

Este es el primer prototipo para el análisis de imágenes de citología. Version Python 3.6 usando Redes Neuronales Convolucionales “CNN”

 

Importando las librerías externas del python para el análisis de datos

 
import numpy as np
import os
import re
import matplotlib.pyplot as plt
%matplotlib inline
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
 
import keras
from keras.utils import to_categorical
from keras.models import Sequential,Input,Model
from keras.layers import Dense, Dropout, Flatten
from keras.layers import Conv2D, MaxPooling2D
from keras.layers.normalization import BatchNormalization
from keras.layers.advanced_activations import LeakyReLU
 

Cargar set de Imágenes de prueba (entrenamiento inicial de la red con fotos de 10 deportes diferentes)

 
dirname = os.path.join(os.getcwd(), 'sportimages')
imgpath = dirname + os.sep 

images = []
directories = []
dircount = []
prevRoot=''
cant=0

print("leyendo imagenes de ",imgpath)

for root, dirnames, filenames in os.walk(imgpath):
    for filename in filenames:
        if re.search("\.(jpg|jpeg|png|bmp|tiff)$", filename):
            cant=cant+1
            filepath = os.path.join(root, filename)
            image = plt.imread(filepath)
            images.append(image)
            b = "Leyendo..." + str(cant)
            print (b, end="\r")
            if prevRoot !=root:
                print(root, cant)
                prevRoot=root
                directories.append(root)
                dircount.append(cant)
                cant=0
dircount.append(cant)

dircount = dircount[1:]
dircount[0]=dircount[0]+1
print('Directorios leidos:',len(directories))
print("Imagenes en cada directorio", dircount)
print('suma Total de imagenes en subdirs:',sum(dircount))
 
leyendo imagenes de  C:\Users\Tommy\Machine learning\TEMAS\CNN\sportimages\
C:\Users\Tommy\Machine learning\TEMAS\CNN\sportimages\americano 1
C:\Users\Tommy\Machine learning\TEMAS\CNN\sportimages\basket 9348
C:\Users\Tommy\Machine learning\TEMAS\CNN\sportimages\beisball 8823
C:\Users\Tommy\Machine learning\TEMAS\CNN\sportimages\boxeo 7752
C:\Users\Tommy\Machine learning\TEMAS\CNN\sportimages\ciclismo 7125
C:\Users\Tommy\Machine learning\TEMAS\CNN\sportimages\f1 7533
C:\Users\Tommy\Machine learning\TEMAS\CNN\sportimages\futbol 5053
C:\Users\Tommy\Machine learning\TEMAS\CNN\sportimages\golf 7617
C:\Users\Tommy\Machine learning\TEMAS\CNN\sportimages\natacion 9768
C:\Users\Tommy\Machine learning\TEMAS\CNN\sportimages\tenis 5172
Directorios leidos: 10
Imagenes en cada directorio [9349, 8823, 7752, 7125, 7533, 5053, 7617, 9768, 5172, 8936]
suma Total de imagenes en subdirs: 77128
 

Creamos las etiquetas (al ser una red supervisada conocemos de previo los resultados del set de datos de entrenamiento)

 
labels=[]
indice=0
for cantidad in dircount:
    for i in range(cantidad):
        labels.append(indice)
    indice=indice+1
print("Cantidad etiquetas creadas: ",len(labels))
 
Cantidad etiquetas creadas:  77128
 
deportes=[]
indice=0
for directorio in directories:
    name = directorio.split(os.sep)
    print(indice , name[len(name)-1])
    deportes.append(name[len(name)-1])
    indice=indice+1
 
0 americano
1 basket
2 beisball
3 boxeo
4 ciclismo
5 f1
6 futbol
7 golf
8 natacion
9 tenis
 
y = np.array(labels)
X = np.array(images, dtype=np.uint8) #convierto de lista a numpy

# Find the unique numbers from the train labels
classes = np.unique(y)
nClasses = len(classes)
print('Total number of outputs : ', nClasses)
print('Output classes : ', classes)
 
Total number of outputs :  10
Output classes :  [0 1 2 3 4 5 6 7 8 9]
 

Creamos Sets de Entrenamiento y de validación

 
train_X,test_X,train_Y,test_Y = train_test_split(X,y,test_size=0.2)
print('Training data shape : ', train_X.shape, train_Y.shape)
print('Testing data shape : ', test_X.shape, test_Y.shape)
 
Training data shape :  (61702, 21, 28, 3) (61702,)
Testing data shape :  (15426, 21, 28, 3) (15426,)
 
plt.figure(figsize=[5,5])

# Display the first image in training data
plt.subplot(121)
plt.imshow(train_X[0,:,:], cmap='gray')
plt.title("Ground Truth : {}".format(train_Y[0]))

# Display the first image in testing data
plt.subplot(122)
plt.imshow(test_X[0,:,:], cmap='gray')
plt.title("Ground Truth : {}".format(test_Y[0]))
 
Text(0.5, 1.0, 'Ground Truth : 0')
 
 

Preprocesamos las imagenes

 
train_X = train_X.astype('float32')
test_X = test_X.astype('float32')
train_X = train_X / 255.
test_X = test_X / 255.
 

Hacemos el One-hot Encoding para la red neuronal

 
# Change the labels from categorical to one-hot encoding
train_Y_one_hot = to_categorical(train_Y)
test_Y_one_hot = to_categorical(test_Y)

# Display the change for category label using one-hot encoding
print('Original label:', train_Y[0])
print('After conversion to one-hot:', train_Y_one_hot[0])
 
Original label: 4
After conversion to one-hot: [0. 0. 0. 0. 1. 0. 0. 0. 0. 0.]
 

Creamos el Set de datos para Entrenamiento y Validación

 
#Mezclar todo y crear los grupos de entrenamiento y testing
train_X,valid_X,train_label,valid_label = train_test_split(train_X, train_Y_one_hot, test_size=0.2, random_state=13)
 
print(train_X.shape,valid_X.shape,train_label.shape,valid_label.shape)
 
(49361, 21, 28, 3) (12341, 21, 28, 3) (49361, 10) (12341, 10)
 

Creamos el modelo de Redes Neuronales Convolucionales

 
#declaramos variables con los parámetros de configuración de la red
INIT_LR = 1e-3 # Valor inicial de learning rate. El valor 1e-3 corresponde con 0.001
epochs = 6 # Cantidad de iteraciones completas al conjunto de imagenes de entrenamiento
batch_size = 64 # cantidad de imágenes que se toman a la vez en memoria
 
sport_model = Sequential()
sport_model.add(Conv2D(32, kernel_size=(3, 3),activation='linear',padding='same',input_shape=(21,28,3)))
sport_model.add(LeakyReLU(alpha=0.1))
sport_model.add(MaxPooling2D((2, 2),padding='same'))
sport_model.add(Dropout(0.5))

sport_model.add(Flatten())
sport_model.add(Dense(32, activation='linear'))
sport_model.add(LeakyReLU(alpha=0.1))
sport_model.add(Dropout(0.5))
sport_model.add(Dense(nClasses, activation='softmax'))
 
sport_model.summary()
 
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_1 (Conv2D)            (None, 21, 28, 32)        896       
_________________________________________________________________
leaky_re_lu_1 (LeakyReLU)    (None, 21, 28, 32)        0         
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 11, 14, 32)        0         
_________________________________________________________________
dropout_1 (Dropout)          (None, 11, 14, 32)        0         
_________________________________________________________________
flatten_1 (Flatten)          (None, 4928)              0         
_________________________________________________________________
dense_1 (Dense)              (None, 32)                157728    
_________________________________________________________________
leaky_re_lu_2 (LeakyReLU)    (None, 32)                0         
_________________________________________________________________
dropout_2 (Dropout)          (None, 32)                0         
_________________________________________________________________
dense_2 (Dense)              (None, 10)                330       
=================================================================
Total params: 158,954
Trainable params: 158,954
Non-trainable params: 0
_________________________________________________________________
 
sport_model.compile(loss=keras.losses.categorical_crossentropy, optimizer=keras.optimizers.Adagrad(lr=INIT_LR, decay=INIT_LR / 100),metrics=['accuracy'])
 

Entrenando el modelo con 6 épocas

Acá la red neuronal  aprenderá  a clasificar las imágenes

 
# este paso puede tomar varios minutos, dependiendo de tu ordenador, cpu y memoria ram libre
# como ejemplo, en mi Macbook pro tarda 4 minutos
sport_train = sport_model.fit(train_X, train_label, batch_size=batch_size,epochs=epochs,verbose=1,validation_data=(valid_X, valid_label))
 
Train on 49361 samples, validate on 12341 samples
Epoch 1/6
49361/49361 [==============================] - 52s 1ms/step - loss: 1.4976 - acc: 0.5007 - val_loss: 1.0535 - val_acc: 0.7835
Epoch 2/6
49361/49361 [==============================] - 52s 1ms/step - loss: 1.1890 - acc: 0.6135 - val_loss: 0.8914 - val_acc: 0.8088
Epoch 3/6
49361/49361 [==============================] - 53s 1ms/step - loss: 1.0780 - acc: 0.6581 - val_loss: 0.7971 - val_acc: 0.8288
Epoch 4/6
49361/49361 [==============================] - 53s 1ms/step - loss: 1.0152 - acc: 0.6749 - val_loss: 0.7364 - val_acc: 0.8421
Epoch 5/6
49361/49361 [==============================] - 57s 1ms/step - loss: 0.9631 - acc: 0.6956 - val_loss: 0.6945 - val_acc: 0.8523
Epoch 6/6
49361/49361 [==============================] - 62s 1ms/step - loss: 0.9226 - acc: 0.7102 - val_loss: 0.6546 - val_acc: 0.8592
 
# guardamos la red, para reutilizarla en el futuro, sin tener que volver a entrenar
sport_model.save("sports_mnist.h5py")
 

Evaluamos la precisión de la red para predecir

 
test_eval = sport_model.evaluate(test_X, test_Y_one_hot, verbose=1)
 
15426/15426 [==============================] - 5s 310us/step
 
print('Test loss:', test_eval[0])
print('Test accuracy:', test_eval[1])
 
Test loss: 0.6547213139182226
Test accuracy: 0.857189161156489
 
accuracy = sport_train.history['acc']
val_accuracy = sport_train.history['val_acc']
loss = sport_train.history['loss']
val_loss = sport_train.history['val_loss']
epochs = range(len(accuracy))
plt.plot(epochs, accuracy, 'bo', label='Training accuracy')
plt.plot(epochs, val_accuracy, 'b', label='Validation accuracy')
plt.title('Training and validation accuracy')
plt.legend()
plt.figure()
plt.plot(epochs, loss, 'bo', label='Training loss')
plt.plot(epochs, val_loss, 'b', label='Validation loss')
plt.title('Training and validation loss')
plt.legend()
plt.show()
 
 
 
predicted_classes2 = sport_model.predict(test_X)
 
predicted_classes=[]
for predicted_sport in predicted_classes2:
    predicted_classes.append(predicted_sport.tolist().index(max(predicted_sport)))
predicted_classes=np.array(predicted_classes)
 
predicted_classes.shape, test_Y.shape
 
((15426,), (15426,))
 

Con los errores encontrados , evaluamos que cosas podemos mejorar y disminuir los falsos (-)

 
correct = np.where(predicted_classes==test_Y)[0]
print("Found %d correct labels" % len(correct))
for i, correct in enumerate(correct[0:9]):
    plt.subplot(3,3,i+1)
    plt.imshow(test_X[correct].reshape(21,28,3), cmap='gray', interpolation='none')
    plt.title("{}, {}".format(deportes[predicted_classes[correct]],
                                                    deportes[test_Y[correct]]))

    plt.tight_layout()
 
Found 13223 correct labels
 
 
incorrect = np.where(predicted_classes!=test_Y)[0]
print("Found %d incorrect labels" % len(incorrect))
for i, incorrect in enumerate(incorrect[0:9]):
    plt.subplot(3,3,i+1)
    plt.imshow(test_X[incorrect].reshape(21,28,3), cmap='gray', interpolation='none')
    plt.title("{}, {}".format(deportes[predicted_classes[incorrect]],
                                                    deportes[test_Y[incorrect]]))
    plt.tight_layout()
 
Found 2203 incorrect labels
 
 

Matriz de confusión para la evaluación de falsos + y falsos –

 
target_names = ["Class {}".format(i) for i in range(nClasses)]
print(classification_report(test_Y, predicted_classes, target_names=target_names))
 
              precision    recall  f1-score   support

     Class 0       0.75      0.71      0.73      1911
     Class 1       0.82      0.91      0.86      1707
     Class 2       0.86      0.77      0.82      1540
     Class 3       0.91      0.92      0.91      1377
     Class 4       0.98      0.99      0.99      1571
     Class 5       0.87      0.44      0.59      1063
     Class 6       0.94      0.84      0.89      1488
     Class 7       0.70      0.93      0.80      1928
     Class 8       0.91      0.95      0.93      1000
     Class 9       0.98      1.00      0.99      1841

    accuracy                           0.86     15426
   macro avg       0.87      0.85      0.85     15426
weighted avg       0.86      0.86      0.85     15426