Реализация нейронной сети на FPGA Автор: Ханов А.Р.<[email protected]>, СПбГУ, мат-мех, аспирант Руководитель: Баклановский М.В. Нейронные сети широко применяются при решении задач аппроксимации и распознавания образов. Эти задачи остро стоят и в информационной безопасности, особенно в таких задачах как распознавание CAPTCHA, анализ сетевого трафика, обнаружение DOS-атак, разработка различных IDS и IPS -систем. Увеличение скорости работы нейронных сетей является важной и актуальной проблемой. Одним из способов, позволяющих ускорить их работу за счет использования параллелизма, который свойственен самой нейронной сети, является ее реализация на кристалле. Существуют различные варианты ее построения, включая реализации на жестких и гибких кристаллах, с использованием различных типов параллелизма [1]. В данной работе представлена реализация нейронной сети на гибком кристалле. Принципиально разными являются задачи реализации нейронных сетей с обучением и без обучения. В первом случае нам известна структура сети и веса синапсов нейронов, необходимо лишь реализовать саму эту сеть и некоторый входной и выходной интерфейсы. При решении второй задачи необходимо реализовывать некоторый алгоритм обучения. Нами решалась первая задача. Необходимо реализовать генератор нейронной сети по ее описанию на некотором псевдоязыке, в котором указана ее структура и весовые коэффициенты. Было решено ограничиться структурами нейронной сети с топологией типа персептрон. При реализации нейронной сети возможно использование нескольких типов параллелизма. При этом по-разному будут использованы ресурсы на кристалле. Нами использовался параллелизм, при котором нейроны на каждом такте накапливают взвешенную сумму, обрабатывая по одному значению из предыдущего слоя за такт. Данные между слоями также передаются последовательно, на каждом такте все нейроны слоя обрабатывают одно и то же значение. При этом для каждого нейрона потребуется лишь один умножитель и сумматор, весь слой будет вычислен за число тактов, равное числу синапсов у каждого нейрона слоя, для всех слоев кроме первого это число равно числу нейронов в предыдущем слое. В результате вся нейронная сеть будет вычислена за число тактов, равное числу нейронов во всех слоях. Был реализован генератор нейронных сетей на языке Perl. В качестве описания он принимает XML-файл, в результате получается программа на языке VHDL, которая реализуют описанную нейронную сеть в виде компонента. В процессе реализации было несколько сложностей. При реализации на процессоре обычно используются типы данных float или double. Использование этих типов данных на кристалле осложнено тем, что компоненты, которые проводят операции с этими типами данных, занимают на кристалле большую площадь. Поэтому было решено использовать числа с фиксированной точкой. Операции с числами с фиксированной точкой следует проводить по следующим формулам: a, p g , q ap * 2| p| gq * 2|q| (ap gq) * 2| p| , | p || q | a, p * g , q ap * 2| p| * gq * 2|q| ap * gq * 2| p||q| ap * gq * 22| p| Здесь a,g – целые части чисел, p,q – дробные части. При сложении чисел с фиксированной точкой разрядность результата увеличивается на единицу. При умножении двух чисел с фиксированной точкой удваивается число бит в целой и дробной части. В случае переполнения мы записываем наибольшее возможное число, при умножении мы отбрасываем половину самых младших бит дробной части. При этом, работая с числами с фиксированной точкой, мы фактически работаем с целыми числами. Более подробно про потери точности при вычислениях с фиксированной точкой можно узнать в [2]. Во-вторых, реализация непрерывной функции активации, сигмоидной или биполярной, может быть различной. В нашей реализации эта функция приближалась фиксированным числом значений на заранее определенном отрезке. Все значения аргумента, лежащие за пределами отрезка, приближались максимальным или минимальным значениями. Подробнее про аппроксимацию функций активации можно узнать здесь [1]. Были проведены тесты, которые оценивают потерю точности результата при различном числе бит в дробной части. Нейронная сеть из 5 нейронов в скрытом слое и одного входного и выходного нейрона была обучена для приближения функции синуса на отрезке от 0 до 3 Пи по 50 произвольным точкам. Далее был сгенерирован код на VHDL, который реализовывал данную структуру на кристалле. В таблице показана средняя квадратическая ошибка вычисления значения функции по 25 последовательным точкам по сравнению с нейросетью, реализованной на процессоре и использующей тип double для работы. Таблица 1. Оценка средней квадратической ошибки вычисления по сравнению с реализацией на процессоре. Число бит в целой и дробной части 12,4 12,8 Суммарная кв. ошибка 0,58760 0,38661 12,12 12,16 0,36965 0,36977 По данной таблице видно, что уже при 8 битах на дробную часть ошибка начинает уменьшаться довольно незначительно. Был проведен синтез данной нейронной сети при различном количестве бит в дробной части для кристалла Spartan 3E 1200K. Синтез проходил на Xilinx ISE 12.1. Результаты показаны в таблице. В первой строке указано число бит для целой и дробной частей, во второй – период и частота прошивки для данного кристалла. Таблица 2. Результаты синтеза Точность Период, частота 12, 4 10.957 нс 91.266 МГц 12, 8 14.401 нс 69.440 МГц 12,12 14.935 нс 66.957 МГц 12,16 15.815 нс 63.231 МГц 12, 20 15.944 нс 62.720 МГц При точности 4 бита в дробной части нейронная сеть уже выдает достаточно точные результаты, и при этом она занимает меньше ресурсов на кристалле. Для тестирования генератора нейронных сетей были реализованы различные топологии сетей с точностью 12 бит на целую и 4 на дробную части. Была реализована нейронная сеть с 40 нейронами в скрытых слоях. Результаты синтеза показаны в таблице. В первом столбце указано число нейронов в каждом из слоев, первый является входным, последний – выходным. В остальных столбцах – различные характеристики, получаемые в результате синтеза. Таблица 3. Результаты синтеза различных топологий структура Период, частота 4 input LUT Число умножителей Slice Flip Flops 90 – 20 – 20 - 10 19.985ns 50.038MHz 8,631(49%) 28(100%) 1,021(5%) 90–10-1010-10 – 10 19.297ns 51.822MHz 5,533(31%) 28(100%) 1,149(6%) 90-40-10 20.493ns 48.797MHz 9,986(57%) 28(100%) 954(5%) При одинаковом количестве нейронов увеличение числа слоев, по которым они распределены, приводит к уменьшению занимаемых на кристалле ресурсов из-за меньшего числа связей между нейронами. Самым востребованным ресурсом оказываются умножители. Оценим скорость работы нашей нейронной сети. Для структуры 90-2020-10 мы имеем частоту около 50 МГц, так как наша реализация сети работает за число тактов, равное числу нейронов в сети, то входной вектор вычисляется за (90+20+20+10)*20 = 2800 нс = 2,8 мкс. Реализация нейронной сети из библиотеки AForge.NET вычисляла одно выходное значение за 7.6 мкс. В результате был написан генератор нейронных сетей для кристалла. Несмотря на то, что компонент был синтезирован для не самого современного кристалла, был получен выигрыш в 2.7 раз по скорости по сравнению с реализацией на С# в библиотеке AForge.NET. При использовании нашего типа параллелизма возникает возможность конвейерной обработки, при которой нейросеть вычисляет сразу несколько значений одновременно. В будущем планируется соединение кристалла с ПК через шину PCIe как внешнего вычислительного модуля для нейронных сетей. Список литературы [1] FPGA NEUROCOMPUTERS , Amos R. Omondi, Jagath C. Rajapakse, Mariusz Bajger, FPGA Implementations of Neural Networks, 2006, pp 1-36 [2] J. L. Holt and J. N. Hwang. 1993. Finite-precision error analysis of neural network hardware implementations. IEEE IEEE Transactions on Computers, 42(3):280–290