深度学习环境在Docker上搭建(基于Linux和WSL)
一、深度学习环境配置选择
在深度学习领域,配置环境的常见做法是使用conda来实现环境隔离。conda是一个广泛使用的工具,用于创建和管理特定的环境,通过在不同的环境中设置特定的Python环境变量路径,实现了环境的特异化。为了实现这一目的,需要将终端置于conda的管理之下。如果你已经安装了conda,你可能已经注意到在bash中需要执行conda init bash
(在Windows上则是conda init pwsh
)来初始化conda的bash或powershell配置。
Docker作为一种虚拟化技术,利用镜像作为基础配置,可以轻松地创建和管理容器。容器是一种轻量级的虚拟化技术,使得应用程序及其依赖可以在独立的运行环境中运行,而不会影响宿主操作系统或其他容器。Docker的出现为服务器管理带来了新的可能性。通过使用容器化技术,我们可以更加灵活地组织和运行应用程序,实现更高效、可靠的服务器管理。越来越多的服务器使用了Docker进行管理,我们就有必要学习一下相关知识。
这里介绍使用Docker作为深度学习环境的配置方法,配置上手比conda多了一点点难度,但是在使用上却方便了很多。
二、为什么使用 Docker 配置深度学习环境
作者的原因是这样的:
在Windows上编写代码,但是并不想破坏电脑的原有环境。服务器资源并不能完全给作者独占太久的时间,因此写完后希望能在本地的Windows电脑上进行Debug和训练时间评估。训练仍然是服务器上训练,但是服务器是Linux环境,希望保持环境的一致性,并不想因为Windows和Linux的差异影响代码运行,更专注于代码而不是环境差异性。conda似乎也能实现上述部分要求,但是如果需要不同版本的cuda环境,就无能为力了。比如作者之前遇到过服务器cuda版本不允许降级,但是安装mindspore框架在高版本的cuda下频繁报错。不推荐使用Docker的几个方面
使用Docker作为深度学习环境,首先你的服务器上存在Docker,这样才有意义。如果服务器没有Docker,而是conda环境,完全没必要学习Docker做自己的开发环境。使用Docker作为深度学习环境,需要了解制作Docker镜像,和保存镜像的命令。作者在Windows上首先搭建了一个基础镜像,然后通过SSH连进容器中。配置好环境之后,通过docker commit
保存当前容器为新的镜像,再通过docker save
导出迁移到服务器上。进阶版还需要掌握Dockerfile的语法,如果你觉得这个过程很难理解,也没有必要学习Docker作开发环境。 在硬件方面,首先,在 WSL2 的发布之前,Docker 在 Windows 上完全是以虚拟机的形式实现的,这意味着不小的性能损耗,并且不支持 GPU 的调用,想用 Docker 在 Windows 平台炼丹的复杂程度堪比登天。WSL2 作为微软拥抱 Linux 社区的一份贡献,使得 Docker 现在完全可以通过 WSL2 来原生运行。
在 Win11 环境中大约有 66% 在 Ubuntu2004 中的机器学习速度,而在 WSL2 中则有 80% 的在Ubuntu2004 中的机器学习速度。使用Docker的炼丹更快!
其次,Docker 是跨平台的,如果 80% 的炼丹速度对你有困扰,完全可以在将你的 Docker 炼丹环境上传到云端,在 Linux 服务器上安装 Docker 之后,再从云端拉取下来,完全可以像 Git 使用代码一样使用深度学习环境。使用 Docker 的跨平台兼容性更好!
最后,使用 Conda 配置 Cuda 炼丹环境,通常情况下除去 Conda 不说,还需要安装 Nvidia 显卡驱动,还有cudatools 包、cudnn 包等等。这些包体积都很大,而且服务器都在国外,下载速度很堪忧。而 Docker 的镜像已经包含了这些包,只需要等待 Docker 镜像下载完成,就能实现开箱即用。使用 Docker 搭建环境速度块!
Conda 和 Docker 环境搭建流程:
另一个是 Windows 的 Hyper-V 功能开启,这个功能默认是关闭的。(注意,台式机主板重置后会默认关闭)
WSL2 安装就比较简单了,直接在 Microsoft Store 中直接搜索 Windows Subsystem for Linux 安装。
再安装你喜欢的 Linux 发行版,写者使用的是 Ubuntu20.04 LTS, 与写者在实验室的环境一致,方便后期到服务器运行代码。这里注意,配置完账户和密码后,一般是不需要进 WSL 内部继续设置了。
安装 Docker Desktop ,这里是官网下载:Docker Desktop release notes | Docker Documentation;
如果有其他安装问题,这是官方指导文档:Install Docker Desktop on Windows | Docker Documentation;
拉取镜像
docker镜像提倡精简,也同时意味着少了很多必要的库,报错缺少库依赖也很常见。当然作者早就为深度学习定制了更好用的镜像,作者使用的镜像相关信息在 DockerHub可以查询到,镜像相应的 DockerFile 在 GitHub 上也可以查到。
//无conda,基于cuda12.0内置了pytorch2.0。 //镜像由于预装好了pytorch2.0,体积比较大,约9.35GB docker pull mortals/codeenv:pytorch2.0-cuda12.0 //预装miniconda,基于cuda12.0,无pytorch //镜像体积约4.85GB docker pull mortals/codeenv:conda-cuda12.0 //同时约有基于cuda11.8的镜像 //镜像体积约为3.78GB docker pull mortals/codeenv:conda-cuda11.8
作者在镜像中提供了两个方便的脚本sshstart.sh
和jupyter.sh
,分别用来配置SSH服务自启动和开启Jupyter服务。使用这两个脚本请提前在容器配置对应的端口映射。SSH服务端口为22,Jupyter服务端口在8888
docker run -it -v D:/project:/opt/project -p 8822:22 -p 6006:6006 -p 8888:8888 --gpus all --shm-size 16G --restart=always mortals/codeenv:pytorch2.0-cuda12.0 /bin/bash
如果上述镜像仍不能满足你的需求,可以从Github获取作者的Dockerfile,修改镜像的系统版本,然后自行编译。
FROM nvidia/cuda:11.8.0-devel-ubuntu20.04
Windows Docker常见问题:
怎么处理Windows下与WSL虚拟机数据穿透。
可以直接把数据复制到WSL中,Docker主要是Linux平台的虚拟化,因此WSL中IO性能损失小。也可以利用Docker的挂载选项,将数据集所在的Windows文件夹映射到Docker中。作者这里时这样用的-v D:\project:/opt/project
Windows中安装的Docker和在WSL中安装的Docker有什么区别,在Windos中安装过Docker后还需要在WSL中安装吗?
Docker Desktop在2021年推出了WSL整合的版本,也就是说Windows的Docker调用的是WSL中Linux 发行版的Docker。在Windos中安装过Docker后不需要在WSL中安装。
Windows 中需要安装nvidia-docker吗?
不需要。Docker 19版本之后,就可以原生支持GPU调用,过去GPU Docker所需要的Runtime被集成到Docker中了,使用时只需要添加--gpus
参数来控制。这里可能会出现添加完--gpus all
参数,将所有GPU都分配给容器,仍然无法使用GPU,或者nvidia-smi
成功运行,但是无法调用GPU进行训练。需要添加容器的环境变量NVIDIA_DRIVER_CAPABILITIES=compute,utility
和NVIDIA_VISIBLE_DEVICES=all
WSL有没有图形界面(GUI)
有,WSLg项目,可以自行搜索。但是这里作者觉得没啥用。
开启远程Docker
可选(但是不推荐):如果希望远程链接 Docker 容器,则需要勾选 Docker Desktop 中设置/General/Expose daemon on tcp://localhost:2375 without TLS;
开启 Docker 远程链接
但是作者发现,仅能使用 tcp://localhost:2375 访问,就算是本机局域网 IP 都无法连接到。那么我们可以使用端口转发,并在防火墙中开启这个端口。管理员权限打开 CMD 使用以下指令修改:(注意修改your-public-ip)
netsh interface portproxy add v4tov4 listenport=2375 connectaddress=127.0.0.1 connectport=2375 listenaddress=<your-public-ip> protocol=tcp
如果不用这个 IP ,管理员权限打开 CMD 使用以下指令删除端口转发 :(注意修改your-public-ip)
netsh interface portproxy delete v4tov4 listenaddress=192.168.191.6 listenport=2375
最后如果发现不能访问,打开防火墙端口:
netsh advfirewall firewall add rule name="docker_daemon" dir=in action=allow protocol=TCP localport=2375
四、在 PyCharm 使用 Docker 环境
添加Docker服务
在插件中安装 Docker 插件(默认捆绑)。注意,这里需要 PyCharm 专业版,社区版的 Docker 支持不完整。
添加 Docker 连接。在左下角边栏有“服务”(service)选项,选中该选项中顶部 “+”选项
添加 Docker 连接,弹出菜单对话框,Windows 默认使用 Docker for WIndows,Linux 可以使用 Unix socket点击确定;如果是远程链接,使用 tcp 套接字,填入自己的ip后,点击确定。
新建 Docker 连接
添加 Docker 注册表 ,这个是为了添加自己的 Docker 账户,拉去和推送镜像更方便。
容器管理
Docker容器可以通过命令行进行管理:
docker run -it -v D:/project:/opt/project -p 8822:22 -p 6006:6006 -p 8888:8888 --gpus all --shm-size 16G --restart=always mortals/codeenv:pytorch2.0-cuda12.0 /bin/bash
也可以预设PyCharm的配置来管理,最后完成之后的配置结果如下图:
Python解释器添加
添加 Docker 镜像的 Python 编译器。点击右下角的编译器名字,可以添加解释器。
添加容器中SSH的Python解释器
这里作者更推荐使用SSH连接容器,方便配置环境,以及运行程序。
这里选择系统解释器,并找到你的系统解释器路径。如果是使用作者的镜像conda-cuda11.8
,那么请先在容器内创建环境之后,再添加下图中的"系统解释器",路径为/opt/conda/envs/环境名称/bin/python3
,请注意配置好你的同步文件夹路径,不然你的代码就无法正常同步。
添加Docker的Python解释器
如果使用Docker请按照下面这个步骤:
因为之前已经连接过了 Docker ,因此可以在这里选择”拉取或使用现有内容“,之后点击确定就可以完成了。
这里选择系统解释器,并找到你的系统解释器路径。如果是使用作者的镜像conda-cuda11.8
,那么请先在容器内创建环境之后,再添加下图中的"Conda环境",路径为/opt/conda/envs/环境名称/bin/python3
。
这样在你的Python解释器列表中就存在这些编译器了。
Run配置
如果使用SSH的Python编译器,只需要选择默认编译器为指定编译器即可。
如果想直接使用Docker作为Python解释器,可以参考作者的设置(这需要上一步你的Docker环境配置好,不然还是建议通过SSH连接如容器中使用)。
到此位置,Docker 深度学习环境已经可以使用了。
附注:在 WSL2 中 Docker 调用 Nvidia GPU 使用 CUDA 训练模型
在很多几年前的博客和教程中,大多数是安装使用 nvidia-docker 来调用GPU,然后如果是在 WSL 中还需要安装 Nvidia 显卡的 CUDA 驱动。
作者在多日的研究 WSL2 和 Docker 文档中,发现 WSL2 已经可以透传 GPU 使用。也就是在 Windows 安装过Nvidia 驱动之后,直接可以在 WSL2 中使用 GPU,可以测试 nvidia-smi 来查看驱动。由于驱动向后兼容,尽量把驱动升级到最新,这样支持的 CUDA 的相关工具更多,尽量避免使用容器中的 CUDA 工具包不兼容出现的奇奇怪怪的 bug 。
Docker 19版本之后,就可以原生支持GPU调用,过去GPU Docker所需要的Runtime被集成到Docker中了,使用时只需要添加--gpus
参数来控制。这里可能会出现添加完--gpus all
参数,将所有GPU都分配给容器,仍然无法使用GPU,或者nvidia-smi
成功运行,但是无法调用GPU进行训练。需要添加容器的环境变量NVIDIA_DRIVER_CAPABILITIES=compute,utility
和NVIDIA_VISIBLE_DEVICES=all
Docker 也支持了 WSL2 GPU 透传,这就不需要再专门下载 Nvidia-docker ,使用方法就是加入运行参数--gpus
WSLg 支持
这是 Linux 原生图形化支持。需要将 \wsl$\Ubuntu-20.04\mnt\wslg.X11-unix\ 映射到 /tmp/.X11-unix。(这里是路径选择方式)