23 февраля 2016 в 22:24

Использование сверточных сетей для поиска, выделения и классификации

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

segnet.png


Уже давно появилось желание изучить сверточные сети и узнать что-то новое, к тому же под рукой есть несколько последних Tesla K40 с 12Гб памяти, Tesla c2050, обычные видеокарты, Jetson TK1 и ноутбук с мобильной GT525M, интереснее всего конечно попробовать на TK1, так как его можно использовать практически везде, хоть на столб фонарный повесить. Самое первое с чего начал, это распознавание цифр, тут конечно удивить нечем, цифры уже давно неплохо распознаются сетями, но при этом постоянно возникает потребность в новых приложениях, которые должны что-то распознавать: номера домов, номера автомобилей, номера вагонов и т.д. Все бы хорошо, но задача распознавания цифр является лишь частью более общих задач.


Свёрточные сети бывают разные. Какие-то умеют только распознавать объекты на изображении. Какие-то умеют выделить прямоугольник с объектом (RCNN, например). А какие-то могут профильтровать изображение и превратить его в некоторую логическую картинку. Мне больше всего понравились последние: они самые быстрые и красивее всего работают. Для тестирования была выбрана одна из самых последних сетей на этом фронте — SegNet, подробнее можно прочитать в статье. Основная идея этого метода заключается в том, что вместо lable подается не число, а изображение, добавляется новый слой «Upsample» для увеличения размерности слоя.

layer {
  	name: "data"
  	type: "DenseImageData"
  	top: "data"
  	top: "label"
  	dense_image_data_param {
   		source: "/path/train.txt"	// файл обучения: image1.png  label1.png
    		batch_size: 4   			   
   		shuffle: true
  	}
}


В конце развернутое изображение и маска из lable подается в слой loss, где каждому классу назначается его вес в функции потерь.

layer {
    	name: "loss"
    	type: "SoftmaxWithLoss"
   	 bottom: "conv_1D"
   	 bottom: "label"
   	 top: "loss"
    	softmax_param {engine: CAFFE}
    	loss_param: {
    	  	weight_by_label_freqs: true
    	  	class_weighting: 1
    	  	class_weighting: 80
  	}
}


Правильно распознать цифры это лишь часть задачи распознавания номеров и далеко не самая сложная, надо для начала этот номер найти, затем найти где примерно располагаются цифры, а затем уже их распознавать. Довольно часто на первых этапа появляются большие ошибки, и в итоге получить высокую достоверность распознавания номеров довольно сложно. Грязные и затертые номера плохо детектируются и с большими погрешностями, шаблон номера плохо накладывается, в результате возникает много неточностей и сложностей. Номер может быть вообще нестандартным с произвольными интервалами и т.д.
Например, номера вагонов имеют множество вариаций написания. Если правильно выделить границы номера, то можно получить хоть 99.9% на каждой цифре. А если цифры переплетены? Если сегментация будет давать разные цифры в разных частях вагона?

title.jpg


Или, например, задача обнаружения автомобильного номера. Конечно, её можно решить и через Haar и через Hog. Но почему бы не попробовать другой метод и сравнить? Тем более когда есть готовая для обучения и разметки база?
На вход сверточной сети подается изображение с автомобильным номером и маска, на которой единицей залит прямоугольник с номером, а все остальное нулем. После обучения проверяем работу на тестовой выборке, где на каждое входное изображение сеть выдает такого же размера маску, на которой закрашивает те пиксели, где по ее мнению есть номер. Результат на рисунках ниже.

8284.jpg

8300.jpg

8338.jpg

8413.jpg

8417.jpg


Просмотрев тестовую выборку можно понять, что этот метод работает достаточно хорошо и почти не дает сбоев, все зависит от качества обучения и настроек. Так как у Vasyutka и ZlodeiBaal была размеченная база номеров, то обучились именно на ней и проверили насколько хорошо всё работает. Результат был не хуже каскада Хаара, а во многих ситуациях даже лучше. Можно отметить некоторые минусы:
  • не детектирует наклонные номера (их не было в обучающей выборке)
  • не детектирует номера, отснятые в упор (их тоже не было в выборке)
  • иногда не детектирует белые номера на чистых белых машинах (скорее всего тоже из-за неполноты обучающей выборки, но, что интересно — этот же глюк был и у каскада Хаара)

