[Из песочницы] Глубокое обучение и Raspberry PI


«Что у нас есть?» — спросил горбоносый поворачиваясь.
«Алдан-3», — сказал бородатый.
«Богатая машина, — сказал я.”[1]

Недавно я решил заняться изучением глубокого обучения. На работе мне выдали новую карточку с поддержкой CUDA и шеф выразил пожелание что эта вершина инженерной мысли позволит нашей лаборатории сделать рывок вперёд, ну или по крайней мере, не отстать от массы конкурентов. У меня уже был некоторый опыт общения с Tensor Flow, но в этот раз я решил попробовать Torch. Привлекало что он написан на языке Lua и C, является достаточно легковесным и легко расширяемым через FFI. И ещё мне не нравится Python.

Недавно на Хабрахабр я наткнулся на статью, в процессе обсуждения которой я вспомнил что где-то в тумбочке у меня пилится Raspberry Pi, модель B+ и мне захотелось посмотреть — а смогу ли я поднять на ней torch и запустить что-нибудь несложное.

Естественно первым делом я захотел посмотреть как на моем десктопе с новой карточкой GPU будет тренироваться alexnet и другие известные сети. На гитхабе есть небольшой проект в котором несколько популярных сетей реализованы на Torch[1]. Поигравшись с ними, я перешёл на решение своих задач, но про них я тут говорить не буду.

А теперь переходим к малинке (Raspberry PI модель B+).

Установка

Копируем инсталлятор torch на малинку[2]:

apt-get install git-core  
git clone https://github.com/torch/distro.git ~/torch --recursive

Первым делом, я решил что мне не хочется ждать пока стандартный установщик Torch скомпилирует OpenBLAS и установит QT со всеми зависимостями, поэтому я решил проделать это вручную:

apt-get install -y build-essential gcc g++ curl cmake libreadline-dev libjpeg-dev libpng-dev ncurses-dev imagemagick libzmq3-dev gfortran libopenblas-base libopenblas-dev

Запускаем компиляцию torch:

cd ~/torch;
./install.sh

У меня компиляция всего занимает примерно час.

— А что это там у вас за лампа? — подозрительно спросил Фарфуркис. [1]

И тут нас ждёт первый облом: создатели torch: не предполагали что его будут компилировать на архитектуре arm, но без поддержки NEON:

