Поиск по сайту Поиск

Стэнфордский курс: лекция 8. ПО для глубокого обучения

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

Предыдущие лекции:

Лекция 1. Введение
Лекция 2. Классификация изображений
Лекция 3. Функция потерь и оптимизация
Лекция 4. Введение в нейронные сети
Лекция 5. Свёрточные нейронные сети
Лекция 6. Обучение нейросетей, часть 1
Лекция 7. Обучение нейросетей, часть 2

GPU vs CPU

Если вы когда-нибудь пробовали собирать компьютер, то наверняка знаете, что внутри него находится множество компонентов. «Сердцем» любой вычислительной машины является центральный процессор (CPU) — небольшой чип, обычно спрятанный под охлаждающим вентилятором в центре материнской платы. Графический процессор (GPU) отвечает за обработку изображений. Иногда графическое ядро может быть интегрировано в CPU, поэтому не совсем корректно ставить знак равенства между GPU и видеокартой.

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

Компьютер изнутри

Одна из главных тем споров в IT-сфере — предпочтение оборудования или ПО того или иного производителя. Наверняка вы сталкивались с дебатами «текстовый редактор Vim против Emacs», «процессоры Intel против AMD», «видеокарты NVIDIA против Radeon». Изначально GPU создавались для рендеринга компьютерной графики, поэтому те, кто часто играет в компьютерные игры, наверняка могут высказать своё мнение о том или ином производителе графических карт. Мы в основном будем фокусироваться на GPU от NVIDIA ввиду их большей распространённости в области машинного обучения.

В чём же разница между CPU и GPU? И то, и другое — вычислительные единицы, выполняющие программы и произвольные инструкции. Но, тем не менее, они существенно отличаются друг от друга.

CPU состоят из небольшого числа ядер, в настоящее время обычно не превышающего десяти. Технология гиперпоточности (hyperthreading) позволяет каждому ядру работать в несколько потоков. Упрощённо говоря, CPU с 10-ю ядрами и 20-ю потоками может выполнять 20 задач одновременно. Это не так много, но на самом деле потоки CPU очень мощные, и одна их инструкция способна включать множество процессов. 

С GPU дела обстоят иначе. Они содержат в себе тысячи вычислительных ядер, но каждое из них работает на гораздо меньшей тактовой частоте, чем CPU (тактовая частота показывает, сколько операций в секунду выполняет процессор). Ядра GPU не могут работать независимо друг от друга, в отличие от CPU. Они распараллеливают задачи и делают их одновременно. Поэтому сравнивать производительность GPU и CPU по числу ядер не имеет смысла — они предназначены для совершенно разных целей.

Новое поколение GPU выходит примерно раз в полтора года. Поэтому опытные исследователи активно переходят в облако и постоянно имеют доступ к новейшим графическим ускорителям. За их обновление, администрирование и поддержку отвечает провайдер, а клиенты могут сэкономить приличные суммы. Например, использование сервера с топовой на сегодняшний день GPU NVIDIA Tesla V100 в REG.RU выйдет дешевле, чем покупка аналогичной видеокарты в магазине, особенно если она нужна вам на ограниченный срок.

Ещё одно существенное отличие между CPU и GPU — использование памяти. CPU в основном расходует оперативную память системы (ОЗУ или RAM), размер которой достигает нескольких десятков гигабайт. GPU имеет собственную встроенную видеопамять (VRAM). В графическом ядре запись и чтение из памяти осуществляются последовательно — например, при обработке пикселей они будут считываться друг за другом, в то время как в CPU доступ к памяти организован более сложным образом.

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

Как мы помним, в свёрточных архитектурах умножение матриц происходит постоянно, поэтому GPU — незаменимый инструмент для обучения нейросетей.

Для того, чтобы запускать код прямо на GPU, NVIDIA разработала ускорители CUDA. Написание CUDA-кода — достаточно сложный процесс, требующий глубокого погружения в архитектуру графических ускорителей. Поэтому для удобства можно использовать более высокоуровневые библиотеки: cuBLAS, cuFFT, cuDNN и другие. Также существует фреймворк openCL, оптимизированный для любых GPU (даже от AMD). Но он, как правило, показывает более медленные результаты.

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

Фреймворки для глубокого обучения

