2019년 3월 19일 화요일

ppc64le 환경에서의 OFED libary와 FIO 설치 및 기본 테스트



Disk의 성능 측정을 위해 FIO를 쓰는 경우가 많습니다.  FIO는 rpm으로도 제공되며, 아래에서 download 받으시면 됩니다.

[u0017649@sys-97540 files]$ wget http://mirror.premi.st/epel/7/ppc64le/Packages/f/fio-3.1-1.el7.ppc64le.rpm

다만 이 FIO는 OFED library와 libaio를 prerequisite으로 필요로 하므로, 미리 이것들을 설치해야 합니다.  libaio야 OS에 포함된 것을 그대로 쓰면 됩니다.

[u0017649@sys-97540 files]$ sudo yum install -y libaio

OFED library는 다음의 Mellanox 홈페이지에서 ppc64le용 패키지를 download 받으실 수 있습니다.

http://www.mellanox.com/page/products_dyn?product_family=26




먼저 OFED library가 요구하는 OS prerequisite을 설치해야 합니다.

[u0017649@sys-97540 files]$ sudo yum install -y pciutils lsof tcl gcc-gfortran libgfortran tcsh tk

[u0017649@sys-97540 files]$ ls -l *.tgz
-rw-rw-r--. 1 u0017649 u0017649 236217006 Mar 18 21:14 MLNX_OFED_LINUX-4.5-1.0.1.0-rhel7.5alternate-ppc64le.tgz

[u0017649@sys-97540 files]$ tar -zxf MLNX_OFED_LINUX-4.5-1.0.1.0-rhel7.5alternate-ppc64le.tgz

압축 해제된 directory 속에 들어가보면 script들이 몇개 보입니다.

[u0017649@sys-97540 files]$ cd MLNX_OFED_LINUX-4.5-1.0.1.0-rhel7.5alternate-ppc64le

[u0017649@sys-97540 MLNX_OFED_LINUX-4.5-1.0.1.0-rhel7.5alternate-ppc64le]$ ls
common_installers.pl            docs                        mlnxofedinstall       src
common.pl                       is_kmp_compat.sh            RPM-GPG-KEY-Mellanox  uninstall.sh
create_mlnx_ofed_installers.pl  LICENSE                     RPMS
distro                          mlnx_add_kernel_support.sh  RPMS_UPSTREAM_LIBS

이제 mlnxofedinstall script를 수행하면 OFED libary가 설치됩니다.

[u0017649@sys-97540 MLNX_OFED_LINUX-4.5-1.0.1.0-rhel7.5alternate-ppc64le]$ sudo ./mlnxofedinstall
(저는 실제로는 RHEL7.5ALT ppc64le 환경을 구할 수 없어서 그냥 RHEL7.4 ppc64le에서 MLNX_OFED_LINUX-4.5-1.0.1.0-rhel7.4-ppc64le.tgz를 받아서 수행했습니다.  실제로는 해당 OS 버전에 정확히 맞는 버전을 download 받아서 수행하셔야 error가 나지 않습니다.)

Detected rhel7u4 ppc64le. Disabling installing 32bit rpms...
Logs dir: /tmp/MLNX_OFED_LINUX.7174.logs
General log file: /tmp/MLNX_OFED_LINUX.7174.logs/general.log
Verifying KMP rpms compatibility with target kernel...
This program will install the MLNX_OFED_LINUX package on your machine.
Note that all other Mellanox, OEM, OFED, RDMA or Distribution IB packages will be removed.
Those packages are removed due to conflicts with MLNX_OFED_LINUX, do not reinstall them.

Do you want to continue?[y/N]:y

Starting MLNX_OFED_LINUX-4.5-1.0.1.0 installation ...

Installing mlnx-ofa_kernel RPM
Preparing...                          ########################################
Updating / installing...
mlnx-ofa_kernel-4.5-OFED.4.5.1.0.1.1.g########################################
Configured /etc/security/limits.conf
Installing kmod-mlnx-ofa_kernel 4.5 RPM
Preparing...                          ########################################
kmod-mlnx-ofa_kernel-4.5-OFED.4.5.1.0.########################################
Installing mlnx-ofa_kernel-devel RPM
...
mlnxofed-docs-4.5-1.0.1.0             ########################################
Preparing...                          ########################################
mpitests_openmpi-3.2.20-e1a0676.45101 ########################################

