{"metadata":{"kaggle":{"accelerator":"none","dataSources":[{"sourceId":73479,"databundleVersionId":8152410,"sourceType":"competition"}],"dockerImageVersionId":30698,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false},"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"codemirror_mode":{"name":"ipython","version":3},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython3","version":"3.9.18"},"papermill":{"default_parameters":{},"duration":10308.207892,"end_time":"2024-04-16T06:33:41.291446","environment_variables":{},"exception":null,"input_path":"__notebook__.ipynb","output_path":"__notebook__.ipynb","parameters":{},"start_time":"2024-04-16T03:41:53.083554","version":"2.5.0"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import pandas as pd\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\nimport os\nfrom tensorflow.keras.backend import clear_session\nimport tensorflow as tf\nimport numpy as np\nfrom sklearn.metrics import confusion_matrix\nimport matplotlib.pyplot as plt\n\nimages_dir = \"./train/\"\nlabels = pd.read_csv(\"./train.csv\")\n\n# add the directory to the filename\nlabels['image_name'] = labels['image_name'].apply(lambda x: os.path.join(images_dir, x))\nlabels['target'] = labels['motor_visible'].apply(lambda x: 'visible' if x == 1 else 'not visible')\n\nBATCH_SIZE = 4\n","metadata":{"execution":{"iopub.execute_input":"2024-04-16T03:41:55.742132Z","iopub.status.busy":"2024-04-16T03:41:55.741427Z","iopub.status.idle":"2024-04-16T03:42:08.006550Z","shell.execute_reply":"2024-04-16T03:42:08.005780Z"},"papermill":{"duration":12.273793,"end_time":"2024-04-16T03:42:08.008850","exception":false,"start_time":"2024-04-16T03:41:55.735057","status":"completed"},"tags":[]},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Primary Classification Model\nFirst, fit a convolutional neural network to classify whether or not an image has a motor present.","metadata":{"papermill":{"duration":0.004656,"end_time":"2024-04-16T03:42:08.018803","exception":false,"start_time":"2024-04-16T03:42:08.014147","status":"completed"},"tags":[]}},{"cell_type":"code","source":"# Initialize the ImageDataGenerator with augmentation\ndatagen = ImageDataGenerator(\n    #rescale=1./255,\n    validation_split=0.25,\n    #rotation_range=30,\n    #width_shift_range=0.2,\n    #height_shift_range=0.2,\n    #shear_range=0.2,\n    #zoom_range=0.2,\n    horizontal_flip=True,\n    vertical_flip=True,\n    fill_mode='nearest'\n)\n\n\n# Create the training and validation generators\ntrain_generator = datagen.flow_from_dataframe(\n    dataframe=labels,\n    directory=None,  \n    x_col='image_name',\n    y_col='target',\n    target_size=(512, 512), # You can change the size of the image\n    batch_size=BATCH_SIZE, # You can change the batch_size\n    class_mode='categorical',  \n    subset='training',\n    color_mode=\"rgb\" # have to load in rgb mode to use pretrained model\n)\n\nvalidation_generator = datagen.flow_from_dataframe(\n    dataframe=labels,\n    directory=None,  \n    x_col='image_name',\n    y_col='target',\n    target_size=(512, 512), # Should match training size\n    batch_size=BATCH_SIZE, # Should match training\n    class_mode='categorical',  \n    subset='validation',\n    color_mode=\"rgb\"\n)\nnum_classes = 2\nclass_names = {v: k for k, v in train_generator.class_indices.items()}\nclass_names","metadata":{"execution":{"iopub.execute_input":"2024-04-16T03:42:08.029588Z","iopub.status.busy":"2024-04-16T03:42:08.029290Z","iopub.status.idle":"2024-04-16T03:42:16.205544Z","shell.execute_reply":"2024-04-16T03:42:16.204715Z"},"papermill":{"duration":8.184183,"end_time":"2024-04-16T03:42:16.207660","exception":false,"start_time":"2024-04-16T03:42:08.023477","status":"completed"},"tags":[]},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Using the EfficientNetV2S with weights trained on imagenet","metadata":{}},{"cell_type":"code","source":"from tensorflow.keras.applications import EfficientNetV2S\nfrom tensorflow.keras.models import Model\nfrom tensorflow.keras.layers import Conv2D, MaxPooling2D, Dropout, GlobalAveragePooling2D, Dense, Input,Add\nfrom tensorflow.keras.regularizers import l2\nfrom tensorflow.keras.optimizers import Adam\ntf.keras.backend.clear_session()\ndef residual_dense_block(input_layer, num_units):\n    # Dense layer 1\n    x = Dense(num_units, activation='relu')(input_layer)\n    # Dense layer 2\n    x = Dense(num_units, activation='relu')(x)\n    # Add shortcut connection\n    shortcut = Dense(num_units)(input_layer)\n    x = Add()([x, shortcut])\n    return x\n# Define input shape\ninput_shape = (512, 512, 3)\n \n# Load the pre-trained model\npretrained = EfficientNetV2S(weights='imagenet', include_top=False, input_shape=input_shape)\n \n# Freeze the layers\npretrained.trainable = False\n \n# Define input tensor\ninputs = Input(shape=input_shape)\n \n# Pass input tensor through VGG16 model\npretrained_output = pretrained(inputs)\n \n# Flatten the output\nx = GlobalAveragePooling2D()(pretrained_output)\n\n\n\n# Dense layers\n#x = Dense(256, activation='relu', kernel_regularizer = l2(0.01))(x)\n#x = Dropout(0.5)(x)\n#x = Dense(128, activation='relu', kernel_regularizer = l2(0.01))(x)\n#x = Dropout(0.5)(x)\n# Output layer\noutputs = Dense(num_classes, activation='softmax')(x)\n\n# Define the model\nmodel = Model(inputs=inputs, outputs=outputs)\nmodel.summary()\n","metadata":{"execution":{"iopub.execute_input":"2024-04-16T03:42:16.219519Z","iopub.status.busy":"2024-04-16T03:42:16.219228Z","iopub.status.idle":"2024-04-16T03:42:21.865076Z","shell.execute_reply":"2024-04-16T03:42:21.864194Z"},"papermill":{"duration":5.653931,"end_time":"2024-04-16T03:42:21.867030","exception":false,"start_time":"2024-04-16T03:42:16.213099","status":"completed"},"tags":[]},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"multi-phase training approach","metadata":{}},{"cell_type":"code","source":"phase1_epochs = 10\nphase1_lr = 0.001\nphase2_epochs = 20\nphase2_lr = 0.00001\nphase3_epochs = 3\nphase3_lr = 0.0001\n\n## Phase 1\npretrained.trainable = False\nmodel.compile(\n    optimizer=Adam(learning_rate = phase1_lr),  \n    loss='categorical_crossentropy', \n    metrics=['accuracy'])\n\nhistory = model.fit(train_generator,\n                    epochs = phase1_epochs, \n                    validation_data = validation_generator)\n\n## Phase 2\npretrained.trainable = True\nmodel.compile(\n    optimizer=Adam(learning_rate = phase2_lr),  \n    loss='categorical_crossentropy', \n    metrics=['accuracy'])\n\nhistory = model.fit(train_generator,\n                    initial_epoch= phase1_epochs,\n                    epochs= phase1_epochs + phase2_epochs, \n                    validation_data= validation_generator)\n\n## Phase 3\npretrained.trainable = False\nmodel.compile(\n    optimizer=Adam(learning_rate = phase3_lr),  \n    loss='categorical_crossentropy', \n    metrics=['accuracy'])\n\nhistory = model.fit(train_generator,\n                    initial_epoch = phase1_epochs + phase2_epochs,\n                    epochs = phase1_epochs + phase2_epochs + phase3_epochs, \n                    validation_data = validation_generator)\n","metadata":{"execution":{"iopub.execute_input":"2024-04-16T03:42:21.884296Z","iopub.status.busy":"2024-04-16T03:42:21.884003Z","iopub.status.idle":"2024-04-16T04:30:15.926892Z","shell.execute_reply":"2024-04-16T04:30:15.925933Z"},"papermill":{"duration":2874.053983,"end_time":"2024-04-16T04:30:15.929080","exception":false,"start_time":"2024-04-16T03:42:21.875097","status":"completed"},"tags":[]},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"It's possible (and more efficient) to save the weights of the model instead of running it multiple times.","metadata":{}},{"cell_type":"code","source":"#model.save_weights('./model_weights.h5')","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# new_model = Model(inputs=inputs, outputs=outputs)\n# new_model.load_weights('./model_weights.h5')","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"This loads both the labeled and unlabeled images without any augmentation and in order so I can make predictions on it","metadata":{}},{"cell_type":"code","source":"images_dir = './'\n\ndatagen_test = ImageDataGenerator(\n    #rescale=1./255  # Optionally rescale pixel values\n)\nimage_generator_test = datagen_test.flow_from_directory(\n    directory=images_dir,\n    target_size=(512, 512),  # You can change the size of the image\n    batch_size=BATCH_SIZE,  # You can change the batch size  \n    shuffle=False,  # Keep the order of images\n    color_mode=\"rgb\"\n)\n\nimage_generator_test.class_indices","metadata":{"execution":{"iopub.execute_input":"2024-04-16T04:30:16.384583Z","iopub.status.busy":"2024-04-16T04:30:16.384216Z","iopub.status.idle":"2024-04-16T04:30:16.956415Z","shell.execute_reply":"2024-04-16T04:30:16.955593Z"},"papermill":{"duration":0.800445,"end_time":"2024-04-16T04:30:16.958562","exception":false,"start_time":"2024-04-16T04:30:16.158117","status":"completed"},"tags":[]},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Run the classification model on all the images","metadata":{}},{"cell_type":"code","source":"# Calculate the total number of images in your generator\ntotal_images = len(image_generator_test.filenames)\n\n# Predict on all images from the generator\npredictions = model.predict(image_generator_test, steps=-(-total_images // BATCH_SIZE), verbose=1)\n\n# Convert model predictions to class labels\npredicted_classes = np.argmax(predictions, axis=1)\n\n# Get the true classes for the images\nsplit = image_generator_test.classes","metadata":{"execution":{"iopub.execute_input":"2024-04-16T04:30:17.411168Z","iopub.status.busy":"2024-04-16T04:30:17.410797Z","iopub.status.idle":"2024-04-16T04:31:35.148997Z","shell.execute_reply":"2024-04-16T04:31:35.147916Z"},"papermill":{"duration":78.098517,"end_time":"2024-04-16T04:31:35.285088","exception":false,"start_time":"2024-04-16T04:30:17.186571","status":"completed"},"tags":[]},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Confusion matrix on the labeled images","metadata":{}},{"cell_type":"code","source":"preds_df = pd.DataFrame({\n    'image_names':image_generator_test.filenames,\n    'type':split,\n    'pred':predicted_classes\n})\n\ntrain_preds = preds_df[preds_df['type']==0].copy()\ntrain_preds.loc[:,'truth'] = labels.loc[:,'motor_visible']\n\nconf_matrix = confusion_matrix(train_preds['truth'].tolist(), train_preds['pred'].tolist())\nconf_matrix","metadata":{"execution":{"iopub.execute_input":"2024-04-16T04:31:35.808838Z","iopub.status.busy":"2024-04-16T04:31:35.808484Z","iopub.status.idle":"2024-04-16T04:31:35.823590Z","shell.execute_reply":"2024-04-16T04:31:35.822747Z"},"papermill":{"duration":0.307296,"end_time":"2024-04-16T04:31:35.825431","exception":false,"start_time":"2024-04-16T04:31:35.518135","status":"completed"},"tags":[]},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Secondary Pixel Location\nNext, use the features from the same convolutional neural network to return the pixel location of the motor","metadata":{"papermill":{"duration":0.232172,"end_time":"2024-04-16T04:31:36.290037","exception":false,"start_time":"2024-04-16T04:31:36.057865","status":"completed"},"tags":[]}},{"cell_type":"code","source":"visible_motor_data = labels[labels['motor_visible'] == 1].copy()\nvisible_motor_data.loc[:, 'x_scaled'] = visible_motor_data['x'] / 512 #rescale the locations to use sigmoid activation\nvisible_motor_data.loc[:, 'y_scaled'] = visible_motor_data['y'] / 512\nvisible_motor_data","metadata":{"execution":{"iopub.execute_input":"2024-04-16T04:31:36.760751Z","iopub.status.busy":"2024-04-16T04:31:36.760010Z","iopub.status.idle":"2024-04-16T04:31:36.785284Z","shell.execute_reply":"2024-04-16T04:31:36.784346Z"},"papermill":{"duration":0.262757,"end_time":"2024-04-16T04:31:36.787760","exception":false,"start_time":"2024-04-16T04:31:36.525003","status":"completed"},"tags":[]},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"pixel_datagen = ImageDataGenerator(validation_split=0.25)  # You can add more preprocessing options here\n\npixel_train_generator = pixel_datagen.flow_from_dataframe(\n    dataframe=visible_motor_data,\n    directory=None,  # Since 'image_path' contains absolute paths\n    x_col='image_name',\n    y_col=['x_scaled', 'y_scaled'],\n    target_size=(512, 512),  # Adjust target size as needed\n    batch_size=BATCH_SIZE,\n    class_mode='raw',  # Use 'raw' for regression\n    subset='training',\n    color_mode=\"rgb\"\n)\n\npixel_validation_generator = pixel_datagen.flow_from_dataframe(\n    dataframe=visible_motor_data,\n    directory=None,  # Since 'image_path' contains absolute paths\n    x_col='image_name',\n    y_col=['x_scaled', 'y_scaled'],\n    target_size=(512, 512),  # Adjust target size as needed\n    batch_size=BATCH_SIZE,\n    class_mode='raw',  # Use 'raw' for regression\n    subset='validation',\n    color_mode=\"rgb\"\n)","metadata":{"execution":{"iopub.execute_input":"2024-04-16T04:31:37.262150Z","iopub.status.busy":"2024-04-16T04:31:37.261389Z","iopub.status.idle":"2024-04-16T04:31:37.565192Z","shell.execute_reply":"2024-04-16T04:31:37.563921Z"},"papermill":{"duration":0.544348,"end_time":"2024-04-16T04:31:37.567333","exception":false,"start_time":"2024-04-16T04:31:37.022985","status":"completed"},"tags":[]},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"For this model, the outputs of the pretrained convolutional network are passed into a normal dense network to predict the x and y values of the pixel","metadata":{}},{"cell_type":"code","source":"#tf.keras.backend.clear_session()\n\n# Define input tensor\npixel_inputs = Input(shape=input_shape)\n\n# Load the pre-trained model\npretrained = EfficientNetV2S(weights='imagenet', include_top=False, input_shape=input_shape)\n \n# Freeze the layers\npretrained.trainable = False\n\n# Pass input tensor through pretrained model\npixel_pretrained_output = pretrained(pixel_inputs)\n \n# Flatten the output\npixel_x = GlobalAveragePooling2D()(pixel_pretrained_output)\n\n# Intermediate Dense Layers\npixel_x = Dense(256, activation='relu', kernel_regularizer = l2(0.01))(pixel_x)\npixel_x = Dropout(0.1)(pixel_x)\npixel_x = Dense(128, activation='relu', kernel_regularizer = l2(0.01))(pixel_x)\npixel_x = Dropout(0.1)(pixel_x)\npixel_x = Dense(32, activation='relu', kernel_regularizer = l2(0.01))(pixel_x)\n\n# Output the x and y pixel\npixel_output = Dense(2, activation='sigmoid')(pixel_x)  # Output 2 values for pixel\npixel_model = Model(inputs=pixel_inputs, outputs=pixel_output)\n\npixel_model.summary()","metadata":{"execution":{"iopub.execute_input":"2024-04-16T04:31:38.040616Z","iopub.status.busy":"2024-04-16T04:31:38.039674Z","iopub.status.idle":"2024-04-16T04:31:38.121256Z","shell.execute_reply":"2024-04-16T04:31:38.120372Z"},"papermill":{"duration":0.319775,"end_time":"2024-04-16T04:31:38.123090","exception":false,"start_time":"2024-04-16T04:31:37.803315","status":"completed"},"tags":[]},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"I experimented a lot with different training schedules, over a series of up to 5 phases.  This was the best\n\nI (or ChatGPT) also wrote a custom loss function to calculate the euclidean distance between the predicted pixel and the true pixel, and I had the model minimize that.","metadata":{}},{"cell_type":"code","source":"from tensorflow.keras.callbacks import ModelCheckpoint\nphase1_epochs = 20\nphase1_lr = .001\nphase1_trainable = False\n\nphase2_epochs =  50\nphase2_lr = .0001\nphase2_trainable = True\n\nphase3_epochs = 0\nphase3_lr = .001\nphase3_trainable = False\n\nphase4_epochs = 30\nphase4_lr = .00001\nphase4_trainable = True\n\nphase5_epochs = 0\nphase5_lr = .000001\nphase5_trainable = True\n\ncheckpoint_path = \"./pixel_model_weights.{val_loss:.2f}.h5\"\ncheckpoint_callback = ModelCheckpoint(\n    filepath=checkpoint_path,\n    monitor='val_loss',\n    save_best_only=True,\n    save_weights_only=True,\n    verbose=1\n)\n\ndef euclidean_distance_loss(y_true, y_pred):\n    # Reshape y_true and y_pred if necessary\n    y_true = tf.reshape(y_true * 512, [-1, 2])\n    y_pred = tf.reshape(y_pred * 512, [-1, 2])\n    \n    # Compute Euclidean distance\n    distance = tf.sqrt(tf.reduce_sum(tf.square(y_true - y_pred), axis=1))\n    \n    # Compute mean distance\n    mean_distance = tf.reduce_mean(distance)\n    \n    return mean_distance\n\n\nphase_epochs = [phase1_epochs,phase2_epochs,phase3_epochs,phase4_epochs,phase5_epochs]\n\n# Initialize empty lists to store loss histories\ncombined_loss = []\ncombined_val_loss = []\n\n# Train the model for each phase and store the history\nfor i, (lr, epochs,trainable) in enumerate([(phase1_lr, phase1_epochs, phase1_trainable), \n                                   (phase2_lr, phase2_epochs, phase2_trainable), \n                                   (phase3_lr, phase3_epochs, phase3_trainable), \n                                   (phase4_lr, phase4_epochs, phase5_trainable), \n                                   (phase5_lr, phase5_epochs, phase5_trainable)]):\n    pretrained.trainable = trainable\n    pixel_model.compile(optimizer=Adam(learning_rate=lr), loss=euclidean_distance_loss)\n    if sum(phase_epochs[:i]) > 50: # this stops it from saving checkpoints early on when it's still really bad\n        history = pixel_model.fit(pixel_train_generator, \n                                validation_data=pixel_validation_generator,\n                                initial_epoch=sum(phase_epochs[:i]), \n                                epochs=sum(phase_epochs[:i+1]),\n                                #callbacks=[checkpoint_callback] # uncomment this to save checkpoints as you go\n                                )\n    else:\n        history = pixel_model.fit(pixel_train_generator, \n                                validation_data=pixel_validation_generator,\n                                initial_epoch=sum(phase_epochs[:i]), \n                                epochs=sum(phase_epochs[:i+1]))\n    if epochs != 0:\n        # Append the loss history of the current phase to the combined history\n        combined_loss += history.history['loss']\n        combined_val_loss += history.history['val_loss']\n\n# Plot the combined loss history\nplt.plot(combined_loss, label='Training Loss')\nplt.plot(combined_val_loss, label='Validation Loss')\nplt.xlabel('Epochs')\nplt.ylabel('Loss')\nplt.title('Combined Loss History')\nplt.legend()\nplt.show()\n","metadata":{"execution":{"iopub.execute_input":"2024-04-16T04:31:38.590635Z","iopub.status.busy":"2024-04-16T04:31:38.590281Z","iopub.status.idle":"2024-04-16T06:32:21.394893Z","shell.execute_reply":"2024-04-16T06:32:21.393976Z"},"papermill":{"duration":7243.829233,"end_time":"2024-04-16T06:32:22.184553","exception":false,"start_time":"2024-04-16T04:31:38.355320","status":"completed"},"tags":[]},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"This is another 5 phase approach that worked pretty well, but the above one ended up working better (at least giving better checkpoints)","metadata":{}},{"cell_type":"code","source":"# phase1_epochs = 20\n# phase1_lr = .001\n# phase1_trainable = False\n\n# phase2_epochs =  30\n# phase2_lr = .0001\n# phase2_trainable = True\n\n# phase3_epochs = 50\n# phase3_lr = .001\n# phase3_trainable = False\n\n# phase4_epochs = 50\n# phase4_lr = .00001\n# phase4_trainable = True\n\n# phase5_epochs = 50\n# phase5_lr = .000001\n# phase5_trainable = True\n\n# def euclidean_distance_loss(y_true, y_pred):\n#     # Reshape y_true and y_pred if necessary\n#     y_true = tf.reshape(y_true * 512, [-1, 2])\n#     y_pred = tf.reshape(y_pred * 512, [-1, 2])\n    \n#     # Compute Euclidean distance\n#     distance = tf.sqrt(tf.reduce_sum(tf.square(y_true - y_pred), axis=1))\n    \n#     # Compute mean distance\n#     mean_distance = tf.reduce_mean(distance)\n    \n#     return mean_distance\n\n\n# phase_epochs = [phase1_epochs,phase2_epochs,phase3_epochs,phase4_epochs,phase5_epochs]\n\n# # Initialize empty lists to store loss histories\n# combined_loss = []\n# combined_val_loss = []\n\n# # Train the model for each phase and store the history\n# for i, (lr, epochs,trainable) in enumerate([(phase1_lr, phase1_epochs, phase1_trainable), \n#                                    (phase2_lr, phase2_epochs, phase2_trainable), \n#                                    (phase3_lr, phase3_epochs, phase3_trainable), \n#                                    (phase4_lr, phase4_epochs, phase5_trainable), \n#                                    (phase5_lr, phase5_epochs, phase5_trainable)]):\n#     pretrained.trainable = trainable\n#     pixel_model.compile(optimizer=Adam(learning_rate=lr), loss=euclidean_distance_loss)\n#     history = pixel_model.fit(pixel_train_generator, \n#                               validation_data=pixel_validation_generator,\n#                               initial_epoch=sum(phase_epochs[:i]), \n#                               epochs=sum(phase_epochs[:i+1]),\n#                               callbacks=[checkpoint_callback])\n#     if epochs != 0:\n#         # Append the loss history of the current phase to the combined history\n#         combined_loss += history.history['loss']\n#         combined_val_loss += history.history['val_loss']\n\n# # Plot the combined loss history\n# plt.plot(combined_loss, label='Training Loss')\n# plt.plot(combined_val_loss, label='Validation Loss')\n# plt.xlabel('Epochs')\n# plt.ylabel('Loss')\n# plt.title('Combined Loss History')\n# plt.legend()\n# plt.show()\n","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# pixel_model = Model(inputs=pixel_inputs, outputs=pixel_output)\n# pixel_model.load_weights('.\\pixel_model_weights.12-9.28.h5')","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Make pixel predictions on all images (including ones the classification model said no motor), then change the no motor predictions to (-1,-1)","metadata":{}},{"cell_type":"code","source":"pixel_predictions = pixel_model.predict(image_generator_test, steps=-(-total_images // BATCH_SIZE), verbose=1)\n\nxs = pixel_predictions[:, 0]\nys = pixel_predictions[:, 1]\n\npreds_df['x'] = xs\npreds_df['y'] = ys\n\ntest_preds = preds_df[preds_df['type']==1]\ntest_preds['x'] = test_preds['x'].apply(lambda x:round(x*512))\ntest_preds['y'] = test_preds['y'].apply(lambda x:round(x*512))\ntest_preds.loc[test_preds['pred'] == 0, ['x', 'y']] = -1\n#test_preds","metadata":{"execution":{"iopub.execute_input":"2024-04-16T06:32:23.827116Z","iopub.status.busy":"2024-04-16T06:32:23.826716Z","iopub.status.idle":"2024-04-16T06:33:33.842320Z","shell.execute_reply":"2024-04-16T06:33:33.841432Z"},"papermill":{"duration":71.583175,"end_time":"2024-04-16T06:33:34.619001","exception":false,"start_time":"2024-04-16T06:32:23.035826","status":"completed"},"tags":[]},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"final = pd.DataFrame({\n    'image_name':test_preds['image_names'].apply(lambda x:x[4:]),\n    'x':test_preds['x'],\n    'y':test_preds['y'],\n    'motor_visible':test_preds['pred']\n})\nfinal.to_csv('./submission.csv',index=False)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Some exploration of the results","metadata":{}},{"cell_type":"code","source":"final['motor_visible'].value_counts()","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Define the size of the heatmap grid\nheatmap_range = [[0, 512], [0, 512]]  # Define the range of x and y coordinates\nheatmap_bins = [100, 100]  # Define the number of bins in each dimension\n\n# Create a 2D histogram from the (x, y) coordinates\nheatmap, xedges, yedges = np.histogram2d(labels['x'], labels['y'], bins=heatmap_bins, range=heatmap_range)\n\n# Plot the heatmap\nplt.imshow(heatmap.T, extent=[*heatmap_range[0], *heatmap_range[1]], origin='lower')\nplt.colorbar(label='Counts')  # Add colorbar with label\nplt.xlabel('X')\nplt.ylabel('Y')\nplt.title('Heatmap of Training (X, Y) Coordinates')\nplt.show()","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Define the size of the heatmap grid\nheatmap_range = [[0, 512], [0, 512]]  # Define the range of x and y coordinates\nheatmap_bins = [100, 100]  # Define the number of bins in each dimension\n\n# Create a 2D histogram from the (x, y) coordinates\nheatmap, xedges, yedges = np.histogram2d(final['x'], final['y'], bins=heatmap_bins, range=heatmap_range)\n\n# Plot the heatmap\nplt.imshow(heatmap.T, extent=[*heatmap_range[0], *heatmap_range[1]], origin='lower')\nplt.colorbar(label='Counts')  # Add colorbar with label\nplt.xlabel('X')\nplt.ylabel('Y')\nplt.title('Heatmap of Predicted (X, Y) Coordinates')\nplt.show()","metadata":{},"execution_count":null,"outputs":[]}]}