В части 4 мы увидели, насколько легко было использовать предварительно обученную версию модели Inception v3 для обнаружения объектов. В этой статье мы загрузим две другие известные сверточные нейронные сети (VGG19 и ResNet-152) и сравним их с Inception v3.

VGG16

Опубликованная в 2014 году модель VGG16, построенная из 16 слоев (исследовательская статья). Он выиграл конкурс ImageNet 2014, достигнув уровня ошибок при классификации объектов 7,4%.

ResNet-152

Опубликованная в 2015 году ResNet-152 представляет собой модель, построенную из 152 слоев (исследовательская статья). Он выиграл конкурс ImageNet 2015, достигнув рекордного количества ошибок при обнаружении объектов 3,57%. Это намного лучше, чем типичный коэффициент ошибок, связанных с человеческим фактором, который обычно составляет 5%.

Скачивание моделей

Пора еще раз посетить модельный зоопарк. Как и в случае с Inception v3, нам нужно загрузить определения и параметры модели. Все три модели были обучены по одним и тем же категориям, поэтому мы можем повторно использовать наш файл synset.txt.

$ wget http://data.dmlc.ml/models/imagenet/vgg/vgg16-symbol.json
$ wget http://data.dmlc.ml/models/imagenet/vgg/vgg16-0000.params
$ wget http://data.dmlc.ml/models/imagenet/resnet/152-layers/resnet-152-symbol.json
$ wget http://data.dmlc.ml/models/imagenet/resnet/152-layers/resnet-152-0000.params

Загрузка моделей

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

Все, что нам нужно изменить, это название модели :) Давайте просто добавим параметр в наши функции loadModel () и init ().

def loadModel(modelname):
        sym, arg_params, aux_params = mx.model.load_checkpoint(modelname, 0)
        mod = mx.mod.Module(symbol=sym)
        mod.bind(for_training=False, data_shapes=[('data', (1,3,224,224))])
        mod.set_params(arg_params, aux_params)
        return mod
def init(modelname):
        model = loadModel(modelname)
        cats = loadCategories()
        return model, cats

Сравнение прогнозов

Сравним эти модели на паре изображений.

*** VGG16
[(0.58786136, 'n03272010 electric guitar'), (0.29260877, 'n04296562 stage'), (0.013744719, 'n04487394 trombone'), (0.013494448, 'n04141076 sax, saxophone'), (0.00988709, 'n02231487 walking stick, walkingstick, stick insect')]

Хорошая работа в двух верхних категориях, но остальные три совершенно неверны. Похоже, вертикальная форма микрофонной стойки смутила модель.

*** ResNet-152
[(0.91063803, 'n04296562 stage'), (0.039011702, 'n03272010 electric guitar'), (0.031426914, 'n03759954 microphone, mike'), (0.011822623, 'n04286575 spotlight, spot'), (0.0020199812, 'n02676566 acoustic guitar')]

Очень высоко в высшей категории. Остальные четыре значимы.

*** Inception v3
[(0.58039135, 'n03272010 electric guitar'), (0.27168664, 'n04296562 stage'), (0.090769522, 'n04456115 torch'), (0.023762707, 'n04286575 spotlight, spot'), (0.0081428187, 'n03250847 drumstick')]

Результаты очень похожи на результаты VGG16 для двух верхних категорий. Остальные три - неоднозначная картина.

Давай попробуем другую картинку.

*** VGG16
[(0.96909302, 'n04536866 violin, fiddle'), (0.026661994, 'n02992211 cello, violoncello'), (0.0017284016, 'n02879718 bow'), (0.00056815811, 'n04517823 vacuum, vacuum cleaner'), (0.00024804732, 'n04090263 rifle')]
*** ResNet-152
[(0.96826887, 'n04536866 violin, fiddle'), (0.028052919, 'n02992211 cello, violoncello'), (0.0008367821, 'n02676566 acoustic guitar'), (0.00070532493, 'n02787622 banjo'), (0.00039021231, 'n02879718 bow')]
*** Inception v3
[(0.82023674, 'n04536866 violin, fiddle'), (0.15483995, 'n02992211 cello, violoncello'), (0.0044540241, 'n02676566 acoustic guitar'), (0.0020963412, 'n02879718 bow'), (0.0015099624, 'n03447721 gong, tam-tam')]

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

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

Сравнение технических характеристик

Вы найдете обширные эталонные тесты моделей в исследовательских статьях, таких как this one. Для разработчиков, вероятно, двумя наиболее важными факторами будут:

  • сколько памяти требуется для этой модели?
  • насколько быстро он может предсказывать?

Чтобы ответить на первый вопрос, мы могли бы сделать обоснованное предположение, посмотрев на размер файла параметров:

  • VGG16: 528MB (около 140 миллионов параметров)
  • ResNet-152: 230 МБ (около 60 млн параметров)
  • Inception v3: 43 МБ (около 25 миллионов параметров)

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

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

t1 = time.time()
model.forward(Batch([array]))
t2 = time.time()
t = 1000*(t2-t1)
print("Predicted in %2.2f millisecond" % t)

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

*** VGG16
Predicted in 0.30 millisecond
*** ResNet-152
Predicted in 0.90 millisecond
*** Inception v3
Predicted in 0.40 millisecond

Подводя итог (применяется стандартный отказ от ответственности):

  • ResNet-152 имеет лучшую точность среди всех трех сетей (на сегодняшний день), но он также в 2–3 раза медленнее.
  • VGG16 самый быстрый - из-за небольшого количества слоев? - но у него самое высокое использование памяти и худшая точность.
  • Inception v3 работает почти так же быстро, обеспечивая лучшую точность и наиболее консервативное использование памяти. Этот последний пункт делает его хорошим кандидатом для стесненных сред. Подробнее об этом в части 6 :)

На сегодня все! Полный код ниже.

Следующий:

  • Часть 6: обнаружение объектов в реальном времени на Raspberry Pi (и он тоже говорит!)