{"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":"markdown","source":"Hello fellow Kagglers,\n\nThis notebook demonstrates the inference process using 5 EfficientNetV2-S models trained on generated data and fine tuned on the provided competition training dataset.\n\nFor each test sample each models makes a prediction for the two locations (Hanford and Livingston), resulting in 5x2=10 predictions. The final predicted target is simply the mean of these 10 predictions.\n\nThis inference notebook has a flag to save the processed test samples, which takes several hours. These processed test samples can then be loaded in proceeding inference runs to speed up the inference process from ~4 hours to just 30 minutes.\n\n[Training Notebook](https://www.kaggle.com/code/markwijkhuizen/g2net-efficientnetv2-s-generated-data-tf)\n\n[Generating Continuous Gravitational-Wave Sign PUB\n](https://www.kaggle.com/code/markwijkhuizen/generating-continuous-gravitational-wave-sign-pub)\n\n[Generating Continuous Gravitational-Wave Noise PUB\n](https://www.kaggle.com/code/markwijkhuizen/generating-continuous-gravitational-wave-noise-pub)\n\nV3:\n* H0(0.10, 0.01) -> H0(0.10, 0.04)\n* Reduced samples from 14K Signal/7K Noise -> 10K Signal/5K Noise\n* Increased epochs 3 -> 5\n* ReLu -> LeakyReLu\n\nV4:\n* Switching from fine tuned model on competition training data to pretrained model on generated data only","metadata":{}},{"cell_type":"code","source":"import sys\nsys.path.append('/kaggle/input/efficientnetv2-pretrained-imagenet21k-weights/brain_automl/')\nsys.path.append('/kaggle/input/efficientnetv2-pretrained-imagenet21k-weights/brain_automl/efficientnetv2/')","metadata":{"execution":{"iopub.status.busy":"2022-11-23T19:40:13.807643Z","iopub.execute_input":"2022-11-23T19:40:13.808084Z","iopub.status.idle":"2022-11-23T19:40:13.835392Z","shell.execute_reply.started":"2022-11-23T19:40:13.807977Z","shell.execute_reply":"2022-11-23T19:40:13.834486Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport tensorflow as tf\nimport tensorflow_addons as tfa\nimport matplotlib.pyplot as plt\nimport matplotlib as mpl\n\nfrom tqdm.notebook import tqdm\n\nimport h5py\nimport glob\nimport gc\nimport os\nimport effnetv2_model\nimport cv2\n\nprint(f'Tensorflow Version: {tf.__version__}')","metadata":{"execution":{"iopub.status.busy":"2022-11-23T19:40:13.837206Z","iopub.execute_input":"2022-11-23T19:40:13.837954Z","iopub.status.idle":"2022-11-23T19:40:19.315128Z","shell.execute_reply.started":"2022-11-23T19:40:13.837918Z","shell.execute_reply":"2022-11-23T19:40:19.314081Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# MatplotLib Global Settings\nmpl.rcParams.update(mpl.rcParamsDefault)\nmpl.rcParams['xtick.labelsize'] = 16\nmpl.rcParams['ytick.labelsize'] = 16\nmpl.rcParams['axes.labelsize'] = 18\nmpl.rcParams['axes.titlesize'] = 24","metadata":{"execution":{"iopub.status.busy":"2022-11-23T19:40:19.316549Z","iopub.execute_input":"2022-11-23T19:40:19.317423Z","iopub.status.idle":"2022-11-23T19:40:19.326942Z","shell.execute_reply.started":"2022-11-23T19:40:19.317384Z","shell.execute_reply":"2022-11-23T19:40:19.324781Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"TARGET_WIDTH = 4096\nTARGET_HEIGHT = 360\nTARGET_WIDTH_COMPRESSED = 256\nTARGET_WIDTH_COMPRESS_RATIO = TARGET_WIDTH // TARGET_WIDTH_COMPRESSED\n\nINPUTS = ['H1', 'L1']\nN_INPUTS = len(INPUTS)\n\nIS_INTERACTIVE = os.environ['KAGGLE_KERNEL_RUN_TYPE'] == 'Interactive'\n\nGENERATE_CACHE = False\nGENERATE_SUBMISSION = True\nUSE_CACHE = True\n\nN_FOLDS = 5","metadata":{"execution":{"iopub.status.busy":"2022-11-23T19:40:19.329948Z","iopub.execute_input":"2022-11-23T19:40:19.330631Z","iopub.status.idle":"2022-11-23T19:40:19.339459Z","shell.execute_reply.started":"2022-11-23T19:40:19.33059Z","shell.execute_reply":"2022-11-23T19:40:19.338388Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Model","metadata":{}},{"cell_type":"code","source":"# EfficientNetV2-S Model\ndef get_model(fold):\n    inputs = tf.keras.layers.Input(shape=[TARGET_HEIGHT, TARGET_WIDTH_COMPRESSED], dtype=tf.uint8)\n    \n    x = tf.expand_dims(inputs, axis=-1)\n    x = tf.tile(x, [1,1,1,3])\n    x = tf.cast(x, tf.float32)\n    x = tf.keras.applications.imagenet_utils.preprocess_input(x, mode='torch')\n\n    cnn = effnetv2_model.get_model(f'efficientnetv2-s', include_top=False, weights=None)\n\n    x = cnn(x)\n    x = tf.keras.layers.LeakyReLU()(x)\n    x = tf.keras.layers.Dropout(0.30)(x)\n\n    output = tf.keras.layers.Dense(1, activation='sigmoid')(x)\n    \n    # Model\n    model = tf.keras.models.Model(inputs=inputs, outputs=output)\n    \n    # Load Weights\n    model.load_weights(f'/kaggle/input/g2net-efficientnetv2s-generated-data-tf/fold_{fold}_model_pretrained.h5')\n    \n    # Set model untrainable\n    model.trainable = False\n    \n    return model","metadata":{"execution":{"iopub.status.busy":"2022-11-23T19:40:19.342528Z","iopub.execute_input":"2022-11-23T19:40:19.342865Z","iopub.status.idle":"2022-11-23T19:40:19.352744Z","shell.execute_reply.started":"2022-11-23T19:40:19.34283Z","shell.execute_reply":"2022-11-23T19:40:19.351745Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"tf.keras.backend.clear_session()\ngc.collect()\n\n# Load all 5 Models\nMODELS = dict()\nfor fold in tqdm(range(N_FOLDS)):\n     MODELS[fold] = get_model(fold)","metadata":{"execution":{"iopub.status.busy":"2022-11-23T19:40:19.354258Z","iopub.execute_input":"2022-11-23T19:40:19.354889Z","iopub.status.idle":"2022-11-23T19:41:38.155943Z","shell.execute_reply.started":"2022-11-23T19:40:19.354855Z","shell.execute_reply":"2022-11-23T19:41:38.154993Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Model Layer Architecture\nprint(MODELS[0].summary())","metadata":{"execution":{"iopub.status.busy":"2022-11-23T19:41:38.157582Z","iopub.execute_input":"2022-11-23T19:41:38.158273Z","iopub.status.idle":"2022-11-23T19:41:38.190077Z","shell.execute_reply.started":"2022-11-23T19:41:38.158232Z","shell.execute_reply":"2022-11-23T19:41:38.189074Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Model Visualised\ntf.keras.utils.plot_model(MODELS[0], show_shapes=True, show_dtype=True, show_layer_names=True, expand_nested=False)","metadata":{"execution":{"iopub.status.busy":"2022-11-23T19:41:38.191465Z","iopub.execute_input":"2022-11-23T19:41:38.192026Z","iopub.status.idle":"2022-11-23T19:41:39.170254Z","shell.execute_reply.started":"2022-11-23T19:41:38.191971Z","shell.execute_reply":"2022-11-23T19:41:39.169076Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Sample Submission","metadata":{}},{"cell_type":"code","source":"sample_submission = pd.read_csv('/kaggle/input/g2net-detecting-continuous-gravitational-waves/sample_submission.csv')\n\ndisplay(sample_submission.head())\ndisplay(sample_submission.info())","metadata":{"execution":{"iopub.status.busy":"2022-11-23T19:41:39.171719Z","iopub.execute_input":"2022-11-23T19:41:39.172177Z","iopub.status.idle":"2022-11-23T19:41:39.224924Z","shell.execute_reply.started":"2022-11-23T19:41:39.172133Z","shell.execute_reply":"2022-11-23T19:41:39.224017Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Inference","metadata":{}},{"cell_type":"code","source":"if GENERATE_CACHE:\n    !mkdir -p test_samples/x","metadata":{"execution":{"iopub.status.busy":"2022-11-23T19:41:39.227541Z","iopub.execute_input":"2022-11-23T19:41:39.227812Z","iopub.status.idle":"2022-11-23T19:41:39.234244Z","shell.execute_reply.started":"2022-11-23T19:41:39.227787Z","shell.execute_reply":"2022-11-23T19:41:39.232431Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"TEST_FILE_PATHS = glob.glob('/kaggle/input/g2net-detecting-continuous-gravitational-waves/test/*.hdf5')\nprint(f'Found {len(TEST_FILE_PATHS)} test samples')","metadata":{"execution":{"iopub.status.busy":"2022-11-23T19:41:39.235943Z","iopub.execute_input":"2022-11-23T19:41:39.236317Z","iopub.status.idle":"2022-11-23T19:41:39.364434Z","shell.execute_reply.started":"2022-11-23T19:41:39.236284Z","shell.execute_reply":"2022-11-23T19:41:39.363434Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Submissions\nSUBMISSION_ROWS = []\n\nfor idx, file_path in enumerate(tqdm(TEST_FILE_PATHS)):\n    if (idx % 100) == 0:\n        print(f'idx {idx}/{len(TEST_FILE_PATHS)}')\n    \n    # In interactive mode only predict the first 100 samples for debugging purposes\n    if IS_INTERACTIVE and idx == 100:\n        break\n    \n    test_id = file_path.split('/')[-1].split('.')[0]\n    predictions = []\n    \n    # Generate sample folder\n    if GENERATE_CACHE:\n        sample_folder = f'test_samples/x/{test_id}'\n        !mkdir $sample_folder\n\n    # Use cache and load processed test samples\n    if USE_CACHE:\n        for detector in INPUTS:\n            patch_uint8 = cv2.imread(f'/kaggle/input/g2net-efficientnetv2s-generated-data-tf-inference/test_samples/x/{test_id}/{detector}.png', -1)\n            patch_uint8 = np.expand_dims(patch_uint8, axis=0)\n            for model in MODELS.values():\n                # Add prediction to predictions list\n                predictions.append(model.predict_on_batch(patch_uint8).squeeze())\n    # Process test samples from scratch\n    else:\n        # Load H5 File\n        with h5py.File(file_path, 'r') as file:\n            SFT_H = np.array(file[test_id]['H1']['SFTs'], dtype=np.complex128)\n            SFT_L = np.array(file[test_id]['L1']['SFTs'], dtype=np.complex128)\n\n        # Normalize Signal\n        signal_norm = {\n            'H1': SFT_H.real ** 2 + SFT_H.imag ** 2,\n            'L1': SFT_L.real ** 2 + SFT_L.imag ** 2,\n        }\n    \n        # For each detector, process sample and make predictions\n        for d_idx, (detector, signal) in enumerate(signal_norm.items()):\n            # Save as PNG\n            patch_uint8 = signal[:, :4096]\n            patch_uint8 = patch_uint8.reshape(TARGET_HEIGHT, TARGET_WIDTH_COMPRESSED, TARGET_WIDTH_COMPRESS_RATIO).mean(axis=2)\n            patch_uint8 = (patch_uint8 - patch_uint8.min())\n            patch_uint8 = patch_uint8 * (255 / patch_uint8.max())\n            patch_uint8 = patch_uint8.astype(np.uint8)\n\n            # Save processed sample\n            if GENERATE_CACHE:\n                cv2.imwrite(f'{sample_folder}/{detector}.png', patch_uint8, [cv2.IMWRITE_PNG_COMPRESSION, 1])\n\n            # Make Predictions\n            if GENERATE_SUBMISSION:\n                patch_uint8 = np.expand_dims(patch_uint8, axis=0)\n\n                # Add prediction to predictions list\n                for model in MODELS.values():\n                    predictions.append(model.predict_on_batch(patch_uint8).squeeze())\n        \n    # Add to predictions\n    SUBMISSION_ROWS.append({\n        'id': test_id,\n        # Target is mean of predictions\n        'target': np.mean(predictions),\n    })","metadata":{"execution":{"iopub.status.busy":"2022-11-23T19:41:39.365906Z","iopub.execute_input":"2022-11-23T19:41:39.366246Z","iopub.status.idle":"2022-11-23T19:42:47.593605Z","shell.execute_reply.started":"2022-11-23T19:41:39.366213Z","shell.execute_reply":"2022-11-23T19:42:47.592528Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Tar generated cache\nif GENERATE_CACHE:\n    !tar -c --remove-files -f test_samples.tar -C test_samples x","metadata":{"execution":{"iopub.status.busy":"2022-11-23T19:42:47.594822Z","iopub.execute_input":"2022-11-23T19:42:47.595179Z","iopub.status.idle":"2022-11-23T19:42:47.602669Z","shell.execute_reply.started":"2022-11-23T19:42:47.59514Z","shell.execute_reply":"2022-11-23T19:42:47.600003Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Submission","metadata":{}},{"cell_type":"code","source":"SUBMISSION_DF =  pd.DataFrame(SUBMISSION_ROWS)\n\ndisplay(SUBMISSION_DF.info())\ndisplay(SUBMISSION_DF.head())","metadata":{"execution":{"iopub.status.busy":"2022-11-23T19:42:47.60398Z","iopub.execute_input":"2022-11-23T19:42:47.60485Z","iopub.status.idle":"2022-11-23T19:42:47.628656Z","shell.execute_reply.started":"2022-11-23T19:42:47.604806Z","shell.execute_reply":"2022-11-23T19:42:47.627765Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Sanity check, predicted target distribution\nplt.figure(figsize=(15,8))\nplt.title('Predicted Target Distribution')\nSUBMISSION_DF['target'].plot(kind='hist', bins=32)\nplt.xlabel('Count')\nplt.xlabel('Predicted Target')\nplt.xlim(0,1)\nplt.grid()\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-11-23T19:42:47.629951Z","iopub.execute_input":"2022-11-23T19:42:47.630517Z","iopub.status.idle":"2022-11-23T19:42:47.967291Z","shell.execute_reply.started":"2022-11-23T19:42:47.630482Z","shell.execute_reply":"2022-11-23T19:42:47.966381Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"SUBMISSION_DF.to_csv('submission.csv', index=False)","metadata":{"execution":{"iopub.status.busy":"2022-11-23T19:42:47.968815Z","iopub.execute_input":"2022-11-23T19:42:47.969197Z","iopub.status.idle":"2022-11-23T19:42:47.977555Z","shell.execute_reply.started":"2022-11-23T19:42:47.969151Z","shell.execute_reply":"2022-11-23T19:42:47.976521Z"},"trusted":true},"execution_count":null,"outputs":[]}]}