Gorio Tech Blog search

Pytorch를 위한 Docker 사용법(Pytorch 도커 사용법)

|

목차

이 글에서는 Pytorch Docker를 생성하고 실행하는 방법을 정리한다.

Ctrl + F로 원하는 명령어를 검색하면 좋다.


기본 설명

여러 개의 Python 프로젝트에 참여하다 보면 각 프로젝트에서 사용하는 Python과 라이브러리들의 버전이 다른 경우가 대부분이다. 그래서 많은 경우 가상환경(python venv 또는 conda 등)을 사용하여 각 프로젝트의 환경을 분리하고는 하는데, Python을 여러 버전을 설치하기 곤란한 경우나 환경을 완전히 분리하고 싶은 경우에는 Docker(도커)를 사용할 수 있다.

Docker는 간단히 Container 기반의 Open-Source 가상화 플랫폼 정도로 정의할 수 있다. Container는 외부와 격리된 공간(파일 통신이 가능하긴 하지만, 일단 넘어가자)이며 내부에서 프로세스를 수행할 수 있다.

Docker를 사용하는 것은 마치 윈도우에서 가상머신을 돌리는 것과 비슷하다. 사실상 완전히 분리된 환경으로 동작하며, 한 환경에 설치된 라이브러리나 프로그램이 다른 환경에 아무런 영향을 미치지 못한다. 두 환경 간의 통신은 지정된 명렁어를 통해서만 가능하다.
참고: 엄밀히 말해서 가상머신과는 다르다. 가상머신은 추가적인 OS를 설치하여 가상화하는 방법인데, 이러한 방식은 Docker에 비해 추가적인 비용이 더 들기 때문에 실제 프로젝트 환경에서 쓰기에는 부적절하다.

Docker의 기본 사용법은 다음과 같다.

  1. 필요한 세팅이 되어 있는 Docker Image를 인터넷에서 다운로드한다. 예: Pytorch Docker Image List
  2. 다운받은 Docker Image로 새 Container를 생성한다. (같은 이미지로 여러 Container를 생성할 수 있다.)
  3. 생성한 Container를 구동시키고(띄우고) 접속한다.
  4. 필요한 Python 라이브러리를 마저 설치하고 사용 가능!

즉, 이미지 다운 → Container 생성 → 사용 순서를 따른다. 참 쉽죠?


설치 및 다운로드

Docker 설치

최신 Ubuntu라면 기본으로 설치되어 있는 경우가 많은 것 같긴 한데… 아니더라도 걱정할 필요는 없다.

curl -fsSL https://get.docker.com/ | sudo sh

password를 입력하고 기다리면 설치가 완료될 것이다.

Ubuntu가 아니라면 WindowsMac을 참고해보자.

최소 19.03 이상의 버전으로 설치하면 된다.

TroubleShooting

이 부분은 위의 설치가 안 되는 환경에서 설치방법을 다룬다.
이전 버전의 docker가 존재해서 문제가 되는 경우가 있는데, 이것들을 삭제하고 재설치하는 방법을 알아본다.

참고로 이전 버전의 docker는 docker, docker.io, docker-engine, 최신 버전은 docker-ce라고 한다.

먼저 삭제를 진행하자.

sudo apt-get remove docker docker-engine docker.io containerd runc

다음 코드를 터미널에 순차적으로 입력하자.

sudo apt-get update
sudo apt-get install apt-transport-https ca-certificates curl gnupg-agent software-properties-common

sudo apt-get update
# Docker official GPG key 추가
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
# 결과: OK

sudo apt-key fingerprint 0EBFCD88

# 결과
pub   4096R/0EBFCD88 2017-02-22
      Key fingerprint = 9DC8 5822 9FC7 DD38 854A  E2D8 8D81 803C 0EBF CD88
uid                  Docker Release (CE deb) <docker@docker.com>
sub   4096R/F273FCD8 2017-02-22

docker repository를 추가하자.

sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"

ModuleNotFoundError: No module named 'apt_pkg' 에러가 뜨면 Python 기본 버전을 잠시 바꿔줬다가 해보자.

update-alternatives  --set python3  /usr/bin/python3.5
# 결과: update-alternatives: using /usr/bin/python3.5 to provide /usr/bin/python3 (python3) in manual mode

sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"

root@vicman2:/home/ywjang# update-alternatives  --set python3  /usr/bin/python3.6
# 결과: update-alternatives: using /usr/bin/python3.6 to provide /usr/bin/python3 (python3) in manual mode

경우에 따라 3.5 대신 다른 버전일 수 있다. sudo update-alternatives --config python3로 버전을 확인해보거나 기본값을 바꿔보자.

이제 설치를 진행하자.

sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io

