company_banner

Установка Facebook image recognition package. Все грабли в одном месте

    Недавно Facebook выпустила свой open-source-проект по распознаванию образов. Конечно же, его сразу захотелось пощупать, посмотреть, как он работает и что с его помощью можно получить. Мы решили разобраться с его установкой и опытным путём проверить, так ли легко его использовать, как об этом пишут в инструкции разработчики.


    Этот проект не самый простой, поэтому возникает вопрос, зачем он нужен, если есть готовые фреймворки типа Keras, TensorFlow и Caffe, где, как говорится, «сел и поехал»? А ответ прост: нужен гибкий инструмент с возможностью расширения, с которым подружится Python. Научились мы отличать кита от чайки, но что нам это даст? IFunny серьёзно делает весёлое приложение и хочет удивлять пользователей новыми фичами, так почему бы не изучить такое богатое направление и применить?


    Прочитав этот разбор, вы станете на шаг ближе к просветлению. Готовы? Тогда хватайте ручку, бумагу и приступаем!


    И да, можно смело считать эту статью мануалом по установке, причём пошаговым, но можно и обращаться к ней в случае, если вылезла ошибка, а Google отводит глаза в сторону или выдаёт в поисковике несусветную чушь.


    Приступая к установке


    Немного не доходя до момента, когда нужно написать первый git clone для их проекта, остановимся на этапе железа и окружения.


    Вроде бы всё прозрачно и красиво. Но. Начнём с железа. Проект очень и очень требовательный. Особенно к памяти, свопу и видеокарте. Изначально сборка велась на AWS-инстансе с конфигурацией:


    • OS: Linux Redhat 2017.09 (EC2) → Ubuntu 16.04 LTS
    • CPU: 16 x Intel® Xeon® CPU E5-2686 v4 @ 2.30GHz;
    • HDD: 1 Tb;
    • Swap: 16 Gb →128 Gb (!!!);
    • RAM: 122 Gb (7 x 16 Gb, 1 x 10 Gb);
    • Graphic adapter: GRID K520 → Tesla M60.

    Почему Ubuntu LTS?

    Лучше сразу используйте Ubuntu LTS, поскольку в нём уже есть все необходимые базовые компиляторы последних версий или же несложно обновиться до последних версий. В процессе сборки и запуска будет понятно, почему мы так резко перескочили с одной системы на другую, поменяли видеокарту и накинули своп.


    Если хотите собрать всё это из любопытства, чтобы посмотреть, как это работает и поиграться, то обзаведитесь как минимум видеокартой с технологией CUDA. Без неё пытаться запуститься бесполезно. Чтобы понимать, какая видеокарта что может — вот линк на вики.


    Видеокарта GRID K520 относится к CUDA capability 3.0+. С ней уже можно работать, но не так быстро как хотелось бы.


    Поехали? Или постоим чуть-чуть…


    Ставим пакет от Nvidia


    Приступаем непосредственно к окружению. Для начала убедимся, что у нас g++ версии не ниже 4.9, иначе в самом конце нас может постигнуть фиаско. Берите самый новый, самый свежий g++, только что из репозитория. Далее ставим свеженькие драйвера от Nvidia.


    sudo yum install nvidia #что-то такое, у амазона свой репозиторий
    sudo yum install cuda #да, именно так, всё просто
    nvcc --version #версия CUDA

    Зарегистрируйтесь на http://developers.nvidia.com и скачайте cuDNN-библиотеку для вашей версии CUDA.



    cd ~/
    tar -xzvf cudnn-$VERSION-linux-x64-v7.tgz

    Для Ubuntu 16.04 всё выглядит попроще:


    sudo apt-get install nvidia-384*
    sudo apt-get install nvidia-cuda-dev
    sudo apt-get install nvidida-cuda-toolkit

    И вот тут можно поступить по-разному. Официальный мануал требует, чтобы мы скопировали файлы в разные места. Можно согласиться с мануалом и скопировать так, как указано. Но можно поступить проще. Из cuda/include скопировать библиотеки в /usr/local/cuda/lib64.


    Установка Lua и LuaRocks


    Дальше. Нам нужна Lua и LuaRocks (ещё один менеджер пакетов — мало нам, мало). Тут всё просто для обеих ОС:


    curl -R -O http://www.lua.org/ftp/lua-5.3.4.tar.gz
    tar zxf lua-5.3.4.tar.gz
    cd lua-5.3.4
    make linux test
    cd ~/
    wget luarocks-2.4.3.tar.gz
    tar -xvf luarocks-2.4.3.tar.gz
    cd luarocks-2.4.3
    ./configure
    make build
    sudo make install
    cd ~/

    Устанавливаем Torch7 и его зависимости


    У нас уже есть luarocks-менеджер зависимостей. А теперь самое интересное: нужно поставить часть зависимостей через LuaRocks (всё не выйдет, иначе поставленное и вовсе не взлетит). Вообще, при установке именно этих зависимостей проблем возникнуть не должно, но тут есть много-много маленьких грабелек (а как же без них).


    1. Torch (должен установиться Torch7).


      git clone https://github.com/torch/distro.git ~/torch --recursive
      cd ~/torch;
      bash install-deps;
      # ./install.sh — так не надо делать, в LUAJIT21 сломано получение содержимого 
      #файла в виде датасета
      TORCH_LUA_VERSION=LUA52 ./install.sh # ставим lua52 и радуемся: всё 
      #компилируется и работает, на warning внимания не обращайте
      source ~/.bashrc # тогда заработает запуск torch через th и будут экспортированы 
      #пути к библиотекам

      По идее, ничто не остановит вас в этот момент, кроме ошибки с 'half'. Данная проблема решается следующим образом: сначала выполняем в консоли команду


      export TORCH_NVCC_FLAGS="-D__CUDA_NO_HALF_OPERATORS__".

      Затем запускаем установку заново.


    2. COCO API: собирается только из исходников, но хотя бы ставится без проблем.


      git clone https://github.com/cocodataset/cocoapi.git
      cd cocoapi
      luarocks make LuaAPI/rocks/coco-scm-1.rockspec

    3. image: проблем нет. Ставим через luarocks: luarocks install image


    4. tds: внезапно это не пакет и вообще ставить надо lua ffi


      luarocks install --server=http://luarocks.org/dev luaffi

    5. cjson: по идее проблем нет, разве что пакет называется json.


      luarocks install json

    6. nnx: и вот тут засада. Вы ведь уже порадовались собранному фреймворку Torch? Тогда клонируем репозиторий в корень torch и ПЕРЕСОБИРАЕМ его целиком. Здесь необходимо уточнить, что сразу собрать с nnx не удастся, в его зависимостях как раз указаны пакеты COCO API, image, tds и cjson.


    7. optim: проблем не найдено, ставится напрямую luarocks install optim.


    8. inn: аналогично luarocks install inn.


    9. cutorch, cunn, cudnn — ставить именно в такой последовательности
      luarocks install cutorch
      luarocks install cunn
      luarocks install cudnn

    Вроде бы всё поставили. Но не покидает чувство что что-то забыли… Что-то важное… Так и есть. Сам проект кто клонировать будет?


    cd ~/
    git clone https://github.com/facebookresearch/deepmask.git
    cd deepmask

    Устанавливаем модели для обучения


    Затянули? Молодцы. А вот теперь будет самая долгая часть. Скачиваем обучающие паки и сетки. И у нас есть два пути. Первый путь — скачать готовые модели и, не обучая сеть, сразу приступить к проверке своей картинки (тут можно смело пропускать шаг тренировки нейросети и сразу ставить зависимости дальше).


    Скачиваем и запускаем
    mkdir -p pretrained/deepmask;
    cd pretrained/deepmask
    wget https://s3.amazonaws.com/deepmask/models/deepmask/model.t7
    mkdir -p pretrained/sharpmask;
    cd pretrained/sharpmask
    wget https://s3.amazonaws.com/deepmask/models/sharpmask/model.t7
    cd ~/deepmask/
    th computeProposals.lua pretrained/deepmask # run DeepMask
    th computeProposals.lua pretrained/sharpmask # run SharpMask
    th computeProposals.lua pretrained/sharpmask -img /path/to/image.jpg

    Как уже было сказано, скачанных моделей достаточно для быстрого старта. Так можно поступить, чтобы не обучать нейросеть в течение нескольких дней, но этого мало для чего-то более серьёзного. Второй путь начинается здесь. Поэтому продолжаем.


    mkdir -p pretrained
    wget https://s3.amazonaws.com/deepmask/models/resnet-50.t7 # ой ой ой, 250 Мб.
    mkdir -p ~/deepmask/data; 
    cd ~/deepmask/data
    wget http://msvocds.blob.core.windows.net/annotations-1-0-3/instances_train-val2014.zip # ~158 Mb
    wget http://msvocds.blob.core.windows.net/coco2014/train2014.zip # ~13 Gb >85k файлов
    wget http://msvocds.blob.core.windows.net/coco2014/val2014.zip # ~6.2 Gb >40k файлов

    Решаем ошибки с CUDA


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


    th train.lua --help
    ....
    THCudaCheck FAIL file=/home/ubuntu/torch/extra/cutorch/lib/THC/THCGeneral.c line=70 error=30 : unknown error
    /home/ubuntu/torch/install/bin/lua: /home/ubuntu/torch/install/share/lua/5.2/trepl/init.lua:389: cuda runtime error (30) : unknown error at /home/ubuntu/torch/extra/cutorch/lib/THC/THCGeneral.c:70


    Когда не хватило CWRAP-модуля

    Смотрим trace. Хм… Очень похоже на то, что не хватает установленных зависимостей: cunn, cudnn установился криво. Ладно, переустанавливаем. Но дело не в них. Let's make an investigation! Проверяем дальше. Пробуем снова установить cutorch и… Бинго! Модуль cwrap не обнаружен.


    Устанавливаем, что ж ещё остаётся делать.


    luarockt install cwrap
    luarockt install cutorch 

    И тут мы снова получаем ошибку, что модуль cwrap не установлен. WTF? Не буду углубляться в механику LuaRocks, но именно пакет cwrap нельзя поставить вот так, сходу. Копаемся в помощнике и находим следующее: «в случае если пакет установлен, но по сути его нет, примените директиву --local». Пакет Шрёдингера. Вроде есть, но его нет. Ладно.


    luarockt install --local wrap

    И снова те же грабли. А вот это уже не смешно. Ставить всё это под sudo категорически не рекомендую. Ну вот зачем математическому пакету суперпользователь? Несколько шагов, которые помогают установить этот пакет из rockspec-файла. Проверьте пути LUA_PATH и LUA_CPATH и выполните следующие команды:


    cd ~/torch
    git clone https://github.com/torch/cwrap.git
    cd cwrap
    cmake .
    cd ..
    TORCH_LUA_VERSION=LUA52 ./install.sh
    cd cwrap
    luarocks make rocks/cwrap-scm-1.rockspec
    luarocks install cutorch
    luarocks install inn
    luarocks install cunn
    luarocks install cudnn

    Обучаем нейросеть (если модели были скачаны — пропускайте этот шаг)


    Справились. Пора приступать к обучению нейросети. Дальнейшие действия могут занять и несколько суток! Внимательно смотрите на те опции, с которыми запускаете тренировку и валидацию!


    cd ~/deepmask
    th train.lua --help
    ```bash
    Смотрим, какие опции он нам предлагает по умолчанию. Описываю только те, которые можно менять или буду менять сам. 
    ```bash
    -nthreads # параметр очень интересный — количество потоков обработки. 
    #Максимальное значение равно количеству (!) ФИЗИЧЕСКИХ (!) процессоров, 
    #в случае с нашим инстансом амазона — 16
    -batch # размер пачки для обработки. По умолчанию 32
    -maxload # я оставил его как есть, поскольку мне нужно обучение на полной 
    #базе. По умолчанию 4000
    -testmaxload # число пачек для валидации. Можно поиграть с параметром, 
    #но учитывайте, что это напрямую влияет на количество памяти, которое 
    #требуется; по умолчанию 500
    -maxepoch  # число эпох. По умолчанию 300 эпох. Это слишком много, 
    #далее станет ясно почему

    Итак, приступим. Раз уж нам достался такой мощный инстанс, что же нам мешает загрузить по максимуму процессоры?


    th train.lua -nthreads 16 -batch 500

    Упс… А ведь Nvidia установила свои библиотеки и отмахивается от всяких vcc --version правильной инфой. Только вот библиотеки лежат в /home/ubuntu/cuda/lib64/libcudnn.so.5. А это значит, что в самый конец файла .bashrc добавляем директиву:


    export CUDNN_PATH="/home/ubuntu/cuda/lib64/libcudnn.so.5"

    По идее, нас ждёт счастье, но нет. Мы снова можем наступить на грабли. Достаточно серьёзные.
    В случае, если грабли найдены не были, то увидите текст, похожий на текст на скриншоте.



    Либо одно из сообщений об ошибке. Сами ошибки и методы их решения подробно описаны под спойлерами.


    th train.lua -nthreads 16 -batch 500

    Вывод в консоль с ошибкой
    Found Environment variable CUDNN_PATH = /home/ubuntu/cuda/lib64/libcudnn.so.5-- ignore option dm
    -- ignore option reload 
    -- ignore option datadir
    nthreads        16      2
    -- ignore option rundir 
    -- ignore option gpu
    batch   500     32
    | running in directory /home/ubuntu/deepmask/exps/deepmask/exp,batch=500,nthreads=16
    | number of paramaters trunk: 15198016  
    | number of paramaters mask branch: 1608768
    | number of paramaters score branch: 526337
    | number of paramaters total: 17333121  
    convert: data//annotations/instances_train2014.json --> .t7 [please be patient]
    convert: data//annotations/instances_train2014.json --> .t7 [please be patient]
    convert: data//annotations/instances_train2014.json --> .t7 [please be patient]
    convert: data//annotations/instances_train2014.json --> .t7 [please be patient]
    convert: data//annotations/instances_train2014.json --> .t7 [please be patient]
    /home/ubuntu/torch/install/bin/lua: ...e/ubuntu/torch/install/share/lua/5.2/threads/threads.lua:183: [thread 16 callback] /home/ubuntu/torch/install/share/lua/5.2/coco/CocoApi.lua:142: Expected value but found T_END at character 1

    Если не сконвертировались модели с ошибкой T_END

    Если вас постигла такая замечательная ошибка, то нужно сделать просто серию замечательных шагов:


    cd ~
    rm -rf torch/
    git clone https://github.com/torch/distro.git ~/torch --recursive
    cd ~/torch;
    bash install-deps;
    TORCH_LUA_VERSION=LUA52 ./install.sh
    git checkout 5961f52a65fe33efa675f71e5c19ad8de56e8dad
    ./clean.sh
    bash install-reps
    TORCH_LUA_VERSION-LUA52 ./install.sh
    luarocks install cudnn
    luarocks install cutorch # именно так! И не спрашивайте. Там ещё достаточно граблей
    luarocks install cunn
    luarocks install inn
    luarocks install tds
    luarocks install optim
    luarocks install nnx
    luarocks install image
    cd ~/coco/
    luarocks make LuaAPI/rocks/coco-scm-1.rockspec

    Если не сконвертировались модели из-за нехватки памяти

    Пересобрали. Доустановили. Запускаемся опять с теми же опциями и видим:


    th train.lua -nthreads 16 -batch 500
    -- ignore option rundir
    -- ignore option dm
    -- ignore option reload
    -- ignore option gpu
    -- ignore option datadir
    nthreads        1       2
    | running in directory /Users/ryan/mess/2016/34/deepmask/exps/deepmask/exp,nthreads=1
    | number of paramaters trunk: 15198016
    | number of paramaters mask branch: 1608768
    | number of paramaters score branch: 526337
    | number of paramaters total: 17333121
    convert: data//annotations/instances_train2014.json --> .t7 [please be patient]
    FATAL THREAD PANIC: (write) not enough memory
    Поток в панике. Что делать? Тушить! Workaround на этот раз очень лайтовый. Даже не надо ничего пересобирать. Просто руками конвертируем аннотации тренировки и валидации. Ошибка чтения файлов лечится так же.
    ```bash
    cd ~/deepmask/
    th
    coco = require 'coco'
    coco.CocoApi("data/annotations/instances_train2014.json")
    #Увидим строчки, которые ниже
    #convert: data/annotations/instances_train2014.json --> .t7 [please be patient]
    #converting: annotations
    #converting: categories
    #converting: images
    #convert: building indices
    #convert: complete [57.22 s]
    #CocoApi
    
    coco.CocoApi("data/annotations/instances_val2014.json")
    #Увидим строчки, которые ниже
    #convert: data/annotations/instances_val2014.json --> .t7 [please be patient]
    #converting: annotations
    #converting: categories
    #converting: images
    #convert: building indices
    #convert: complete [26.07 s]
    #CocoApi

    Обучаем нейросеть


    Вот теперь приготовления завершены. Все модели есть, сети есть, изображения для тренировки и валидации есть. Снова запускаем. Попробуем максимально нагрузить.


    th train.lua -batch 500 -nthreads 16

    Параллельно смотрим htop (не самая лучшая идея, поскольку он не покажет разделение потребляемой памяти по типу).



    Мягко говоря, жарковато. Напоминаю: 16 физических процессоров, каждый по 8 ядер, с виртуализацией. И память. Неудивительно, что через несколько минут работы терминал выдал «Убито»!


    Повторяем попытку, делаем условия "полегче":


    th train.lua -maxepoch 2 -nthreads 4

    Вывод из консоли тут
    Found Environment variable CUDNN_PATH = /home/ubuntu/cuda/lib64/libcudnn.so.5maxepoch   2       300
    -- ignore option datadir
    -- ignore option gpu
    -- ignore option dm
    nthreads        4       2
    -- ignore option rundir 
    -- ignore option reload 
    | running in directory /home/ubuntu/deepmask/exps/deepmask/exp,maxepoch=2,nthreads=4
    | number of paramaters trunk: 15198016  
    | number of paramaters mask branch: 1608768
    | number of paramaters score branch: 526337
    | number of paramaters total: 17333121  
    | start training

    Ещё раз. Использованные 154 Гб памяти — это все банки RAM, часть свопа и часть виртуальной памяти. Останавливаем. Остановка через kill или Ctrl + C не критична вообще. При перезапуске обучения все старые модели затираются.


    Даже на амазонской машине можно спокойно оставить скрипт работать и идти заниматься своими делами часа полтора-два.


    Как не терять сессию при работе с инстансом Amazon

    Кстати, важная пометка: чтобы увидеть, что что-то получилось, результаты тренировки нейросети и т.д., при работе через ssh используйте screen. Внезапно пропала связь и прочее? Не беда. Переподключились к машине, ввели screen -r — и мы снова видим то, на чём вылетели.


    Опция -nthreads 4 вымучена перезапусками и засеканием времени тренировки нейросети. Потому что при большей загрузке начинается конкуренция за оперативную память, а параметров у нас очень и очень много (в сумме 17 млн).


    На обучающую выборку в 85К изображений. Кстати, каждый чётный шаг обучения скрипта проводит валидацию нейросети.


    Вывод в консоль информации по обучению, 16 потоков, 12 эпох
    th train.lua -nthreads 16 -maxepoch 12
    Found Environment variable CUDNN_PATH = /home/ubuntu/cuda/lib64/libcudnn.so.5-- ignore option reload
    -- ignore option dm
    maxepoch        12      300
    -- ignore option gpu
    nthreads        16      2
    -- ignore option datadir
    -- ignore option rundir
    | running in directory /home/ubuntu/deepmask/exps/deepmask/exp,maxepoch=12,nthreads=16
    | number of paramaters trunk: 15198016
    | number of paramaters mask branch: 1608768
    | number of paramaters score branch: 526337
    | number of paramaters total: 17333121
    | start training
    [train] | epoch 00001 | s/batch 0.67 | loss: 0.31743
    [train] | epoch 00002 | s/batch 0.67 | loss: 0.18296
    [test]  | epoch 00002 | IoU: mean 054.60 median 061.36 suc@.5 062.63 suc@.7 036.53 | acc 092.91 | bestmodel *
    [train] | epoch 00003 | s/batch 0.67 | loss: 0.16256
    [train] | epoch 00004 | s/batch 0.67 | loss: 0.15217
    [test]  | epoch 00004 | IoU: mean 059.10 median 065.86 suc@.5 068.97 suc@.7 043.31 | acc 093.93 | bestmodel *
    [train] | epoch 00005 | s/batch 0.67 | loss: 0.14583
    [train] | epoch 00006 | s/batch 0.67 | loss: 0.14183
    [test]  | epoch 00006 | IoU: mean 056.79 median 064.92 suc@.5 065.88 suc@.7 042.34 | acc 094.27 | bestmodel x
    [train] | epoch 00007 | s/batch 0.67 | loss: 0.13739
    [train] | epoch 00008 | s/batch 0.67 | loss: 0.13489
    [test]  | epoch 00008 | IoU: mean 059.53 median 067.17 suc@.5 069.44 suc@.7 045.33 | acc 094.69 | bestmodel *
    [train] | epoch 00009 | s/batch 0.67 | loss: 0.13417
    [train] | epoch 00010 | s/batch 0.67 | loss: 0.13290
    [test]  | epoch 00010 | IoU: mean 061.80 median 069.41 suc@.5 072.71 suc@.7 048.92 | acc 094.67 | bestmodel *
    [train] | epoch 00011 | s/batch 0.67 | loss: 0.13070
    [train] | epoch 00012 | s/batch 0.67 | loss: 0.12711
    [test]  | epoch 00012 | IoU: mean 060.16 median 067.43 suc@.5 070.71 suc@.7 046.34 | acc 094.85 | bestmodel x

    Провели обучение и можно приступать к следующему этапу. На основе полученных DeepMask-моделей необходимо сгенерировать SharpMask.


    th train.lua -dm ~/deepmask/exps/deepmask/exp\,maxepoch\=2\,nthreads\=4/ 
    # необходимо точно указать путь, где лежат наши модели

    Если была запущена тренировка с другими параметрами, то название папки с моделями будет иное. Но основной путь до неё тот же. Пока идёт обучение DeepMask или построение SharpMask, продолжим установку.


    Ставим google-glog


    С ним проблем не возникло, потому что он и правда простой и беспроблемный.


    cd ~/
    git clone https://github.com/google/glog.git
    cd glog
    ./autogen.sh
    ./configure
    make
    sudo make install

    Multipathnet, fbpython и целый ворох зависимостей


    Теперь от нас всего-то требуется клонировать проект multipathnet, установить к нему зависимости и запустить распознавание. Кажется, я где-то уже слышал что всё «легко и просто».


    cd ~/
    git clone https://github.com/facebookresearch/multipathnet.git
    luarocks install torchnet
    luarocks install class
    luarocks install fbpython 

    Не пытайтесь ставить fbpython через Conda или Anaconda и прочее. Как выражается Facebook в инструкции: note that this won't work with anaconda as it ships with it's own libraries which conflict with torch. Если перевести примерно и с долей юмора, то «это их собственная баржа, на ней свои заморочки и свой капитан».


    Итак, кто-то опять умолчал о зависимостях.


    ...
    -- Found Torch7 in /home/ubuntu/torch/install
    -- REQUIRED_ARGS (missing:  THPP_INCLUDE_DIR THPP_LIBRARIES) 
    -- Looking for pthread.h
    ...

    Гуглим во все стороны, что это за переменные и почему их у нас до сих пор нет.


    cd ~/
    git clone https://github.com/facebook/folly.git
    git clone https://github.com/facebook/fbthrift.git
    git clone https://github.com/facebook/thpp
    git clone https://github.com/facebookarchive/fblualib.git 
    # не пользуйтесь форком, форк не работает, клонируем из архива

    Я считаю, это прекрасно. Ещё небольшой зоопарк. Ладно. Для тех, кто на Ubuntu:


    Команды и вывод в консоль тут, очень много
    sudo apt-get install zlib1g-dev binutils-dev libjemalloc-dev libssl-dev
    sudo apt-get install libevent-dev
    sudo apt-get install libsnappy-dev
    sudo apt-get install libboost-all-dev libgoogle-glog-dev libgflags-dev liblz4-dev liblzma-dev libsnappy-dev
    Linux:
    cd ~/
    git clone https://github.com/gflags/gflags.git
    
    cd gflags
    mkdir build && cd build
    $ ccmake ..
      - Press 'c' to configure the build system and 'e' to ignore warnings.
    # Обязательно включаем SHARED_LIB
      - Set CMAKE_INSTALL_PREFIX and other CMake variables and options.
    # Жмём 'c' ещё раз
      - Continue pressing 'c' until the option 'g' is available.
    # Жмём 'g' и радуемся
      - Then press 'g' to generate the configuration files for GNU Make.
    cd ..
    cmake -fpic -shared configure .
    make
    sudo make install
    
    cd ~/
    git clone https://github.com/google/glog.git
    export LDFLAGS='-L/usr/local/lib'
    cd glog
    autoreconf -ivf
    ./configure
    make
    sudo make install
    
    cd ~/
    git clone https://github.com/google/double-conversion.git
    cd double-conversion
    cmake . -DBUILD_SHARED_LIBS=ON # не спрашивайте. ну не хавает 
    #здесь cmake по дефолту -fpic -shared
    make
    sudo make install
    Теперь для всех:
    wget https://github.com/google/googletest/archive/release-1.8.0.tar.gz && \
    tar zxf release-1.8.0.tar.gz && \
    rm -f release-1.8.0.tar.gz && \
    cd googletest-release-1.8.0 && \
    cmake configure . && \
    make && \
    sudo make install
    
    cd ~/folly
    cmake -fpic -shared configure ..
    make (optionally -j$(proc))
    sudo make install

    Дальше всё идёт только для Ubuntu, посколько на RHEL было бессмысленно пытаться обновить всё окружение. На момент написания статьи дальше в RHEL продвинуться просто было невозможно, ограничение на максимальную версию пакетов для инстансов «Амазона» тому виной.


    Пользователи Linux могут самостоятельно продолжить установку пакетов, но искать необходимые пакеты необходимо будет вам (ну а если в процессе наткнетесь на грабли — добро пожаловать в комментарии, с радостью помогу решить проблемы).


    Ставим fbthrift


    НИКОГДАне трогайте build_folly_fbthrift.sh. Иначе придётся откатиться к моменту, когда ничего нет, кроме тренировки модели.


    Все команды по установке
    sudo apt-get install flex bison
    git clone https://github.com/no1msd/mstch.git
    cd mstch
    cmake .
    make
    sudo make install
    cd ~/
    git clone https://github.com/facebook/wangle.git
    cd wangle/wangle
    cmake .
    make
    sudo make install
    cd ~/
    git clone https://github.com/facebook/zstd.git
    cd zstd
    make
    sudo make install
    cd ~/
    git clone https://github.com/krb5/krb5.git
    cd krb5/src
    autoreconf -ivf
    ./configure
    make
    sudo make install
    cd ~/fbthrift/build
    cmake -fpic -shared configure .
    make
    sudo make install

    И теперь думаете, что счастье есть и можно устанавливать thpp. Как показала практика — нет. Упираетесь в тысячу косяков… Fbthrift! Для начала:


    cd ~/fbthrift/thrift/compiler/py
    sudo python setup.py install

    Это установит недостающий thrift_compiler. Далее оказывается, что вообще отсутствует frontend.so. Забыли скомпилироть и положить в папку. Ну ладно (для справки: ниже строка генерации frontend.so для g++ ~v5.4).


    cd ~/fbthrift/thrift/compiler/py
    g++ -I /usr/include/python2.7 -I ~/fbthrift -std=c++1y -fpic -shared -o frontend.so compiler.cc -lboost_python -lpython2.7 -L/build/lib -lcompiler_base -lcompiler_ast -lboost_system -lboost_filesystem -lssl -lcrypto
    sudo cp frontend.so /usr/local/lib/python2.7/dist-packages/thrift_py-0.9.0-py2.7.egg/thrift_compiler/

    Если у вас чего-то не хватает, скомпилируйте сами. Такое ощущение, что дальше еще и дописывать придется за них код. И предчувствие не обмануло.


    Если поймали ошибку вызова методов с неправильным количеством параметров


    Вооот, теперь нас ждёт счастье. Ну почти. Добрые самаритяне из Facebook поменяли вызовы функций в torch7, но между делом забыли сделать правильный вызов в thpp. Как мило.


    cd ~/thpp/thpp/detail/
    nano TensorGeneric.h

    Нужно поправить следующие вызовы (кэп подсказывает: после dim добавилась часть ", 0"):


    static void _max(THTensor* values, THLongTensor* indices,
                       THTensor* t, int dim) {
        return THTensor_(max)(values, indices, t, dim, 0); 
      }
      static void _min(THTensor* values, THLongTensor* indices,
                       THTensor* t, int dim) {
        return THTensor_(min)(values, indices, t, dim, 0);
      }
      static void _sum(THTensor* r, THTensor* t, int dim) {
        return THTensor_(sum)(r, t, dim, 0);
      }
      static void _prod(THTensor* r, THTensor* t, int dim) {
        return THTensor_(prod)(r, t, dim, 0);
      }

    Собираем пакет заново, но это ещё не всё...


    cd ~/thpp/thpp
    ccmake .
    #Делаем опцию NO_TEST = ON, жмём 'c', потом 'g'
    cmake . 
    make
    sudo make install

    Ставим fblualib


    Теперь на очереди fblualib. С ним можно расправиться легко и просто. Повторюсь: ни в коем случае не пользуйтесь их скриптами, которые носят заманчивые имена install-all.sh. Накроются все ваши пляски, и придётся начинать почти с нуля.


    sudo apt-get install \
      libedit-dev \
      libmatio-dev \
      libpython-dev \
      python-numpy

    Поставим, вдруг упустили. Не мудрено с такой «простой» инструкцией от разработчиков. Проверили, что у нас есть numpy для ВСЕХ версий питона.


    cd ~/fblualib/fblualib
    cmake -fpic -shared configure .
    make
    sudo make install

    И снова куча ошибок. А всё почему? Да потому, что кто-то не стал править вызовы функций и в rocks-пакетах. Значит, правим вызовы руками. Просто писали инструкцию для Lua версии ниже 5.2, а он уже у нас 5.2, и искать старую нужную версию нет смысла. Проще поправить вызов функций.


    cd ~/fblualib/fblualib/python
    luarocks make rockspec/*

    Выдаст ошибку при компиляции типа «недоопределённый тип». Всё просто. В файле с ошибкой правим определение типа luaL_reg на luaL_Reg (ЗАЧЕМ меняли вызов, я не знаю!)


    Файлов с ошибкой будет два. Правки должны быть сделаны на 191 и 341 строках в двух файлах, которые будут в сообщении об ошибке.


    Исправили вызов — попробовали. Скомпилировалось? Можно радоваться.


    В принципе, уже после данных манипуляций можно было бы просто из ~/fblualib/fblualib ещё раз вызвать ./build.sh, но это уже дело вкуса — руками надёжнее.


    Продолжаем мучения:


    cd ~/coco
    luarocks make LuaAPI/rocks/coco-scm-1.rockspec 
    # на всякий случай обновим зависимости
    sudo pip install Cython
    cd PythonAPI
    make
    sudo make install

    Запускаем построение SharpMask для обученной нейросети


    По идее, мы уже достигли дна, в смысле — дошли до конца инструкции по установке. Осталась самая приятная часть. Кстати, как раз закончился процесс создания SharpMask.


    th train.lua -dm exps/deepmask/exp\,maxepoch\=2\,nthreads\=4/ -maxepoch 2 -nthreads 4
    Found Environment variable CUDNN_PATH = /home/ubuntu/cuda/lib64/libcudnn.so.5gSz        160     112
    nthreads        4       2
    -- ignore option gpu
    -- ignore option reload 
    maxepoch        2       300
    -- ignore option datadir
    -- ignore option dm
    hfreq   0       0.5
    -- ignore option rundir 
    | running in directory /home/ubuntu/deepmask/exps/sharpmask/exp,gSz=160,hfreq=0,maxepoch=2,nthreads=4   
    | number of paramaters net h: 1090466   
    | number of paramaters net v: 1660050   
    | number of paramaters total: 2750516   
    | start training
    [train] | epoch 00001 | s/batch 1.95 | loss: 0.16018    
    [train] | epoch 00002 | s/batch 1.95 | loss: 0.13267    
    [test]  | epoch 00002 | IoU: mean 059.74 median 065.92 suc@.5 069.00 suc@.7 043.39 | bestmodel *

    Вполне себе хорошие данные для дальнейшей работы с моделями. Не забывайте добавлять в LUA_PATH /home//?.lua и в .bashrc тоже. Исходя из опыта установки всего проекта и тренировки моделей, просто сделайте линки из multipathnet на deepmask/data и линки sharpmask/model.t7 и deepmask/model.t7 и не занимайтесь копированием файлов.

    cd ~/deepmask
    mkdir data && cd data
    mkdir models && mkdir proposals
    ln -s ~/deepmask/data ~/multipathnet/data
    #deepMask и sharpMask — если были другие параметры обучения,
    # то папки другие будут
    ln -s ~/deepmask/exps/deepmask/exp,maxepoch=2,nthreads=4/model.t7 ~/deepmask/data/models/deepmask.t7 
    ln -s ~/deepmask/exps/sharpmask/exp,gSz=160,hfreq=0,maxepoch=2,nthreads=4/model.t7 ~/deepmask/data/models/sharpmask.t7

    Если не запускается из-за ошибки в тестах


    Из файла fbcoco.lua убираем следующие строки:


    require 'testCoco.init'
    require 'Tester_FRCNN'

    Теперь точно не зависнет и не сегфолтнется.


    Долгожданная проверка!


    Пора запускать проверку!


    th demo.lua -img data/test6.jpg

    Вывод в консоль
    Found Environment variable CUDNN_PATH = /home/ubuntu/cuda/lib64/libcudnn.so.5nn.Sequential {
      [input -> (1) -> (2) -> (3) -> (4) -> (5) -> (6) -> output]
      (1): nn.ParallelTable {
        input
          |`-> (1): nn.Sequential {
          |      [input -> (1) -> (2) -> (3) -> output]
          |      (1): NoBackprop: nn.Sequential {
          |        [input -> (1) -> (2) -> (3) -> (4) -> (5) -> output]
          |        (1): nn.SpatialConvolution(3 -> 64, 7x7, 2,2, 3,3) without bias
          |        (2): inn.ConstAffine
          |        (3): nn.ReLU
          |        (4): nn.SpatialMaxPooling(3x3, 2,2, 1,1)
          |        (5): nn.Sequential {
          |          [input -> (1) -> (2) -> output]
          |          (1): nn.Sequential {
          |            [input -> (1) -> (2) -> (3) -> output]
          |            (1): nn.ConcatTable {
          |              input
          |                |`-> (1): nn.Sequential {
          |                |      [input -> (1) -> (2) -> (3) -> (4) -> (5) -> output]
          |                |      (1): nn.SpatialConvolution(64 -> 64, 3x3, 1,1, 1,1) without bias
          |                |      (2): inn.ConstAffine
          |                |      (3): nn.ReLU
          |                |      (4): nn.SpatialConvolution(64 -> 64, 3x3, 1,1, 1,1) without bias
          |                |      (5): inn.ConstAffine
          |                |    }
          |                 `-> (2): nn.Identity
          |                 ... -> output
          |            }
          |            (2): nn.CAddTable
          |            (3): nn.ReLU
          |          }
          |          (2): nn.Sequential {
          |            [input -> (1) -> (2) -> (3) -> output]
          |            (1): nn.ConcatTable {
          |              input
          |                |`-> (1): nn.Sequential {
          |                |      [input -> (1) -> (2) -> (3) -> (4) -> (5) -> output]
          |                |      (1): nn.SpatialConvolution(64 -> 64, 3x3, 1,1, 1,1) without bias
          |                |      (2): inn.ConstAffine
          |                |      (3): nn.ReLU
          |                |      (4): nn.SpatialConvolution(64 -> 64, 3x3, 1,1, 1,1) without bias
          |                |      (5): inn.ConstAffine
          |                |    }
          |                 `-> (2): nn.Identity
          |                 ... -> output
          |            }
          |            (2): nn.CAddTable
          |            (3): nn.ReLU
          |          }
          |        }
          |      }
          |      (2): nn.Sequential {
          |        [input -> (1) -> (2) -> output]
          |        (1): nn.Sequential {
          |          [input -> (1) -> (2) -> (3) -> output]
          |          (1): nn.ConcatTable {
          |            input
          |              |`-> (1): nn.Sequential {
          |              |      [input -> (1) -> (2) -> (3) -> (4) -> (5) -> output]
          |              |      (1): nn.SpatialConvolution(64 -> 128, 3x3, 2,2, 1,1) without bias
          |              |      (2): inn.ConstAffine
          |              |      (3): nn.ReLU
          |              |      (4): nn.SpatialConvolution(128 -> 128, 3x3, 1,1, 1,1) without bias
          |              |      (5): inn.ConstAffine
          |              |    }
          |               `-> (2): nn.SpatialConvolution(64 -> 128, 1x1, 2,2) without bias
          |               ... -> output
          |          }
          |          (2): nn.CAddTable
          |          (3): nn.ReLU
          |        }
          |        (2): nn.Sequential {
          |          [input -> (1) -> (2) -> (3) -> output]
          |          (1): nn.ConcatTable {
          |            input
          |              |`-> (1): nn.Sequential {
          |              |      [input -> (1) -> (2) -> (3) -> (4) -> (5) -> output]
          |              |      (1): nn.SpatialConvolution(128 -> 128, 3x3, 1,1, 1,1) without bias
          |              |      (2): inn.ConstAffine
          |              |      (3): nn.ReLU
          |              |      (4): nn.SpatialConvolution(128 -> 128, 3x3, 1,1, 1,1) without bias
          |              |      (5): inn.ConstAffine
          |              |    }
          |               `-> (2): nn.Identity
          |               ... -> output
          |          }
          |          (2): nn.CAddTable
          |          (3): nn.ReLU
          |        }
          |      }
          |      (3): nn.Sequential {
          |        [input -> (1) -> (2) -> output]
          |        (1): nn.Sequential {
          |          [input -> (1) -> (2) -> (3) -> output]
          |          (1): nn.ConcatTable {
          |            input
          |              |`-> (1): nn.Sequential {
          |              |      [input -> (1) -> (2) -> (3) -> (4) -> (5) -> output]
          |              |      (1): nn.SpatialConvolution(128 -> 256, 3x3, 2,2, 1,1) without bias
          |              |      (2): inn.ConstAffine
          |              |      (3): nn.ReLU
          |              |      (4): nn.SpatialConvolution(256 -> 256, 3x3, 1,1, 1,1) without bias
          |              |      (5): inn.ConstAffine
          |              |    }
          |               `-> (2): nn.SpatialConvolution(128 -> 256, 1x1, 2,2) without bias
          |               ... -> output
          |          }
          |          (2): nn.CAddTable
          |          (3): nn.ReLU
          |        }
          |        (2): nn.Sequential {
          |          [input -> (1) -> (2) -> (3) -> output]
          |          (1): nn.ConcatTable {
          |            input
          |              |`-> (1): nn.Sequential {
          |              |      [input -> (1) -> (2) -> (3) -> (4) -> (5) -> output]
          |              |      (1): nn.SpatialConvolution(256 -> 256, 3x3, 1,1, 1,1) without bias
          |              |      (2): inn.ConstAffine
          |              |      (3): nn.ReLU
          |              |      (4): nn.SpatialConvolution(256 -> 256, 3x3, 1,1, 1,1) without bias
          |              |      (5): inn.ConstAffine
          |              |    }
          |               `-> (2): nn.Identity
          |               ... -> output
          |          }
          |          (2): nn.CAddTable
          |          (3): nn.ReLU
          |        }
          |      }
          |    }
           `-> (2): nn.Identity
           ... -> output
      }
      (2): inn.ROIPooling
      (3): nn.Sequential {
        [input -> (1) -> (2) -> (3) -> output]
        (1): nn.Sequential {
          [input -> (1) -> (2) -> output]
          (1): nn.Sequential {
            [input -> (1) -> (2) -> (3) -> output]
            (1): nn.ConcatTable {
              input
                |`-> (1): nn.Sequential {
                |      [input -> (1) -> (2) -> (3) -> (4) -> (5) -> output]
                |      (1): nn.SpatialConvolution(256 -> 512, 3x3, 2,2, 1,1) without bias
                |      (2): inn.ConstAffine
                |      (3): nn.ReLU
                |      (4): nn.SpatialConvolution(512 -> 512, 3x3, 1,1, 1,1) without bias
                |      (5): inn.ConstAffine
                |    }
                 `-> (2): nn.SpatialConvolution(256 -> 512, 1x1, 2,2) without bias
                 ... -> output
            }
            (2): nn.CAddTable
            (3): nn.ReLU
          }
          (2): nn.Sequential {
            [input -> (1) -> (2) -> (3) -> output]
            (1): nn.ConcatTable {
              input
                |`-> (1): nn.Sequential {
                |      [input -> (1) -> (2) -> (3) -> (4) -> (5) -> output]
                |      (1): nn.SpatialConvolution(512 -> 512, 3x3, 1,1, 1,1) without bias
                |      (2): inn.ConstAffine
                |      (3): nn.ReLU
                |      (4): nn.SpatialConvolution(512 -> 512, 3x3, 1,1, 1,1) without bias
                |      (5): inn.ConstAffine
                |    }
                 `-> (2): nn.Identity
                 ... -> output
            }
            (2): nn.CAddTable
            (3): nn.ReLU
          }
        }
        (2): nn.SpatialAveragePooling(7x7, 1,1)
        (3): nn.View(512)
      }
      (4): nn.ConcatTable {
        input
          |`-> (1): nn.Linear(512 -> 81)
          |`-> (2): nn.Linear(512 -> 81)
          |`-> (3): nn.Linear(512 -> 81)
          |`-> (4): nn.Linear(512 -> 81)
          |`-> (5): nn.Linear(512 -> 81)
          |`-> (6): nn.Linear(512 -> 81)
           `-> (7): nn.Linear(512 -> 324)
           ... -> output
      }
      (5): nn.ModeSwitch {
        input
          |`-> (1): nn.ConcatTable {
          |      input
          |        |`-> (1): nn.SelectTable(4)
          |         `-> (2): nn.SelectTable(7)
          |         ... -> output
          |    }
           `-> (2): nn.Sequential {
                 [input -> (1) -> (2) -> output]
                 (1): nn.ParallelTable {
                   input
                     |`-> (1): nn.Sequential {
                     |      [input -> (1) -> (2) -> output]
                     |      (1): nn.SoftMax
                     |      (2): nn.View(1, -1, 81)
                     |    }
                     |`-> (2): nn.Sequential {
                     |      [input -> (1) -> (2) -> output]
                     |      (1): nn.SoftMax
                     |      (2): nn.View(1, -1, 81)
                     |    }
                     |`-> (3): nn.Sequential {
                     |      [input -> (1) -> (2) -> output]
                     |      (1): nn.SoftMax
                     |      (2): nn.View(1, -1, 81)
                     |    }
                     |`-> (4): nn.Sequential {
                     |      [input -> (1) -> (2) -> output]
                     |      (1): nn.SoftMax
                     |      (2): nn.View(1, -1, 81)
                     |    }
                     |`-> (5): nn.Sequential {
                     |      [input -> (1) -> (2) -> output]
                     |      (1): nn.SoftMax
                     |      (2): nn.View(1, -1, 81)
                     |    }
                     |`-> (6): nn.Sequential {
                     |      [input -> (1) -> (2) -> output]
                     |      (1): nn.SoftMax
                     |      (2): nn.View(1, -1, 81)
                     |    }
                      `-> (7): nn.Identity
                      ... -> output
                 }
                 (2): nn.ConcatTable {
                   input
                     |`-> (1): nn.Sequential {
                     |      [input -> (1) -> (2) -> (3) -> output]
                     |      (1): nn.NarrowTable
                     |      (2): nn.JoinTable
                     |      (3): nn.Mean
                     |    }
                      `-> (2): nn.SelectTable(7)
                      ... -> output
                 }
               }
           ... -> output
      }
      (6): nn.ParallelTable {
        input
          |`-> (1): nn.Identity
           `-> (2): nn.BBoxNorm
           ... -> output
      }
    }
    {
      1 : 
        {
          1 : CudaTensor - size: 2x81
          2 : CudaTensor - size: 2x324
        }
    }
    {
      1 : 
        {
          1 : CudaTensor - size: 2x3x224x224
          2 : CudaTensor - size: 2x5
        }
    }
    {
      1 : 0.17677669529664
      2 : 0.25
      3 : 0.35355339059327
      4 : 0.5
      5 : 0.70710678118655
      6 : 1
      7 : 1.4142135623731
    }

    0.66218614578247    17  dog 
    | done


    Очевидно, на картинке собака! Пора подвести итоги.


    Результаты бега по граблям


    Вы сделали это! И стали на шаг ближе к просветлению. А если ещё и прошли по всем граблям (и даже нашли пару новых, в чём я совершенно не сомневаюсь), то, однозначно, можете зависать над землёй на высоте трёх ци и легко устанавливать все зависимости для проекта одним движением брови.


    Задачка была не из лёгких, а информации в интернете было очень и очень мало, особенно по багам с несовместимостью версий.


    Причина проста: весь проект по распознаванию образов был выпущен в тот момент, когда все компоненты и зависимости были рабочие и ставились прямо из репозиториев. Позже все пошли вразнос и никто не стал исправлять кривые связи, неточности языка, версионность, недостаток файлов и прочее. Но мы, как всегда, всё превозмогли и всех победили.


    Вообще сам набор после нормальной сборки и приведения в рабочий вид оставил приятное впечатление, если бы не процесс приведения в чувство всей этой Санта-Барбары.


    Все трудности преодолели, теперь можно немного поговорить о планах на будущее. А они у нас далекоидущие: в целях эксперимента перейти на CUDA 9.1, cuDNN 7, который обещает почти тройной прирост производительности для алгоритмов свёрточной нейронной сети и усовершенствованной свёрточной нейронной сети. Правда, это потянет за собой пересборку части пакетов (точнее, пересборку inn, cunn, cudnn, cutorch через LuaRocks и правку зависимостей).


    Буду рад ответить на ваши вопросы, а если расскажете о собственных граблях, постараюсь разобраться и помочь!

    • +36
    • 5,3k
    • 4
    FunCorp 153,04
    Разработка развлекательных сервисов
    Поделиться публикацией
    Комментарии 4
    • +1
      Этот проект не самый простой, поэтому возникает вопрос, зачем он нужен, если есть готовые фреймворки типа Keras, TensorFlow и Caffe, где, как говорится, «сел и поехал»? А ответ прост: нужен гибкий инструмент с возможностью расширения, с которым подружится Python.

      Этот ответ отлично применим и к Keras + TF. А если настройка инфраструктуры FB Image Recognition Package — это действительно такая головная боль, как вы описали, то его бы я гибким и удобным как раз не назвал.
      • +1
        Есть надежда, что все ошибки несовместимости версий уйдут и тогда действительно станет легче устанавливать и пользоваться.
        Согласен. Keras и TF из разряда «сел и поехал», но для них все равно необходимо либо писать собственный код, либо искать подходящий проект по распознаванию.
        В случае с FB — готовый комплект, который они успешно применяют в продакшн среде (я уверен, что версия в репозитории не самая последняя).
        Но в итоге получили полноценный рабочий инстанс, который можно использовать для распознавания образов.
      • 0

        О да, напоминает мои мучения, когда я этот Torch встраивал в Rspamd. Вначале я удивлялся, почему же нигде нет deb/rpm пакетов, чтобы не эмбеддить огромный фреймворк себе в код, а потом столкнулся с непревзойденным качеством кода от Facebook, который собирается и работает только в Facebook. Например, они ставят -march=native на компиляции и "проверяют" так наличие всяких смешных наборов инструкций, например, avx2. Стоит ли говорить, как "счастливы" от этого пользователи бинарных пакетов, у которых этих инструкций внезапно нет?


        Или, например, они хотят собираться с sse4.2, при этом используя только интрисики из sse2 — зачем им там sse4.2, непонятно.


        Еще забавно, что они используют генерацию C кода через lua на этапе сборки, что сломано примерно везде, где только можно.


        В итоге пришлось делать очень большой объем работы, чтобы это работало хотя бы немного универсально. К сожалению, open source проекты от больших корпораций очень сильно грешат этим (взять тот же Яндекс, ага), так как пишут их люди, не имеющие культуры open source разработки и не особо заботящиеся об удобстве пользователей, у которых нет отдела девопсов, которые бы их чудо поделие собирали и выкатывали.

        • 0
          С необходимостью перечисления всех необходимых наборов инструкций сталкивался и меня это тоже удивляло. Вроде бы не так сложно сделать проверку и компилировать с теми наборами инструкций, которые поддерживается, для удобства пользователей.

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

        Самое читаемое
        Интересные публикации