Docker深度学习环境篇第二弹:PyCharm + Docker + GPUs = Everything you need for DL development

Docker深度学习环境篇第二弹:PyCharm + Docker + GPUs = Everything you need for DL development

五月31日

update: 更新了Step 7&8的路径问题

之前写的时候,没有注意到在pycharm的帮助文档中Configuring Remote Interpreters via Docker的一段话:

Docker Machine on Linux does not share user home folder, and any other folders as well. Thus, for running, debugging and profiling applications, the user should add shared folders with the project sources to the VirtualBox Docker virtual machine manually. These shared folders on VM should be mapped one to one to the folders on the host Linux machine, i.e. (host) /home/user <=> /home/user(VM) or (host) /home/my/project <=> /home/my/project (VM)

所以Pycharm docker只把当前工作目录映射到container里面,如果你要读取你host机器上的数据的话需要手动添加目录,具体做法我写在 steps 8 中。

--------------------------------------------------分割线----------------------------------------------------------------


Problem Formulation

在上回Docker--深度学习环境配置一站式解决方案 - 知乎专栏中,我简要介绍了Docker的概念,如何使用别人上传到Docker Hub的镜像Image,以及如何利用NVIDIA的Docker插件在Docker container中调用本地GPU。根据我的实验表明,利用上一篇文章中的方法,运行效率和原生环境一致,nvidia-docker插件并不影响GPU的计算速度以及数据传输。

但是我在上篇中只介绍了利用命令行和notebook开发的方法,只适合跑demo和实验,对于有多个模块并行开发的大型Python工程可能不太方便。这一篇中,我想介绍如何在本机运行的pycharm里直接调用Docker container里面的Python解释器,这样一来,你既可以充分利用现有的Docker image资源,同时能够发挥Pycharm IDE里的强大功能(比如自动补全,断点调试等等)。

如果觉得有用,请各位看官老爷点赞转发 :) 。

Objective

在上一篇的基础上,我有一个安装了所有深度学习框架的Docker image。现在我想在Pycharm中完成我的所有python代码,点击运行的时候,Pycharm可以调用那个image的python interpreter来执行我的代码。同时我还希望它能自动调用GPU,自动代码补全,而且我还很懒,不想修改任何本机环境。

Ingredients

Ubuntu intel架构,Docker, nvidia-docker插件, 我写的docker image

请参考前作 Docker--深度学习环境配置一站式解决方案 - 知乎专栏

Pycharm

熟悉Python开发的人应该都听说过这个IDE,我就不过多介绍了,只想说JetBrains不亏是被Google选中的公司,他们自己开发和维护的许多项目都堪称业界良心。需要注意的是我接下来要介绍的功能需要Pycharm Pro版。什么?没钱?没问题,都说了是业界良心,只要你有一个academic email都可以到这免费申请Free for Students: Professional Developer Tools from JetBrains

nvidia-docker-compose

docker-compose是Docker里的另一个强大功能,简单来说就是你有了Image和你的App后,通过一个compose文件可以告诉Docker每次以什么方式开启你的container。在这里我们只要利用其中一个很小的功能,即每次我在Pycharm中运行一个python文件的时候,run 一个我指定的image,并利用这个运行的container里的python解释器来运行我Pycharm里的Python代码,代码运行结束后container自动退出。当然,我们做深度学习的还是希望container能调用GPU,所以用的是nvidia-docker-compose




