Создайте и разверните собственную модель обнаружения объектов с помощью нескольких строк кода.

Введение

В этой статье я расскажу, как с помощью нескольких строк кода любой может создать свою собственную модель машинного обучения (ML) и развернуть ее в рабочей среде.

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

  1. Управление трафиком
  2. Раннее выявление рака
  3. Наблюдение
  4. Автоматизация процессов
  5. Список продолжается…

Итак, приступим!

Требования

Для этого упражнения вам не понадобится много.

  1. Учетная запись Google — мы будем использовать Colab для обучения нашей модели и подключим наш Google Диск для хранения учебных материалов.
  2. Python 3.X установлен на вашем компьютере
  3. pip или anaconda установлены на вашем компьютере
  4. Виртуальная среда Python — необязательно (рекомендуется)
  5. Докер установлен на вашем компьютере — опционально (только для деплоя в продакшене)

И это все!

*Colab — я знаю, что некоторые из вас сейчас могут подумать: «Зачем нам использовать Colab или любую другую платформу для обучения нашей модели, когда мы можем сделать это на наших компьютерах?». Ну правда в том, что вам не нужно его использовать. Просто обучать вашу модель быстрее, потому что Colab предоставляет вам возможность использовать GPU вместо CPU для обучения, что в x раз быстрее.

1) Подготовьте папку проекта

Итак, первое, с чего мы собираемся начать, — это создать папку проекта и установить необходимые пакеты.

*Отказ от ответственности — я занимаюсь разработкой для Mac OS. Если вы пользователь Linux, вы обнаружите, что все команды, которые я буду выполнять, работают и в Linux.

Мои друзья Windows, я рекомендую вам использовать любое программное обеспечение командной строки, которое воспроизводит Linux-подобные команды (GIT Bash, Linux Bash и т. д.)

Теперь давайте откроем терминал и создадим папку проекта:

mkdir object-detection
cd object-detection

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

virtualenv venv

Теперь мы хотим активировать нашу новую среду и начать ее использовать:

source venv/bin/activate

И вуаля, мы отсортировали папку нашего проекта.

Теперь все, что нам нужно, это установить несколько пакетов, используя pip или anaconda. В этом случае я буду использовать pip, но команда для anaconda почти идентична (вам просто нужно заменить pip на conda).

pip install detecto
pip install matplotlib
pip install flask
pip install flask-cors

Позвольте мне объяснить, что мы устанавливаем здесь:

  • Детекто — это, по сути, пакет, построенный поверх PyTorch и позволяющий нам с легкостью обучать модели компьютерного зрения.
  • maptolib — это пакет для построения графиков или, в нашем случае, вывода изображений с ограничивающими прямоугольниками.
  • flask — это, по сути, пакет, который позволит нам обернуть нашу модель API и предоставить ее нашим клиентам.
  • flask-cors — название говорит само за себя, этот пакет предназначен исключительно для включения запросов CORS к нашим API.

И мы закончили с установкой пакетов!

2) Подготовка набора обучающих данных

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

В нашем случае мы будем готовить наборы изображений и добавлять к ним коробки с метками, чтобы научить машину отличать интересующие объекты от остального мира.

Есть несколько различных инструментов, которые мы можем использовать для маркировки изображений, например:

  1. метка
  2. этикетка
  3. Инструмент аннотирования изображений VGG
  4. супервизор
  5. Этикетка
  6. и т.д..

Все вышеперечисленные инструменты дают аналогичный результат в виде xml-файла с координатами прямоугольников вокруг объектов и соответствующими метками.

Я буду использовать labelimg, вы можете найти его здесь.

Сначала нам нужно получить изображения для нашего набора данных. Для этой цели я загрузил изображения груш и клубники с сайта unsplash.com. Вы можете скачать мой набор данных ниже или перейти на unsplash.com и получить свои собственные изображения.

Архив изображений

После того, как вы запустите labelimg, вы должны увидеть такой экран.

Теперь нам нужно указать labelimg на папку, в которой хранятся изображения. Для этого нажмите «Открыть каталог» и выберите папку, в которой вы сохранили свои изображения (или изображения из моего набора данных).

Теперь пришло время пометить эти изображения!

Вы увидите список всех доступных изображений в правой нижней части экрана.

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

