시작하기전 정품 비트세이버가 설치 되어있어야지 설치가 가능하다.

 

비트세이버 커스텀 곡을 플레이 해보고 싶다면 BMBF를 반드시 설치를 해야하는데 이 apk를 어떻게 설치를 해야할지가 좀 막막했다.

 

핸드폰이면 그냥 apk다운받아서 설치하면 되지만 오큘러스는 그리 쉽게 허락을 하지 않았으니;;

 

알아보니 여러가지 방법이 있었고 그 중에서 sideloader로 오큘러스에 apk를 설치하는 방법이 있어서 이를 활용해보려고 한다.

 

1. sideloader를 다운받기 위해서 간단한 양식을 작성한다.

headjack.io/tutorial/sideload-install-app-apk-oculus-go-quest/#tool

 

How to Sideload Apps on Oculus Go & Quest + FREE sideloading tool

This article explains three ways to install APKs on an Oculus Go / Quest, and also includes a FREE sideloader tool to make your life easier.

headjack.io

위 사이트에 들어가서 이름하고 이메일을 작성하고 SEND ME THE TOOL을 누르면 confirm메일이 오고 confirm을 하면 다운로드 링크가 담긴 메일이 하나 더 온다. (메일이 안왔으면 스팸이나 프로모션 항목을 확인해보면 있다.)

 

다운로드받고 압축을 풀고 실행을 하면 셋업이 진행되고 그 동안 스텝 2를 진행한다.

 

2. BMBF를 다운로드한다. (BMBF는 불법이라서 자동 업데이트가 안된다, 만약 업데이트를 하고 싶다면 기존의 버전을 삭제하고 새로운 버전을 다시 다운로드해서 설치하는 방법을 사용해야한다.)

bmbf.dev/stable

 

BMBF Stable Releases

Update to Beat Saber 1.12.1 and 1.12.2! Lots of changes in this update, with more to come... What's new?: Modloader updates Better game detection (should solve some com.beatgames.beatsaber-1 issues, or failure to recognize that the game has been uninstalle

bmbf.dev

위 사이트에서 BMBF 안정된 버전의 apk를 다운로드 한다.

 

3. 오큘러스 개발자모드 활성화

오큘러스 앱을 설치한 핸드폰에서 쉽게 설정이 가능하다. (같은 와이파이 사용해야지 설정이 가능함)

앱을켜고 -> 설정(맨 하단 우측) -> 연결된 오큘러스 디바이스 클릭 -> 그 외 설정 클릭 -> 개발자모드 클릭 및 활성화

 

4. 오큘러스의 USB 디버깅 허용 및 파일 엑세스 허용 그리고 인스톨

sideloader가 다 셋업이 된것 같다면 USB로 오큘러스를 연결하고 USB 디버깅 허용 및 파일 엑세스 허용을 하고(오큘러스를 착용하고 허용해야 함) 다 되었으면 컴퓨터로 돌아가 다운 받은 apk를 드래그 및 드롭을 해서 인스톨을 진행한다.

 

마지막으로 오큘러스를 쓰고 메뉴판에서 을 클릭하고 맨 상단 오른쪽에 알수없는 출처라고 적힌 항목을 클릭해서 설치하면 된다.

'취미' 카테고리의 다른 글

2021년 4월 2일 NHK 뉴스 번역  (0) 2021.04.03
2021년 4월 1일 NHK 뉴스 번역  (0) 2021.04.01
2021년 3월 31일 NHK 뉴스 번역  (0) 2021.03.31
2021년 3월 30일 NHK 뉴스 번역  (0) 2021.03.31
2021년 3월 29일 NHK 뉴스 번역  (0) 2021.03.31

이글은 반복되는 Ubuntu 세팅 및 CUDA 설치가 번거로워 한번에 모아보기 위해 참고용으로 작성하였다.

 

주의, Nvidia 드라이버를 따로 설치하지 말고 GUI 사용자는 1번 항목을 따라하지 말고 개별 1. 항목을 따라야한다.

 

1. GUI 기능 끄기(옵션)

$ sudo systemctl set-default multi-user

 

개별 1. Nouveau 비활성화 및 재부팅[1]

$ sudo bash -c "echo blacklist nouveau > /etc/modprobe.d/blacklist-nvidia-nouveau.conf"
$ sudo bash -c "echo options nouveau modeset=0 >> /etc/modprobe.d/blacklist-nvidia-nouveau.conf"
$ sudo reboot now

 

2. 패키지 추가 및 업데이트, CUDA 설치 그리고 재부팅[2]

$ wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2004/x86_64/cuda-ubuntu2004.pin
$ sudo mv cuda-ubuntu2004.pin /etc/apt/preferences.d/cuda-repository-pin-600
$ wget http://developer.download.nvidia.com/compute/cuda/11.0.2/local_installers/cuda-repo-ubuntu2004-11-0-local_11.0.2-450.51.05-1_amd64.deb
$ sudo dpkg -i cuda-repo-ubuntu2004-11-0-local_11.0.2-450.51.05-1_amd64.deb
$ sudo apt-key add /var/cuda-repo-ubuntu2004-11-0-local/7fa2af80.pub
$ sudo apt-get update
$ sudo apt-get -y install cuda
$ sudo reboot now

 

 

그림 1. 과 같이 nvidia-smi를 입력해 잘 나오는지 확인한다.

 

그림1. CUDA설치후 CUDA버전 및 GPU가 잘 잡히는지 nvidia-smi로 확인할 수 있다.

 

3. 아나콘다 설치 및 파이토치 설치[3, 4]

# 아나콘다 설치(설치 마지막 물음인 conda init 항목은 yes로 해야한다.)
$ wget https://repo.anaconda.com/archive/Anaconda3-2020.11-Linux-x86_64.sh
$ chmod +x ./Anaconda3-2020.11-Linux-x86_64.sh
$ ./Anaconda3-2020.11-Linux-x86_64.sh
$ source .bashrc

# 만약 아나콘다 설치중 마지막 conda init 물음에 no로 답한 경우만 진행
$ ./anaconda3/bin/conda init
$ source .bashrc

# 파이토치 설치
$ conda install pytorch torchvision torchaudio cudatoolkit=11.0 -c pytorch

 

 

최종적으로 파이토치에서 GPU사용가능 여부를 확인한다.

$ python
>>> import torch
>>> torch.cuda.is_available()

 

참고문헌

1. How to disable/blacklist Nouveau nvidia driver on Ubuntu 20.04 Focal Fossa Linux, Available Online: linuxconfig.org/how-to-disable-blacklist-nouveau-nvidia-driver-on-ubuntu-20-04-focal-fossa-linux 15 Feb 2021.

2. CUDA Tollkit 11.0 Download, Available Online: developer.nvidia.com/cuda-11.0-download-archive 15 Feb 2021.

3. Anaconda Individual Edition Installer, Available Online: www.anaconda.com/products/individual 15 Feb 2021.

4. Pytorch Get Start Locally, Available Online: pytorch.org/get-started/locally/ 15 Feb 2021.

처음에는 당황했으나 아래 메세지를 읽어보니 힌트를 얻을 수 있었다.

 

Tell CMake where to find the compiler by setting either the environment
variable "CUDACXX" or the CMake cache entry CMAKE_CUDA_COMPILER to the full
path to the compiler, or to the compiler name if it is in the PATH.

 

cmake가 쿠다 컴파일러를 찾지 못해서 발생한는 에러로 [1]을 참고해 아래와 같이 쿠다 경로만 지정해 주면 끝난다.

 

export CUDA_HOME=/usr/local/cuda 
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/cuda/lib64:/usr/local/cuda/extras/CUPTI/lib64 
export PATH=$PATH:$CUDA_HOME/bin

 

쿠다가 여러개 깔려있다면 위의 경로말고 원하는 쿠다버전 경로로 설정해야한다. 그렇지 않으면 최근에 깔린 버전이 걸린다.

 

참고문헌

1. No CMAKE_CUDA_COMPILER could be found, Available online: github.com/jetsonhacks/buildLibrealsense2TX/issues/13 24 Dec 2020.

PCIe ssd하고 SATA ssd 두개를 혼합해서 사용하다가 SATA ssd를 1개 더 추가해서 RAID로 묶어서 사용하려고 했다.

그런데 BIOS에서 묶는데는 성공했으나 ubuntu installation 화면에서 PCIe ssd가 안잡히는 일이 발생하였다.

 

슬롯 문제인가 했는데 아니였다.

 

계속 삽질하다가 우연히 나랑 비슷한 일을 겪은 사람의 글[1]을 발견하고 힌트를 얻어 RAID를 사용하기 위해서 켜놓은 intel rapid storage technology 기능을 혹시나 해서 꺼봤더니 되었다.

 

참고문헌

1. M.2 Samsung SM951 NVME SSD Not Recognized on Linux, Avaiable online: superuser.com/questions/1022849/m-2-samsung-sm951-nvme-ssd-not-recognized-on-linux 24 Dec 2020.

