赞
踩
Docker提供了一种静态链接Linux核到应用程序的方式. 采用Docker容器可以调用GPUs,因此对于Tensorflow或者其它机器学习框架的部署是一种很好的工具.
利用Docker,不需要太多设置就可以重现机器学习项目,而不用再像下面这样:
- # 6 hours of installing dependencies
- python train.py
- > ERROR: libobscure.so cannot open shared object
只需进行类似于下面的操作,即可以执行 train.py 脚本,其集成了所有的依赖项,包括GPU支持:
- dockrun tensorflow/tensorflow:0.12.1-gpu python train.py
- > TRAINING SUCCESSFUL
此处, Docker是暂时的,且不会保存容器内的任何数据. 这里把Docker容器想象成一个1GB大小的 tensorflow.exe 应用程序,集成了需要编译的所有依赖项.
开源软件往往有很多依赖项,造成难以重用,比如不同编译器的版本、丢失头文件、不正确的库路径等等,这些都导致需要浪费很多时间来设置依赖项,以运行软件.
对于机器学习项目,如果想要分享在GitHub上,项目的依赖项一般是一系列的Linux命令行,复制并粘贴到终端中安装.
Docker通过一个命令行来拉取正确的Docker镜像,可以取代后一部分的操作,运行项目程序. 通过静态的将项目所有依赖项集成进一个3GB的压缩镜像中,重用时只需拉取下载下来即可.
以基于Torch的 pix2pix 项目为例,直接在Ubuntu平台上时:
- git clone https://github.com/phillipi/pix2pix.git
- cd pix2pix
- bash datasets/download_dataset.sh facades
- # install dependencies for some time
- ...
- # train
- env \
- DATA_ROOT=datasets/facades \
- name=facades \
- niter=200 \
- save_latest_freq=400 \
- which_direction=BtoA \
- display=0 \
- gpu=0 \
- cudnn=0 \
- th train.lua

