2019년 4월 25일 목요일

RAPIDS.ai on IBM POWER9 : ppc64le 환경에서 cuDF를 source로부터 build하기



RAPIDS.ai는 NVIDIA가 요즘 공을 들이고 있는 GPU를 이용한 data science platform입니다.  그 핵심 모듈이 cuDF와 cuML입니다.  이 모듈들은 최근 발표된 IBM PowerAI toolkit에도 포함되어 있습니다.  ( https://www.ibm.com/support/knowledgecenter/en/SS5SF7_1.6.0/navigation/pai_getstarted_rapids.html 참조)

다만 IBM PowerAI는 CUDA 10.1만을 지원하는 등 제약 사항이 일부 있기 때문에 모든 환경에서 유연하게 사용하시기가 곤란한 부분이 있을 수 있습니다.  그래도 어차피 RAPIDS는 open source니까, ppc64le 아키텍처 위에서 그냥 source로부터 build하시면 됩니다.  이번 posting에서는 cuDF를 Ubuntu 18.04 ppc64le에서 build하는 방법을 보시겠습니다.

일단 아래와 같이 cuda 10.0을 설치합니다.

~/files$ wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/ppc64el/cuda-repo-ubuntu1804_10.0.130-1_ppc64el.deb

~/files$ sudo apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/ppc64el/7fa2af80.pub

~/files$ sudo apt-get update

~/files$ sudo apt-get install cuda

~/files$ sudo tar -xvf ./cudnn-10.0-linux-ppc64le-v7.5.0.56.solitairetheme8 -C /usr/local

~/files$ sudo tar -xvf ./nccl_2.4.2-1+cuda10.0_ppc64le.txz -C /usr/local

Python은 Anaconda3를 설치하여 Python 3.6.8을 사용했습니다. 

~/files$  which python
/home/u0017649/anaconda3/bin/python

먼저 conda install 명령으로 아래 package들을 설치합니다.

~/files$ conda install numpy six setuptools cython pandas pytest cmake flatbuffers rapidjson boost boost-cpp thrift snappy zlib gflags brotli lz4-c zstd arrow -c conda-forge

먼저 유의하실 것은 Ubuntu 18.10의 기본 gcc 버전인 gcc-8은 CUDA 10.0을 지원하지 않습니다.  그런데 또 현재 cudf v0.7.0은 아직 CUDA 10.1을 지원하지 않습니다.  그래서 해결책은 Ubuntu에 gcc-7과 g++-7을 설치해야 합니다.

~/files$ sudo apt-get install -y gcc-7 gcc-7-base gcc-7-powerpc-linux-gnu libgcc-7-dev g++-7

~/files$ sudo rm /usr/bin/gcc /usr/bin/g++

~/files$ sudo ln -s /usr/bin/gcc-7 /usr/bin/gcc

~/files$ sudo ln -s /usr/bin/g++-7 /usr/bin/g++

먼저, RMM을 설치합니다.

~/files$ git clone --recursive  https://github.com/rapidsai/rmm.git

~/files$ cd rmm

~/files/rmm$ rm -rf build

~/files/rmm$ mkdir build && cd build

~/files/rmm/build$ cmake ..

~/files/rmm/build$ make -j2

~/files/rmm/build$ sudo make install

~/files/rmm/build$ cd ../python

~/files/rmm/python$ python setup.py install


다음으로는 custrings를 설치합니다.

~/files$ git clone --recursive https://github.com/rapidsai/custrings.git

~/files$ cd custrings/cpp

~/files/custrings/cpp$ mkdir build && cd build

~/files/custrings/cpp/build$ cmake ..

~/files/custrings/cpp$ make -j2

~/files/custrings/cpp$ sudo make install

다음으로는 thrift를 설치합니다. 

~/files$ git clone --recursive https://github.com/apache/thrift

~/files$ cd thrift/

~/files/thrift$ sudo apt-get install libssl-dev

~/files/thrift$ ./bootstrap.sh

~/files/thrift$ ./configure

~/files/thrift$ cd build

~/files/thrift/build$ cmake ..

~/files/thrift/build$ make -j2

~/files/thrift/build$ sudo make install

다음으로는 Arrow를 설치합니다. 

~/files$ sudo apt-get install libdouble-conversion1 libghc-double-conversion-dev libdouble-conversion-dev libgoogle-glog-dev libgoogle-glog0v5 thrift-compiler libthrift-java

~/files$ git clone https://github.com/apache/arrow.git

~/files$ cd arrow/cpp

~/files/arrow/cpp$ mkdir build && cd build

여기서 특정 header 파일을 아래와 같이 일부 수정해야 합니다.  이 error는 꼭 ppc64le 환경에서만 나는 것은 아니고, 나중에 patch가 될 예정입니다.   ( error: there are no arguments to ‘DCHECK’ that depend on a template parameter, so a declaration of ‘DCHECK’ must be available 이라는 error 방지용.  https://github.com/apache/arrow/issues/4014 참조)

~/files/arrow/cpp/build$ vi ~/files/arrow/cpp/src/arrow/util/sse-util.h
...
#include "logging.h"   # 이 include 문을 삽입해야 함


~/files/arrow/cpp/build$ cmake -DCMAKE_BUILD_TYPE=release -DARROW_PYTHON=on -DARROW_PLASMA=on -DARROW_BUILD_TESTS=OFF  -DARROW_PARQUET=ON ..

~/files/arrow/cpp/build$ make -j2

~/files/arrow/cpp/build$ sudo make install

~/files/arrow/cpp/build$ cd ../../python

~/files/arrow/python$ export ARROW_HOME=/usr/local

기본으로 설치되는 Cython 버전이 맞지 않으므로, 반드시 0.29 버전으로 새로 설치해야 하더라고요.

~/files/arrow/python$ pip install Cython==0.29

~/files/arrow/python$ MAKEFLAGS=-j2 python setup.py build_ext --build-type=release --with-parquet --inplace

~/files/arrow/python$ MAKEFLAGS=-j2 python setup.py build_ext --build-type=release --with-parquet --bundle-arrow-cpp bdist_wheel

위에서 생성되는 wheel file을 아래와 같이 설치하시면 됩니다.

~/files/arrow/python$ pip install dist/pyarrow-0.13.1.dev40+g6907d972.d20190408-cp37-cp37m-linux_ppc64le.whl


이제 비로소 cudf를 설치할 수 있게 되었습니다.

~/files$ git clone --recursive https://github.com/rapidsai/cudf.git

~/files$ cd cudf

~/files/cudf$ git submodule update --init --remote --recursive

여기서 역시 아래의 file 하나를 수정해야 합니다.  이 역시 ppc64le에 국한된 문제는 아니고, 아래 link에서 해결된 것인데, 나중에 patch로 반영될 예정입니다.  ( https://github.com/rapidsai/cudf/issues/1384 참조)

~/files/cudf$ vi cpp/tests/hashing/hash_partition_test.cu
...
  // The indices of the columns that will be hashed to determine the partitions
  constexpr static const std::array<int, sizeof...(cols)> cols_to_hash{{cols...}};
};
 template< typename tuple_of_vectors       # 이하 4줄의 line을 추가하시면 됩니다.
           gdf_hash_func hash,
           int... cols>
 constexpr const std::array<int, sizeof...(cols)> TestParameters<tuple_of_vectors, hash, cols...>::cols_to_hash;


그 다음은 아래와 같이 build하시면 됩니다.

~/files/cudf$ cd cpp

~/files/cudf/cpp$ mkdir build && cd build

~/files/cudf/cpp/build$ cmake .. -DCMAKE_INSTALL_PREFIX=~/anaconda3

~/files/cudf/cpp/build$ make -j2

~/files/cudf/cpp/build$ sudo make install

root@8f2f82cf3e22:/mnt/cudf# cd python

root@8f2f82cf3e22:/mnt/cudf/python# python setup.py build_ext --inplace

root@8f2f82cf3e22:/mnt/cudf/python# python setup.py install
...
Best match: numpy 1.16.2
Adding numpy 1.16.2 to easy-install.pth file
Installing f2py script to /opt/anaconda3/bin
Installing f2py3 script to /opt/anaconda3/bin
Installing f2py3.6 script to /opt/anaconda3/bin

Using /opt/anaconda3/lib/python3.6/site-packages
Finished processing dependencies for cudf==0.7.0.dev0+679.g97833593.dirty

2019년 4월 9일 화요일

PowerAI 1.6.0이 나왔습니다



PowerAI 1.6이 2019년 3월 15일에 이미 나왔습니다.  정리가 늦었네요.

PowerAI 1.6부터는 배포 방식이 또 크게 변했습니다.  이제부터는 rpm이나 deb 등의 package로 배포되는 것이 아니라, IBM이 운영하는 별도의 conda channel을 통해서 python package 형태로 배포됩니다.  따라서 이제는 Redhat용과 Ubuntu용이 별도로 나오지 않고, 모두 공통적으로 conda install 명령을 통해서 설치하시면 됩니다.

공식적인 설치 가이드는 아래 link를 참조하시면 됩니다.

https://www.ibm.com/support/knowledgecenter/SS5SF7_1.6.0/navigation/pai_install.html

이럴 경우 생기는 의문이 아마 3가지 있으실 것입니다. 

1) 기존 PowerAI 버전에서의 upgrade는 어떻게 하지 ?

: 예, IBM의 입장은 단호박입니다.  그냥 기존 버전을 지우고 새로 설치하랍니다.

https://www.ibm.com/support/knowledgecenter/SS5SF7_1.6.0/navigation/pai_upgrade.html

2) Tensorflow나 pytorch 등은 원래가 python package이니까 그렇다치고, caffe는 python package가 아닌데 그것도 conda package로 제공이 되나 ?

