2019년 10월 10일 목요일

SRILM을 IBM POWER (ppc64le) 아키텍처의 Redhat에서 build하기


SRILM은 음성인식 등에 쓰이는 statistical language model(LM)들을 쉽게 구축하고 적용할 수 있는 toolkit입니다.  이것을 IBM POWER 서버에 설치된 Redhat이나 Ubuntu 등 linux OS에서도 build해서 사용할 수 있느냐에 대한 답변은 "Yes, 된다" 입니다.

SRILM의 현재 최신버전인 1.7.3 버전에서는 ppc64 (big-endian) 만 지원하는 것처럼 되어 있습니다만, 이는 그냥 ppc64le가 template에 아직 update가 안되었을 뿐이며, template만 약간 수정하면 ppc64le (little-endian)에서도 쉽게 build 하실 수 있습니다. 

먼저, 필요 OS fileset들을 설치합니다.  여기서는 Redhat 7.5를 기준으로 했습니다.

[user612@p612-met1 ~]$ sudo yum install -y gawk tcl-devel libticonv-devel bzip2

SRILM의 최신 버전 1.7.3을 아래 URL에서 download 받고, POWER 서버에 upload 합니다.

http://www.speech.sri.com/projects/srilm/download.html

압축을 해제합니다.

[user612@p612-met1 ~]$ mkdir srilm

[user612@p612-met1 ~]$ cd srilm

[user612@p612-met1 srilm]$ tar -xvf ../srilm-1.7.3.tar.gz

먼저 source에 포함된 machine-type 이라는 shell script를 수행해보면 MACHINE_TYPE을 못 찾겠다는 error가 납니다.  이는 아래와 같이 shell script를 약간만 수정하면 해결됩니다.

[user612@p612-met1 srilm]$ ./sbin/machine-type
could not determine MACHINE_TYPE

[user612@p612-met1 srilm]$ vi ./sbin/machine-type
...
            *)
                case "`uname -m`" in
                ppc64)  MACHINE_TYPE=ppc64
                        ;;
                ppc64le) MACHINE_TYPE=ppc64le    # Newly added
                        ;;                                       # Newly added
                i686)   MACHINE_TYPE=i686
                        ;;

이제 잘 됩니다.

[user612@p612-met1 srilm]$ ./sbin/machine-type
ppc64le

이어서 Makefile에서 SRILM home directory를 update 합니다.  사실 이건 ppc64le 아키텍처에서만 수정해야 하는 것이 아니라 x86 등 모든 아키텍처에서 다 환경에 맞게 수정해야 하는 부분입니다.

[user612@p612-met1 srilm]$ vi Makefile
...
# SRILM = /home/speech/stolcke/project/srilm/devel
SRILM = /home/user612/srilm    # Update per environment

ppc64le 아키텍처가 지원 안되는 것처럼 보이는 것은 아래의 common/Makefile.machine.* 파일들에 ppc64만 있고 ppc64le가 없기 때문입니다.  그냥 기존의 ppc64를 ppc64le로 copy해줍니다.

[user612@p612-met1 srilm]$ cp common/Makefile.machine.ppc64 common/Makefile.machine.ppc64le

그리고 여기서 LINK할 library에 pthread를 추가해줍니다.  (이를 안 해주면 어떤 error가 나는지는 맨 아래에 적었습니다.)

[user612@p612-met1 srilm]$ vi common/Makefile.machine.ppc64le
...
#   ADDITIONAL_LIBRARIES = -lm -ldl
   ADDITIONAL_LIBRARIES = -lm -ldl -lpthread   # Added -lpthread
...

이제 그냥 make를 수행하시면 됩니다.  아무 error 없이 잘 build 됩니다.

[user612@p612-met1 srilm]$ make -j16

이제 PATH를 잡아주고 ngram 명령을 수행해봅니다.  아래와 같이 잘 수행되는 것을 보실 수 있습니다.

[user612@p612-met1 srilm]$ pwd
/home/user612/srilm

[user612@p612-met1 srilm]$ export PATH=$PATH:/home/user612/srilm/bin/ppc64le

[user612@p612-met1 srilm]$ ngram -help
Usage of command "ngram"
 -version:                print version information
 -order:                  max ngram order
                Default value: 3
 -debug:                  debugging level for lm
                Default value: 0
 -skipoovs:               skip n-gram contexts containing OOVs
...



** 만약 위에서 common/Makefile.machine.ppc64le 속의 "ADDITIONAL_LIBRARIES = -lm -ldl -lpthread" 부분을 고치지 않는다면 다음과 같은 error를 겪게 되실 것입니다.  이 error가 나는 이유는 /usr/lib64/libpthread.so.0 가 참조되지 않기 때문이니, 위와 같이 common/Makefile.machine.ppc64le을 수정하시면 해결됩니다.