Installation finished successfully.

Preparing...                          ################################# [100%]
Updating / installing...
   1:mlnx-fw-updater-4.5-1.0.1.0      ################################# [100%]

Added 'RUN_FW_UPDATER_ONBOOT=no to /etc/infiniband/openib.conf

Attempting to perform Firmware update...
No devices found!

To load the new driver, run:
/etc/init.d/openibd restart

저는 이 시스템에 infiniband adapter가 없기 때문에 위와 같이 'No devices found!'라는 메시지가 나옵니다만, 여기서는 신경 안쓰셔도 됩니다.   다만 맨 마지막 메시지처럼, 새로 설치된 driver를 load하려면 리부팅까지는 필요없고 아래와 같은 명령을 내리시면 됩니다.

먼저 아래와 같이 lsmod 명령으로 IB 관련 모듈이 load된 것이 있는지 살펴 봅니다.  보시다시피 없습니다.

[u0017649@sys-97540 files]$ sudo lsmod | grep ib
libcrc32c               1614  1 xfs
ibmvscsi               34850  5
scsi_transport_srp     18042  1 ibmvscsi
ibmveth                32369  0

이제 아래 명령으로 driver를 load합니다.

[u0017649@sys-97540 files]$ sudo /etc/init.d/openibd restart
Unloading HCA driver:                                      [  OK  ]
Loading HCA driver and Access Layer:                       [  OK  ]

다시 lsmod 명령으로 IB 관련 모듈이 load된 것이 있는지 살펴 봅니다.   아까와는 달리 뭔가가 많이 올라온 것을 보실 수 있습니다.

[u0017649@sys-97540 files]$ sudo lsmod | grep ib
ib_ucm                 17919  0
ib_ipoib              196794  0
ib_cm                  57708  3 rdma_cm,ib_ucm,ib_ipoib
ib_umad                19974  0
mlx5_ib               380860  0
ib_uverbs             135906  3 mlx5_ib,ib_ucm,rdma_ucm
mlx5_core            1040727  2 mlx5_ib,mlx5_fpga_tools
mlx4_ib               242651  0
ib_core               341508  10 rdma_cm,ib_cm,iw_cm,mlx4_ib,mlx5_ib,ib_ucm,ib_umad,ib_uverbs,rdma_ucm,ib_ipoib
mlx4_core             413829  2 mlx4_en,mlx4_ib
mlx_compat             28099  15 rdma_cm,ib_cm,iw_cm,mlx4_en,mlx4_ib,mlx5_ib,mlx5_fpga_tools,ib_ucm,ib_core,ib_umad,ib_uverbs,mlx4_core,mlx5_core,rdma_ucm,ib_ipoib
devlink                35827  4 mlx4_en,mlx4_ib,mlx4_core,mlx5_core
libcrc32c               1614  1 xfs
ibmvscsi               34850  5
scsi_transport_srp     18042  1 ibmvscsi
ibmveth                32369  0


이제 download 받은 FIO를 설치합니다.  설치 자체는 간단합니다.

[u0017649@sys-97540 files]$ sudo rpm -Uvh fio-3.1-1.el7.ppc64le.rpm                                     warning: fio-3.1-1.el7.ppc64le.rpm: Header V3 RSA/SHA256 Signature, key ID 352c64e5: NOKEY
Preparing...                          ################################# [100%]
Updating / installing...
   1:fio-3.1-1.el7                    ################################# [100%]

이제 fio 명령이 생겼습니다.

[u0017649@sys-97540 files]$ which fio
/usr/bin/fio

제가 테스트하는 서버는 SATA 디스크를 가상으로 쪼개어 받은 매우 형편없는 spec의 포팅용 가상머신입니다.  따라서 제대로 된 성능 테스트는 아니라는 점을 미리 인지하시기 바랍니다.