Это должно выглядеть примерно так:

Не забудьте сохранить каждый результат в той же папке, где хранится изображение.

Вот и все. Мы подготовили учебный материал.

3) Обучение нашей модели

Как я упоминал ранее, мы можем либо пойти дальше и обучить наш мод локально на наших компьютерах, либо мы можем использовать сервис Google Colab, который позволяет нам использовать графические процессоры бесплатно.

В моем примере я буду проводить обучение в Colab, но вы можете выполнить те же действия на своем компьютере.

Загрузка файлов на Google Диск, чтобы мы могли получить к ним доступ из Colab — пропустите этот шаг, если вы запускаете код на своем компьютере.

Я создал папку на своем Google Диске для проекта и назвал ее обнаружение объектов. Я также загрузил свой набор данных (изображения вместе с файлами меток ml) в новую папку в разделе «Обнаружение объектов/изображения».

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

Это должно выглядеть примерно так:

Теперь вернемся в папку обнаружения объектов и правой кнопкой мыши выберем опцию

Подробнее-› Google Colaboratory

Сначала мы хотим включить графические процессоры для нашего ноутбука Colab:

Правка -> Настройки ноутбука -> Аппаратный ускоритель и выберите GPU

Затем нам нужно подключить нашу среду Colab к нашему Google Диску.

Для этого мы подключим диск к нашему ноутбуку Colab.

from google.colab import drive 
drive.mount('/content/drive')

Давайте посмотрим, что мы сделали с этими двумя строками:

  1. импортированный пакетный диск из стандартной библиотеки colab
  2. и подключили наш диск Google к нашей среде

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

Вы успешно смонтировали диск!

5 строк кода для обучения нашей модели

Итак, теперь и в Colab, и в локальной среде мы можем начать писать 5 строк кода, которые позволят нам обучить нашу модель.

Во-первых, нам нужно установить библиотеку детектирования.

Внутри блокнота Colab мы можем сделать это так

!pip install detecto

добавьте его как код и запустите.

Для тех, кто просто запускает его локально, вы можете просто сделать:

pip install detecto

Внутри вашего терминала.

Далее мы добавим строки, которые фактически будут выполнять обучение.

from detecto import core, utils, visualize
dataset = core.Dataset('/content/drive/My Drive/Projects/objects-detection/images/')
model = core.Model(['pear', 'strawberry'])
model.fit(dataset, verbose=1, epochs=10)

Давайте посмотрим на каждую строку кода:

  1. Импортные модули детектора
  2. Создал набор данных из папки «images» (содержащей наши файлы JPEG и XML)
  3. Инициализирована модель для обнаружения наших пользовательских объектов (клубника и груша).
  4. Обучил нашу модель на наборе данных (подробный — это флаг, который позволяет нам отображать или скрывать ход обучения. Эпохи — это флаг, который позволяет нам указать, сколько раундов обучения мы хотим запустить на нашем наборе данных; по умолчанию — 10)

И это все. После запуска этого кода и ожидания некоторое время ваша модель будет обучена.

4) Тестирование нашей пользовательской модели

Теперь, когда обучение завершено, пришло время протестировать нашу модель.

image = utils.read_image('/content/drive/My Drive/Projects/objects-detection/validation/tiard-schulz-Zt3JBpD6afg-unsplash.jpg')
predictions = model.predict(image)
labels, boxes, scores = predictions
print(labels) 
print(boxes)
print(scores)

Давайте посмотрим на код построчно:

  1. Чтение изображения (замените путь к изображению на свой)
  2. Запуск нашей модели для поиска объектов на нашем изображении
  3. Извлечение меток объектов (найденных на изображении), ограничивающих рамок (расположение объектов) и оценок (вероятность предсказания)
  4. Печать этикеток, коробок и счетов для проверки

Вывод приведенного выше кода будет примерно таким (зависит от выбранного вами изображения):

