本文采用知识共享署名 4.0 国际许可协议进行许可,转载时请注明原文链接,图片在使用时请保留全部内容,可适当缩放并在引用处附上图片所在的文章链接。
文章目录
硬件环境
处理器:AMD® Ryzen 5 3600 6-core processor × 12
显卡:NVIDIA Corporation TU104 [GeForce RTX 2060]
内存:16G DDR4
硬盘:1T SSD
系统:Ubuntu 20.04.1 LTS
深度学习开发环境搭建docker
Docker
Docker 是一个开源的应用容器引擎,基于 go语言并遵从 Apache2.0 协议开源。
Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。
容器是完全使用沙箱机制,相互之间不会有任何接口(类似 iPhone 的 app),更重要的是容器性能开销极低。
NVIDIA Docker 安装
- docker安装 官网上有详细的介绍:Install Docker Engine on Ubuntudocs.docker.com 或者运行下面的命令安装:
sudo apt-get update
sudo apt-get install docker.io
systemctl start docker
systemctl enable docker
可以运行这条命令检查是否安装成功:
docker version
- 安装NVIDIA Container Toolkit
#首先要确保已经安装了
nvidia driver
# 2. 添加源 distribution=$(. /etc/os-release;echo $ID$VERSION_ID) curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add - curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | sudo tee /etc/apt/sources.list.d/nvidia-docker.list
# 2. 安装并重启 sudo apt-get update && sudo apt-get install -y nvidia-container-toolkit sudo systemctl restart docker
sudo docker run -it --name test_nvidia_docker --gpus all nvidia/cuda:11.0-base
其中最后的参数nvidia/cuda:11.0-base 是Nvidia官方的镜像,需要根据工作站主机中实际安装的cuda版本进行修改,版本可以用nvcc -V查看。
进入容器之后可以跑一下nvidia-smi命令看看:
Mon Jan 18 22:59:37 2021
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 450.102.04 Driver Version: 450.102.04 CUDA Version: 11.0 |
|-------------------------------+----------------------+----------------------+
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
| | | MIG M. |
|===============================+======================+======================|
| 0 GeForce RTX 2060 Off | 00000000:26:00.0 On | N/A |
| 0% 41C P8 8W / 160W | 947MiB / 5931MiB | 5% Default |
| | | N/A |
+-------------------------------+----------------------+----------------------+
+-----------------------------------------------------------------------------+
| Processes: |
| GPU GI CI PID Type Process name GPU Memory |
| ID ID Usage |
|=============================================================================|
+-----------------------------------------------------------------------------+
Docker基本使用
启动已停止运行的容器
查看所有的容器命令如下:
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e8240c787e2f nvidia/cuda:11.0-base "/bin/bash" 26 minutes ago Exited (0) 52 seconds ago train_mnist
ae3d00922c08 nvidia/cuda:11.0-base "/bin/bash" 37 hours ago Exited (0) 37 hours ago test_nvidia_docker
使用 docker start 启动一个已停止的容器:
$ docker start ae3d00922c08
zyh@zyh:~$ sudo docker start ae3d00922c08
ae3d00922c08
停止一个容器
停止容器的命令如下:
$ docker stop <容器 ID>
停止的容器可以通过 docker restart 重启:
$ docker restart <容器 ID>
进入容器
在使用 -d 参数时,容器启动后会进入后台。此时想要进入容器,可以通过以下指令进入:
- docker attach
- docker exec:推荐大家使用 docker exec 命令,因为此退出容器终端,不会导致容器的停止。
attach 命令
下面演示了使用 docker attach 命令。
$ docker attach e8240c787e2f
注意: 如果从这个容器退出,会导致容器的停止。
exec 命令
下面演示了使用 docker exec 命令。
docker exec -it e8240c787e2f /bin/bash
注意: 如果从这个容器退出,容器不会停止,这就是为什么推荐大家使用 docker exec 的原因。
更多参数说明请使用 docker exec --help 命令查看。
导出和导入容器
导出容器
如果要导出本地某个容器,可以使用 docker export 命令。
$ docker export e8240c787e2f > train_mnist.tar
导出容器 e8240c787e2f 快照到本地文件 train_mnist.tar。
这样将导出容器快照到本地文件。
导入容器快照
可以使用 docker import 从容器快照文件中再导入为镜像,以下实例将快照文件 ubuntu.tar 导入到镜像 test/ubuntu:v1:
$ cat docker/train_mnist.tar | docker import - test/train_mnist:v1
此外,也可以通过指定 URL 或者某个目录来导入,例如:
$ docker import http://example.com/exampleimage.tgz example/imagerepo
删除容器
删除容器使用 docker rm 命令:
$ docker rm -f ae3d00922c08
下面的命令可以清理掉所有处于终止状态的容器。
$ docker container prune
拷贝本地文件到docker
-
查找容器
docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES e8240c787e2f nvidia/cuda:11.0-base "/bin/bash" 42 minutes ago Up 8 minutes train_mnist
-
确定我们的容器名,并获取容器长ID
docker inspect -f '{{.ID}}' train_mnist
zyh@zyh:~/temp$ sudo docker inspect -f '{{.ID}}' train_mnist e8240c787e2fde06a3f1066db71bc63cb52514c3cb0175d51713f248a2e2b56c
-
复制文件
sudo docker cp /home/zyh/temp/cuda_11.0.2_450.51.05_linux.run e8240c787e2fde06a3f1066db71bc63cb52514c3cb0175d51713f248a2e2b56c:/home/zyh
docker 训练模型
-
创建docker
sudo docker run -it --name train_mnist \ -v /etc/timezone:/etc/timezone \ -v /etc/localtime:/etc/localtime \ -v /home/zyh/WorkSpace/_share:/home/workspace/_share \ --gpus all nvidia/cuda:11.0-base
-
查看 nvidia 驱动
nvidia-smi
-
安装 cuda
sudo sh ./cuda_11.0.2_450.51.05_linux.run
配置环境变量
vim ~/.bashrc export CUDA_HOME=/usr/local/cuda-11.0 export LD_LIBRARY_PATH=${CUDA_HOME}/lib64 export PATH=${CUDA_HOME}/bin:${PATH} source ~/.bashrc
查看安装版本
nvcc -V
-
安装 CuDNN
tar -xzvf cudnn-11.0-linux-x64-v8.0.5.39.tgz sudo cp cuda/lib64/* /usr/local/cuda-11.0/lib64/ sudo cp cuda/include/* /usr/local/cuda-11.0/include/
查看 CUDNN的版本
cat /usr/local/cuda/include/cudnn_version.h | grep CUDNN_MAJOR -A 2
-
安装conda
chmod +x Anaconda3-2020.11-Linux-x86_64.sh ./Anaconda3-2020.11-Linux-x86_64.sh
-
测试
创建 python3.8+pytorch1.7+cuda11.0的虚拟环境
conda create --name python_38-pytorch_1.7.0 python=3.8
进入环境
conda activate python_38-pytorch_1.7.0
安装pytorch
pip install torch==1.7.0+cu110 torchvision==0.8.1+cu110 torchaudio===0.7.0 -f https://download.pytorch.org/whl/torch_stable.html
测试文件
import argparse import torch import torch.nn as nn import torch.nn.functional as F import torch.optim as optim from torchvision import datasets, transforms class Net(nn.Module): def __init__(self): super(Net, self).__init__() self.conv1 = nn.Conv2d(1, 20, 5, 1) self.conv2 = nn.Conv2d(20, 50, 5, 1) self.fc1 = nn.Linear(4 * 4 * 50, 500) self.fc2 = nn.Linear(500, 10) def forward(self, x): x = F.relu(self.conv1(x)) x = F.max_pool2d(x, 2, 2) x = F.relu(self.conv2(x)) x = F.max_pool2d(x, 2, 2) x = x.view(-1, 4 * 4 * 50) x = F.relu(self.fc1(x)) x = self.fc2(x) return F.log_softmax(x, dim=1) def train(args, model, device, train_loader, optimizer, epoch): model.train() for batch_idx, (data, target) in enumerate(train_loader): data, target = data.to(device), target.to(device) optimizer.zero_grad() output = model(data) loss = F.nll_loss(output, target) loss.backward() optimizer.step() if batch_idx % args.log_interval == 0: print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format( epoch, batch_idx * len(data), len(train_loader.dataset), 100. * batch_idx / len(train_loader), loss.item())) def test(args, model, device, test_loader): model.eval() test_loss = 0 correct = 0 with torch.no_grad(): for data, target in test_loader: data, target = data.to(device), target.to(device) output = model(data) # sum up batch loss test_loss += F.nll_loss(output, target, reduction='sum').item() # get the index of the max log-probability pred = output.argmax(dim=1, keepdim=True) correct += pred.eq(target.view_as(pred)).sum().item() test_loss /= len(test_loader.dataset) print('\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format( test_loss, correct, len(test_loader.dataset), 100. * correct / len(test_loader.dataset))) def main(): parser = argparse.ArgumentParser(description='PyTorch MNIST Example') parser.add_argument('--batch-size', type=int, default=64, metavar='N', help='input batch size for training (default: 64)') parser.add_argument('--test-batch-size', type=int, default=1000, metavar='N', help='input batch size for testing (default: 1000)') parser.add_argument('--epochs', type=int, default=10, metavar='N', help='number of epochs to train (default: 10)') parser.add_argument('--lr', type=float, default=0.01, metavar='LR', help='learning rate (default: 0.01)') parser.add_argument('--momentum', type=float, default=0.5, metavar='M', help='SGD momentum (default: 0.5)') parser.add_argument('--no-cuda', action='store_true', default=False, help='disables CUDA training') parser.add_argument('--seed', type=int, default=1, metavar='S', help='random seed (default: 1)') parser.add_argument('--log-interval', type=int, default=10, metavar='N', help='how many batches to wait before logging training status') parser.add_argument('--save-model', action='store_true', default=False, help='For Saving the current Model') args = parser.parse_args() use_cuda = not args.no_cuda and torch.cuda.is_available() torch.manual_seed(args.seed) device = torch.device("cuda" if use_cuda else "cpu") kwargs = {'num_workers': 1, 'pin_memory': True} if use_cuda else {} train_loader = torch.utils.data.DataLoader( datasets.MNIST('./data', train=True, download=True, transform=transforms.Compose([ transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,)) ])), batch_size=args.batch_size, shuffle=True, **kwargs) test_loader = torch.utils.data.DataLoader( datasets.MNIST('./data', train=False, transform=transforms.Compose([ transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,)) ])), batch_size=args.test_batch_size, shuffle=True, **kwargs) model = Net().to(device) optimizer = optim.SGD(model.parameters(), lr=args.lr, momentum=args.momentum) for epoch in range(1, args.epochs + 1): train(args, model, device, train_loader, optimizer, epoch) test(args, model, device, test_loader) if (args.save_model): torch.save(model.state_dict(), "mnist_cnn.pt") if __name__ == '__main__': main()