commit e325fb344cc50d3e306db7c596a9cbe6d40d91cc
parent 5814b7cc96900f4de7b4dea18fddb827d46a75bf
Author: Ivan Gankevich <igankevich@ya.ru>
Date: Wed, 10 Aug 2016 23:09:09 +0300
Generate makefile.
Diffstat:
cps-16-mic.tex | | | 128 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
main.tex | | | 128 | ------------------------------------------------------------------------------- |
makefile | | | 16 | ++++++++++++++++ |
3 files changed, 144 insertions(+), 128 deletions(-)
diff --git a/cps-16-mic.tex b/cps-16-mic.tex
@@ -0,0 +1,128 @@
+\documentclass[a4paper]{article}
+\usepackage{pmstyle}
+%\usepackage{showframe}
+
+\begin{document}
+%\hyphenation{СПбГУ}
+
+% УДК для статьи берется со страницы http://udc.biblio.uspu.ru/
+\udk{УДК 004.051}
+
+\author{Милова~Е.\:А., Свешникова~С.\:Ю., Ганкевич~И.\:Г.}
+%, Дегтярев~А.\:Б.
+%%%%%%%%% Название статьи
+\title{Ускорение обучения глубокой нейронной сети \\ путем оптимизации алгоритма \\ для запуска на MIC архитектуре}
+
+%подпись внизу страницы
+\renewcommand{\thefootnote}{ }
+{\footnotetext{{\it Милова Евгения Андреевна} -- студент, Санкт-Петербургский государственный университет; e-mail: milova.evg@gmail.com, тел.: +7(911)038-38-35}}
+{\footnotetext{{\it Свешникова Светлана Юрьевна} -- студент, Санкт-Петербургский государственный университет; e-mail: svetasvesh@yandex.ru, тел.: +7(812)428-47-83}}
+{\footnotetext{{\it Ганкевич Иван Геннадьевич} -- аспирант, Санкт-Петербургский государственный университет; e-mail: i.gankevich@spbu.ru, тел.: +7(812)428-47-83}}
+%{\footnotetext{{\it Дегтярев Александр Борисович} -- профессор, Санкт-Петербургский государственный университет; e-mail: deg@csa.ru, тел.: +7(812)428-47-83}}
+
+%сборка заголовка
+\maketitle
+
+%рекомендация научрука
+\recprof{Дегтяревым~А.\:Б.}
+
+\razdel{Введение}
+Глубокой нейронной сетью называют перцептрон с более, чем одним скрытым (обучающим) слоем. Для обучения такой сети обычно применяется метод обратного распространения ошибки~\cite{learning-deep-architectures}. Метод обратного распространения ошибки --- итеративный градиентный алгоритм, целью которого является минимизация ошибки при обучении нейронной сети. Итерация алгоритма состоит из трех основных шагов-функций: dnnForward прогоняет через сеть обучающую выборку, получая на выходе некоторый результат; dnnBackward вычисляет ошибку,
+%(разницу между результатом выполнения обучающей выборки и правильным ответом)
+затем в каждом слое сети, начиная с предпоследнего, для каждого узла вычисляет коррекцию весовых коэффициентов; dnnUpdate обновляет веса нейронов в соответствии с вычисленной ранее поправкой. Обучение сети заканчивается, когда ошибка достигает заданного минимально допустимого значения.
+Такая сеть показывает прекрасные результаты во многих областях, в том числе таких, как распознавание изображений и голоса. Однако ее недостатком является очень длительный процесс обучения. В связи с этим, решено исследовать вопрос об эффективности работы такого вида сетей на параллельных вычислительных архитектурах.
+Для тестирования взята нейронная сеть из 8 слоев (1 входящий, 6 скрытых, 1 выходящий). Для анализа результатов выбраны такие параметры, как скорость обучения нейронной сети и точность распознавания объектов. %Сеть считается правильно обученной, если точность $\geq19$.
+
+Запуск задачи производился на процессоре Intel Xeon (спецификация указана в таблице~1). Сначала был произведен запуск задачи с использованием только одного ядра. Затем произведена оптимизация кода для запуска на параллельной архитектуре. Также принято решение протестировать эффективность MIC-архитектуры для решения данной задачи. MIC (Many Integrated Core) --- архитектура, основой которой является использование большого количества вычислительных ядер архитектуры x86 в одном сопроцессоре, подключаемом к основному процессору. Характеристики используемого сопроцессора Intel Xeon Phi также указаны в таблице~1.
+
+\Table{Характеристики вычислителей, используемых для запуска задачи}{l p{0.7\textwidth}}{
+Процессор & 2$\times$Intel Xeon CPU E5-2695 v2 (12 ядер, 2 потока на ядро, 2,40ГГц ) \\
+Сопроцессор & Intel Xeon Phi-5110P (60 ядер, 4 потока на ядро, 1,053ГГц) \\
+\hline
+}
+
+%\podrazdel{Векторизация внутренних функций}
+\razdel{Оптимизация для запуска на параллельных архитектурах}
+Каждое ядро процессора Intel Xeon и сопроцессора Intel Xeon Phi содержит блок векторных вычислений. За один такт процессора возможна обработка 16-ти 32-битных чисел или 8-ми 64-битных чисел. Векторизация кода при обработке массивов дает большой потенциал для ускорения работы программы при запуске на параллельных архитектурах.
+Для векторизации использовалась технология Array Notation расширения Intel Cilk Plus. Intel Cilk Plus --- расширение языков С и С++ для поддержки параллелизма, реализованное в компиляторе Intel.
+
+Для работы с массивом вместо цикла for в Array Notation используется конструкция
+\verb=array[start_index : length].=
+Например, следующий код к каждому $i$-му элементу массива W прибавляет $i$-й элемент массива Wdelta
+\begin{verbatim}W[0:count] += Wdelta[0:count]; \end{verbatim}
+С помощью Array Notation можно векторизовать выполнение и более сложных операций.
+Поиск максимального элемента в массиве выполняется при помощи выражения \verb=__sec_reduce_max=
+\begin{verbatim}const float max = __sec_reduce_max(in_vec[base:ncols]); \end{verbatim}
+Суммирование элементов массива --- при помощи \verb=__sec_reduce_add=
+\begin{verbatim}const float sumexp = __sec_reduce_add(in_vec[base:ncols]); \end{verbatim}
+
+После проведенной векторизации код был запущен на процессоре Intel Xeon на 12 ядрах (24 потока). Программа ускорилась в 14,5 раз, по сравнению с запуском невекторизованного кода на 1 ядре.
+
+\razdel{Портирование кода на архитектуру MIC}
+Для работы с Intel Xeon Phi была использована offload-модель передачи данных. В режиме offload блок кода, выделенный директивой \verb=#pragma offload= \verb=target (mic)=, выполняется на сопроцессоре, остальной код выполняется на основном процессоре. Также для каждой переменной необходимо указать сопроцессору размер выделяемой под нее памяти. Режим offload поддерживает две модели передачи данных: явную и неявную.
+
+\podrazdel{Явная модель передачи данных}
+При использовании явной модели программист указывает, какие именно переменные должны быть скопированы на сопроцессор. Также указывается направление копирования. Достоинством данной модели является возможность успешной компиляции кода любым компилятором, а не только Intel Compiler. Неизвестные директивы будут просто проигнорированы, без генерации ошибок, код будет скомпилирован для работы только на центральном процессоре.
+
+\Table{Сравнение времени работы и точности обучения}{l l p{1.2cm} p{1.3cm}l l}{
+Арх. & Версия программы & Кол-во потоков & Время, сек. & Ускорение & Точность \\
+\hline
+x86 & Исходная & \noindent\hphantom{00}1 & 7952 & $\times$\noindent\hphantom{0}1 & 19,19 \\
+x86 & Параллельная & \noindent\hphantom{0}48 & \noindent\hphantom{0}542 & $\times$14,7 & 18,99 \\
+MIC & Offload & 240 & 6889 & $\times$\noindent\hphantom{0}1,2 & 20,05 \\
+MIC & Cilk & 240 & \noindent\hphantom{0}589 & $\times$13,5 & 20,05 \\
+\hline
+}
+
+Функции обучения нейронной сети вызываются внутри двух вложенных циклов. Внутренний цикл был помечен для выполнения на сопроцессоре.
+К сожалению, у явной модели работы с памятью есть существенный недостаток. Она поддерживает лишь побитовое копирование данных.
+%Структура, содержащая поля-указатели, не может быть скопирована таким образом.
+В данной программе все характеристики нейронной сети содержатся в структуре nodeArg, содержащей поля-указатели. Она указывается в качестве аргумента для отправляемых на исполнение сопроцессору функций.
+Для корректного копирования структуры nodeArg на сопроцессор необходимо скопировать по отдельности каждое ее поле, и уже на сопроцессоре собрать структуру заново.
+
+Запуск на кластере показал, что такая модель передачи данных не подходит для данной задачи. Программа выполняется лишь не-\linebreak\newpage\noindentмного быстрее, чем на одном ядре процессора и в 12 раз медленнее, чем на всех ядрах (таблица~2). В связи с этим, было принято решение использовать неявную модель передачи данных на сопроцессор.
+
+\podrazdel{Неявная модель передачи данных}
+Основным принципом работы неявной модели является использование разделяемой между CPU и MIC памяти в рамках единого виртуального адресного пространства. Данный подход позволяет работать со сложными типами данных. Таким образом отпадает ограничение, связанное с побитовым копированием, возникающее при использование явной модели. Преобразование программы осуществлялось следующим образом.
+\begin{enumerate}
+\item Используемые данные отмечены ключевым словом\linebreak \verb=_Cilk_shared=, которое позволяет размещать их в разделяемой памяти.
+\begin{verbatim}
+nodeArg.d_B[i-1]=(_Cilk_shared
+float*)_Offload_shared_malloc(N*sizeof(float));
+\end{verbatim}
+\item Используемые внутри цикла обучения функции также отмечены как разделяемые:
+\begin{verbatim}
+#pragma offload_attribute (push, _Cilk_shared)
+...
+#pragma offload_attribute (pop)
+\end{verbatim}
+\item Создана отдельная функция для цикла обучения нейронной сети для ее использования в разделяемой памяти:
+\begin{verbatim}
+_Cilk_shared void dnn(NodeArg&, ChunkContainer&) {...}
+\end{verbatim}
+\item Функция, отправляемая для выполнения на сопроцессор помечена командой \verb=_Cilk_offload:=
+\begin{verbatim}
+_Cilk_offload dnn(nodeArg, oneChunk);
+\end{verbatim}
+\end{enumerate}
+
+Стоит отметить, что неявная схема работы оказалась более проста в использовании, по сравнению с явной схемой, и позволила достичь приемлемого времени обучения. Получено ускорение времени работы программы в 13,5 раз по сравнению с последовательной версией.
+
+%\vskip -1cm
+
+\razdel{Выводы}
+Проведено тестирование задачи обучения глубоких нейронных сетей на различных вычислительных архитектурах. Результаты представлены в таблице~2. Версия для MIC не дает прироста производительности по сравнению с параллельной версией для процессора. На это влияет много факторов, которые связаны как с особенностями алгоритма, так и с теми ограничениями, которые были поставлены при решении данной задачи. Итеративность выполнения алгоритма не дает большого потенциала для распараллеливания. Оптимизации поддается только каждый его шаг, связанный с вычислениями на матрице.
+Полученное ускорение в 13,5 раз при запуске на MIC архитектуре по сравнению с последовательной версией в целом кореллирует с результатами, полученными в других исследованиях~\cite{dnn-xeon-phi-thesis, dnn-xeon-phi-finance}. Кроме того, не был рассмотрен native-режим работы с сопроцессором, при котором весь код запускается на сопроцессоре без использования основного процессора. Возможно, это позволит добиться большего ускорения, но данный вопрос оставлен для последующих исследований.
+
+\razdel{Заключение}
+Исследован вопрос о возможности ускорения работы нейронных сетей с последовательным алгоритмом обучения, произведена оптимизация алгоритма для параллельных архитектур, указаны причины, влияющие на эффективность распараллеливания данной задачи. Также рассмотрен вопрос эффективности MIC-архитектуры для решения данной задачи.
+
+%список литературы
+\begin{thebibliography}{3}
+\bibitem{learning-deep-architectures} Bengio~Y. Learning deep architectures for AI // Foundations and trends in Machine Learning. 2009. Vol. 2, No~1. P. 1--127.
+\bibitem{dnn-xeon-phi-thesis} Viebke~A. Accelerated Deep Learning using Intel Xeon Phi: Ph.D. dissertation, Linnaeus University, 2015.
+\bibitem{dnn-xeon-phi-finance} Dixon~M., Klabjan~D., Bang~J.\:H. Implementing deep neural networks for financial market prediction on the Intel Xeon Phi // Proceedings of the 8\textsuperscript{th} Workshop on High Performance Computational Finance. 2015. Article No~6.
+\end{thebibliography}
+
+\end{document}
+% that's all folks
diff --git a/main.tex b/main.tex
@@ -1,128 +0,0 @@
-\documentclass[a4paper]{article}
-\usepackage{pmstyle}
-%\usepackage{showframe}
-
-\begin{document}
-%\hyphenation{СПбГУ}
-
-% УДК для статьи берется со страницы http://udc.biblio.uspu.ru/
-\udk{УДК 004.051}
-
-\author{Милова~Е.\:А., Свешникова~С.\:Ю., Ганкевич~И.\:Г.}
-%, Дегтярев~А.\:Б.
-%%%%%%%%% Название статьи
-\title{Ускорение обучения глубокой нейронной сети \\ путем оптимизации алгоритма \\ для запуска на MIC архитектуре}
-
-%подпись внизу страницы
-\renewcommand{\thefootnote}{ }
-{\footnotetext{{\it Милова Евгения Андреевна} -- студент, Санкт-Петербургский государственный университет; e-mail: milova.evg@gmail.com, тел.: +7(911)038-38-35}}
-{\footnotetext{{\it Свешникова Светлана Юрьевна} -- студент, Санкт-Петербургский государственный университет; e-mail: svetasvesh@yandex.ru, тел.: +7(812)428-47-83}}
-{\footnotetext{{\it Ганкевич Иван Геннадьевич} -- аспирант, Санкт-Петербургский государственный университет; e-mail: i.gankevich@spbu.ru, тел.: +7(812)428-47-83}}
-%{\footnotetext{{\it Дегтярев Александр Борисович} -- профессор, Санкт-Петербургский государственный университет; e-mail: deg@csa.ru, тел.: +7(812)428-47-83}}
-
-%сборка заголовка
-\maketitle
-
-%рекомендация научрука
-\recprof{Дегтяревым~А.\:Б.}
-
-\razdel{Введение}
-Глубокой нейронной сетью называют перцептрон с более, чем одним скрытым (обучающим) слоем. Для обучения такой сети обычно применяется метод обратного распространения ошибки~\cite{learning-deep-architectures}. Метод обратного распространения ошибки --- итеративный градиентный алгоритм, целью которого является минимизация ошибки при обучении нейронной сети. Итерация алгоритма состоит из трех основных шагов-функций: dnnForward прогоняет через сеть обучающую выборку, получая на выходе некоторый результат; dnnBackward вычисляет ошибку,
-%(разницу между результатом выполнения обучающей выборки и правильным ответом)
-затем в каждом слое сети, начиная с предпоследнего, для каждого узла вычисляет коррекцию весовых коэффициентов; dnnUpdate обновляет веса нейронов в соответствии с вычисленной ранее поправкой. Обучение сети заканчивается, когда ошибка достигает заданного минимально допустимого значения.
-Такая сеть показывает прекрасные результаты во многих областях, в том числе таких, как распознавание изображений и голоса. Однако ее недостатком является очень длительный процесс обучения. В связи с этим, решено исследовать вопрос об эффективности работы такого вида сетей на параллельных вычислительных архитектурах.
-Для тестирования взята нейронная сеть из 8 слоев (1 входящий, 6 скрытых, 1 выходящий). Для анализа результатов выбраны такие параметры, как скорость обучения нейронной сети и точность распознавания объектов. %Сеть считается правильно обученной, если точность $\geq19$.
-
-Запуск задачи производился на процессоре Intel Xeon (спецификация указана в таблице~1). Сначала был произведен запуск задачи с использованием только одного ядра. Затем произведена оптимизация кода для запуска на параллельной архитектуре. Также принято решение протестировать эффективность MIC-архитектуры для решения данной задачи. MIC (Many Integrated Core) --- архитектура, основой которой является использование большого количества вычислительных ядер архитектуры x86 в одном сопроцессоре, подключаемом к основному процессору. Характеристики используемого сопроцессора Intel Xeon Phi также указаны в таблице~1.
-
-\Table{Характеристики вычислителей, используемых для запуска задачи}{l p{0.7\textwidth}}{
-Процессор & 2$\times$Intel Xeon CPU E5-2695 v2 (12 ядер, 2 потока на ядро, 2,40ГГц ) \\
-Сопроцессор & Intel Xeon Phi-5110P (60 ядер, 4 потока на ядро, 1,053ГГц) \\
-\hline
-}
-
-%\podrazdel{Векторизация внутренних функций}
-\razdel{Оптимизация для запуска на параллельных архитектурах}
-Каждое ядро процессора Intel Xeon и сопроцессора Intel Xeon Phi содержит блок векторных вычислений. За один такт процессора возможна обработка 16-ти 32-битных чисел или 8-ми 64-битных чисел. Векторизация кода при обработке массивов дает большой потенциал для ускорения работы программы при запуске на параллельных архитектурах.
-Для векторизации использовалась технология Array Notation расширения Intel Cilk Plus. Intel Cilk Plus --- расширение языков С и С++ для поддержки параллелизма, реализованное в компиляторе Intel.
-
-Для работы с массивом вместо цикла for в Array Notation используется конструкция
-\verb=array[start_index : length].=
-Например, следующий код к каждому $i$-му элементу массива W прибавляет $i$-й элемент массива Wdelta
-\begin{verbatim}W[0:count] += Wdelta[0:count]; \end{verbatim}
-С помощью Array Notation можно векторизовать выполнение и более сложных операций.
-Поиск максимального элемента в массиве выполняется при помощи выражения \verb=__sec_reduce_max=
-\begin{verbatim}const float max = __sec_reduce_max(in_vec[base:ncols]); \end{verbatim}
-Суммирование элементов массива --- при помощи \verb=__sec_reduce_add=
-\begin{verbatim}const float sumexp = __sec_reduce_add(in_vec[base:ncols]); \end{verbatim}
-
-После проведенной векторизации код был запущен на процессоре Intel Xeon на 12 ядрах (24 потока). Программа ускорилась в 14,5 раз, по сравнению с запуском невекторизованного кода на 1 ядре.
-
-\razdel{Портирование кода на архитектуру MIC}
-Для работы с Intel Xeon Phi была использована offload-модель передачи данных. В режиме offload блок кода, выделенный директивой \verb=#pragma offload= \verb=target (mic)=, выполняется на сопроцессоре, остальной код выполняется на основном процессоре. Также для каждой переменной необходимо указать сопроцессору размер выделяемой под нее памяти. Режим offload поддерживает две модели передачи данных: явную и неявную.
-
-\podrazdel{Явная модель передачи данных}
-При использовании явной модели программист указывает, какие именно переменные должны быть скопированы на сопроцессор. Также указывается направление копирования. Достоинством данной модели является возможность успешной компиляции кода любым компилятором, а не только Intel Compiler. Неизвестные директивы будут просто проигнорированы, без генерации ошибок, код будет скомпилирован для работы только на центральном процессоре.
-
-\Table{Сравнение времени работы и точности обучения}{l l p{1.2cm} p{1.3cm}l l}{
-Арх. & Версия программы & Кол-во потоков & Время, сек. & Ускорение & Точность \\
-\hline
-x86 & Исходная & \noindent\hphantom{00}1 & 7952 & $\times$\noindent\hphantom{0}1 & 19,19 \\
-x86 & Параллельная & \noindent\hphantom{0}48 & \noindent\hphantom{0}542 & $\times$14,7 & 18,99 \\
-MIC & Offload & 240 & 6889 & $\times$\noindent\hphantom{0}1,2 & 20,05 \\
-MIC & Cilk & 240 & \noindent\hphantom{0}589 & $\times$13,5 & 20,05 \\
-\hline
-}
-
-Функции обучения нейронной сети вызываются внутри двух вложенных циклов. Внутренний цикл был помечен для выполнения на сопроцессоре.
-К сожалению, у явной модели работы с памятью есть существенный недостаток. Она поддерживает лишь побитовое копирование данных.
-%Структура, содержащая поля-указатели, не может быть скопирована таким образом.
-В данной программе все характеристики нейронной сети содержатся в структуре nodeArg, содержащей поля-указатели. Она указывается в качестве аргумента для отправляемых на исполнение сопроцессору функций.
-Для корректного копирования структуры nodeArg на сопроцессор необходимо скопировать по отдельности каждое ее поле, и уже на сопроцессоре собрать структуру заново.
-
-Запуск на кластере показал, что такая модель передачи данных не подходит для данной задачи. Программа выполняется лишь не-\linebreak\newpage\noindentмного быстрее, чем на одном ядре процессора и в 12 раз медленнее, чем на всех ядрах (таблица~2). В связи с этим, было принято решение использовать неявную модель передачи данных на сопроцессор.
-
-\podrazdel{Неявная модель передачи данных}
-Основным принципом работы неявной модели является использование разделяемой между CPU и MIC памяти в рамках единого виртуального адресного пространства. Данный подход позволяет работать со сложными типами данных. Таким образом отпадает ограничение, связанное с побитовым копированием, возникающее при использование явной модели. Преобразование программы осуществлялось следующим образом.
-\begin{enumerate}
-\item Используемые данные отмечены ключевым словом\linebreak \verb=_Cilk_shared=, которое позволяет размещать их в разделяемой памяти.
-\begin{verbatim}
-nodeArg.d_B[i-1]=(_Cilk_shared
-float*)_Offload_shared_malloc(N*sizeof(float));
-\end{verbatim}
-\item Используемые внутри цикла обучения функции также отмечены как разделяемые:
-\begin{verbatim}
-#pragma offload_attribute (push, _Cilk_shared)
-...
-#pragma offload_attribute (pop)
-\end{verbatim}
-\item Создана отдельная функция для цикла обучения нейронной сети для ее использования в разделяемой памяти:
-\begin{verbatim}
-_Cilk_shared void dnn(NodeArg&, ChunkContainer&) {...}
-\end{verbatim}
-\item Функция, отправляемая для выполнения на сопроцессор помечена командой \verb=_Cilk_offload:=
-\begin{verbatim}
-_Cilk_offload dnn(nodeArg, oneChunk);
-\end{verbatim}
-\end{enumerate}
-
-Стоит отметить, что неявная схема работы оказалась более проста в использовании, по сравнению с явной схемой, и позволила достичь приемлемого времени обучения. Получено ускорение времени работы программы в 13,5 раз по сравнению с последовательной версией.
-
-%\vskip -1cm
-
-\razdel{Выводы}
-Проведено тестирование задачи обучения глубоких нейронных сетей на различных вычислительных архитектурах. Результаты представлены в таблице~2. Версия для MIC не дает прироста производительности по сравнению с параллельной версией для процессора. На это влияет много факторов, которые связаны как с особенностями алгоритма, так и с теми ограничениями, которые были поставлены при решении данной задачи. Итеративность выполнения алгоритма не дает большого потенциала для распараллеливания. Оптимизации поддается только каждый его шаг, связанный с вычислениями на матрице.
-Полученное ускорение в 13,5 раз при запуске на MIC архитектуре по сравнению с последовательной версией в целом кореллирует с результатами, полученными в других исследованиях~\cite{dnn-xeon-phi-thesis, dnn-xeon-phi-finance}. Кроме того, не был рассмотрен native-режим работы с сопроцессором, при котором весь код запускается на сопроцессоре без использования основного процессора. Возможно, это позволит добиться большего ускорения, но данный вопрос оставлен для последующих исследований.
-
-\razdel{Заключение}
-Исследован вопрос о возможности ускорения работы нейронных сетей с последовательным алгоритмом обучения, произведена оптимизация алгоритма для параллельных архитектур, указаны причины, влияющие на эффективность распараллеливания данной задачи. Также рассмотрен вопрос эффективности MIC-архитектуры для решения данной задачи.
-
-%список литературы
-\begin{thebibliography}{3}
-\bibitem{learning-deep-architectures} Bengio~Y. Learning deep architectures for AI // Foundations and trends in Machine Learning. 2009. Vol. 2, No~1. P. 1--127.
-\bibitem{dnn-xeon-phi-thesis} Viebke~A. Accelerated Deep Learning using Intel Xeon Phi: Ph.D. dissertation, Linnaeus University, 2015.
-\bibitem{dnn-xeon-phi-finance} Dixon~M., Klabjan~D., Bang~J.\:H. Implementing deep neural networks for financial market prediction on the Intel Xeon Phi // Proceedings of the 8\textsuperscript{th} Workshop on High Performance Computational Finance. 2015. Article No~6.
-\end{thebibliography}
-
-\end{document}
-% that's all folks
diff --git a/makefile b/makefile
@@ -0,0 +1,16 @@
+NAME = cps-16-mic
+
+$(NAME).pdf: $(NAME).tex makefile
+ pdflatex $(NAME)
+ pdflatex $(NAME)
+ ls *.bib 2>/dev/null && bibtex $(NAME) || true
+ pdflatex $(NAME)
+
+%.eps: %.svg
+ inkscape --without-gui --export-eps=$@ $<
+
+clean:
+ rm -f $(NAME).log $(NAME).aux $(NAME).pdf *-converted-to.pdf
+ rm -f $(NAME).nav $(NAME).snm $(NAME).toc $(NAME).out
+ rm -f $(NAME).bbl $(NAME).blg $(NAME).vrb
+