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

Это качественное исследование - вы также можете проверить высокотехнологичное исследование всех этапов этого проекта. Кроме того, в моем предыдущем проекте: Обнаружение полос с использованием OpenCV также есть видео на YouTube и вспомогательный пост на Medium.

Работа с нейронными сетями может быть болезненной не потому, что они плохие, а потому, что они такие новые. Я поделился с другом, как он приближает день разработки для Интернета с alert() операторами до того, как у нас появились отладчики в браузере! Нет абсолютно никакого качественного представления о том, насколько хорошо у нас дела.

Но вот в чем дело: раньше было еще хуже. Вам пришлось ждать несколько дней, прежде чем вы узнаете, повлияла ли эта настройка положительно или отрицательно. Сегодня, благодаря AWS EC2 и графическим процессорам, я смог быстро выполнять итерации и быстро учиться.

Заявление о проблеме

Мы используем Немецкую базу данных классификации дорожных знаков размером около 150 МБ и около 30 000 маркированных дорожных знаков. Цель проста - создать фрагмент кода, который может взять новое изображение и определить, какой это тип знака. Насколько точно мы можем это сделать?

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

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

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

Что вы делаете, когда сталкиваетесь с современными технологиями? Вы возродили технологию 20-летней давности - нейронные сети. В 2012 году AlexNet успешно применил архитектуру, аналогичную LeNet-5 1988 года, и выиграл соревнование, значительно опередив все предыдущие попытки. С тех пор нейронные сети стали де-факто методом классификации изображений.

Террор

Ладно, нет кода для написания, верно? Ой. Теперь нужно настроить миллиард параметров сети. Да, большинство из них будут настраиваться по мере того, как видят все больше и больше данных. Но вам все равно нужно настроить правильные гиперпараметры (параметры, которые влияют на другие параметры), чтобы они были правильными.

Я начал со стандартной архитектуры LeNet. Он имеет два сверточных слоя и три полностью связанных слоя. Все входные изображения имеют размер 32x32 с тремя каналами цвета.

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

  1. Образцы входных данных имели разные счетчики для каждого выходного класса. То есть было несколько примеров одного типа знаков и множество других. Как и все, я пытался увеличить изображения двумя способами - повернуть и сдвинуть. К сожалению, для меня это не сильно улучшило ситуацию. В конце концов, попытка уравновесить это вручную (написание кода вместо использования нейронной сети) несправедлива и дает неточную картину реального мира, при которой один тип знака появляется чаще, чем другие.
  2. Пытался нормализовать входной диапазон. Вместо цветов от 0 до 255 я попробовал от 0 до 1, от -0,5 до 0,5 и от 0,1 до 0,9. Хотя это определенно рекомендуется, я видел приличную производительность и без него. Я лично против внесения изменений в введенные данные вручную, подробнее об этом ниже.

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

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

Так что я пошел в кроличью нору обрезки сети. Я удалил один слой полной свертки и сделал слои FC шириной 128, 64 и 32. Произошла волшебная вещь - поскольку сеть была намного проще, она обучалась быстрее, поэтому я мог использовать ее для большего количества эпох. Это означало, что со временем я смогу поднять его еще выше. Я снова вернул 90%, когда использовал фильтры свертки большого размера.

Слой свертки

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

Для меня, вместо использования одного сверточного слоя с фильтром 15x15 для изображения 32x32, я мог бы использовать меньший фильтр 5x5 в двух слоях, что помогло сократить объем вычислений.

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

Полностью связанный слой

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

Я оставил его маленьким - 128/64/32 на трех слоях. Я понимаю, что сокращение их по мере их продвижения вынуждает модель придерживаться того, что имеет значение, и отпускать то, что не имеет значения.

Гиперпараметры

Мы много слышали о скорости обучения, и пока у вас достаточно данных, установка действительно небольшой скорости обучения всегда является правильным решением. В этом случае особо нечего настраивать. Однако размер партии интересен. Если вы установите его слишком маленьким, градиент не сможет сделать значимые предположения о том, куда идти дальше. Если вы установите слишком высокое значение, сеть будет видеть меньшее количество шагов общего градиентного спуска. Число, которое я часто видел здесь, - 128. Начните с этого. Третий параметр - размер эпохи, обычно он больше говорит о том, как долго вы хотите обучать сеть. В идеале вы должны написать небольшое условие if, которое проверяет, когда точность перестает улучшаться и перестает работать.

Вывод

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

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

Вы можете найти весь код этого проекта здесь:



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