text_plain_output_1.png
from glob import glob

from itertools import chain

from keras.applications.resnet_v2 import ResNet50V2

from keras.callbacks import ModelCheckpoint, LearningRateScheduler, EarlyStopping, TensorBoard, ReduceLROnPlateau

from keras.layers import Conv2D, SeparableConv2D, MaxPool2D, LeakyReLU, Activation

from keras.layers import GlobalAveragePooling2D, MaxPooling2D, Reshape

from keras.layers import Input, Dense, Flatten, Dropout, BatchNormalization, AveragePooling2D

from keras.models import Sequential, Model

from keras.models import model_from_json

from keras.optimizers import Adam, RMSprop

from keras.preprocessing.image import ImageDataGenerator

from random import sample

from sklearn.metrics import roc_curve, auc, precision_recall_curve, average_precision_score, plot_precision_recall_curve, f1_score, confusion_matrix, accuracy_score

import matplotlib.pyplot as plt

import numpy as np # linear algebra

import os

import pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)

import sklearn.model_selection as skl

all_xray_df = pd.read_csv('/kaggle/input/data/Data_Entry_2017.csv')
all_image_paths = {os.path.basename(x): x for x in glob(os.path.join('/kaggle/input/data', 'images*', '*', '*.png'))}
all_xray_df['path'] = all_xray_df['Image Index'].map(all_image_paths.get)
all_xray_df.sample(3)

all_labels = np.unique(list(chain(*all_xray_df['Finding Labels'].map(lambda x: x.split('|')).tolist())))
all_labels = [x for x in all_labels if len(x) > 0]
for c_label in all_labels:
    if len(c_label) > 1:
        all_xray_df[c_label] = all_xray_df['Finding Labels'].map(lambda finding: 1.0 if c_label in finding else 0)
all_xray_df['pneumonia_class'] = all_xray_df['Pneumonia']
all_xray_df.sample(3)

def create_splits(df, test_size, column_name):
    train_df, valid_df = skl.train_test_split(df, test_size=test_size, stratify=df[column_name])
    p_inds = train_df[train_df[column_name] == 1].index.tolist()
    np_inds = train_df[train_df[column_name] == 0].index.tolist()
    np_sample = sample(np_inds, len(p_inds))
    train_df = train_df.loc[p_inds + np_sample]
    p_inds = valid_df[valid_df[column_name] == 1].index.tolist()
    np_inds = valid_df[valid_df[column_name] == 0].index.tolist()
    np_sample = sample(np_inds, 4 * len(p_inds))
    valid_df = valid_df.loc[p_inds + np_sample]
    return (train_df, valid_df)
train_df, valid_df = create_splits(all_xray_df, 0.2, 'pneumonia_class')

def my_image_augmentation():
    my_idg = ImageDataGenerator(rescale=1.0 / 255.0, horizontal_flip=True, vertical_flip=False, height_shift_range=0.1, width_shift_range=0.1, rotation_range=20, shear_range=0.1, zoom_range=0.1)
    return my_idg
def make_train_gen(train_df, img_size, batch_size):
    idg = my_image_augmentation()
    train_gen = idg.flow_from_dataframe(dataframe=train_df, directory=None, x_col='path', y_col='pneumonia_class', class_mode='raw', target_size=img_size, batch_size=batch_size)
    return train_gen
def make_val_gen(valid_df, img_size, batch_size):
    val_idg = ImageDataGenerator(rescale=1.0 / 255.0)
    val_gen = val_idg.flow_from_dataframe(dataframe=valid_df, directory=None, x_col='path', y_col='pneumonia_class', class_mode='raw', target_size=img_size, batch_size=batch_size)
    return val_gen
batch_size = 64
img_size = (224, 224)
train_gen = make_train_gen(train_df, img_size, batch_size)
val_gen = make_val_gen(valid_df, img_size, batch_size)

## May want to look at some examples of our augmented training data. 
## This is helpful for understanding the extent to which data is being manipulated prior to training, 
## and can be compared with how the raw data look prior to augmentation

t_x, t_y = next(train_gen)
fig, m_axs = plt.subplots(4, 4, figsize = (16, 16))
for (c_x, c_y, c_ax) in zip(t_x, t_y, m_axs.flatten()):
    c_ax.imshow(c_x[:,:,0], cmap = 'bone')
    if c_y == 1: 
        c_ax.set_title('Pneumonia')
    else:
        c_ax.set_title('No Pneumonia')
    c_ax.axis('off')

def load_pretrained_model():
    """
    model = VGG16(include_top=True, weights='imagenet')
    transfer_layer = model.get_layer('block5_pool')
    vgg_model = Model(inputs = model.input, outputs = transfer_layer.output)
    for layer in vgg_model.layers[0:17]:
        layer.trainable = False
    """
    model = ResNet50V2(include_top=False, weights='imagenet')
    resnet_model = Model(inputs=model.input, outputs=model.output, name='Resnet')
    return resnet_model