기본적인 write 테스트를 해봅니다.  numjobs=1로 돌리는데, CPU 사용량은 거의 없습니다.

[u0017649@sys-97540 files]$ time fio --randrepeat=1 --ioengine=libaio --direct=1 --gtod_reduce=1 --name=test --filename=/tmp/test1 --bs=64k --iodepth=64 --size=500M --numjobs=1 --readwrite=randwrite --rwmixwrite=100
test: (g=0): rw=randwrite, bs=(R) 64.0KiB-64.0KiB, (W) 64.0KiB-64.0KiB, (T) 64.0KiB-64.0KiB, ioengine=libaio, iodepth=64
fio-3.1
Starting 1 process
test: Laying out IO file (1 file / 500MiB)
Jobs: 1 (f=1): [w(1)][99.3%][r=0KiB/s,w=0KiB/s][r=0,w=0 IOPS][eta 00m:02s]
...

Run status group 0 (all jobs):
  WRITE: bw=1924KiB/s (1970kB/s), 1924KiB/s-1924KiB/s (1970kB/s-1970kB/s), io=500MiB (524MB), run=266076-266076msec

Disk stats (read/write):
  sda: ios=0/7363, merge=0/667, ticks=0/15785000, in_queue=15789550, util=100.00%

real    4m26.400s
user    0m0.328s
sys     0m0.457s

이번에는 numjobs를 2로 다시 해보았습니다.  (OS memory cache 효과를 없애기 위해 filename에 다른 file 이름을 써야 합니다.)  처음의 numjobs=1보다는 빠르지만 물론 2배 빠른 것은 아닙니다.

[u0017649@sys-97540 files]$ time fio --randrepeat=1 --ioengine=libaio --direct=1 --gtod_reduce=1 --name=test --filename=/tmp/test2 --bs=64k --iodepth=64 --size=500M --numjobs=2 --readwrite=randwrite --rwmixwrite=100
test: (g=0): rw=randwrite, bs=(R) 64.0KiB-64.0KiB, (W) 64.0KiB-64.0KiB, (T) 64.0KiB-64.0KiB, ioengine=libaio, iodepth=64
...
fio-3.1
Starting 2 processes
test: Laying out IO file (1 file / 500MiB)
Jobs: 2 (f=2): [w(2)][99.3%][r=0KiB/s,w=0KiB/s][r=0,w=0 IOPS][eta 00m:03s]
...

Run status group 0 (all jobs):
  WRITE: bw=2455KiB/s (2514kB/s), 1227KiB/s-1228KiB/s (1257kB/s-1257kB/s), io=1000MiB (1049MB), run=417045-417161msec

Disk stats (read/write):
  sda: ios=0/14383, merge=0/1643, ticks=0/48880230, in_queue=48926190, util=100.00%

real    6m57.439s
user    0m0.737s
sys     0m0.848s


이번에는 디스크가 아닌 공유 메모리 상에 써보겠습니다.  아래와 같이 /dev/shm에 1.8G 여유 공간이 있습니다.

[u0017649@sys-97540 files]$ df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda5        31G  7.3G   24G  24% /
devtmpfs        1.7G     0  1.7G   0% /dev
tmpfs           1.8G   23M  1.8G   2% /dev/shm
tmpfs           1.8G   23M  1.8G   2% /run
tmpfs           1.8G     0  1.8G   0% /sys/fs/cgroup
/dev/sda2      1014M  166M  849M  17% /boot
tmpfs           357M     0  357M   0% /run/user/1001

다만 이건 임시 메모리 파일시스템인 tmpfs이므로 버퍼를 쓰지 않는 --direct=1 옵션을 쓸 수 없습니다.  따라서 그냥 --direct=0 옵션을 택해야 합니다.  당연히 4GB/s의 우수한 속도가 나옵니다.