SSH로만 접속해서 GUI를 사용하지 않는데 켤 때 마다 GPU를 조금 잡아먹음(14MB) 눈에 거슬려서 다음과 같이 함

 

끄기

$ sudo systemctl set-default multi-user

켜기

$ sudo systemctl set-default graphical

 

임차권등기명령 신청전 나의 상황은 아래와 같다.

신청날짜: 2020.12.07 (계약 해지일(2020.12.06) 이후에(2020.12.07 부터) 신청이 가능하다.)

계약기간: 2018.12.07 ~ 2020.12.06

보증금: 이억이천삼오백만원

소명자료: 녹취록(사용안함), 의사표시 공시송달(단, 공시송달 확정일이 계약 해지일(2020.12.06)로부터 최소 1개월 전(최소 2020.11.06 이전에 확정이 되어야함) 이여야지 인정이 됨)

주택도시공사 전세보증에 가입된 상태(이거 없었으면 답이 없었을수도...)

 

사건내용은 이렇다.

약 2020.08.15쯤(확실하지 않음) 임대인에게 계약해지를 통보하기 위해 임대인에게 전화를 했지만, 전화에 응하지 않았다. 그 뒤 몇번 더 시도를 했지만 역시 전화를 받지 않았으며 어쩔 수 없이 내용증명을 우편으로 임대인 주소지로 전달하였는데, 반송이 되었다. 처음에는 주소가 잘못 되었나 생각했는데 집배원의 말에 의하면 집에 개소리가 들렸고 사람이 없는 집은 아닌것 같다고 했다. 그래서 반송된 내용증명을 바탕으로 의사표시 공시송달을 신청하였으며 그 후 공시송달(공시송달은 법무사를 통해서 신청을 하였다.)이 끝나기 전에 다행이 임대인이랑 연락이 되어서 급하게 녹취를 진행하였다. (임대인이 못 믿겨워서 공시송달은 그냥 두었다...) 임대인 사정을 들어보니 코로나때문에 임대사업이 망했다나 뭐라나... 그래서 빚이좀 있어서 연락을 잘 안받고 도망다니는? 신세로 보였다;; 아무튼 이런저런 말을 하는데 결론은 돈이 없어서 보증금을 못 돌려주겠다는 거고... 하지만 다행이 주택도시공사 전세보증에 가입이 된 상태이고, 보증금을 받으려면 진행절차 중 가장 중요한 임차권등기명령을 신청해야 한다고 해서 이렇게 신청하기에 이르게 되었다. (살면서 이런일도 다 있더라...)

 

처음에는 인터넷으로 신청을 하려고 했으나 집에 프린터기, 스캐너(사진으로 찍으면 되지만 제일 중요한 문서출력이 안된다.)도 없고 이상하게 전사소송사이트를 접속하려고 하면 보안시스템이 충돌나는지 보안프로그램을 설치해도 계속 문제가 생겨서 그냥 직접 지방법원에 가서 서류를 작성하기로 마음먹었다...

 

처음에는 복잡할 줄 알았지만 1시간 내로 금방 할 수 있는 내용이고 인터넷으로 혼자 모르는 용어랑 시름하는 것 보다는 직원에게 물어봐서 정확하고 빠르게 진행을 할 수 있어서 인터넷보다는 그냥 시간좀 내서 관할 지방법원에 찾아가는게 더 좋다고 생각한다. (물론 돈만있으면 가장 좋은건 법무사에게 맏기면 되지만...)

 

준비해야할 서류는 다음과 같다.

1. 등본 또는 초본(주소가 나와야함)

2. 부동산 등기부등본(이건 법원가서 해도되고 아니면 동사무소 또는 인터넷 또는 무인기기에서 출력이 가능하다.)

3. 임대차계약서

4. 소명자료(나의경우 공시송달관련 자료를 첨부함)

5. 신분증

 

이정도면 되고 나머지는 직접가서 펜으로 작성하면 된다. 작성하는 항목도 어렵지않고 모르면 그냥 물어보면 된다. 그리고 등록세, 송달료등 결제가 필요하기 때문에 5만원 정도 적당히 준비해서 가면 된다.

 

신청에는 무리가 없었고(법원거리가 멀어서 좀 고생했지만...) 다른 게시글을 보니깐 도면을 첨부하는 사람도 있던데 도면은 필수가 아니라 선택이라서 없어도 상관 없다고 한다. 그리고 처음에는 공시송달처럼 법무사에게 맞기려고 했는데 가격이 좀 생각보다 비싸서;; 막상해보면 그 가격이 나올리가 없는데,,, 이번일로 다음에 비슷한 일이 터지면 그냥 직접하는게 좋다고 생각한다.

 