['strawberry', 'strawberry', 'strawberry', 'strawberry', 'pear', 'pear', 'strawberry', 'pear', 'strawberry', 'pear', 'pear']
tensor([[2452.0452, 4442.3599, 3442.1204, 5482.8232],
        [2674.3801, 1145.6279, 3394.1516, 1775.2996],
        [1041.0961, 2159.0103, 1681.6707, 2878.9133],
        [1347.9767, 5104.0605, 2330.7642, 6038.6021],
        [2509.6628, 4483.7910, 3419.3689, 5410.0591],
        [1399.2555, 5132.0474, 2254.4937, 6039.6279],
        [3381.9873, 1852.3215, 4010.2600, 2570.3640],
        [ 468.3965, 2090.4729, 2573.8916, 3904.5371],
        [3676.3425,  610.6763, 4145.3604, 1329.3901],
        [3695.3311,  642.4642, 4156.2090, 1339.7739],
        [3406.6868, 1866.6627, 4016.7891, 2654.2966]])
tensor([0.5450, 0.4850, 0.4824, 0.3997, 0.1882, 0.1450, 0.1412, 0.1241, 0.1221,
        0.0999, 0.0965])

Итак, как вы видите выше, у нас есть 3 выхода:

  1. Показывает нам все метки объектов, которые были найдены на изображении.
  2. Распечатывает координаты для каждого обнаруженного объекта.
  3. Распечатывает баллы (вероятность) того, что эти объекты будут идентифицированы правильно.

Мы также можем взглянуть на само изображение с ограничивающими рамками, выполнив эту команду:

visualize.show_labeled_image(image, boxes, labels)

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

Добавьте этот код, чтобы применить порог:

import torch
import matplotlib.pyplot as plt
import matplotlib.patches as patches
lab = []
box = []
for i in range(len(scores)):
  if scores[i] > 0.3:
    lab.append(labels[i])
    box.append(boxes[i])
box = torch.stack(box)
fig,ax = plt.subplots(1)
ax.imshow(image)
for i in range(len(box)):
  ax.add_patch(patches.Rectangle((box[i][0],box[i][1]),box[i][2] - box[i][0],box[i][3] - box[i][1],linewidth=1,edgecolor='r',facecolor='none'))

plt.show()

Позвольте мне объяснить в нескольких словах, что происходит в коде выше. Сначала мы импортировали пакеты для работы с графиками и изображениями. Затем мы перебираем каждую оценку (вероятность), и только те, которые выше 0,3 (30%), мы добавляем в новый список, который мы будем использовать для построения наших полей. Отфильтрованный результат будет выглядеть примерно так:

И вот оно. Ваша собственная модель компьютерного зрения, способная находить клубнику и груши на ваших изображениях.

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

model.save('/content/drive/My Drive/Projects/objects-detection/model_weights.pth')

5) Производство нашей модели

Итак, теперь у вас есть модель, которую вы можете запустить из файла Python, заставить ее считывать изображения из локальной папки и показывать результаты. Но полезно ли это?

Большинство моделей, которые я создаю, предназначены не для чисто исследовательских целей, а для производственного использования нашими клиентами. Что это значит?

Это означает, что модель должна быть легко развертываемой и масштабируемой. Он должен иметь возможность связываться с нашими службами внутри и снаружи. Как мы этого достигаем?

В этом разделе статьи я покажу вам, как нашу модель можно легко преобразовать в микросервис API и развернуть ее в производственной среде с помощью Docker.

Для этой части я скопировал сохраненную модель (model_weights.pth) обратно на свой компьютер, так как нам не требуется никакого дополнительного тяжелого обучения.

Первое, что мы хотим сделать, это убедиться, что мы можем загрузить модель и обнаружить объекты локально.

Я написал этот код, чтобы сделать это:

import torch
import matplotlib.pyplot as plt
import matplotlib.patches as patches
from detecto import core, utils, visualize
model = core.Model.load('model_weights.pth', ['pear', 'strawberry'])
image = utils.read_image('assets/validation/plush-design-studio-WMvOeO-D8xo-unsplash.jpg')
predictions = model.predict(image)
labels, boxes, scores = predictions
lab = []
box = []
for i in range(len(scores)):
  if scores[i] > 0.3:
    lab.append(labels[i])
    box.append(boxes[i])
box = torch.stack(box)
fig,ax = plt.subplots(1)
ax.imshow(image)
for i in range(len(box)):
  ax.add_patch(patches.Rectangle((box[i][0],box[i][1]),box[i][2] - box[i][0],box[i][3] - box[i][1],linewidth=1,edgecolor='r',facecolor='none'))

