Летом я работал над улучшением возможностей Flux в области компьютерного зрения. Мое конкретное направление работы заключалось в добавлении новых моделей в зоопарк моделей Flux, внедрении некоторых новых функций, а также улучшении скорости предыдущих слоев. >. В частности, я добился 18-кратного ускорения для Convolutions и примерно 3-кратного для BatchNorm.

Я перечисляю все основные PR, которые я сделал во время этого проекта. Некоторые из них объединены, некоторые не объединены, а некоторые даже находятся в стадии разработки. Мы обсуждаем только основные PR, оставляя без внимания исправления ошибок и небольшие патчи. Так вот они

  1. Добавлена ​​поддержка более эффективной привязки CUDNN для сверток
  2. Реализует оболочку для CUDNN BatchNorm и связывает ее с Flux
  3. Позволяет Flux поддерживать глубинные свертки в ЦП
  4. Поддержка выделения рабочего пространства в CUDNN Convolutions
  5. Добавлены обертки для функций активации CUDNN и некоторые функции для эффективных сверток
  6. Поддержка выделения рабочего пространства в CUDNN Convolutions
  7. Добавлены обертки для функций активации CUDNN и некоторые функции для эффективных сверток
  8. Добавить поддержку Pure Julia Depthwise Convolutions и их градиентов
  9. Добавить модели VGG в модельный зоопарк
  10. Демонстрация использования остаточных сетей в качестве классификатора сцен
  11. Поместите популярные модели Imagenet Winning, такие как Inception Nets, в модельный зоопарк

В ходе этого проекта были разработаны следующие новые пакеты.

  1. FastStyleTransfer.jl
  2. МУРА.jl
  3. Тесты глубокого обучения
  4. CNNVisualize.jl
  5. DeepDream.jl

Пошаговое руководство по запросам на слияние

Давайте рассмотрим эти изменения одно за другим.

Добавьте оболочку для CUDNN BatchNorm.

Flux в настоящее время не имеет выделенного ядра графического процессора для BatchNorm. BatchNorm — один из самых важных слоев нейронных сетей, и они ускоряют обучение, имея дело со сдвигом внутренней средней ковариации. До сих пор мы использовали код ЦП Flux для BatchNorm (который, очевидно, будет медленным). Таким образом, этот PR направлен на решение этой проблемы путем включения слоя CUDNN Batchnorm Layer и его интеграции с Flux AD. Некоторые основные улучшения скорости (и потребления памяти): 1.860 s (1367 allocations: 50.92 KiB) —> 2.782 ms (276 allocations: 10.38 KiB). Я сравниваю общее время (вперед и назад) BatchNorm(100) для массива размером 224 * 224 * 100 * 10. Этот PR еще не объединен. Его необходимо обновить до версии Julia 1.0 (которая поддерживается мастером Flux) перед слиянием.

Ускорьте свертки CUDA во Flux

Я провел тесты между Flux и Pytorch (читайте дальше, чтобы узнать об этом больше). Мы профилировали нейронные сети и обнаружили некоторые проблемы в Flux Conv Layer. Основным узким местом было broadcasted bias addition, которое мы выполняли. Поэтому вместо использования broadcasted bias addition мы используем cudnnAddTensor для версии CUDNN до 7.1. Для всего, что выше 7.1, мы переходим к использованию cudnnConvolutionBiasActivationForward с активацией всегда identity и, наконец, диспетчеризируем другие активации. Основные улучшения скорости с использованием этого обновления отражены в репозитории DeepLearningBenchmarks. Кроме того, этот PR зависит от PR CuArrays, поэтому его нельзя объединить, пока не будут объединены CuArrays. Кроме того, для адаптации к Julia 1.0 требуются обновления.

Собственные свертки глубины Джулии в Flux и NNlib

Глубоко разделяемые свертки жизненно важны для мобильных приложений глубоких нейронных сетей. MobileNets и Xception Net напрямую используют эту форму свертки. Поэтому очень важно, чтобы библиотека глубокого обучения поддерживала такие свертки из коробки. Во-первых, это включало реализацию процессорной версии кода в NNlib. Затем нам просто нужно подключить свертки по глубине к Flux AD. Стандартная поддержка также позволяет легко определять некоторые из добавляемых моделей в Metalhead.jl и model-zoo. В рамках будущей работы над этой темой для этого алгоритма должна быть привязка CUDNN.

Добавлена ​​поддержка дополнительных алгоритмов свертки CUDNN.