: 예, 됩니다.  그냥 ~/anaconda3/bin/caffe 의 형태로 설치됩니다.  꼭 python 통하지 않고 그냥 binary 실행 파일 형태로 사용하시면 됩니다.

3) Python2와 python3 모두 지원하나 ?

: 예, 모두 지원합니다.  conda install powerai로 설치할 때, 자동으로 자신이 python2 환경인지 python3 환경인지 감지하여 그에 맞는 package를 설치합니다.


현재 공식적으로 지원이 되는 것은 아래와 같은 환경들입니다.   CUDA 10.1에서만 지원이 되고, Redhat 7.6에서만 지원이 되는 것이 좀 그렇긴 합니다.  그런데 해보면 CUDA 10.0에서도 돌긴 돌아가는 것 같습니다만... 그래도 IBM에서 지원한다는 환경에서 쓰시는 것이 낫겟지요.

https://www.ibm.com/support/knowledgecenter/SS5SF7_1.6.0/navigation/pai_req.html

Component               Version Recommended
Red Hat Enterprise Linux 7.6 7.6
Ubuntu                     18.04 18.04
NVIDIA GPU driver         418 418.39
Anaconda                2018.12 2018.12


실제로 보면 아직 conda channel을 계속 손보고 있는지, Anaconda2에서는 잘 되지만 Anaconda3에서는 알 수 없는 이유로 설치가 일부 안 되기도 합니다.  그럴 때 python 버전을 (공식 지원 버전인) 3.7이 아닌 3.6.8로 낮추고 하면 또 설치가 잘 되기도 하고요.  이 conda channel은 IBM이 별도로 운영하는 것이라서, 계속 update를 하고 있는 것으로 보입니다.