추가로 주택보증공사에서는 계약일이 끝나고 1개월뒤 보증금을 못받을 때 보증사고로 본다고 하는데 이때 법원에서 온 임차권등기명령 서류를 가지고 있다가 1개월 뒤 이행청구를 진행하면 된다고 한다.

 

추가로 신청을하고 하루정도 지난다음 나의 사건검색 에서 등기명령 신청후 법원에서 받은 사건번호를 검색하면 접수가 잘 되었는지 확인이 가능하다. 사건번호를 잊어버렸다면 송달료를 결제한 영수증에 있는 은행번호로 송달료 조회 로 사건번호를 찾을 수 있다.

'기타' 카테고리의 다른 글

마취 없이 손톱 제거 후기  (0) 2021.02.18

코사인 유사도(cosine similarity)는 두 벡터간의 방향 유사도를 나타내며 코사인 값으로 -1 ~ 1 사이의 값이 나온다.

1에 가깝다면 두 벡터는 같은 방향을 바라보고 있다는 의미이고 0에 가까우면 두 벡터는 직교 그리고 -1에 가까우면 두 벡터는 반대 방향을 바라보고 있다는 의미가 된다.

 

수식으로 살펴보면 아래와 같다.

$$similarity(V_{a}, V_{b}) = \frac{ V_{a} \cdot V_{b} }{ \|V_{a}\|_{2} \times \|V_{b}\|_{2} } = V_{a(normalized)} \cdot V_{b(normalized)}$$

 

계산을 진행 할 때는 맨 마지막 항 처럼 정규화된 두 벡터의 내적만 계산하면 되고, 이를 numpy를 사용하여 그대로 구현하면 아래와 같이 작성을 할 수 있다.

 

코드에는 eps를 사용하여 만약 L2 norm 값이 1e-12보다 작은 경우(사실 원래 목적은 0이 되는 걸 방지하려고 넣은거임)를 제거하기 위해서 추가하였다.

 

사실 pytorch나 scikit-learn에 있는 코사인 유사도를 사용하면 편하지만, numpy로 구현한 이유는 속도 측면에서 이득이 있기 때문에 이렇게 구현했다. 간단하게 scikit-learn과 numpy를 비교한 결과는 아래 그림1과 같다.

 

그림1 어레이 크기에 따른 scikit-learn과 numpy의 간단한 속도 비교결과

 

비교에 각 2차원 어레이를 사용하였다. 예로 가로축 값이 10이면 10x10 행렬을 계산에 사용했다는 의미가 되며 세로축은 해당 행렬을 계산하는데 걸린 시간을 의미한다.

 

실험을 진행한 코드는 아래와 같다.

결론은 큰 차이를 보기 힘들엇지만 시간이 중요하다면 이렇게 만들어서 사용하는 것도 괜찮을 것 같다.

지금 쓰고있는 내용은 [1]에서 발생하는 노트북 문제에 대해서 서술하는 내용이다. 처음 제작할때는 pyspark를 고려하지 않았다.

 

jupyter에서 pyspark를 처음사용할때 그냥 !pip install pyspark만 하면 끝나는줄 알았지만 작동구조상 버전에 맞지않게 설치하게되면 작동이 그림 1 처럼 안된다..(그냥 설치하면 pyspark 3.0.1(최신버전)로 설치됨을 확인했다.)

 

그림 1. jupyter에서는 그냥 pip 로 설치해서 바로 사용이 안된다.

해결방법은 내가 알고있는 선에서는 2가지 있다. 버전을 맞추거나 그래도 안되면 스파크파일 내부에 setup.py가 있는데 이로 설치를 진행하면 된다.

 

1. 버전에 맞게 설치

큰 문제는 버전이 맞지 않기 때문이며 그림 2 처럼 버전을 맞게 설치하면 대부분 해결된다.

그림 2. 버전에 맞게 설치하면 의외로 간단히 해결된다.

2. setup.py로 설치

사실 pip 패키지 배포에 문제가 없는 이상 대부분 잘 작동이 되겠지만 혹시 모르니,, 안되면 spark 바이너리를 다운받으면 내부에 보통 python 디렉토리에 파이썬 설치파일이 들어있다. 이를 이용해서 그림 3 처럼 설치하면 깔끔하게 설치가 가능하다.

그림 3. pyspark 설치를 진행하기전 설치 명령어를 보여준다.
그림 4. !pip 과정 없이 바로 실행이 가능하다.