Число различных программ и библиотек для глубокого обучения растёт с каждым годом. К самым известным относятся TensorFlow, Caffe, PyTorch, также развиваются Paddle от Baidu, CNTK от Microsoft, MXNet от Amazon и многие другие. И хотя каждая библиотека содержит свои отличительные функции, некоторые особенности присутствуют во всех фреймворках:

— в них легко строить большие вычислительные графы;

— легко вычислять градиенты для вычислительных графов;

— они эффективно используют GPU.

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

TensorFlow

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

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

Объекты tf.placeholder используются для передачи входных данных в вычислительный граф, а метод tf.maximum вводит нелинейность ReLU.

Сначала мы выполняем матричное умножение переменных x и w1 (данных и параметров), а затем вычисляем потери L2 между прогнозируемыми (y_pred) и истинными (y) значениями с помощью базовых тензорных операций. Как вы могли заметить, у нас пока нет никаких данных и на самом деле этот код ничего не делает. 

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

При запуске графа мы генерируем данные с помощью np.random, чтобы передать конкретные значения в ранее созданные placeholders. Вызов метода tf.Session().run начинает выполнение вычислений. В качестве первого аргумента мы указываем параметры, которые хотим посчитать: потери loss и градиенты grad_w1, grad_w2. Второй аргумент feed_dict содержит в себе передаваемые в граф данные. После выполнения этой строки TensorFlow запустит граф и вычислит все необходимые значения.

Код пока не обучает нейросеть: для этого достаточно добавить всего несколько строк с реализацией градиентного спуска и обновлением весов:

Построив график потерь, мы увидим, что нейросеть действительно обучается и потери уменьшаются:

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

К счастью, в TensorFlow есть готовое решение проблемы. Вместо того, чтобы использовать веса в виде tf.placeholder, мы объявим их как tf.Variable. Variable — это значение, которое находится внутри вычислительного графа и сохраняется при каждом его запуске.

Теперь нам не нужно каждый раз обновлять веса и градиенты, поскольку они уже находятся в графе. Мы отправляем на вход только данные и метки, а на выходе получаем потери. Чтобы обновление выполнялось внутри графа, добавим оптимизатор optimizer для вычисления градиентов и будем минимизировать их с помощью переменной updates, которая использует метод minimize и передаётся в tf.Session:

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

Несколько слов о Keras

Keras — высокоуровневое API, которое обычно используется «поверх» Tensorflow и позволяет создавать и обучать нейросети с помощью простых и понятных команд. Он отлично подойдёт для построения базовых моделей и знакомства с Machine Learning. Если вам не терпится попробовать написать код для своей первой по-настоящему рабочей нейросети, рекомендуем ознакомиться с нашей статьёй Как начать работу с Keras, Deep Learning и Python.

PyTorch

В PyThorch существует понятие трёх уровней абстракции. Для каждой из них можно найти аналогичные объекты в TensorFlow:

Мы не будем подробно останавливаться на деталях и сразу рассмотрим код двухслойной нейросети с оптимизатором Adam, реализацию которой мы использовали выше. В PyTorch он будет выглядеть примерно следующим образом:

Модуль nn, как вы могли догадаться, содержит в себе готовые функции для работы с нейросетями. Помимо него в библиотеке есть множество полезных инструментов: например, метод DataLoader позволяет удобно импортировать наборы данных, разбивать их на мини-пакеты, перемешивать и использовать собственные классы датасетов. А с дополнительной утилитой TorchVision можно быстро загружать предварительно обученные популярные модели: AlexNet, VGG16, ResNet и другие.

Совершить подробную и занимательную экскурсию по PyTorch можно, прочитав эту статью.

Caffe

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

Весь алгоритм работы с Caffe можно охарактеризовать следующими шагами:

  1. Сконвертируйте данные в формат HDF5 или LMDB с помощью готовых скриптов;
  2. Задайте настройки для нейросети (отредактируйте prototxt);
  3. Настройте solver (оптимизацию) (отредактируйте prototxt);
  4. Запустите обучение (готовый скрипт).

Caffe доступен и в Python. Лучше всего использовать новую версию Caffe2, которая интегрирована в PyTorch: она хорошо подходит для работы с массивами NumPy, извлечения признаков из данных, настройки и обучения моделей, а также обеспечивает поддержку мобильных платформ iOS, Android и других.