특정 버전 설치는 apt-cache madison docker-ce로 버전을 확인 후 sudo apt-get install docker-ce= docker-ce-cli= containerd.io와 같이 설치하자.

설치 확인은 다음 hello_world를 실행해서 확인해보자.

sudo docker run hello-world

Nvidia Toolkit 설치

Container에서 GPU를 정상적으로 잘 사용하려면 nvidia toolkit를 설정해 주어야 한다.
아래 다섯 줄만 터미널에서 실행해 주자.

distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add -
curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | sudo tee /etc/apt/sources.list.d/nvidia-docker.list

sudo apt-get update && sudo apt-get install -y nvidia-container-toolkit
sudo systemctl restart docker

2번째 줄에서 OK가 출력되고, 3번째 줄에서 deb 어쩌구 하는 메시지가 여러 줄 나온다. 4번째는 update와 설치가 진행되고, 5번째 줄은 docker를 재시작한다.

Docker 권한 설정

Docker를 사용하려고 하면 root 권한이 (거의) 항상 필요하다. 매번 sudo를 입력하는 것은 상당히 귀찮기 때문에 현재 접속한 user에게 권한을 주자.

sudo usermod -aG docker $USER # 현재 접속중인 사용자에게 권한주기
sudo usermod -aG docker gorio # gorio 사용자에게 권한주기

재부팅하면 권한 설정이 완료된다.

sudo reboot

이제부터 docker를 쓸 때는 sudo docker 대신 docker라고만 해도 된다.

Docker Image 다운로드

사용할 수 있는 Docker Image를 찾으려면 다음 사이트를 확인하면 된다. 이미 다운받을 곳을 알고 있다면, 해당 사이트에서 진행하자.

# Pytorch 최신 버전의 Docker를 받고 싶으면 아래과 같이 하자.
docker pull pytorch/pytorch:latest
# 사실 아래처럼 써도 똑같은 이미지를 받을 수 있다. 기본 tag가 latest이기 때문.
docker pull pytorch/pytorch

# Tags 탭을 누르면 여러 버전의 Docker Image를 볼 수 있다. 원하는 버전을 받아 보자.
docker pull pytorch/pytorch:1.9.0-cuda10.2-cudnn7-runtime

이미지의 이름은 <Repository> : <Tag> 의 형식을 갖는다. pytorch/pytorch가 repository 이름이고, tag는 latest가 하나의 예시이다.

참고로 CUDA 버전에 맞는 PyTorch 버전을 포함하는 Docker Image를 다운받아야 한다. 여기여기를 참고하면 된다.

다운받은 Image 확인

Image를 다운받았으면, 어떤 Image를 받았는지 확인해보자. 지금까지 다운받은 모든 Image들이 표시된다.

docker images
# 결과
REPOSITORY        TAG                             IMAGE ID       CREATED        SIZE
pytorch/pytorch   1.9.0-cuda10.2-cudnn7-runtime   3850639cdf7a   5 days ago     4.42GB
pytorch/pytorch   latest                          5ffed6c83695   2 months ago   7.25GB

Image 삭제

docker rmi <image_id>

이미 해당 이미지로 생성한 컨테이너가 있다면 다음과 비슷한 에러가 뜨면서 삭제가 되지 않는다.

Error response from daemon: conflict: unable to delete bd58e1ea5cd2 (must be forced) 
- image is being used by stopped container fc69401afaf6

컨테이너를 전부 제거하고 이미지를 삭제하거나, 아예 컨테이너까지 강제 삭제하려면 다음과 같이 쓰면 된다.

docker rmi -f <image_id>

모든 image를 삭제하는 방법도 있다. 물론 복구는 되지 않는다.

docker rmi $(docker images -q)

None(untagged) Image 조회 및 삭제

docker를 빌드할 때 오류 등으로 완전히 진행되지 않으면 <none> image가 생성되기도 한다. 이를 조회하고 삭제하는 방법은 다음과 같다.

docker images -f "dangling=true" -q

검색된 id를 위의 Image 삭제 명령어로 실행해도 되지만, 한 번에 삭제하는 방법이 있다.

docker rmi $(docker images -f "dangling=true" -q)
# 해당 이미지로 이미 컨테이너가 생성되었다면 -f 옵션을 쓰자.
docker rmi -f $(docker images -f "dangling=true" -q)

삭제에 관한 조금 더 자세한 내용은 여기를 참조해도 좋을 것 같다.


Container 생성 및 실행

Container 실행하는 걸 Container를 띄운다고 표현하기도 한다.

우선 Container를 Image로부터 생성해보자.

Container 생성 및 실행

docker run -it --gpus all --name prj_gorio pytorch/pytorch:1.6.0-cuda10.1-cudnn7-devel /bin/bash
# 결과
root@fcdd07478fdf:/workspace# 