비교적 간단한 내용이지만 나중에 또 시간 낭비할까봐 메모로 남겨둔다.

 

참고문헌

1. Available online: github.com/titania7777/SparkNotebook 13 Oct 2020.

이 글은 ray 도큐먼트(document)[1]를 바탕으로 요약 정리 및 코드 실행 결과를 적어놓은 글이다.

 

ray 프레임워크(framework)는 분산 어플리케이션을 구축할 수 있도록 도와주는 API이다. 내가 ray를 공부하기 시작한 이유는 당연히 분산처리를 해야할 데이터가 생겼기 때문이다. 분산처리 프레임워크로 윈도우에서는 현재 이슈가 좀 있지만 공식적으로 윈도우도 지원하며 언어는 파이썬과 자바를 지원한다.

 

분산처리를 도와주는 프레임워크이기에 분산처리를 이용할 수 있는 곳이면 어디든지 사용이 가능하다 예로

  1. 하이퍼파라메터(hyperparameter)를 튜닝할때 그리드 서치(grid serach)를 이용한다고 가정 한다면 찾고자 하는 값의 범위나 모델의 크기에 따라서 다르지만 보통 많은 시간을 투자해야한다. 이때 병렬로 처리를 하면 무척 빠르게 값을 찾는 게 가능할 것이다[2].

  2. 강화학습(reinforcement learning)에서는 설정한 환경에 따라서 많은 탐색(exploration)을 해야하는 경우가 있고 때에따라 보상(rewad)을(를) 제대로 받지 못할 수도 있다. (주로 상황에따른 보상을 제대로 설정하지 않아서 의도치않은 상황이 발생하는 경우도 있다.) 그러면 학습속도가 굉장히 느려지는 경우가 발생하는데 이때 조금 억지스럽지만 환경 및 액션 설정들을 바꾸기가 힘들고 이대로 학습을 계속 진행해야 하는 상황 이라면 A3C같은 병렬처리 강화학습 알고리즘을 고려할 수 있다.

  3. tensorflow 나 pytorch로 모델을 만들고 학습을 진행할때도 병렬로 학습을 진행할수도 있다. 이경우 만약 그래픽카드가 한컴퓨터에 여러개 붙어있는 경우라면 유명한 apex[3]를 사용해 GPU를 효율적으로 활용 할 수도 있지만 여러 컴퓨터가 물리적으로 분리가 되어있는 상황에서 ray를 활용하면 여러 컴퓨터에서 병렬처리를 할 수가 있다.

  4. tensorflow나 pytorch로 모델을 만들었다면 이제 서빙(serving)을 해야한다. 이때도 ray를 활용하여 병렬적으로 처리를 진행할 수도 있다. 아니면 상황에 따라서 도커를 이용해 컨테이너화를 진행하고 오케스트레이션을 통해서 진행하는 방법도 있다.

일반적으로 ray를 사용한다면 다음 6가지 함수를 기억하고 넘어가면 좋다.

 

  1. ray.init()
    => ray 컨텍스트(context) 초기화를 진행한다.
  2. @ray.remote
    => 병렬처리를 위한 ray만의 파이썬 데코레이터(decorator)로 기본적으로 함수에 붙여서 사용하며 클래스(class)에 붙여서 사용하면 액터(actor)라고 부른다.
  3. .remote()
    => @ray.remote 데코레이터를 붙였다면 언제든지 호출을 할수가 있으며 .remote()를 호출한 함수에 인자(argument)를 던져줄때 .remote()에 대신 던져준다.
  4. ray.put()
    => 오브젝트 저장소(object store)에 받은 인자값을 저장하며 이때 오브젝트의 특정한 ID값을 던져준다. 이 기능은 같은 인자를 반복적으로 넘길때 오버헤드를 줄여주는 특별한 기능을한다.
  5. ray.get()
    => 오브젝트의 ID값에 해당하는 값을 돌려준다. 이 함수가 호출될 때 비로소 분산처리가 시작되며 연속적으로(sequential) ray.get()을 지정했다면 선 ray.get() 작업이 끝날때 까지 뒤 작업들은 기다리게 된다.
  6. ray.wait()
    => .remote()로 지정된 오브젝트들 중에서 준비가 된 오브젝트의 ID를 돌려준다.

*지금부터 시작할 모든 실습은 모두 도커에서 진행하였다.

팁 1: ray.get의 사용의 주의

ray.get()을 잘못 사용하는 경우 발생할 수 있는 문제에 대해서 다룬다.