Что же использовать?

На наш взгляд, TensorFlow — наилучший вариант для большинства проектов. Он не идеален, но имеет огромное сообщество и очень широко применяется в самых разных сферах. К тому же, его можно использовать с более высокоуровневой оболочкой (Keras, Sonnet и другие).

PyTorch лучше всего подходит для исследований, а Caffe2 — для развёртывания готовых моделей и их адаптации на мобильных устройствах.

⌘⌘⌘

Если вы просмотрели все предыдущие лекции, спешим поздравить — мы вместе прошли уже половину курса. Расскажите в комментариях, интересны ли вам материалы, какие темы показались наиболее полезными и важными. Задавайте вопросы, если столкнулись с чем-то непонятным — мы обязательно ответим.

Следующие лекции (список будет дополняться по мере появления материалов):

Лекция 9. Архитектуры CNN
Лекция 10. Рекуррентные нейронные сети

С оригинальной лекцией можно ознакомиться на YouTube.

Поведенческие факторы ранжирования и их влияние на SEO: взгляд изнутри

Поведенческие факторы ранжирования и их влияние на SEO: взгляд изнутри

Редакция блога продолжает цикл образовательных SEO-статей. Сегодня вместе с SEO-специалистом REG.RU Евгением Сметаниным мы расскажем, что такое поведенческие факторы ранжирования,...
Read More
Безвозмездно, то есть даром: что можно получить бесплатно в REG.RU

Безвозмездно, то есть даром: что можно получить бесплатно в REG.RU

В REG.RU мы постоянно работаем над развитием и улучшением сервисов, и на первое место всегда ставим заботу о клиентах. У...
Read More
Domains weekly: неудавшийся захват Domovoy.ru, гранты от ICANN и домен, приносящий богатство

Domains weekly: неудавшийся захват Domovoy.ru, гранты от ICANN и домен, приносящий богатство

Сегодня поделимся новостями о том, как сеть супермаркетов не смогла заполучить желаемый домен, почему в Китае ценятся числовые адреса и...
Read More
Шпаргалка по Python для Django

Шпаргалка по Python для Django

В Python очень много полезных функций, библиотек и других элементов, перечислить которые в одном материале очень сложно. Мы поделимся базовой...
Read More
Domains weekly: безопасное инвестирование, открытие зоны .NEW и блокчейн‑домены

Domains weekly: безопасное инвестирование, открытие зоны .NEW и блокчейн‑домены

Дайджест домейнера с новостями о безопасном способе инвестирования в домены, политике ICANN в отношении доменных споров, открытии общедоступной регистрации .NEW...
Read More
Как подготовить и провести вебинар на любую тему: стратегия из 8 шагов от REG.RU

Как подготовить и провести вебинар на любую тему: стратегия из 8 шагов от REG.RU

Харизматичный спикер, интересная тема, качественная презентация, внимательные слушатели — что же ещё нужно для хорошего вебинара? В этом материале мы...
Read More
Domains weekly: популярные ccTLDs в России, 17‑летняя ошибка Microsoft и уязвимости аукционных доменов

Domains weekly: популярные ccTLDs в России, 17‑летняя ошибка Microsoft и уязвимости аукционных доменов

Сегодня расскажем о том, как изменился рынок доменных имён в 2019 году, какие национальные домены кроме .RU и .РФ используют...
Read More
10 фишек Облачных серверов REG.RU

10 фишек Облачных серверов REG.RU

Если вы выбрали для своего проекта VPS, то наверняка знаете об их особенностях. Но что, если мы скажем, что Облачные...
Read More
Настраиваем шифрование жесткого диска, чтобы избежать утечек данных

Настраиваем шифрование жесткого диска, чтобы избежать утечек данных

В каждой компании есть сотрудники, которые хранят на рабочем компьютере конфиденциальную информацию, и её утечка может оказаться катастрофой. Среди таких...
Read More
Domains weekly: отказ в зоне .INTERNET, «собачья» прибыль и дроп домена Google

Domains weekly: отказ в зоне .INTERNET, «собачья» прибыль и дроп домена Google

ICANN вновь и вновь отказывает индийской компании в делегировании зоны .INTERNET, собака вдохновила хозяина на домен стоимостью полмиллиона долларов, Google...
Read More