설치 방법은 매우 간단합니다.  먼저 Anaconda 최신 버전 (2018.12) 설치하신 뒤에, https://public.dhe.ibm.com/ibmdl/export/pub/software/server/ibm-ai/conda/ 를 conda 채널로 등록하신 뒤에 'conda install powerai' 하시면 됩니다.   이렇게 PowerAI full package를 설치하면 대략 4GB 정도 추가 공간을 차지하게 됩니다.  무료이고, 등록할 때 별도의 id/password 같은 것을 묻지는 않습니다.

아래는 Anaconda2 기준의 설치 방법입니다.  매우 쉽습니다.


root@sys-97759:/tmp# wget https://repo.continuum.io/archive/Anaconda2-2018.12-Linux-ppc64le.sh

root@sys-97759:/tmp# chmod a+x Anaconda2-2018.12-Linux-ppc64le.sh

root@sys-97759:/tmp# ./Anaconda2-2018.12-Linux-ppc64le.sh
...
[/root/anaconda2] >>> /opt/anaconda2

root@sys-97759:/tmp# which conda
/opt/anaconda2/bin/conda

root@sys-97759:/tmp# conda config --prepend channels https://public.dhe.ibm.com/ibmdl/export/pub/software/server/ibm-ai/conda/

root@sys-97759:/tmp# conda install powerai