시작하기전 간단한 지연 함수를 만들어서 테스트를 해본다. 아래 코드1 은 파이썬의 지연함수 time.sleep(1)를 사용해서 do_some_work(x)를 부를때마다 1초 지연하는 코드이다.

# 코드 1
import time
from datetime import datetime

def do_some_work(x):
    time.sleep(1) # 1초 지연.
    return x

start = datetime.now()
results = [do_some_work(x) for x in range(4)]
print("duration =", datetime.now() - start)
print("results = ", results)

코드 1의 결과 대략 4초가 걸린다

코드 1의 결과를 보면 예상대로 대략 총 4초가 나왔다. 이제 ray를 통한 병렬처리로 시간을 단축해보겠다. 시작전 잘못된 사례를 살펴보겠다. 아래 코드 2는 ray.get()의 사용의 잘못된 예의 코드이다.

# 코드 2
import time
from datetime import datetime
import ray

ray.init() # ray 컨텍스트 초기화

@ray.remote
def do_some_work(x):
    time.sleep(1) # 1초 지연.
    return x

start = datetime.now()
results = [ray.get(do_some_work.remote(x)) for x in range(4)]
print("duration =", datetime.now() - start)
print("results = ", results)

코드 2의 결과 대략 4초가 걸린다(위의 오류는 도커에서 실행해서 발생한는 오류로 지금 진행할 내용들은 전부 단순 튜토리얼 이니 신경쓸필요 없다.)

코드 2의 결과는 코드 1의 결과랑 비슷함을 알수가 있다. 그러나 만약 병렬 처리를 하고싶다면 이런 결과는 원치 않을것 이다. 문제는 ray.get()을 호출할때 연속적으로 for문을 통해서 호출을 해준것이 문제이다. 이렇게 연속적으로 ray.get()을 호출하게 되면 나중에 호출된 ray.get()은 앞서 호출된 ray.get()의 작업이 끝날때 까지 기다리게 된다. 그래서 순차적으로 ray.get()을 호출하지말고 병렬처리하고 싶은 함수나 클래스에 .remote()를 불러주고 ray.get()은 한번만 호출한다고 생각하면 된다. 아래 코드 3이 올바른 ray.get()의 사용법이다.

# 코드 3
import time
from datetime import datetime
import ray

ray.init() # ray 컨텍스트 초기화

@ray.remote
def do_some_work(x):
    time.sleep(1) # 1초 지연.
    return x

start = datetime.now()
results = [do_some_work.remote(x) for x in range(4)]
results = ray.get(results) # ray.get()은 한번만 불러준다.
print("duration =", datetime.now() - start)
print("results = ", results)

코드 3의 결과 대략 1초가 걸린다.

코드 3의 결과를 보면 대략 1초안에 4초짜리 프로세스를 병렬로 진행하였다.

 

팁 2: 매우 작은 작업에는 ray는 오히려 독이된다.

ray는 기본적으로 분산처리를 위한 프레임워크이다. 이 말은 여러개의 프로세서들을 통제하기 위해서 스케줄링, 프로세스간 커뮤니케이션, 시스템 상태 업데이트등 많은 추가적인 작업이 들어간다. 그래서 만약 저 위해서 했던 간단한 작업은 1초짜리지만 0.1밀리세컨드로 줄인다면(해야할 작업이 ray의 준비 작업시간보다 빠르다면)이는 오버헤드가 걸렸다고 하며 옳지못한 결과를 보게 된다. 코드 4는 코드1의 1초 부분을 0.0001초로 바꾼 것 이다.

# 코드 4
import time
from datetime import datetime

def do_some_work(x):
    time.sleep(0.0001) # 0.1밀리세컨드 지연.
    return x

start = datetime.now()
results = [do_some_work(x) for x in range(4)]
print("duration =", datetime.now() - start)
print("results = ", results)

코드 4의 결과 0.6밀리세컨드가 걸린다.

코드 4의 결과를 보면 실행에 대략 0.6밀리세컨드가 걸렸다. 과연 이 작업을 ray를 이용해 병렬로 처리할때 더 빠르게 처리를 할 수 있을까? 코드 5는 코드 3의 1초 지연을 0.0001초로 바꾼 것 이다.

# 코드 5
import time
from datetime import datetime
import ray

ray.init() # ray 컨텍스트 초기화

@ray.remote
def do_some_work(x):
    time.sleep(0.0001) # 0.1밀리세컨드 지연.
    return x

start = datetime.now()
results = [do_some_work.remote(x) for x in range(4)]
results = ray.get(results) # ray.get()은 한번만 불러준다.
print("duration =", datetime.now() - start)
print("results = ", results)

