четверг, 9 августа 2018 г.

MXNet и нейронные сети: простые примеры

Хотя MXNet может ускорить любые числовые вычисления библиотека разработана в основном для нейронных сетей. Ниже будет приведен пример использования возможностей MXNet.

Нейронные сети - это просто функции для преобразования входного массива X в выходной массив Y. В случае классификации изображений, X может представлять пиксельные значения изображения, а Y может представлять соответствующие вероятности того, что изображение принадлежит к каждому из 10 классов. При переводе текстов с одного языка на другой, X и Y оба могут обозначать последовательности слов. На данный момент условимся, что X и Y представляют собой вектора фиксированной длины.

Чтобы выполнить преобразование нейронные сети создают слои вычислений. Каждый слой состоит из линейной функции с последующим нелинейным преобразованием. В MXNet мы можем выразить это так:

hidden_linear = mx.sym.dot(X, W)
hidden_activation = mx.sym.tanh(hidden_linear)

Линейные трансформации состоят из умножения на массивы параметров (W в выражении выше). Когда мы говорим об обучении мы подразумеваем нахождение правильного набора значений для W. При единственном существующем слое мы можем реализовать знакомый набор линейных моделей, включающий линейную и логистическую регрессию, линейные машины опорных векторов (SVM), и алгоритм перцептрона. С большим количеством слоев и меньшими усилиями мы можем реализовать все современные шедевры техник глубокого обучения.

Конечно сотни или тысячи матричных умножений могут быть вычислительно затратными. В целом эти линейные операции являются вычислительным узким горлышком. К счастью линейные операции могут выполняться параллельно на тысячах ядер GPU. Но низкоуровневое программирование GPU требует специальных навыков, которые не так распространены даже среди ведущих исследователей в обществе машинного обучения. Более того, даже для экспертов CUDA, реализация новой архитектуры нейронной сети не должна требовать недель программирования для воплощения низкоуровневых линейных алгебраических операций. Вот где MXNet приходит на помощь.

  • MXNet предоставляет оптимизированные числовые вычисления для GPU и рапределенных экосистем, из комфортных высокоуровневых окружений таких как Python и R
  • MXNet автоматизирует общие рабочие потоки, таким образом что стандартная нейронная сеть может быть записана всего несколькими строками кода

Теперь взглянем поближе на вычислительные требования нейронных сетей и дадим представление того как MXNet помогает в написании более качественного, быстрого кода. Например мы имеем нейронную сеть натренированную распознавать спам по содержимому электронных писем. Поток писем может приходить из онлайн-сервиса (в рабочем режиме нейронной сети (при выводе результата от сети)), или из большого оффлайн набора данных D (в тренировочное время нейронной сети). В любом случае набор данных обычно должен быть обработан CPU.

Для быстрого вычисления преобразования нейронной сети нам нужны параметры нейронной сети и числовые точки экземпляров данных чтобы сделать эти вычисления в памяти GPU. Для любого примера X параметры сети W одинаковы. Более того размер модели нейронной сети имеет тенденцию затмевать размер отдельного экземпляра данных. Таким образом мы приходим к логичному выводу что параметры нейронной сети должны всегда находиться в памяти GPU, даже если набор данных сам должен находиться в CPU или входить потоком. Это предотвращает превращение системы ввода/вывода узким горлышком во время тренировки или в рабочем режиме нейронной сети.

К счастью MXNet делает такой вид назначений просто.

import mxnet.ndarray as nd

X = nd.zeros((10000, 40000), mx.cpu(0)) #Выделяем массив для хранения 1000 точек данных (в 40k измерений) которые располагаются в CPU
W1 = nd.zeros(shape=(40000, 1024), mx.gpu(0)) #Выделяем 40k x 1024 матрицу весов в GPU для первого слоя сети
W2 = nd.zeros(shape=(1024, 10), mx.gpu(0)) #Выделяем 1024 x 1024 матрицу весов в GPU для второго слоя сети

Схожим образом MXNet делает простым определение вычислительного устройства

with mx.Context(mx.gpu()): # При отсутствии этого выражения, по умолчанию, MXNet будет выполнять на CPU
    h = nd.tanh(nd.dot(X, W1))
    y = nd.sigmoid(nd.dot(h1, W2))

Таким образом, только с высокоуровневым пониманием того как вычисления располагаются в исполняемом окружении, MXNet позволяет оказывать детализированный контроль когда необходимо.