From ece964549f6dadd65d33cdca39087528631acd37 Mon Sep 17 00:00:00 2001 From: Mu Li Date: Sun, 26 Mar 2017 09:40:06 -0700 Subject: [PATCH] add dockerfiles and hosted docker images for python/julia/r/scala (#5574) --- docker/.gitignore | 2 + docker/Dockerfiles/Dockerfile.in.julia | 7 ++ docker/Dockerfiles/Dockerfile.in.lib.cpu | 10 ++ docker/Dockerfiles/Dockerfile.in.lib.gpu | 9 ++ docker/Dockerfiles/Dockerfile.in.python | 6 + docker/Dockerfiles/Dockerfile.in.r-lang | 7 ++ docker/Dockerfiles/Dockerfile.in.scala | 7 ++ docker/README.md | 133 ++++++++++++++++------- docker/cpu/Dockerfile | 13 --- docker/cuda/7.5/Dockerfile | 25 ----- docker/cuda/8.0/Dockerfile | 25 ----- docker/install/cpp.sh | 8 ++ docker/install/julia.sh | 11 ++ docker/install/python.sh | 10 ++ docker/install/r.sh | 18 +++ docker/install/scala.sh | 8 ++ docker/run.sh | 11 ++ docker/tool.sh | 80 ++++++++++++++ 18 files changed, 288 insertions(+), 102 deletions(-) create mode 100644 docker/.gitignore create mode 100644 docker/Dockerfiles/Dockerfile.in.julia create mode 100644 docker/Dockerfiles/Dockerfile.in.lib.cpu create mode 100644 docker/Dockerfiles/Dockerfile.in.lib.gpu create mode 100644 docker/Dockerfiles/Dockerfile.in.python create mode 100644 docker/Dockerfiles/Dockerfile.in.r-lang create mode 100644 docker/Dockerfiles/Dockerfile.in.scala delete mode 100644 docker/cpu/Dockerfile delete mode 100644 docker/cuda/7.5/Dockerfile delete mode 100644 docker/cuda/8.0/Dockerfile create mode 100755 docker/install/cpp.sh create mode 100755 docker/install/julia.sh create mode 100755 docker/install/python.sh create mode 100755 docker/install/r.sh create mode 100755 docker/install/scala.sh create mode 100644 docker/run.sh create mode 100755 docker/tool.sh diff --git a/docker/.gitignore b/docker/.gitignore new file mode 100644 index 000000000000..2a377effe731 --- /dev/null +++ b/docker/.gitignore @@ -0,0 +1,2 @@ +Dockerfile.* +!Dockerfile.in.* diff --git a/docker/Dockerfiles/Dockerfile.in.julia b/docker/Dockerfiles/Dockerfile.in.julia new file mode 100644 index 000000000000..42422ddbed54 --- /dev/null +++ b/docker/Dockerfiles/Dockerfile.in.julia @@ -0,0 +1,7 @@ +# -*- mode: dockerfile -*- +# part of the dockerfile to install the julia binding + +COPY install/julia.sh install/ +RUN install/julia.sh +ENV MXNET_HOME /mxnet +RUN julia -e 'Pkg.add("MXNet")' diff --git a/docker/Dockerfiles/Dockerfile.in.lib.cpu b/docker/Dockerfiles/Dockerfile.in.lib.cpu new file mode 100644 index 000000000000..002e2d1e4209 --- /dev/null +++ b/docker/Dockerfiles/Dockerfile.in.lib.cpu @@ -0,0 +1,10 @@ +# -*- mode: dockerfile -*- +# dockerfile to build libmxnet.so on CPU +FROM ubuntu:14.04 + +COPY install/cpp.sh install/ +RUN install/cpp.sh + +RUN git clone --recursive https://github.com/dmlc/mxnet && cd mxnet && \ + make -j$(nproc) && \ + rm -r build diff --git a/docker/Dockerfiles/Dockerfile.in.lib.gpu b/docker/Dockerfiles/Dockerfile.in.lib.gpu new file mode 100644 index 000000000000..2185babf085c --- /dev/null +++ b/docker/Dockerfiles/Dockerfile.in.lib.gpu @@ -0,0 +1,9 @@ +# -*- mode: dockerfile -*- +# dockerfile to build libmxnet.so on GPU +FROM nvidia/cuda:8.0-cudnn5-devel + +COPY install/cpp.sh install/ +RUN install/cpp.sh + +RUN git clone --recursive https://github.com/dmlc/mxnet && cd mxnet && \ + make -j$(nproc) USE_CUDA=1 USE_CUDA_PATH=/usr/local/cuda USE_CUDNN=1 diff --git a/docker/Dockerfiles/Dockerfile.in.python b/docker/Dockerfiles/Dockerfile.in.python new file mode 100644 index 000000000000..b7979b231d7d --- /dev/null +++ b/docker/Dockerfiles/Dockerfile.in.python @@ -0,0 +1,6 @@ +# -*- mode: dockerfile -*- +# part of the dockerfile to install the python binding + +COPY install/python.sh install/ +RUN install/python.sh +ENV PYTHONPATH=/mxnet/python diff --git a/docker/Dockerfiles/Dockerfile.in.r-lang b/docker/Dockerfiles/Dockerfile.in.r-lang new file mode 100644 index 000000000000..321094ec6c63 --- /dev/null +++ b/docker/Dockerfiles/Dockerfile.in.r-lang @@ -0,0 +1,7 @@ +# -*- mode: dockerfile -*- +# part of the dockerfile to install the r binding + +COPY install/r.sh install/ +ADD https://raw.githubusercontent.com/dmlc/mxnet/master/R-package/DESCRIPTION install/ +RUN install/r.sh +RUN cd mxnet && make rpkg && R CMD INSTALL mxnet_current_r.tar.gz diff --git a/docker/Dockerfiles/Dockerfile.in.scala b/docker/Dockerfiles/Dockerfile.in.scala new file mode 100644 index 000000000000..a45fbfdaaab6 --- /dev/null +++ b/docker/Dockerfiles/Dockerfile.in.scala @@ -0,0 +1,7 @@ +# -*- mode: dockerfile -*- +# part of the dockerfile to install the scala binding + +COPY install/scala.sh install/ +RUN install/scala.sh + +RUN cd mxnet && make scalapkg diff --git a/docker/README.md b/docker/README.md index 5b2897ade43f..95fa668e97d7 100644 --- a/docker/README.md +++ b/docker/README.md @@ -1,58 +1,113 @@ # Docker images for MXNET -Pre-built docker images are available at https://hub.docker.com/r/dmlc/mxnet/ - ## How to use -1. First pull the pre-built image +First make sure [docker](https://docs.docker.com/engine/installation/) is +installed. The docker plugin +[nvidia-docker](https://github.com/NVIDIA/nvidia-docker) is required to run on +Nvidia GPUs. + +Pre-built docker containers are available at https://hub.docker.com/r/mxnet/ + +For example, the following command launches a container with the Python package +installed. It will pull the docker images from docker hub if it does not exist +locally. + +```bash +docker run -ti --rm mxnet/python +``` + +Then you can run MXNet in python, e.g.: + +```bash +# python -c 'import mxnet as mx; a = mx.nd.ones((2,3)); print((a*2).asnumpy())' +[[ 2. 2. 2.] + [ 2. 2. 2.]] +``` + +If the host machine has at least one GPU installed and `nvidia-docker` is installed, namely +`nvidia-docker run --rm nvidia/cuda nvidia-smi` runs successfully, then you can +run a container with GPU supports + +```bash +nvidia-docker run -ti --rm mxnet/python:gpu +``` + +Now you can run the above example in `GPU 0`: + +```bash +# python -c 'import mxnet as mx; a = mx.nd.ones((2,3), mx.gpu(0)); print((a*2).asnumpy())' +[[ 2. 2. 2.] + [ 2. 2. 2.]] +``` + +## Hosted containers + +All images are based on Ubuntu 14.04. The `gpu` tag is built with CUDA 8.0 and +cuDNN 5. + +### Python - ```bash - docker pull dmlc/mxnet - ``` -2. Then we can run the python shell in the docker +Hosted at https://hub.docker.com/r/mxnet/python/ - ```bash - docker run -ti dmlc/mxnet python - ``` - For example - ```bash - $ docker run -ti dmlc/mxnet python - Python 2.7.6 (default, Jun 22 2015, 17:58:13) - [GCC 4.8.2] on linux2 - Type "help", "copyright", "credits" or "license" for more information. - >>> import mxnet as mx - import mxnet as mx - >>> quit() - quit() - ``` +Python versions: 2.7.12 and 3.5.2. - Note: One may get the error message `libdc1394 error: Failed to initialize - libdc1394`, which is due to opencv and can be ignored. +Available tags: -3. Train a model on MNIST to check everything works +- mxnet/python +- mxnet/python:gpu - ``` - docker run dmlc/mxnet python /mxnet/example/image-classification/train_mnist.py - ``` +### R -If the host machine has Nvidia GPUs, we can use `dmlc/mxnet:cuda`, which has both CUDA and CUDNN installed. -To launch the docker, we need to install [nvidia-docker](https://github.com/NVIDIA/nvidia-docker) first. +Hosted at https://hub.docker.com/r/mxnet/r-lang/ -1. Pull the image +R version: 3.3.3 - ```bash - docker pull dmlc/mxnet:cuda - ``` +Available tags: -2. Train MNIST on GPU 0 +- mxnet/r-lang +- mxnet/r-lang:gpu - ```bash - nvidia-docker run dmlc/mxnet:cuda python /mxnet/example/image-classification/train_mnist.py --gpus 0 - ``` + +### Julia + +Hosted at https://hub.docker.com/r/mxnet/julia/ + +Julia version: 0.5.1 + +Available tags: + +- mxnet/julia +- mxnet/julia:gpu + +#### Scala + +Hosted at https://hub.docker.com/r/mxnet/scala/ + +Scala version: 2.11.8 + +Available tags: + +- mxnet/scala ## How to build +The following command build the default Python package + +```bash +./tool.sh build python cpu +``` + +Run `./tool.sh` for more details. Use + + +Tips: The following commands stop all docker containers and delete all docker images. + +```bash +docker stop $(docker ps -a -q) +docker rm $(docker ps -a -q) +``` + ```bash -docker build -t dmlc/mxnet:cpu cpu -docker build -t dmlc/mxnet:cuda cuda +docker rmi $(docker images -a -q) ``` diff --git a/docker/cpu/Dockerfile b/docker/cpu/Dockerfile deleted file mode 100644 index 1e5a956450dc..000000000000 --- a/docker/cpu/Dockerfile +++ /dev/null @@ -1,13 +0,0 @@ -FROM ubuntu:14.04 -MAINTAINER Mu Li - -# install the core library -RUN apt-get update && apt-get install -y build-essential git libopenblas-dev libopencv-dev -RUN git clone --recursive https://github.com/dmlc/mxnet/ && cd mxnet && \ - cp make/config.mk . && \ - echo "USE_BLAS=openblas" >>config.mk && \ - make -j$(nproc) - -# python pakcage -RUN apt-get install -y python-numpy wget unzip -ENV PYTHONPATH /mxnet/python diff --git a/docker/cuda/7.5/Dockerfile b/docker/cuda/7.5/Dockerfile deleted file mode 100644 index ff0b0bbb2cd6..000000000000 --- a/docker/cuda/7.5/Dockerfile +++ /dev/null @@ -1,25 +0,0 @@ -FROM nvidia/cuda:7.5-cudnn5-devel -MAINTAINER Qingsong Liu - -RUN apt-get update && apt-get install -y \ - git \ - libopenblas-dev \ - libopencv-dev \ - python-dev \ - python-numpy \ - python-setuptools \ - wget \ - python-pip \ - unzip - -RUN cd /root && git clone --recursive https://github.com/dmlc/mxnet && cd mxnet && \ - cp make/config.mk . && \ - sed -i 's/USE_BLAS = atlas/USE_BLAS = openblas/g' config.mk && \ - sed -i 's/USE_CUDA = 0/USE_CUDA = 1/g' config.mk && \ - sed -i 's/USE_CUDA_PATH = NONE/USE_CUDA_PATH = \/usr\/local\/cuda/g' config.mk && \ - sed -i 's/USE_CUDNN = 0/USE_CUDNN = 1/g' config.mk && \ - make -j"$(nproc)" - -ENV PYTHONPATH /root/mxnet/python - -WORKDIR /root/mxnet diff --git a/docker/cuda/8.0/Dockerfile b/docker/cuda/8.0/Dockerfile deleted file mode 100644 index c67375576f03..000000000000 --- a/docker/cuda/8.0/Dockerfile +++ /dev/null @@ -1,25 +0,0 @@ -FROM nvidia/cuda:8.0-cudnn5-devel -MAINTAINER Qingsong Liu - -RUN apt-get update && apt-get install -y \ - git \ - libopenblas-dev \ - libopencv-dev \ - python-dev \ - python-numpy \ - python-setuptools \ - wget \ - python-pip \ - unzip - -RUN cd /root && git clone --recursive https://github.com/dmlc/mxnet && cd mxnet && \ - cp make/config.mk . && \ - sed -i 's/USE_BLAS = atlas/USE_BLAS = openblas/g' config.mk && \ - sed -i 's/USE_CUDA = 0/USE_CUDA = 1/g' config.mk && \ - sed -i 's/USE_CUDA_PATH = NONE/USE_CUDA_PATH = \/usr\/local\/cuda/g' config.mk && \ - sed -i 's/USE_CUDNN = 0/USE_CUDNN = 1/g' config.mk && \ - make -j"$(nproc)" - -ENV PYTHONPATH /root/mxnet/python - -WORKDIR /root/mxnet diff --git a/docker/install/cpp.sh b/docker/install/cpp.sh new file mode 100755 index 000000000000..91b8b8db0607 --- /dev/null +++ b/docker/install/cpp.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +# libraries for building mxnet c++ core on ubuntu + +apt-get update && apt-get install -y \ + build-essential git libatlas-base-dev libopencv-dev \ + libcurl4-openssl-dev libgtest-dev cmake wget unzip + +cd /usr/src/gtest && cmake CMakeLists.txt && make && cp *.a /usr/lib diff --git a/docker/install/julia.sh b/docker/install/julia.sh new file mode 100755 index 000000000000..604a1bc2c234 --- /dev/null +++ b/docker/install/julia.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +# install libraries for mxnet's julia package on ubuntu + +# the julia version shipped with ubuntu (version 0.4) is too low. so download a +# new version +# apt-get install -y julia + +wget -q https://julialang.s3.amazonaws.com/bin/linux/x64/0.5/julia-0.5.1-linux-x86_64.tar.gz +tar -zxf julia-0.5.1-linux-x86_64.tar.gz +rm julia-0.5.1-linux-x86_64.tar.gz +ln -s $(pwd)/julia-6445c82d00/bin/julia /usr/bin/julia diff --git a/docker/install/python.sh b/docker/install/python.sh new file mode 100755 index 000000000000..0459bb9198c4 --- /dev/null +++ b/docker/install/python.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +# install libraries for mxnet's python package on ubuntu + +apt-get update && apt-get install -y python-dev python3-dev + +# the version of the pip shipped with ubuntu may be too lower, install a recent version here +cd /tmp && wget https://bootstrap.pypa.io/get-pip.py && python3 get-pip.py && python2 get-pip.py + +pip2 install nose pylint numpy nose-timer requests +pip3 install nose pylint numpy nose-timer requests diff --git a/docker/install/r.sh b/docker/install/r.sh new file mode 100755 index 000000000000..9351763ddcee --- /dev/null +++ b/docker/install/r.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +# install libraries for mxnet's r package on ubuntu + +echo "deb http://cran.rstudio.com/bin/linux/ubuntu trusty/" >> /etc/apt/sources.list +gpg --keyserver keyserver.ubuntu.com --recv-key E084DAB9 +gpg -a --export E084DAB9 | apt-key add - + +apt-get update +apt-get install -y r-base r-base-dev libxml2-dev libxt-dev libssl-dev + +cd "$(dirname "${BASH_SOURCE[0]}")" + +if [ ! -f "./DESCRIPTION" ]; then + cp ../../R-package/DESCRIPTION . +fi + +Rscript -e "install.packages('devtools', repo = 'https://cran.rstudio.com')" +Rscript -e "library(devtools); library(methods); options(repos=c(CRAN='https://cran.rstudio.com')); install_deps(dependencies = TRUE)" diff --git a/docker/install/scala.sh b/docker/install/scala.sh new file mode 100755 index 000000000000..8cbe91199463 --- /dev/null +++ b/docker/install/scala.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +# install libraries for mxnet's scala package on ubuntu + +apt-get install -y maven default-jdk + +wget http://downloads.lightbend.com/scala/2.11.8/scala-2.11.8.deb +dpkg -i scala-2.11.8.deb +rm scala-2.11.8.deb diff --git a/docker/run.sh b/docker/run.sh new file mode 100644 index 000000000000..0037ab1926d7 --- /dev/null +++ b/docker/run.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +# Build and push all docker containers + +DEVICES=('cpu' 'gpu') +LANGUAGES=('python' 'julia' 'r-lang' 'scala') +for DEV in "${DEVICES[@]}"; do + for LANG in "${LANGUAGES[@]}"; do + ./tool.sh build ${LANG} ${DEV} + ./tool.sh push ${LANG} ${DEV} + done +done diff --git a/docker/tool.sh b/docker/tool.sh new file mode 100755 index 000000000000..31a98822350d --- /dev/null +++ b/docker/tool.sh @@ -0,0 +1,80 @@ +#!/usr/bin/env bash +# +# Script to build, test and push a docker container +# +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +function show_usage() { + echo "" + echo "Usage: $(basename $0) COMMAND DEVICE LANGUAGE " + echo "" + echo " COMMAND: build or commit." + echo " commit needs logined in docker hub" + echo " DEVICE: targed device, e.g. cpu, or gpu" + echo " LANGUAGE: the language binding to buld, e.g. python, r-lang, julia, or scala" + echo "" +} + +if (( $# < 3 )); then + show_usage + exit -1 +fi + +COMMAND=$( echo "$1" | tr '[:upper:]' '[:lower:]' ) +shift 1 +LANGUAGE=$( echo "$1" | tr '[:upper:]' '[:lower:]' ) +shift 1 +DEVICE=$( echo "$1" | tr '[:upper:]' '[:lower:]' ) +shift 1 + +DOCKERFILE_LIB="${SCRIPT_DIR}/Dockerfiles/Dockerfile.in.lib.${DEVICE}" +if [ ! -e ${DOCKERFILE_LIB} ]; then + echo "Error DEVICE=${DEVICE}, failed to find ${DOCKERFILE_LIB}" + show_usage + exit 1 +fi + +DOCKERFILE_LANG="${SCRIPT_DIR}/Dockerfiles/Dockerfile.in.${LANGUAGE}" +if [ ! -e ${DOCKERFILE_LANG} ]; then + echo "Error LANGUAGE=${LANGUAGE}, failed to find ${DOCKERFILE_LANG}" + show_usage + exit 1 +fi + +if [[ "${DEVICE}" == *"gpu"* ]] && [[ "{COMMAND}" == "test" ]]; then + DOCKER_BINARY="nvidia-docker" +else + DOCKER_BINARY="docker" +fi + +DOCKER_TAG="mxnet/${LANGUAGE}" +if [ "${DEVICE}" != 'cpu' ]; then + DOCKER_TAG="${DOCKER_TAG}:${DEVICE}" +fi +DOCKERFILE="Dockerfile.${LANGUAGE}.${DEVICE}" + +# print arguments +echo "DOCKER_BINARY: ${DOCKER_BINARY}" +echo "DOCKERFILE: ${DOCKERFILE}" +echo "DOCKER_TAG: ${DOCKER_TAG}" + +if [[ "${COMMAND}" == "build" ]]; then + rm -rf ${DOCKERFILE} + cp ${DOCKERFILE_LIB} ${DOCKERFILE} + cat ${DOCKERFILE_LANG} >>${DOCKERFILE} + # To remove the following error caused by opencv + # libdc1394 error: Failed to initialize libdc1394" + CMD="sh -c 'ln -s /dev/null /dev/raw1394';" + # setup scala classpath + if [[ "${LANGUAGE}" == "scala" ]]; then + CMD+="CLASSPATH=\${CLASSPATH}:\`ls /mxnet/scala-package/assembly/linux-x86_64-*/target/*.jar | paste -sd \":\"\` " + fi + echo "CMD ${CMD} bash" >>${DOCKERFILE} + ${DOCKER_BINARY} build -t ${DOCKER_TAG} -f ${DOCKERFILE} . +elif [[ "${COMMAND}" == "push" ]]; then + ${DOCKER_BINARY} push ${DOCKER_TAG} +else + echo "Unknow COMMAND=${COMMAND}" + show_usage + exit 1 +fi