Pull to refresh

Data mining: Инструментарий — Theano

Reading time6 min
Views51K

В предыдущих материалах этого цикла мы рассматривали методы предварительной обработки данных при помощи СУБД. Это может быть полезно при очень больших объемах обрабатываемой информации. В этой статье я продолжу описывать инструменты для интеллектуальной обработки больших объёмов данных, остановившись на использовании Python и Theano.

Рассмотрим задачи, которые мы будем решать, и какими инструментами для этого воспользуемся. Читать предыдущие части [1,2,3] желательно, но не обязательно. Исходные данные, которые были получены в результате выполнения предыдущих частей цикла статей можно взять отсюда[Исходные данные].

Задачи

Если среди данных есть скрытые взаимосвязи, корреляция между признаками, структурные связи, то в таком случае возникает задача уменьшения размерности входных данных. Эта проблема особенно ярко себя проявляет в ситуации, когда обрабатывается большое число разреженных данных.
Для сравнения методов уменьшения размерности данных мы собираемся рассмотреть метод нейросетевого сжатия (Autoencoder) и метод главных компонент (PCA).
Классический путь решения этой задачи — метод анализа главных компонент (PCA). В википедии неплохо описано [4], там же есть ссылка [5] на сайт с примерами в Excel, и подробным и довольно понятным описанием. Вот еще ссылки на статьи на Хабре[6,7].
Как правило, результаты уменьшения размерности входных данных, в первую очередь сравнивают именно с результатами применения этого метода.
В статье [8] описано что такое автоенкодер и как он работает, потому основной материал будет посвящен именно реализации и применению этого подхода.
Бангио и Йошуа написали хороший и внятный обзор применения нейросетевого сжатия, если вдруг кому-нибудь нужна библиография и ссылки на работы в этом направлении, чтобы сравнивать свои результаты с существующими, в работе [9], раздел 4.6, стр. 48 — 50.
В качестве инструментария, я решил применять Python и Theano[10]. Этот пакет я обнаружил после прослушивания курсов Neural Networks for Machine Learning, изучая ссылки предоставленные преподавателем J. Hinton. При помощи этого пакета реализованы нейронные сети «глубокого обучения» (deep learning neural networks). Такого рода сети, как было описано в лекциях и статье [11, 12] легли в основу системы для распознавания голоса, используемой Google в Android.
Этот подход к построению нейронных сетей по мнению некоторых ученых является достаточно перспективным, и уже показывает неплохие результаты. Потому мне стало интересно применить его для решения задач на Kaggle.
Также, на сайте deeplearning.net достаточно много примеров построения систем машинного обучения с использованием именно этого пакета.

Инструменты

В документации разработчиков, дано такое определение:
Theano — это библиотека Python и оптимизирующий компилятор, которые позволяют определять, оптимизировать и вычислять математические выражения эффективно используя многомерные массивы
Возможности библиотеки:
  • тесная интеграция с NumPy;
  • прозрачное использование GPU;
  • эффективное дифференцирование переменных;
  • быстрая и стабильная оптимизация;
  • динамическая генерация кода на C;
  • расширенные возможности юнит-тестирования и самопроверок;

Theano используется в высокоинтенсивных вычислительных научных исследований с 2007 года.
По сути, программирование под Theano не является программированием в полном смысле этого слова, так как пишется программа на Python, которая создает выражение для Theano.
С другой стороны, это является программированием, так как мы объявляем переменные, создаем выражение которое говорит что делать с этими переменнымии компилируем эти выражения в функции, которые используются при вычислении.
Если кратко, то вот список того, что именно может делать Theano в отличии от NumPy.
  • оптимизация скорости выполнения: Theano может использовать g++ или nvcc для того чтобы откомпилировать части части вашего выражения в инструкции GPU или CPU, которые выполняются намного быстрее чистого Python;
  • диференциицирование переменных: Theano может автоматически строить выражения для вычисления градиента;
  • стабильность оптимизации: Theano может распознать некоторые численно неточно вычисляемые выражения и рассчитать их используя более надежные алгоритмы

Наиболее близкий к Theano пакет это sympy. Пакет sympy можно сравнить с Mathematica, в то время как NumPy более похож на пакет MATLAB. Theano является гибридом, разработчики которого попытались взять лучшие стороны обоих этих пакетов.
Скорее всего, в продолжение цикла, будет написана отдельная статью о том как настроить theano, подключить использование CUDA GPU к тренировке нейронных сетей и решать проблемы, возникающие при установке.
А пока, на моей операционной системе Linux Slackware 13.37 установлен python-2.6, setuptools-0.6c9-py2.6, g++, python-dev, NumPy, SciPy, BLAS. Подробный мануал по установке для распространеных ОС на английском языке: [12].
Прежде чем мы начнем снижать размерность данных, попытаемся реализовать простой пример использования Theano для написания функции, которая позволит нам решить нашу задачу о разбиении группы на две части.
В качестве метода для разбиения данных на два класса воспользуемся логистической регрессией[13].
Код примера основывается на [14] с некоторыми изменениями:
import numpy 
import theano
import theano.tensor as T
import csv as csv 

