{"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":"# Import Modules\nimport gc\nimport os\nimport multiprocessing\nimport time\nimport numpy as np\nimport pandas as pd\nimport pyarrow.parquet as pq\nimport tensorflow as tf\nfrom tqdm import tqdm\n\n# Constants\nbatch_size = 1024","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2023-03-28T09:20:03.537146Z","iopub.execute_input":"2023-03-28T09:20:03.537661Z","iopub.status.idle":"2023-03-28T09:20:08.047672Z","shell.execute_reply.started":"2023-03-28T09:20:03.537571Z","shell.execute_reply":"2023-03-28T09:20:08.046723Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# directory\nhome_dir = \"/kaggle/input/icecube-neutrinos-in-deep-ice/\"\ntrain_format = home_dir + 'train/batch_{batch_id:d}.parquet'\ntest_format = home_dir + 'test/batch_{batch_id:d}.parquet'\nmodel_home = \"/kaggle/input/icecubes/\"\n\n# Model(s)\nmodel_names_128 = [\"train_tpu_v9/tpurun_v9e_mod_bin64_epoch1.h5\",\n                   \"train_tpu_v9/tpurun_v9e_mod_bin64_epoch2.h5\",\n                   \"train_tpu_v9/tpurun_v9e_mod_bin64_epoch3.h5\",\n                   \"train_tpu_v9/tpurun_v9e_mod_bin64_epoch5.h5\",\n                   \"train_tpu_v9/tpurun_v9e_mod_bin64_epoch6.h5\"]\n\n# Model(s)\nmodel_names_160 = [\"train_tpu_v10/tpurun_v10c_mod_bin64_epoch5.h5\",\n                   \"train_tpu_v10/tpurun_v10c_mod_bin64_epoch6.h5\",\n                   \"train_tpu_v10/tpurun_v10d_mod_bin64_epoch1.h5\",\n                   \"train_tpu_v10/tpurun_v10d_mod_bin64_epoch2.h5\",\n                   \"train_tpu_v10/tpurun_v10d_mod_bin64_epoch3.h5\",\n                   \"train_tpu_v10/tpurun_v10d_mod_bin64_epoch4.h5\",]\n\nweights = np.array([1/11.,\n                    1/11.,\n                    1/11.,\n                    1/11.,\n                    1/11.,\n                    1/11.,\n                    1/11.,\n                    1/11.,\n                    1/11.,\n                    1/11.,\n                    1/11.])","metadata":{"execution":{"iopub.status.busy":"2023-03-28T09:20:08.049602Z","iopub.execute_input":"2023-03-28T09:20:08.050206Z","iopub.status.idle":"2023-03-28T09:20:08.057828Z","shell.execute_reply.started":"2023-03-28T09:20:08.050169Z","shell.execute_reply":"2023-03-28T09:20:08.056624Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Load Model","metadata":{}},{"cell_type":"code","source":"models_128 = list()\nfor model_name in model_names_128:\n    print(model_name)\n    \n    model_path = model_home + model_name\n    model = tf.keras.models.load_model(model_path)\n    model.summary()\n    \n    models_128.append(model)\n    \nmodels_160 = list()\nfor model_name in model_names_160:\n    print(model_name)\n    \n    model_path = model_home + model_name\n    model = tf.keras.models.load_model(model_path)\n    model.summary()\n    \n    models_160.append(model)","metadata":{"execution":{"iopub.status.busy":"2023-03-28T09:20:08.059636Z","iopub.execute_input":"2023-03-28T09:20:08.059996Z","iopub.status.idle":"2023-03-28T09:20:31.013286Z","shell.execute_reply.started":"2023-03-28T09:20:08.059959Z","shell.execute_reply":"2023-03-28T09:20:31.012106Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"max_pulse_count = model.inputs[0].shape[1]\nn_features = model.inputs[0].shape[2]\noutput_bins = model.layers[-1].weights[0].shape[-1]\n\nbin_num = int(np.sqrt(output_bins))\n\nprint(\"    bin_num    : \", bin_num)\nprint(\"max_pulse_count: \", max_pulse_count)\nprint(\"   n_features  : \", n_features)","metadata":{"execution":{"iopub.status.busy":"2023-03-28T09:20:31.014687Z","iopub.execute_input":"2023-03-28T09:20:31.015084Z","iopub.status.idle":"2023-03-28T09:20:31.023919Z","shell.execute_reply.started":"2023-03-28T09:20:31.015046Z","shell.execute_reply":"2023-03-28T09:20:31.022623Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Set Detector Geometry","metadata":{}},{"cell_type":"code","source":"# sensor_geometry\nsensor_geometry_df = pd.read_csv(home_dir + \"sensor_geometry.csv\")\n\n# evaluate error\nsensor_x = sensor_geometry_df.x\nsensor_y = sensor_geometry_df.y\nsensor_z = sensor_geometry_df.z\n\n# detector constants\nc_const = 0.299792458  # speed of light [m/ns]\n\nx_min = sensor_x.min()\nx_max = sensor_x.max()\ny_min = sensor_y.min()\ny_max = sensor_y.max()\nz_min = sensor_z.min()\nz_max = sensor_z.max()\n\ndetector_length = np.sqrt((x_max - x_min)**2 + (y_max - y_min)**2 + (z_max - z_min)**2)\nt_valid_length = detector_length / c_const\n\nprint(\"t_valid_length: \", t_valid_length, \" ns\")","metadata":{"execution":{"iopub.status.busy":"2023-03-28T09:20:31.02788Z","iopub.execute_input":"2023-03-28T09:20:31.028781Z","iopub.status.idle":"2023-03-28T09:20:31.050685Z","shell.execute_reply.started":"2023-03-28T09:20:31.028687Z","shell.execute_reply":"2023-03-28T09:20:31.049831Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Data I/O Helper","metadata":{}},{"cell_type":"markdown","source":"## Angle one-hot encoding edges\n\n- It is efficient to train the model by classification task, initially.\n- azimuth and zenith are independent\n- azimuth distribution is flat and zenith distribution is sinusoidal.\n  - Flat on the spherical surface\n  - $\\phi > \\pi$ events are a little bit rarer than $\\phi < \\pi$ events, (maybe) because of the neutrino attenuation by earth.\n- So, the uniform bin is used for azimuth, and $\\left| \\cos \\right|$ bin is used for zenith","metadata":{}},{"cell_type":"code","source":"azimuth_edges = np.linspace(0, 2 * np.pi, bin_num + 1)\nzenith_edges_flat = np.linspace(0, np.pi, bin_num + 1)\nzenith_edges = list()\nzenith_edges.append(0)\nfor bin_idx in range(1, bin_num):\n    zen_now = np.arccos(np.cos(zenith_edges[-1]) - 2 / (bin_num))\n    zenith_edges.append(zen_now)\nzenith_edges.append(np.pi)\nzenith_edges = np.array(zenith_edges)","metadata":{"execution":{"iopub.status.busy":"2023-03-28T09:20:31.06391Z","iopub.execute_input":"2023-03-28T09:20:31.064327Z","iopub.status.idle":"2023-03-28T09:20:31.075875Z","shell.execute_reply.started":"2023-03-28T09:20:31.064293Z","shell.execute_reply":"2023-03-28T09:20:31.074923Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Define a function converts from prediction to angles\n\n- Calculation of the mean-vector in a bin $\\theta \\in ( \\theta_0, \\theta_1 )$ and $\\phi \\in ( \\phi_0, \\phi_1 )$\n  - $\\vec{r} \\left( \\theta, ~ \\phi \\right) = \\left< \\sin \\theta \\cos \\phi, ~ \\sin \\theta \\sin \\phi, ~ \\cos \\theta \\right>$\n  - $\\bar{\\vec{r}} = \\frac{ \\int_{\\theta_{0}}^{\\theta_{1}} \\int_{\\phi_0}^{\\phi_1} \\vec{r} \\left( \\theta, ~ \\phi \\right) \\sin \\theta \\,d\\phi \\,d\\theta }{ \\int_{\\theta_{0}}^{\\theta_{1}} \\int_{\\phi_0}^{\\phi_1} 1 \\sin \\theta \\,d\\phi \\,d\\theta }$\n  - $ \\int_{\\theta_{0}}^{\\theta_{1}} \\int_{\\phi_0}^{\\phi_1} 1 \\sin \\theta \\,d\\phi \\,d\\theta = \\left( \\phi_1 - \\phi_0 \\right) \\left( \\cos \\theta_0 - \\cos \\theta_1 \\right)$\n  - $\n\\int_{\\theta_{0}}^{\\theta_{1}} \\int_{\\phi_0}^{\\phi_1} {r}_{x} \\left( \\theta, ~ \\phi \\right) \\sin \\theta \\,d\\phi \\,d\\theta = \n\\int_{\\theta_{0}}^{\\theta_{1}} \\int_{\\phi_0}^{\\phi_1} \\sin^2 \\theta \\cos \\phi \\,d\\phi \\,d\\theta = \n\\left( \\sin \\phi_1 - \\sin \\phi_0 \\right) \\left( \\frac{\\theta_1 - \\theta_0}{2} - \\frac{\\sin 2 \\theta_1 - \\sin 2 \\theta_0}{4} \\right)\n$\n  - $\n\\int_{\\theta_{0}}^{\\theta_{1}} \\int_{\\phi_0}^{\\phi_1} {r}_{y} \\left( \\theta, ~ \\phi \\right) \\sin \\theta \\,d\\phi \\,d\\theta = \n\\int_{\\theta_{0}}^{\\theta_{1}} \\int_{\\phi_0}^{\\phi_1} \\sin^2 \\theta \\sin \\phi \\,d\\phi \\,d\\theta = \n\\left( \\cos \\phi_0 - \\cos \\phi_1 \\right) \\left( \\frac{\\theta_1 - \\theta_0}{2} - \\frac{\\sin 2 \\theta_1 - \\sin 2 \\theta_0}{4} \\right)\n$\n  - $\n\\int_{\\theta_{0}}^{\\theta_{1}} \\int_{\\phi_0}^{\\phi_1} {r}_{z} \\left( \\theta, ~ \\phi \\right) \\sin \\theta \\,d\\phi \\,d\\theta = \n\\int_{\\theta_{0}}^{\\theta_{1}} \\int_{\\phi_0}^{\\phi_1} \\sin \\theta \\cos \\theta \\,d\\phi \\,d\\theta = \n\\left( \\phi_1 - \\phi_0 \\right) \\left( \\frac{\\cos 2 \\theta_0 - \\cos 2 \\theta_1}{4} \\right)\n$","metadata":{}},{"cell_type":"code","source":"angle_bin_zenith0 = np.tile(zenith_edges[:-1], bin_num)\nangle_bin_zenith1 = np.tile(zenith_edges[1:], bin_num)\nangle_bin_azimuth0 = np.repeat(azimuth_edges[:-1], bin_num)\nangle_bin_azimuth1 = np.repeat(azimuth_edges[1:], bin_num)\n\nangle_bin_area = (angle_bin_azimuth1 - angle_bin_azimuth0) * (np.cos(angle_bin_zenith0) - np.cos(angle_bin_zenith1))\nangle_bin_vector_sum_x = (np.sin(angle_bin_azimuth1) - np.sin(angle_bin_azimuth0)) * ((angle_bin_zenith1 - angle_bin_zenith0) / 2 - (np.sin(2 * angle_bin_zenith1) - np.sin(2 * angle_bin_zenith0)) / 4)\nangle_bin_vector_sum_y = (np.cos(angle_bin_azimuth0) - np.cos(angle_bin_azimuth1)) * ((angle_bin_zenith1 - angle_bin_zenith0) / 2 - (np.sin(2 * angle_bin_zenith1) - np.sin(2 * angle_bin_zenith0)) / 4)\nangle_bin_vector_sum_z = (angle_bin_azimuth1 - angle_bin_azimuth0) * ((np.cos(2 * angle_bin_zenith0) - np.cos(2 * angle_bin_zenith1)) / 4)\n\nangle_bin_vector_mean_x = angle_bin_vector_sum_x / angle_bin_area\nangle_bin_vector_mean_y = angle_bin_vector_sum_y / angle_bin_area\nangle_bin_vector_mean_z = angle_bin_vector_sum_z / angle_bin_area\n\nangle_bin_vector = np.zeros((1, bin_num * bin_num, 3))\nangle_bin_vector[:, :, 0] = angle_bin_vector_mean_x\nangle_bin_vector[:, :, 1] = angle_bin_vector_mean_y\nangle_bin_vector[:, :, 2] = angle_bin_vector_mean_z\n\nangle_bin_vector_unit = angle_bin_vector[0].copy()\nangle_bin_vector_unit /= np.sqrt((angle_bin_vector_unit**2).sum(axis=1).reshape((-1, 1)))","metadata":{"execution":{"iopub.status.busy":"2023-03-28T09:20:31.077315Z","iopub.execute_input":"2023-03-28T09:20:31.077886Z","iopub.status.idle":"2023-03-28T09:20:31.091672Z","shell.execute_reply.started":"2023-03-28T09:20:31.077841Z","shell.execute_reply":"2023-03-28T09:20:31.090759Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def pred_to_angle(pred, epsilon=1e-8):\n    # convert prediction to vector\n    pred_vector = (pred.reshape((-1, bin_num * bin_num, 1)) * angle_bin_vector).sum(axis=1)\n    \n    # normalize\n    pred_vector_norm = np.sqrt((pred_vector**2).sum(axis=1))\n    mask = pred_vector_norm < epsilon\n    pred_vector_norm[mask] = 1\n    \n    # assign <1, 0, 0> to very small vectors (badly predicted)\n    pred_vector /= pred_vector_norm.reshape((-1, 1))\n    pred_vector[mask] = np.array([1., 0., 0.])\n    \n    # convert to angle\n    azimuth = np.arctan2(pred_vector[:, 1], pred_vector[:, 0])\n    azimuth[azimuth < 0] += 2 * np.pi\n    zenith = np.arccos(pred_vector[:, 2])\n    \n    # mask bad norm predictions as 0, 0\n    azimuth[mask] = 0.\n    zenith[mask] = 0.\n    \n    return azimuth, zenith","metadata":{"execution":{"iopub.status.busy":"2023-03-28T09:20:31.093496Z","iopub.execute_input":"2023-03-28T09:20:31.093975Z","iopub.status.idle":"2023-03-28T09:20:31.10412Z","shell.execute_reply.started":"2023-03-28T09:20:31.09394Z","shell.execute_reply":"2023-03-28T09:20:31.103008Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Weighted-Vector Ensemble","metadata":{}},{"cell_type":"code","source":"def weighted_vector_ensemble(angles, weight):\n    # Convert angle to vector\n    vec_models = list()\n    for angle in angles:\n        az, zen = angle\n\n        sa = np.sin(az)\n        ca = np.cos(az)\n        sz = np.sin(zen)\n        cz = np.cos(zen)\n\n        vec = np.stack([sz * ca, sz * sa, cz], axis=1)\n        vec_models.append(vec)\n    vec_models = np.array(vec_models)\n\n    # Weighted-mean\n    vec_mean = (weight.reshape((-1, 1, 1)) * vec_models).sum(axis=0) / weight.sum()\n    vec_mean /= np.sqrt((vec_mean**2).sum(axis=1)).reshape((-1, 1))\n\n    # Convert vector to angle\n    zenith = np.arccos(vec_mean[:, 2])\n    azimuth = np.arctan2(vec_mean[:, 1], vec_mean[:, 0])\n    azimuth[azimuth < 0] += 2 * np.pi\n    \n    return azimuth, zenith","metadata":{"execution":{"iopub.status.busy":"2023-03-28T09:20:31.105841Z","iopub.execute_input":"2023-03-28T09:20:31.106243Z","iopub.status.idle":"2023-03-28T09:20:31.117255Z","shell.execute_reply.started":"2023-03-28T09:20:31.10621Z","shell.execute_reply":"2023-03-28T09:20:31.1163Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Single event reader function\n\n- Pick-up important data points first\n    - Rank 3 (First)\n        - not aux, in valid time window\n    - Rank 2\n        - not aux, out of valid time window\n    - Rank 1\n        - aux, in valid time window\n    - Rank 0 (Last)\n        - aux, out of valid time window\n    - In each ranks, take pulses from highest charge","metadata":{}},{"cell_type":"code","source":"open_batch_dict = dict()\n\n\n# read single event from batch_meta_df\ndef read_event(event_idx, batch_meta_df, max_pulse_count):\n    # read metadata\n    batch_id, first_pulse_index, last_pulse_index = batch_meta_df.iloc[event_idx][[\"batch_id\", \"first_pulse_index\", \"last_pulse_index\"]].astype(\"int\")\n\n    # close past batch df\n    if batch_id - 1 in open_batch_dict.keys():\n        del open_batch_dict[batch_id - 1]\n\n    # open current batch df\n    if batch_id not in open_batch_dict.keys():\n        open_batch_dict.update({batch_id: pd.read_parquet(test_format.format(batch_id=batch_id))})\n    \n    batch_df = open_batch_dict[batch_id]\n    \n    # read event\n    event_feature = batch_df[first_pulse_index:last_pulse_index + 1]\n    sensor_id = event_feature.sensor_id\n    \n    # merge features into single structured array\n    dtype = [\n        (\"time\", \"float16\"),\n        (\"charge\", \"float16\"),\n        (\"auxiliary\", \"float16\"),\n        (\"x\", \"float16\"),\n        (\"y\", \"float16\"),\n        (\"z\", \"float16\"),\n        (\"rank\", \"short\"),\n    ]\n    \n    \n    event_x = np.zeros(last_pulse_index - first_pulse_index + 1, dtype)\n    event_x[\"time\"] = event_feature.time.values - event_feature.time.min()\n    event_x[\"charge\"] = event_feature.charge.values\n    event_x[\"auxiliary\"] = event_feature.auxiliary.values\n    event_x[\"x\"] = sensor_geometry_df.x[sensor_id].values\n    event_x[\"y\"] = sensor_geometry_df.y[sensor_id].values\n    event_x[\"z\"] = sensor_geometry_df.z[sensor_id].values\n\n    # For long event, pick-up\n    if len(event_x) > max_pulse_count:\n        # Find valid time window\n        t_peak = event_x[\"time\"][event_x[\"charge\"].argmax()]\n        t_valid_min = t_peak - t_valid_length\n        t_valid_max = t_peak + t_valid_length\n\n        t_valid = (event_x[\"time\"] > t_valid_min) * (event_x[\"time\"] < t_valid_max)\n\n        # rank\n        event_x[\"rank\"] = 2 * (1 - event_x[\"auxiliary\"]) + (t_valid)\n\n        # sort by rank and charge (important goes to backward)\n        event_x = np.sort(event_x, order=[\"rank\", \"charge\"])\n\n        # pick-up from backward\n        event_x = event_x[-max_pulse_count:]\n\n        # resort by time\n        event_x = np.sort(event_x, order=\"time\")\n\n    return event_idx, len(event_x), event_x","metadata":{"execution":{"iopub.status.busy":"2023-03-28T09:20:31.119173Z","iopub.execute_input":"2023-03-28T09:20:31.119569Z","iopub.status.idle":"2023-03-28T09:20:31.133812Z","shell.execute_reply.started":"2023-03-28T09:20:31.119535Z","shell.execute_reply":"2023-03-28T09:20:31.132638Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Data I/O (for CPU) & Normalization\n\n- Read data\n- Concatenate and convert\n- Normalize time, charge and position variables","metadata":{}},{"cell_type":"markdown","source":"## Read test metadata and define spliter (for CPU)","metadata":{}},{"cell_type":"code","source":"test_meta_df = pq.read_table(home_dir + 'test_meta.parquet').to_pandas()\ntest_meta_df.head()","metadata":{"execution":{"iopub.status.busy":"2023-03-28T09:20:31.135415Z","iopub.execute_input":"2023-03-28T09:20:31.135759Z","iopub.status.idle":"2023-03-28T09:20:31.231511Z","shell.execute_reply.started":"2023-03-28T09:20:31.135727Z","shell.execute_reply":"2023-03-28T09:20:31.230442Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"batch_counts = test_meta_df.batch_id.value_counts().sort_index()\n\nbatch_max_index = batch_counts.cumsum()\nbatch_max_index[test_meta_df.batch_id.min() - 1] = 0\nbatch_max_index = batch_max_index.sort_index()\n\n\ndef test_meta_df_spliter(batch_id):\n    return test_meta_df.loc[batch_max_index[batch_id - 1]:batch_max_index[batch_id] - 1]","metadata":{"execution":{"iopub.status.busy":"2023-03-28T09:20:31.233029Z","iopub.execute_input":"2023-03-28T09:20:31.233379Z","iopub.status.idle":"2023-03-28T09:20:31.244768Z","shell.execute_reply.started":"2023-03-28T09:20:31.233349Z","shell.execute_reply":"2023-03-28T09:20:31.243822Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Read test data and predict batch-by-batch","metadata":{}},{"cell_type":"code","source":"# cleanup\ngc.collect()\n\ntest_batch_ids = test_meta_df.batch_id.unique()\n\ntest_event_id = list()\ntest_azimuth = list()\ntest_zenith = list()\n\n# Public test handling\nif len(test_batch_ids) == 1:\n    submission_df = pd.read_parquet('/kaggle/input/icecube-neutrinos-in-deep-ice/sample_submission.parquet')\n    submission_df.to_csv('submission.csv')\nelse:\n    for batch_id in test_batch_ids:\n        # One batch at a time\n        batch_meta_df = test_meta_df_spliter(batch_id)\n\n        # register pulses\n        test_x = np.zeros((len(batch_meta_df), max_pulse_count, n_features), dtype = \"float16\")    \n        test_x[:, :, 2] = -1    \n\n        def read_event_local(event_idx):\n            return read_event(event_idx, batch_meta_df, max_pulse_count)\n\n        # scan events\n        iterator = range(len(batch_meta_df))\n        with multiprocessing.Pool() as pool:\n            for event_idx, pulse_count, event_x in pool.map(read_event_local, iterator):\n                # feature\n                test_x[event_idx, :pulse_count, 0] = event_x[\"time\"]\n                test_x[event_idx, :pulse_count, 1] = event_x[\"charge\"]\n                test_x[event_idx, :pulse_count, 2] = event_x[\"auxiliary\"]\n                test_x[event_idx, :pulse_count, 3] = event_x[\"x\"]\n                test_x[event_idx, :pulse_count, 4] = event_x[\"y\"]\n                test_x[event_idx, :pulse_count, 5] = event_x[\"z\"]\n\n        del batch_meta_df\n\n        # Normalize\n        test_x[:, :, 0] /= 1000   # 1000  # time\n        test_x[:, :, 1] /= 300    # charge\n        test_x[:, :, 3] /= 577    # x\n        test_x[:, :, 4] /= 577    # y\n        test_x[:, :, 5] /= 577    # z\n        test_x = test_x[:, :,  [0,1,2,3,4,5]]\n\n        third_shape = test_x.shape[0] // 5\n\n        # Predictions\n        preds_azimuth = []\n        preds_zenith = []\n\n        # Predict - Part 1\n        pred_angles = []    \n        for i, model in enumerate(models_160):\n            pred_model = model.predict(test_x[:third_shape, :, :], batch_size = batch_size, verbose=1)\n            az_model, zen_model = pred_to_angle(pred_model)\n            pred_angles.append((az_model, zen_model))        \n        for i, model in enumerate(models_128):\n            pred_model = model.predict(test_x[:third_shape, :128, :], batch_size = batch_size, verbose=1)\n            az_model, zen_model = pred_to_angle(pred_model)\n            pred_angles.append((az_model, zen_model))\n        pred_azimuth, pred_zenith = weighted_vector_ensemble(pred_angles, weights)\n        preds_azimuth.extend(pred_azimuth)\n        preds_zenith.extend(pred_zenith)\n\n        # Predict - Part 2\n        pred_angles = []\n        for i, model in enumerate(models_160):\n            pred_model = model.predict(test_x[third_shape:2*third_shape, :, :], batch_size = batch_size, verbose=1)\n            az_model, zen_model = pred_to_angle(pred_model)\n            pred_angles.append((az_model, zen_model))\n        for i, model in enumerate(models_128):\n            pred_model = model.predict(test_x[third_shape:2*third_shape, :128, :], batch_size = batch_size, verbose=1)\n            az_model, zen_model = pred_to_angle(pred_model)\n            pred_angles.append((az_model, zen_model))\n        pred_azimuth, pred_zenith = weighted_vector_ensemble(pred_angles, weights)\n        preds_azimuth.extend(pred_azimuth)\n        preds_zenith.extend(pred_zenith)\n\n        # Predict - Part 3\n        pred_angles = []\n        for i, model in enumerate(models_160):\n            pred_model = model.predict(test_x[2*third_shape:3*third_shape, :, :], batch_size = batch_size, verbose=1)\n            az_model, zen_model = pred_to_angle(pred_model)\n            pred_angles.append((az_model, zen_model))\n        for i, model in enumerate(models_128):\n            pred_model = model.predict(test_x[2*third_shape:3*third_shape, :128, :], batch_size = batch_size, verbose=1)\n            az_model, zen_model = pred_to_angle(pred_model)\n            pred_angles.append((az_model, zen_model))        \n        pred_azimuth, pred_zenith = weighted_vector_ensemble(pred_angles, weights)\n        preds_azimuth.extend(pred_azimuth)\n        preds_zenith.extend(pred_zenith)\n        \n        # Predict - Part 4\n        pred_angles = []\n        for i, model in enumerate(models_160):\n            pred_model = model.predict(test_x[3*third_shape:4*third_shape, :, :], batch_size = batch_size, verbose=1)\n            az_model, zen_model = pred_to_angle(pred_model)\n            pred_angles.append((az_model, zen_model))\n        for i, model in enumerate(models_128):\n            pred_model = model.predict(test_x[3*third_shape:4*third_shape, :128, :], batch_size = batch_size, verbose=1)\n            az_model, zen_model = pred_to_angle(pred_model)\n            pred_angles.append((az_model, zen_model))        \n        pred_azimuth, pred_zenith = weighted_vector_ensemble(pred_angles, weights)\n        preds_azimuth.extend(pred_azimuth)\n        preds_zenith.extend(pred_zenith)\n\n        # Predict - Part 5\n        pred_angles = []\n        for i, model in enumerate(models_160):\n            pred_model = model.predict(test_x[4*third_shape:, :, :], batch_size = batch_size, verbose=1)\n            az_model, zen_model = pred_to_angle(pred_model)\n            pred_angles.append((az_model, zen_model))\n        for i, model in enumerate(models_128):\n            pred_model = model.predict(test_x[4*third_shape:, :128, :], batch_size = batch_size, verbose=1)\n            az_model, zen_model = pred_to_angle(pred_model)\n            pred_angles.append((az_model, zen_model))\n        pred_azimuth, pred_zenith = weighted_vector_ensemble(pred_angles, weights)\n        preds_azimuth.extend(pred_azimuth)\n        preds_zenith.extend(pred_zenith)\n\n        event_ids = test_meta_df.event_id[test_meta_df.batch_id == batch_id].values\n\n        for event_id, azimuth, zenith in zip(event_ids, preds_azimuth, preds_zenith):\n            if np.isfinite(azimuth) and np.isfinite(zenith):\n                test_event_id.append(int(event_id))\n                test_azimuth.append(azimuth)\n                test_zenith.append(zenith)\n            else:\n                test_event_id.append(int(event_id))\n                test_azimuth.append(0.)\n                test_zenith.append(0.)\n\n        # cleanup\n        gc.collect()\n    \n    # Create and Save Submission.csv\n    submission_df = pd.DataFrame({\"event_id\": test_event_id,\n                                  \"azimuth\": test_azimuth,\n                                  \"zenith\": test_zenith})\n    submission_df = submission_df.sort_values(by = ['event_id'])\n    submission_df.to_csv(\"submission.csv\", index = False)\n\n    # Summary\n    submission_df.head()","metadata":{"execution":{"iopub.status.busy":"2023-03-28T09:20:31.249162Z","iopub.execute_input":"2023-03-28T09:20:31.249422Z","iopub.status.idle":"2023-03-28T09:20:58.097897Z","shell.execute_reply.started":"2023-03-28T09:20:31.249398Z","shell.execute_reply":"2023-03-28T09:20:58.096941Z"},"trusted":true},"execution_count":null,"outputs":[]}]}