[u0017649@sys-97540 files]$ sudo fio --randrepeat=1 --ioengine=libaio --direct=0 --gtod_reduce=1 --name=test --filename=/dev/shm/test2 --bs=64k --iodepth=64 --size=500M --numjobs=2 --readwrite=randwrite --rwmixwrite=100
test: (g=0): rw=randwrite, bs=(R) 64.0KiB-64.0KiB, (W) 64.0KiB-64.0KiB, (T) 64.0KiB-64.0KiB, ioengine=libaio, iodepth=64

...

Run status group 0 (all jobs):
  WRITE: bw=3906MiB/s (4096MB/s), 1953MiB/s-2024MiB/s (2048MB/s-2123MB/s), io=1000MiB (1049MB), run=247-256msec



Read 테스트는 다음과 같이 합니다.

[u0017649@sys-97540 files]$ fio --randrepeat=1 --ioengine=libaio --direct=1 --gtod_reduce=1 --name=test --filename=/tmp/test1 --bs=64k --iodepth=64 --size=1G --numjobs=2 --readwrite=randread --rwmixread=100  test: (g=0): rw=randread, bs=(R) 64.0KiB-64.0KiB, (W) 64.0KiB-64.0KiB, (T) 64.0KiB-64.0KiB, ioengine=libaio, iodepth=64

...

Run status group 0 (all jobs):
   READ: bw=13.2MiB/s (13.9MB/s), 6778KiB/s-6793KiB/s (6941kB/s-6956kB/s), io=2048MiB (2147MB), run=154363-154703msec


2019년 3월 18일 월요일

H2O Driverless AI를 통한 인물별 의료비 예측


H2O Driverless AI (이하 H2O DAI)의 또다른 유력한 use case인 보험 업무에 대해 살펴보겠습니다.   보험사에게 있어 의료비가 많이 들 것 같은 사람을 골라내는 것은 보험사의 수익과 직결되는 무척 중요한 일입니다.  아래 Kaggle site에서 얻은 환자 기본 정보 및 각 환자에게 든 의료비에 대한 dataset을 이용하여 H2O DAI가 예상 의료비를 얼마나 정확히 측정하는지 테스트 해보겠습니다.

https://www.kaggle.com/mirichoi0218/insurance

이 dataset에는 다음과 같은 칼럼들이 있습니다. 

age  나이
sex  성별
bmi  비만도
children  자녀수
smoker  흡연여부
region  사는 지역
charges  의료비

보험사에서 예측하고 싶은 것은 물론 맨 마지막 칼럼인 charges 부분일 것입니다.  이제 H2O DAI를 이용하여 어떻게 이 dataset으로부터 특정 조건을 가진 인물의 예상 의료비를 뽑아낼 수 있는지 step by step으로 알아보시도록 하겠습니다.

1) 웹 브라우저를 통해 H2O DAI에 접속합니다.   맨 처음 menu는 'DATASET'이며, 여러가지 입력 방법 중에서 저는 제 laptop으로부터 upload하는 menu를 택하겠습니다.



2) 저는 위의 Kaggle dataset (insurance.csv)에서 미리 일부 row들을 떼어내어 insurance_test.xlsx를 만들었고, 그 나머지를 insurance_training.xlsx로 저장해놓았습니다.  이것들을 선택하여 H2O DAI에 dataset으로 등록합니다.



3) insurance_training.xlsx와 insurance_test.xlsx가 dataset으로 등록되었습니다.   우측의 'Click for Actions' 부분을 눌러 나오는 sub-menu 중 'DETAILS' 부분을 클릭해 봅니다.



4) 이 DETAILS' 메뉴에서는 이 dataset이 어떤 정보를 담고 있는지 보실 수 있습니다.  각 칼럼별 평균/최대/최소/편차 등의 기본 정보와 최초 20개 row의 값 등을 보실 수 있습니다. 