...
g++ -Wreturn-type -Wimplicit -DINSTANTIATE_TEMPLATES    -I. -I../../include   -u matherr -L../../lib/ppc64le  -g -O3 -o ../bin/ppc64le/ngram-merge ../obj/ppc64le/ngram-merge.o ../obj/ppc64le/liboolm.a -lm -ldl ../../lib/ppc64le/libflm.a ../../lib/ppc64le/libdstruct.a ../../lib/ppc64le/libmisc.a ../../lib/ppc64le/libz.a -ltcl -lm   2>&1 | c++filt
/usr/bin/ld: ../obj/ppc64le/liboolm.a(Vocab.o): undefined reference to symbol 'pthread_getspecific@@GLIBC_2.17'
//usr/lib64/libpthread.so.0: error adding symbols: DSO missing from command line
collect2: error: ld returned 1 exit status
test -f ../bin/ppc64le/ngram-merge
make[2]: *** [../bin/ppc64le/ngram-merge] Error 1
make[2]: *** Waiting for unfinished jobs....
make[2]: Leaving directory `/home/user612/srilm/lm/src'
make[1]: *** [release-programs] Error 1
make[1]: Leaving directory `/home/user612/srilm'
make: *** [World] Error 2

H2O DriverlessAI 에서의 custom recipe 등록하는 방법



H2O DriverlessAI (이하 H2O DAI) 버전 1.7 이상에서는 custom recipe를 등록해서 사용할 수 있는 기능, 즉 BYOR(Bring Your Own Recipe) 기능을 사용하실 수 있습니다.  이 recipe라는 것은 결국 python code인데, 자신만의 recipe를 어떤 format으로 어떻게 coding해야 하는지에 대해서는 다음의 github에 예제가 있으므로 참조하시기 바랍니다.

https://github.com/h2oai/driverlessai-recipes/


그렇게 recipe code를 작성하고 난 뒤에 어떻게 H2O DAI에 등록을 하느냐에 대해서 아래에 그림과 함께 정리했습니다.

우선은 custom recipe code를 새로 등록하기 전에, 기존의 recipe들에는 무엇이 있었는지 확인하겠습니다.

먼저 dataset을 선택해서 평소처럼 'Predict' 메뉴에 들어갑니다.  거기서 평소와는 달리 'EXPERT SETTINGS' 부분을 click 합니다.



그렇게 들어간 메뉴 오른쪽 상단에 'RECIPE' tab이 보입니다.  그걸 click 하십시요.



아래 그림과 같이 'Include specific models' 부분의 'SELECT VALUES' button을 click 하십시요.



그 결과를 보면 다음과 같습니다.  기본적으로 9개의 recipe가 이미 등록되어 있는 것을 보실 수 있습니다.  나중에 custom recipe를 등록한 뒤에 이 화면과 비교해보시면 됩니다.



이제 custome recipe code를 등록하겠습니다.  여기서는 여러분의 PC에 custom recipe를 위한 python code가 저장되어 있다고 가정하겠습니다.  'EXPERT SETTINGS' 메뉴의 맨 왼쪽 상단에 있는 '+ UPLOAD CUSTOM RECIPE' button을 click 하십시요.



그러면 upload할 code를 선택하기 위한 box가 나타납니다.  여기서 제가 upload할 code는 아래 github에서 가져온 것입니다.

https://github.com/h2oai/driverlessai-recipes/blob/master/models/algorithms/h2o-3-models.py

그 code를 선택하여 click 하시면 문법 등의 검증 과정을 거쳐 H2O DAI가 available한 recipe로 등록합니다.



이제 사실상 끝난 것입니다.   확인을 위해 아까 위에서 했던 것처럼 아래 그림과 같이 'Include specific models' 부분의 'SELECT VALUES' button을 click 하십시요.



이제 새로 upload된 python code 안의 custom model들이 새로 등록된 것을 보실 수 있습니다.



Default로는 모든 custom recipe도 enable되어 있습니다.  올리신 custom recipe들을 적용하고 싶지 않을 때는 오른쪽 상단의 'Disable/Enable Custom' toggle button을 클릭하시면 됩니다.

올리신 custom recipe를 제거하고 싶으시면 H2O DAI의 설치 direcoty 밑의 ./tmp/contrib/ 밑의 아래 내용들을 지우시면 됩니다.   그러신 뒤에 H2O DAI를 restart 하셔야 합니다.

$ pwd
/home/user612/dai-1.7.1-linux-ppc64le/tmp/contrib

