{"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 pandas as pd\nimport numpy as np\nfrom matplotlib import pyplot as plt\nimport matplotlib.patches as mpatches\nimport cv2\nimport os","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2023-03-22T10:37:22.064284Z","iopub.execute_input":"2023-03-22T10:37:22.065119Z","iopub.status.idle":"2023-03-22T10:37:22.285766Z","shell.execute_reply.started":"2023-03-22T10:37:22.065002Z","shell.execute_reply":"2023-03-22T10:37:22.284808Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# The Challenge","metadata":{}},{"cell_type":"markdown","source":"# Dataset Format","metadata":{}},{"cell_type":"markdown","source":"The training data consists of two folders and one csv file:\n- `dataset/images/train/` contains images of DTP-F devices,\n- `dataset/labels/train/` contains the labels (i.e. which of the 5 checks are satisfied) for each image in `dataset/images/train/`, along with bounding boxes for the checks satisfied in the image (out of scope for this challenge, only provided for data visualisation),\n- `dataset/train.csv` is a file listing for each image and each check whether the check is satisfied (1) or not (0) in the image using the proper file format of this competition.\n\nThe test data, for which we challenge you to make predictions, consists of one folder and one csv file:\n- `dataset/images/test/` contains images of DTP-F devices for which you need to decide the compliance of our 5 checks,\n- `dataset/test.csv` is the file you need to submit, listing for each image and each check whether the check is satisfied (1) or not (0) in the image. The `image_id_and_subtask` column is pre-filled and your task is to fill-in the  `prediction` column.","metadata":{}},{"cell_type":"code","source":"os.listdir(\"/kaggle/input/ada-image-recognition-fiber/\")","metadata":{"execution":{"iopub.status.busy":"2023-03-22T10:37:22.290403Z","iopub.execute_input":"2023-03-22T10:37:22.290727Z","iopub.status.idle":"2023-03-22T10:37:22.299881Z","shell.execute_reply.started":"2023-03-22T10:37:22.290699Z","shell.execute_reply":"2023-03-22T10:37:22.298909Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Example of the satisfied checks and bounding boxes for the image 2323432.jpg, the mapping between the id (first value of each line) and the checks is provided further in this notebook.","metadata":{}},{"cell_type":"code","source":"f = open(\"/kaggle/input/ada-image-recognition-fiber/dataset/labels/train/2323432.txt\")\nlabels_2323432 = [line.rstrip().split(\" \") for line in f]\nlabels_2323432","metadata":{"execution":{"iopub.status.busy":"2023-03-22T10:37:26.611921Z","iopub.execute_input":"2023-03-22T10:37:26.613116Z","iopub.status.idle":"2023-03-22T10:37:26.629911Z","shell.execute_reply.started":"2023-03-22T10:37:26.613070Z","shell.execute_reply":"2023-03-22T10:37:26.628813Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# The DTP-F Images","metadata":{}},{"cell_type":"markdown","source":"We can take a look at one of the images, and see what checks are satisfied in it. We can even look at where in the image these checks are satisfied (this is out of scope for this competition, but can be used to understand the problem).","metadata":{}},{"cell_type":"code","source":"# display the image of the DTP-F 2323432.jpg\nimg = cv2.imread(\"/kaggle/input/ada-image-recognition-fiber/dataset/images/train/2323432.jpg\")\nimg = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\nplt.imshow(img)\nplt.title(\"DTP-F 2323432.jpg\")\nplt.axis('off')\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-03-22T10:37:29.484954Z","iopub.execute_input":"2023-03-22T10:37:29.485387Z","iopub.status.idle":"2023-03-22T10:37:31.116719Z","shell.execute_reply.started":"2023-03-22T10:37:29.485353Z","shell.execute_reply":"2023-03-22T10:37:31.115788Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"We can parse the lines in the labels to transform them into an easy-to-work-with format\n","metadata":{}},{"cell_type":"code","source":"labels_2323432 = [[int(line[0]), (float(line[1]), float(line[2]), float(line[3]), float(line[4]))] for line in labels_2323432]\nlabels_2323432","metadata":{"execution":{"iopub.status.busy":"2023-03-22T10:37:34.482694Z","iopub.execute_input":"2023-03-22T10:37:34.483111Z","iopub.status.idle":"2023-03-22T10:37:34.492264Z","shell.execute_reply.started":"2023-03-22T10:37:34.483078Z","shell.execute_reply":"2023-03-22T10:37:34.491199Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"We now display the bounding boxes for each check satisfied in the image (notice the mapping between check id and its meaning)","metadata":{}},{"cell_type":"code","source":"img = cv2.imread(\"/kaggle/input/ada-image-recognition-fiber/dataset/images/train/2323432.jpg\")\nimg = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\ndh, dw, _ = img.shape\n\nid_to_color = {\n    0:(\"Screw\", (0,255,0)),\n    1:(\"Foam\", (0,255,255)),\n    2:(\"Plastic cover\", (255,0,255)),\n    3:(\"Tie-wrap\", (0,0,255)),\n    4:(\"Rubbers\", (255,0,0)),\n}\n\npresent_categories = set()\nfor category_id, bounding_box in labels_2323432:\n    \n    x, y, w, h = bounding_box\n\n    # Taken from https://stackoverflow.com/questions/64096953/how-to-convert-yolo-format-bounding-box-coordinates-into-opencv-format\n    l = int((x - w / 2) * dw)\n    r = int((x + w / 2) * dw)\n    t = int((y - h / 2) * dh)\n    b = int((y + h / 2) * dh)\n    \n    if l < 0:\n        l = 0\n    if r > dw - 1:\n        r = dw - 1\n    if t < 0:\n        t = 0\n    if b > dh - 1:\n        b = dh - 1\n        \n    cv2.rectangle(img, (l, t), (r, b), id_to_color[category_id][1], 20)\n    present_categories.add(category_id)\n\nlegend_values = []\nfor category_id in present_categories:\n    legend_values.append(mpatches.Patch([color/255 for color in id_to_color[category_id][1]], label=id_to_color[category_id][0], fill=False))\n\nplt.imshow(img)\nplt.title(\"DTP-F 2323432.jpg + bounding boxes\")\nplt.axis(\"off\")\nplt.legend(handles=legend_values, loc=\"lower left\")\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-03-22T10:37:37.946366Z","iopub.execute_input":"2023-03-22T10:37:37.946723Z","iopub.status.idle":"2023-03-22T10:37:39.461005Z","shell.execute_reply.started":"2023-03-22T10:37:37.946694Z","shell.execute_reply":"2023-03-22T10:37:39.460015Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Notice that this DTP-F only contains one tie wrap, the check `two_tie_wraps` is thus the only one not satisfied in this image. We can verify that this is the case using the file `dataset/train.csv` which describes the compliance of each image in the dataset using the specific format for this competition.","metadata":{}},{"cell_type":"code","source":"train_csv = pd.read_csv(\"/kaggle/input/ada-image-recognition-fiber/train.csv\")\ntrain_csv","metadata":{"execution":{"iopub.status.busy":"2023-03-22T10:37:48.277233Z","iopub.execute_input":"2023-03-22T10:37:48.277578Z","iopub.status.idle":"2023-03-22T10:37:48.297525Z","shell.execute_reply.started":"2023-03-22T10:37:48.277548Z","shell.execute_reply":"2023-03-22T10:37:48.296501Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_csv.loc[train_csv[\"image_id_and_subtask\"].str.contains(\"2323432\")]","metadata":{"execution":{"iopub.status.busy":"2023-03-22T10:37:51.317194Z","iopub.execute_input":"2023-03-22T10:37:51.317574Z","iopub.status.idle":"2023-03-22T10:37:51.338064Z","shell.execute_reply.started":"2023-03-22T10:37:51.317543Z","shell.execute_reply":"2023-03-22T10:37:51.336972Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Let's Get Coding!","metadata":{}},{"cell_type":"markdown","source":"# Training an Image Classifier","metadata":{}},{"cell_type":"markdown","source":"Let us now train a simple binary classifier for the `two_screws` check and use its result to build a sample submission. We start with an empty dataframe to contain the file name of our images and whether the `two_screws` check is satisfied in them.\n","metadata":{}},{"cell_type":"code","source":"two_screws_data = pd.DataFrame({\"image\" : [], \"two_screws\" : []})\ntwo_screws_data","metadata":{"execution":{"iopub.status.busy":"2023-03-22T10:37:54.434132Z","iopub.execute_input":"2023-03-22T10:37:54.434486Z","iopub.status.idle":"2023-03-22T10:37:54.445177Z","shell.execute_reply.started":"2023-03-22T10:37:54.434457Z","shell.execute_reply":"2023-03-22T10:37:54.443930Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"We can extract the file names used in the training data from the `dataset/train.csv` file, by only keeping the first part of the text in the first column for each `two_screws` check.","metadata":{}},{"cell_type":"code","source":"def extract_name(a):\n    return a.split(\"_\")[0] + \".jpg\"\n\ntrain_csv_two_screws = train_csv.loc[train_csv[\"image_id_and_subtask\"].str.contains(\"two_screws\")]\ntwo_screws_data[\"image\"] = train_csv_two_screws[\"image_id_and_subtask\"].apply(extract_name)\ntwo_screws_data[\"image\"] = two_screws_data[\"image\"].astype(\"string\")\ntwo_screws_data","metadata":{"execution":{"iopub.status.busy":"2023-03-22T10:37:57.548620Z","iopub.execute_input":"2023-03-22T10:37:57.549381Z","iopub.status.idle":"2023-03-22T10:37:57.572170Z","shell.execute_reply.started":"2023-03-22T10:37:57.549346Z","shell.execute_reply":"2023-03-22T10:37:57.570963Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"We now need to add the correct prediction for the `two_screws` check for each image in the training data.","metadata":{}},{"cell_type":"code","source":"two_screws_data[\"two_screws\"] = train_csv_two_screws[\"prediction\"]\ntwo_screws_data[\"two_screws\"] = two_screws_data[\"two_screws\"].astype(\"string\")\ntwo_screws_data","metadata":{"execution":{"iopub.status.busy":"2023-03-22T10:37:59.757231Z","iopub.execute_input":"2023-03-22T10:37:59.757594Z","iopub.status.idle":"2023-03-22T10:37:59.773625Z","shell.execute_reply.started":"2023-03-22T10:37:59.757564Z","shell.execute_reply":"2023-03-22T10:37:59.772422Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Let us select some examples of compliant and non-compliant DTP-F for the `two_screws` check, i.e. some images where two screws are visible and some where they are not.","metadata":{}},{"cell_type":"code","source":"compliant = two_screws_data.loc[two_screws_data[\"two_screws\"] == \"1\"].sample(6)[\"image\"].values\nnon_compliant = two_screws_data.loc[two_screws_data[\"two_screws\"] == \"0\"].sample(6)[\"image\"].values","metadata":{"execution":{"iopub.status.busy":"2023-03-22T10:38:05.488702Z","iopub.execute_input":"2023-03-22T10:38:05.489171Z","iopub.status.idle":"2023-03-22T10:38:05.500115Z","shell.execute_reply.started":"2023-03-22T10:38:05.489136Z","shell.execute_reply":"2023-03-22T10:38:05.499030Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"images = [cv2.imread(\"/kaggle/input/ada-image-recognition-fiber/dataset/images/train/\" + image) for image in compliant]\nimages = [cv2.cvtColor(image, cv2.COLOR_BGR2RGB) for image in images]\n\nfig, axs = plt.subplots(nrows=2, ncols=3, figsize=(20, 12))\n\nfor i, ax in enumerate(axs.flatten()):\n    if i < len(images):\n        ax.imshow(images[i])\n        ax.axis('off')\n    else:\n        ax.axis('off')\n\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-03-22T10:38:07.807679Z","iopub.execute_input":"2023-03-22T10:38:07.808048Z","iopub.status.idle":"2023-03-22T10:38:18.355910Z","shell.execute_reply.started":"2023-03-22T10:38:07.808018Z","shell.execute_reply":"2023-03-22T10:38:18.355025Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"images = [cv2.imread(\"/kaggle/input/ada-image-recognition-fiber/dataset/images/train/\" + image) for image in non_compliant]\nimages = [cv2.cvtColor(image, cv2.COLOR_BGR2RGB) for image in images]\n\nfig, axs = plt.subplots(nrows=2, ncols=3, figsize=(20, 12))\n\nfor i, ax in enumerate(axs.flatten()):\n    if i < len(images):\n        ax.imshow(images[i])\n        ax.axis('off')\n    else:\n        ax.axis('off')\n\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-02-20T16:28:10.633009Z","iopub.execute_input":"2023-02-20T16:28:10.633914Z","iopub.status.idle":"2023-02-20T16:28:20.846681Z","shell.execute_reply.started":"2023-02-20T16:28:10.633876Z","shell.execute_reply":"2023-02-20T16:28:20.845335Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"We can now use this `two_screws_data` dataframe to train a simple classifier. We start by importing the required libraries and seting up some metadata.","metadata":{}},{"cell_type":"code","source":"import tensorflow as tf\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\nfrom tensorflow.keras.models import Sequential\nfrom tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense\n\n# define the path to the directory containing the images\npath_to_images = \"/kaggle/input/ada-image-recognition-fiber/dataset/images/train/\"\n\n# define the size of the images and the batch size\nimg_size = (224, 224)\nbatch_size = 32","metadata":{"execution":{"iopub.status.busy":"2023-03-22T10:38:18.357522Z","iopub.execute_input":"2023-03-22T10:38:18.358443Z","iopub.status.idle":"2023-03-22T10:38:25.670359Z","shell.execute_reply.started":"2023-03-22T10:38:18.358408Z","shell.execute_reply":"2023-03-22T10:38:25.669327Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"We can now setup the image generator from our data. We set one up for training and one for validation in order to see the performance of our model during training.","metadata":{}},{"cell_type":"code","source":"# ceate an image data generator to load the images and perform data augmentation\ndatagen = ImageDataGenerator(rescale=1./255, validation_split=0.2)\n\n# load the training and validation data from the dataframe using the image data generator\ntrain_data = datagen.flow_from_dataframe(two_screws_data, directory=path_to_images, x_col=\"image\", y_col=\"two_screws\",\n                                          target_size=img_size, batch_size=batch_size, class_mode=\"binary\", subset=\"training\")\nval_data = datagen.flow_from_dataframe(two_screws_data, directory=path_to_images, x_col=\"image\", y_col=\"two_screws\",\n                                        target_size=img_size, batch_size=batch_size, class_mode=\"binary\", subset=\"validation\")","metadata":{"execution":{"iopub.status.busy":"2023-03-22T10:38:25.672215Z","iopub.execute_input":"2023-03-22T10:38:25.672808Z","iopub.status.idle":"2023-03-22T10:38:27.653962Z","shell.execute_reply.started":"2023-03-22T10:38:25.672753Z","shell.execute_reply":"2023-03-22T10:38:27.652794Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"We now define a Convolutional Neural Network (CNN) architecture which corresponds to our model. This simple architecture is used for demonstration purposes, and participants are encouraged to explore different architectures, techniques, and models for this challenge.","metadata":{}},{"cell_type":"code","source":"model = Sequential()\nmodel.add(Conv2D(32, (3, 3), activation='relu', input_shape=(img_size[0], img_size[1], 3)))\nmodel.add(MaxPooling2D((2, 2)))\nmodel.add(Conv2D(64, (3, 3), activation='relu'))\nmodel.add(MaxPooling2D((2, 2)))\nmodel.add(Conv2D(128, (3, 3), activation='relu'))\nmodel.add(MaxPooling2D((2, 2)))\nmodel.add(Flatten())\nmodel.add(Dense(128, activation='relu'))\nmodel.add(Dense(1, activation='sigmoid'))\nmodel.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])","metadata":{"execution":{"iopub.status.busy":"2023-03-22T10:38:27.656025Z","iopub.execute_input":"2023-03-22T10:38:27.656668Z","iopub.status.idle":"2023-03-22T10:38:31.246980Z","shell.execute_reply.started":"2023-03-22T10:38:27.656630Z","shell.execute_reply":"2023-03-22T10:38:31.246023Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"We are now ready to train our model, and visualize its performance during training.","metadata":{}},{"cell_type":"code","source":"history = model.fit(train_data, epochs=10, validation_data=val_data)\n\n# plot the training and validation accuracy\nplt.plot(history.history['accuracy'])\nplt.plot(history.history['val_accuracy'])\nplt.title('Model accuracy')\nplt.ylabel('Accuracy')\nplt.xlabel('Epoch')\nplt.legend(['Train', 'Validation'], loc='upper left')\nplt.show()\n\n# plot the training and validation loss\nplt.plot(history.history['loss'])\nplt.plot(history.history['val_loss'])\nplt.title('Model loss')\nplt.ylabel('Loss')\nplt.xlabel('Epoch')\nplt.legend(['Train', 'Validation'], loc='upper left')\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-03-22T10:38:31.249004Z","iopub.execute_input":"2023-03-22T10:38:31.249354Z","iopub.status.idle":"2023-03-22T11:10:39.207397Z","shell.execute_reply.started":"2023-03-22T10:38:31.249310Z","shell.execute_reply":"2023-03-22T11:10:39.206414Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Creating a Submission with our Predictions","metadata":{}},{"cell_type":"markdown","source":"We can now use our model to perform inference on the test data. We create a dataframe`two_screws_data_test` similarly as before to contain our predictions.","metadata":{}},{"cell_type":"code","source":"test_csv = pd.read_csv(\"/kaggle/input/ada-image-recognition-fiber/test.csv\")\ntest_csv_two_screws = test_csv.loc[test_csv[\"image_id_and_subtask\"].str.contains(\"two_screws\")]\ntwo_screws_data_test = pd.DataFrame({\"image\" : [], \"two_screws\" : []})\ntwo_screws_data_test[\"image\"] = test_csv_two_screws[\"image_id_and_subtask\"].apply(extract_name)\ntwo_screws_data_test[\"image\"] = two_screws_data_test[\"image\"].astype(\"string\")\n\n# create an image data generator to load the images\ntest_datagen = ImageDataGenerator(rescale=1./255)\n\npath_to_test_images = \"/kaggle/input/ada-image-recognition-fiber/dataset/images/test/\"\n\n# load the test data from the dataframe using the image data generator\ntest_data = test_datagen.flow_from_dataframe(two_screws_data_test, directory=path_to_test_images, x_col=\"image\",\n                                             target_size=img_size, batch_size=batch_size, class_mode=None, shuffle=False)\n\n# make predictions on the test data using the trained model\npredictions = model.predict(test_data)\n\n# convert the predictions to binary class labels (0 or 1)\nclass_labels = np.round(predictions)","metadata":{"execution":{"iopub.status.busy":"2023-03-22T11:10:39.209476Z","iopub.execute_input":"2023-03-22T11:10:39.210086Z","iopub.status.idle":"2023-03-22T11:11:37.801208Z","shell.execute_reply.started":"2023-03-22T11:10:39.210048Z","shell.execute_reply":"2023-03-22T11:11:37.800046Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Load `dataset/test.csv` and initialize every check with 0. ","metadata":{}},{"cell_type":"code","source":"test_csv = pd.read_csv(\"/kaggle/input/ada-image-recognition-fiber/test.csv\")\ntest_csv[\"prediction\"] = 0\ntest_csv","metadata":{"execution":{"iopub.status.busy":"2023-03-22T11:11:37.803731Z","iopub.execute_input":"2023-03-22T11:11:37.804832Z","iopub.status.idle":"2023-03-22T11:11:37.822374Z","shell.execute_reply.started":"2023-03-22T11:11:37.804790Z","shell.execute_reply":"2023-03-22T11:11:37.821354Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"We can now add our predictions to `dataset/test.csv` in order to make a submission. ","metadata":{}},{"cell_type":"code","source":"predictions = [str(int(class_labels[i][0])) for i in range(len(class_labels))]","metadata":{"execution":{"iopub.status.busy":"2023-03-22T11:30:21.420076Z","iopub.execute_input":"2023-03-22T11:30:21.420459Z","iopub.status.idle":"2023-03-22T11:30:21.425765Z","shell.execute_reply.started":"2023-03-22T11:30:21.420409Z","shell.execute_reply":"2023-03-22T11:30:21.424474Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_csv.loc[test_csv[\"image_id_and_subtask\"].str.contains(\"two_screws\"), [\"prediction\"]] = predictions","metadata":{"execution":{"iopub.status.busy":"2023-03-22T11:30:38.059455Z","iopub.execute_input":"2023-03-22T11:30:38.059899Z","iopub.status.idle":"2023-03-22T11:30:38.069784Z","shell.execute_reply.started":"2023-03-22T11:30:38.059862Z","shell.execute_reply":"2023-03-22T11:30:38.068287Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_csv","metadata":{"execution":{"iopub.status.busy":"2023-03-22T11:30:38.367249Z","iopub.execute_input":"2023-03-22T11:30:38.368095Z","iopub.status.idle":"2023-03-22T11:30:38.382548Z","shell.execute_reply.started":"2023-03-22T11:30:38.368049Z","shell.execute_reply":"2023-03-22T11:30:38.381295Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"We can now save the `test_csv` file as a submission, not forgetting to remove the index from the dataframe when saving. We can now submit `test_submission.csv` to the competition! ","metadata":{}},{"cell_type":"code","source":"test_csv.to_csv(\"test_submission.csv\",index=False)","metadata":{"execution":{"iopub.status.busy":"2023-03-22T11:30:43.429824Z","iopub.execute_input":"2023-03-22T11:30:43.430183Z","iopub.status.idle":"2023-03-22T11:30:43.441733Z","shell.execute_reply.started":"2023-03-22T11:30:43.430152Z","shell.execute_reply":"2023-03-22T11:30:43.440782Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}