5) Dataset 우측의 'Click for Actions' 부분을 눌러 나오는 sub-menu 중 'VISUALIZATION'을 클릭하면 여러가지 다양한 graph가 자동으로 생성됩니다.   가령 'OUTLIERS PLOT'을 보면 전체 data 중 일부가 표준편차에서 크게 벗어난 것을 보실 수 있습니다.  그런 부분은 표에서 보는 것보다는 이렇게 그래프로 시각화해서 보면 직관적으로 이해하기가 쉽지요.  그렇게 크게 벗어난 오렌지색 점을 클릭해보면 해당 row의 상세 정보를 보실 수도 있습니다.






6) H2O DAI에서 가장 중요한 것은 역시 'PREDICT' 메뉴입니다.  이 메뉴를 통해서 예측 모델을 자동 생성하게 됩니다. 



7) 'PREDICT' 메뉴에 들어가면 꼭 하셔야 할 일은 단 하나 밖에 없습니다.  어느 칼럼에 대한 예측 모델을 만드느냐에 대한 선택입니다.  여기서는 당연히 charges 칼럼을 택합니다.





8) 추가로 선택하실 수 있는 메뉴는 중앙 하단의 3개의 라디오 다이얼입니다.  각각의 의미와 강약 조절은 아래와 같습니다.   여기서는 default로 제시된 8-3-8을 그대로 적용하겠습니다.



Accuracy : 어떤 알고리즘들을 몇 개나 적용할지 정합니다.  물론 다이얼 숫자가 높을 수록 더 많은 알고리즘을 적용합니다.
Time : 머신러닝에서 반복 훈련, 즉 iteration을 몇 회나 수행할지 정합니다.  물론 다이얼 숫자가 높을 수록 더 많은 회수가 적용됩니다.
Interpretability : 머신러닝으로 만들어진 모델에 대한 해석의 강도 조절 부분입니다.  다이얼 숫자가 높을 수록 더 단순화해서 해석해줍니다.


9) Launch를 누르면 자동 모델 생성이 시작되고 모델이 training 되는 과정을 보시게 됩니다.  중앙 상단을 보면 그 단계에서 하고 있는 작업과 적용되는 알고리즘 등이 실시간으로 업데이트 되면서 보여집니다.  중앙 하단에는 그 시점까지의 분석 단계에서 판단할 때 가장 중요한 변수/feature, 즉 입력된 dataset의 칼럼 중 어느 칼럼이 가장 중요한 역할을 하더라는 것이 실시간으로 분석되어 보여집니다.   가령 3% 경과된 시점에서는 LIGHTGBM 알고리즘을 처리 중이고, 흡연여부-비만지수-나이 순으로 병원비에 중요한 영향을 끼친다고 나옵니다. 






10) 그러나 auto feature engineering이 본격적으로 시작되면서 경과%가 진행되면서 그 값들은 계속 변화합니다.  가령 79% 경과 진행 중일 때는 무려 497개의 feature에 대해 1582개의 model에 대해서 평가 중이라고 나오지요.  원래 dataset의 칼럼 수, 즉 feature 수가 7개 밖에 없었다는 점을 생각하면 H2O DAI가 정말 다양한 조합의 feature engineering을 자동으로 수행하고 있다는 점을 아실 수 있습니다.  그 결과로 나오는 중앙 하단의 'Variable Importance', 즉 어떤 변수/feature가 병원비 지출액에 가장 중요한 영향을 끼치더라는 점도 비만도와 성별, 그리고 흡연여부가 결합되어 새로 생성된 변수를 가장 중요시하는 것을 보실 수 있습니다.  그 항목들을 자세히 보시면, 정말 모든 경우에 흡연여부가 가장 중요한 영향을 끼친다는 것을 보실 수 있습니다.  흡연인 여러분, 아무래도 담배는 끊으셔야 할 것 같습니다.



11) 모델 생성이 완료되면 우측 하단에 요약 설명이 나옵니다.  그러나 가장 중요한 것은 중앙 상단 메뉴의 3번쨰 항목, 즉 'SCORE ON ANOTHER DATASET' 입니다.  여기에 우리가 원하는 charges 값을 뺀 다른 값들 (연령, 사는 곳, 성별, 흡연 여부 등)이 들어있는 표를 입력하면, 해당 사람들이 얼마나 병원비를 쓸지 예측한 값을 출력해주거든요.   여기서는 미리 입력해둔 insurance_test.xlsx를 test dataset으로 선택하겠습니다.  그러면 곧장 해당 사람들의 병원비(charges) 값을 예측하여 그 결과를 csv 파일로 download 시켜줍니다.





