Возможно ли модифицировать YOLOv8, чтобы использовать его в качестве извлечителя признаков для других задач?

Вопрос или проблема

Я изучаю документацию YOLOv8 здесь, но не вижу простого способа сделать то, что я предложил в заголовке. Я хочу загрузить предобученную модель YOLOv8, создать более крупную модель, которая будет содержать YOLOv8 в качестве субмодуля, и изменить функцию прямого распространения YOLOv8, чтобы иметь доступ к функции потерь обнаружения объектов и свёрточным признакам, чтобы их можно было использовать для последующих слоев для других пользовательских задач.

Чтобы сделать это понятнее, вот как yolov8 изначально предназначен для использования согласно https://docs.ultralytics.com/quickstart/#use-with-python:

from ultralytics import YOLO

# Создайте новую модель YOLO с нуля
model = YOLO('yolov8n.yaml')

# Загрузите предобученную модель YOLO (рекомендуется для обучения)
model = YOLO('yolov8n.pt')

# Обучите модель, используя набор данных 'coco128.yaml' в течение 3 эпох
results = model.train(data="coco128.yaml", epochs=3)

# Оцените производительность модели на валидационном наборе
results = model.val()

# Выполните обнаружение объектов на изображении, используя модель
results = model('https://ultralytics.com/images/bus.jpg')

# Экспортируйте модель в формате ONNX
success = model.export(format="onnx")

Вместо этого я хочу сделать что-то подобное:

import torch
import torch.nn as nn
from ultralytics import YOLO

class Yolov8Wrapper(nn.Module):

    def __init__(self, yolov8_feature_dim, n1, n2, n3):
        super().__init__()
        self.yolov8 = YOLO('yolov8n.pt')
        self.fc1 = nn.Linear(yolov8_feature_dim, n1)
        self.fc2 = nn.Linear(yolov8_feature_dim, n2)
        self.fc3 = nn.Linear(yolov8_feature_dim, n3)

    def forward(self, images, gt_boxes):
        features, loss = self.yolov8(images, gt_boxes)
        logits1 = self.fc1(features)
        logits2 = self.fc2(features)
        logits3 = self.fc3(features)
        return {
            'logits1': logits1,
            'logits2': logits2,
            'logits3': logits3,
            'yolov8_loss': loss,
        }

Код выше является очень упрощённым наброском и, конечно, не будет работать, но более или менее это идея. Кроме того, создавая этот специальный обёртку, я не смогу использовать готовую функциональность для обучения, валидации и предсказания, которая идет с библиотекой YOLO, так как это будет индивидуальная архитектура (YOLOv8 будет всего лишь её субмодулем). Таким образом, мне также нужно выяснить, как написать пользовательский загрузчик данных, чтобы предоставить YOLOv8 ввод, который он ожидает, плюс дополнительные данные, требуемые моим обёрткой (могут быть разные дополнительные слои в обёртке, предсказывающие различные выходы на основе признаков YOLOv8; думайте об этом как о многозадачном обучении).

Это возможно? Как это может быть сделано?

просто несколько идей для обёртки:

import torch
import torch.nn as nn
from ultralytics import YOLO

class Yolov8Wrapper(nn.Module):

    def __init__(self, yolov8_feature_dim, n1, n2, n3):
        super().__init__()
        self.yolov8 = YOLO('yolov8n.pt')
        self.fc1 = nn.Linear(yolov8_feature_dim, n1)
        self.fc2 = nn.Linear(yolov8_feature_dim, n2)
        self.fc3 = nn.Linear(yolov8_feature_dim, n3)

    def forward(self, images, gt_boxes):
        class CustomDataset(torch.utils.data.Dataset):
            def __init__(self, images, gt_boxes):
                self.images = images
                self.gt_boxes = gt_boxes

            def __len__(self):
                return len(self.images)

            def __getitem__(self, idx):
                image = self.images[idx]
                gt_box = self.gt_boxes[idx]
                return (image, gt_box)

        custom_dataloader = torch.utils.data.DataLoader(CustomDataset(images, gt_boxes), batch_size=1)

        with torch.no_grad():
            for batch_idx, (image, gt_box) in enumerate(custom_dataloader):
                features, loss = self.yolov8(image, gt_box)

        logits1 = self.fc1(features)
        logits2 = self.fc2(features)
        logits3 = self.fc3(features)

        return {
            'logits1': logits1,
            'logits2': logits2,
            'logits3': logits3,
            'yolov8_loss': loss,
        }
