ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Docker] 딥러닝과 파이썬 환경구축을 위한 도커파일
    💫 Computer Science/Python & AI Framework 2021. 12. 31. 10:36

     

     

     

    는 도커도 쓰고 로컬 파이썬도 쓰고 있었는데 최근에 개인 노트북과 회사 노트북의 환경을 모두 초기화하였습니다.

    로컬에는 어떤 언어도 프레임워크도 설치하지 않고 도커 컨테이너만 사용하려고 합니다.

    확실히 관리하기 정말 편하고 이것저것 변경하기가 너무 편해요.

    예를 들어서 Inference를 위한 flask API 용 환경은 최대한 가볍고 심플한 파이썬 컨테이너를 띄워놓고,

    딥러닝을 위한 주피터 파이토치 환경을 띄워놓으면,

    서로 다른 두 환경을 왔다갔다 하면서 작업하기도 편리하고 콘다 사용시 충돌문제가 없어 너무 좋았습니다.

     

    그리고 docker-compose를 통해서 여러개의 컨테이너를 원하는 옵션으로 한번에 띄울 수 있어서 좋습니다.

    예를 들어서 하나의 작업을 할 때 jupyter + pytorch + tensorboard + mongodb 가 필요하다고 하면 이를 하나의 컨테이너에 다 구축해도 되지만 따로따로 분리해서 docker-compose로 띄워주고 서로 연결시켜 사용하면 편하더라고요.

    mongodb같은 경우는 다른 컨테이너에서도 사용할 수 있기 때문에 주로 독립적으로 빼주는 편이고,

    각 컨테이너의 포트 포워딩 설정이나 환경변수, 그리고 실행시 사용할 명령어 등을 미리 등록해놓으면 docker run을 통해 컨테이너를 실행시킬 때 일일히 옵션을 적어줘야할 필요도 없습니다.

     

     

     

    Docker 이미지를 만드는 팁

     

    BASE 이미지를 작은 것으로 선택

    • Alpine Linux 다른 리눅스보다 훨씬 작음, 이유는 C 라이브러리로 musl을 사용하며 유닉스 도구들을 busybox 기반으로 하고 있음
    • 그렇지만 Python application 환경의 BASE 이미지로 사용하는 것은 권장하지 않음
      Using Apline can make Python Docker builds 50x slower
    • 이유는 PyPI 올라간 라이브러리들은 보통 Wheel 포맷을 사용한다. Alpine 리눅스는 Wheel 포맷을 지원하지 않는다!! 그래서 직접 소스 코드(.tar.gz)를 내려받아 컴파일 해야 하는 경우가 생긴다.
    • Wheel 포맷을 지원하지 않는 이유는 musl 라이브러리가 GNU C 라이브러리(glibc)로 컴파일된 wheel 바이너리를 지원하지 않기 때문. 그래서 PyPI에서 라이브러리를 받을 때 .whl 패키지가 아닌 .tar.gz를 다운받음
    • Wheel 포맷은 Python에서 설치 없이 바로 실행할 수 있다는 장점이 있다. 그 이유는 Wheel 포맷 자체가 zip 압축에서 확장자만 바꾼 것이며, Python은 Java의 .jar처럼 zip 파일을 바로 실행할 수 있기 때문이다.
    • 파이썬 애플리케이션 도커 이미지는 Debian Buster 기반의 python:3.8-buster 또는 3.8-slim-buster 을 사용하는 것이 좋다.

     

     

    이미지 레이어 개수를 줄이는 것이 좋다.

    레이어는 RUN, ADD, COPY 명령문에서만 생성되기 때문에 여러개로 분리된 명령을 chaining하는 것이 좋다.

    RUN apt-get update
    RUN apt-get -y install git
    RUN apt-get -y install locales
    RUN apt-get -y install gcc
    
    ↓
    
    RUN apt-get update && apt-get install -y \
        gcc \
        git \
        locales

     

     

    추천하는 파이썬 도커 이미지 종류

    • Default python Image

    python:version

    # Dockerfile
    FROM python:3.9 # python:version
    ...

     

    • Slim Image

    python:version-slim
    python:version-buster
    python:version-slim-buster

    # Dockerfile
    FROM python:3.9-slim # python:version-slim
    # or FROM python:3.9-slim-buster # python:version-slim-buster
    # or FROM python:3.9-buster # python:version-buster
    ...

     

    • cicleci Image

    python:version-circleci

    # Dockerfile
    FROM python:3.9-circleci # python:version-circleci
    ...



     

    nvidia-docker

    먼저, nvidia cuda를 사용하는 GPU 환경을 갖춘 도커 이미지를 만들기 위해서는 일반 도커 명령어(docker run, docker build..) 에 gpu 관련 옵션을 사용하거나 nvidia-docker 명령어를 사용하면 된다.(nvidia-docker run, nvidia-docker build..)

     

    nvidia 환경을 갖춘 도커파일을 만드는 방법은,

    1. host 컴퓨터에 nvidia driver를 설치
    2. host 컴퓨터의 OS 버전에 맞는 cuda를 설치한다. (이떄 다른 버전의 cuda가 돌아가고 있으면 안된다.)
    3. nvidia-docker, docker nvidia-container-toolkit 설치
    4. host OS, cuda 버전을 BASE 이미지의 버전과 잘 맞춰줘야 한다.
      ex. host 컴퓨터 os가 우분투20.04 버전에 cuda는 11.2라면 BASE 이미지는 nvidia/cuda:11.2.0-base-ubuntu20.04 를 사용.

     

     

    nvidia-docker Comand

    $ nvidia-docker login
    $ nvidia-docker build --tag <imagename>:<tagname>
    $ nvidia-docker run, build, commit, push, start, exec, attach..
    $ nvidia-docker history <imagename>:<tagname>
    $ nvidia-docker cp <host파일경로> <containername>:<docker파일경로>
    $ docker log [options] container

     

     

     

    Docker Image Example

     

    Docker Image Example 1: debian + miniconda

    # Base Image   
    FROM debian:latest
    ENV LC_ALL=C.UTF-8
    
    # Install Miniconda
    ENV LANG=C.UTF-8 LC_ALL=C.UTF-8
    ENV PATH /opt/conda/bin:$PATH
    RUN apt-get -qq update && apt-get -qq -y install wget curl bzip2 ca-certificates git sudo vim build-essential \
        && curl -sSL https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -o /tmp/miniconda.sh \
        && bash /tmp/miniconda.sh -bfp /usr/local \
        && rm -rf /tmp/miniconda.sh \
        && conda install -y python=3 \
        && conda update conda \
    #    && apt-get -qq -y remove curl bzip2 \
        && apt-get -qq -y autoremove \
        && apt-get autoclean \
        && rm -rf /var/lib/apt/lists/* /var/log/dpkg.log \
        && conda clean --all --yes
    
    # Install Python Packages
    RUN pip install tensorflow && \
    	pip install cython && \
    	pip install nltk && \
    	pip install pandas && \
    	pip install seaborn && \
    	pip install sklearn && \
    	pip install simplejson && \
    	pip install psycopg2-binary && \
    	conda install av -c conda-forge && \
    	pip install jupyterlab jupyterhub && \
    	pip install jupyterlab-system-monitor
    
    
    # Requirements.txt 있을때
    # COPY requirements.txt /tmp
    # WORKDIR /tmp
    # RUN pip install -r requirements.txt

     

     

     

    Docker Image Example 2 : Jupyter + pytorch + Mecab

    # Base Image
    FROM nvidia/cuda:11.2.0-base-ubuntu20.04
    ENV LANG=C.UTF-8 LC_ALL=C.UTF-8
    
    # Basic Utils
    ARG DEBIAN_FRONTEND=noninteractive
    RUN apt-get -qq update && \
    	apt-get install --no-install-recommends -y build-essential \
    	bzip2 \
    	ca-certificates \
    	curl \
    	git \
    	libcanberra-gtk-module \
    	libgtk2.0-0 \
    	libx11-6 \
    	sudo \
    	graphviz \
    	vim
    
    # Install Miniconda
    ENV PATH /opt/conda/bin:$PATH
    RUN apt-get install -y wget ibglib2.0-0 libxext6 libsm6 libxrender1 \
    	mercurial subversion
    RUN wget --quiet https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O ~/miniconda.sh && \
    	/bin/bash ~/miniconda.sh -b -p /opt/conda && \
    	rm ~/miniconda.sh && \
    	ln -s /opt/conda/etc/profile.d/conda.sh /etc/profile.d/conda.sh && \
    	echo ". /opt/conda/etc/profile.d/conda.sh" >> ~/.bashrc && \
    	echo "conda activate base" >> ~/.bashrc
    RUN apt-get install -y default-jdk default-jre
    RUN apt-get install -y grep sed dpkg && \
    	TINI_VERSION=`curl https://github.com/krallin/tini/releases/latest | grep -o "/v.*\"" | sed 's:^..\(.*\).$:\1:'` && \
    	curl -L "https://github.com/krallin/tini/releases/download/v${TINI_VERSION}/tini_${TINI_VERSION}.deb" > tini.deb && \
    	dpkg -i tini.deb && \
    	rm tini.deb && \
    	apt-get clean
    
    # Install Python Packages
    RUN conda install av -c conda-forge && \
    	conda install -c conda-forge jupyterlab && \
    	pip install --upgrade pip && \
    	pip install torch==1.7.1+cu110 torchvision==0.8.2+cu110 torchaudio===0.7.2 -f https://download.pytorch.org/whl/torch_stable.html && \
        pip install sklearn matplotlib pandas numba tensorflow tensorboard kss regex ray pymongo jupyterlab-system-monitor
    
    RUN mkdir -p /workspace 
    WORKDIR /workspace 
    
    # KoLNPy
    RUN pip install Jpype1 tweepy==3.10.0 konlpy 
    RUN cd /workspace && \ 
    	curl -s https://raw.githubusercontent.com/konlpy/konlpy/master/scripts/mecab.sh | bash -s

    저는 주로 NLP를 하기 때문에 거의 모든 이미지에 KoNLPy와 Mecab을 위한 부분이 있습니다.

     

     

     

    docker-compose.yml

    version: '3'
    
    services:
      mongo:
        image: mongo
        restart: always
        volumes:
          - /mnt/sub/docker_volumes/amy-vol/mongo_db:/data/db
        ports:
          - "1234:27017"
        environment:
          - MONGO_USERNAME=amy
          - MONGO_PASSWORD=***
          - MONGO_DATABASE=***
    
      jupyter0:
        image: amy/pytorch
        volumes:
          - /mnt/sub/docker_volumes/amy-vol/_data:/workspace
        ports:
          - "1233:8888"
          - "1222:8265"
        depends_on:
          - mongo
        links:
          - mongo
        runtime: nvidia
        shm_size: '63gb' # df -h /dev/shm
        command: jupyter lab --allow-root --config /workspace/jupyter_notebook_config.py
    
      tensorboard0:
        image: amy/pytorch
        volumes:
          - /mnt/sub/docker_volumes/amy-vol/_data:/workspace
        ports:
          - "2222:8889"
        command: tensorboard --logdir=log/tensorboard --port=8889 --host=0.0.0.0

     

     

     

     

    그리고 mongo, jupyter, tensorboard를 한번에 띄우는 docker-compose.yml 파일

    이 파일을 docker-compose up으로 빌드하면 세 컨테이너가 모두 띄워집니다.

    docker-compose.yml에서 NVIDIA_VISIBLE_DEVICES=1 옵션을 사용해서 각 컨테이너마다 사용할 GPU를 지정할 수 있는데 GPU가 여러개인 경우 train환경과 텐서보드를 여러개의 컨테이너로 분리해서 사용하는 경우도 많습니다.

    # docker-compose.yml
    ....
    	services:
        train:
            image: imagename
            environment:
                - NVIDIA_VISIBLE_DEVICES=1
            // or runtime: nvidia
            command:
                명령어
                
    ...

     

     

    컨테이너 안에서 GPU를 인식하고 있는지 확인

    import torch
    
    print(f'torch.__version__: {torch.__version__}')
    
    print(f'GPU 사용여부: {torch.cuda.is_available()}')
    gpu_count = torch.cuda.device_count()
    print(f'GPU count: {gpu_count}')
    if gpu_count > 0:
        print(f'GPU name: {torch.cuda.get_device_name(0)}')
        
        
    # torch.__version__: 1.7.1+cu110
    # GPU 사용여부: True
    # GPU count: 1
    # GPU name: GeForce RTX 3080

     

     

    CPU GPU 학습 시간 비교

    import time
    from sklearn.datasets import make_regression
    from xgboost import XGBRegressor
    
    def model_test(model_name, model):
        x, y = make_regression(n_samples=100000, n_features=100)
        
        start_time = time.time()
        model.fit(x, y)
        end_time = time.time()
        return f'{model_name}: 소요시간: {(end_time - start_time)} 초'
    
    xgb = XGBRegressor(n_estimators=1000, 
                       learning_rate=0.01, 
                       subsample=0.8, 
                       colsample_bytree=0.8,
                       objective='reg:squarederror', 
                      )
    
    print(model_test('xgb (cpu)', xgb))
    
    xgb = XGBRegressor(n_estimators=1000, 
                       learning_rate=0.01, 
                       subsample=0.8, 
                       colsample_bytree=0.8,
                       objective='reg:squarederror', 
                       tree_method='gpu_hist')
    
    print(model_test('xgb (gpu)', xgb))
    
    
    # xgb (cpu): 소요시간: 109.3758487701416 초
    # xgb (gpu): 소요시간: 6.266696453094482 초

     

     

     

     

    위 DockerImage와 compose 파일, 테스트 파일까지 모두 모아논 레포지토리는 아래 주소 입니다.

    필요하시면 사용하세요..!

     

    GitHub - MinkyungPark/docker_data_science: docker for data science

    docker for data science. Contribute to MinkyungPark/docker_data_science development by creating an account on GitHub.

    github.com

     

     

     

     

     

     

     

    References

    https://jonnung.dev/docker/2020/04/08/optimizing-docker-images/

    https://pythonspeed.com/articles/base-image-python-docker-images/

     

     

    댓글

Designed by Tistory.