Analyse des résultats de l'architecture YoloV3 sur des images médicales

Cet article est une critique de l' article original de Medium (des expériences sont en cours avec des modifications de certaines conditions).





Le domaine d'application des réseaux de neurones en médecine se développe rapidement. Dans ce domaine, des tùches sont résolues qui facilitent le travail des médecins. En particulier, l'une des tùches demandées dans ce domaine est la détection d'objets dans les images médicales (c'est lorsqu'un rectangle est superposé à l'image, ce qui limite la zone dans laquelle il y a supposément un objet). Un exemple d'une telle image est montré ci-dessous.





https://github.com/ultralytics/yolov3
https://github.com/ultralytics/yolov3

https://github.com/ultralytics/yolov3





, - . person tie. ( person 0.59, tie - 0.62). (, , , , ..), , , , , . ( , "person 0.59". , person - - 0.59). , - , 0 1.





, , . , , .





, . , 20 . 2019- ( 2,6 ). . - , . .





, , .





, , ( - ) , ( ).





.





YOLOv3. ? , =) .





YOLOv3 , YOLO (You Only Look Once). , CNN (Convolutional Neural Network) ( ). YOLOv3 106- . , YOLOv3 ( 3), . YOLOv3:





https://www.researchgate.net/figure/The-framework-of-YOLOv3-neural-network-for-ship-detection_fig2_335228064
https://www.researchgate.net/figure/The-framework-of-YOLOv3-neural-network-for-ship-detection_fig2_335228064

https://www.researchgate.net/figure/The-framework-of-YOLOv3-neural-network-for-ship-detection_fig2_335228064





YOLO 13 13. ? , bounding box' ( ) , . (, ) confidence value ( ). , , (, ). YOLOv3.





https://medium.com/nerd-for-tech/a-real-time-object-detection-model-using-yolov3-algorithm-for-non-gpu-computers-8941a20b445
https://medium.com/nerd-for-tech/a-real-time-object-detection-model-using-yolov3-algorithm-for-non-gpu-computers-8941a20b445

https://medium.com/nerd-for-tech/a-real-time-object-detection-model-using-yolov3-algorithm-for-non-gpu-computers-8941a20b445





, YOLO , anchor boxes ( ). Medium. ( ) . , anchor boxes ( ) bounding box' COCO k-.





YOLOv3 .





, . ? , . Kaggle, . .





. stage_2_train_images.zip stage_2_test_images.zip. , , . ( ) 26684 . DICOM 1024 1024. .





Class





Target





Patients





Lung Opacity





1





9555





No Lung Opacity / Not Normal





0





11821





Normal





0





8851





DICOM. JPG .





import pydicom as dicom
import os
from tqdm import tqdm
import numpy as np
import cv2
import pandas as pd

 dicom  jpg
def dicom_to_jpg(source_folder,destination_folder,labels):
    images_path = os.listdir(source_folder)
    image_dirs_label = {'image_dir':[],'Target':[]}
    for n, image in tqdm(enumerate(images_path)):
        ds = dicom.dcmread(os.path.join(source_folder, image))
        pixel_array_numpy = ds.pixel_array
        image = image.replace('.dcm', '.jpg')
        cv2.imwrite(os.path.join(destination_folder, image), pixel_array_numpy)
        image_dirs_label['image_dir'].append(os.path.join(destination_folder, image))
        image_dirs_label['Target'].append(train_labels[train_labels.patientId== image.split('.')[0]].Target.values[0])
    print('{} dicom files converted to jpg!'.format(len(images_path)))
    return pd.DataFrame(image_dirs_label)
      
      



3 , : Normal — 0, No Lung Opacity / Not Normal — 0, Lung Opacity — 1. Class, Target Patients, , . .





, (positive Lung Opacity). (negative) 1:4 ( , ).





Déséquilibre de classe





( , ). (positive) — . Albumentations. .





import albumentations as A
import pandas as pd
import cv2
import os
transformer
transform = A.Compose([
        A.RandomRotate90(),
        A.Flip(),
        A.Transpose(),
        A.OneOf([
            A.IAAAdditiveGaussianNoise(),
            A.GaussNoise(),
        ], p=0.2),
        A.OneOf([
            A.MotionBlur(p=.2),
            A.MedianBlur(blur_limit=3, p=0.1),
            A.Blur(blur_limit=3, p=0.1),
        ], p=0.2),
        A.ShiftScaleRotate(shift_limit=0.0625, scale_limit=0.2, rotate_limit=45, p=0.2),
        A.OneOf([
            A.OpticalDistortion(p=0.3),
            A.GridDistortion(p=.1),
            A.IAAPiecewiseAffine(p=0.3),
        ], p=0.2),
        A.OneOf([
            A.CLAHE(clip_limit=2),
            A.IAASharpen(),
            A.IAAEmboss(),
            A.RandomBrightnessContrast(),        ], p=0.3),
        A.HueSaturationValue(p=0.3),
    ])
      
      



( " ", , )





