<jupyter_start><jupyter_text>SAR 2020AI Masters Class              Image Classifier     **CHEST XRAY CLASSIFIER**Construyamos un clasificador de imágenes desde cero y veamos si podemos usarlo para diferenciar las radiografías de tórax frontales de las laterales.Las radiografías de tórax frontal y lateral son tan similares dentro de una clase y tan diferentes entre clases que diferenciarlas es una tarea trivial para una red neuronal. Pero, puede usar el * mismo código exacto * para entrenar al clasificador para diferenciar cualquier otra clase de imágenes:* Neumotórax vs neumonía vs normal* Accidente cerebrovascular vs sin accidente cerebrovascular* HCC vs adenoma* Perro caliente vs no un perro calienteCuanto más sutiles sean las diferencias entre tus clases, más datos de entrenamiento (y tiempo) necesitarás.---Este tutorial se basa en la Lección 1 de Practical Deep Learning for Coders v3, un curso gratuito que ofrece [fast.ai] (https://course.fast.ai/). Recomiendo encarecidamente a todos los interesados que visiten fast.ai para obtener más información: es el mejor recurso que existe para aprender y ponerse al día en la clasificación de imágenes, así como en tareas más avanzadas como detección de objetos, segmentación de imágenes y procesamiento del lenguaje natural.<jupyter_code>!pip3 install fastai | grep -v 'already satisfied'
from fastai.vision import *
from fastai.metrics import error_rate
from fastai.callbacks.hooks import *
from fastai.imports import *
from fastai import *

import os
!rm -rf images
!rm -rf sample_data 

!wget -q --no-check-certificate 'https://www.dropbox.com/s/p32oela6ac63d7e/cxr.zip' -O ./cxr.zip
!mkdir images
!cd images; unzip -q "../cxr.zip" 
!rm -rf ./images/__MACOSX
!ls images
# Guarde la ruta a nuestro directorio de imágenes en una variable llamada ruta
path = Path('/content/images/cxr/')
# get_image_files es una función de conveniencia de fastai.vision que busca en `path` y devuelve una lista de todos los archivos de imagen que encuentra
filenames = get_image_files(path)
print(filenames[99])<jupyter_output><empty_output><jupyter_text>Como puede ver en el nombre de archivo de ejemplo, la * clase de imagen * está codificada en el nombre del archivo. Este es un método común de etiquetar imágenes para el aprendizaje automático: garantiza que la etiqueta correcta siempre esté asociada con cada imagen en lugar de en un archivo separado.Todas las imágenes se nombran de manera coherente:> `{class}_{serial number}.jpg`> `frontal_0001.jpg`, `lateral_0056.jpg`, etc.---** Protip **Cuando puede identificar un * patrón * que aísla el texto que desea de una cadena más larga, puede usar * expresiones regulares *, o * RegEx *, para extraer el texto. El patrón RegEx para extraer la clase (frontal o lateral) de la ruta completa del archivo ('/content/images/cxr/lateral_0062.jpg') es:> **`/([^/]+)_\d+.jpg$`**Guardaremos este patrón RegEx como una variable llamada `pattern`.Obtenga más información sobre RegEx y practique en [Pythex.org] (https://pythex.org/).<jupyter_code>pattern = re.compile(r'/([^/]+)_\d+.jpg$')
# Establezca los argumentos necesarios para fastai ImageDataBunch
validation_percentage=0.5 #Haremos una división 50:50: entrenar al 50%, validar al 50%
batchsize = 8 # Pesos de red actualizados después de cada lote. El tamaño depende de la memoria de la GPU y del tamaño de la imagen
imagesize=224 # Las imágenes cambiarán de tamaño a 224x224 px
# Aplicar transformaciones de imagen aleatorias: volteo horizontal, pequeñas rotaciones, etc.
# Básicamente multiplica la cantidad de imágenes únicas disponibles
transforms = get_transforms()
np.random.seed(25)
# Un ImageDataBunch es una construcción de datos rápida que ensambla las imágenes y la configuración requerida
# y los prepara para cargarlos en la red neuronal.
# Las diferentes bibliotecas de aprendizaje automático tienen semánticas ligeramente diferentes para estos objetos de carga de datos
data = ImageDataBunch.from_name_re(
    path, 
    filenames, 
    pattern, 
    valid_pct=validation_percentage, 
    ds_tfms = transforms, 
    size=imagesize, 
    bs=batchsize).normalize(imagenet_stats)
# Podemos mirar ImageDataBunch y ver que contiene conjuntos de datos de validación y entrenamiento separados
data
# ImageDataBunch tiene dos clases [frontal, lateral], y 50 imágenes cada una en los conjuntos de datos de entrenamiento y validación
data.classes, data.c, len(data.train_ds), len(data.valid_ds)
# Podemos mostrar un lote de 8 imágenes con sus etiquetas asociadas de verdad fundamental
# Tenga en cuenta que algunas de las imágenes se han volteado horizontalmente de forma arbitraria
data.show_batch(rows=3, figsize=(10,8))
# Construya el alumno de la red neuronal pasándole nuestro ImageDataBunch
# Tenga en cuenta que lo estamos basando en una red existente, llamada Resnet34
# Resnet34 está preentrenado en ImageNet, que aprendió de millones de imágenes regulares
# Esperamos transferir lo que ImageNet ya sabe al dominio CXR
learn = cnn_learner(
    data,
    models.resnet34,
    metrics=(error_rate, accuracy)
)
# ¡Finalmente comenzaremos a entrenar la red!
# Haremos que revise las 50 imágenes de entrenamiento 4 veces
# Cada vez a lo largo de todo el conjunto de entrenamiento se denomina una época
# Recuerde que definimos un lote como 8 imágenes, por lo que después de cada 8 imágenes la red ajustará su configuración
# Después de cada época, informará su tasa de error actual y precisión
learn.fit_one_cycle(4)
# Podemos guardar el modelo entrenado y usarlo más tarde para evaluar nuevos CXR
learn.save('cxr-frontlat-stage1')
learn.export()
# El objetivo de entrenar una red neuronal es "minimizar la función de pérdida"
# La función de pérdida es una fórmula que cuantifica qué tan lejos del rendimiento perfecto en la tarea asignada está la red.
# Después de cada lote, la red mide qué tan lejos de ser perfecto está y ajusta sus parámetros
# de tal manera que se acerque un poco más a la perfección.
# La cantidad por la cual se ajustan los parámetros está determinada por la Tasa de aprendizaje (LR)
learn.recorder.plot_losses()
# Podemos visualizar los casos en los que la red se equivocó o acertó pero con menos confianza
interp = ClassificationInterpretation.from_learner(learn)
interp.plot_top_losses(9, figsize=(15,11), heatmap=True)
# Una matriz de confusión traza los gráficos predichos vs reales
# Es más útil cuando hay varias clases y puedes ver qué clases es confuso para qué otras
interp.plot_confusion_matrix(figsize=(3,3), dpi=200)
# Descargue un nuevo lote de radiografías de tórax que no estén relacionadas con las que se usan para entrenar
!wget --no-check-certificate 'https://www.dropbox.com/s/639j1pbq12gs107/palat.zip' -O ./palat.zip

!cd images; unzip -q "../palat.zip" 
!rm -rf ./images/__MACOSX
!ls images
# Descargue un nuevo lote de radiografías de tórax que no estén relacionadas con las que se usan para entrenar
learn = load_learner('/content/images/cxr/', test=ImageImageList.from_folder('/content/images/palat/test/'))
pred,y = learn.get_preds(ds_type=DatasetType.Test)
# Mire una instantánea de las predicciones - podemos ver que es una lista donde cada entrada son dos números -
# la probabilidad que la red asigna a que el CXR dado sea un PA o lateral.
# El número más alto se considera la asignación de clase para ese CXR
pred[205:210].data.numpy()
# Argmax simplemente elige el índice del mayor número de opciones disponibles
# En este caso, elija el número más alto para cada fila en la lista de predicciones
lbls = np.argmax(pred, axis=1)
lbls[205:210]
# Recordatorio de cómo se definieron originalmente nuestras clases
classes = ['frontal','lateral']
print(classes)
for x in range(205, 210):
    print("Test Image %d" % x)
    print("Network prediction [frontal, lateral]: %s" % (pred[x]).data.numpy())
    print("np.argmax of prediction matrix.......: %s" % (lbls[x]).data.numpy())
    print("Predicted class......................: %s" % (classes[lbls[x]]))
    print()
# Imprima todas las imágenes de prueba con la etiqueta asignada por nuestra red capacitada
ims = learn.data.test_ds.x
rows = 40
cols = 10
figsize=(20,70)
fig,axes = plt.subplots(rows,cols,figsize=figsize)
fig.suptitle('predictions', weight='bold',size=14)
for idx,im in enumerate(ims):
  im.show(ax=axes.flat[idx], title=classes[lbls[idx]])<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.07559602252306218, 'fraction_numerical': 0.014017012100155745, 'mean_word_length': 4.84184744576627, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 12, 'https://': 4, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '2', 'dir': 'jupyter-structured-clean-dedup', 'id': '603708', 'license': 'Apache-2.0', 'n_tokens_mistral': 2858, 'n_tokens_neox': 2745, 'n_words': 1063, 'path': '03 - Image_Classifier.ipynb', 'repo_name': 'JhennerTigreros/SAR2020', 'size': '8347'}