Существует множество алгоритмов свертки. Все они используют свойства input tensor и filter tensor и имеют очень специализированные процедуры, разработанные для эффективных сверток. К счастью, в CUDNN встроены эти специально разработанные процедуры свертки. Поэтому нам нужно интегрировать его непосредственно в CuArrays и предоставить его API для использования из других пакетов, таких как Flux. Обертки для простой операции свертки были предварительно написаны на CuArrays. Так что нам нужно только создать обертки для workspace allocation. Этот PR добавляет необходимые оболочки и изменяет определения функций свертки, чтобы предоставить API для algorithm change. Таким образом, для конечного пользователя единственным изменением будет изменение аргумента ключевого слова algo.

Добавьте оболочки для дополнительных функций свертки и активации.

При тестировании Flux Convolution Code мы выяснили некоторые основные узкие места, возникающие из-за Backward Pass for Convolution Bias. Следовательно, естественным выбором было обернуть функцию CUDNN, которая эффективно вычисляет градиент для смещения. Также мы смогли обернуть функцию для одновременного применения activation и adding bias. Чтобы использовать эту функцию, cudnnConvolutionBiasActivationFunction нам нужно было обернуть функции Activation Forward и Backward Pass. Теперь давайте посмотрим, каких улучшений скорости мы достигли с этим обновлением.

Недавно в Metalhead были добавлены некоторые модели, такие как GoogleNet и Resnet (особая благодарность Аюшу Шридхару [@ayush1999] за его работу над ONNX.jl). Однако этот код создается автоматически и не обязательно читается человеком. Более того, единственное, что мы могли делать с этими моделями, — это делать прогнозы. Мы не можем использовать его для чего-то вроде извлечения признаков. Поэтому мы портировали некоторые мои модели из модельного зоопарка и вручную загружали в него веса. Для более подробного использования Metalhead перейдите здесь.

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

Эта часть проекта все еще находится в зачаточном состоянии. Большая часть работы для этого сделана (но в основном она разбросана по модельному зоопарку). Зоопарк моделей, по сути, предназначен для того, чтобы пользователи могли импортировать все виды моделей в свой код. Модели могут быть необученными (в настоящее время таковыми являются большинство моделей). Таким образом, основная мотивация заключается в том, что если мы хотим обучить модель ResNeXt, нам не нужно переопределять что-то, что уже кем-то сделано. Мы должны иметь возможность загрузить модель без каких-либо усилий.

julia> model = VGG19() # This fetches an untrained VGG19 model 
julia> model_trained = trained(VGG19) # Get the trained VGG19 model. This is the same as previously calling VGG19() 
julia> trained(VGG11) # We get an error as we don't currently have a trained VGG11 model but VGG11() works fine

Краткое описание пакетов

Этот пакет предоставляет простой API для генерации мечты на нужном изображении. Вам нужно предоставить изображение, выбрать, какой тип сна вы хотите и какую модель использовать. Этот пакет опирается на Flux и Metalhead для своих обученных моделей.

Изображение выше было сгенерировано с использованием guided deepdream.

CNNVisualize.jl

За прошедшие годы было разработано несколько алгоритмов визуализации для понимания функционирования нейронных сетей. Этот пакет предназначен для реализации таких алгоритмов. Большинство из них будут работать в Metalhead «из коробки». В настоящее время этот пакет находится в стадии разработки, однако большая его часть завершена.

Вот небольшая демонстрация пакета

FastStyleTransfer.jl

Это реализация документа Потери восприятия для передачи стиля в реальном времени и сверхразрешения. Есть явные отклонения от бумаги. Мы использовали лучшие реализации слоев, которые на данный момент доступны во Flux. Что касается точной архитектуры, то она все еще находится в разработке. Мы предоставляем три предварительно обученные модели с этим пакетом. API был максимально простым.

Ниже небольшой пример переноса стиля на MonaLisa

Обзор работы, проделанной в GSoC 2018

Как вы можете видеть из приведенных выше PR-описаний, большая часть моей работы была связана с бенчмаркингом моделей Flux и повышением скорости везде, где это возможно. Первоначальной частью моей работы было добавление новых моделей компьютерного зрения в модельный зоопарк Flux. Поэтому мы добавили такие модели, как VGGNets, ResNets, DenseNets и т. д., в модельный зоопарк Flux. Кроме того, мы смогли перенести некоторые из этих моделей в пакет Metalhead, специально разработанный для решения проблем компьютерного зрения. После множества экспериментов и помощи некоторых людей из сообщества JuliaLang мы смогли исправить некоторые проблемы с точностью, с которыми мы столкнулись. Далее мы приступили к разработке пакета для выполнения FastStyleTransfer. Это позволяет пользователям легко train создавать свои модели, а также stylize изображения. Мы также смогли обучить некоторые модели плотной сети и воссоздать результаты статьи MURA.

