{"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 classification-models-3D","metadata":{"execution":{"iopub.status.busy":"2021-09-23T14:16:16.107116Z","iopub.execute_input":"2021-09-23T14:16:16.107482Z","iopub.status.idle":"2021-09-23T14:16:23.916916Z","shell.execute_reply.started":"2021-09-23T14:16:16.1074Z","shell.execute_reply":"2021-09-23T14:16:23.915996Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!pip install keras_applications","metadata":{"execution":{"iopub.status.busy":"2021-09-28T15:59:46.789394Z","iopub.execute_input":"2021-09-28T15:59:46.789902Z","iopub.status.idle":"2021-09-28T15:59:57.585364Z","shell.execute_reply.started":"2021-09-28T15:59:46.789818Z","shell.execute_reply":"2021-09-28T15:59:57.584155Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import keras_applications as ka\nimport os\nimport collections\nfrom tensorflow import keras\n_all__ = ['load_model_weights']\n\ndef get_submodules_from_kwargs(kwargs):\n    #backend = kwargs.get('backend', ka._KERAS_BACKEND)\n    #layers = kwargs.get('layers', ka._KERAS_LAYERS)\n    #models = kwargs.get('models', ka._KERAS_MODELS)\n    #utils = kwargs.get('utils', ka._KERAS_UTILS)\n    backend = kwargs.get('backend', keras.backend)\n    layers = kwargs.get('layers', keras.layers)\n    models = kwargs.get('models', keras.models)\n    utils = kwargs.get('utils', keras.utils)\n    return backend, layers, models, utils\n\ndef slice_tensor(x, start, stop, axis):\n    if axis == 4:\n        return x[:, :, :, :, start:stop]\n    elif axis == 1:\n        return x[:, start:stop, :, :, :]\n    else:\n        raise ValueError(\"Slice axis should be in (1, 4), got {}.\".format(axis))\n\n\ndef GroupConv3D(filters,\n                kernel_size,\n                strides=(1, 1, 1),\n                groups=32,\n                kernel_initializer='he_uniform',\n                use_bias=True,\n                activation='linear',\n                padding='valid',\n                **kwargs):\n    \"\"\"\n    Grouped Convolution Layer implemented as a Slice,\n    Conv3D and Concatenate layers. Split filters to groups, apply Conv3D and concatenate back.\n    Args:\n        filters: Integer, the dimensionality of the output space\n            (i.e. the number of output filters in the convolution).\n        kernel_size: An integer or tuple/list of a single integer,\n            specifying the length of the 1D convolution window.\n        strides: An integer or tuple/list of a single integer, specifying the stride\n            length of the convolution.\n        groups: Integer, number of groups to split input filters to.\n        kernel_initializer: Regularizer function applied to the kernel weights matrix.\n        use_bias: Boolean, whether the layer uses a bias vector.\n        activation: Activation function to use (see activations).\n            If you don't specify anything, no activation is applied (ie. \"linear\" activation: a(x) = x).\n        padding: one of \"valid\" or \"same\" (case-insensitive).\n    Input shape:\n        5D tensor with shape: (batch, rows, cols, height, channels) if data_format is \"channels_last\".\n    Output shape:\n        5D tensor with shape: (batch, new_rows, new_cols, new_height, filters) if data_format is \"channels_last\".\n        rows and cols values might have changed due to padding.\n    \"\"\"\n\n    backend, layers, models, keras_utils = get_submodules_from_kwargs(kwargs)\n    slice_axis = 4 if backend.image_data_format() == 'channels_last' else 1\n\n    def layer(input_tensor):\n        inp_ch = int(backend.int_shape(input_tensor)[-1] // groups)  # input grouped channels\n        out_ch = int(filters // groups)  # output grouped channels\n\n        blocks = []\n        for c in range(groups):\n            slice_arguments = {\n                'start': c * inp_ch,\n                'stop': (c + 1) * inp_ch,\n                'axis': slice_axis,\n            }\n            x = layers.Lambda(slice_tensor, arguments=slice_arguments)(input_tensor)\n            x = layers.Conv3D(out_ch,\n                              kernel_size,\n                              strides=strides,\n                              kernel_initializer=kernel_initializer,\n                              use_bias=use_bias,\n                              activation=activation,\n                              padding=padding)(x)\n            blocks.append(x)\n\n        x = layers.Concatenate(axis=slice_axis)(blocks)\n        return x\n\n    return layer\n\n\ndef expand_dims(x, channels_axis):\n    if channels_axis == 4:\n        return x[:, None, None, None, :]\n    elif channels_axis == 1:\n        return x[:, :, None, None, None]\n    else:\n        raise ValueError(\"Slice axis should be in (1, 4), got {}.\".format(channels_axis))\n\n\ndef ChannelSE(reduction=16, **kwargs):\n    \"\"\"\n    Squeeze and Excitation block, reimplementation inspired by\n        https://github.com/Cadene/pretrained-models.pytorch/blob/master/pretrainedmodels/models/senet.py\n    Args:\n        reduction: channels squeeze factor\n    \"\"\"\n    backend, layers, models, keras_utils = get_submodules_from_kwargs(kwargs)\n    channels_axis = 4 if backend.image_data_format() == 'channels_last' else 1\n\n    def layer(input_tensor):\n        # get number of channels/filters\n        channels = backend.int_shape(input_tensor)[channels_axis]\n\n        x = input_tensor\n\n        # squeeze and excitation block in PyTorch style with\n        x = layers.GlobalAveragePooling3D()(x)\n        x = layers.Lambda(expand_dims, arguments={'channels_axis': channels_axis})(x)\n        x = layers.Conv3D(channels // reduction, (1, 1, 1), kernel_initializer='he_uniform')(x)\n        x = layers.Activation('relu')(x)\n        x = layers.Conv3D(channels, (1, 1, 1), kernel_initializer='he_uniform')(x)\n        x = layers.Activation('sigmoid')(x)\n\n        # apply attention\n        x = layers.Multiply()([input_tensor, x])\n\n        return x\n\n    return\n\n\ndef _find_weights(model_name, dataset, include_top):\n    w = list(filter(lambda x: x['model'] == model_name, WEIGHTS_COLLECTION))\n    w = list(filter(lambda x: x['dataset'] == dataset, w))\n    w = list(filter(lambda x: x['include_top'] == include_top, w))\n    return w\n\n\ndef load_model_weights(model, model_name, dataset, classes, include_top, **kwargs):\n    _, _, _, keras_utils = get_submodules_from_kwargs(kwargs)\n\n    weights = _find_weights(model_name, dataset, include_top)\n\n    if weights:\n        weights = weights[0]\n\n        if include_top and weights['classes'] != classes:\n            raise ValueError('If using `weights` and `include_top`'\n                             ' as true, `classes` should be {}'.format(weights['classes']))\n\n        weights_path = keras_utils.get_file(\n            weights['name'],\n            weights['url'],\n            cache_subdir='models',\n            md5_hash=weights['md5']\n        )\n\n        model.load_weights(weights_path)\n\n    else:\n        raise ValueError('There is no weights for such configuration: ' +\n                         'model = {}, dataset = {}, '.format(model.name, dataset) +\n                         'classes = {}, include_top = {}.'.format(classes, include_top))\n\n\nWEIGHTS_COLLECTION = [\n\n    # resnet18\n    {\n        'model': 'resnet18',\n        'dataset': 'imagenet',\n        'classes': 1000,\n        'include_top': False,\n        'url': 'https://github.com/ZFTurbo/classification_models_3D/releases/download/v1.0/resnet18_inp_channel_3_tch_0_top_False.h5',\n        'name': 'resnet18_inp_channel_3_tch_0_top_False.h5',\n        'md5': 'e616829b530e021857ccf5ff02cf83a0',\n    },\n    # resnet18\n    {\n        'model': 'resnet18',\n        'dataset': 'imagenet',\n        'classes': 1000,\n        'include_top': True,\n        'url': 'https://github.com/ZFTurbo/classification_models_3D/releases/download/v1.0/resnet18_inp_channel_3_tch_0_top_True.h5',\n        'name': 'resnet18_inp_channel_3_tch_0_top_True.h5',\n        'md5': '1ebbd4226330d7f21ddb5a0e93ab78d7',\n    }\n    \n]\n\nbackend = None\nlayers = None\nmodels = None\nkeras_utils = None\n\nModelParams = collections.namedtuple(\n    'ModelParams',\n    ['model_name', 'repetitions', 'residual_block', 'attention']\n)\n\n\n# -------------------------------------------------------------------------\n#   Helpers functions\n# -------------------------------------------------------------------------\n\ndef handle_block_names(stage, block):\n    name_base = 'stage{}_unit{}_'.format(stage + 1, block + 1)\n    conv_name = name_base + 'conv'\n    bn_name = name_base + 'bn'\n    relu_name = name_base + 'relu'\n    sc_name = name_base + 'sc'\n    return conv_name, bn_name, relu_name, sc_name\n\n\ndef get_conv_params(**params):\n    default_conv_params = {\n        'kernel_initializer': 'he_uniform',\n        'use_bias': False,\n        'padding': 'valid',\n    }\n    default_conv_params.update(params)\n    return default_conv_params\n\n\ndef get_bn_params(**params):\n    axis = 4 if backend.image_data_format() == 'channels_last' else 1\n    default_bn_params = {\n        'axis': axis,\n        'momentum': 0.99,\n        'epsilon': 2e-5,\n        'center': True,\n        'scale': True,\n    }\n    default_bn_params.update(params)\n    return default_bn_params\n\n\n# -------------------------------------------------------------------------\n#   Residual blocks\n# -------------------------------------------------------------------------\n\ndef residual_conv_block(filters, stage, block, strides=(1, 1, 1), attention=None, cut='pre'):\n    \"\"\"The identity block is the block that has no conv layer at shortcut.\n    # Arguments\n        input_tensor: input tensor\n        kernel_size: default 3, the kernel size of\n            middle conv layer at main path\n        filters: list of integers, the filters of 3 conv layer at main path\n        stage: integer, current stage label, used for generating layer names\n        block: 'a','b'..., current block label, used for generating layer names\n        cut: one of 'pre', 'post'. used to decide where skip connection is taken\n    # Returns\n        Output tensor for the block.\n    \"\"\"\n\n    def layer(input_tensor):\n\n        # get params and names of layers\n        conv_params = get_conv_params()\n        bn_params = get_bn_params()\n        conv_name, bn_name, relu_name, sc_name = handle_block_names(stage, block)\n\n        #x = layers.BatchNormalization(name=bn_name + '1', **bn_params)(input_tensor)\n        x = layers.Activation('relu', name=relu_name + '1')(input_tensor)\n\n        # defining shortcut connection\n        if cut == 'pre':\n            shortcut = input_tensor\n        elif cut == 'post':\n            shortcut = layers.Conv3D(filters, (1, 1, 1), name=sc_name, strides=strides, **conv_params)(x)\n        else:\n            raise ValueError('Cut type not in [\"pre\", \"post\"]')\n\n        # continue with convolution layers\n        x = layers.ZeroPadding3D(padding=(1, 1, 1))(x)\n        x = layers.Conv3D(filters, (3, 3, 3), strides=strides, name=conv_name + '1',**conv_params)(x)\n\n        #x = layers.BatchNormalization(name=bn_name + '2', **bn_params)(x)\n        x = layers.Activation('relu', name=relu_name + '2')(x)\n        x = layers.ZeroPadding3D(padding=(1, 1, 1))(x)\n        x = layers.Conv3D(filters, (3, 3, 3), name=conv_name + '2',**conv_params)(x)\n\n        # use attention block if defined\n        if attention is not None:\n            x = attention(x)\n\n        # add residual connection\n        x = layers.Add()([x, shortcut])\n        return x\n\n    return layer\n\n\ndef residual_bottleneck_block(filters, stage, block, strides=None, attention=None, cut='pre'):\n    \"\"\"The identity block is the block that has no conv layer at shortcut.\n    # Arguments\n        input_tensor: input tensor\n        kernel_size: default 3, the kernel size of\n            middle conv layer at main path\n        filters: list of integers, the filters of 3 conv layer at main path\n        stage: integer, current stage label, used for generating layer names\n        block: 'a','b'..., current block label, used for generating layer names\n        cut: one of 'pre', 'post'. used to decide where skip connection is taken\n    # Returns\n        Output tensor for the block.\n    \"\"\"\n\n    def layer(input_tensor):\n\n        # get params and names of layers\n        conv_params = get_conv_params()\n        bn_params = get_bn_params()\n        conv_name, bn_name, relu_name, sc_name = handle_block_names(stage, block)\n\n        x = layers.BatchNormalization(name=bn_name + '1', **bn_params)(input_tensor)\n        x = layers.Activation('relu', name=relu_name + '1')(x)\n\n        # defining shortcut connection\n        if cut == 'pre':\n            shortcut = input_tensor\n        elif cut == 'post':\n            shortcut = layers.Conv3D(filters * 4, (1, 1, 1), name=sc_name, strides=strides, **conv_params)(x)\n        else:\n            raise ValueError('Cut type not in [\"pre\", \"post\"]')\n\n        # continue with convolution layers\n        x = layers.Conv3D(filters, (1, 1, 1), name=conv_name + '1', **conv_params)(x)\n\n        x = layers.BatchNormalization(name=bn_name + '2', **bn_params)(x)\n        x = layers.Activation('relu', name=relu_name + '2')(x)\n        x = layers.ZeroPadding3D(padding=(1, 1, 1))(x)\n        x = layers.Conv3D(filters, (3, 3, 3), strides=strides, name=conv_name + '2', **conv_params)(x)\n\n        x = layers.BatchNormalization(name=bn_name + '3', **bn_params)(x)\n        x = layers.Activation('relu', name=relu_name + '3')(x)\n        x = layers.Conv3D(filters * 4, (1, 1, 1), name=conv_name + '3', **conv_params)(x)\n\n        # use attention block if defined\n        if attention is not None:\n            x = attention(x)\n\n        # add residual connection\n        x = layers.Add()([x, shortcut])\n\n        return x\n\n    return layer\n\n\n# -------------------------------------------------------------------------\n#   Residual Model Builder\n# -------------------------------------------------------------------------\n\n\ndef ResNet(model_params, input_shape=None, input_tensor=None, include_top=True,\n           classes=1000, weights='imagenet', **kwargs):\n    \"\"\"Instantiates the ResNet, SEResNet architecture.\n    Optionally loads weights pre-trained on ImageNet.\n    Note that the data format convention used by the model is\n    the one specified in your Keras config at `~/.keras/keras.json`.\n    Args:\n        include_top: whether to include the fully-connected\n            layer at the top of the network.\n        weights: one of `None` (random initialization),\n              'imagenet' (pre-training on ImageNet),\n              or the path to the weights file to be loaded.\n        input_tensor: optional Keras tensor\n            (i.e. output of `layers.Input()`)\n            to use as image input for the model.\n        input_shape: optional shape tuple, only to be specified\n            if `include_top` is False (otherwise the input shape\n            has to be `(224, 224, 3)` (with `channels_last` data format)\n            or `(3, 224, 224)` (with `channels_first` data format).\n            It should have exactly 3 inputs channels.\n        classes: optional number of classes to classify images\n            into, only to be specified if `include_top` is True, and\n            if no `weights` argument is specified.\n    Returns:\n        A Keras model instance.\n    Raises:\n        ValueError: in case of invalid argument for `weights`,\n            or invalid input shape.\n    \"\"\"\n    print('kwargs',kwargs)\n    global backend, layers, models, keras_utils\n    backend, layers, models, keras_utils = get_submodules_from_kwargs(kwargs)\n    print('layers',layers)\n    if input_tensor is None:\n        img_input = layers.Input(shape=input_shape, name='data')\n    else:\n        if not backend.is_keras_tensor(input_tensor):\n            img_input = layers.Input(tensor=input_tensor, shape=input_shape)\n        else:\n            img_input = input_tensor\n\n    # choose residual block type\n    ResidualBlock = model_params.residual_block\n    if model_params.attention:\n        Attention = model_params.attention(**kwargs)\n    else:\n        Attention = None\n\n    # get parameters for model layers\n    no_scale_bn_params = get_bn_params(scale=False)\n    bn_params = get_bn_params()\n    conv_params = get_conv_params()\n    init_filters = 64\n\n    # resnet bottom\n    x = layers.BatchNormalization(name='bn_data', **no_scale_bn_params)(img_input)\n    x = layers.ZeroPadding3D(padding=(3, 3, 3))(x)\n    x = layers.Conv3D(init_filters, (7, 7, 7), strides=(2, 2, 2), name='conv0', **conv_params)(x)\n    x = layers.BatchNormalization(name='bn0', **bn_params)(x)\n    x = layers.Activation('relu', name='relu0')(x)\n    x = layers.ZeroPadding3D(padding=(1, 1, 1))(x)\n    x = layers.MaxPooling3D((3, 3, 3), strides=(2, 2, 2), padding='valid', name='pooling0')(x)\n\n    # resnet body\n    for stage, rep in enumerate(model_params.repetitions):\n        for block in range(rep):\n\n            filters = init_filters * (2 ** stage)\n\n            # first block of first stage without strides because we have maxpooling before\n            if block == 0 and stage == 0:\n                x = ResidualBlock(filters, stage, block, strides=(1, 1, 1),\n                                  cut='post', attention=Attention)(x)\n\n            elif block == 0:\n                x = ResidualBlock(filters, stage, block, strides=(2, 2, 2),\n                                  cut='post', attention=Attention)(x)\n\n            else:\n                x = ResidualBlock(filters, stage, block, strides=(1, 1, 1),\n                                  cut='pre', attention=Attention)(x)\n\n    #x = layers.BatchNormalization(name='bn1', **bn_params)(x)\n    x = layers.Activation('relu', name='relu1')(x)\n\n    # resnet top\n    if include_top:\n        x = layers.GlobalAveragePooling3D(name='pool1')(x)\n        x = layers.Dense(classes, name='fc1')(x)\n        x = layers.Activation('softmax', name='softmax')(x)\n\n    # Ensure that the model takes into account any potential predecessors of `input_tensor`.\n    if input_tensor is not None:\n        inputs = keras_utils.get_source_inputs(input_tensor)\n    else:\n        inputs = img_input\n\n    # Create model.\n    model = models.Model(inputs, x)\n\n    if weights:\n        if type(weights) == str and os.path.exists(weights):\n            model.load_weights(weights)\n        else:\n            load_model_weights(model, model_params.model_name,\n                               weights, classes, include_top, **kwargs)\n\n    return model\n\n\n# -------------------------------------------------------------------------\n#   Residual Models\n# -------------------------------------------------------------------------\n\nMODELS_PARAMS = {\n    'resnet18': ModelParams('resnet18', (2, 2, 2, 2), residual_conv_block, None),\n    'resnet34': ModelParams('resnet34', (3, 4, 6, 3), residual_conv_block, None),\n    'resnet50': ModelParams('resnet50', (3, 4, 6, 3), residual_bottleneck_block, None),\n    'resnet101': ModelParams('resnet101', (3, 4, 23, 3), residual_bottleneck_block, None),\n    'resnet152': ModelParams('resnet152', (3, 8, 36, 3), residual_bottleneck_block, None),\n    'seresnet18': ModelParams('seresnet18', (2, 2, 2, 2), residual_conv_block, ChannelSE),\n    'seresnet34': ModelParams('seresnet34', (3, 4, 6, 3), residual_conv_block, ChannelSE),\n}\n\n\ndef ResNet18(input_shape=None, input_tensor=None, weights=None, classes=1000, include_top=True, **kwargs):\n    return ResNet(\n        MODELS_PARAMS['resnet18'],\n        input_shape=input_shape,\n        input_tensor=input_tensor,\n        include_top=include_top,\n        classes=classes,\n        weights=weights,\n        **kwargs\n    )\n\n\ndef ResNet34(input_shape=None, input_tensor=None, weights=None, classes=1000, include_top=True, **kwargs):\n    return ResNet(\n        MODELS_PARAMS['resnet34'],\n        input_shape=input_shape,\n        input_tensor=input_tensor,\n        include_top=include_top,\n        classes=classes,\n        weights=weights,\n        **kwargs\n    )\n\n\ndef ResNet50(input_shape=None, input_tensor=None, weights=None, classes=1000, include_top=True, **kwargs):\n    return ResNet(\n        MODELS_PARAMS['resnet50'],\n        input_shape=input_shape,\n        input_tensor=input_tensor,\n        include_top=include_top,\n        classes=classes,\n        weights=weights,\n        **kwargs\n    )\n\n\ndef ResNet101(input_shape=None, input_tensor=None, weights=None, classes=1000, include_top=True, **kwargs):\n    return ResNet(\n        MODELS_PARAMS['resnet101'],\n        input_shape=input_shape,\n        input_tensor=input_tensor,\n        include_top=include_top,\n        classes=classes,\n        weights=weights,\n        **kwargs\n    )\n\n\ndef ResNet152(input_shape=None, input_tensor=None, weights=None, classes=1000, include_top=True, **kwargs):\n    return ResNet(\n        MODELS_PARAMS['resnet152'],\n        input_shape=input_shape,\n        input_tensor=input_tensor,\n        include_top=include_top,\n        classes=classes,\n        weights=weights,\n        **kwargs\n    )\n\n\ndef SEResNet18(input_shape=None, input_tensor=None, weights=None, classes=1000, include_top=True, **kwargs):\n    return ResNet(\n        MODELS_PARAMS['seresnet18'],\n        input_shape=input_shape,\n        input_tensor=input_tensor,\n        include_top=include_top,\n        classes=classes,\n        weights=weights,\n        **kwargs\n    )\n\n\ndef SEResNet34(input_shape=None, input_tensor=None, weights=None, classes=1000, include_top=True, **kwargs):\n    return ResNet(\n        MODELS_PARAMS['seresnet34'],\n        input_shape=input_shape,\n        input_tensor=input_tensor,\n        include_top=include_top,\n        classes=classes,\n        weights=weights,\n        **kwargs\n    )\n\n\ndef preprocess_input(x, **kwargs):\n    return x\n\n","metadata":{"execution":{"iopub.status.busy":"2021-09-28T16:00:03.388856Z","iopub.execute_input":"2021-09-28T16:00:03.389346Z","iopub.status.idle":"2021-09-28T16:00:03.477561Z","shell.execute_reply.started":"2021-09-28T16:00:03.389297Z","shell.execute_reply":"2021-09-28T16:00:03.476109Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import tensorflow as tf\nimport numpy as np\nfrom tensorflow import keras\nimport pandas as pd\nimport matplotlib.pyplot as plt\nfrom tensorflow.keras.preprocessing import image\nimport cv2\nimport time\nimport glob\nimport os\nimport pandas\nfrom tensorflow.keras import layers\n#from classification_models_3D.keras import Classifiers\ntf.random.set_seed(1)\nnp.random.seed(1)\n#random.seed(1)","metadata":{"execution":{"iopub.status.busy":"2021-09-28T16:00:04.401769Z","iopub.execute_input":"2021-09-28T16:00:04.402115Z","iopub.status.idle":"2021-09-28T16:00:04.553095Z","shell.execute_reply.started":"2021-09-28T16:00:04.402085Z","shell.execute_reply":"2021-09-28T16:00:04.551987Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_all_slices(df,base_dir): \n    all_paths = []\n    for i in list(df['folder_id']):\n        i = os.path.join(base_dir,i)\n        all_paths.append(len(glob.glob(i+'/flair/*')))\n    return all_paths\n\ndef split_train_test(slices_list,folders_list,label_list,split_ratio=0.1):\n    test_size = int(len(slices_list)*split_ratio)\n    test_slices_list = slices_list[:test_size]\n    test_folders_list = folders_list[:test_size]\n    test_label_list = label_list[:test_size]\n    train_slices_list = slices_list[test_size:]\n    train_folders_list = folders_list[test_size:]\n    train_label_list = label_list[test_size:]\n    return train_slices_list,train_folders_list,train_label_list,test_slices_list,test_folders_list,test_label_list","metadata":{"execution":{"iopub.status.busy":"2021-09-28T16:00:04.831911Z","iopub.execute_input":"2021-09-28T16:00:04.832287Z","iopub.status.idle":"2021-09-28T16:00:04.846547Z","shell.execute_reply.started":"2021-09-28T16:00:04.832248Z","shell.execute_reply":"2021-09-28T16:00:04.845326Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df = pd.read_csv('../input/rsnasubmissionresult/result.csv',dtype='str')\nbase_dir = '../input/classify-tumor-best/DATATUMORONLY_TRAIN/train'\n#slices_list = np.array(get_all_slices(df,base_dir))","metadata":{"execution":{"iopub.status.busy":"2021-09-28T16:00:05.686842Z","iopub.execute_input":"2021-09-28T16:00:05.687238Z","iopub.status.idle":"2021-09-28T16:00:05.708394Z","shell.execute_reply.started":"2021-09-28T16:00:05.687206Z","shell.execute_reply":"2021-09-28T16:00:05.707249Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df = df.iloc[:525,:]\ntest_df = df.iloc[526:,:]","metadata":{"execution":{"iopub.status.busy":"2021-09-28T16:00:05.905277Z","iopub.execute_input":"2021-09-28T16:00:05.905747Z","iopub.status.idle":"2021-09-28T16:00:05.911582Z","shell.execute_reply.started":"2021-09-28T16:00:05.905716Z","shell.execute_reply":"2021-09-28T16:00:05.91033Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_slices_list = np.array(get_all_slices(train_df,base_dir))\ntest_slices_list = np.array(get_all_slices(test_df,base_dir))\n#slices_list = np.array(list(df['flair']))\ntrain_folders_list = np.array(list(train_df['folder_id']))\ntest_folders_list = np.array(list(test_df['folder_id']))\ntrain_label_list = np.array(list(train_df['MGMT_value']))\ntest_label_list = np.array(list(test_df['MGMT_value']))\nindexes = np.where((train_slices_list > 0 )&(train_slices_list < 50))\ntrain_slices_list = np.take(train_slices_list,indexes)[0]\ntrain_folders_list = np.take(train_folders_list,indexes)[0]\ntrain_label_list = np.take(train_label_list,indexes)[0]\nindexes = np.where((test_slices_list > 0 )&(test_slices_list < 50))\ntest_slices_list = np.take(test_slices_list,indexes)[0]\ntest_folders_list = np.take(test_folders_list,indexes)[0]\ntest_label_list = np.take(test_label_list,indexes)[0]","metadata":{"execution":{"iopub.status.busy":"2021-09-28T16:00:06.599425Z","iopub.execute_input":"2021-09-28T16:00:06.599828Z","iopub.status.idle":"2021-09-28T16:00:09.745204Z","shell.execute_reply.started":"2021-09-28T16:00:06.599788Z","shell.execute_reply":"2021-09-28T16:00:09.744094Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# df = pd.read_csv('../input/rsnasubmissionresult/result.csv',dtype='str')\n# base_dir = '../input/classify-tumor-best/DATATUMORONLY_TRAIN/train'\n# slices_list = np.array(get_all_slices(df,base_dir))\n# #slices_list = np.array(list(df['flair']))\n# folders_list = np.array(list(df['folder_id']))\n# label_list = np.array(list(df['MGMT_value']))\n# indexes = np.where((slices_list > 0 )&(slices_list < 50))\n# slices_list = np.take(slices_list,indexes)[0]\n# folders_list = np.take(folders_list,indexes)[0]\n# label_list = np.take(label_list,indexes)[0]\n# shuffler = np.random.permutation(len(slices_list))\n# slices_list = slices_list[shuffler]\n# folders_list = folders_list[shuffler]\n# label_list = label_list[shuffler]\n# train_slices_list,train_folders_list,train_label_list,\\\n# test_slices_list,test_folders_list,test_label_list = split_train_test(slices_list,folders_list,label_list,split_ratio=0.1)","metadata":{"execution":{"iopub.status.busy":"2021-09-28T15:36:59.546675Z","iopub.execute_input":"2021-09-28T15:36:59.547028Z","iopub.status.idle":"2021-09-28T15:36:59.551707Z","shell.execute_reply.started":"2021-09-28T15:36:59.546991Z","shell.execute_reply":"2021-09-28T15:36:59.550682Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class DataGenerator(keras.utils.Sequence):\n    def __init__(self,slices_list,folders_list,label_list,width=256,height=256,batch_size=16,shuffle=True):\n        self.batch_size = batch_size\n        self.base_dir = '../input/classify-tumor-best/DATATUMORONLY_TRAIN/train'\n        self.width = width\n        self.crop_length = 224\n        self.height = height\n        self.tolerance = 5\n        self.shuffle = shuffle\n        self.intial_slices_list = slices_list\n        self.intial_folders_list = folders_list\n        self.intial_label_list = label_list\n        #print(len(self.slices_list))\n        self.on_epoch_end()\n    \n    def on_epoch_end(self):\n        print('epoch ended')\n        self.slices_list = self.intial_slices_list.copy()\n        self.folders_list = self.intial_folders_list.copy()\n        self.label_list = self.intial_label_list.copy()\n        if self.shuffle:\n            shuffler = np.random.permutation(len(self.slices_list))\n            self.slices_list = self.slices_list[shuffler]\n            self.folders_list = self.folders_list[shuffler]\n            self.label_list = self.label_list[shuffler]\n\n    def __len__(self):\n        return len(self.intial_slices_list)\n    \n    def __getitem__(self,user_index):\n        start =time.time()\n        index = self.slices_list[0]\n        #print(len(self.slices_list))\n        labels = []\n        indexes = np.where((self.slices_list >= index-self.tolerance) &(self.slices_list <= index+self.tolerance))\n        tol_slice= np.take(self.slices_list, indexes)[0]\n        tol_folder= np.take(self.folders_list, indexes)[0]\n        random_indexes = np.random.choice(indexes[0], size=min(self.batch_size,len(tol_folder)),replace=False)\n        random_folder = np.take(self.folders_list,random_indexes)\n        random_slices = np.take(self.slices_list,random_indexes)\n        random_labels = np.take(self.label_list,random_indexes)\n        self.folders_list = np.delete(self.folders_list,random_indexes)\n        self.slices_list = np.delete(self.slices_list,random_indexes)\n        self.label_list = np.delete(self.label_list,random_indexes)\n        #print(len(self.slices_list))\n        self.max_depth = random_slices.max()\n        #print(random_folder)\n        batch_x = self.__data_gen_batch(random_folder)\n        #for i in random_folder:\n        #    labels.append(int(self.label_list[np.where(self.folders_list == i)[0]][0]))\n        #print(labels)\n        return batch_x,self.one_hot_encoder(random_labels.astype(np.int8))\n    \n    def one_hot_encoder(self,y):\n        b = np.zeros((len(y), 2))\n        b[np.arange(len(y)),y] = 1\n        return b\n    \n    def get_max_len(self,batch,min_depth=50):\n        max_len = 0\n        for patient_id in batch['folder_id']:\n            #print(os.path.join(self.base_dir,patient_id,'flair/*'))\n            length = len(glob.glob(os.path.join(self.base_dir,patient_id,'flair/*')))\n            if length > max_len:\n                max_len = length\n        if max_len < min_depth:\n            max_len = min_depth\n        return max_len\n\n    def __data_gen_image(self,folder_name):\n        flair_path = glob.glob(os.path.join(self.base_dir,folder_name,'flair/*'))\n        flair_path = sorted(flair_path,key=lambda x:x.split('-')[-1].split('.')[-2].zfill(3))\n        all_images = []\n        all_images = np.zeros(shape=(self.max_depth,self.height,self.height,1),dtype=np.float64)\n        for i,img_path in enumerate(flair_path):\n            img = image.load_img(img_path,target_size=(self.height,self.width),color_mode='grayscale')\n            img = image.img_to_array(img)\n            all_images[i,] = img\n        return np.transpose(all_images,(1,2,0,3))\n\n    def __data_gen_batch(self,folder_names):\n        batch_data = np.empty(shape=(len(folder_names),self.height,self.width,self.max_depth,1))\n        for i,patient_id in enumerate(folder_names):\n            batch_data[i,] = self.__data_gen_image(patient_id)\n        return batch_data\n    \n    def crop(self,image,crop_length=224):\n        img_height ,img_width = image.shape[:2]\n        start_y = (img_height - self.crop_length) // 2\n        start_x = (img_width - self.crop_length) // 2\n        cropped_image=image[start_y:(img_height - start_y), start_x:(img_width - start_x), :]\n        return cropped_image","metadata":{"execution":{"iopub.status.busy":"2021-09-28T16:00:10.292962Z","iopub.execute_input":"2021-09-28T16:00:10.293311Z","iopub.status.idle":"2021-09-28T16:00:10.320576Z","shell.execute_reply.started":"2021-09-28T16:00:10.293281Z","shell.execute_reply":"2021-09-28T16:00:10.318667Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_datagen = DataGenerator(train_slices_list,train_folders_list,train_label_list,batch_size=5,height=224,width=224,shuffle=True)\ntest_datagen = DataGenerator(test_slices_list,test_folders_list,test_label_list,batch_size=5,height=224,width=224,shuffle=True)","metadata":{"execution":{"iopub.status.busy":"2021-09-28T16:00:10.795853Z","iopub.execute_input":"2021-09-28T16:00:10.796222Z","iopub.status.idle":"2021-09-28T16:00:10.804448Z","shell.execute_reply.started":"2021-09-28T16:00:10.796169Z","shell.execute_reply":"2021-09-28T16:00:10.802794Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# for _ in range(3):\n#     print('new epoch')\n#     for i in range(len(test_datagen)-1):\n#         x,y = test_datagen[i]\n#         print(i,x.shape,len(test_datagen.slices_list))\n#     test_datagen.on_epoch_end()","metadata":{"execution":{"iopub.status.busy":"2021-09-16T17:09:27.567536Z","iopub.execute_input":"2021-09-16T17:09:27.567865Z","iopub.status.idle":"2021-09-16T17:09:31.741822Z","shell.execute_reply.started":"2021-09-16T17:09:27.567834Z","shell.execute_reply":"2021-09-16T17:09:31.740929Z"},"collapsed":true,"jupyter":{"outputs_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_model(width=256, height=256, depth=None):\n    \"\"\"Build a 3D convolutional neural network model.\"\"\"\n\n    inputs = keras.Input((width, height, depth, 1))\n    \n    x = layers.Conv3D(filters=32, kernel_size=3, activation=\"relu\",padding='same')(inputs)\n    x = layers.MaxPool3D(pool_size=2)(x)\n    #x = layers.BatchNormalization()(x)\n\n    x = layers.ZeroPadding3D(padding=(1, 1, 1))(x)\n    x = layers.Conv3D(filters=64, kernel_size=3, activation=\"relu\",padding='same')(x)\n    x = layers.MaxPool3D(pool_size=2)(x)\n    #x = layers.BatchNormalization()(x)\n    \n    x = layers.ZeroPadding3D(padding=(1, 1, 1))(x)\n    x = layers.Conv3D(filters=128, kernel_size=3, activation=\"relu\",padding='same')(x)\n    x = layers.MaxPool3D(pool_size=2)(x)\n    #x = layers.BatchNormalization()(x)\n    \n    x = layers.ZeroPadding3D(padding=(1, 1, 1))(x)\n    x = layers.Conv3D(filters=256, kernel_size=3, activation=\"relu\",padding='same')(x)\n    x = layers.MaxPool3D(pool_size=2)(x)\n    #x = layers.BatchNormalization()(x)\n\n    x = layers.GlobalAveragePooling3D()(x)\n    x = layers.Dense(units=512, activation=\"relu\")(x)\n    x = layers.Dropout(0.3)(x)\n\n    outputs = layers.Dense(units=2, activation=\"softmax\")(x)\n\n    # Define the model.\n    model = keras.Model(inputs, outputs, name=\"3dcnn\")\n    return model\n\nmodel = get_model(width=224, height=224, depth=None)\nmodel.summary()\nModel: \"3dcnn\"","metadata":{"execution":{"iopub.status.busy":"2021-09-23T14:18:38.499039Z","iopub.execute_input":"2021-09-23T14:18:38.499406Z","iopub.status.idle":"2021-09-23T14:18:38.590689Z","shell.execute_reply.started":"2021-09-23T14:18:38.49937Z","shell.execute_reply":"2021-09-23T14:18:38.589764Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#ResNet18, preprocess_input = Classifiers.get('resnet18')\nmodel = ResNet18(input_shape=(224, 224, None, 1), weights=None,include_top=True)","metadata":{"execution":{"iopub.status.busy":"2021-09-28T16:00:15.674136Z","iopub.execute_input":"2021-09-28T16:00:15.674491Z","iopub.status.idle":"2021-09-28T16:00:18.622321Z","shell.execute_reply.started":"2021-09-28T16:00:15.67446Z","shell.execute_reply":"2021-09-28T16:00:18.621175Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.summary()","metadata":{"execution":{"iopub.status.busy":"2021-09-28T16:00:18.624846Z","iopub.execute_input":"2021-09-28T16:00:18.625715Z","iopub.status.idle":"2021-09-28T16:00:18.682324Z","shell.execute_reply.started":"2021-09-28T16:00:18.625666Z","shell.execute_reply":"2021-09-28T16:00:18.681267Z"},"collapsed":true,"jupyter":{"outputs_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"x = layers.Dense(units=512, activation=\"relu\")(model.layers[-3].output)\nx = layers.Dropout(0.2)(x)\nx = layers.Dense(units=256, activation=\"relu\")(x)\nx = layers.Dropout(0.2)(x)\nx = layers.Dense(units=128, activation=\"relu\")(x)\nx = layers.Dropout(0.2)(x)\noutputs = layers.Dense(units=2, activation=\"softmax\")(x)\n# Define the model.\nnew_model = keras.Model(model.input, outputs, name=\"resnet18_3d\")\nnew_model.summary()","metadata":{"execution":{"iopub.status.busy":"2021-09-28T16:00:31.885103Z","iopub.execute_input":"2021-09-28T16:00:31.885461Z","iopub.status.idle":"2021-09-28T16:00:31.999433Z","shell.execute_reply.started":"2021-09-28T16:00:31.885429Z","shell.execute_reply":"2021-09-28T16:00:31.998319Z"},"collapsed":true,"jupyter":{"outputs_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"os.makedirs('models')","metadata":{"execution":{"iopub.status.busy":"2021-09-28T16:00:32.253335Z","iopub.execute_input":"2021-09-28T16:00:32.253756Z","iopub.status.idle":"2021-09-28T16:00:32.25988Z","shell.execute_reply.started":"2021-09-28T16:00:32.253726Z","shell.execute_reply":"2021-09-28T16:00:32.258501Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"new_model.compile(\n    loss=\"categorical_crossentropy\",\n    optimizer=tf.keras.optimizers.Adam(learning_rate=0.001),\n    metrics=[\"accuracy\"]\n)\ncheckpoint_cb = tf.keras.callbacks.ModelCheckpoint(\n    filepath=\"models/3d_image_classification.hdf5\", save_best_only=True,monitor=\"val_accuracy\",mode=\"max\",verbose=0)","metadata":{"execution":{"iopub.status.busy":"2021-09-28T16:00:32.692701Z","iopub.execute_input":"2021-09-28T16:00:32.693076Z","iopub.status.idle":"2021-09-28T16:00:32.713816Z","shell.execute_reply.started":"2021-09-28T16:00:32.693044Z","shell.execute_reply":"2021-09-28T16:00:32.712338Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"new_model.fit(\n    train_datagen,\n    steps_per_epoch=len(train_datagen)//5-2,\n    validation_data=test_datagen,\\\n    validation_steps=len(test_datagen)//5-2,\n    epochs=300,\n    verbose=1,\n    callbacks = [checkpoint_cb]\n)","metadata":{"execution":{"iopub.status.busy":"2021-09-28T16:00:33.865545Z","iopub.execute_input":"2021-09-28T16:00:33.86593Z"},"collapsed":true,"jupyter":{"outputs_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"new_model.save('best_50.hdf5')","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_datagen = DataGenerator(train_slices_list,train_folders_list,train_label_list,batch_size=5,height=224,width=224,shuffle=True)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"true_cnt = 0\nall_cnt = 0\nfor i in range(len(train_datagen)//5):\n    x,y = train_datagen[i]\n    y_pred = new_model.predict(x)\n    output = np.argmax(np.round_(y_pred,1),axis=1)==np.argmax(y,1)\n    true_cnt += sum(output)\n    all_cnt += len(output)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"true_cnt/all_cnt","metadata":{},"execution_count":null,"outputs":[]}]}