"". JPG DICOM YOLOv3 (backbone') DarkNet. DarkNet . YOLOv3 ( Darknet) CheXNet. CheXNet 121- , , . CheXNet. 14 , , CheXNet 2- (negative — positive — ). TensorFlow, DenseNet121. .





#  CheXNet   classifier_weights.hdf5,    
https://drive.google.com/file/d/1Bd50DpRWorGMDuEZ3-VHgndpJZwUGTAr/view
from absl import flags
from absl.flags import FLAGS
import numpy as np
import tensorflow as tf
from tensorflow.keras import Model
from tensorflow.keras.applications import DenseNet121
from tensorflow.keras.layers import (
    Add,
    Concatenate,
    Conv2D,
    Input,
    Lambda,
    LeakyReLU,
    MaxPool2D,
    UpSampling2D,
    ZeroPadding2D,
    BatchNormalization,
    Dense
)
def base_model(chexnet_weights=None,size=None):
    dense_net_121 = DenseNet121(input_shape = [size,size,3], include_top = False,pooling = 'avg')
    base_model_output = Dense(units = 14, activation = 'relu')(dense_net_121.output)
    base_model = Model(inputs = dense_net_121.input,outputs = base_model_output)
    output_layer = Dense(1, activation = 'sigmoid')(base_model.layers[-2].output)
    model = Model(inputs = base_model.inputs, outputs = output_layer)
    if chexnet_weights:
        model.load_weights(chexnet_weights)
    final_base_model = Model(inputs = model.inputs, outputs = model.layers[-3].output)
    return final_base_model
def ChexNet(name=None, chexnet_weights='PATH_TO_WEIGTHS/classifier_weights.hdf5',size=None):
    chexnet = base_model(chexnet_weights = chexnet_weights, size = size)
    back_bone = Model(inputs = chexnet.inputs, outputs=(chexnet.get_layer('pool3_conv').output,
                                                           chexnet.get_layer('pool4_conv').output,
                                                           chexnet.output),name=name)
    return back_bone
      
      



:





Model





Total params





Trainable params





Non-trainable params





DarkNet





61576342





61523734





52608





CheXNet





27993206





27892662





100544





, CheXNet 2 , DarkNet. CheXNet.





YOLOv3 CheXNet ( ).





, (1 ) (positive negative), , ( positive). YOLOv3 416 416 13 13 (416 / 32 = 13). 13 13. anchor box' 3, 13 13 3- anchor box'. 13 13 3 = 507 ( ). , 507 . positive ( ) 2 (), 2 507-2=505 . , . , "" .





, ImageDataGenerator . , ( ), .





# true_augmented_labels -  DataFrame,    
   (  ,  ()
datagen=ImageDataGenerator(
        rescale = 1. / 255.,
        validation_split = 0.20)
train_generator = datagen.flow_from_dataframe(
dataframe = true_augmented_labels,
x_col = "image_dir",
y_col = "Target",
subset = "training",
batch_size = 4,
seed = 42,
shuffle = True,
class_mode = "binary",
target_size = (416, 416))
valid_generator = datagen.flow_from_dataframe(
dataframe = true_augmented_labels,
x_col = "image_dir",
y_col = "Target",
subset = "validation",
batch_size = 4,
seed = 42,
shuffle = True,
class_mode = "binary",
target_size = (416, 416))
      
      



( positive, negative), .





#  brucechou1983_CheXNet_Keras_0.3.0_weights.h5  classifier_weights.hdf5
   https://www.kaggle.com/theewok/chexnet-keras-weights/version/1
  https://github.com/junaidnasirkhan/Replacing-YoloV3-Backbone-with-ChexNet-for-Pneumonia-Detection
dense_net_121 = DenseNet121(input_shape = [416,416] + [3], include_top = False, pooling = 'avg')
base_model_output = Dense(units = 14, activation = 'relu')(dense_net_121.output)
base_model = Model(inputs = dense_net_121.input, outputs = base_model_output)
 "" 
base_model.load_weights('brucechou1983_CheXNet_Keras_0.3.0_weights.h5')
   
for layer in base_model.layers[:10]:
    layer.trainable = False
      
output_layer = Dense(1, activation = 'sigmoid')(base_model.layers[-2].output)
model = Model(inputs = base_model.inputs, outputs = output_layer)
model.compile(optimizer = 'adam', loss = 'binary_crossentropy', metrics = ['accuracy', f1_m]) 
checkpoint = ModelCheckpoint(filepath = 'classifier_weights.hdf5', monitor = 'val_accuracy',  verbose = 0, save_best_only = True, save_weights_only = True, mode = 'auto')
log_dir = "classifier_logs/" + datetime.datetime.now().strftime("%Y%m%d-%H%M%S")
tensorboard = TensorBoard(log_dir = log_dir, histogram_freq = 1, write_graph = True, write_grads = True)
callback_list = [checkpoint, tensorboard]
 
model.fit(train_generator,
  validation_data = valid_generator,
  epochs = 1, #     3
  steps_per_epoch = len(train_generator),
  callbacks = callback_list)
      
      



positive ( ).





#       rsna_train_pos.tfrecord  rsna_val_pos.tfrecord
     .names (  )
  "opacity"  "no_opacity"
model = train(dataset = 'PATH_TO_TFRECORD/rsna_train_pos.tfrecord',
          val_dataset = 'PATH_TO_TFRECORD/rsna_val_pos.tfrecord',
          backbone = 'chexnet',
          classes = 'PATH_TO_CLASSES/RSNA_VOC.names', 
          size = 416,
          epochs = 30,
          batch_size = 16,          learning_rate = 1e-4,
          num_classes = 1)
      
      



hdf5.





(YOLOv3 CheXNet).





learning_rate = 1e-4, epoch = 20





loss'





learning_rate = 1e-4, epochs = 30





loss'





  • .





  • CheXNet DarkNet , CheXNet, DarkNet.





  • CheXNet 1 , 20 30 , .





  • , epoch, .





. :





  • ( , learning_rate)









  • CheXNet





  • Vers l' article original sur Medium





  • Vers mon GitHub








All Articles