12) 그렇게 해서 얻은 해당 환자들의 예상 병원비와 실제 병원비의 결과는 아래 그래프와 같습니다.  파란 곡선이 실제값이고, 오렌지색 곡선이 H2O DAI가 예측한 값입니다.  놀랍도록 잘 맞춘 것을 보실 수 있습니다.   다만 중간 정도에 H2O DAI는 7천4백불 정도를 예상했는데 실제로는 2만8천불을 사용하여 H2O DAI의 예상이 크게 틀린 환자가 있습니다.  이 환자의 상태를 보면, BMI 지수가 높은 비흡연자입니다.  아마도 H2O DAI가 만든 모델에서는 BMI 지수는 그다지 중요하지 않고 흡연 여부가 가장 중요했는데, 이 환자의 경우는 그 예측이 빗나간 것 같습니다.



13) 위에서 BMI 지수니 흡연여부니 하는 것은 어디까지나 저 개인의 짐작에 불과할 뿐 수학적인 모델로 계산한 결과는 아닙니다.  왜 이 머신러닝 모델이 이런 예측값을 내놓았는지 해석하는 것이 바로 MLI (Machine Learning Interpretation)입니다.  H2O는 K-LIME과 Decision Tree, Random Forest 등 다양한 MLI 기능을 제공합니다.  그런 MLI는 모델 생성 완료시의 메뉴 맨 상단의 'Interpret This Model'을 클릭함으로써 생성할 수 있습니다. 



14) 이런 MLI 해석 결과도 어느 정도 data science에 대한 소양이 있어야 볼 수 있는 것이 사실입니다.  가령 LIME이 무엇인지 알아야 이해를 할 수 있으니까요.  (참고로 LIME은 Locally Interpretable Model-agnostic Explainations을 뜻하는 말로서, 어떤 모델을 생성할 때 사용된 변수 값을 하나씩 바꿔보고 그 모델의 결과에 얼마나 변화가 생기는지 봄으로써 어느 변수가 가장 중요한 역할을 하는지 해석하는 기법입니다.)  하지만 H2O DAI는 일반인들도 이해하기 쉬운 설명도 제시합니다.





15) 가령 Summary 부분의 맨 아래는 원래 dataset의 칼럼 중에서 어느 칼럼이 가장 중요한 역할을 하는지 보여줍니다. 



16) KLIME에서는 각각의 예측값에 대해, 어떤 변수가 어느 정도의 영향을 끼쳤는지를 수식화해서 보여줍니다.



17) 가장 쉬운 설명은 KLIME 메뉴 중 중앙상단의 'Explanations' 버튼을 클릭하면 볼 수 있습니다.   여기서는 흡연여부, BMI 지수 등의 변수의 증감에 따라 우리가 알고자 하는 target (여기서는 병원비)의 증감이 어떻게 변화하는지 최대한 단순화하여 제시합니다.  여기에 제시된 설명에 따르면 흡연여부가 가장 중요하고, 자녀가 있는지 여부가 그 다음이며, 사는 곳이 어디인지도 꽤 큰 영향을 미치는 것 같습니다.  아마 부유한 동네인지 또는 그 지방의 식습관 등이 영향을 주는 것일까요 ?  왜 그런지 모르겠습니다만 이 예측 모델에서는 의외로 BMI 지수, 즉 비만 여부는 상대적으로 그다지 큰 영향을 주지는 않는다고 판단하고 있습니다.



이 포스팅의 결론은 다음과 같습니다.

1. H2O DAI는 무척 정확한 예측 모델을 정말 쉽게 만들어낼 수 있을 뿐만 아니라, 왜 그런 예측을 했는지도 매우 쉽게 풀어서 설명해줍니다.  
2. 흡연자 여러분, 금연 합시다.