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

Стэнфордский курс: лекция 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.

Domains weekly: .РФ на страже русского языка, рост new gTLDs и пассивный доход от PORNO.COM

Domains weekly: .РФ на страже русского языка, рост new gTLDs и пассивный доход от PORNO.COM

В новой подборке новостей мы расскажем, как развивался русский язык вместе с зоной .РФ, что за риски таит в себе...
Read More
VPS нового поколения, ИИ, юникодные домены и мини‑сериал об админах: всё, что вы знали и чего могли не знать о REG.RU

VPS нового поколения, ИИ, юникодные домены и мини‑сериал об админах: всё, что вы знали и чего могли не знать о REG.RU

Ура-ура! 22 мая нам исполнилось 14 лет, и мы по-прежнему двигаемся только вперёд и становимся лучше. Мы решили поделиться с...
Read More
Domains weekly: старт .MEET от Google, годовой рост .RU и .РФ, вирусная реклама рэп‑альбома с new gTLDs

Domains weekly: старт .MEET от Google, годовой рост .RU и .РФ, вирусная реклама рэп‑альбома с new gTLDs

В новой еженедельной подборке новостей расскажем о старте регистраций в зоне  .MEET от Google, вирусной рекламной кампании нового рэп-альбома Future...
Read More
Как скорость загрузки страниц на мобильных устройствах влияет на посещаемость сайта

Как скорость загрузки страниц на мобильных устройствах влияет на посещаемость сайта

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

Популярные уязвимости сайтов: чем опасны и как их избежать

Для любого, кто управляет веб-сайтом, на первом месте должен стоять вопрос безопасности. Критические угрозы и уязвимости могут сильно ударить как...
Read More
Domains weekly: 10 лет .РФ, новый топ регистраторов в .COM и спор за ягодный домен

Domains weekly: 10 лет .РФ, новый топ регистраторов в .COM и спор за ягодный домен

В свежей подборке новостей расскажем о юбилее .РФ, отчёте ICANN о динамике регистраций в зоне .COM и неудачной попытке канадской...
Read More
С днём рождения, .РФ!

С днём рождения, .РФ!

В этом году кириллической национальной российской доменной зоне исполняется 10 лет. Мы решили вспомнить, как всё начиналось: в этом материале...
Read More
Domains weekly: стагнация ccTLD, конец страстей по .ORG и взлом клиентов GoDaddy

Domains weekly: стагнация ccTLD, конец страстей по .ORG и взлом клиентов GoDaddy

В сегодняшней подборке новостей расскажем, как изменилось число регистраций национальных доменов по сравнению с прошлым годом, чем закончилась сделка с...
Read More
Как поменять домен, чтобы сайт не просел в поисковой выдаче

Как поменять домен, чтобы сайт не просел в поисковой выдаче

Итак, вы решили изменить имя своего сайта после ребрендинга или просто выбрали более короткий домен. Но как при этом сохранить...
Read More
Domains weekly: Zoombombing, снижение доходов ICANN и зона .DEALER

Domains weekly: Zoombombing, снижение доходов ICANN и зона .DEALER

В сегодняшнем доменном дайджесте мы расскажем, что такое Zoombombing, какие прогнозы у ICANN по доходам на следующий год и почему...
Read More