diff --git "a/task4.ipynb" "b/task4.ipynb" new file mode 100644--- /dev/null +++ "b/task4.ipynb" @@ -0,0 +1,5625 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "3e4123d5-321d-434e-bef8-4de3983eb897", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Requirement already satisfied: opencv-python in c:\\users\\gaurav lodhi\\anaconda3\\lib\\site-packages (4.10.0.84)\n", + "Requirement already satisfied: scikit-learn in c:\\users\\gaurav lodhi\\anaconda3\\lib\\site-packages (1.4.2)\n", + "Requirement already satisfied: pyyaml in c:\\users\\gaurav lodhi\\anaconda3\\lib\\site-packages (6.0.1)\n", + "Requirement already satisfied: ultralytics in c:\\users\\gaurav lodhi\\anaconda3\\lib\\site-packages (8.3.12)\n", + "Requirement already satisfied: tqdm in c:\\users\\gaurav lodhi\\anaconda3\\lib\\site-packages (4.66.4)\n", + "Requirement already satisfied: numpy>=1.21.2 in c:\\users\\gaurav lodhi\\anaconda3\\lib\\site-packages (from opencv-python) (1.26.4)\n", + "Requirement already satisfied: scipy>=1.6.0 in c:\\users\\gaurav lodhi\\anaconda3\\lib\\site-packages (from scikit-learn) (1.13.1)\n", + "Requirement already satisfied: joblib>=1.2.0 in c:\\users\\gaurav lodhi\\anaconda3\\lib\\site-packages (from scikit-learn) (1.4.2)\n", + "Requirement already satisfied: threadpoolctl>=2.0.0 in c:\\users\\gaurav lodhi\\anaconda3\\lib\\site-packages (from scikit-learn) (2.2.0)\n", + "Requirement already satisfied: matplotlib>=3.3.0 in c:\\users\\gaurav lodhi\\anaconda3\\lib\\site-packages (from ultralytics) (3.8.4)\n", + "Requirement already satisfied: pillow>=7.1.2 in c:\\users\\gaurav lodhi\\anaconda3\\lib\\site-packages (from ultralytics) (10.3.0)\n", + "Requirement already satisfied: requests>=2.23.0 in c:\\users\\gaurav lodhi\\anaconda3\\lib\\site-packages (from ultralytics) (2.32.2)\n", + "Requirement already satisfied: torch>=1.8.0 in c:\\users\\gaurav lodhi\\anaconda3\\lib\\site-packages (from ultralytics) (2.4.1)\n", + "Requirement already satisfied: torchvision>=0.9.0 in c:\\users\\gaurav lodhi\\anaconda3\\lib\\site-packages (from ultralytics) (0.19.1)\n", + "Requirement already satisfied: psutil in c:\\users\\gaurav lodhi\\appdata\\roaming\\python\\python312\\site-packages (from ultralytics) (6.0.0)\n", + "Requirement already satisfied: py-cpuinfo in c:\\users\\gaurav lodhi\\anaconda3\\lib\\site-packages (from ultralytics) (9.0.0)\n", + "Requirement already satisfied: pandas>=1.1.4 in c:\\users\\gaurav lodhi\\anaconda3\\lib\\site-packages (from ultralytics) (2.2.2)\n", + "Requirement already satisfied: seaborn>=0.11.0 in c:\\users\\gaurav lodhi\\anaconda3\\lib\\site-packages (from ultralytics) (0.13.2)\n", + "Requirement already satisfied: ultralytics-thop>=2.0.0 in c:\\users\\gaurav lodhi\\anaconda3\\lib\\site-packages (from ultralytics) (2.0.9)\n", + "Requirement already satisfied: colorama in c:\\users\\gaurav lodhi\\anaconda3\\lib\\site-packages (from tqdm) (0.4.6)\n", + "Requirement already satisfied: contourpy>=1.0.1 in c:\\users\\gaurav lodhi\\anaconda3\\lib\\site-packages (from matplotlib>=3.3.0->ultralytics) (1.2.0)\n", + "Requirement already satisfied: cycler>=0.10 in c:\\users\\gaurav lodhi\\anaconda3\\lib\\site-packages (from matplotlib>=3.3.0->ultralytics) (0.11.0)\n", + "Requirement already satisfied: fonttools>=4.22.0 in c:\\users\\gaurav lodhi\\anaconda3\\lib\\site-packages (from matplotlib>=3.3.0->ultralytics) (4.51.0)\n", + "Requirement already satisfied: kiwisolver>=1.3.1 in c:\\users\\gaurav lodhi\\anaconda3\\lib\\site-packages (from matplotlib>=3.3.0->ultralytics) (1.4.4)\n", + "Requirement already satisfied: packaging>=20.0 in c:\\users\\gaurav lodhi\\anaconda3\\lib\\site-packages (from matplotlib>=3.3.0->ultralytics) (23.2)\n", + "Requirement already satisfied: pyparsing>=2.3.1 in c:\\users\\gaurav lodhi\\anaconda3\\lib\\site-packages (from matplotlib>=3.3.0->ultralytics) (3.0.9)\n", + "Requirement already satisfied: python-dateutil>=2.7 in c:\\users\\gaurav lodhi\\anaconda3\\lib\\site-packages (from matplotlib>=3.3.0->ultralytics) (2.9.0.post0)\n", + "Requirement already satisfied: pytz>=2020.1 in c:\\users\\gaurav lodhi\\anaconda3\\lib\\site-packages (from pandas>=1.1.4->ultralytics) (2024.1)\n", + "Requirement already satisfied: tzdata>=2022.7 in c:\\users\\gaurav lodhi\\anaconda3\\lib\\site-packages (from pandas>=1.1.4->ultralytics) (2023.3)\n", + "Requirement already satisfied: charset-normalizer<4,>=2 in c:\\users\\gaurav lodhi\\anaconda3\\lib\\site-packages (from requests>=2.23.0->ultralytics) (2.0.4)\n", + "Requirement already satisfied: idna<4,>=2.5 in c:\\users\\gaurav lodhi\\anaconda3\\lib\\site-packages (from requests>=2.23.0->ultralytics) (3.7)\n", + "Requirement already satisfied: urllib3<3,>=1.21.1 in c:\\users\\gaurav lodhi\\anaconda3\\lib\\site-packages (from requests>=2.23.0->ultralytics) (2.2.2)\n", + "Requirement already satisfied: certifi>=2017.4.17 in c:\\users\\gaurav lodhi\\anaconda3\\lib\\site-packages (from requests>=2.23.0->ultralytics) (2024.8.30)\n", + "Requirement already satisfied: filelock in c:\\users\\gaurav lodhi\\anaconda3\\lib\\site-packages (from torch>=1.8.0->ultralytics) (3.13.1)\n", + "Requirement already satisfied: typing-extensions>=4.8.0 in c:\\users\\gaurav lodhi\\anaconda3\\lib\\site-packages (from torch>=1.8.0->ultralytics) (4.11.0)\n", + "Requirement already satisfied: sympy in c:\\users\\gaurav lodhi\\anaconda3\\lib\\site-packages (from torch>=1.8.0->ultralytics) (1.12)\n", + "Requirement already satisfied: networkx in c:\\users\\gaurav lodhi\\anaconda3\\lib\\site-packages (from torch>=1.8.0->ultralytics) (3.2.1)\n", + "Requirement already satisfied: jinja2 in c:\\users\\gaurav lodhi\\anaconda3\\lib\\site-packages (from torch>=1.8.0->ultralytics) (3.1.4)\n", + "Requirement already satisfied: fsspec in c:\\users\\gaurav lodhi\\anaconda3\\lib\\site-packages (from torch>=1.8.0->ultralytics) (2024.3.1)\n", + "Requirement already satisfied: setuptools in c:\\users\\gaurav lodhi\\anaconda3\\lib\\site-packages (from torch>=1.8.0->ultralytics) (69.5.1)\n", + "Requirement already satisfied: six>=1.5 in c:\\users\\gaurav lodhi\\anaconda3\\lib\\site-packages (from python-dateutil>=2.7->matplotlib>=3.3.0->ultralytics) (1.16.0)\n", + "Requirement already satisfied: MarkupSafe>=2.0 in c:\\users\\gaurav lodhi\\anaconda3\\lib\\site-packages (from jinja2->torch>=1.8.0->ultralytics) (2.1.3)\n", + "Requirement already satisfied: mpmath>=0.19 in c:\\users\\gaurav lodhi\\anaconda3\\lib\\site-packages (from sympy->torch>=1.8.0->ultralytics) (1.3.0)\n" + ] + } + ], + "source": [ + "!pip install opencv-python scikit-learn pyyaml ultralytics tqdm" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e1425e96-d454-499f-9525-04cd498109a1", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Copying and Annotating all images: 10%|█ | 4452/44287 [00:46<16:43, 39.71it/s] " + ] + } + ], + "source": [ + "import os\n", + "import cv2\n", + "import shutil\n", + "from tqdm import tqdm\n", + "from sklearn.model_selection import train_test_split\n", + "\n", + "# Define dataset paths\n", + "base_dir = 'C:/Users/Gaurav Lodhi/Downloads/Winners/datasetss'\n", + "train_dir = 'dataset/images/train/'\n", + "val_dir = 'dataset/images/val/'\n", + "test_dir = 'dataset/images/test/'\n", + "train_labels_dir = 'dataset/labels/train/'\n", + "val_labels_dir = 'dataset/labels/val/'\n", + "test_labels_dir = 'dataset/labels/test/'\n", + "\n", + "# Create directories for images and labels\n", + "os.makedirs(train_dir, exist_ok=True)\n", + "os.makedirs(val_dir, exist_ok=True)\n", + "os.makedirs(test_dir, exist_ok=True)\n", + "os.makedirs(train_labels_dir, exist_ok=True)\n", + "os.makedirs(val_labels_dir, exist_ok=True)\n", + "os.makedirs(test_labels_dir, exist_ok=True)\n", + "\n", + "# Splitting ratio\n", + "train_ratio = 0.7\n", + "val_ratio = 0.2\n", + "test_ratio = 0.1\n", + "\n", + "# Class names\n", + "class_names = [\n", + " 'Vegetable_Fresh_zucchini', 'Vegetable_Fresh_Okra', 'Vegetable_Fresh_Cuccumber',\n", + " 'Vegetable_Fresh_Chilli', 'stale_tomato', 'stale_watermelon', 'Stale_Strawberry',\n", + " 'Stale_Spanich', 'stale_potato', 'stale_pomogrante', 'stale_orange', 'stale_onion',\n", + " 'stale_okra', 'stale_mango', 'Stale_Lulo', 'stale_lemon', 'stale_chilli',\n", + " 'stale_capsicum', 'stale_beetroot', 'stale_bitter_ground', 'stale_avacado',\n", + " 'stalecucumber', 'Stalepear', 'staleapple', 'Fruit_Fresh_Banana', 'pearfresh',\n", + " 'Fresh_Watermelon', 'Fruit_Fresh_Avacado', 'fresh_tomato', 'Fresh_Tamarillo',\n", + " 'Fresh_Strawberry', 'fresh_Spanich', 'fresh_potato', 'fresh_pomegrante',\n", + " 'fresh_orange', 'fresh_onion', 'fresh_lulo', 'fresh_lemon', 'fresh_eggplant',\n", + " 'fresh_cauliflower', 'fresh_capsicum', 'fresh_carrot', 'fresh_bitter_gourd',\n", + " 'Fresh_cabbage', 'fresh_beetroot', 'freshapple'\n", + "]\n", + "\n", + "# Map each class name to a numeric label\n", + "class_map = {name: idx for idx, name in enumerate(class_names)}\n", + "\n", + "# Count total number of images for the progress bar\n", + "total_images = 0\n", + "folders = [folder for folder in os.listdir(base_dir) if os.path.isdir(os.path.join(base_dir, folder))]\n", + "\n", + "for folder in folders:\n", + " folder_path = os.path.join(base_dir, folder)\n", + " total_images += len([img for img in os.listdir(folder_path) if img.endswith(('.jpg', '.jpeg', '.png'))])\n", + "\n", + "# Function to annotate images and move them to the correct folder\n", + "def annotate_and_move_images(images, folder_path, dest_dir, labels_dir, class_id, folder_name_index):\n", + " for img in images:\n", + " image_path = os.path.join(folder_path, img)\n", + " \n", + " # Rename the image to include the folder index\n", + " dest_image_name = f\"{folder_name_index}_{img}\" # Include folder index in the image name\n", + " dest_image_path = os.path.join(dest_dir, dest_image_name)\n", + " shutil.copy(image_path, dest_image_path)\n", + "\n", + " # Load the image to get dimensions\n", + " img_data = cv2.imread(image_path)\n", + " if img_data is None:\n", + " print(f\"Warning: Couldn't read image {img}\")\n", + " continue\n", + "\n", + " height, width, _ = img_data.shape\n", + "\n", + " # Create YOLO format annotation (whole image)\n", + " x_center = 0.5\n", + " y_center = 0.5\n", + " obj_width = 1.0\n", + " obj_height = 1.0\n", + " annotation = f\"{class_id} {x_center} {y_center} {obj_width} {obj_height}\\n\"\n", + "\n", + " # Save the annotation with the updated name\n", + " annotation_name = dest_image_name.replace('.jpg', '.txt').replace('.jpeg', '.txt').replace('.png', '.txt')\n", + " annotation_path = os.path.join(labels_dir, annotation_name)\n", + " with open(annotation_path, 'w') as f:\n", + " f.write(annotation)\n", + "\n", + "# Iterate over each folder (class) with a progress bar for overall progress\n", + "with tqdm(total=total_images, desc=\"Copying and Annotating all images\") as pbar:\n", + " for folder_index, folder in enumerate(folders):\n", + " folder_path = os.path.join(base_dir, folder)\n", + "\n", + " images = [img for img in os.listdir(folder_path) if img.endswith(('.jpg', '.jpeg', '.png'))]\n", + " if len(images) == 0:\n", + " continue\n", + "\n", + " train_imgs, temp_imgs = train_test_split(images, test_size=(1 - train_ratio), random_state=42)\n", + " val_imgs, test_imgs = train_test_split(temp_imgs, test_size=test_ratio / (test_ratio + val_ratio), random_state=42)\n", + "\n", + " # Get the class ID from the folder name using the class map\n", + " class_id = class_map.get(folder)\n", + " if class_id is None:\n", + " print(f\"Error: Class not found for folder {folder}\")\n", + " continue\n", + "\n", + " # Annotate and move images for train, val, and test sets\n", + " annotate_and_move_images(train_imgs, folder_path, train_dir, train_labels_dir, class_id, folder_index)\n", + " annotate_and_move_images(val_imgs, folder_path, val_dir, val_labels_dir, class_id, folder_index)\n", + " annotate_and_move_images(test_imgs, folder_path, test_dir, test_labels_dir, class_id, folder_index)\n", + "\n", + " pbar.update(len(images))\n", + "\n", + "print(\"Data split and annotation process completed.\")" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "a7f22d7c-4494-479d-9371-73560bb3c733", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "New https://pypi.org/project/ultralytics/8.3.13 available Update with 'pip install -U ultralytics'\n", + "Ultralytics 8.3.12 Python-3.12.4 torch-2.4.1+cpu CPU (11th Gen Intel Core(TM) i5-1135G7 2.40GHz)\n", + "\u001b[34m\u001b[1mengine\\trainer: \u001b[0mtask=detect, mode=train, model=yolov8n.pt, data=C:/Users/Gaurav Lodhi/Downloads/Winners/GRID_test1/dataset/data.yaml, epochs=10, time=None, patience=100, batch=32, imgsz=640, save=True, save_period=-1, cache=False, device=None, workers=8, project=None, name=train12, exist_ok=False, pretrained=True, optimizer=auto, verbose=True, seed=0, deterministic=True, single_cls=False, rect=False, cos_lr=False, close_mosaic=10, resume=False, amp=True, fraction=1.0, profile=False, freeze=None, multi_scale=False, overlap_mask=True, mask_ratio=4, dropout=0.0, val=True, split=val, save_json=False, save_hybrid=False, conf=None, iou=0.7, max_det=300, half=False, dnn=False, plots=True, source=None, vid_stride=1, stream_buffer=False, visualize=False, augment=False, agnostic_nms=False, classes=None, retina_masks=False, embed=None, show=False, save_frames=False, save_txt=False, save_conf=False, save_crop=False, show_labels=True, show_conf=True, show_boxes=True, line_width=None, format=torchscript, keras=False, optimize=False, int8=False, dynamic=False, simplify=True, opset=None, workspace=4, nms=False, lr0=0.01, lrf=0.01, momentum=0.937, weight_decay=0.0005, warmup_epochs=3.0, warmup_momentum=0.8, warmup_bias_lr=0.1, box=7.5, cls=0.5, dfl=1.5, pose=12.0, kobj=1.0, label_smoothing=0.0, nbs=64, hsv_h=0.015, hsv_s=0.7, hsv_v=0.4, degrees=0.0, translate=0.1, scale=0.5, shear=0.0, perspective=0.0, flipud=0.0, fliplr=0.5, bgr=0.0, mosaic=1.0, mixup=0.0, copy_paste=0.0, copy_paste_mode=flip, auto_augment=randaugment, erasing=0.4, crop_fraction=1.0, cfg=None, tracker=botsort.yaml, save_dir=runs\\detect\\train12\n", + "Overriding model.yaml nc=80 with nc=46\n", + "\n", + " from n params module arguments \n", + " 0 -1 1 464 ultralytics.nn.modules.conv.Conv [3, 16, 3, 2] \n", + " 1 -1 1 4672 ultralytics.nn.modules.conv.Conv [16, 32, 3, 2] \n", + " 2 -1 1 7360 ultralytics.nn.modules.block.C2f [32, 32, 1, True] \n", + " 3 -1 1 18560 ultralytics.nn.modules.conv.Conv [32, 64, 3, 2] \n", + " 4 -1 2 49664 ultralytics.nn.modules.block.C2f [64, 64, 2, True] \n", + " 5 -1 1 73984 ultralytics.nn.modules.conv.Conv [64, 128, 3, 2] \n", + " 6 -1 2 197632 ultralytics.nn.modules.block.C2f [128, 128, 2, True] \n", + " 7 -1 1 295424 ultralytics.nn.modules.conv.Conv [128, 256, 3, 2] \n", + " 8 -1 1 460288 ultralytics.nn.modules.block.C2f [256, 256, 1, True] \n", + " 9 -1 1 164608 ultralytics.nn.modules.block.SPPF [256, 256, 5] \n", + " 10 -1 1 0 torch.nn.modules.upsampling.Upsample [None, 2, 'nearest'] \n", + " 11 [-1, 6] 1 0 ultralytics.nn.modules.conv.Concat [1] \n", + " 12 -1 1 148224 ultralytics.nn.modules.block.C2f [384, 128, 1] \n", + " 13 -1 1 0 torch.nn.modules.upsampling.Upsample [None, 2, 'nearest'] \n", + " 14 [-1, 4] 1 0 ultralytics.nn.modules.conv.Concat [1] \n", + " 15 -1 1 37248 ultralytics.nn.modules.block.C2f [192, 64, 1] \n", + " 16 -1 1 36992 ultralytics.nn.modules.conv.Conv [64, 64, 3, 2] \n", + " 17 [-1, 12] 1 0 ultralytics.nn.modules.conv.Concat [1] \n", + " 18 -1 1 123648 ultralytics.nn.modules.block.C2f [192, 128, 1] \n", + " 19 -1 1 147712 ultralytics.nn.modules.conv.Conv [128, 128, 3, 2] \n", + " 20 [-1, 9] 1 0 ultralytics.nn.modules.conv.Concat [1] \n", + " 21 -1 1 493056 ultralytics.nn.modules.block.C2f [384, 256, 1] \n", + " 22 [15, 18, 21] 1 439642 ultralytics.nn.modules.head.Detect [46, [64, 128, 256]] \n", + "Model summary: 249 layers, 2,699,178 parameters, 2,699,162 gradients, 7.0 GFLOPs\n", + "\n", + "Transferred 313/391 items from pretrained weights\n", + "\u001b[34m\u001b[1mTensorBoard: \u001b[0mStart with 'tensorboard --logdir runs\\detect\\train12', view at http://localhost:6006/\n", + "Freezing layer 'model.22.dfl.conv.weight'\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[34m\u001b[1mtrain: \u001b[0mScanning C:\\Users\\Gaurav Lodhi\\Downloads\\Winners\\GRID_test1\\dataset\\labels\\train.cache... 58175 images, 5978 backgrounds, 3875 corrupt: 100%|██████████| 64153/64153 [00:00here for more info. \n", + "\u001b[1;31mView Jupyter log for further details." + ] + } + ], + "source": [ + "from ultralytics import YOLO\n", + "import os\n", + "\n", + "# Define dataset config for YOLOv8\n", + "data_yaml = \"\"\"\n", + "train: C:/Users/Gaurav Lodhi/Downloads/Winners/GRID_test1/dataset/images/train\n", + "val: C:/Users/Gaurav Lodhi/Downloads/Winners/GRID_test1/dataset/images/val\n", + "test: C:/Users/Gaurav Lodhi/Downloads/Winners/GRID_test1/dataset/images/test\n", + "\n", + "nc: 46 # Number of classes\n", + "names: [\n", + " 'Vegetable_Fresh_zucchini',\n", + " 'Vegetable_Fresh_Okra',\n", + " 'Vegetable_Fresh_Cuccumber',\n", + " 'Vegetable_Fresh_Chilli',\n", + " 'stale_tomato',\n", + " 'stale_watermelon',\n", + " 'Stale_Strawberry',\n", + " 'Stale_Spanich',\n", + " 'stale_potato',\n", + " 'stale_pomogrante',\n", + " 'stale_orange',\n", + " 'stale_onion',\n", + " 'stale_okra',\n", + " 'stale_mango',\n", + " 'Stale_Lulo',\n", + " 'stale_lemon',\n", + " 'stale_chilli',\n", + " 'stale_capsicum',\n", + " 'stale_beetroot',\n", + " 'stale_bitter_ground',\n", + " 'stale_avacado',\n", + " 'stalecucumber',\n", + " 'Stalepear',\n", + " 'staleapple',\n", + " 'Fruit_Fresh_Banana',\n", + " 'pearfresh',\n", + " 'Fresh_Watermelon',\n", + " 'Fruit_Fresh_Avacado',\n", + " 'fresh_tomato',\n", + " 'Fresh_Tamarillo',\n", + " 'Fresh_Strawberry',\n", + " 'fresh_Spanich',\n", + " 'fresh_potato',\n", + " 'fresh_pomegrante',\n", + " 'fresh_orange',\n", + " 'fresh_onion',\n", + " 'fresh_lulo',\n", + " 'fresh_lemon',\n", + " 'fresh_eggplant',\n", + " 'fresh_cauliflower',\n", + " 'fresh_capsicum',\n", + " 'fresh_carrot',\n", + " 'fresh_bitter_gourd',\n", + " 'Fresh_cabbage',\n", + " 'fresh_beetroot',\n", + " 'freshapple'\n", + "]\n", + "\"\"\"\n", + "\n", + "# Save config to data.yaml file\n", + "data_yaml_path = 'C:/Users/Gaurav Lodhi/Downloads/Winners/GRID_test1/dataset/data.yaml'\n", + "os.makedirs(os.path.dirname(data_yaml_path), exist_ok=True)\n", + "\n", + "with open(data_yaml_path, 'w') as f:\n", + " f.write(data_yaml)\n", + "\n", + "# Load YOLOv8 model and train\n", + "model = YOLO('yolov8n.pt') # Load the YOLOv8 nano model\n", + "\n", + "# Train the model\n", + "model.train(data=data_yaml_path, epochs=10, imgsz=640, batch=32)\n", + "print(\"Training completed.\")\n", + "\n", + "# Validate the model\n", + "results = model.val(data=data_yaml_path, imgsz=640)\n", + "\n", + "# Print validation results\n", + "print(\"Validation results:\", results)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "base", + "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.12.4" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +}