Библиотека глубокого обучения Tensorflow |
|||||||||||
МЕНЮ Искусственный интеллект Поиск Регистрация на сайте Помощь проекту ТЕМЫ Новости ИИ Искусственный интеллект Разработка ИИГолосовой помощник Городские сумасшедшие ИИ в медицине ИИ проекты Искусственные нейросети Слежка за людьми Угроза ИИ ИИ теория Внедрение ИИКомпьютерные науки Машинное обуч. (Ошибки) Машинное обучение Машинный перевод Реализация ИИ Реализация нейросетей Создание беспилотных авто Трезво про ИИ Философия ИИ Big data Работа разума и сознаниеМодель мозгаРобототехника, БПЛАТрансгуманизмОбработка текстаТеория эволюцииДополненная реальностьЖелезоКиберугрозыНаучный мирИТ индустрияРазработка ПОТеория информацииМатематикаЦифровая экономика
Генетические алгоритмы Капсульные нейросети Основы нейронных сетей Распознавание лиц Распознавание образов Распознавание речи Техническое зрение Чат-боты Авторизация |
2017-04-13 14:51 Здравствуй, Хабр! Цикл статей по инструментам для обучения нейронных сетей продолжается обзором популярного фреймворка Tensorflow. Tensorflow (далее — TF) — довольно молодой фреймворк для глубокого машинного обучения, разрабатываемый в Google Brain. Долгое время фреймворк разрабатывался в закрытом режиме под названием DistBelief, но после глобального рефакторинга 9 ноября 2015 года был выпущен в open source. За год с небольшим TF дорос до версии 1.0, обрел интеграцию с keras, стал значительно быстрее и получил поддержку мобильных платформ. В последнее время фреймворк развивается еще и в сторону классических методов, и в некоторых частях интерфейса уже чем-то напоминает scikit-learn. До текущей версии интерфейс менялся активно и часто, но разработчики пообещали заморозить изменения в API. Мы будем рассматривать только Python API, хотя это не единственный вариант — также существуют интерфейсы для C++ и мобильных платформ. Установка TF устанавливается стандартно через python pip. Есть нюанс: существуют отдельные алгоритмы установки для работы на CPU и на видеокартах. В случае с CPU всё просто: нужно поставить из pip пакет под названием tensorflow. Во втором случае нужно:
Впрочем, документация утверждает, что поддерживаются и более ранние версии CUDA Toolkit и cuDNN, но рекомендует устанавливать версии, указанные выше. Разработчики рекомендуют устанавливать TF в отдельную среду с virtualenv, чтобы избежать возможные проблемы с версионированием и зависимостями. Еще один вариант установки — Docker. По умолчанию из контейнера будет работать только CPU-версия, но если использовать специальный nvidia docker, то можно использовать и GPU. Сам я не пробовал, но говорят, что TF работает даже с Windows. Установка проводится через тот же pip и, говорят, работает без проблем. Я пропускаю процесс сборки из исходников, однако и такой вариант может иметь смысл. Дело в том, что пакет из репозитория собирается без поддержки SSE и прочих плюшек. В последних версиях TF проверяет наличие таких плюшек и сообщает, что из исходников он будет работать быстрее. Подробно процесс установки описан тут. Документация Документации и примеров очень много.
Лучше всего ориентироваться на официальную документацию — из-за быстрого развития и частой смены api, в интернете очень много туториалов и скриптов, которые ориентированы на старые версии (ну как старые… полугодовой давности) со старым API, они не будут работать с последними версиями фреймворка. Базовые элементы TF С помощью «Hello, world» убедимся, что всё установилось правильно:
Первой же строчкой подключаем TF. Уже сложилось правило вводить для фреймворка соответствующее сокращение. Этот же кусочек кода встречается в документации и позволяет удостовериться в том, что всё установилось правильно. Граф вычислений Работа c TF строится вокруг построения и выполнения графа вычислений. Граф вычислений — это конструкция, которая описывает то, каким образом будут проводиться вычисления. В классическом императивном программировании мы пишем код, который выполняется построчно. В TF привычный императивный подход к программированию необходим только для каких-то вспомогательных целей. Основа TF — это создание структуры, задающей порядок вычислений. Программы естественным образом структурируются на две части — составление графа вычислений и выполнение вычислений в созданных структурах. Граф вычислений в TF по смыслу не отличается от такового в Theano. В предыдущей статье цикла дано отличное описание этой сущности. В TF граф состоит из плейсхолдеров, переменных и операций. Из этих элементов можно собрать граф, в котором будут вычисляться тензоры. Тензоры — многомерные массивы, они служат «топливом» для графа. Тензором может быть как отдельное число, вектор признаков из решаемой задачи или изображение, так и целый батч описаний объектов или массив из изображений. Вместо одного объекта мы можем передать в граф массив объектов и для него будет вычислен массив ответов. Работа TF с тензорами похожа на то, как обрабатывает массивы numpy, в функциях которого можно указать ось массива, относительно которой будет выполняться вычисление. Сессии Вычислительные графы выполняются в сессиях. Объект сессии ( Далее в посте будут появляться стандартные для TF картинки с изображениями графов, сгенерированные встроенной утилитой под названием Tensorboard. Обозначения там вот такие:
Тензоры, операции и переменные Создадим, к примеру, тензор, заполненный нулями.
Вообще, API в TF будет во многом напоминать numpy и
Различие между строчками состоит в том, что в первой строке происходит вычисление тензора, а во второй строке мы просто печатаем представление объекта. Описание тензора показывает нам несколько важных вещей:
Над тензорами можно совершать разнообразные операции:
В примере выше мы используем конструкцию Создадим теперь переменную на основе тензора:
Переменная участвует в вычислениях в качестве узла вычислительного графа, сохраняет состояние, и ей нужна какая-нибудь инициализация. Так, если в следующем примере обойтись без первой строчки, то TF выкинет исключение.
Операции над переменными создают вычислительный граф, который можно потом выполнить. Еще есть плейсхолдеры — объекты, которые параметризуют граф и отмечают места для подстановки внешних значений. Как написано в официальной документации, плейсхолдер — это обещание подставить значение потом. Создадим плейсхолдер и назначаем ему тип данных и размер:
Еще такой пример использования. Здесь два плейсхолдера служат входными узлами для сумматора:
Простейшие вычисления. В качестве примера создадим и вычислим несколько выражений.
И граф вычисления:
Попробуем собрать что-нибудь более практически значимое.
И вот такой граф для неё. В фрагменте с запуском вычисления функции есть один момент, который отличает этот пример от предыдущих. Дело в том, что в плейсхолдер вместо одного скалярного значения мы передаем целый массив. TF обрабатывает все значения массива вместе, в рамках одного тензора (помним, что массив == тензор). Точно таким же образом мы можем передавать в граф объекты целыми батчами и поставлять нейронной сети картинки целиком. В целом работа с тензорами напоминает работу с массивами в numpy. Однако, есть некоторые отличия. Когда мы хотим понизить размерность, каким-либо образом объединив значения в тензоре по определенному измерению, мы пользуемся теми функциями, которые начинаются с reduce_. Машинное обучение Разберем для начала уже не раз упоминавшуюся здесь классическую линейную регрессию, с детальным описанием которой можно ознакомиться тут, однако для обучения будем использовать метод градиентного спуска. Куда же без этой картинки Начну с линейной регрессии, а потом добавлю полиномиальные признаки.
Выглядеть они будут примерно так: Я еще разобью выборку на обучающую и контрольную в пропорции 70/30, но этот и некоторые другие рутинные моменты оставлю в полном исходнике, ссылка на который будет чуть ниже. Сначала построим простую линейную регрессию.
Тут я создаю два плейсхолдера для признака и ответа и формулу вида . Плейсхолдер для признака используется в формуле, а вот плейсхолдер для ответа я подставлю в функцию потерь :
В TF реализован десяток методов оптимизации. Мы будем использовать классический градиентный спуск, указав ему в параметрах скорость обучения. Метод minimize создаст нам операцию, вычисление которой будет минимизировать функцию потерь.
Инициализация переменных — она необходима для дальнейших вычислений:
Всё, наконец-то можно обучать. Я запущу 100 эпох обучения на обучающей части выборки, после каждого обучения буду устраивать контроль на отложенной части.
Первое выполнение сессией одновременно операций Получается вот такая динамика обучения: В этом графе присутствуют вспомогательные переменные с градиентами и операции инициализации, они вынесены в отдельный блок. А вот и результаты вычисления модели: Значения для графика я вычислил вот таким способом:
Тут в граф я передаю значение только для плейсхолдера Полный листинг программы есть тут. Результат получился предсказуемым для такой простой линейной модели. Полиномиальная регрессия Попробуем разнообразить регрессию полиномиальными признаками, регуляризацией и изменением скорости обучения модели. В генерации набора данных добавим некоторое количество степеней и нормируем признаки с помощью PolynomialFeatures и StandardScaler из библиотеки scikit-learn. Первый объект создаст нам полиномиальных признаков сколько захотим, а второй нормирует их. Для перехода к полиномиальной регрессии заменим всего несколько строк в графе вычислений:
Фактически сейчас мы считаем . Очевидно, существует опасность переобучения модели на ровном месте, поэтому добавим регуляризационные штрафы на веса. Штрафы добавим к функции потерь (loss в примерах) в виде дополнительных слагаемых и получим почти что ElasticNet из sklearn.
Для самой популярной L2-регрессии существует отдельная функция Ради примера добавлю еще одно существенное изменение, которое коснется темпа обучения. Довольно часто при обучении тяжелых нейросетей это просто необходимая мера для того, чтобы избежать проблем с обучением и получить приемлемый результат. Очень простая идея — по мере обучения постепенно понижать параметр шага, избегая больших неприятностей. Вместо константного темпа будем использовать экспоненциальное затухание, которое я взял прямиком из документации:
Внутри функции скрывается формула:
Получаем вот такие темпы снижения ошибок на обучении и контроле: Помимо экспоненциального затухания есть и другие функции, которые позволяют снижать скорость обучения, и конечно ничто не мешает создать еще одну функцию под свои нужды. Сама модель после обучения и разнообразных подборов параметров будет выглядеть как-то так: Для получения этого результата я изменял коэффициенты при регуляризации и скорости обучения. Перебор значений констант в формуле потерь — отличный способ увидеть своими глазами эффект работы регуляризаторов, крайне рекомендую поиграть с настройками в полном исходнике полиномиальной регрессии, он доступен тут. Сохранение и загрузка графов Мы получили модель и было бы неплохо её сохранить. В TF всё достаточно просто — в API есть специальный объект-сериализатор, который делает две вещи:
Вот всё что нужно — это создать этот объект:
Сохранение состояния текущей сессии производится с помощью метода
Уже как-то принято, что сохраненные состояния модели называют чекпойнтами, отсюда название папок и расширения файлов. Восстановление производится с помощью метода
Сначала с помощью специальной функции получаем состояние чекпойнта (если вдруг в целевой директории нет сохраненной модели, функция вернет Tensorboard Крайне полезная система в составе TF — web-dashboard, который позволяет собирать статистику из дампов и логов и наблюдать, что же всё-таки происходит во время вычислений. Крайне удобно то, что дашборд работает на веб-сервере и можно, например, запустив tensorboard на удаленной машине в облаке, наблюдать происходящее у себя в окне браузера. Tensorboard умеет:
Обратная сторона медали — чтобы статистика попадала в дашборд, её нужно сохранять в логи (в формате protobuf) с помощью специального API. API не очень сложный, сгруппирован в Еще при использовании Tensorboard важно также не забывать про параметр Есть несколько типов функций, которые сохраняют данные переменных различным образом:
Данная функция позволит собрать гистограмму для выхода слоя и примерно оценить динамику изменений при обучении. Функция Для сохранения логов нужно чуть больше: сначала нужно создать FileWriter для записи файла.
И объединить всю статистику в одном объекте. Теперь нужно вот этот объект
Впрочем, для простого сохранения графа достаточно вот такого кода:
И нюанс: по умолчанию Tensorboard локально доступен по адресу 127.0.1.1:6006. Надеюсь, сохранил читателям несколько секунд времени и нейронов этим замечанием. Многослойный перцептрон Разберем каноничный пример с запоминанием функции xor, которую линейная модель не может усвоить из-за невозможности линейного разделения пространства признаков. Многослойные сети усваивают функцию из-за того, что делают неявное преобразование пространства признаков в разделимое или же (в зависимости от реализации) делают нелинейное разбиение этого пространства. Мы реализуем первый вариант — создадим двухслойный перцептрон с нелинейной активацией слоев. Первый слой будет делать нелинейное преобразование, а второй слой — это практически линейная регрессия, которая работает на преобразованном пространстве признаков. В качестве элемента нелинейности будем использовать функцию relu. Определим структуру сети:
В отличие от keras и других более высокоуровневых библиотек, TF, подобно Theano предполагает детальное определение каждого слоя как совокупности некоторых арифметических операций. Это верно не для всех видов слоёв, например, сверточные и dropout-слои определяются одной функцией, в то время как обычный полносвязный слой представляет собой объявление не только переменных для весов и сдвигов, но и самих операций (перемножение весов с выходом предыдущего слоя, добавление сдвига, применение функции активации). Разумеется, довольно часто всё это оборачивается в подобную функцию:
При этом по моему собственному опыту объявление и инициализацию переменных удобнее оставлять снаружи: иногда требуется использовать их еще где-нибудь внутри графа (типичный пример — сиамские нейронные сети с общими весами) или же просто иметь доступ для простого логирования в файл и вывода текущих значений, а tensorboard по каким-то причинам пользоваться не хочется. Используем элементарную функцию потерь:
и обучим:
Получившийся граф: В сравнении с регрессией практически ничего не изменилось: тот же процесс обучения, та же функция потерь. Единственная часть кода, которая сильно изменилась — это код построения вычислительного графа. Дошло до того, что у меня накопился набор скриптов под конкретные задачи, в которых я меняю только подачу данных и граф вычислений. Конечно, в данном примере нет проверки на отложенной выборке. Убедиться в правильности работы сети можно с помощью вычисления выхода нейронной сети в графе:
Полный код данного примера доступен тут. На ноутбуке пятилетней давности весь код отрабатывает за 5 секунд. Конечно, в случае более сложных моделей добавляется валидация на отложенной выборке и слежение за качеством по мере обучения и встроенные в TF методы подачи данных в граф. Управление ресурсами Довольно часто мир бывает несправедлив, и задача может не помещаться полностью в одно устройство. Или же менеджмент купил всего одну Tesla, и разработчики периодически вступают в конфликты из-за занятой карточки. В TF на такие случаи есть механизмы управления вычислениями. Внутри фреймворка устройства обозначаются как «/cpu:0», «/gpu:0» и т.д. Самое простое — можно указывать, где конкретно будет «жить» та или иная переменная:
В этом примере переменная Еще можно передать в сессию конфигурационный объект, с помощью которого можно изменять проведение вычислений графа. Выглядит это примерно так:
В конфиге первым делом можно включить параметр Допустим, в команде разработчиков можно договориться об ограничении потребления памяти GPU. Сделать это можно с помощью такого кода:
В такой конфигурации сессия не будет потреблять более четверти памяти GPU, а это значит, что можно одновременно запустить расчеты еще нескольких моделей, а еще можно запустить модель считаться на CPU, но проще всего включить параметр Заключение TF буквально за год-полтора разросся настолько, что впору делать отдельные обзоры о применении сверточных и рекуррентных сетей, обучения с подкреплением и о применении фреймворка к различным задачам. В этом кратком обзоре не затронуты темы структур для чтения данных, свертки, разнообразные методы оптимизации и высокоуровневые библиотеки-обертки. Продолжить знакомство можно, попробовав для начала «поиграть» с настройками обучения и разобравшись с различными оптимизаторами. Ну и конечно попробовать TF в соревнованиях на Kaggle! Автор выражает благодарность sovcharenko, Ferres и bauchgefuehl за помощь в подготовке текста. UPD: Источник: habrahabr.ru Комментарии: |
||||||||||