В этом руководстве мы будем использовать двоичную логистическую регрессию для обучения классификатора красного цвета в Python.

Чтобы руководство было относительно коротким, я разделил его на две части - Часть I. Создание цветового классификатора с использованием логистической регрессии. Часть II: Обнаружение знаков остановки с использованием двоичной маски, полученной из цветового классификатора.

Первым шагом любой проблемы машинного обучения является доступ к хорошему набору обучающих данных - в нашем случае нам требуются изображения, состоящие только из красного цвета (положительные образцы), и изображения, содержащие цвета, отличные от красного (отрицательные образцы). Мне удалось создать набор данных, который содержал разнообразный пул красных изображений, извлеченных из самих знаков остановки при различных условиях освещения. Эти вариации освещения позволят нам обучить относительно надежный классификатор цветов. Цвета, отличные от красного, были включены в обучающую выборку как отрицательные образцы. Вы можете найти набор данных здесь, на моем GitHub: https://github.com/MariaHarris24/StopSign_detection.

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

Цветовая сегментация как проблема классификации

Логистическая регрессия - это дискриминативная модель, то есть она моделирует условное распределение вероятностей P (y | x; w) с помощью сигмоидной функции:

Здесь «x» относится к индивидуальному значению пикселя, а «y» - это скаляр (-1 или 1), это метка, связанная с пикселем x, а «ω» - это параметр веса, который необходимо усвоить во время тренировки.

Ниже вы можете увидеть математическое и графическое представление сигмовидной функции:

Сигмоидальная функция имеет свойство преобразования непрерывных значений в распределение Бернулли (дискретное), которое, в свою очередь, может использоваться для целей классификации. Из приведенного выше графика видно, что для больших значений k функция выдаст 1 и 0 для меньших значений k. Следует отметить, что сигмоид используется, когда мы имеем дело с классификацией между двумя классами, то есть двоичной классификацией (что является нашим случаем). Для более чем двух / многоклассовой классификации используется функция softmax.

Теперь, когда мы выработали интуитивное понимание того, как работает сигмоид, теперь нам нужно оценить весовой параметр 'ω' так, чтобы мы могли максимизировать логарифм условной вероятности P (y | x; ω) - математически это можно записать так:

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

Для приведенного выше уравнения оптимальное значение «ω» может быть достигнуто с помощью градиентного спуска. Поскольку градиентный спуск включает минимизацию функции; поэтому мы будем использовать отрицательное log p (y | x; ω) в качестве функции для минимизации - это математически эквивалентно приведенному выше уравнению. Теперь мы можем записать уравнение градиентного спуска для нашей задачи следующим образом:

Быстрая подготовка к градиентному спуску; это метод оптимизации, который можно использовать для итеративного поиска минимума функции. Этот минимум может быть или не быть глобальным минимумом. Интуиция, лежащая в основе градиентного спуска, заключается в том, что мы берем производную функции, минимум которой мы пытаемся найти. Эта производная, по сути, является касательной / наклоном к функции, и наша цель - двигаться в направлении, противоположном этому, то есть в направлении отрицательного градиента, пока мы не достигнем минимума. Скорость, с которой происходит сходимость, диктуется параметром, называемым скоростью обучения «α» - он определяет размер шага (величину, которую мы перемещаем) во время каждой итерации.

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

Импорт набора данных:

Во-первых, нам нужно загрузить и изменить наши обучающие данные. Ниже вы можете найти код функции, которая будет читать изображения из указанной папки и складывать их в матрицу Nx3. Здесь отдельные три канала (RGB) будут служить функциями, а значения пикселей каждого из трех каналов RGB будут заполнять пространство функций - вот почему у нас есть матрица Nx3. Более того, функция также будет генерировать соответствующие метки для каждого значения пикселя: 1 для красного и -1 для других цветов. Обязательно передайте правильное значение для параметра «label_val», поскольку он определяет, какое значение будет занимать метка, соответствующая пикселю.

Обучение:

После загрузки обучающих данных следующий шаг включает обучение классификатора цветов с использованием градиентного спуска (см. Код ниже). Функция возвращает вектор (3x1) параметра «ω». Мы будем использовать этот параметр для описания границы нашей классификации, описанной в разделе тестирования. Вы можете изменить скорость обучения и количество итераций. Для проверки сходимости я нанес на график разницу между предыдущей омегой и текущей. Если абсолютная разница между ними очень меньше за пару итераций, это означает, что мы, скорее всего, получили минимум. Тем не менее, не переусердствуйте с данными, обучая классификатор большому количеству итераций.

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

Тестирование:

Логистическая регрессия генерирует линейную границу решения, которая описывается уравнением x.ω = 0 (скалярное произведение x и ω). Следовательно, для x.ω≥0, т. Е. Значения пикселей на или выше линейной границы будут предсказаны как красный положительный пиксель, а для x.ω ‹0, пиксель будет предсказан как красный отрицательный пиксель. Лучше всего это можно понять, обратившись к приведенной ниже схеме двух функций:

Код для этого шага довольно прост. Мы отправляем тестовое изображение и ω в функцию, которая выполняет скалярное произведение между ними, а затем классифицирует пиксели в соответствии с критериями скалярного произведения, упомянутыми ранее. На этапе классификации мы будем присваивать значение 255 пикселям, которые прогнозируются как красные, и 0 - пикселям, которые прогнозируются как не красные - таким образом мы получим нашу двоичную маску. Код этой функции приведен ниже:

Исходное изображение и его двоичная маска показаны ниже.

Как видите, наш классификатор умеет сегментировать красные пиксели. Затем нам нужно использовать какие-то критерии обнаружения формы, которые могут различать форму знака остановки. Об этом мы поговорим во второй части. Спасибо за чтение!