[  6%] Building C object lib/TH/CMakeFiles/TH.dir/THVector.c.o
In file included from /home/pi/torch/pkg/torch/lib/TH/THVector.c:2:0:
/home/pi/torch/pkg/torch/lib/TH/generic/THVectorDispatch.c: In function ‘THByteVector_vectorDispatchInit’:
/home/pi/torch/pkg/torch/lib/TH/generic/simd/simd.h:64:3: error: impossible constraint in ‘asm’
   asm volatile ( "cpuid\n\t"

Пришлось пофиксить это дело[3]. И после этого, всё заработало! Если вам лень делать это всё самому и хочется быстро попробовать пример, я сделал архив с пред-компилированным torch для Raspberry PI -B (без поддержки NEON): https://github.com/vfonov/deep-pi/releases/download/v1/torch_intstall_raspbian_arm6l_20161218.tar.gz[4], распаковывается в /home/pi

Тестирование

Для проверки я решил посмотреть скорость тренировки распознавания рукописных цифр MNIST[5], соответствующий пример есть в наборе демок[6] для Torch:

th train-on-mnist.lua 
<torch> set nb of threads to 4  
<mnist> using model:    
nn.Sequential {
  [input -> (1) -> (2) -> (3) -> (4) -> (5) -> (6) -> (7) -> (8) -> (9) -> (10) -> output]
  (1): nn.SpatialConvolutionMM(1 -> 32, 5x5)
  (2): nn.Tanh
  (3): nn.SpatialMaxPooling(3x3, 3,3, 1,1)
  (4): nn.SpatialConvolutionMM(32 -> 64, 5x5)
  (5): nn.Tanh
  (6): nn.SpatialMaxPooling(2x2, 2,2)
  (7): nn.Reshape(576)
  (8): nn.Linear(576 -> 200)
  (9): nn.Tanh
  (10): nn.Linear(200 -> 10)
}
<warning> only using 2000 samples to train quickly (use flag -full to use 60000 samples)    
<mnist> loading only 2000 examples  
<mnist> done    
<mnist> loading only 1000 examples  
<mnist> done    
<trainer> on training set:  
<trainer> online epoch # 1 [batchSize = 10] 
 [===================>.................... 471/2000 ....................................]  ETA: 2m20s | Step: 92ms      

В общем неплохо, для сравнения — на десктопе с i5-4590 CPU @ 3.30GHz, без использования GPU:

[=======================>................ 571/2000 ....................................]  ETA: 27s613ms | Step: 19ms   

Т.е в этом примере малинка работает примерно в 5 раз медленнее чем современный десктоп.

Распознавания изображений

одушевлённый теперь «Алдан» иногда печатал на выходе: «Думаю. Прошу не мешать» [1]

Теперь настал черёд заставить малинку распознавать изображения с помощью натренированной googlenet. Тут меня ждал второй подвох: в Alexnet такое огромное количество параметров, что памяти малинки уже не хватает. Но тут на выручку приходит squeezenet и Network-in-Network, автор последней даже сделал натренерованную модель в формате для torch[7].

Для начала надо преобразовать модель так чтобы её можно было использовать на архитектуре ARM (тренировать на Raspberry PI не стоит — результаты будут готовы лет через сто).

На десктопе надо загрузить модель в бинарном формате torch, и записать в формате ‘ascii’, потом на малинке — преобразовать обратно:

Desktop:

model=torch.load(‘blah.t7’)
torch.save(‘blah_ascii.t7’,model,’ascii’)

Raspberry PI:

model=torch.load(‘blah_ascii.t7’,’ascii’)
torch.save(‘blah_arm.t7’,model)

Версию для arm можно загрузить тут[8].

Я сделал маленький скриптик для проверки работоспособности на малинке:
Полный текст тут[9].

...
local m=torch.load(prefix..'nin_bn_final_arm.t7')
...
local input=image.load(prefix.."n07579787_ILSVRC2012_val_00049211.JPEG")
...
local output=model:forward(cropped)
...

И вуаля, запускаем с изображением из тестового набора ImageNET[10]:

>th test_single.lua n07579787_ILSVRC2012_val_00049211.JPEG
loading model:0.57sec   
Running neural net:13.46sec 
 25.3%: n07579787: plate    
 13.8%: n07873807: pizza, pizza pie     
 8.8%: n04263257: soup bowl     
 8.0%: n07590611: hot pot, hotpot   
 7.2%: n07831146: carbonara     

T.e за 14 сек малинка удачно справилась с процедурой распознавания образов!

Настало время сделать пример поинтересней: приделываем интерфейс к камере из пакета camera и веб интерфейс из пакета display, и у нас получается интерактивная машина, раз в 14 секунд объявляющая миру что она видит. Надо только установить пакет для работы с камерой (luarocks install camera) и для визуализации через веб-интерфейс (luarocks install display).

Полный текст тут[11].

…
-- подцепляем камеру
local cam = image.Camera {idx=0,width=iW,height=iH}
...
  local frame = cam:forward()
  local cropped = image.crop(frame, w1, h1, w1+oW, h1+oH) -- center patch
…
 -- отправляем кадр зрителю
  display_sample_in.win=display.image(cropped,display_sample_in)
…
 -- прогоняем его через нейросеть
  local output=model:forward(cropped)
…
-- отправляем описание - чего увидели
  display_output.win=display.text(out_text,display_output)

Перед запуском надо запустить демона из пакета display: nohup th -ldisplay.start 8000 0.0.0.0 &

Испытания

Тестовая установка:

image

Результат:

image

image

image

Заключение

Итак у нас получилась недорогая машинка для распознавания образов, которой вы можете порадовать ваших друзей во время новогодних праздников. Естественно, задача классификации изображения может быть заменена на что-то более продуктивное, например можно легко сделать систему для идентификации человека по физиономии, несколько примеров есть тут[12] или можно идентифицировать фигуры людей[13] на камере наблюдения за вашим огородом.

Для оптимизации производительности можно попробовать использовать nnpack[14], или даже сделать интерфейс к векторному ускорителю встроенному в процессор малинки как тут[15].

Примечания:

Цитаты из «Понедельник начинается в субботу» и «Сказка о тройке» А. и Б. Стругацких.
Описание процедуры на английском и репозиторий со всеми исходниками находится на гитхабе[16].

Использованны источники

  1. ^ Torch (github.com)
  2. ^ малинку (torch.ch)
  3. ^ пофиксить это дело (github.com)
  4. ^ https://github.com/vfonov/deep-pi/releases/download/v1/torch_intstall_raspbian_arm6l_20161218.tar.gz (github.com)
  5. ^ MNIST (yann.lecun.com)
  6. ^ наборе демок (github.com)
  7. ^ модель в формате для torch (gist.github.com)
  8. ^ тут (github.com)
  9. ^ тут (github.com)
  10. ^ ImageNET (image-net.org)
  11. ^ тут (github.com)
  12. ^ тут (torch.ch)
  13. ^ идентифицировать фигуры людей (github.com)
  14. ^ nnpack (github.com)
  15. ^ тут (github.com)
  16. ^ гитхабе (github.com)
По теме: ( из рубрики )

    Оставить отзыв

    Ваш адрес email не будет опубликован. Обязательные поля помечены *

    *
    *

    4 × 3 =

    Top