Steps

  1. (Optional)更新系统
    在Ubuntu中,如果要安装什么,我习惯先跑两个命令更新系统:
    sudo apt-get -y update
    sudo apt-get -y upgrade
    

  2. 安装 nvidia-docker-compose
    如果你已经如上篇所述在你的主机上安装好Docker,nvidia-docker以及cuda驱动,那么你只要通过以下命令
    pip install nvidia-docker-compose
    

    就可以安装nvidia-docker-compose和原生的docker-compose,注意我这里的pip是anaconda2版本,所以docker-compose会被安装在 ~/anaconda2/bin/docker-compose 中,我没有测试过其它版本的pip。

  3. 生成compose文件
    安装nvidia-docker-compose好后,按顺序执行以下命令,就可以在你的home目录下创建一个目录compose,

    cd
    mkdir compose
    cd compose
    touch docker-compose.yml
    

    用你的editor打开docker-compose.yml,把下面的内容复制进去,保存。

    version: '2'
    services:
      dl:
        image: yiminglin/dl-image
    

    这段话的意思是这个每次运行这个compose文件,我就启用一个service名叫dl,dl只指定了我要run的image是哪个。
    在当前compose目录中,运行

    nvidia-docker-compose -G
    

    会发现文件夹中多了一个nvidia-docker-compose.yml,里面的内容如下:

    services:
      dl:
        devices:
        - /dev/nvidia0
        - /dev/nvidiactl
        - /dev/nvidia-uvm
        - /dev/nvidia-uvm-tools
        image: yiminglin/dl-image
        volumes:
        - nvidia_driver_375.51:/usr/local/nvidia:ro
    version: '2'
    volumes:
      nvidia_driver_375.51:
        external: true
    
    可以看到它只是把我们写的compose文件丰富了一下,加入了nvidia的一些服务。
  4. Pycharm Docker Setting
    在pycharm中新建一个工程,进入File->Setting->Build,Excution,Deployment找到Docker,然后按加号添加一个Docker服务器。注意把Certificates folder 清空,Docker Compose excitable选择你第2步安装的docker-compose

  5. Pycharm工程中添加remote intepreter
    在Setting里选择你的Project Interpreter,点击右边的齿轮,选择 Add Remote

    选择最后一个Docker Compose,按加号添加第3步生成的nvidia-docker-compose.yml文件
    按ok,可以看到Project Interpreter 里多了一个可选的解释器:Remote Python 2.7.12 Docker Compose (dl at [/home/yiming/compose/nvidia-docker-compose.yml])
    按ok后可能需要等待一段时间让pycharm导入所有的skeletons和制作索引。
  6. 测试script
    在你设置好的project里面新增一个python script测试一下你的Docker container中的interpreter吧!
    import tensorflow as tf
    
    
    a = tf.constant(2)
    sess = tf.InteractiveSession()
    
    print "tensorflow version:", tf.__version__
    print "tensorflow output:", sess.run(a)
    
    sess.close()
    
    看到代码补全了吗,有没有很激动??
    Pycharm的输出验证了我们的操作确实调用了GPU:
    2017-05-26 14:56:01.468368: I tensorflow/core/common_runtime/gpu/gpu_device.cc:887] Found device 0 with properties: 
    name: GeForce GTX 1060 3GB
    major: 6 minor: 1 memoryClockRate (GHz) 1.7085
    pciBusID 0000:01:00.0
    Total memory: 2.94GiB
    Free memory: 2.25GiB
    2017-05-26 14:56:01.468385: I tensorflow/core/common_runtime/gpu/gpu_device.cc:908] DMA: 0 
    2017-05-26 14:56:01.468393: I tensorflow/core/common_runtime/gpu/gpu_device.cc:918] 0:   Y 
    2017-05-26 14:56:01.468408: I tensorflow/core/common_runtime/gpu/gpu_device.cc:977] Creating TensorFlow device (/gpu:0) -> (device: 0, name: GeForce GTX 1060 3GB, pci bus id: 0000:01:00.0)
    tensorflow version: 1.1.0
    tensorflow output: 2
    

    如果在脚本还没退出的时候在命令行中运行:
    docker ps
    
    可以看见Pycharm确实run了一个新的docker container, 启动的service就是我们在docker-compose.yml里面指定的 dl 服务,script跑完后该container会自动退出。
  7. 更改环境变量 (for caffe and opencv)
    经过上一步后,pycharm已经能调用你在docker image里面通过pip安装在python文件夹里的packages,但是由于在我的image里面,caffe,caffe2和OpenCV是放在不同目录下的,要让我们的python解释器到docker container里的目录里去找命令,需要我们做手动更改

    点击pycharm主视图的左下角的Docker,在选择/compose_dl_1(如果没有则先运行Docker服务),再在右边选择Environment variables,选择第一个PYTHONPATH,按最右边的铅笔图标,把value改成
    /opt/project:/opt/caffe/python:/opt/caffe2/build:~/opencv/build
    


    按下OK,最后记得按右下角的Save,重启Pycharm。大功告成,phew,现在把测试代码丰富一下,看看我们的新解释器你不能找到Opencv和caffe
    import tensorflow as tf
    import cv2
    import caffe
    import caffe2
    
    a = tf.constant(2)
    sess = tf.InteractiveSession()
    
    print "tensorflow version:", tf.__version__
    print "tensorflow output:", sess.run(a)
    
    sess.close()
    

  8. (optional) Bind your local paths to the container
  9. On Linux, the container is created in an isolated environment and does not share folders with your host machine. If you'd like to load data using the absolute paths, you will have to manually bind the paths on your host to the container created.

    Similar to step 7, select Volume Bindings in the properties of container /compose_dl_1, click the green "+" and add the bindings you need. Since everything is in the home folder in my case, I just bind the home folder to the same place in the container as indicated in the third row in the screenshot below.

    For debugging, carry out the same operations to the container /pycharm_helpers_PY-171.4424.42.



Bonus

这里提供一个完整的Ubuntu装机脚本,对于新装好的Ubuntu只要就可以准备好本教程所有需要的essentials,安装好docker,nvidia-docker, cuda等,下载脚本后只需要一行命令

bash new_ubuntu.sh

Closing thoughts

如果python是深度学习开发的lingua franca,那么Docker应该可以算是开发环境的一个lingua franca,用来搭建代码到硬件的桥梁。开发环境的配置应该是所有理工学生的基本功,但令我惊讶的是,哪怕博士生和博后,配置一个环境也要花上好几天,极其低效。我觉得对docker的利用可以大大减少这些重复劳动,无论你来自industrial还是academic背景。对于industry,针对cloud servers发布的image可以大大减轻甲方系统管理的负担。对于academic的人来说,别人为了测试你发布的源码所花的时间越少,你的work越有可能获得citation。如果你跟我一样被封闭的MATLAB宠坏了,又想进工业界,还是好好磨练基本功吧。

References

PyCharm 2017.1 Help
Configuring Remote Interpreters via Docker Compose
Connect nvidia-docker as remote python interpreter in Pycharm · Issue #303 · NVIDIA/nvidia-docker
How To Use PyCharm Docker Integration with GPU-enabled Containers
编辑于 2017-06-01