{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "66f5a637",
   "metadata": {},
   "source": [
    "\n",
    "# Реализация архитектуры YOLOv10 для детекции автомобилей\n",
    "\n",
    "**Статья (ResearchGate):** YOLOv10: Real-Time End-to-End Object Detection  \n",
    "https://www.researchgate.net/publication/380821008_YOLOv10_Real-Time_End-to-End_Object_Detection\n",
    "\n",
    "**Выбранный датасет:** Cars (`sshikamaru/car-object-detection`)\n",
    "\n",
    "Ноутбук адаптирован **для локального запуска**. Нужны только папка датасета и доступ в интернет для установки пакетов и загрузки весов `yolov10n.pt`.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "00d6d9c6",
   "metadata": {},
   "source": [
    "\n",
    "## 1. Краткая постановка задачи\n",
    "\n",
    "Нужно реализовать новую архитектуру детекции объектов из научной статьи и применить её к одному из практических датасетов.  \n",
    "В этом ноутбуке используется **YOLOv10** и датасет **Cars** с одной категорией `car`.\n",
    "\n",
    "**Почему YOLOv10:**\n",
    "- это новая end-to-end архитектура детекции;\n",
    "- она убирает зависимость от `NMS` за счёт **consistent dual assignments**;\n",
    "- сочетает высокую точность и низкую задержку.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4e11fec6",
   "metadata": {},
   "source": [
    "\n",
    "## 2. Архитектура YOLOv10: детально, но компактно\n",
    "\n",
    "YOLOv10 сохраняет общую одностадийную схему `backbone -> neck -> detection head`, но меняет и обучение, и внутренние блоки модели.\n",
    "\n",
    "**Структура:**\n",
    "1. **Backbone** извлекает иерархию признаков из изображения.\n",
    "2. **Neck (PAN/FPN-подобное слияние)** объединяет признаки разных масштабов.\n",
    "3. **Dual head** во время обучения:\n",
    "   - **one-to-many head** даёт плотный обучающий сигнал;\n",
    "   - **one-to-one head** учится выдавать одно лучшее предсказание на объект.\n",
    "4. На инференсе используется **one-to-one branch**, поэтому модель работает **без NMS**.\n",
    "\n",
    "**Ключевые механизмы новизны:**\n",
    "- **Consistent dual assignments.** Оба режима назначения позитивных примеров согласованы одной метрикой сопоставления. Это позволяет обучать модель как обычный YOLO, но на инференсе перейти к end-to-end детекции без отдельного этапа подавления дубликатов.\n",
    "- **Lightweight classification head.** Классификационная ветвь облегчена глубинно-разделимыми свёртками, чтобы снизить FLOPs и задержку.\n",
    "- **Spatial-channel decoupled downsampling.** Уменьшение разрешения и изменение числа каналов разделены: сначала точечная свёртка по каналам, затем depthwise downsampling. Это уменьшает потери информации и вычислительные затраты.\n",
    "- **Rank-guided block design.** Глубина и тип блоков распределяются по стадиям неравномерно: более избыточные стадии упрощаются сильнее.\n",
    "- **Large-kernel conv + PSA (partial self-attention).** В глубоких стадиях модель расширяет receptive field и добавляет ограниченное self-attention без резкого роста стоимости.\n",
    "\n",
    "**Практический смысл:**\n",
    "YOLOv10 — это не просто «ещё один YOLO», а попытка одновременно улучшить **точность, задержку и end-to-end поведение**.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "f6c77b40",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[33mWARNING: Ignoring invalid distribution ~ulsectl (/home/konnilol/.pyenv/versions/3.12.12/lib/python3.12/site-packages)\u001b[0m\u001b[33m\n",
      "\u001b[0m\u001b[33mWARNING: Ignoring invalid distribution ~hirp (/home/konnilol/.pyenv/versions/3.12.12/lib/python3.12/site-packages)\u001b[0m\u001b[33m\n",
      "\u001b[0m\u001b[33mWARNING: Ignoring invalid distribution ~ulsectl (/home/konnilol/.pyenv/versions/3.12.12/lib/python3.12/site-packages)\u001b[0m\u001b[33m\n",
      "\u001b[0m\u001b[33mWARNING: Ignoring invalid distribution ~hirp (/home/konnilol/.pyenv/versions/3.12.12/lib/python3.12/site-packages)\u001b[0m\u001b[33m\n",
      "\u001b[0m\u001b[33mWARNING: Ignoring invalid distribution ~ulsectl (/home/konnilol/.pyenv/versions/3.12.12/lib/python3.12/site-packages)\u001b[0m\u001b[33m\n",
      "\u001b[0m\u001b[33mWARNING: Ignoring invalid distribution ~hirp (/home/konnilol/.pyenv/versions/3.12.12/lib/python3.12/site-packages)\u001b[0m\u001b[33m\n",
      "\u001b[0m"
     ]
    }
   ],
   "source": [
    "\n",
    "# Если пакеты уже стоят, ячейку можно пропустить\n",
    "import sys\n",
    "!{sys.executable} -m pip -q install -U ultralytics pandas scikit-learn pyyaml matplotlib tqdm\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "ab07ed58",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "ultralytics version: 8.4.24\n"
     ]
    }
   ],
   "source": [
    "\n",
    "from pathlib import Path\n",
    "import os\n",
    "import random\n",
    "import shutil\n",
    "import time\n",
    "import yaml\n",
    "import math\n",
    "from collections import defaultdict\n",
    "\n",
    "import numpy as np\n",
    "import pandas as pd\n",
    "from sklearn.model_selection import train_test_split\n",
    "from tqdm.auto import tqdm\n",
    "import matplotlib.pyplot as plt\n",
    "from PIL import Image\n",
    "\n",
    "from ultralytics import YOLO\n",
    "import ultralytics\n",
    "\n",
    "SEED = 42\n",
    "random.seed(SEED)\n",
    "np.random.seed(SEED)\n",
    "\n",
    "print('ultralytics version:', ultralytics.__version__)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e324bdfd",
   "metadata": {},
   "source": [
    "\n",
    "## 3. Поиск датасета на локальной машине\n",
    "\n",
    "Ожидается исходная структура Kaggle-датасета с папкой `training_images` и CSV-файлом разметки `train_solution_bounding_boxes (1).csv`.\n",
    "\n",
    "Если автоопределение не сработает, задайте путь вручную в `MANUAL_DATA_ROOT`.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "67abf7a2",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "DATA_ROOT = /home/konnilol/Downloads/car-object-detection/data\n",
      "CSV_PATH   = /home/konnilol/Downloads/car-object-detection/data/train_solution_bounding_boxes (1).csv\n",
      "TRAIN_IMAGES_DIR exists: True\n",
      "TEST_IMAGES_DIR exists: True\n"
     ]
    }
   ],
   "source": [
    "\n",
    "MANUAL_DATA_ROOT = None  # например: Path('./car-object-detection/data')\n",
    "\n",
    "candidate_roots = [\n",
    "    Path('./car-object-detection/data'),\n",
    "    Path('./car-object-detection'),\n",
    "    Path('./data/car-object-detection'),\n",
    "    Path('./data'),\n",
    "    Path('.'),\n",
    "]\n",
    "\n",
    "def find_dataset_root(manual_root=None):\n",
    "    if manual_root is not None:\n",
    "        p = Path(manual_root)\n",
    "        if (p / 'training_images').exists():\n",
    "            return p\n",
    "        if (p / 'data' / 'training_images').exists():\n",
    "            return p / 'data'\n",
    "    for root in candidate_roots:\n",
    "        root = Path(root)\n",
    "        if (root / 'training_images').exists():\n",
    "            return root\n",
    "        if (root / 'data' / 'training_images').exists():\n",
    "            return root / 'data'\n",
    "    for root, dirs, files in os.walk('.'):\n",
    "        root = Path(root)\n",
    "        if (root / 'training_images').exists():\n",
    "            return root\n",
    "    return None\n",
    "\n",
    "DATA_ROOT = find_dataset_root(MANUAL_DATA_ROOT)\n",
    "if DATA_ROOT is None:\n",
    "    raise FileNotFoundError('Не найдена папка датасета. Укажите MANUAL_DATA_ROOT.')\n",
    "\n",
    "csv_candidates = list(DATA_ROOT.glob('train_solution_bounding_boxes*.csv'))\n",
    "if not csv_candidates:\n",
    "    raise FileNotFoundError('Не найден CSV-файл с bbox-разметкой.')\n",
    "\n",
    "CSV_PATH = csv_candidates[0]\n",
    "TRAIN_IMAGES_DIR = DATA_ROOT / 'training_images'\n",
    "TEST_IMAGES_DIR = DATA_ROOT / 'testing_images'\n",
    "\n",
    "print('DATA_ROOT =', DATA_ROOT.resolve())\n",
    "print('CSV_PATH   =', CSV_PATH.resolve())\n",
    "print('TRAIN_IMAGES_DIR exists:', TRAIN_IMAGES_DIR.exists())\n",
    "print('TEST_IMAGES_DIR exists:', TEST_IMAGES_DIR.exists())\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ae5dd86a",
   "metadata": {},
   "source": [
    "\n",
    "## 4. Подготовка данных в формате YOLO\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "d6258a24",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "             image        xmin        ymin        xmax        ymax\n",
      "0   vid_4_1000.jpg  281.259045  187.035071  327.727931  223.225547\n",
      "1  vid_4_10000.jpg   15.163531  187.035071  120.329957  236.430180\n",
      "2  vid_4_10040.jpg  239.192475  176.764801  361.968162  236.430180\n",
      "3  vid_4_10020.jpg  496.483358  172.363256  630.020260  231.539575\n",
      "4  vid_4_10060.jpg   16.630970  186.546010  132.558611  238.386422\n",
      "(559, 5)\n",
      "['image', 'xmin', 'ymin', 'xmax', 'ymax']\n"
     ]
    }
   ],
   "source": [
    "\n",
    "df = pd.read_csv(CSV_PATH)\n",
    "print(df.head())\n",
    "print(df.shape)\n",
    "print(df.columns.tolist())\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "5551305b",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Число изображений с bbox: 355\n",
      "Число bbox: 559\n"
     ]
    }
   ],
   "source": [
    "\n",
    "# Нормализуем имена колонок\n",
    "rename_map = {}\n",
    "for c in df.columns:\n",
    "    low = c.lower().strip()\n",
    "    if low == 'image': rename_map[c] = 'image'\n",
    "    elif low == 'xmin': rename_map[c] = 'xmin'\n",
    "    elif low == 'ymin': rename_map[c] = 'ymin'\n",
    "    elif low == 'xmax': rename_map[c] = 'xmax'\n",
    "    elif low == 'ymax': rename_map[c] = 'ymax'\n",
    "\n",
    "df = df.rename(columns=rename_map)\n",
    "required = {'image', 'xmin', 'ymin', 'xmax', 'ymax'}\n",
    "missing = required - set(df.columns)\n",
    "if missing:\n",
    "    raise ValueError(f'В CSV не хватает колонок: {missing}')\n",
    "\n",
    "# Оставляем только валидные bbox\n",
    "df = df.dropna(subset=['image', 'xmin', 'ymin', 'xmax', 'ymax']).copy()\n",
    "df['xmin'] = df['xmin'].astype(float)\n",
    "df['ymin'] = df['ymin'].astype(float)\n",
    "df['xmax'] = df['xmax'].astype(float)\n",
    "df['ymax'] = df['ymax'].astype(float)\n",
    "df = df[(df['xmax'] > df['xmin']) & (df['ymax'] > df['ymin'])].copy()\n",
    "\n",
    "image_to_boxes = defaultdict(list)\n",
    "for row in df.itertuples(index=False):\n",
    "    image_to_boxes[row.image].append((row.xmin, row.ymin, row.xmax, row.ymax))\n",
    "\n",
    "all_images = sorted([p.name for p in TRAIN_IMAGES_DIR.glob('*') if p.suffix.lower() in {'.jpg', '.jpeg', '.png'}])\n",
    "all_images = [img for img in all_images if img in image_to_boxes]\n",
    "\n",
    "print('Число изображений с bbox:', len(all_images))\n",
    "print('Число bbox:', sum(len(v) for v in image_to_boxes.values()))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "bc59de1c",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "train: 284 val: 71\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Подготовка train: 100%|██████████| 284/284 [00:00<00:00, 3154.36it/s]\n",
      "Подготовка val: 100%|██████████| 71/71 [00:00<00:00, 3173.78it/s]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "path: /home/konnilol/Downloads/work_yolov10_cars/converted\n",
      "train: images/train\n",
      "val: images/val\n",
      "names:\n",
      "  0: car\n",
      "\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    }
   ],
   "source": [
    "\n",
    "WORKDIR = Path('./work_yolov10_cars').resolve()\n",
    "CONVERTED = WORKDIR / 'converted'\n",
    "for split in ['train', 'val']:\n",
    "    (CONVERTED / 'images' / split).mkdir(parents=True, exist_ok=True)\n",
    "    (CONVERTED / 'labels' / split).mkdir(parents=True, exist_ok=True)\n",
    "\n",
    "train_imgs, val_imgs = train_test_split(all_images, test_size=0.2, random_state=SEED, shuffle=True)\n",
    "print('train:', len(train_imgs), 'val:', len(val_imgs))\n",
    "\n",
    "def yolo_line(box, w, h, cls_id=0):\n",
    "    xmin, ymin, xmax, ymax = box\n",
    "    xc = ((xmin + xmax) / 2.0) / w\n",
    "    yc = ((ymin + ymax) / 2.0) / h\n",
    "    bw = (xmax - xmin) / w\n",
    "    bh = (ymax - ymin) / h\n",
    "    return f\"{cls_id} {xc:.6f} {yc:.6f} {bw:.6f} {bh:.6f}\"\n",
    "\n",
    "for split_name, split_imgs in [('train', train_imgs), ('val', val_imgs)]:\n",
    "    for img_name in tqdm(split_imgs, desc=f'Подготовка {split_name}'):\n",
    "        src = TRAIN_IMAGES_DIR / img_name\n",
    "        dst = CONVERTED / 'images' / split_name / img_name\n",
    "        shutil.copy2(src, dst)\n",
    "\n",
    "        with Image.open(src) as im:\n",
    "            w, h = im.size\n",
    "        label_path = CONVERTED / 'labels' / split_name / f'{Path(img_name).stem}.txt'\n",
    "        lines = [yolo_line(box, w, h, cls_id=0) for box in image_to_boxes[img_name]]\n",
    "        label_path.write_text(''.join(lines), encoding='utf-8')\n",
    "\n",
    "DATA_YAML = WORKDIR / 'cars_yolov10.yaml'\n",
    "data_cfg = {\n",
    "    'path': str(CONVERTED),\n",
    "    'train': 'images/train',\n",
    "    'val': 'images/val',\n",
    "    'names': {0: 'car'}\n",
    "}\n",
    "DATA_YAML.write_text(yaml.safe_dump(data_cfg, sort_keys=False, allow_unicode=True), encoding='utf-8')\n",
    "print(DATA_YAML.read_text(encoding='utf-8'))\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ee065dd4",
   "metadata": {},
   "source": [
    "\n",
    "## 5. Обучение YOLOv10\n",
    "\n",
    "Для локальной машины выбран **YOLOv10n** — самый компактный вариант семейства.  \n",
    "Это позволяет показать архитектуру статьи и при этом сохранить разумное время обучения.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "e8cb02d5",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[KDownloading https://github.com/ultralytics/assets/releases/download/v8.4.0/yolov10n.pt to 'yolov10n.pt': 100% ━━━━━━━━━━━━ 5.6MB 3.6MB/s 1.5s.5s<0.0s1.4s8s\n",
      "Ultralytics 8.4.24 🚀 Python-3.12.12 torch-2.10.0+cu128 CUDA:0 (NVIDIA GeForce RTX 3080, 9873MiB)\n",
      "\u001b[34m\u001b[1mengine/trainer: \u001b[0magnostic_nms=False, amp=True, angle=1.0, augment=False, auto_augment=randaugment, batch=16, bgr=0.0, box=7.5, cache=False, cfg=None, classes=None, close_mosaic=10, cls=0.5, compile=False, conf=None, copy_paste=0.0, copy_paste_mode=flip, cos_lr=False, cutmix=0.0, data=/home/konnilol/Downloads/work_yolov10_cars/cars_yolov10.yaml, degrees=0.0, deterministic=True, device=None, dfl=1.5, dnn=False, dropout=0.0, dynamic=False, embed=None, end2end=None, epochs=40, erasing=0.4, exist_ok=True, fliplr=0.5, flipud=0.0, format=torchscript, fraction=1.0, freeze=None, half=False, hsv_h=0.015, hsv_s=0.7, hsv_v=0.4, imgsz=640, int8=False, iou=0.7, keras=False, kobj=1.0, line_width=None, lr0=0.01, lrf=0.01, mask_ratio=4, max_det=300, mixup=0.0, mode=train, model=yolov10n.pt, momentum=0.937, mosaic=1.0, multi_scale=0.0, name=yolov10n_cars, nbs=64, nms=False, opset=None, optimize=False, optimizer=auto, overlap_mask=True, patience=100, perspective=0.0, plots=True, pose=12.0, pretrained=True, profile=False, project=/home/konnilol/Downloads/work_yolov10_cars/runs, rect=False, resume=False, retina_masks=False, rle=1.0, save=True, save_conf=False, save_crop=False, save_dir=/home/konnilol/Downloads/work_yolov10_cars/runs/yolov10n_cars, save_frames=False, save_json=False, save_period=-1, save_txt=False, scale=0.2, seed=42, shear=0.0, show=False, show_boxes=True, show_conf=True, show_labels=True, simplify=True, single_cls=False, source=None, split=val, stream_buffer=False, task=detect, time=None, tracker=botsort.yaml, translate=0.05, val=True, verbose=True, vid_stride=1, visualize=False, warmup_bias_lr=0.1, warmup_epochs=3.0, warmup_momentum=0.8, weight_decay=0.0005, workers=8, workspace=None\n",
      "Overriding model.yaml nc=80 with nc=1\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      9856  ultralytics.nn.modules.block.SCDown          [64, 128, 3, 2]               \n",
      "  6                  -1  2    197632  ultralytics.nn.modules.block.C2f             [128, 128, 2, True]           \n",
      "  7                  -1  1     36096  ultralytics.nn.modules.block.SCDown          [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    249728  ultralytics.nn.modules.block.PSA             [256, 256]                    \n",
      " 11                  -1  1         0  torch.nn.modules.upsampling.Upsample         [None, 2, 'nearest']          \n",
      " 12             [-1, 6]  1         0  ultralytics.nn.modules.conv.Concat           [1]                           \n",
      " 13                  -1  1    148224  ultralytics.nn.modules.block.C2f             [384, 128, 1]                 \n",
      " 14                  -1  1         0  torch.nn.modules.upsampling.Upsample         [None, 2, 'nearest']          \n",
      " 15             [-1, 4]  1         0  ultralytics.nn.modules.conv.Concat           [1]                           \n",
      " 16                  -1  1     37248  ultralytics.nn.modules.block.C2f             [192, 64, 1]                  \n",
      " 17                  -1  1     36992  ultralytics.nn.modules.conv.Conv             [64, 64, 3, 2]                \n",
      " 18            [-1, 13]  1         0  ultralytics.nn.modules.conv.Concat           [1]                           \n",
      " 19                  -1  1    123648  ultralytics.nn.modules.block.C2f             [192, 128, 1]                 \n",
      " 20                  -1  1     18048  ultralytics.nn.modules.block.SCDown          [128, 128, 3, 2]              \n",
      " 21            [-1, 10]  1         0  ultralytics.nn.modules.conv.Concat           [1]                           \n",
      " 22                  -1  1    282624  ultralytics.nn.modules.block.C2fCIB          [384, 256, 1, True, True]     \n",
      " 23        [16, 19, 22]  1    861718  ultralytics.nn.modules.head.v10Detect        [1, [64, 128, 256]]           \n",
      "YOLOv10n summary: 224 layers, 2,707,430 parameters, 2,707,414 gradients, 8.4 GFLOPs\n",
      "\n",
      "Transferred 493/595 items from pretrained weights\n",
      "Freezing layer 'model.23.dfl.conv.weight'\n",
      "\u001b[34m\u001b[1mAMP: \u001b[0mrunning Automatic Mixed Precision (AMP) checks...\n",
      "\u001b[34m\u001b[1mAMP: \u001b[0mchecks passed ✅\n",
      "\u001b[34m\u001b[1mtrain: \u001b[0mFast image access ✅ (ping: 0.0±0.0 ms, read: 2544.0±1441.6 MB/s, size: 99.8 KB)\n",
      "\u001b[K\u001b[34m\u001b[1mtrain: \u001b[0mScanning /home/konnilol/Downloads/work_yolov10_cars/converted/labels/train... 284 images, 0 backgrounds, 0 corrupt: 100% ━━━━━━━━━━━━ 284/284 3.1Kit/s 0.1s\n",
      "\u001b[34m\u001b[1mtrain: \u001b[0mNew cache created: /home/konnilol/Downloads/work_yolov10_cars/converted/labels/train.cache\n",
      "WARNING ⚠️ Box and segment counts should be equal, but got len(segments) = 93, len(boxes) = 284. To resolve this only boxes will be used and all segments will be removed. To avoid this please supply either a detect or segment dataset, not a detect-segment mixed dataset.\n",
      "\u001b[34m\u001b[1mval: \u001b[0mFast image access ✅ (ping: 0.0±0.0 ms, read: 1967.5±1363.5 MB/s, size: 100.8 KB)\n",
      "\u001b[K\u001b[34m\u001b[1mval: \u001b[0mScanning /home/konnilol/Downloads/work_yolov10_cars/converted/labels/val... 71 images, 0 backgrounds, 0 corrupt: 100% ━━━━━━━━━━━━ 71/71 2.2Kit/s 0.0s\n",
      "\u001b[34m\u001b[1mval: \u001b[0mNew cache created: /home/konnilol/Downloads/work_yolov10_cars/converted/labels/val.cache\n",
      "WARNING ⚠️ Box and segment counts should be equal, but got len(segments) = 26, len(boxes) = 71. To resolve this only boxes will be used and all segments will be removed. To avoid this please supply either a detect or segment dataset, not a detect-segment mixed dataset.\n",
      "\u001b[34m\u001b[1moptimizer:\u001b[0m 'optimizer=auto' found, ignoring 'lr0=0.01' and 'momentum=0.937' and determining best 'optimizer', 'lr0' and 'momentum' automatically... \n",
      "\u001b[34m\u001b[1moptimizer:\u001b[0m AdamW(lr=0.002, momentum=0.9) with parameter groups 95 weight(decay=0.0), 108 weight(decay=0.0005), 107 bias(decay=0.0)\n",
      "Plotting labels to /home/konnilol/Downloads/work_yolov10_cars/runs/yolov10n_cars/labels.jpg... \n",
      "Image sizes 640 train, 640 val\n",
      "Using 8 dataloader workers\n",
      "Logging results to \u001b[1m/home/konnilol/Downloads/work_yolov10_cars/runs/yolov10n_cars\u001b[0m\n",
      "Starting training for 40 epochs...\n",
      "\n",
      "      Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size\n",
      "\u001b[K       1/40      2.69G      1.683       7.06      1.481         21        640: 100% ━━━━━━━━━━━━ 18/18 1.5it/s 12.3s0.1s\n",
      "\u001b[K                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100% ━━━━━━━━━━━━ 3/3 1.2s/it 3.5s11.7s\n",
      "                   all         71         71    0.00324      0.972     0.0605     0.0209\n",
      "\n",
      "      Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size\n",
      "\u001b[K       2/40       2.7G      1.178      6.123      1.192         23        640: 100% ━━━━━━━━━━━━ 18/18 10.7it/s 1.7s0.2s\n",
      "\u001b[K                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100% ━━━━━━━━━━━━ 3/3 18.8it/s 0.2s.2s\n",
      "                   all         71         71    0.00296      0.887      0.018    0.00601\n",
      "\n",
      "      Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size\n",
      "\u001b[K       3/40       2.7G      1.212      5.516      1.207         21        640: 100% ━━━━━━━━━━━━ 18/18 10.6it/s 1.7s0.2s\n",
      "\u001b[K                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100% ━━━━━━━━━━━━ 3/3 19.0it/s 0.2s.2s\n",
      "                   all         71         71    0.00319      0.958     0.0246    0.00701\n",
      "\n",
      "      Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size\n",
      "\u001b[K       4/40       2.7G      1.307       5.02      1.217         18        640: 100% ━━━━━━━━━━━━ 18/18 9.6it/s 1.9s0.1s\n",
      "\u001b[K                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100% ━━━━━━━━━━━━ 3/3 16.2it/s 0.2s.2s\n",
      "                   all         71         71      0.117      0.127     0.0468     0.0208\n",
      "\n",
      "      Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size\n",
      "\u001b[K       5/40       2.7G      1.361      4.394      1.248         17        640: 100% ━━━━━━━━━━━━ 18/18 10.4it/s 1.7s0.1s\n",
      "\u001b[K                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100% ━━━━━━━━━━━━ 3/3 16.3it/s 0.2s.2s\n",
      "                   all         71         71      0.152      0.169      0.108     0.0357\n",
      "\n",
      "      Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size\n",
      "\u001b[K       6/40       2.7G      1.379      3.794      1.264         24        640: 100% ━━━━━━━━━━━━ 18/18 10.4it/s 1.7s0.1s\n",
      "\u001b[K                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100% ━━━━━━━━━━━━ 3/3 17.1it/s 0.2s.2s\n",
      "                   all         71         71      0.219      0.324      0.183     0.0938\n",
      "\n",
      "      Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size\n",
      "\u001b[K       7/40       2.7G      1.398      3.413      1.262         23        640: 100% ━━━━━━━━━━━━ 18/18 10.6it/s 1.7s0.1s\n",
      "\u001b[K                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100% ━━━━━━━━━━━━ 3/3 16.3it/s 0.2s.3s\n",
      "                   all         71         71      0.392      0.381      0.356      0.194\n",
      "\n",
      "      Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size\n",
      "\u001b[K       8/40       2.7G      1.414       3.18      1.248         18        640: 100% ━━━━━━━━━━━━ 18/18 10.4it/s 1.7s0.1s\n",
      "\u001b[K                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100% ━━━━━━━━━━━━ 3/3 16.6it/s 0.2s.2s\n",
      "                   all         71         71        0.3      0.296      0.223      0.114\n",
      "\n",
      "      Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size\n",
      "\u001b[K       9/40       2.7G      1.358       2.84      1.207         26        640: 100% ━━━━━━━━━━━━ 18/18 10.6it/s 1.7s0.1s\n",
      "\u001b[K                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100% ━━━━━━━━━━━━ 3/3 16.7it/s 0.2s.2s\n",
      "                   all         71         71      0.481      0.479      0.341      0.202\n",
      "\n",
      "      Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size\n",
      "\u001b[K      10/40       2.7G      1.307      2.631      1.229         28        640: 100% ━━━━━━━━━━━━ 18/18 10.4it/s 1.7s0.1s\n",
      "\u001b[K                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100% ━━━━━━━━━━━━ 3/3 16.9it/s 0.2s.2s\n",
      "                   all         71         71      0.224      0.282      0.219       0.14\n",
      "\n",
      "      Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size\n",
      "\u001b[K      11/40       2.7G      1.255      2.341      1.169         27        640: 100% ━━━━━━━━━━━━ 18/18 10.6it/s 1.7s0.1s\n",
      "\u001b[K                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100% ━━━━━━━━━━━━ 3/3 16.7it/s 0.2s.2s\n",
      "                   all         71         71      0.375      0.648      0.413      0.241\n",
      "\n",
      "      Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size\n",
      "\u001b[K      12/40       2.7G      1.241      2.263      1.177         20        640: 100% ━━━━━━━━━━━━ 18/18 10.5it/s 1.7s0.1s\n",
      "\u001b[K                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100% ━━━━━━━━━━━━ 3/3 17.4it/s 0.2s.2s\n",
      "                   all         71         71      0.412      0.423      0.351      0.223\n",
      "\n",
      "      Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size\n",
      "\u001b[K      13/40       2.7G       1.28      2.189      1.201         23        640: 100% ━━━━━━━━━━━━ 18/18 10.6it/s 1.7s0.1s\n",
      "\u001b[K                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100% ━━━━━━━━━━━━ 3/3 17.2it/s 0.2s.2s\n",
      "                   all         71         71       0.56      0.676      0.574      0.374\n",
      "\n",
      "      Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size\n",
      "\u001b[K      14/40       2.7G      1.284      2.012        1.2         21        640: 100% ━━━━━━━━━━━━ 18/18 10.5it/s 1.7s0.1s\n",
      "\u001b[K                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100% ━━━━━━━━━━━━ 3/3 17.0it/s 0.2s.2s\n",
      "                   all         71         71      0.625      0.469      0.533      0.338\n",
      "\n",
      "      Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size\n",
      "\u001b[K      15/40       2.7G      1.242      1.782      1.161         20        640: 100% ━━━━━━━━━━━━ 18/18 10.6it/s 1.7s0.1s\n",
      "\u001b[K                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100% ━━━━━━━━━━━━ 3/3 16.7it/s 0.2s.2s\n",
      "                   all         71         71      0.594      0.563      0.539      0.337\n",
      "\n",
      "      Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size\n",
      "\u001b[K      16/40       2.7G      1.217      1.633      1.166         27        640: 100% ━━━━━━━━━━━━ 18/18 10.4it/s 1.7s.1s\n",
      "\u001b[K                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100% ━━━━━━━━━━━━ 3/3 16.6it/s 0.2s.2s\n",
      "                   all         71         71      0.557      0.662      0.585      0.363\n",
      "\n",
      "      Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size\n",
      "\u001b[K      17/40       2.7G      1.237      1.603      1.162         25        640: 100% ━━━━━━━━━━━━ 18/18 10.7it/s 1.7s0.1s\n",
      "\u001b[K                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100% ━━━━━━━━━━━━ 3/3 17.0it/s 0.2s.2s\n",
      "                   all         71         71      0.514      0.718      0.637      0.423\n",
      "\n",
      "      Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size\n",
      "\u001b[K      18/40       2.7G      1.227      1.588      1.156         30        640: 100% ━━━━━━━━━━━━ 18/18 10.4it/s 1.7s0.1s\n",
      "\u001b[K                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100% ━━━━━━━━━━━━ 3/3 16.6it/s 0.2s.2s\n",
      "                   all         71         71       0.59      0.606      0.591      0.371\n",
      "\n",
      "      Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size\n",
      "\u001b[K      19/40       2.7G      1.169       1.53      1.142         23        640: 100% ━━━━━━━━━━━━ 18/18 10.6it/s 1.7s0.1s\n",
      "\u001b[K                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100% ━━━━━━━━━━━━ 3/3 16.8it/s 0.2s.2s\n",
      "                   all         71         71      0.549      0.704      0.623      0.395\n",
      "\n",
      "      Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size\n",
      "\u001b[K      20/40       2.7G      1.181      1.472      1.128         21        640: 100% ━━━━━━━━━━━━ 18/18 10.6it/s 1.7s0.1s\n",
      "\u001b[K                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100% ━━━━━━━━━━━━ 3/3 17.3it/s 0.2s.2s\n",
      "                   all         71         71      0.708      0.662      0.699      0.449\n",
      "\n",
      "      Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size\n",
      "\u001b[K      21/40       2.7G      1.122      1.366        1.1         26        640: 100% ━━━━━━━━━━━━ 18/18 10.5it/s 1.7s0.1s\n",
      "\u001b[K                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100% ━━━━━━━━━━━━ 3/3 16.9it/s 0.2s.2s\n",
      "                   all         71         71      0.665      0.672       0.66      0.416\n",
      "\n",
      "      Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size\n",
      "\u001b[K      22/40       2.7G      1.151      1.339       1.11         28        640: 100% ━━━━━━━━━━━━ 18/18 10.4it/s 1.7s.1s\n",
      "\u001b[K                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100% ━━━━━━━━━━━━ 3/3 17.3it/s 0.2s.2s\n",
      "                   all         71         71       0.48      0.592      0.494      0.338\n",
      "\n",
      "      Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size\n",
      "\u001b[K      23/40       2.7G      1.076      1.212      1.087         17        640: 100% ━━━━━━━━━━━━ 18/18 10.7it/s 1.7s0.1s\n",
      "\u001b[K                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100% ━━━━━━━━━━━━ 3/3 16.3it/s 0.2s.2s\n",
      "                   all         71         71      0.545      0.704      0.606      0.418\n",
      "\n",
      "      Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size\n",
      "\u001b[K      24/40       2.7G      1.126      1.182      1.124         20        640: 100% ━━━━━━━━━━━━ 18/18 10.8it/s 1.7s0.1s\n",
      "\u001b[K                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100% ━━━━━━━━━━━━ 3/3 17.6it/s 0.2s.2s\n",
      "                   all         71         71      0.655      0.722      0.645      0.425\n",
      "\n",
      "      Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size\n",
      "\u001b[K      25/40       2.7G      1.116      1.161      1.091         24        640: 100% ━━━━━━━━━━━━ 18/18 10.2it/s 1.8s.1s\n",
      "\u001b[K                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100% ━━━━━━━━━━━━ 3/3 15.9it/s 0.2s.3s\n",
      "                   all         71         71      0.706      0.775      0.729      0.473\n",
      "\n",
      "      Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size\n",
      "\u001b[K      26/40       2.7G       1.12      1.133      1.108         23        640: 100% ━━━━━━━━━━━━ 18/18 10.3it/s 1.7s0.1s\n",
      "\u001b[K                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100% ━━━━━━━━━━━━ 3/3 17.1it/s 0.2s.2s\n",
      "                   all         71         71      0.484      0.648      0.561       0.38\n",
      "\n",
      "      Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size\n",
      "\u001b[K      27/40       2.7G      1.072      1.111      1.081         32        640: 100% ━━━━━━━━━━━━ 18/18 10.6it/s 1.7s0.1s\n",
      "\u001b[K                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100% ━━━━━━━━━━━━ 3/3 17.3it/s 0.2s.2s\n",
      "                   all         71         71      0.546      0.797      0.579       0.39\n",
      "\n",
      "      Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size\n",
      "\u001b[K      28/40       2.7G      1.061      1.095      1.082         15        640: 100% ━━━━━━━━━━━━ 18/18 10.5it/s 1.7s0.1s\n",
      "\u001b[K                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100% ━━━━━━━━━━━━ 3/3 17.0it/s 0.2s.2s\n",
      "                   all         71         71      0.683      0.704      0.699       0.48\n",
      "\n",
      "      Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size\n",
      "\u001b[K      29/40       2.7G       1.05      1.075      1.053         23        640: 100% ━━━━━━━━━━━━ 18/18 10.6it/s 1.7s0.1s\n",
      "\u001b[K                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100% ━━━━━━━━━━━━ 3/3 17.0it/s 0.2s.2s\n",
      "                   all         71         71      0.712       0.73      0.724      0.505\n",
      "\n",
      "      Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size\n",
      "\u001b[K      30/40       2.7G      1.026      1.021      1.048         21        640: 100% ━━━━━━━━━━━━ 18/18 10.5it/s 1.7s0.1s\n",
      "\u001b[K                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100% ━━━━━━━━━━━━ 3/3 16.4it/s 0.2s.2s\n",
      "                   all         71         71       0.69      0.721      0.699      0.481\n",
      "Closing dataloader mosaic\n",
      "\n",
      "      Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size\n",
      "\u001b[K      31/40       2.7G     0.9717      1.005      1.061         12        640: 100% ━━━━━━━━━━━━ 18/18 7.4it/s 2.4s<0.1s\n",
      "\u001b[K                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100% ━━━━━━━━━━━━ 3/3 17.4it/s 0.2s.2s\n",
      "                   all         71         71      0.513      0.652      0.516      0.358\n",
      "\n",
      "      Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size\n",
      "\u001b[K      32/40       2.7G     0.9624     0.9446      1.039         12        640: 100% ━━━━━━━━━━━━ 18/18 10.7it/s 1.7s0.1s\n",
      "\u001b[K                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100% ━━━━━━━━━━━━ 3/3 17.8it/s 0.2s.2s\n",
      "                   all         71         71      0.658      0.789       0.77      0.531\n",
      "\n",
      "      Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size\n",
      "\u001b[K      33/40       2.7G     0.9605     0.8613      1.086         12        640: 100% ━━━━━━━━━━━━ 18/18 10.9it/s 1.7s0.1s\n",
      "\u001b[K                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100% ━━━━━━━━━━━━ 3/3 18.0it/s 0.2s.2s\n",
      "                   all         71         71      0.726      0.775      0.786      0.538\n",
      "\n",
      "      Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size\n",
      "\u001b[K      34/40       2.7G     0.9543      0.816      1.041         12        640: 100% ━━━━━━━━━━━━ 18/18 10.8it/s 1.7s0.1s\n",
      "\u001b[K                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100% ━━━━━━━━━━━━ 3/3 17.2it/s 0.2s.2s\n",
      "                   all         71         71      0.657      0.803      0.799      0.557\n",
      "\n",
      "      Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size\n",
      "\u001b[K      35/40       2.7G     0.9323     0.8171       1.02         12        640: 100% ━━━━━━━━━━━━ 18/18 10.7it/s 1.7s0.1s\n",
      "\u001b[K                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100% ━━━━━━━━━━━━ 3/3 17.7it/s 0.2s.2s\n",
      "                   all         71         71        0.8      0.718      0.792      0.557\n",
      "\n",
      "      Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size\n",
      "\u001b[K      36/40       2.7G      0.902     0.7194      1.028         12        640: 100% ━━━━━━━━━━━━ 18/18 10.4it/s 1.7s.1s\n",
      "\u001b[K                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100% ━━━━━━━━━━━━ 3/3 17.0it/s 0.2s.2s\n",
      "                   all         71         71       0.71      0.759      0.728      0.492\n",
      "\n",
      "      Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size\n",
      "\u001b[K      37/40       2.7G     0.9003     0.7076      1.027         12        640: 100% ━━━━━━━━━━━━ 18/18 10.8it/s 1.7s0.1s\n",
      "\u001b[K                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100% ━━━━━━━━━━━━ 3/3 16.3it/s 0.2s.2s\n",
      "                   all         71         71      0.723      0.773      0.747      0.509\n",
      "\n",
      "      Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size\n",
      "\u001b[K      38/40       2.7G     0.8693     0.6802      1.002         12        640: 100% ━━━━━━━━━━━━ 18/18 10.6it/s 1.7s0.1s\n",
      "\u001b[K                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100% ━━━━━━━━━━━━ 3/3 17.7it/s 0.2s.2s\n",
      "                   all         71         71      0.804      0.761      0.795      0.551\n",
      "\n",
      "      Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size\n",
      "\u001b[K      39/40       2.7G     0.8885     0.7155      1.039         11        640: 100% ━━━━━━━━━━━━ 18/18 10.6it/s 1.7s0.1s\n",
      "\u001b[K                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100% ━━━━━━━━━━━━ 3/3 16.2it/s 0.2s.2s\n",
      "                   all         71         71      0.802      0.761      0.811      0.564\n",
      "\n",
      "      Epoch    GPU_mem   box_loss   cls_loss   dfl_loss  Instances       Size\n",
      "\u001b[K      40/40       2.7G     0.8847     0.6909      1.004         12        640: 100% ━━━━━━━━━━━━ 18/18 10.4it/s 1.7s0.1s\n",
      "\u001b[K                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100% ━━━━━━━━━━━━ 3/3 16.6it/s 0.2s.2s\n",
      "                   all         71         71      0.859      0.718      0.822      0.572\n",
      "\n",
      "40 epochs completed in 0.028 hours.\n",
      "Optimizer stripped from /home/konnilol/Downloads/work_yolov10_cars/runs/yolov10n_cars/weights/last.pt, 5.7MB\n",
      "Optimizer stripped from /home/konnilol/Downloads/work_yolov10_cars/runs/yolov10n_cars/weights/best.pt, 5.7MB\n",
      "\n",
      "Validating /home/konnilol/Downloads/work_yolov10_cars/runs/yolov10n_cars/weights/best.pt...\n",
      "Ultralytics 8.4.24 🚀 Python-3.12.12 torch-2.10.0+cu128 CUDA:0 (NVIDIA GeForce RTX 3080, 9873MiB)\n",
      "YOLOv10n summary (fused): 102 layers, 2,265,363 parameters, 0 gradients, 6.5 GFLOPs\n",
      "\u001b[K                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100% ━━━━━━━━━━━━ 3/3 10.4it/s 0.3s.4s\n",
      "                   all         71         71      0.859      0.718      0.822      0.572\n",
      "Speed: 0.1ms preprocess, 1.4ms inference, 0.0ms loss, 0.2ms postprocess per image\n",
      "Results saved to \u001b[1m/home/konnilol/Downloads/work_yolov10_cars/runs/yolov10n_cars\u001b[0m\n",
      "Папка эксперимента: /home/konnilol/Downloads/work_yolov10_cars/runs/yolov10n_cars\n"
     ]
    }
   ],
   "source": [
    "\n",
    "MODEL_NAME = 'yolov10n.pt'\n",
    "IMG_SIZE = 640\n",
    "EPOCHS = 40\n",
    "BATCH = 16\n",
    "PROJECT_DIR = str(WORKDIR / 'runs')\n",
    "RUN_NAME = 'yolov10n_cars'\n",
    "\n",
    "model = YOLO(MODEL_NAME)\n",
    "train_results = model.train(\n",
    "    data=str(DATA_YAML),\n",
    "    epochs=EPOCHS,\n",
    "    imgsz=IMG_SIZE,\n",
    "    batch=BATCH,\n",
    "    project=PROJECT_DIR,\n",
    "    name=RUN_NAME,\n",
    "    exist_ok=True,\n",
    "    pretrained=True,\n",
    "    seed=SEED,\n",
    "    degrees=0.0,\n",
    "    translate=0.05,\n",
    "    scale=0.20,\n",
    "    fliplr=0.5,\n",
    "    mosaic=1.0,\n",
    "    mixup=0.0,\n",
    "    cache=False,\n",
    "    verbose=True,\n",
    ")\n",
    "\n",
    "print('Папка эксперимента:', train_results.save_dir)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1d1e88d7",
   "metadata": {},
   "source": [
    "\n",
    "## 6. Валидация и расчёт метрик\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "3aa7e14a",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Ultralytics 8.4.24 🚀 Python-3.12.12 torch-2.10.0+cu128 CUDA:0 (NVIDIA GeForce RTX 3080, 9873MiB)\n",
      "YOLOv10n summary (fused): 102 layers, 2,265,363 parameters, 0 gradients, 6.5 GFLOPs\n",
      "\u001b[34m\u001b[1mval: \u001b[0mFast image access ✅ (ping: 0.0±0.0 ms, read: 5182.2±873.8 MB/s, size: 114.5 KB)\n",
      "\u001b[K\u001b[34m\u001b[1mval: \u001b[0mScanning /home/konnilol/Downloads/work_yolov10_cars/converted/labels/val.cache... 71 images, 0 backgrounds, 0 corrupt: 100% ━━━━━━━━━━━━ 71/71 42.5Mit/s 0.0s\n",
      "WARNING ⚠️ Box and segment counts should be equal, but got len(segments) = 26, len(boxes) = 71. To resolve this only boxes will be used and all segments will be removed. To avoid this please supply either a detect or segment dataset, not a detect-segment mixed dataset.\n",
      "\u001b[K                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95): 100% ━━━━━━━━━━━━ 5/5 19.3it/s 0.3s.6s\n",
      "                   all         71         71      0.858      0.718      0.822      0.571\n",
      "Speed: 0.1ms preprocess, 2.5ms inference, 0.0ms loss, 0.1ms postprocess per image\n"
     ]
    },
    {
     "data": {
      "application/vnd.positron.dataexplorer+json": {
       "comm_id": "e0cba7cf-bc02-4ddc-8430-2117dd2d179c",
       "shape": {
        "columns": 2,
        "rows": 5
       },
       "source": "pandas",
       "title": "pandas",
       "version": 1
      },
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>metric</th>\n",
       "      <th>value</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>Precision</td>\n",
       "      <td>0.857842</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>Recall</td>\n",
       "      <td>0.718310</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>F1</td>\n",
       "      <td>0.781900</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>mAP@0.50</td>\n",
       "      <td>0.822248</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>mAP@0.50:0.95</td>\n",
       "      <td>0.571469</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "          metric     value\n",
       "0      Precision  0.857842\n",
       "1         Recall  0.718310\n",
       "2             F1  0.781900\n",
       "3       mAP@0.50  0.822248\n",
       "4  mAP@0.50:0.95  0.571469"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "\n",
    "best_weights = Path(train_results.save_dir) / 'weights' / 'best.pt'\n",
    "if not best_weights.exists():\n",
    "    raise FileNotFoundError(f'Не найдены веса: {best_weights}')\n",
    "\n",
    "best_model = YOLO(str(best_weights))\n",
    "val_metrics = best_model.val(data=str(DATA_YAML), split='val', imgsz=IMG_SIZE, plots=False)\n",
    "\n",
    "precision = float(val_metrics.box.mp)\n",
    "recall = float(val_metrics.box.mr)\n",
    "map50 = float(val_metrics.box.map50)\n",
    "map5095 = float(val_metrics.box.map)\n",
    "f1 = 2 * precision * recall / (precision + recall + 1e-12)\n",
    "\n",
    "metrics_df = pd.DataFrame({\n",
    "    'metric': ['Precision', 'Recall', 'F1', 'mAP@0.50', 'mAP@0.50:0.95'],\n",
    "    'value': [precision, recall, f1, map50, map5095]\n",
    "})\n",
    "metrics_df\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "4151f174",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Сохранено: /home/konnilol/Downloads/work_yolov10_cars/yolov10_cars_metrics.csv\n"
     ]
    }
   ],
   "source": [
    "\n",
    "metrics_csv = WORKDIR / 'yolov10_cars_metrics.csv'\n",
    "metrics_df.to_csv(metrics_csv, index=False)\n",
    "print('Сохранено:', metrics_csv)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9fb2bcbb",
   "metadata": {},
   "source": [
    "\n",
    "## 7. Небольшая оценка задержки инференса\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "e23ca3b1",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.positron.dataexplorer+json": {
       "comm_id": "79424d58-c09e-4e89-819f-01b750bea844",
       "shape": {
        "columns": 2,
        "rows": 2
       },
       "source": "pandas",
       "title": "pandas",
       "version": 1
      },
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>metric</th>\n",
       "      <th>value</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>mean_latency_ms</td>\n",
       "      <td>8.742471</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>fps</td>\n",
       "      <td>114.384141</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "            metric       value\n",
       "0  mean_latency_ms    8.742471\n",
       "1              fps  114.384141"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "\n",
    "sample_images = sorted((CONVERTED / 'images' / 'val').glob('*'))[:50]\n",
    "latencies = []\n",
    "for p in sample_images:\n",
    "    t0 = time.perf_counter()\n",
    "    _ = best_model.predict(source=str(p), imgsz=IMG_SIZE, verbose=False, save=False)\n",
    "    latencies.append((time.perf_counter() - t0) * 1000.0)\n",
    "\n",
    "lat_ms = float(np.mean(latencies)) if latencies else float('nan')\n",
    "fps = 1000.0 / lat_ms if lat_ms and not math.isnan(lat_ms) else float('nan')\n",
    "\n",
    "speed_df = pd.DataFrame({'metric': ['mean_latency_ms', 'fps'], 'value': [lat_ms, fps]})\n",
    "speed_df\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ba28ecf1",
   "metadata": {},
   "source": [
    "\n",
    "## 8. Визуализация предсказаний\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "76c3b64e",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<Figure size 1400x1000 with 6 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "\n",
    "vis_images = sorted((CONVERTED / 'images' / 'val').glob('*'))[:6]\n",
    "results = best_model.predict([str(p) for p in vis_images], imgsz=IMG_SIZE, conf=0.25, verbose=False, save=False)\n",
    "\n",
    "plt.figure(figsize=(14, 10))\n",
    "for i, res in enumerate(results, start=1):\n",
    "    plt.subplot(2, 3, i)\n",
    "    img = res.plot()[:, :, ::-1]\n",
    "    plt.imshow(img)\n",
    "    plt.axis('off')\n",
    "    plt.title(Path(res.path).name, fontsize=9)\n",
    "plt.tight_layout()\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "71b0ec75",
   "metadata": {},
   "source": [
    "Архитектура.\n",
    "В работе использована YOLOv10n из статьи YOLOv10: Real-Time End-to-End Object Detection. Модель сохраняет схему backbone → neck → detection head, но ключевая новизна — end-to-end детекция без NMS за счёт механизма consistent dual assignments. Дополнительно применяются облегчённая классификационная голова, улучшенное понижение разрешения, крупные ядра свёртки и PSA-блоки для более эффективного извлечения признаков.\n",
    "\n",
    "Результаты на датасете Cars.\n",
    "После обучения получены:\n",
    "\n",
    "Precision = 0.858\n",
    "\n",
    "Recall = 0.718\n",
    "\n",
    "F1 = 0.782\n",
    "\n",
    "mAP@0.50 = 0.822\n",
    "\n",
    "mAP@0.50:0.95 = 0.571\n",
    "\n",
    "Средняя скорость инференса:\n",
    "\n",
    "8.74 мс на изображение\n",
    "\n",
    "около 114.4 FPS\n",
    "\n",
    "Вывод.\n",
    "YOLOv10 показала хорошее качество детекции при очень высокой скорости работы. По mAP@0.50 модель уже достаточно точна для практического применения, а по mAP@0.50:0.95 видно, что локализация не идеальна, но остаётся уверенной. В целом архитектура выглядит перспективной для задач обнаружения объектов в реальном времени, где важен компромисс между точностью и скоростью."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "name": "python"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