В целом проявление этих недостатков закономерно, сеть плохо находит то, чего не было в обучающей выборке. Если тщательно подойти к процессу подготовки базы, то и результат будет высокого качества.
Полученное решение можно применить для большого класса задач поиска объектов, не только автомобильных номеров. Хорошо, номер найден, теперь надо найти там цифры и распознать их. Это тоже не простая задача, как кажется на первый взгляд, нужно проверить множество гипотез их расположения, а что если номер не стандартный, не подходит под маску, то дело труба. Если автомобильные номера изготавливаются по госту и имеют определенный формат, то есть номера, которые могут быть написаны как угодно, от руки, с разным интервалом. Например, номера вагонов, пишутся с пробелами, единички занимают гораздо меньше места, чем другие цифры.
К нам на помощь снова спешат сверточные сети. А что если использовать туже самую сеть для поиска и распознавания. Будем искать и распознавать номера вагонов. На вход сети подается изображение, на котором есть номер и маска, где квадратики с цифрами заполняются значениями от 1 до 10, а фон заполняется нулем.

number mask.png


После не очень долгого обучения на Tesla K40 получен результат. Чтобы результат был более читабельным, разные цифры раскрашены в разные цвета. Определить номер по цветам большого труда уже не составит.

vagon in.png

vagon_res.png


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

3.png

3_res.png


А что если попробовать что-то более необычное, интересное и сложное, например выделение и сегментацию на медицинских изображениях. Для теста снимки флюорографии были взяты с открытой базы КТ и X-RAY снимков, по ним было проведено обучение сегментации легких и в результате удалось достаточно точно выделить интересующую область. На вход сети также подавалось исходное изображение и маска с нулем и единицей. Справа результат, который выдает сверточная сеть, а слева выделена та же область на изображении.

f1.jpg


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

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

Работает данный метод достаточно быстро, на видеокарте Tesla обработка одного снимка происходит за 10-15 мс, а на Jetson TK1 за 1.4 секунды. Про то, как запустить Caffe на Jetson TK1 и какой скорости обработки можно на нем достичь в этих задачах, наверно лучше посвятить отдельную статью.

P.S.
Обучение занимало не более 12 часов.
Размер базы по номерам 1200 изображений.
Размер базы по вагонам 6000 изображений.
Размер базы по легким 480 изображений.

1. SegNet
2. A Deep Convolutional Encoder-Decoder Architecture for Image Segmentation (pdf)
3. Haar
4. Hog
5. Сегментация легких на изображениях (pdf)
Автор: @Nikkolo
Recognitor
рейтинг 36,01