#Открываем и читаем csv файл
csv_file_object = csv.reader(open('./titanik_train_final.csv', 'rb'), delimiter='\t')
data=[]                                     #Создаем переменную-массив
for row in csv_file_object:      # Каждую строку
    data.append(row)                # заносим в  массив data
data = numpy.array(data)        # Превращаем обычный массив в тип numpy.array 
data = data.astype('float')        # Конвертируем в тип float
Y = data[:,1]                            # Все строки первого столбца заносим в Y
X = data[:,2:]                           # Все строки со второго столбца и до последнего заносим в X 
#Аналогично для тестовой выборки, только без Y
csv_file_object = csv.reader(open('./titanik_test_final.csv', 'rb'), delimiter='\t')
data_test=[]                         
for row in csv_file_object:     
    data_test.append(row)           
Tx = numpy.array(data_test)
Tx = Tx.astype('float')
Tx = Tx[:,1:]
#Создаем объект для получения случайных чисел
rng = numpy.random
#Количество строк
N = 891
#Количество столбцов
feats = 56
#Количество тренировочных шагов
training_steps = 10000

# Декларируем символьные переменные Theano 
x = T.matrix("x")
y = T.vector("y")
w = theano.shared(rng.randn(feats), name="w")
b = theano.shared(0., name="b")

# Создаем «выражение» Theano
p_1 = 1 / (1 + T.exp(-T.dot(x, w) - b))           # Вероятность того, что результат равен  1
prediction = p_1 > 0.5                                    # Порог для прогнозирования
xent = -y * T.log(p_1) - (1-y) * T.log(1-p_1) # Функция ошибки для перекрестной энтропии
cost = xent.mean() + 0.01 * (w ** 2).sum()  # Стоимость минимизации
gw,gb = T.grad(cost, [w, b])                          # Рассчитываем градиент стоимости
                                          
# Компилируем «выражение» Theano
train = theano.function(
          inputs=[x,y],
          outputs=[prediction, xent],
          updates=((w, w - 0.1 * gw), (b, b - 0.1 * gb)))
predict = theano.function(inputs=[x], outputs=prediction)

# Тренировка модели
for i in range(training_steps):
    pred, err = train(X, Y)

#Прогнозирование
P = predict(Tx)
#Сохраняем в файл
numpy.savetxt('./autoencoder.csv',P,'%i')
 

Наиболее интересными в этом коде являются строки:
# Создаем «выражение» Theano
p_1 = 1 / (1 + T.exp(-T.dot(x, w) - b))           # Вероятность того, что результат равен  1
prediction = p_1 > 0.5                                    # Порог для прогнозирования
xent = -y * T.log(p_1) - (1-y) * T.log(1-p_1) # Функция ошибки для перекрестной энтропии
cost = xent.mean() + 0.01 * (w ** 2).sum()  # Стоимость минимизации
gw,gb = T.grad(cost, [w, b])                          # Рассчитываем градиент стоимости
                                          
# Компилируем «выражение» Theano
train = theano.function(
          inputs=[x,y],
          outputs=[prediction, xent],
          updates=((w, w - 0.1 * gw), (b, b - 0.1 * gb)))
predict = theano.function(inputs=[x], outputs=prediction)
 

Здесь происходит следующее(разбираем с конца !): У нас есть два «выражения» train и predict. Они «компилируются»(это не только компиляция, но в начале изучения лучше будет упростить) при помощи theano.function в вид, который может быть потом вызван и исполнен.
Входными параметрами у нас для прогнозирования является x, а выходным — выражение prediction, которое равно p_1 > 0,5 — т. е. порог, который возвращает значение да/нет, т. е. значения 0 или 1. В свою очередь, выражение p_1 содержит сведения о том, что именно нужно делать с переменной х, а именно:
p_1 = 1 / (1 + T.exp(-T.dot(x, w) - b))
где x, w, b — переменные, при этом w и b мы определяем при помощи выражения train.
Для train входными данными будут x, y, а выходными prediction и xent. При этом мы будем обновлять(искать оптимальные значения) для w и b, обновляя их по формулам
w-0.1*gw, b-0.1*gb
где gw и gb — градиенты, связанные с ошибкой xent через выражение cost.
А ошибка, вычисляемая по формуле, получается из вот такого выражения:
xent = -y * T.log(p_1) - (1-y) * T.log(1-p_1)
И когда мы «компилируем» выражения predict и train, Theano берет все необходимые выражения, создает для них код на С для CPU/GPU и исполняет их соответствующим образом. Это дает заметный прирост в производительности, при этом не лишая нас удобств использования среды Python.
Результатом исолнения указанного кода будет качество прогноза, равное 0.765555 про правилам оценивания Kaggle для соревнования Titanik.
В следующих статьях цикла мы попытаемся уменьшить размерность задачи используя разные алгоритмы, а результаты сравним.
Tags:
Hubs:
Total votes 23: ↑21 and ↓2+19
Comments4

Articles