(base) root@sys-97759:/tmp# python
Python 2.7.15 |Anaconda, Inc.| (default, Dec 14 2018, 19:05:19)
[GCC 7.3.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import tensorflow
>>> import torch
>>> import caffe2




2019년 4월 8일 월요일

ppc64le Redhat 7 환경에서의 nvidia-docker2 대신 nvidia-container-runtime 사용


nvidia-docker는 현재 버전 2가 나와 있습니다만, 아직 Redhat 7 ppc64le에서는 버전 1만 지원이 되고 있습니다.   그렇다고 nvidia-docker2를 Redhat 7 ppc64le에서는 완전히 못 쓰는 것은 아닙니다.  수동으로 nvidia-container-runtime을 설치해주면 되기 때문입니다.   여기에 정리된 것은 아래 site에 나온 수동 등록 방법을 직접 ppc64le 아키텍처의 GPU 서버인 IBM AC922에서 수행해본 결과입니다.

https://github.com/nvidia/nvidia-container-runtime#docker-engine-setup

먼저 docker-ce를 설치하기 위해 docker.repo를 등록합니다.

[root@ac922 home]# vi /etc/yum.repos.d/docker.repo
[docker]
name=Docker
baseurl=http://ftp.unicamp.br/pub/ppc64el/rhel/7/docker-ppc64el/
enabled=1
gpgcheck=0

아래와 같이 nvidia-container-runtime.repo를 등록합니다.

[root@ac922 home]# distribution=$(. /etc/os-release;echo $ID$VERSION_ID)

[root@ac922 home]# echo $distribution
rhel7.5

[root@ac922 home]# curl -s -L https://nvidia.github.io/nvidia-container-runtime/$distribution/nvidia-container-runtime.repo | sudo tee /etc/yum.repos.d/nvidia-container-runtime.repo
[libnvidia-container]
name=libnvidia-container
baseurl=https://nvidia.github.io/libnvidia-container/centos7/$basearch
repo_gpgcheck=1
gpgcheck=0
enabled=1
gpgkey=https://nvidia.github.io/libnvidia-container/gpgkey
sslverify=1
sslcacert=/etc/pki/tls/certs/ca-bundle.crt

[nvidia-container-runtime]
name=nvidia-container-runtime
baseurl=https://nvidia.github.io/nvidia-container-runtime/centos7/$basearch
repo_gpgcheck=1
gpgcheck=0
enabled=1
gpgkey=https://nvidia.github.io/nvidia-container-runtime/gpgkey
sslverify=1
sslcacert=/etc/pki/tls/certs/ca-bundle.crt

이제 gpg 관련해서 key를 지울텐데, 여기서는 기존에 f796ecb0 key가 설치된 적이 없었기 때문에 error가 납니다.  에러는 무시하셔도 됩니다.

[root@ac922 home]# gpg --homedir /var/lib/yum/repos/ppc64le/7Server/nvidia-container-runtime/gpgdir --delete-key f796ecb0
gpg (GnuPG) 2.0.22; Copyright (C) 2013 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

gpg: keyblock resource `/var/lib/yum/repos/ppc64le/7Server/nvidia-container-runtime/gpgdir/secring.gpg': No such file or directory
gpg: keyblock resource `/var/lib/yum/repos/ppc64le/7Server/nvidia-container-runtime/gpgdir/pubring.gpg': No such file or directory
gpg: key "f796ecb0" not found: Unknown system error
gpg: f796ecb0: delete key failed: Unknown system error


다만 다음과 같은 error가 나는 경우가 있는데, 이는 어떻게든 고치셔야 합니다.

Repository cuda is listed more than once in the configuration
https://nvidia.github.io/libnvidia-container/centos7/ppc64le/repodata/repomd.xml: [Errno -1] repomd.xml signature could not be verified for libnvidia-container
Trying other mirror

가장 쉬운 방법은 아래와 같이 repo_gpgcheck=1을 0으로 바꿔서 repo에 대한 gpg check을 안 하도록 하는 것입니다.

[root@ac922 home]# vi /etc/yum.repos.d/nvidia-container-runtime.repo
...
#repo_gpgcheck=1
repo_gpgcheck=0


그 다음으로 yum makecache를 수행합니다.  일부 존재하지 않는 mirror site에 대해서 error가 날텐데, 무시하셔도 됩니다.

[root@ac922 home]# yum makecache
...

failure: repodata/6f7751fe9609cd7adda0ef3002368400ba63b01793d8a0fe0fea8ae56c3265c65015c9b5d274fbfab7b6c4aa8738a3df7e53c8de1987a410c91624412330825c-filelists.xml.xz from nvidia-container-runtime: [Errno 256] No more mirrors to try.
https://nvidia.github.io/nvidia-container-runtime/centos7/ppc64le/repodata/6f7751fe9609cd7adda0ef3002368400ba63b01793d8a0fe0fea8ae56c3265c65015c9b5d274fbfab7b6c4aa8738a3df7e53c8de1987a410c91624412330825c-filelists.xml.xz: [Errno 14] HTTPS Error 404 - Not Found


중요한 것은 아래와 같이 그 다음에 수행하는 yum list에서 nvidia-container가 보이기만 하면 된다는 것입니다.

[root@ac922 home]# yum list | grep nvidia | grep container
libnvidia-container-devel.ppc64le          1.0.0-1                 libnvidia-container
libnvidia-container-static.ppc64le         1.0.0-1                 libnvidia-container
libnvidia-container-tools.ppc64le          1.0.0-1                 libnvidia-container
libnvidia-container1.ppc64le               1.0.0-1                 libnvidia-container
libnvidia-container1-debuginfo.ppc64le     1.0.0-1                 libnvidia-container
nvidia-container-runtime.ppc64le           2.0.0-1.docker18.03.1   nvidia-container-runtime
nvidia-container-runtime-hook.ppc64le      1.4.0-2                 nvidia-container-runtime

이제 docker-ce를 설치합니다.

[root@ac922 home]# yum install -y docker-ce

이어서 nvidia-container-runtime를 설치합니다.

[root@ac922 home]# yum install -y libnvidia-container-devel nvidia-container-runtime

그리고나서 nvidia-runtime을 docker에 등록하기 위해 daemon configuration file을 아래와 같이 등록합니다.   이 방법 말고 위 site에서는 systemd drop-in file이라는 것을 써도 된다고 되어 있는데, 제가 해보니 그 방법은 뭐가 잘못 되었는지 error가 나더군요.  그러니 아래 방법을 쓰십시요.

[root@ac922 home]# vi /etc/docker/daemon.json
{
    "runtimes": {
        "nvidia": {
            "path": "/usr/bin/nvidia-container-runtime",
            "runtimeArgs": []
        }
    }
}

이제 위 config file에 따라 아래와 같이 docker를 시작합니다.

[root@ac922 home]# systemctl daemon-reload

[root@ac922 home]# systemctl start docker

이제 docker를 run 시켜 봅니다.  기존 nvidia-docker version 1과의 차이점은 이제 nvidia-docker라는 명령을 쓰는 것이 아니라 --runtime=nvidia라고 쓰면 된다는 것입니다.  이제 테스트를 위해 기존에 만들어 두었던 tensorflow 1.3을 담은 docker image를 구동시켜 보겠습니다.

[root@ac922 home]# docker run --runtime=nvidia --rm -ti bsyu/tf1.3-ppc64le:v0.1
...
root@d72b1ea6b739:/# python
Python 3.6.1 |Anaconda custom (64-bit)| (default, May 11 2017, 15:31:35)
[GCC 4.8.4] on linux
Type "help", "copyright", "credits" or "license" for more information.

>>> import tensorflow as tf

아래와 같이 GPU를 제대로 잡아오는지 보겠습니다.  잘 됩니다.

>>> sess=tf.Session()
2019-04-08 08:26:15.424143: I tensorflow/core/common_runtime/gpu/gpu_device.cc:955] Found device 0 with properties:
name: Tesla V100-SXM2-32GB
...
2019-04-08 08:26:15.730328: I tensorflow/core/common_runtime/gpu/gpu_device.cc:976] DMA: 0 1 2 3
2019-04-08 08:26:15.730347: I tensorflow/core/common_runtime/gpu/gpu_device.cc:986] 0:   Y Y Y Y
2019-04-08 08:26:15.730365: I tensorflow/core/common_runtime/gpu/gpu_device.cc:986] 1:   Y Y Y Y
2019-04-08 08:26:15.730382: I tensorflow/core/common_runtime/gpu/gpu_device.cc:986] 2:   Y Y Y Y
2019-04-08 08:26:15.730397: I tensorflow/core/common_runtime/gpu/gpu_device.cc:986] 3:   Y Y Y Y
2019-04-08 08:26:15.730428: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1045] Creating TensorFlow device (/gpu:0) -> (device: 0, name: Tesla V100-SXM2-32GB, pci bus id: 0004:04:00.0)
2019-04-08 08:26:15.730450: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1045] Creating TensorFlow device (/gpu:1) -> (device: 1, name: Tesla V100-SXM2-32GB, pci bus id: 0004:05:00.0)
2019-04-08 08:26:15.730468: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1045] Creating TensorFlow device (/gpu:2) -> (device: 2, name: Tesla V100-SXM2-32GB, pci bus id: 0035:03:00.0)
2019-04-08 08:26:15.730488: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1045] Creating TensorFlow device (/gpu:3) -> (device: 3, name: Tesla V100-SXM2-32GB, pci bus id: 0035:04:00.0)