위의 결과는 Container를 만들고, /bin/bash가 바로 실행되어 Container 내부에서 터미널이 열려 있는 상태라고 생각하면 된다.

옵션을 살펴보자. Ubuntu를 좀 다뤄봤으면 대충만 봐도 알 수는 있겠지만.

Container 생성 옵션

위에서 사용한 옵션을 대략 설명하면 아래와 같다.

Option Description
-it Iterative Terminal. Container 종료 없이 탈출 가능.
–name, -n Container의 이름을 지정한다. 안 쓰면 nice_spence 같은 임의의 이름으로 생성된다.
–volume, -v Container와 공유할 디렉토리를 지정한다. -v <외부 Dir>:<Container Dir> 형식으로 쓴다. 파일 생성/수정/삭제가 동기화된다.
–gpus all Container 내부에서 GPU를 쓸 수 있도록 한다. nvidia toolkit이 설치되어 있어야 한다.
/bin/bash Container 생성 시 시작할 프로세스이다. bash의 설치 위치에 따라 적당히 변경하면 된다.

옵션은 순서 변경이 가능하지만, Image와 실행 프로세스는 마지막에 두자.

참고 19.03 이하 버전에서는 nvidia-docker 버전에 따라 아래처럼 사용한다. nvidia-docker v2에서는 --gpus all 대신 --runtime=nvidia를 사용한다. nvidia-docker v1은 --runtime=nvidia 또는 --gpus all 명령줄 플래그 대신 nvidia-docker 별칭을 사용한다.

추가 옵션을 더 줄 수도 있다. 은근히 많으니 공식 문서를 참조하자.

Container 작동 확인

Python 라이브러리와 PyTorch GPU 사용이 가능한지 확인해 보자.

pip freeze
python -V
python
import torch

# GPU check
torch.cuda.is_available()

# GPU 정보 확인
torch.cuda.get_device_name(0)

# 사용 가능한 GPU 개수
torch.cuda.device_count()

# 현재 GPU 번호
torch.cuda.current_device()

# device 정보 반환
torch.cuda.device(0)
# 결과:
True
'TITAN Xp'
2
0
<torch.cuda.device object at 0x7f015b7f6610>

nvidia-smi는 잘 작동하는데 torch.cuda.is_available()이 안 된다면 CUDA 버전과 PyTorch 버전이 안 맞을 확률이 높다. 다른 Docker Image를 사용하자.

실행중인 Container 확인

docker ps
# 결과
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

실행 중인 Container가 없으면 위처럼 별다른 정보가 나오지 않는다.

모든 Container의 리스트 확인

실행중인 Container 말고도 종료된 것까지 모두 보여준다.

docker ps -a

같은 명령어에 -a 옵션만 주면 된다. --all과 같은 의미인 것은 아마도? 알 것이다.

Container 검색

생성된 모든 컨테이너 중 특정한 Container 종류만 검색하려면 필터 옵션을 쓰면 된다.
아래 예시는 최신 pytorch docker image로 생성한 container들을 검색한다.

docker ps -a --filter ancestor=pytorch/pytorch:latest

Container 생성 후 volume 추가하는 방법

원래 생성할 때 연결하는 것이 기본이고, 안타깝게도 현재로서는 이미 생성된 docker에 간단히 volume을 추가할 수는 없다.

실수로 volume을 추가하는 것을 docker 생성 시 까먹었다면 해결할 수 있는 방법은 2가지다.

  1. 어차피 연결하기 전에 수정한 사항은 그리 많지 않을 가능성이 크므로 그냥 새로 만든다.
  2. 다음 코드를 실행한다.
docker commit <container-id> <newname>
docker run -ti -v <dir_in_somewhere>:/<dir_in_container> <newname> /bin/bash
  • <container-id>docker ps -a 명령을 통해 volume을 추가하고자 하는 container id를 확인한다.
  • docker commit은 아래에서 설명하겠지만 container를 통째로 저장하는 명령이다.
  • <newname>은 생성할 container 백업의 이름인데 대문자는 사용 불가능하다.
  • 그리고 <dir_in_somewhere>, <dir_in_container>은 각각 원하는 docker 밖 directory, docker 안 directory 경로를 지정하면 된다.

Container 관리

Container 이름 변경

실수로 --name 옵션을 안 쓰고 생성해서 임의의 이름으로 생성되었거나 이름이 마음에 안 들면 Container 이름을 간단히 바꿀 수 있다.

docker rename <old-name> <new-name>

Container 띄우기

생성 시 실행하는 것 말고, 종료 상태의 Container를 시작하려면 docker start <docker-name>과 같이 쓴다.