코드 5의 결과 대략 19.3밀리세컨드가 걸린다.

코드 5의 결과를 보면 실행에 대략 19.3밀리세컨드로 오히려 더 오래걸린다. 이 처럼 가벼운 작업에 있어서는 그냥 ray없이 그냥 사용하는 편이 더 나을수도 있다.

 

팁 3: 같은 오브젝트를 .remote()에 반복해서 넘길때는 ray.put()을 명시적으로 사용하자.

병렬처리를 하는데 있어서 같은 오브젝트를 동시에 실행하고 싶다고 가정 해본다. 그러면 자연스럽게 처리에 사용할 오브젝트를 복사해서 동시에 실행해야 되지 않을까 하는데 쓰는 작업이 있다면 모를까 읽기 작업에 있어서는 사용할 오브젝트를 복사해서 전달해줄 필요가 전혀없고 하나의 오브젝트만 전달해서 공유해 사용을 할수가 있다. 이때 ray.put()이 힘을 발휘한다. 코드 6은 numpy로 만든 비교적 큰 오브젝트를 연속해서 넘기고 있다.

# 코드 6
from datetime import datetime
import numpy as np
import ray

ray.init() # ray 컨텍스트 초기화

@ray.remote
def no_work(x):
    return

start = datetime.now()
x = np.zeros((5000, 5000))
results = [no_work.remote(x) for x in range(20)]
results = ray.get(results)
print("duration =", datetime.now() - start)

코드 6의 결과 대략 2초가 걸린다.

일반적으로 코드 6과 같이 작성을 하면 ray는 내부적으로 ray.put()을 여러번 부르게 되고 병렬처리에 있어서 오브젝트를 계속 복사하는데 많은 시간을 사용하게된다. 이때 이를 방지하기 위해서 코드 7과 같이 명시적으로 ray.put()을 한번만 호출하여 리턴된 오브젝트 ID값을 .remote()의 인자로 넘겨주면 된다.

# 코드 7
from datetime import datetime
import numpy as np
import ray

ray.init() # ray 컨텍스트 초기화

@ray.remote
def no_work(x):
    return

start = datetime.now()
x = ray.put(np.zeros((5000, 5000))) # 오브젝트 ID x를 .remote()에 넘긴다.
results = [no_work.remote(x) for x in range(20)]
results = ray.get(results)
print("duration =", datetime.now() - start)

코드 7의 결과 대략 89.8밀리세컨드가 걸린다.

코드 7에서 단순히 명시적으로 ray.put()을 호출해준것 밖에 없는데 확실히 성능이 눈에띄게 좋아졌다.

 

팁 4: ray.wait()을 적극 활용해 병렬 파이프라인 처리의 특징을 최대한 활용하자.

팁 1 에서는 모든 프로세스가 같은 처리 시간을 갖는다고 가정을 했고 ray.get()을 한뒤 그 후 처리에 있어서는 언급을 안했다. 만약 모든 프로세스가 다른 처리 시간을 갖는다고 가정하면 팁 1에서는 빠르게 동작 할지라도 마지막 가장 늦은 프로세스가 끝날때 까지는 기다려야 한다. 그후 값을 돌려받고 다음 처리를 진행하게 되는데 이때 처리가 빨리 끝나는 프로세스값을 먼저 받아서 먼저 처리를 하면 그 성능을 더욱 극대화 할수가 있다. 빨래를 3번 걸쳐서 진행한다고 할 때 첫 번째 세탁물의 세탁이 끝나고 건조 중일 때 다음 세탁물은 이전 세탁물의 건조가 끝날 때 까지 기다 지리 않고 계속해서 세탁을 계속 진행할 수가 있듯이 말이다. 이 과정에서 누가 먼저 끝났는지 알기 위해서 ray.wait()을 사용한다. 먼저 코드 8은 연속균등분포(uniform distribution)에서 0 ~ 4 사이 랜덤으로 샘플링해 지연을 한다. 그리고 병렬 파이프라인 처리 활용의 효과를 보이기 그 뒤 지연 작업인 process_results를 추가로 넣는다.

# 코드 8
from datetime import datetime
import time
import random
import ray

ray.init()

@ray.remote
def do_some_work(x):
    time.sleep(random.uniform(0, 4)) # 0 ~ 4초 사이 램덤으로 지연
    return x

def process_results(results):
    sum = 0
    for x in results:
        time.sleep(1)
        sum += x
    return sum