$ rm -rf models_global_packages/* transformers_global_packages/* models/*



2019년 10월 8일 화요일

H2O DriverlessAI에서 큰 dataset을 학습할 때 memory를 적게 사용하도록 하는 설정 방법


H2O DriverlessAI는 서버 메모리를 많이 사용하는 솔루션입니다.  기본적인 rule of thumb은 training dataset의 10배 크기의 서버 메모리가 필요하다는 것입니다.  즉, 만약 training dataset이 30GB라면, 서버 메모리는 300GB 이상 있어야 합니다.

그런데 살다보면 training dataset이 30GB인데 서버 메모리는 100GB 밖에 안 되는 경우도 있습니다.  이런 경우에는 H2O DriverlessAI는 쓰지 못하는 것일까요?  꼭 그렇지는 않습니다.

H2O DriverlessAI는 기본적으로 'data가 너무 크다'라고 생각하면 down-sampling이라는 것을 합니다.  즉, data 중에서 일부만 발췌헤서 training에 사용하는 것입니다.

그렇다면 당연히 몇가지 의문이 생깁니다.

1.  '너무 크다'라는 것의 기준은 무엇인가?

당연히 기준이 있어야 하는데, 그건 H2O DriverlessAI의 config.toml이라는 파일 속에 있습니다.  이 파일은 H2O DriverlessAI의 설치 home directory에 들어있습니다.  기본적으로는 아래와 같이 statistical_threshold_data_size_large = 500000000 라는 parameter에 의해 정해지는데, 이 값은 default가 500M으로 되어 있고, 이 값은 data의 byte 수 등이 아니라 rows * columns 의 숫자입니다.   즉, 가령 50개의 column을 가진 CSV 파일의 row수가 10M을 넘어간다면 H2O DriverlessAI는 이 dataset이 '너무 크다' 라고 판단합니다.

[user612@p612-met1 dai-1.7.1-linux-ppc64le]$ vi ./config.toml
...
# Internal threshold for number of rows x number of columns to trigger certain statistical
# techniques (fewer genes created, removal of high max_depth for tree models, etc.) that can speed up modeling.
# Also controls maximum rows used in training final model,
# by sampling statistical_threshold_data_size_large / columns number of rows
#statistical_threshold_data_size_large = 500000000


2. 이 파라미터를 어떻게 얼마나 조정해야 하는가?

만약 이 기본값으로 training할 때 서버 메모리 부족으로 error가 난다면, 이 기준값을 내려야 합니다.  제가 해보니 이 수치가 정확하게 rows * columns를 맞추는 것은 아니니, 정확하게는 try & error를 통해 경험치로 조정하셔야 합니다.  아무튼 이것을 수정하는 방법은 저 config.toml 파일을 수정한 뒤 H2O DriverlessAI를 retstart 하는 것입니다.   아래의 예는 그 기준을 1/5f로 줄인 것입니다.

[user612@p612-met1 dai-1.7.1-linux-ppc64le]$ vi ./config.toml
...
#statistical_threshold_data_size_large = 500000000
statistical_threshold_data_size_large = 100000000


3. Sampling은 어떤 기준으로 이루어지는가? 

기본적으로 sampling 할 때는 알아서 적절히 하게 되어 있습니다.  특히 현재 training하려는 문제의 결과가 regression(결과가 숫자로 나오는 경우)의 경우와 classification(몇가지 정해진 카테고리 중 하나로 나오는 것)의 경우에 대해 각각 다릅니다.

- Regression의 경우 : Random sampling (마구잡이 샘플링)
- Classification의 경우 : Stratified sampling (계층별 샘플링)

그런데 특히 sparse data에 대한 classification인 경우, 즉 신용카드사의 정상/비정상 거래처럼 대부분은 정상이고 극히 일부만 비정상 거래인 경우에는 그렇쟎아도 부족한 비정상 거래 data 건수가 더 줄어들지 않을까 염려됩니다.  만약 그렇게 class별로 record 수가 5배 이상 차이가 날 경우, H2O DriverlessAI는 알아서 그 dataset을 imbalanced dataset이라고 판단하고 그에 따라 sampling을 진행합니다.

이런 imbalanced sampling는 "Expert Settings" tab의 "MODEL" 메뉴에서 조정이 가능하며, 다음과 같이 여러가지 방법을 제공합니다.




어떤 sampling 방법이 가장 좋은지에는 정답이 없습니다만, 위에서 언급한 신용카드 사기 거래 dataset과 같이 imbalance가 심한 dataset에서는  잘 판단이 서지 않을 때는 일단 Over_under_sampling을 택하는 것이 낫지 않을까 합니다.  (저는 일일이 테스트 해보지는 못했습니다.)

Automatic :  모든 class를 필요에 따라 적절히 sampling (default)
Over_sampling : 소수 class를 더 많이 sampling하여 균형을 맞춤
Under_sampling : 다수 class를 더 적게 sampling하여 균형을 맞춤 
Over_under_sampling : 소수 class는 over sampling하고 다수 class는 under sampling하여 균형을 맞춤
Off : Sampling을 하지 않음




4. 이렇게 down-sampling하면 결과로 만들어지는 accuracy에 저하가 발생하지 않는가 ?

당연히 일부 발생할 수도 있습니다.  그런 저하를 용납할 수 없는 상황이시라면 서버 메모리를 더 사셔야 합니다...



## Training의 메모리 필요량을 줄이는 다른 기본적인 방법들 

1.  Accuracy Dial을 낮춘다

- Accuracy를 높일 수록 좀더 많은 model을 적용해보기 때문에 당연히 메모리 사용량이 늘어납니다.  Accuracy dial을 3~4 정도로 낮게 두면 메모리 사용량이 극적으로 줄어듭니다.  그럴 경우 당연히 accuracy도 떨어진다는 단점이 있습니다.

2.  Expert Settings tab 중 'MODEL' 메뉴에서 lightGBM을 제외한 모든 model을 off 시킨다

- 무조건 많은 model을 적용한다고 accuracy가 다 높아지는 것은 아닙니다.  실제로 대부분의 경우 lightGBM과 XGBoost에서 가장 좋은 accuracy가 나옵니다.  따라서, Rulefit이나 GLM, Tensorflow 등의 모델들을 off 시켜 놓으면 역시 메모리 사용량이 극적으로 줄어듭니다.  물론 accuracy도 좀 떨어지긴 합니다.






2019년 9월 18일 수요일

IBM POWER에서 Julia를 source로부터 build 하기



Redhat 7.6 ppc64le 위에서 docker를 이용하여 Ubuntu 18.04 ppc64le 환경을 만들고 그 위에서 Julia 1.2.0을 source로부터 build하는 과정입니다.

먼저 root user로 기존에 jupyter 및 scipy-notebook이 설치된 ppc64le용 docker image를 구동합니다.

[user609@c609-kvm1 ~]$ sudo docker run -ti --rm --user root -e NB_GID=100 -e GEN_CERT=yes -e GRANT_SUDO=yes brlee/jupyter:scipy-notebook bash

먼저 julia 관련 환경 변수를 설정합니다.

root@5b95ee340ef3:~# cd /opt

root@5b95ee340ef3:/opt# export JULIA_DEPOT_PATH=/opt/julia
root@5b95ee340ef3:/opt# export JULIA_PKGDIR=/opt/julia
root@5b95ee340ef3:/opt# export JULIA_VERSION=1.2.0

root@5b95ee340ef3:/opt# mkdir /opt/julia-${JULIA_VERSION}

그리고나서 julia의 source를 github에서 download 받습니다.

root@5b95ee340ef3:/opt# cd /tmp

root@5b95ee340ef3:/tmp# git clone git://github.com/JuliaLang/julia.git

root@5b95ee340ef3:/tmp# cd julia

또한 julia build에 필요한 OS package들을 설치해야 합니다.

root@5b95ee340ef3:/tmp/julia# apt-get update

root@5b95ee340ef3:/tmp/julia# apt-get install -y gfortran fonts-dejavu gcc libreadline-dev readline-common libx11-dev libxt-dev libbz2-dev liblzma-dev libpcre2-dev libpcre3-dev  libcurl4-gnutls-dev gfortran-5-powerpc-linux-gnu texlive-latex-base texinfo texlive-fonts-extra openjdk-8-jdk openjdk-8-jdk-headless vim libmbedtls-dev libmbedcrypto1 m4 libssh2-1-dev

이렇게 설치가 되어 있더라, 현재 버전에서는 일부 파일들의 버전이 정확히 맞지가 않아서 error가 좀 있습니다.  이는 다음과 같이 그냥 다른 버전의 이름으로 soft link를 걸어서 해결할 수 있습니다.

root@5b95ee340ef3:/tmp/julia# ln -s /usr/lib/powerpc64le-linux-gnu/libmbedtls.so.10 /usr/lib/powerpc64le-linux-gnu/libmbedtls.so.12

root@5b95ee340ef3:/tmp/julia# ln -s /usr/lib/powerpc64le-linux-gnu/libmbedcrypto.so.2.8.0 /usr/lib/powerpc64le-linux-gnu/libmbedcrypto.so.3

우리가 여기서 compile할 것은 v1.2.0 입니다.

root@5b95ee340ef3:/tmp/julia# git checkout tags/v1.2.0

Build 자체는 매우 쉽습니다.  그냥 make 하시면 됩니다.   그런데 그렇게 하면 일단 error가 납니다.  다음과 같이 "ELF load command alignment not page-aligned" error 입니다.  이는 아마도 POWER architecture에서 huge page를 사용하기 때문에 발생하는 것일 수 있습니다.

root@5b95ee340ef3:/tmp/julia# nohup make -j8 &
...
Serialization  ──  1.911660 seconds
Libdl  ──────────  0.074467 seconds
Markdown  ───────  1.986755 seconds
error during bootstrap:
LoadError("sysimg.jl", 16, LoadError("/tmp/julia/usr/share/julia/stdlib/v1.2/LibGit2/src/LibGit2.jl", 21, LoadError("/tmp/julia/usr/share/julia/stdlib/v1.2/LibGit2/src/utils.jl", 44, ErrorException("error compiling version: could not load library \"libgit2\"\nlibcurl.so.4: ELF load command alignment not page-aligned"))))
rec_backtrace at /tmp/julia/src/stackwalk.c:94
record_backtrace at /tmp/julia/src/task.c:219 [inlined]
...

이 문제는 다음과 같이 몇개의 so 파일을 docker image 내의 OS file들로 교체하면 간단히 해결됩니다.

root@5b95ee340ef3:/tmp/julia# cp /usr/lib/powerpc64le-linux-gnu/libcurl.so.4.5.0 ./usr/lib/libcurl.so.4

root@5b95ee340ef3:/tmp/julia# cp /usr/lib/powerpc64le-linux-gnu/libmbedtls.so.2.8.0 ./usr/lib/libmbedtls.so.2.16.0

root@5b95ee340ef3:/tmp/julia# cp /usr/lib/powerpc64le-linux-gnu/libmbedtls.so.2.8.0 ./usr/lib/libmbedtls.so.2.6.0

root@5b95ee340ef3:/tmp/julia# cp /usr/lib/powerpc64le-linux-gnu/libmbedtls.so.2.8.0 ./deps/scratch/mbedtls-2.6.0-gpl/library/libmbedtls.so.2.6.0

root@5b95ee340ef3:/tmp/julia# cp /usr/lib/powerpc64le-linux-gnu/libssh2.so.1.0.1 ./deps/scratch/libssh2-30e9c1347e3b8baa2951db612f05e6d87fc8e2f2/src/libssh2.so.1.0.1

root@5b95ee340ef3:/tmp/julia# cp /usr/lib/powerpc64le-linux-gnu/libssh2.so.1.0.1 ./deps/scratch/libssh2-30e9c1347e3b8baa2951db612f05e6d87fc8e2f2/tests/libssh2.so.1.0.1

root@5b95ee340ef3:/tmp/julia# cp /usr/lib/powerpc64le-linux-gnu/libssh2.so.1.0.1 ./usr/lib/libssh2.so.1.0.1

그 다음에 다시 make를 수행하면 성공적으로 잘 build 됩니다.

root@5b95ee340ef3:/tmp/julia# make
...
REPL  ───────────  1.273557 seconds
Statistics  ─────  0.487972 seconds
Stdlibs total  ── 93.832328 seconds
Sysimage built. Summary:
Total ─────── 146.463495 seconds
Base: ───────  52.627857 seconds 35.9324%
Stdlibs: ────  93.832328 seconds 64.0653%
    JULIA usr/lib/julia/sys-o.a
Generating precompile statements... 898 generated in 131.715009 seconds (overhead  97.270528 seconds)
    LINK usr/lib/julia/sys.so

root@5b95ee340ef3:/tmp/julia# make install

이제 docker image size를 줄이기 위해 불필요한 file을 제거합니다.

root@5b95ee340ef3:/tmp/julia# cd ..

root@5b95ee340ef3:/tmp# rm -rf julia

그 다음에 parent OS에서 docker image를 commit하면 됩니다.

[user609@c609-kvm1 ~]$ sudo docker commit 5b95ee340ef3 brlee/jupyter:julia-1.2.0

이 image는 다음의 이름으로 public docker hub에 push해놓았습니다.

[user609@c609-kvm1 ~]$ sudo docker push brlee/jupyter:julia-1.2.0



2019년 8월 9일 금요일

REAR : Linux on POWER에서 사용가능한 OS backup 솔루션


Redhat이건 Ubuntu건 Linux on POWER의 OS backup/restore 솔루션으로 REAR(RElax-And-Recover)라는 open source tool을 이용할 수 있습니다.

REAR는 다음 URL에 사용법이나 source code 등이 자세히 나와 있습니다. 

http://relax-and-recover.org

Ubuntu 18.04 같은 경우에는 다음과 같이 정규 apt repository에 포함이 되어 있습니다.

u0017649@sys-99014:~/files$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 18.10
Release:        18.10
Codename:       cosmic

u0017649@sys-99014:~$ apt-cache pkgnames | grep -i rear
rear
rear-doc

REAR와 함께 install 되어야 하는 pre-requisite OS package들은 대략 다음과 같습니다.

u0017649@sys-99014:~$ sudo apt-get install -y rear rear-doc
...
The following NEW packages will be installed:
  attr isolinux keyutils libisoburn1 libnfsidmap2 libtirpc1 nfs-common rear rear-doc rpcbind syslinux-common xorriso
...

그러나 Ubuntu 16.04 같은 경우에는 다음과 같이 REAR가 apt repository에 포함되어있지 않습니다.

u0017649@sys-99404:~$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 16.04.2 LTS
Release:        16.04
Codename:       xenial

u0017649@sys-99404:~$ apt-cache pkgnames | grep rear

이 경우에도 당황하지 않으셔도 됩니다.  Ubuntu 18.04에 있는 최신 REAR를 download 받아서 사용할 수 있으니까요.  물론 여기서는 ppc64el용의 것을 download 받으셔야 합니다.

u0017649@sys-99014:~/REAR$ wget http://ports.ubuntu.com/ubuntu-ports/pool/universe/r/rear/rear_2.3+dfsg-1_ppc64el.deb

그리고 다음과 같이 REAR 설치에 필요한 prerequisite OS package들을 download 받습니다.

u0017649@sys-99404:~/REAR$ apt-get download attr isolinux keyutils libisoburn1 libnfsidmap2 libtirpc1 nfs-common rpcbind syslinux-common xorriso libburn4 libisoburn1 libisofs6 libevent-2.0-5
Get:1 http://ports.ubuntu.com/ubuntu-ports xenial/main ppc64el attr ppc64el 1:2.4.47-2 [24.6 kB]
Get:2 http://ports.ubuntu.com/ubuntu-ports xenial/main ppc64el isolinux all 3:6.03+dfsg-11ubuntu1 [44.6 kB]
Get:3 http://ports.ubuntu.com/ubuntu-ports xenial/main ppc64el keyutils ppc64el 1.5.9-8ubuntu1 [46.7 kB]
Get:4 http://ports.ubuntu.com/ubuntu-ports xenial/main ppc64el libnfsidmap2 ppc64el 0.25-5 [29.9 kB]
Get:5 http://ports.ubuntu.com/ubuntu-ports xenial/main ppc64el rpcbind ppc64el 0.2.3-0.2 [38.4 kB]
Get:6 http://ports.ubuntu.com/ubuntu-ports xenial/main ppc64el syslinux-common all 3:6.03+dfsg-11ubuntu1 [1,181 kB]
Get:7 http://ports.ubuntu.com/ubuntu-ports xenial/universe ppc64el libisoburn1 ppc64el 1.4.2-4ubuntu1 [335 kB]
Get:8 http://ports.ubuntu.com/ubuntu-ports xenial/universe ppc64el xorriso ppc64el 1.4.2-4ubuntu1 [263 kB]
...

Download가 다 끝난 뒤 보면 아래와 같은 file들이 보입니다.

u0017649@sys-99404:~/REAR$ ls -l
total 2948
-rw-r--r-- 1 u0017649 u0017649   24640 Sep  9  2014 attr_1%3a2.4.47-2_ppc64el.deb
-rw-r--r-- 1 u0017649 u0017649   44606 Feb 24  2016 isolinux_3%3a6.03+dfsg-11ubuntu1_all.deb
-rw-r--r-- 1 u0017649 u0017649   46694 Dec 10  2015 keyutils_1.5.9-8ubuntu1_ppc64el.deb
-rw-r--r-- 1 u0017649 u0017649  139746 Feb 17  2016 libburn4_1.4.2.pl01-1_ppc64el.deb
-rw-r--r-- 1 u0017649 u0017649  108980 Mar 13  2017 libevent-2.0-5_2.0.21-stable-2ubuntu0.16.04.1_ppc64el.deb
-rw-r--r-- 1 u0017649 u0017649  334928 Apr 18  2016 libisoburn1_1.4.2-4ubuntu1_ppc64el.deb
-rw-r--r-- 1 u0017649 u0017649  195768 Feb  5  2016 libisofs6_1.4.2-2_ppc64el.deb
-rw-r--r-- 1 u0017649 u0017649   29864 Feb 17  2014 libnfsidmap2_0.25-5_ppc64el.deb
-rw-r--r-- 1 u0017649 u0017649   70442 Sep  5  2018 libtirpc1_0.2.5-1ubuntu0.1_ppc64el.deb
-rw-r--r-- 1 u0017649 u0017649  171216 May  8 19:08 nfs-common_1%3a1.2.8-9ubuntu12.2_ppc64el.deb
-rw-r--r-- 1 u0017649 u0017649  336988 Aug  8 22:26 rear_2.3+dfsg-1_ppc64el.deb
-rw-r--r-- 1 u0017649 u0017649   38358 Nov 11  2015 rpcbind_0.2.3-0.2_ppc64el.deb
-rw-r--r-- 1 u0017649 u0017649 1181310 Feb 24  2016 syslinux-common_3%3a6.03+dfsg-11ubuntu1_all.deb
-rw-r--r-- 1 u0017649 u0017649  263420 Apr 18  2016 xorriso_1.4.2-4ubuntu1_ppc64el.deb

이를 아래와 같이 dpkg 명령으로 다 설치하면 됩니다.

u0017649@sys-99404:~/REAR$ sudo dpkg -i *
...
Setting up xorriso (1.4.2-4ubuntu1) ...
Setting up rear:ppc64el (2.3+dfsg-1) ...
Processing triggers for man-db (2.7.5-1) ...
Processing triggers for libc-bin (2.23-0ubuntu7) ...
Processing triggers for systemd (229-4ubuntu16) ...
Processing triggers for ureadahead (0.100.0-19) ...
Processing triggers for install-info (6.1.0.dfsg.1-5) ...

이제 rear 명령을 쓰실 수 있습니다.

u0017649@sys-99404:~$ which rear
/usr/sbin/rear

REAR를 통해 boot 이미지를 만들고 backup을 받으려면 USB storage(또는 USB stick)를 사용하시는 것이 일반적입니다.  USB port에 USB storage를 꽂으시고 그것이 /dev/sdc로 인식되면, 아래와 같이 일단 format을 해줍니다.  이때 당연히 USB storage 안의 기존 data는 모두 삭제되는데, label은 REAR-000으로 붙여집니다.

u0017649@sys-99404:~$ sudo rear format /dev/sdc

그리고 다음과 같이 REAR의 local config file을 업데이트합니다.

u0017649@sys-99404:~$ sudo vi /etc/rear/local.conf
OUTPUT=USB
BACKUP=NETFS
BACKUP_URL="usb:///dev/disk/by-label/REAR-000"

다음 명령으로 USB storage 안에 boot image를 만듭니다.

u0017649@sys-99404:~$ sudo rear -v mkrescue

그리고나서 아래와 같은 명령으로 OS backup을 받습니다.  이때 backup에 사용되는 format은 tar 입니다.

u0017649@sys-99404:~$ sudo rear -v mkbackup

이제 저 USB storage로부터 booting을 하여 'Recover Arch Rear'를 선택한 뒤, 'arch rear' prompt가 나오면 'rear recover' 명령을 수행하면 OS가 restore 됩니다.   저는 USB storage도 없고 물리적인 linux 서버도 없어서 restore는 테스트해보지 못했습니다만, REAR의 홈페이지에 나와 있는 유튜브 동영상 중에 캡춰한 화면의 recover 메뉴는 아래와 같습니다.




혹시 필요하신 분들을 위하여, 위에서 사용한 'REAR' directory 속의 rear 및 그 prerequisite OS package들을 download 받아둔 REAR.tgz 파일을 아래 Google drive에 올려두었습니다.

https://drive.google.com/open?id=10FjolrZSpuDl6qDKv3dKwOJyCLMxXr7l


2019년 7월 23일 화요일

공유 HW infrastructure에서의 H2O DriverlessAI 사용 방안


H2O DriverlessAI (이하 DAI)를 사내의 여러 팀에서 사용할 경우 먼저 참고하셔야 할 사항은 다음과 같습니다.

1) DAI의 training(DAI 용어로는 experiment)는 host memory든 GPU memory든 꼭 필요한 만큼의 memory만 사용합니다.  따라서 시스템 자원의 여유만 충분하다면 하나의 서버에서 여러 training을 한꺼번에 수행해도 됩니다.

2) DAI는 일반적으로 dataset 크기의 10배에 해당하는 메모리를 사용한다고 예상하시면 됩니다.  가령 1GB의 dataset으로 training을 한다고 하면, 10GB의 메모리가 필요합니다.  "Accuracy" dial setting을 낮추면 더 적은 memory로도 training이 가능합니다.

3) DAI는 CPU 자원도 많이 쓰지만 특히 memory 자원에 민감합니다.  하나의 DAI training이 이미 시스템의 거의 모든 memory를 다 쓰고 있는 상황에서, 추가적으로 다른 DAI training을 수행하기 시작한다면, 이 두 DAI training 모두가 memory 부족으로 fail될 수 있습니다.

4) DAI는 GPU 자원이 없거나 GPU가 있어도 GPU의 메모리가 부족한 경우 그냥 CPU를 이용해서 training을 수행합니다.  따라서 GPU가 없거나 GPU 메모리가 부족하다고 해서 DAI training이 fail나는 경우는 없습니다.


위와 같은 사항을 이해한다면, 서로의 상황을 잘 이해하고 서로 배려하는 소수의 사용자들이 하나의 서버에서 여러개의 training을 동시에 수행하는 것은 별 문제를 일으키지 않습니다.  그러나 서로에 대해 잘 모르는 여러 팀의 여러 사용자들이 하나의 서버를 공유하는 것은 쉽지 않습니다.

이렇게 불특정 다수의 사용자들이 제한된 서버 자원을 이용하여 DAI에서 training을 하기 위해서는 각 사용자마다 한정된 시스템 자원 (CPU, memory, GPU)를 나누어주는 것이 가장 안정적입니다.  그러나 각각의 사용자들에게 완전히 격리된 가상머신을 할당해줄 경우 낭비되는 자원이 너무 많아진다는 약점이 있습니다.


이런 점들을 고려할 때, 가장 좋은 솔루션은 docker(GPU가 있는 환경에서는 nvidia-docker)를 사용하는 것입니다.  Docker를 사용할 경우의 장점은 아래와 같습니다.

1) 각 사용자가 사용하는 DAI docker image에서 사용할 수 있는 CPU와 memory, GPU의 한도를 정할 수 있으므로 각 사용자는 안정적인 training이 가능합니다.

2) 이미 다른 사용자에게 할당된 자원이라도, 당장 사용하지 않는 자원은 다른 사용자들의 docker container가 사용할 수 있으므로 전체적인 시스템 활용률이 높아집니다.

3) CPU나 메모리, disk 공간 등에 대한 가상화 오버헤드가 거의 없습니다.   IP도 사용자마다 1개씩 필요하지 않고, 각 사용자들에게는 서로 다른 port number만 할당해주면 됩니다.

4) 각 사용자 간의 보안은 일반적인 linux 보안 정책을 그대로 사용합니다.  따라서 보안 구분이 필요한 사용자 그룹마다 각기 다른 linux OS user id를 생성하여 관리하면 됩니다. 

5) 서비스의 생성은 command line 또는 script 한줄로 몇 초 안에 간단하게 처리되며, 이는 수퍼 유저(root)의 권한을 가진 시스템 관리자만 할 수 있습니다.

6) 100% 오픈소스로 간단하게 구축할 수 있습니다.


DAI를 구동할 때 docker를 이용하는 방법은 다음과 같이 간단합니다.  DAI가 설치된 docker image를 다음과 같이 구동하면 됩니다.

$ sudo docker run --runtime=nvidia --init --rm -p 12311:12345 -v /user01/data:/data -v /user01/log:/log -v /user01/tmp:/tmp h2oai/dai-redhat7-ppc64le:v0.1 

--runtime=nvidia : GPU를 사용하는 nvidia-docker 환경임을 명기
-p 12311:12345 : docker 내부의 DAI가 사용하는 port인 12345를 parent OS에서는 12311 port로 전달
-v /user01/data:/data : Parent OS의 /user01/data directory를 docker 내부에서는 /data directory로 mount 
h2oai/dai-redhat7-ppc64le:v0.1 : DAI가 설치된 docker image의 이름과 tag


위에서는 아무런 자원 제약을 주지 않고, 전체 시스템의 자원을 다 사용할 수 있도록 docker container를 구동한 것입니다.  이 경우, 1GB 정도의 AML dataset을 training할 때의 자원 사용 현황은 아래와 같습니다.   DAI process가 10GB의 memory(Res Data 기준 - 실제 real memory를 점유한 크기)를 사용하고 있으며 CPU도 (HW thread를 제외하고) 8개의 CPU core를 다 쓰고 있는 것을 보실 수 있습니다.



이렇게 시스템 자원의 제약 없이 수행한 경우엔 1GB dataset 수행에 (accuracy-time-interpretability dial 2-2-2로 세팅) 23m 29s가 걸렸습니다.



이번에는 CPU 자원은 core 4개, 메모리 자원은 5GB로 제한을 주고 수행해보겠습니다.

$ sudo docker run --runtime=nvidia --init --rm --cpus=4 --memory=5g -p 12311:12345 -v /user01/data:/data -v /user01/log:/log -v /user01/tmp:/tmp h2oai/dai-redhat7-ppc64le:v0.1

이 경우 동일한 크기의 dataset을 동일한 dial 세팅으로 수행할 때 자원 사용 현황은 아래와 같습니다.   DAI process가 4GB의 memory(Res Data 기준 - 실제 real memory를 점유한 크기)를 사용하고 있으며 CPU도 (HW thread를 제외하고) 8개의 CPU core 중 절반만을 쓰고 있는 것을 보실 수 있습니다.



이렇게 시스템 자원을 4 CPU core, 5GB의 메모리로 제약을 주고 수행한 경우엔 1GB dataset 수행에 (accuracy-time-interpretability dial 2-2-2로 세팅) 41m 12s가 걸렸습니다.   자원 제약 없을 때보다 2배 정도의 시간이 걸린 것을 보실 수 있습니다.




Docker container 수행시 GPU 자원을 할당하는 것은 아래와 같이 NVIDIA_VISIBLE_DEVICES 변수를 환경변수로 사용하면 됩니다.  아래의 경우에서는 2번과 3번 2개의 GPU를 할당하게 됩니다.

$ sudo docker run --runtime=nvidia --init --rm --cpus=4 --memory=5g -e NVIDIA_VISIBLE_DEVICES=2,3 -p 12311:12345 -v /user01/data:/data -v /user01/log:/log -v /user01/tmp:/tmp h2oai/dai-redhat7-ppc64le:v0.1