def build_my_model():
    """
    # my_model = Sequential()
    # ....add your pre-trained model, and then whatever additional layers you think you might
    # want for fine-tuning (Flatteen, Dense, Dropout, etc.)
    # if you want to compile your model within this function, consider which layers of your pre-trained model, 
    # you want to freeze before you compile 
    # also make sure you set your optimizer, loss function, and metrics to monitor
    # Todo
    my_model = Sequential()
    vgg_model = load_pretrained_model()
    # Add the convolutional part of the VGG16 model from above.
    my_model.add(vgg_model)
    # Flatten the output of the VGG16 model because it is from a
    # convolutional layer.
    my_model.add(Flatten())
    # Add a dropout-layer which may prevent overfitting and
    # improve generalization ability to unseen data e.g. the test-set.
    my_model.add(Dropout(0.5))
    # Add a dense (aka. fully-connected) layer.
    # This is for combining features that the VGG16 model has
    # recognized in the image.
    my_model.add(Dense(1024, activation='relu'))
    # Add a dropout-layer which may prevent overfitting and
    # improve generalization ability to unseen data e.g. the test-set.
    my_model.add(Dropout(0.5))
    # Add a dense (aka. fully-connected) layer.
    # This is for combining features that the VGG16 model has
    # recognized in the image.
    my_model.add(Dense(512, activation='relu'))
    # Add a dropout-layer which may prevent overfitting and
    # improve generalization ability to unseen data e.g. the test-set.
    my_model.add(Dropout(0.5))
    # Add a dense (aka. fully-connected) layer.
    # This is for combining features that the VGG16 model has
    # recognized in the image.
    my_model.add(Dense(256, activation='relu'))
    # Add a dropout-layer which may prevent overfitting and
    # improve generalization ability to unseen data e.g. the test-set.
    my_model.add(Dropout(0.5))
    # Add a dense (aka. fully-connected) layer.
    # This is for combining features that the VGG16 model has
    # recognized in the image.
    my_model.add(Dense(1, activation='sigmoid'))
    """
    resnet_model = load_pretrained_model()
    my_model = Sequential([resnet_model, BatchNormalization(), Conv2D(1024, 1, activation='relu'), Dropout(0.5), BatchNormalization(), Conv2D(256, 1, activation='relu'), Dropout(0.5), AveragePooling2D((7, 7)), BatchNormalization(), Conv2D(1, 1, activation='sigmoid'), Reshape((-1,))])
    return my_model
my_model = build_my_model()
my_model.summary()

weight_path = '{}_my_model.best.hdf5'.format('xray_class')
checkpoint = ModelCheckpoint(weight_path, monitor='val_binary_accuracy', verbose=1, save_best_only=True, mode='auto', save_weights_only=True)
early = EarlyStopping(monitor='val_binary_accuracy', mode='auto', patience=5)
def scheduler(epoch, lr):
    if epoch < 1:
        return lr
    else:
        return lr * np.exp(-0.1)
lr_scheduler = LearningRateScheduler(scheduler)
callbacks_list = [checkpoint, early, lr_scheduler]

from keras.models import model_from_json
model_path = '/kaggle/input/model-and-weights/my_model2.json'
weight_path = '/kaggle/input/model-and-weights/xray_class_my_model2.best.hdf5'
json_file = open(model_path, 'r')
loaded_model_json = json_file.read()
json_file.close()
my_model = model_from_json(loaded_model_json)
my_model.load_weights(weight_path)

optimizer = RMSprop(learning_rate=0.0001)
loss = 'binary_crossentropy'
metrics = ['binary_accuracy']
my_model.compile(optimizer=optimizer, loss=loss, metrics=metrics)
history = my_model.fit_generator(train_gen, validation_data=(valX, valY), epochs=10, callbacks=callbacks_list)

weight_path = 'xray_class_my_model.best.hdf5'
my_model.load_weights(weight_path)
pred_Y = my_model.predict(valX, batch_size=100, verbose=True)

def plot_auc(t_y, p_y):
    fpr, tpr, threshold = roc_curve(valY, pred_Y)
    roc_auc = auc(fpr, tpr)
    plt.xlim([0, 1])
    plt.ylim([0, 1])
    return
def plot_prec_rec(val_Y, pred_Y):
    prec, rec, threshold = precision_recall_curve(val_Y, pred_Y)
    plt.xlim([0, 1])
    plt.ylim([0, 1])
def plot_history(history):
    n = len(history.history['loss'])
    return

def optimize_accuracy(t_y, p_y):
    best_threshold = None
    best_accuracy = 0.0
    for t in np.arange(0.5, 1, 0.1):
        pred = (p_y.reshape(-1) > t) * 1.0
        accuracy = np.mean(pred == t_y)
        if accuracy > best_accuracy:
            best_threshold = t
            best_accuracy = accuracy
    return (best_threshold, best_accuracy)
best_threshold, best_accuracy = optimize_accuracy(valY, pred_Y)
print('Threshold of %.2f gives best accuracy at %.4f' % (best_threshold, best_accuracy))
pred_Y_class = pred_Y > best_threshold
f1_score(valY, pred_Y_class)