В прошлом видео мы поговорили о том, как решаются задачи классификации изображений с помощью глубоких нейронных сетей. Давайте теперь обсудим, как решать такие задачи на практике. Представим, что у нас появилась такая необходимость, нужно классифицировать картинки. Прежде всего, нужно собрать базу изображений, про которые мы заведомо знаем, к какому классу они принадлежат. После этого нам нужно определиться с алгоритмом, которым мы будем классифицировать изображения, и при необходимости как-то эти картинки предобработать. Чуть позже мы поговорим о том, как это можно сделать. Ну и, собственно, после этого необходимо обучить нейронную сеть. Обсудим сначала, какие бывают библиотеки. Библиотек, на самом деле, огромное множество, часть из них перечислена на этом слайде, поговорим про каждую из них и обсудим плюсы и минусы. Библиотека torch7 написана на C++, все взаимодействие с клиентским кодом происходит через Lua. torch7 существует достаточно давно, и очень много готовых реализаций для разнообразных задач. Tensorflow. Относительно новая, очень удобная библиотека, из минусов: как раз из-за того, что она новая, очень часто возникает ситуация, что исторические реализации сделаны на других библиотеках, на tensorflow приходится что-то дописывать. С другой стороны, это делать часто очень просто, поэтому можно просто реализовать то, чего нет. Библиотека theano. Тоже существует достаточно давно, очень популярна в академических кругах. Ученые любят использовать ее для иллюстраций своих статей и для быстрых экспериментов. Из минусов: она достаточно низкоуровневая, и требуется много сил и опыта, чтобы понять, как с помощью нее работать с сетями. То есть она на самом деле про тензорные вычисления, а не про нейронные сети, и нужен просто некоторый опыт, чтобы с ней работать. Поэтому очень часто работают не непосредственно с theano, а используют некие обертки вокруг нее. Две из них — это keras и lasagna, и они как раз позволяют работать с theano в более удобном виде. Ну и, наконец, последняя библиотека, упомянутая на этом слайде — это caffe, это одна из первых библиотек для работы со сверточными нейронными сетями, она написана на C++, и из ее плюсов: то, что очень часто ее используют для продакшн-задач. Потому, что она на C++, потому, что часть про исполнение и применение нейронных сетей, она достаточно хорошо отделима. При выборе библиотеки стоит обращать на разнообразные факторы, приходится учитывать любовь разработчиков к тому или иному языку программирования: кто-то предпочитает Python, кто-то — Lua, ну и, наконец, хороший способ — просто попытаться посмотреть, кто решал похожую задачу и на каком фреймворке, и брать эту реализацию за основу. Поэтому это очень часто тоже определяет выбор библиотеки: если что-то уже готово на torch7, зачем пробовать что-то другое? В принципе, переключения между этими фреймворками не такие сложные, идеология у них похожа, поэтому если разобраться, как работает один из них, то другим воспользоваться тоже можно. Кроме того, существуют конвертеры моделей между этими фреймворками, это тоже облегчает переходы. Соответственно, выбирать библиотеку нужно, исходя из задач. Если никаких нет других предпочтений, я бы рекомендовал воспользоваться tensorflow. Из плюсов tensorflow: у него очень хорошая и богатая документация, очень много туториалов, поэтому он прекрасно подходит именно для знакомства с библиотеками про нейронные сети. Из плюсов еще у tensorflow достаточно хороший и простой python api, а само ядро библиотеки написано на С++. Поэтому, опять же, если говорить про внедрение в продакшн, есть отделимая часть, которая только про исполнение модели. Почему я говорю про внедрение в продакшн? Очень часто решение задачи классификации, оно разделяется на две части: мы подбираем модели, обучаем классификаторы, а потом уже обученные классификаторы куда-то внедряются, и для исполнения вот этих моделей, на самом деле, все библиотеки обучения нейронных сетей, они не нужны, нужна только та часть про исполнение. В некоторых библиотеках эту часть легко отделить, или можно взять целиком библиотеку, и она никак не влияет на производительность, а в некоторых библиотеках возникают некоторые проблемы. tensorflow здесь удобно в этом смысле сделана. Второй момент, который стоит обязательно учесть при решении практической задачи: нужно прежде всего посмотреть, не решал ли кто-то задачу до этого, и нет ли вообще готового решения. Готовое решение можно искать в так называемом зоопарке моделей, например, для библиотеки caffe есть единый репозиторий таких моделей, и можно просто попытаться найти там, что уже готово. То есть там есть несколько моделей, обученных для ImageNet, причем с лучшими результатами на момент обучения, есть другие прикладные задачи. Поэтому, возможно, ничего придумывать не нужно, и ваша практическая задача уже решена кем-то. Тогда берем готовую модель и используем ее на практике. Одна из самых часто используемых моделей — это модель, обученная оксфордской группой под названием VGG, ее устройство мы обсуждали в предыдущем видео, вот она есть готовая в том же зоопарке моделей. Из ее плюсов: у нее очень простая структура, она наиболее кроссплатформенная между библиотеками, поэтому поддерживается, скорее всего, любой библиотекой нейронной сети, которую мы будем использовать на практике, и у нее достаточно хорошие результаты. Она не самый лучший результат показывает на коллекции ImageNet, но входит в тройку. Есть готовая VGG-модель для библиотеки caffe, и, как я уже говорил, из этой библиотеки есть конвертеры в любую другую модель. Вернемся к нашей задаче. У нас стоит задача сделать классификацию на какие-то классы, которых нет в исходном ImageNet. Коллекцию мы собрали, и теперь у нас есть разные варианты. Можно взять нашу коллекцию и обучить нейронную сеть с нуля, так же, как это делали для решения задачи ImageNet. Но это сделать не так просто. Для этого нужно, во-первых, собрать очень большую коллекцию, это часто невозможно, потому что разметить миллион картинок — это очень трудоемкое занятие. Другой вариант — взять предобученную модель, из того же зоопарка моделей, например, взять VGG и дообучить ее на наших данных. Что значит дообучить? Опять же, тут есть несколько вариантов. Под дообучением можно понимать следующее: мы берем один из последних полносвязных слоев, выбрасываем самый последний слой, который отвечает за классы на ImageNet, заменяем его слоем с тем количеством классов, которые есть у нас, и дообучаем только превращение последнего полносвязного слоя в слой с выходом, который отвечает на вопрос, к какому классу принадлежит картинка. Плюс такого подхода в том, что это сделать очень просто, здесь достаточно небольшого числа картинок, чтобы произвести такое обучение, никакие большие мощности для этого не нужны, это можно делать на средненьком ноутбуке. И наконец, несмотря на то, что это достаточно простая процедура, мы обучаем только последний слой, это работает очень хорошо во многих случаях. Пример того, как дообучить последний слой с помощью библиотеки tensorflow, можно посмотреть по этой ссылке. Другой вариант: можно взять Уже готовую модель, обученную на коллекции ImageNet, проинициализировать нашу модель этой модели, опять же заменить последний слой и дообучать уже не только последний переход от полносвязного слоя к ответу, но и всю сеть целиком. Это более дорогостоящая операция, нужно больше вычислительных мощностей, но так как сеть уже предобучена на большой базе, это все равно намного быстрее и гораздо проще делается, чем обучать сеть с нуля. Выбор между этими вариантами зависит от задачи, от размера базы, которая у вас есть, и от желания получить то или иное качество. Но повторюсь, дообучение последнего слоя очень часто дает хорошие результаты, несмотря на то, что вычислений времени на эту операцию нужно гораздо меньше, чем на дообучение сети с нуля. Другой пример практической задачи, который использует предобученные нейронные сети, это поиск изображений. Мы можем взять VGG, или в данном случае мы поговорим про самую первую архитектуру AlexNet и будем считать, что один из последних слоев описывает изображение. Какие слои мы можем взять? Мы можем взять пятый сверточный слой, шестой полносвязный или седьмой полносвязный. И следующий вопрос, когда мы ищем изображение, картинки описываются вектором признаков одного из этих слоев. Теперь вопрос: как нам картинки сравнить, чтобы определить, похожа она или нет? Самый простейший вариант: просто сравнивать их по евклидовому расстоянию. Давайте посмотрим на пример. Здесь я представил несколько результатов работы поиска похожих. Самая левая картинка — это картинка-запрос. Справа идут, соответственно, ответы. Здесь представлены примеры того, какие результаты выдаются, если брать в качестве вектора, описывающего картинку, пятый, шестой или седьмой слой. Видно, что приемлемые результаты получаются в данном случае, только если брать седьмой слой. На втором и третьем месте мы видим результаты фотографии той же двери. Это достаточно сложный пример, поэтому не очень хорошо работает. Но тем не менее мы видим вот такие результаты. Соответственно, по ссылке можно найти подробное описание, из каких соображений стоит выбирать, какой слой использовать для поиска изображений, как сравнивать полученные вектора признаков между собой, и увидеть, какие комбинации работают лучше в тех или иных ситуациях. Хочется отметить следующий момент: мы использовали выходы последних слоев нейронной сети для дообучения классификатора для разнообразных задач, мы использовали эти же выходы для решения задач поиска изображений. Более того, мы обучали сеть изначально на коллекции ImageNet, а применяли на совершенно других коллекциях, в том числе коллекциях другой природы. Как показывает практика, эти методы хорошо работают, даже если применять данные подходы к картинкам совершенно другим, например, к картинкам из компьютерной графики. То есть, в ImageNet компьютерной графики нет или ее там очень мало, но тем не менее картинки ищутся достаточно хорошо при использовании этой сети. Что это всё означает? Эти факты говорят о том, что нейронные сети, предобученные на большой базе разнообразных изображений, достаточно хорошо описывают эти картинки, то есть, вот, предполученные признаки очень хорошо эти картинки описывают, и это достаточно фундаментальный и полезный результат. Это означает, что это представление можно использовать в совершенно разнообразных задачах. А еще это означает, что нейронные сети хорошо работают. В следующем видео мы посмотрим на другие задачи компьютерного зрения, и как нейронные сети помогают их решать.