plt.show()

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

Теперь нам нужно преобразовать нашу модель, чтобы она была доступна через вызов API.

Если вы не знакомы с флягой, здесь можно прочитать о том, как это работает.

Вот код после добавления оболочки фляги вокруг нашей модели:

# Importing packages
from detecto import core, utils, visualize
from flask import Flask, escape, request, jsonify, Response
import skimage
from flask_cors import CORS
import numpy as np
import torch
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.patches as patches
from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas
import io

# Initilaising app and wrapping it in CORS to allow request from different services
app = Flask(__name__)
CORS(app)

# Telling matplotlib to not create GUI Windows as our application is backend and doesn't require direct visulaization
matplotlib.use('agg')

# Loading our custom model
model = core.Model.load('model_weights.pth', ['pear', 'strawberry'])

# Adding new POST endpoint that will accept image and output image with bounding boxes of detected objects
@app.route("/detect", methods=['POST'])
def detect():
    
    # Accessing file from request
    file = request.files['image']
    image = skimage.io.imread(file)

    # Using model to detect objects
    predictions = model.predict(image)
    labels, boxes, scores = predictions

    # Applying threshold
    lab = []
    box = []
    for i in range(len(scores)):
        if scores[i] > 0.4:
            lab.append(labels[i])
            box.append(boxes[i])

    box = torch.stack(box)

    # Creating figure and displaying original image
    fig,ax = plt.subplots(1)
    ax.imshow(image)

    # Adding bounding boxes
    for i in range(len(box)):
        ax.add_patch(patches.Rectangle((box[i][0],box[i][1]),box[i][2] - box[i][0],box[i][3] - box[i][1],linewidth=1,edgecolor='r',facecolor='none'))
    
    # Preparing output
    output = io.BytesIO()
    FigureCanvas(fig).print_png(output)
    
    # Sending response as png image
    return Response(output.getvalue(), mimetype='image/png')

if __name__ == '__main__':
    app.debug = True
    app.run(host = '0.0.0.0',port=5000, threaded=True)

Теперь, если вы попытаетесь сделать POST-запрос на свой локальный хост с портом 5000 и прикрепленным изображением в качестве данных формы, вы получите обратно изображение с обнаруженными объектами.

Теперь, когда у нас есть микросервис API с нашей моделью, мы можем подготовить его к развертыванию.

Сначала нам нужно сохранить список всех зависимостей для этого проекта в один файл.

Мы можем сделать это, выполнив эту команду внутри папки проекта:

pip freeze > requirements.txt

Лучший способ выполнить развертывание — встроить свой код в образ докера. Это позволит вам легко развернуть вашу модель как в локальной среде, так и в облаке.

Здесь вы можете найти больше информации о Docker.

В той же папке, что и наша кодовая база, давайте создадим новый файл и назовем его «Dockerfile».

внутри этого файла напишите следующий код:

FROM jjanzic/docker-python3-opencv

ADD . /app

WORKDIR /app

RUN pip install -r requirements.txt

EXPOSE 5000

CMD [ "python", "./detect.py" ]

Давайте посмотрим, что происходит внутри этого кода:

  1. Мы используем образ Ubuntu с предустановленным python и opencv в качестве базового образа.
  2. Мы скопировали наш код в Docker Image
  3. Мы установили все зависимости проекта
  4. Мы открыли порт для прослушивания (5000)
  5. И, наконец, мы запускаем наш Python API в фоновом режиме.

Теперь давайте создадим наш образ Docker:

docker build -t object-detection .

Где -t — имя нашего изображения, а «.» означает, что мы собираем его из Dockerfile в этом каталоге.

После того, как наш образ был создан, мы можем развернуть его, запустив либо локально, выполнив следующую команду:

docker run -p 5000:5000 object-detection

«-p» — это то, как мы монтируем порт хоста к порту, указанному в образе докера.

Или разверните его на таких платформах, как Open-Shift, Kubernetes и т. д.…

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

И теперь он у вас есть. Полностью функциональная модель в производстве.

Поздравляем!

Дайте мне знать, как вы нашли эту статью, и если у вас есть какие-либо вопросы :)

Ссылки

Окончательная кодовая база доступна здесь