{"cells":[{"metadata":{},"cell_type":"markdown","source":"Image Processing project (Image Steganalysis) using SRNet model."},{"metadata":{},"cell_type":"markdown","source":"### The two main caracteristics of SRNet are :\n* it uses a lot a residual connections to help propagate the gradient throughout the layers\n* it uses only one channel (but it may be a good idea to adapt it to 3 channels, as you are necessarily loosing information by converting to grayscale)"},{"metadata":{},"cell_type":"markdown","source":"## Basic Imports"},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport os\nimport gc\nimport matplotlib\nimport matplotlib.pyplot as plt\nimport matplotlib.image as mpimg\nfrom tqdm.notebook import tqdm\nimport random\nimport joblib\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import roc_curve, auc\nfrom time import time\nfrom collections import Counter\n\nfrom PIL import Image\nfrom random import shuffle\n\nimport tensorflow as tf\nfrom tensorflow.keras.metrics import AUC\n\nimport keras\nimport keras.backend as K\nimport keras.layers as L\nfrom keras import Model\nfrom keras.utils import plot_model\nfrom keras.preprocessing.image import ImageDataGenerator\n\nimport warnings\nwarnings.filterwarnings(\"ignore\")\n\n%matplotlib inline","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"PATH = \"/kaggle/input/alaska2-image-steganalysis/\"\nIMAGE_IDS = os.listdir(os.path.join(PATH, 'Cover'))\nN_IMAGES = len(IMAGE_IDS)\nALGORITHMS = ['JMiPOD', 'JUNIWARD', 'UERD']\nIMG_SIZE = 256\n\nsample_sub = pd.read_csv(PATH + 'sample_submission.csv')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# To make things reproductible\n\ndef seed_everything(seed=42):\n    np.random.seed(seed)\n    tf.random.set_seed(seed)\n    os.environ['PYTHONHASHSEED'] = str(seed)\n    os.environ['TF_DETERMINISTIC_OPS'] = '1'\n    os.environ['TF_KERAS'] = '1'\n\nseed_everything()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Define the SRNet Model"},{"metadata":{"trusted":true},"cell_type":"code","source":"def layer_type1(x_inp, filters, kernel_size=(3, 3), dropout_rate=0):\n    x = L.Conv2D(filters, kernel_size, padding=\"same\")(x_inp)\n    x = L.BatchNormalization()(x)\n    x = L.ReLU()(x)\n    if dropout_rate > 0:\n        x = L.Dropout(dropout_rate)(x)\n\n    return x\n\ndef layer_type2(x_inp, filters, kernel_size=(3, 3), dropout_rate=0):\n    x = layer_type1(x_inp, filters)\n    x = L.Conv2D(filters, kernel_size, padding=\"same\")(x)\n    x = L.BatchNormalization()(x)\n    x = L.ReLU()(x)\n    if dropout_rate > 0:\n        x = L.Dropout(dropout_rate)(x)\n\n    x = L.Add()([x, x_inp])\n    \n    return x\n\ndef layer_type3(x_inp, filters, kernel_size=(3, 3), dropout_rate=0):\n    x = layer_type1(x_inp, filters)\n    x = L.Conv2D(filters, kernel_size, padding=\"same\")(x)\n    x = L.BatchNormalization()(x)\n    x = L.ReLU()(x)\n    x = L.AveragePooling2D(pool_size=(3, 3), strides=(2, 2))(x)\n    if dropout_rate > 0:\n        x = L.Dropout(dropout_rate)(x)\n        \n    x_res = L.Conv2D(filters, kernel_size, strides=(2, 2))(x_inp)\n    x_res = L.BatchNormalization()(x_res)\n    if dropout_rate > 0:\n        x_res = L.Dropout(dropout_rate)(x_res)\n\n    x = L.Add()([x, x_res])\n    \n    return x\n\ndef layer_type4(x_inp, filters, kernel_size=(3, 3), dropout_rate=0):\n    x = layer_type1(x_inp, filters)\n    x = L.Conv2D(filters, kernel_size=(3, 3), padding=\"same\")(x)\n    x = L.BatchNormalization()(x)\n    if dropout_rate > 0:\n        x = L.Dropout(dropout_rate)(x)    \n    x = L.GlobalAveragePooling2D()(x)\n    \n    return x","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def alaska_weighted_auc(y_true, y_valid):\n    tpr_thresholds = [0.0, 0.4, 1.0]\n    weights =        [       2,   1]\n    \n    fpr, tpr, thresholds = roc_curve(y_true, y_valid)\n    \n    # size of subsets\n    areas = np.array(tpr_thresholds[1:]) - np.array(tpr_thresholds[:-1])\n    \n    # The total area is normalized by the sum of weights such that the final weighted AUC is between 0 and 1.\n    normalization = np.dot(areas, weights)\n    \n    try:\n    \n        competition_metric = 0\n        for idx, weight in enumerate(weights):\n            y_min = tpr_thresholds[idx]\n            y_max = tpr_thresholds[idx + 1]\n            mask = (y_min < tpr) & (tpr < y_max)\n\n            x_padding = np.linspace(fpr[mask][-1], 1, 100)\n\n            x = np.concatenate([fpr[mask], x_padding])\n            y = np.concatenate([tpr[mask], [y_max] * len(x_padding)])\n            y = y - y_min # normalize such that curve starts at y=0\n            score = auc(x, y)\n            submetric = score * weight\n            best_subscore = (y_max - y_min) * weight\n            competition_metric += submetric\n    except:\n        # sometimes there's a weird bug so return naive score\n        return .5\n        \n    return competition_metric / normalization\n\ndef alaska_tf(y_true, y_val):\n    \"\"\"Wrapper for the above function\"\"\"\n    return tf.py_function(func=alaska_weighted_auc, inp=[y_true, y_val], Tout=tf.float32)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def make_model(input_shape=(IMG_SIZE, IMG_SIZE, 3), num_type2=5, dropout_rate=0):\n    # I reduced the size (image size, filters and depth) of the original network because it was way to big\n    inputs = L.Input(shape=input_shape)\n    \n    x = layer_type1(inputs, filters=64, dropout_rate=dropout_rate)\n    x = layer_type1(x, filters=16, dropout_rate=dropout_rate)    \n    \n    for _ in range(num_type2):\n        x = layer_type2(x, filters=16, dropout_rate=dropout_rate)         \n    \n    x = layer_type3(x, filters=16, dropout_rate=dropout_rate) \n    x = layer_type3(x, filters=32, dropout_rate=dropout_rate)            \n    x = layer_type3(x, filters=64, dropout_rate=dropout_rate)            \n    #x = layer_type3(x, filters=128, dropout_rate=dropout_rate) \n    \n    x = layer_type4(x, filters=128, dropout_rate=dropout_rate)        \n    \n    x = L.Dense(64)(x)\n    x = L.BatchNormalization()(x)\n    x = L.ReLU()(x)\n    if dropout_rate > 0:\n        x = L.Dropout(dropout_rate)(x)\n\n    predictions = L.Dense(1, activation=\"sigmoid\")(x)\n    \n    model = Model(inputs=inputs, outputs=predictions)\n    keras_auc = AUC()\n    \n    model.compile(optimizer='adam',\n                  loss='binary_crossentropy', \n                  metrics=[alaska_tf])\n    \n    return model\n    ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model = make_model(num_type2=4, dropout_rate=0.1)\nmodel.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plot_model(model, show_shapes=True, to_file=\"model.png\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Generate Dataset and Fit Model"},{"metadata":{"trusted":true},"cell_type":"code","source":"def load_image(data):\n    i, j, img_path, labels = data\n    \n    img = Image.open(img_path)\n    img = img.convert('RGB')\n    img = img.resize((IMG_SIZE, IMG_SIZE), Image.ANTIALIAS)\n    \n    label = labels[i][j]\n    \n    return [np.array(img), label]\n\ndef load_training_data_multi(n_images=100):\n    train_data = []\n    data_paths = [os.listdir(os.path.join(PATH, alg)) for alg in ['Cover'] + ALGORITHMS]\n    labels = [np.zeros(N_IMAGES), np.ones(N_IMAGES), np.ones(N_IMAGES), np.ones(N_IMAGES)]\n    \n    print('Loading...')\n    for i, image_path in enumerate(data_paths):\n        print(f'\\t {i+1}-th folder')\n        \n        train_data_alg = joblib.Parallel(n_jobs=4, backend='threading')(\n            joblib.delayed(load_image)([i, j, os.path.join(PATH, [['Cover'] + ALGORITHMS][0][i], img_p), labels]) for j, img_p in enumerate(image_path[:n_images]))\n\n        train_data.extend(train_data_alg)\n        \n    shuffle(train_data)\n    return train_data","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def load_test_data():\n    test_data = []\n    for img_p in os.listdir(os.path.join(PATH, 'Test')):\n        img = Image.open(os.path.join(PATH, 'Test', img_p))\n        img = img.convert('RGB')\n        img = img.resize((IMG_SIZE, IMG_SIZE), Image.ANTIALIAS)\n        test_data.append([np.array(img)])\n            \n    return test_data","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"start = time()\ntraining_data = load_training_data_multi(n_images=5000)\n\ntrainImages = np.array([i[0] for i in training_data]).reshape(-1, IMG_SIZE, IMG_SIZE, 3)\ntrainLabels = np.array([i[1] for i in training_data], dtype=int)\n\nX_train, X_val, y_train, y_val = train_test_split(trainImages, trainLabels, random_state=42, stratify=trainLabels)\n\n# Then save some RAM\ndel training_data\ndel trainImages\ndel trainLabels\ngc.collect()\n\nprint(f\"{(time() - start) / 60: .2f} min elapsed.\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model.fit(X_train, y_train,\n          validation_data=(X_val, y_val),\n          batch_size=16,\n          epochs=5, \n          verbose=1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test = load_test_data()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_images = np.array([i[0] for i in test]).reshape(-1, IMG_SIZE, IMG_SIZE, 3)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"predict = model.predict(test_images, batch_size=64)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"sample_sub['Label'] = predict","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"sample_sub.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"sample_sub.to_csv('submission.csv', index=False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]}],"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":4,"nbformat_minor":4}