start = datetime.now()
datas = ray.get([do_some_work.remote(x) for x in range(10)]) # 이 작업은 대략 4초 안으로 걸린다.
results = process_results(datas) # 이 작업은 대략 10초 정도 걸린다.
print("duration = ", datetime.now() - start)
print("results = ", results)

코드 8의 결과 대략 13초가 걸린다.

코드 8의 결과는 do_some_work의 4초 안으로 걸리는 결과와 process_results의 10초 정도 걸리는 결과를 생각해 볼때 대략 13초 정도가 나온다. 하지만 이 결과는 최선의 결과가 아니다. 왜냐하면 do_some_work가 전부 4초대를 내놓는 작업이 아니라 1초보다 빠른 작업을 내놓는 작업이 있을수도 있다. 그러면 우리가 할 일은 단순 합을 구하는 작업이니 모든 작업이 끝날때까지 기다릴 필요가 전혀없고 끝난 프로세스먼저 결과를 가져와 더하면 된다. process_results는 1초 지연 작업이 있기에 이는 현명한 방법이다. 이를 위해서 코드 9처럼 누가 먼저 끝났는지 ray.wait()으로 수시로 확인을하고 값을 가져오고 처리하면 된다.

# 코드 9
from datetime import datetime
import time
import random
import ray

ray.init()

@ray.remote
def do_some_work(x):
    time.sleep(random.uniform(0, 4)) # 0 ~ 4초 사이 램덤으로 지연
    return x

def process_results(sum, result):
    time.sleep(1)
    sum += result
    return sum

start = datetime.now()
datas = [do_some_work.remote(x) for x in range(10)]
sum = 0
while len(datas):
    done, datas = ray.wait(datas) # 다된 작업은 done으로 넘긴다.
    sum = process_results(sum, ray.get(done[0]))
print("duration = ", datetime.now() - start)
print("results = ", sum)

코드 9의 결과 대략 10초가 걸린다.

코드 8과 코드 9는 거의 같지만 코드 9처럼 먼저 끝나는 작업을 먼저 처리하는 방식이 더욱더 효율적임을 확인할 수 있다.

 

참고문헌

1. Tips for first-time users, Available online: docs.ray.io/en/master/auto_examples/tips-for-first-time.html 15 Sep 2020.

2. Tune Distributed Experiments, Available online: docs.ray.io/en/master/tune/tutorials/tune-distributed.html#tune-distributed 15 Sep 2020.

3. NVIDIA apex GitHub Repository, Available online: github.com/NVIDIA/apex 15 Sep 2020.

요즘 윈도우에서 windows terminal 앱을 사용하니깐 너무 좋다. 추가로 vim만 있으면 터미널에서 바로 텍스트 편집이 가능하니 좋을 것 같다.

 

vim을 윈도우에 설치하려면 이곳 에서 최신버전의 설치파일을 다운받은 후 설치를 진행한다.

 

그리고 "윈도우키 + Pause" 를 누른후 고급 시스템 설정에 들어가 환경변수에 vim이 설치된 경로를 추가해준다.

 

환경변수에 vim 이 설치된 경로를 추가해준다.

 

그러면 이제 파워 셸(powershell) 에서 vim을 치면 vim을 사용할수 있고, 추가적으로 나는 우분투에서 vi를 쳐서 실행하는 습관 때문에 익숙하지 않아서 별칭(alias)을 추가로 설정하기로 한다.

 

그런데 New-Alias 또는 Set-Alias 는 새로운 세션의 터미널을 열때 적용이 되지 않았다. 이를 해결하기 위해서는 profile.ps1을 수정하면 된다[1]. 이 파일은 우분투 bash의 .bashrc 랑 비슷하다.

 

그래서 변수인 $profile을 확인하여 profile.ps1 파일 위치를 확인하고[2] vim 을 이용해서 즉석으로 수정한다.

 

vim을 이용해 profile.ps1을 수정한다.
profile.ps1을 수정한다. 이 파일은 .bashrc와 비슷하게 파워 셸 세션이 시작할 때 마다 자동으로 수행된다.

 

그리고 새로운 세션을 여고 vi를 입력해 잘 되는지 확인해 본다.

 

새로운 세션을 연 후 vi alias가 적용됨을 확인한다.

참고문헌

1. "How to create permanent PowerShell Aliases", Jul 2014, stackoverflow.com/questions/24914589/how-to-create-permanent-powershell-aliases

2. "Understanding the Six PowerShell Profiles", May 2012, web.archive.org/web/20121105003839/blogs.technet.com/b/heyscriptingguy/archive/2012/05/21/understanding-the-six-powershell-profiles.aspx

 

 

 

 

+ Recent posts