docker start prj_gorio

Container 접속

위의 명령은 Container를 띄운 것(구동시킨 것)이다. 실제로 접속해서 사용하려면 attach를 사용해야 한다.

docker attach prj_gorio

Container 밖으로 탈출

이 항목은 Container 생성 시 -it 옵션을 주고 생성했을 때만 가능하다.

Ctrl + P를 누르고 Ctrl + Q를 누르면 Container를 죽이지 않고 탈출할 수 있다.

Container 종료

Container를 완전히 종료하려면(삭제가 아니다!) Ctrl + D를 누르거나 다음과 같이 쓴다.

exit

Container 삭제

docker rm <container-name> [<container-name2>]
# 예시
docker rm prj_gorio
docker rm 503d22a4c01d prj_gorio ...

참고로 모든 container를 삭제하려면 다음과 같이 쓰면 된다.

docker rm -f $(docker ps -aq)

container 필터 검색과 결합하여 사용할 수도 있다.

docker rm -f $(docker ps -aq --filter ancestor=pytorch/pytorch:latest)

Container 내부 설정

Docker Image에 따라 다르지만, 기본적인 App이 설치되어 있지 않은 경우가 있다.

그런 경우에는 다음과 같이 입력하자. sudo는 쓰지 않는다.

apt-get update
apt-get install git vim wget
...

Container $\leftrightarrow$ 외부 파일 복사

docker cp <filename> <container-name>:/<path>/
# 파일명을 바꾸면서 복사하려면
docker cp <filename> <container-name>:/<path>/<filename>
# 디렉토리는 추가 옵션 없이 그냥 쓸 수 있다.
docker cp <directory-name> <container-name>:/<path>/

# 예시
docker cp gorio.py prj_gorio:/run/
docker cp gorio.py prj_gorio:/run/gorio.py
docker cp gorio.py prj_gorio:/preprocess/morio.py
docker cp gorio_test/ prj_gorio:/

Image와 Container를 파일로 저장 & 복원

Image 저장: docker save

Docker image를 tar 파일로 저장하려면 다음과 같이 쓴다.

docker save [option] <filename> [image_name]

# -o 옵션은 파일명을 지정한다.
docker save -o pytorch_latest.tar pytorch/pytorch:latest

Image 로드: docker load

docker save 명령으로 저장한 파일을 다시 Image로 불러오려면 다음과 같이 쓴다.

docker export로 생성한 tar 파일을 docker load로 불러오려고 시도하면 에러가 뜬다.

docker load -i <tar filename>

# 예시
docker load -i pytorch_latest.tar

Container 백업: docker commit -p

현재 생성되어 있는 container를 그 상태 그대로 저장하는 방법은 다음과 같다.

우선 docker commit -p 명령을 이용하여 container를 image로 만든다.

docker commit -p <container-id> <new_image_name>

그리고 위의 docker save -o 명령으로 이미지를 *.tar 파일로 만든다.

만들어진 파일을 다른 곳으로 옮긴 후 docker load -i 명령으로 이미지를 불러오면 된다.

같은 설명을 여기에서도 볼 수 있다.

참고로 8GB 이상의 파일이 있으면 commit이 안되고 Error processing tar file(exit status 1): unexpected EOF 같은 에러가 뜨니 너무 큰 파일은 굳이 container 안에 집어넣지 말고 container 생성 시 공유 옵션(--volume)을 이용하는 편이 낫다.

Container 백업: docker export

생성된 컨테이너를 파일로 저장할 수 있다.

docker export <container_name or conainter_ID> > xxx.tar

# 예시
docker export prj_gorio > gorio.tar

Container 로드: docker import

export 커맨드를 통해 만들어진 tar 파일을 다시 docker image로 생성하는 명령어이다.

docker save로 생성한 tar 파일을 docker import로 불러오려고 시도하면 에러가 뜬다.

docker import <filename or URL> [image name[:tag name]]

# 예시
docker import gorio.tar
docker import gorio.tar pytorch/pytorch:1.6.0-cuda10.1-cudnn7-devel

에러 해결법

  • docker: Error response from daemon: could not select device driver "" with capabilities: [[gpu]]. - nvidia-cuda-toolkit을 설치 또는 재설치한다.
  • docker: Error response from daemon: failed to create shim task: nvidia-container-cli: requirement error: unsatisfied condition: cuda>=xx.x, please update your driver to a newer version - 설치된 cuda 버전이 docker image가 요구하는 cuda version보다 낮다. cuda 또는 nvidia-driver를 버전 업그레이드한다.

참고

  • CUDA 재설치 등의 작업을 수행한 경우 nvidia toolkit 작업을 다시 해 주어야 한다. 여기를 참조하면 된다.