```

.

Ответ или решение

В современном мире компьютерного зрения YOLO (You Only Look Once) является одной из самых популярных и мощных архитектур для детекции объектов. Последняя версия, YOLOv8, предлагает значительное улучшение по сравнению с предыдущими версиями, включая более эффективную обработку изображений и улучшенные показатели точности. Однако, в условиях специфических бизнес-задач часто требуется модификация стандартной модели, например, использование YOLOv8 как экстрактора признаков для других задач. Рассмотрим возможность такой модификации.

Теория (Theory)

YOLOv8 — это архитектура нейросетевой модели, специализированная на задаче детекции объектов. Ёе ключевое достоинство — способность эффективно обрабатывать изображения в реальном времени, идентифицируя и локализуя объекты с высоким уровнем точности. В стандартной реализации YOLOv8 обучение и прогнозирование сконцентрированы на задачах детекции, что включает в себя расчет потерь, основанных на различии предсказанных координат объектов и их истинных значений.

Однако, архитектура YOLO также может быть адаптирована для других применений. Одним из таких применений может быть использование модели в качестве экстрактора признаков. Эта функциональность дает возможность захватывать промежуточные представления (features) из модели и использовать их для других аналитически задач, например, для мультизадачного обучения, классификации или сегментации.

Пример (Example)

Рассмотрим пример, в котором пользователь хотел бы интегрировать YOLOv8 как компонент более сложной модели, выполняющей сразу несколько задач. Стандартный подход к использованию модели YOLOv8 для детекции объектов выглядит следующим образом:

from ultralytics import YOLO

# Создание новой модели YOLO с нуля
model = YOLO('yolov8n.yaml')

# Загрузка предобученной модели YOLO (рекомендуется для обучения)
model = YOLO('yolov8n.pt')

# Обучение модели с помощью датасета 'coco128.yaml' на 3 эпохи
results = model.train(data="coco128.yaml", epochs=3)

# Оценка эффективности модели на валидационной выборке
results = model.val()

# Выполнение детекции объектов на изображении с использованием модели
results = model('https://ultralytics.com/images/bus.jpg')

# Экспорт модели в формат ONNX
success = model.export(format="onnx")

Для адаптации YOLOv8 как экстрактора признаков мы бы хотели получить промежуточные слои модели с тем, чтобы эти признаки могли быть использованы в дополнительных слоях или компонентах архитектуры. Пример кода для подобной задачи может выглядеть следующим образом:

import torch
import torch.nn as nn
from ultralytics import YOLO

class Yolov8Wrapper(nn.Module):

    def __init__(self, yolov8_feature_dim, n1, n2, n3):
        super().__init__()
        self.yolov8 = YOLO('yolov8n.pt')
        self.fc1 = nn.Linear(yolov8_feature_dim, n1)
        self.fc2 = nn.Linear(yolov8_feature_dim, n2)
        self.fc3 = nn.Linear(yolov8_feature_dim, n3)

    def forward(self, images, gt_boxes):
        # Рассмотрим создание промежуточного датасета для работы с изображениями и координатами
        class CustomDataset(torch.utils.data.Dataset):
            def __init__(self, images, gt_boxes):
                self.images = images
                self.gt_boxes = gt_boxes

            def __len__(self):
                return len(self.images)

            def __getitem__(self, idx):
                image = self.images[idx]
                gt_box = self.gt_boxes[idx]
                return (image, gt_box)

        custom_dataloader = torch.utils.data.DataLoader(CustomDataset(images, gt_boxes), batch_size=1)

        with torch.no_grad():
            for batch_idx, (image, gt_box) in enumerate(custom_dataloader):
                features, loss = self.yolov8(image, gt_box)

        logits1 = self.fc1(features)
        logits2 = self.fc2(features)
        logits3 = self.fc3(features)

        return {
            'logits1': logits1,
            'logits2': logits2,
            'logits3': logits3,
            'yolov8_loss': loss,
        }

Этот код иллюстрирует, как можно адаптировать YOLOv8 и обучить модель для выполнения дополнительных задач, используя промежуточные представления.

Применение (Application)

Для реализации предложенного подхода необходимо выполнить несколько важных шагов:

  1. Поиск промежуточных слоев: Прежде всего, вам необходимо определить слои модели YOLOv8, от которых вы хотите получить признаки. Это может потребовать глубокого понимания структуры модели и работы с её внутренней архитектурой.

  2. Изменение функции forward: Вам потребуется модифицировать функцию forward модели YOLOv8, чтобы она возвращала не только результаты детекции, но и признаки с этих промежуточных слоев. Это может потребовать модификации исходного кода модели или обёртывания её в дополнительный слой как показывалось выше.

  3. Создание кастомной архитектуры: После того, как вы получите доступ к промежуточным признакам, вы можете использовать их в собственных слоях модели, реализованных на основе задачи, которую вы решаете. Это может включать добавление полностью связанных слоев, слоев свертки или других компонентов, необходимых для вашей задачи.

  4. Обучение модели: Вам также потребуется разработать новый процесс обучения, который учитывает как потери YOLOv8, так и специфичные потери для ваших дополнительных задач. Это, возможно, потребует модификации стандартных функций обучения и оценки и работы с кастомными датасетами и загрузчиками данных.

Следует учитывать, что любые изменения в стандартной архитектуре могут влиять на производительность и эффективность модели, поэтому необходимо тщательно подходить к её тестированию и валидации.

Оцените материал
Добавить комментарий

Капча загружается...