{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"!pip install git+https://github.com/qubvel/classification_models.git\n\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport os\nimport random\nimport cv2\nimport tensorflow as tf\n\nfrom math import ceil, floor\nfrom copy import deepcopy\nfrom tqdm.notebook import tqdm\nfrom imgaug import augmenters as iaa\n\nimport tensorflow.keras as keras\nimport tensorflow.keras.backend as K\nfrom tensorflow.keras.callbacks import Callback, ModelCheckpoint\nfrom tensorflow.keras.layers import Dense, Flatten, Dropout\nfrom tensorflow.keras.models import Model, load_model\nfrom tensorflow.keras.utils import Sequence\nfrom tensorflow.keras.losses import binary_crossentropy\nfrom tensorflow.keras.optimizers import Adam\nfrom tensorflow.keras.metrics import AUC, Recall, Precision, BinaryCrossentropy\nfrom classification_models.tfkeras import Classifiers\nfrom tensorflow.keras.layers import *\nfrom sklearn.utils.class_weight import compute_class_weight\n\ndef calculating_class_weights(y_true):\n    number_dim = np.shape(y_true)[1]\n    weights = np.empty([number_dim, 2])\n    for i in range(number_dim):\n        weights[i] = compute_class_weight('balanced', classes=np.unique(y_true[:, i]), y=y_true[:, i])\n    return weights\n\n\ndef ModelCheckpointFull(model_name):\n    return ModelCheckpoint(model_name, \n                            monitor = 'val_accuracy', \n                            verbose = 1, \n                            save_best_only = True, \n                            save_weights_only = True, \n                            mode = 'max', \n                            period = 1)\n\n# Create Model\ndef create_model(num_classes):\n    K.clear_session()\n    \n#     SE_resnext101, preprocess_input = Classifiers.get('seresnext101')\n#     engine = SE_resnext101(include_top=False,\n#                            input_shape=(256, 256, 3),\n#                            backend = tf.keras.backend,\n#                            layers = tf.keras.layers,\n#                            models = tf.keras.models,\n#                            utils = tf.keras.utils,\n#                           weights = 'imagenet')\n## densenet121\n    denseNet, preprocess_input = Classifiers.get('densenet121')\n    engine = denseNet(include_top=False,\n                           input_shape=(256, 256, 3),\n                           backend = tf.keras.backend,\n                           layers = tf.keras.layers,\n                           models = tf.keras.models,\n                           utils = tf.keras.utils,\n                          weights = 'imagenet')\n    \n\n##\n\n    x = GlobalAveragePooling2D(name='avg_pool')(engine.output)\n    x = Dropout(0.15)(x)\n    out = Dense(num_classes, activation='sigmoid', name='new_output')(x)\n    model = Model(inputs=engine.input, outputs=out)\n\n    return model\n\ndef metrics_define(num_classes):\n    metrics_all = ['accuracy',\n    AUC(curve='PR',multi_label=True,name='auc_pr'),\n    AUC(multi_label=True, name='auc_roc')\n    ]\n\n    return metrics_all\n\ndef get_weighted_loss(weights):\n    def weighted_loss(y_true, y_pred):\n        return K.mean((weights[:,0]**(1-y_true))*(weights[:,1]**(y_true))*K.binary_crossentropy(y_true, y_pred), axis=-1)\n    return weighted_loss","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2021-11-08T11:57:12.062521Z","iopub.execute_input":"2021-11-08T11:57:12.062768Z","iopub.status.idle":"2021-11-08T11:57:31.255612Z","shell.execute_reply.started":"2021-11-08T11:57:12.06269Z","shell.execute_reply":"2021-11-08T11:57:31.254812Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import pydicom\n\ndef correct_dcm(dcm):\n    x = dcm.pixel_array + 1000\n    px_mode = 4096\n    x[x>=px_mode] = x[x>=px_mode] - px_mode\n    dcm.PixelData = x.tobytes()\n    dcm.RescaleIntercept = -1000\n\ndef window_image(dcm, window_center, window_width):    \n    if (dcm.BitsStored == 12) and (dcm.PixelRepresentation == 0) and (int(dcm.RescaleIntercept) > -100):\n        correct_dcm(dcm)\n    img = dcm.pixel_array * dcm.RescaleSlope + dcm.RescaleIntercept\n    img = cv2.resize(img, SHAPE[:2], interpolation = cv2.INTER_LINEAR)\n    img_min = window_center - window_width // 2\n    img_max = window_center + window_width // 2\n    img = np.clip(img, img_min, img_max)\n    return img\n\ndef bsb_window(dcm):\n    brain_img = window_image(dcm, 40, 80)\n    subdural_img = window_image(dcm, 80, 200)\n    brain_img = (brain_img - 0) / 80\n    subdural_img = (subdural_img - (-20)) / 200\n    soft_img = window_image(dcm, 40, 380)\n    soft_img = (soft_img - (-150)) / 380\n    bsb_img = np.array([brain_img, subdural_img, soft_img]).transpose(1,2,0)\n    return bsb_img\n\ndef _read_dicom(path, SHAPE):\n    dcm = pydicom.dcmread(path)\n    try:\n        img = bsb_window(dcm)\n    except:\n        img = np.zeros(SHAPE)\n    return img","metadata":{"execution":{"iopub.status.busy":"2021-11-08T11:57:50.367571Z","iopub.execute_input":"2021-11-08T11:57:50.368335Z","iopub.status.idle":"2021-11-08T11:57:50.454668Z","shell.execute_reply.started":"2021-11-08T11:57:50.368294Z","shell.execute_reply":"2021-11-08T11:57:50.453785Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def _read_png(path, SHAPE):\n    img = cv2.imread(path)\n    img = cv2.resize(img, dsize=(256, 256))\n    return img/255.0\n\n# Image Augmentation\nsometimes = lambda aug: iaa.Sometimes(0.25, aug)\naugmentation = iaa.Sequential([ iaa.Fliplr(0.25),\n                                iaa.Flipud(0.10),\n                                sometimes(iaa.Crop(px=(0, 25), keep_size = True, sample_independently = False))   \n                            ], random_order = True)       \n        \n# Generators\nclass TrainDataGenerator(keras.utils.Sequence):\n    def __init__(self, dataset, class_names, batch_size = 16, img_size = (256, 256, 3), \n                 augment = False, shuffle = True, *args, **kwargs):\n        self.dataset = dataset\n        self.ids = self.dataset['imgfile'].values\n        self.labels = self.dataset[class_names].values\n        self.batch_size = batch_size\n        self.img_size = img_size\n        self.augment = augment\n        self.shuffle = shuffle\n        self.on_epoch_end()\n\n    def __len__(self):\n        return int(ceil(len(self.ids) / self.batch_size))\n\n    def __getitem__(self, index):\n        indices = self.indices[index*self.batch_size:(index+1)*self.batch_size]\n        X, Y = self.__data_generation(indices)\n        return X, Y\n\n    def augmentor(self, image):\n        augment_img = augmentation        \n        image_aug = augment_img.augment_image(image)\n        return image_aug\n\n    def on_epoch_end(self):\n        self.indices = np.arange(len(self.ids))\n        if self.shuffle:\n            np.random.shuffle(self.indices)\n\n    def __data_generation(self, indices):\n        X = np.empty((self.batch_size, *self.img_size))\n        Y = np.empty((self.batch_size, len(class_names)), dtype=np.float32)\n        \n        for i, index in enumerate(indices):\n            ID = self.ids[index]\n            if '.png' not in ID:\n                image = _read_dicom('../input/rsna-intracranial-hemorrhage-detection/rsna-intracranial-hemorrhage-detection/stage_2_train/'+ID+'.dcm', self.img_size)\n            else:\n                if 'NonHemo' in ID:\n                    image = _read_png('../input/cq500-normal-images-and-labels/'+ID, self.img_size)\n                else:\n                    if 'content' in ID:\n                        ID = ID[9:]\n                    image = _read_png('../input/rsna-cq500-abnormal-data/'+ID, self.img_size)\n            if self.augment:\n                X[i,] = self.augmentor(image)\n            else:\n                X[i,] = image\n            Y[i,] = self.labels[index]        \n        return X, Y","metadata":{"execution":{"iopub.status.busy":"2021-11-08T11:57:59.220134Z","iopub.execute_input":"2021-11-08T11:57:59.220473Z","iopub.status.idle":"2021-11-08T11:57:59.238877Z","shell.execute_reply.started":"2021-11-08T11:57:59.220439Z","shell.execute_reply":"2021-11-08T11:57:59.23823Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from prettytable import PrettyTable\nfrom sklearn import metrics\nfrom sklearn.metrics import roc_auc_score, accuracy_score, precision_score, recall_score, f1_score\nfrom sklearn.metrics import precision_recall_curve\nfrom sklearn.metrics import average_precision_score\nfrom sklearn.metrics import roc_curve, auc, roc_auc_score\nfrom sklearn.metrics import multilabel_confusion_matrix\nfrom sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay\nimport seaborn as sns\n\n\ndef print_confusion_matrix(y_test, y_pred, class_names):\n    matrix = confusion_matrix(y_test, y_pred)\n    plt.figure(figsize=(6, 4))\n    cm = matrix.astype('float') / matrix.sum(axis=1)[:, np.newaxis]\n    sns.heatmap(cm,cmap='crest',linecolor='white',linewidths=1,annot=True, xticklabels = class_names, yticklabels = class_names)\n    plt.title('Confusion Matrix')\n    plt.ylabel('True Label')\n    plt.xlabel('Predicted Label')\n    plt.show()\n\ndef print_performance_metrics(y_test, y_pred, class_names):\n    print('Accuracy:', np.round(metrics.accuracy_score(y_test, y_pred),4))\n    print('Precision:', np.round(metrics.precision_score(y_test, y_pred, average='weighted'),4))\n    print('Recall:', np.round(metrics.recall_score(y_test, y_pred, average='weighted'),4))\n    print('F1 Score:', np.round(metrics.f1_score(y_test, y_pred, average='weighted'),4))\n    print('Cohen Kappa Score:', np.round(metrics.cohen_kappa_score(y_test, y_pred), 4))\n    print('Matthews Corrcoef:', np.round(metrics.matthews_corrcoef(y_test, y_pred), 4))\n    if len(np.unique(y_test)) == 2:\n        print('ROC AUC:',roc_auc_score(y_test,y_pred))\n    print('\\t\\tClassification Report:\\n', metrics.classification_report(y_test, y_pred, target_names=class_names))\n","metadata":{"execution":{"iopub.status.busy":"2021-11-08T11:58:21.383518Z","iopub.execute_input":"2021-11-08T11:58:21.384193Z","iopub.status.idle":"2021-11-08T11:58:21.485584Z","shell.execute_reply.started":"2021-11-08T11:58:21.384137Z","shell.execute_reply":"2021-11-08T11:58:21.484864Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn.utils import shuffle\n\ntrain_df = pd.read_csv('../input/cq500-normal-images-and-labels/NormalAbnormal/NormalAbnormal/Train_f1.csv')\nabnormal = train_df.loc[train_df['Abnormal']==1]\ntrain_df = train_df.append(abnormal, ignore_index=True)\ntrain_df = shuffle(train_df)\n\nval_df = pd.read_csv('../input/cq500-normal-images-and-labels/NormalAbnormal/NormalAbnormal/Validation_f1.csv')","metadata":{"execution":{"iopub.status.busy":"2021-11-08T12:02:57.241974Z","iopub.execute_input":"2021-11-08T12:02:57.242902Z","iopub.status.idle":"2021-11-08T12:02:58.385451Z","shell.execute_reply.started":"2021-11-08T12:02:57.242858Z","shell.execute_reply":"2021-11-08T12:02:58.384705Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df=train_df[:200000]","metadata":{"execution":{"iopub.status.busy":"2021-11-08T12:03:03.049676Z","iopub.execute_input":"2021-11-08T12:03:03.050225Z","iopub.status.idle":"2021-11-08T12:03:03.054447Z","shell.execute_reply.started":"2021-11-08T12:03:03.050169Z","shell.execute_reply":"2021-11-08T12:03:03.053572Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df","metadata":{"execution":{"iopub.status.busy":"2021-11-08T12:03:08.435485Z","iopub.execute_input":"2021-11-08T12:03:08.436287Z","iopub.status.idle":"2021-11-08T12:03:08.451447Z","shell.execute_reply.started":"2021-11-08T12:03:08.436249Z","shell.execute_reply":"2021-11-08T12:03:08.450599Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"val_df","metadata":{"execution":{"iopub.status.busy":"2021-11-08T12:03:14.528525Z","iopub.execute_input":"2021-11-08T12:03:14.528784Z","iopub.status.idle":"2021-11-08T12:03:14.542011Z","shell.execute_reply.started":"2021-11-08T12:03:14.528755Z","shell.execute_reply":"2021-11-08T12:03:14.541211Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"HEIGHT = 256\nWIDTH = 256\nCHANNELS = 3\nTRAIN_BATCH_SIZE = 32\nVALID_BATCH_SIZE = 64\nSHAPE = (HEIGHT, WIDTH, CHANNELS)\n\nclass_names = ['Normal', 'Abnormal']\n\nweights = calculating_class_weights((train_df[class_names].values).astype(np.float32))\nprint(weights)\n\ndata_generator_train = TrainDataGenerator(train_df,\n                                          class_names,\n                                          TRAIN_BATCH_SIZE,\n                                          SHAPE,\n                                          augment = True,\n                                          shuffle = True)\ndata_generator_val = TrainDataGenerator(val_df,\n                                        class_names, \n                                        VALID_BATCH_SIZE, \n                                        SHAPE,\n                                        augment = False,\n                                        shuffle = True\n                                        )\n\nTRAIN_STEPS = int(len(data_generator_train)/10)\nprint(TRAIN_STEPS)\nVal_STEPS = int(len(data_generator_val)/10)\nprint(Val_STEPS)\nLR = 1e-6","metadata":{"execution":{"iopub.status.busy":"2021-11-08T12:03:21.991701Z","iopub.execute_input":"2021-11-08T12:03:21.991951Z","iopub.status.idle":"2021-11-08T12:03:22.142652Z","shell.execute_reply.started":"2021-11-08T12:03:21.991922Z","shell.execute_reply":"2021-11-08T12:03:22.141859Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"Metrics = metrics_define(len(class_names))\nmodel = create_model(len(class_names))\n# model.load_weights('../input/stroke-binary-classification-model/model_alldata_retrain_f1_run2.h5')\nmodel.compile(optimizer = Adam(learning_rate = LR),\n              loss = get_weighted_loss(weights),\n              metrics = Metrics)","metadata":{"execution":{"iopub.status.busy":"2021-11-08T12:04:03.745101Z","iopub.execute_input":"2021-11-08T12:04:03.745884Z","iopub.status.idle":"2021-11-08T12:04:10.31022Z","shell.execute_reply.started":"2021-11-08T12:04:03.745843Z","shell.execute_reply":"2021-11-08T12:04:10.309509Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"history = model.fit(data_generator_train,\n                    validation_data = data_generator_val,\n                    validation_steps = Val_STEPS,\n                    steps_per_epoch = TRAIN_STEPS,\n                    epochs = 10,\n                    callbacks = [ModelCheckpointFull('denseNet121_alldata_retrain_f1_run3.h5')],\n                    verbose = 1, workers=4\n                    )","metadata":{"execution":{"iopub.status.busy":"2021-11-08T12:04:12.372511Z","iopub.execute_input":"2021-11-08T12:04:12.37299Z","iopub.status.idle":"2021-11-08T13:05:27.040464Z","shell.execute_reply.started":"2021-11-08T12:04:12.372952Z","shell.execute_reply":"2021-11-08T13:05:27.039556Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.plot(history.history['loss'])\nplt.plot(history.history['val_loss'])\nplt.title('model loss')\nplt.ylabel('loss')\nplt.xlabel('epoch')\nplt.legend(['train', 'val'], loc='upper left')\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2021-11-08T13:13:54.677626Z","iopub.execute_input":"2021-11-08T13:13:54.677908Z","iopub.status.idle":"2021-11-08T13:13:54.910708Z","shell.execute_reply.started":"2021-11-08T13:13:54.677878Z","shell.execute_reply":"2021-11-08T13:13:54.910004Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.plot(history.history['accuracy'])\nplt.plot(history.history['val_accuracy'])\nplt.title('model auc_accuracy')\nplt.ylabel('accuracy')\nplt.xlabel('epoch')\nplt.legend(['train', 'val'], loc='upper left')\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2021-11-08T13:13:58.788014Z","iopub.execute_input":"2021-11-08T13:13:58.788299Z","iopub.status.idle":"2021-11-08T13:13:58.998774Z","shell.execute_reply.started":"2021-11-08T13:13:58.788269Z","shell.execute_reply":"2021-11-08T13:13:58.998097Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# model.load_weights('../input/stroke-binary-classification-model/denseNet121_alldata_retrain_f1_run3.h5')","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"val_df = pd.read_csv('../input/cq500-normal-images-and-labels/NormalAbnormal/NormalAbnormal/Validation_f1.csv')\nabnormal = val_df.loc[val_df['Abnormal']==1]\nnormal = val_df.loc[val_df['Normal']==1]\nnormal=shuffle(normal)\nnormal = normal.iloc[0:len(abnormal)]\nval_df = abnormal.append(normal, ignore_index=True)\nval_df = shuffle(val_df)\nprint(len(val_df))\n\nHEIGHT = 256\nWIDTH = 256\nCHANNELS = 3\nVALID_BATCH_SIZE = 64\nSHAPE = (HEIGHT, WIDTH, CHANNELS)\n\nclass_names = ['Normal', 'Abnormal']\ndata_generator_test = TrainDataGenerator(val_df,\n                                        class_names, \n                                        VALID_BATCH_SIZE, \n                                        SHAPE,\n                                        augment = False,\n                                        shuffle = False\n                                        )\n\ny_true = val_df[class_names].values\ny_hat = model.predict(data_generator_test, verbose=1)\n\ny_hat = y_hat[0:len(y_true)]\ny_pred = np.argmax(y_hat, axis=1)\ny_true = np.argmax(y_true, axis=1)","metadata":{"execution":{"iopub.status.busy":"2021-11-08T13:14:03.713632Z","iopub.execute_input":"2021-11-08T13:14:03.714219Z","iopub.status.idle":"2021-11-08T13:26:17.648665Z","shell.execute_reply.started":"2021-11-08T13:14:03.714163Z","shell.execute_reply":"2021-11-08T13:26:17.647851Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print_confusion_matrix(y_true, y_pred, class_names)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print_performance_metrics(y_true, y_pred, class_names)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"val_df = pd.read_csv('../input/cq500-normal-images-and-labels/NormalAbnormal/NormalAbnormal/RSNA/Validation_f0.csv')\nabnormal = val_df.loc[val_df['Abnormal']==1]\nnormal = val_df.loc[val_df['Normal']==1]\nnormal=shuffle(normal)\nnormal = normal.iloc[0:len(abnormal)]\nval_df = abnormal.append(normal, ignore_index=True)\nval_df = shuffle(val_df)\nprint(len(val_df))\n\nHEIGHT = 256\nWIDTH = 256\nCHANNELS = 3\nVALID_BATCH_SIZE = 64\nSHAPE = (HEIGHT, WIDTH, CHANNELS)\n\nclass_names = ['Normal', 'Abnormal']\ndata_generator_test = TrainDataGenerator(val_df,\n                                        class_names, \n                                        VALID_BATCH_SIZE, \n                                        SHAPE,\n                                        augment = False,\n                                        shuffle = False\n                                        )\n\ny_true = val_df[class_names].values\ny_hat = model.predict(data_generator_test, verbose=1)\n\ny_hat = y_hat[0:len(y_true)]\ny_pred = np.argmax(y_hat, axis=1)\ny_true = np.argmax(y_true, axis=1)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print_confusion_matrix(y_true, y_pred, class_names)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print_performance_metrics(y_true, y_pred, class_names)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"val_df = pd.read_csv('../input/cq500-normal-images-and-labels/NormalAbnormal/NormalAbnormal/CQ500/Validation_f0.csv')\nabnormal = val_df.loc[val_df['Abnormal']==1]\nnormal = val_df.loc[val_df['Normal']==1]\nnormal=shuffle(normal)\nnormal = normal.iloc[0:len(abnormal)]\nval_df = abnormal.append(normal, ignore_index=True)\nval_df = shuffle(val_df)\nprint(len(val_df))\n\nHEIGHT = 256\nWIDTH = 256\nCHANNELS = 3\nVALID_BATCH_SIZE = 64\nSHAPE = (HEIGHT, WIDTH, CHANNELS)\n\nclass_names = ['Normal', 'Abnormal']\ndata_generator_test = TrainDataGenerator(val_df,\n                                        class_names, \n                                        VALID_BATCH_SIZE, \n                                        SHAPE,\n                                        augment = False,\n                                        shuffle = False\n                                        )\n\ny_true = val_df[class_names].values\ny_hat = model.predict(data_generator_test, verbose=1)\n\ny_hat = y_hat[0:len(y_true)]\ny_pred = np.argmax(y_hat, axis=1)\ny_true = np.argmax(y_true, axis=1)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print_confusion_matrix(y_true, y_pred, class_names)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print_performance_metrics(y_true, y_pred, class_names)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}