Следующим шагом было выполнение тестов для текущих реализаций Flux и устранение узких мест везде, где это возможно. Итак, мы написали сценарии бенчмаркинга для Flux и Pytorch и выполнили сравнение между ними. Впервые оказалось, что Pytorch намного быстрее Flux. Однако нам удалось найти причину такой низкой скорости. Оказалось, что это из-за отсутствия специализированного ядра для широковещательного добавления и его обратного прохода. Поэтому немедленным решением было wrap some of the CUDNN Functions и интегрировать их с Flux. Это на самом деле значительно сокращает время, затрачиваемое этими слоями. В настоящее время мы на одном уровне с Pytorch по времени для каждого из отдельных слоев.

Опыт работы в ЮлияКОН

Мне удалось побывать на JuliaCon 2018 в Лондоне. Спасибо The Julia Project и NumFOCUS за финансирование этой поездки. У меня была возможность представить плакат о работе, которую я проделал во время GSoC. Это была первая конференция, на которой я присутствовал, так что это был действительно уникальный опыт. Я смог поделиться своей работой с другими людьми и даже получил несколько ценных советов по этому поводу. Кроме того, я обнаружил несколько новых интересных проектов с открытым исходным кодом, в которые я хотел бы внести свой вклад в будущем. Наконец, всегда приятно встретить людей, с которыми я общался в Slack.

Зачем использовать Julia и Flux для глубокого обучения?

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

Просто подумайте о реализации стандартной модели Computer Vision в одном из популярных фреймворков, таких как Pytorch или Tensorflow. Это довольно просто, верно? Просто вызовите необходимые слои с помощью их API, и все готово. Теперь представьте, что вам нужно определить что-то, чего нет в их стандартной библиотеке. Вам нужно сначала написать свой пользовательский слой (как прямой, так и обратный проходы, если вам интересно) на C++, и если это не достаточно сложно, вы можете определить ядро ​​графического процессора для этого кода в CUDA C. Теперь вы интегрируете этот слой (очевидно, на Python) с Pytorch или Tensorflow в соответствии с их конкретным API. И удачи в отладке SegFaults, которые вы получаете.

Теперь давайте посмотрим, как это сделать во Flux. Вы начинаете с написания слоя на Julia и его версии для графического процессора CUDA с помощью CUDAnative (приветствуем Tim Besand [@maleadt] за его отличную работу). Что касается интеграции в Flux AD, вы просто используете макрос @grad. Это так просто!

Одна из жалоб, которые у вас могут возникнуть, — это отсутствие большого количества обученных моделей. Однако благодаря ONNX.jl и Keras.jl проблема более или менее решена. Оба они являются работой Аюш Шридхар. Используя их, вы можете использовать модели, обученные с помощью Pytorch или CNTK, если они хранятся в формате ONNX. Кроме того, теперь у вас есть широкий спектр моделей обучения с подкреплением, таких как AlphaGo.jl (от Теджана Кармали), написанных с использованием Flux, помимо моделей компьютерного зрения в model-zoo. и Metalhead.jl.

Будущие работы по проекту

Этот проект сильно отклонился от того, что я изначально предложил, но в основном во благо. Вещи, реализованные в рамках этого проекта, несомненно, должны помочь в более быстром обучении глубоких нейронных сетей во Flux, а также помочь в создании более сложных моделей с использованием Flux. При этом интересным моментом для будущего этого проекта будет завершение добавления моделей классификации объектов в Metalhead, как это предлагается в этом выпуске. Еще одна интересная вещь — несколько моделей Обнаружения объектов, созданных с помощью Flux, в одном месте. Кроме того, мы должны продолжать устранять текущие узкие места, которые еще предстоит устранить. Мы должны продолжать добавлять тесты в DeepLearningBenchmarks, что жизненно важно для выявления узких мест.

Благодарности

Во-первых, я должен поблагодарить Google за организацию Google Summer of Code, которая дала мне прекрасную возможность поработать с сообществом Open Source. Также я благодарю NumFOCUS и JuliaLang за то, что они выбрали меня для работы над этим проектом. Затем я хотел бы поблагодарить своих наставников Вирал Шаха и Майн Иннес за их постоянную поддержку и руководство в моем проекте. Наконец, позвольте мне поблагодарить великолепное сообщество JuliaLang за то, что оно развеяло мои сомнения и стало прекрасным источником знаний.

Первоначально опубликовано на сайте avik-pal.github.io 13 августа 2018 г.