Parent OS에서 본 nvidia-smi에서도 python이 GPU를 점거하는 모습을 보실 수 있습니다.

+-----------------------------------------------------------------------------+
| NVIDIA-SMI 418.40.04    Driver Version: 418.40.04    CUDA Version: 10.1     |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  Tesla V100-SXM2...  On   | 00000004:04:00.0 Off |                    0 |
| N/A   40C    P0    65W / 300W |  30175MiB / 32480MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+
|   1  Tesla V100-SXM2...  On   | 00000004:05:00.0 Off |                    0 |
| N/A   41C    P0    70W / 300W |  30173MiB / 32480MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+
|   2  Tesla V100-SXM2...  On   | 00000035:03:00.0 Off |                    0 |
| N/A   41C    P0    65W / 300W |  30173MiB / 32480MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+
|   3  Tesla V100-SXM2...  On   | 00000035:04:00.0 Off |                    0 |
| N/A   42C    P0    66W / 300W |  30173MiB / 32480MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+

+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Memory |
|  GPU       PID   Type   Process name                             Usage      |
|=============================================================================|
|    0     14371      C   python                                     30165MiB |
|    1     14371      C   python                                     30163MiB |
|    2     14371      C   python                                     30163MiB |
|    3     14371      C   python                                     30163MiB |
+-----------------------------------------------------------------------------+



PS.   아예 --runtime=nvidia 옵션 없이 그냥 docker 명령만 써서 nvidia-container-runtime을 구동하고 싶다면 다음과 같이  "default-runtime": "nvidia" 을 /etc/docker/daemon.json에 추가해주시면 됩니다.


[root@ac922 home]# vi /etc/docker/daemon.json
{
    "default-runtime": "nvidia",
    "runtimes": {
        "nvidia": {
            "path": "/usr/bin/nvidia-container-runtime",
            "runtimeArgs": []
        }
    }
}