Комментарии (24)

  • +1
    А какой был размер обучающей выборки? Каково время обучения? Работает ли сеть для сегментации объектов у которых изменяется скейл\поворот?

    вот можете ознакомится еще с подходами
    https://github.com/mrgloom/Semantic-Segmentation-Evaluation
    • 0
      А какой был размер обучающей выборки?

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

      Каково время обучения?

      На одной тэсле за ночь обучается.

      Работает ли сеть для сегментации объектов у которых изменяется скейл\поворот?

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

      вот можете ознакомится еще с подходами
      github.com/mrgloom/Semantic-Segmentation-Evaluation

      Да, мы смотрели некоторые из них. В принципе в своей прошлой статье я частично рассказывал — https://habrahabr.ru/post/277069/
      • 0
        По автомобилям было порядка 1000 размеченных, по лёгким было порядка 500 размеченных. По поездам была сильно больше выборка, думаю в районе 3х тысяч.

        В обоих случаях выборки милипизерные по меркам Deep Learning… вы использовали фичи на чем-то типа ImageNet предобученные?
        • 0
          Нет, всё чисто по входным изображениям даже без их модификации дополнительных. Мы тоже были несколько в шоке, когда после обучения по 500 картинкам такую разметку лёгких получили:)
          Но, в принципе, авторы SegNet утверждают, что вот это они получили по выборке 5000 размеченных, без дополнительных их изменений:

          • 0
            Хм, если я правильно помню, то там первый кусок сети (тот что сворачивает картинку) — это ошметок от VGG16… или вы и его тоже обучали сами?
            • 0
              Ну, либо я слепой, либо всё же сами. Вот сеть которую использовали при обучении на одном из примеров: https://yadi.sk/d/yTQ6WhRkpPDKi. Никаких загрузок посторонних коэффициентов не вижу.
              Вот работа авторов — http://arxiv.org/pdf/1511.00561v2.pdf http://arxiv.org/pdf/1511.02680v1.pdf
              Да, первые 13 свёрточных уровней взяты из "VGG-16", но про предзагрузку весов нигде ни слова нет. Обучается всё одновременно.
        • 0
          Они милипизерные если из классифицировать 0 или 1, а здесь классификация пикселей, это увеличение данных для обучения в десятки раз.
          В легких было 250 в первой версии и 480 во второй.

          Никаких дополнительных коэффициентов, предобработки не делалось. Бралось Caffe, сеть и подготавливалась база для обучения.
          • 0
            Всё равно выглядит довольно удивительно. DeepLab обучают вроде как на большем числе сэмплов, да и переиспользуют часть весов от VGG16. Вообщем надо поковырять эту сетку...
      • 0
        Попробовал запустить код из туториала, но похоже эта сеть требует очень много памяти, вы не смотрели сколько памяти занимает в пике?
        • 0
          отдельно не смотрел, когда сеть конфигурируется, каффе вроде суммарный объем пишет и он был около 4 Гб кажется.
          • 0
            https://github.com/alexgkendall/caffe-segnet/issues/21

            Попробовал так же на CPU, тоже зафейлилось, но видимо по какой то другой причине, хотя вроде как все 8Gb памяти сожрало.

            Попробовал так же уменьшать размер изображения, но тогда надо подбирать параметры upsample_param, автоматом (как сверточные слои) это не работает.
        • 0
          Если оно запустилось на TK1, то сетка жрет не больше 1Гб памяти, т.к. больше там нету
          • 0
            При распознавании 480 Мб, Можно будет посмотреть сколько при обучении сеть выделяет памяти каким нибудь монитором для GPU.
            • 0
              Так можно тупо nvidia-smi запустить из стандартного пакета от nvidia. Оно показвыает какой процесс сколько памяти GPU потребляет, ну и другую полезную информацию о карточках.
              • 0
                Так интересно сколько в пике, а nvidia-smi даст только для текущего момента, если только дергать её через какие то короткие интервалы и логировать и потом парсить.
                • 0
                  По моим наблюдениям, caffe во время тренировки грузит карту стабильно и особых всплесков там не бывает.
          • 0
            Не знаю как это реализованно в caffe, но по логике чтобы прогнать через сетку изображение надо загрузить обученные веса + в каждый момент времени в памяти можно держать данные только для curr и prev слоя, т.е. должно получится сильно меньше чем в тренировочной фазе, еще учитывая то что в блобах в тестовой фазе и градиенты не надо хранить.
            • 0
              Могу ошибаться (но можно уточнить в коде), но вроде бы caffe при загрузке сети аллоцирует памяти столько, сколько требуется и в процессе работы с сеткой, пасмять не освобождает
  • 0
    А откуда брались тестовые выборки?
    • 0
      По номерам были у ZlodeiBaal а для легких часть скачали с сайта
      • 0
        Я в том плане что была ли разделена тестовая выборка от обучающей или тестовые примеры брались из обучающей выборки?
        • 0
          Конечно различная. Иначе некорректно.
          При этом по машинам она была принципиально разная — ту по которой обучались мы собирали руками, а то по чему тестировались — это всё что нам народ наприсылал сюда — https://habrahabr.ru/company/recognitor/blog/222539/
          • 0
            Ну по тексту это неясно, а примеров когда используют подмножество обучающей выборки я, к сожалению, видел не мало
            Поэтому хорошо когда явно указывается что было обучающей, а что тестовой выборкой
            • 0
              Бывает, но это скорее ради публикаций, ну или так просто от нечего делать.
              Интересно что на легких если подсунуть из обучающей выборки, то края даже получаются ломанные, как я вырезал вручную.

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

Самое читаемое Разработка