如果依赖项较少时,该训练脚本是不错的,但实际上是有许多比较坑依赖项,如:
安装依赖项时,可能出现各种错误,比如:
- luajit: symbol lookup error:
- /root/torch/install/lib/lua/5.1/libTHNN.so: undefined symbol: TH_CONVERT_ACCREAL_TO_REAL
Docker则通过Docker Hub将项目依赖项打包做成二进制镜像形式.
在Linux服务器上安装 docker 和 nvidia-docker,然后Docker容器就可以访问GPUs,且基本上没有性能损失.
如果是Mac平台,可以安装 Docker for Mac,但是不能进行GPU运算,虽然少数Mac可能支持CUDA. 不过,仍可以以CPU模式进行测试,虽然速度很慢.
在Linux平台,下面的脚本可以在Ubuntu16.04安装 docker,可用于云服务商:
curl -fsSL https://affinelayer.com/docker/setup-docker.py | sudo python3
Docker安装成功后,可以以容器的方式运行 pix2pix 项目:
sudo docker run --rm --volume /:/host --workdir /host$PWD affinelayer/pix2pix <command>
具体过程如下:
- git clone https://github.com/phillipi/pix2pix.git
- cd pix2pix
- bash datasets/download_dataset.sh facades
- sudo docker run --rm --volume /:/host --workdir /host$PWD affinelayer/pix2pix \
- env \
- DATA_ROOT=datasets/facades \
- name=facades \
- niter=200 \
- save_latest_freq=400 \
- which_direction=BtoA \
- display=0 \
- gpu=0 \
- cudnn=0 \
- th train.lua
这里会下载作者编译的镜像(支持Torch+nvidia-docker),大概3GB的文件.
运行时会打印训练debug信息. 不过这里没有利用GPU. 基于GPU,能够有效提高pix2pix的训练速度.
要利用GPU,仅需将 docker 替换为 nvidia-docker.
标准Docker中还未集成 nvidia-docker,因此需要另外安装. 这里提供一种基于Ubuntu16.04 LTS环境的安装脚本:
curl -fsSL https://affinelayer.com/docker/setup-nvidia-docker.py | sudo python3
这里大概花费5分钟完成安装,在 Microsoft Azure 和 AWS 测试过.
当 nvidia-docker 安装完成后,可以打印当前显卡的信息:
sudo nvidia-docker run --rm nvidia/cuda nvidia-smi
现在开启 pix2pix 的GPU训练模式:
- sudo nvidia-docker run --rm --volume /:/host --workdir /host$PWD affinelayer/pix2pix \
- env \
- DATA_ROOT=datasets/facades \
- name=facades \
- niter=200 \
- save_latest_freq=400 \
- which_direction=BtoA \
- display=0 \
- th train.lua
使用了同一个 pix2pix Docker镜像,不过开启了GPU模式.
对于基于Python的Tensorflow,可能用到一组命令行选项:
--env PYTHONUNBUFFERED=x # 即时打印所有的输出
--env CUDA_CACHE_PATH=/host/tmp/cuda-cache #每次调用重新编译CUDA核,可避免每次启动Tensorflow的1分钟延迟
即:
- sudo nvidia-docker run --rm --volume /:/host --workdir /host$PWD \
- --env PYTHONUNBUFFERED=x \
- --env CUDA_CACHE_PATH=/host/tmp/cuda-cache \
- <image> \
- <command>
若觉得命令行太长,可以定义一个别名(alias):
alias dockrun="sudo nvidia-docker run --rm --volume /:/host --workdir /host\$PWD --env PYTHONUNBUFFERED=x --env CUDA_CACHE_PATH=/host/tmp/cuda-cache"
利用别名 dockrun,运行 pix2pix-tensorflow:
- git clone https://github.com/affinelayer/pix2pix-tensorflow.git
- cd pix2pix-tensorflow
- python tools/download-dataset.py facades
- dockrun affinelayer/pix2pix-tensorflow python pix2pix.py \
- --mode train \
- --output_dir facades_train \
- --max_epochs 200 \
- --input_dir facades/train \
- --which_direction BtoA
pix2pix-tensorflow 项目除了需要Tensorflow 0.12.1外,没有其它依赖项. 即便这样,在Github issue中还是有人遇到Tensorflow版本不对的问题.
使用Docker镜像来进行项目开发是很简单的.
只需在一个空路径中建立一个文件,命名为Dockerfile,内容类似于下面的形式:
- FROM nvidia/cuda:8.0-cudnn5-devel # 父镜像
- WORKDIR /root # 类似于 cd /root,进入到/root路径
-
- # 在shell终端运行命令,以安装training dependencies
- RUN apt-get update
- RUN apt-get install -y --no-install-recommends git ca-certificates sudo
-
- # torch 深度学习框架
- RUN git clone https://github.com/torch/distro.git torch --recursive && \
- cd torch && \
- git checkout 49c5b4fd478cb2e7f87ba5853510d26bf28a3d83 && \
- bash install-deps && \
- bash install.sh -b
-
- ENV PATH="/root/torch/install/bin/:${PATH}" # 指定torch环境变量
-
- # 安装tool dependencies
- # datasets/download_dataset.sh and models/download_model.sh
- # wget
- RUN apt-get install -y --no-install-recommends wget
-
- # scripts/combine_A_and_B.py and scripts/edges/batch_hed.py
- # opencv
- RUN apt-get install -y --no-install-recommends python python-dev
- RUN curl -O https://bootstrap.pypa.io/get-pip.py && python get-pip.py
- RUN pip install numpy scipy
-
- RUN curl -OL https://github.com/Itseez/opencv/archive/2.4.13.zip && \
- unzip 2.4.13.zip && \
- cd opencv-2.4.13 && \
- mkdir release && \
- cd release && \
- cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local .. && \
- make && \
- make install
-
- # scripts/edges/batch_hed.py
- # Caffe 深度学习框架
- # based on https://github.com/BVLC/caffe/blob/master/docker/gpu/Dockerfile # Caffe 官方镜像源
- # 安装Caffe依赖项
- RUN apt-get update && apt-get install -y --no-install-recommends \
- build-essential \
- cmake \
- git \
- wget \
- libatlas-base-dev \
- libboost-all-dev \
- libgflags-dev \
- libgoogle-glog-dev \
- libhdf5-serial-dev \
- libleveldb-dev \
- liblmdb-dev \
- libopencv-dev \
- libprotobuf-dev \
- libsnappy-dev \
- protobuf-compiler \
- python-dev \
- python-numpy \
- python-pip \
- python-setuptools \
- python-scipy && \
- rm -rf /var/lib/apt/lists/*
-
- ENV CAFFE_ROOT=/opt/caffe # 指定Caffe环境变量
-
- RUN mkdir -p $CAFFE_ROOT && \
- cd $CAFFE_ROOT && \
- git clone --depth 1 https://github.com/s9xie/hed . && \
- git checkout 9e74dd710773d8d8a469ad905c76f4a7fa08f945 && \
- pip install --upgrade pip && \
- cd python && for req in $(cat requirements.txt) pydot; do pip install $req; done && cd .. && \像不一致. 另外,如果 docker build指定了CPU,也会导致在另一台机器上不能运行.
- # https://github.com/s9xie/hed/pull/23
- sed -i "s|add_subdirectory(examples)||g" CMakeLists.txt && \
- mkdir build && cd build && \
- # /opt/caffe/include/caffe/util/cudnn.hpp(123): error: argument of type "int" is incompatible with parameter of type "cudnnNanPropagation_t" => -DUSE_CUDNN=OFF
- # /usr/bin/ld: cannot find -lopencv_dep_cudart => -DCUDA_USE_STATIC_CUDA_RUNTIME=OFF
- cmake -DUSE_CUDNN=OFF -DCUDA_USE_STATIC_CUDA_RUNTIME=OFF .. && \
- make -j"$(nproc)"
-
- ENV PYCAFFE_ROOT $CAFFE_ROOT/python # 指定Caffe的python API
- ENV PYTHONPATH $PYCAFFE_ROOT:$PYTHONPATH
- ENV PATH $CAFFE_ROOT/build/tools:$PYCAFFE_ROOT:$PATH # 指定Caffe的C++ API
- RUN echo "$CAFFE_ROOT/build/lib" >> /etc/ld.so.conf.d/caffe.conf && ldconfig
- RUN cd $CAFFE_ROOT && curl -O http://vcl.ucsd.edu/hed/hed_pretrained_bsds.caffemodel
-
- # scripts/edges/PostprocessHED.m
-
- RUN apt-get update && \
- apt-get install -y --no-install-recommends octave liboctave-dev && \
- octave --eval "pkg install -forge image" && \
- echo "pkg load image;" >> /root/.octaverc
- RUN curl -O https://pdollar.github.io/toolbox/archive/piotr_toolbox.zip && \
- unzip piotr_toolbox.zip && \
- octave --eval "addpath(genpath('/root/toolbox')); savepath;" && \
- echo "#include <stdlib.h>" > wrappers.hpp && \
- cat /root/toolbox/channels/private/wrappers.hpp >> wrappers.hpp && \
- mv wrappers.hpp /root/toolbox/channels/private/wrappers.hpp && \
- mkdir /root/mex && \
- cd /root/toolbox/channels/private && \
- mkoctfile --mex -DMATLAB_MEX_FILE -o /root/mex/convConst.mex convConst.cpp && \
- mkoctfile --mex -DMATLAB_MEX_FILE -o /root/mex/gradientMex.mex gradientMex.cpp && \
- mkoctfile --mex -DMATLAB_MEX_FILE -o /root/mex/imPadMex.mex imPadMex.cpp && \
- mkoctfile --mex -DMATLAB_MEX_FILE -o /root/mex/imResampleMex.mex imResampleMex.cpp && \
- mkoctfile --mex -DMATLAB_MEX_FILE -o /root/mex/rgbConvertMex.mex rgbConvertMex.cpp && \
- octave --eval "addpath('/root/mex'); savepath;" && \
- # gradient2 causes a segfault, use builtin gradient instead
- echo "function [a, b] = gradient2(x)\n[a, b] = gradient(x, 1);\nend" > /root/mex/gradient2.m
-
- RUN curl -O https://raw.githubusercontent.com/pdollar/edges/master/private/edgesNmsMex.cpp && \
- octave --eval "mex edgesNmsMex.cpp" && \
- mv edgesNmsMex.mex /root/mex/
-
- RUN apt-get install -y --no-install-recommends python-imaging

基于该Dockerfile,编译:
- mkdir docker-build
- cd docker-build
- curl -O https://affinelayer.com/docker/Dockerfile
- sudo docker build --rm --no-cache --tag pix2pix .
花费一段时间完成后,即可新建Docker镜像,查看Docker镜像:
sudo docker images pix2pix
- output:
- REPOSITORY TAG IMAGE ID CREATED SIZE
- pix2pix latest bf5bd6bb35f8 3 seconds ago 11.38 GB
设置Docker Hub账户,docker login登录,即可推送镜像:
- sudo docker tag pix2pix <accountname>/pix2pix
- sudo docker push <accountname>/pix2pix
这样即可使用该镜像来运行分享的软件和项目,很方便快捷.
也可以不用把Docker镜像推送到Docker Hub中,直接保存到本地:
- # save image to disk, this took about 18 minutes 保存到磁盘
- sudo docker save pix2pix | gzip > pix2pix.image.gz
-
- # load image from disk, this took about 4 minutes 从磁盘加载
- gunzip --stdout pix2pix.image.gz | sudo docker load
Docker镜像便于复制,不必每次都利用Dockerfile重复创建镜像. 查看创建镜像历史:
sudo docker history --no-trunc pix2pix
采用Dockerfile重复创建镜像可能导致版本不一样. 例如,如果Dockerfile中有 git clone 或者 apt-get update 命令,在不同的时间编译相同的Dockerfile,就可能导致创建的镜像不一致. 另外,如果 docker build指定了CPU,也会导致在另一台机器上不能运行.
因此,Docker镜像的目的是为了便于复用和部署,如果需要直接从Dockerfile复用镜像,则需要仔细对待Dockerfile文件内容,否则可能出现问题.
如果从零开始编译Dockerfile,并添加 –network none,断开网络链接,则可重现性更好,但推荐直接从镜像进行复用.
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。