写在�前面:本教程对计算机硬件要求�较高,教程中使用了�AWS提供的服务.
训练一个具有大量图像的神经网络会带来一些挑战。即使使用最新的GPU,也不可能在合理的时间内使用单个GPU来训练大型网络。在一台机器中使用多个gpu可以稍微减轻这个问题。但是,可以连接到一台机器上的gpu的数量是有限的(通常为8或16)。本教程解释了如何使用多个包含多个gpu的多台机器来训练大的网络,使用tb级的数据。
Note:This blog without all the resources that are outside the original,reproduced please indicate the source.
官网:mxnet.incubator.apache.org,文中如有任何错漏的地方请谅解并指出,不胜感激.
准备
想与之前�几个教程相似:
- 安装MXNet
- OpenCV python库
$ pip install opencv-python
处理
�磁盘空间
对大数据进行训练的第一步是下载数据并进行预处理。对于本教程,我们将使用完整的ImageNet
数据集。请注意,至少需要2 TB的磁盘空间来下载和预处理这些数据。强烈建议使用SSD
代替HDD
。SSD
更擅长处理大量的小图像文件。在预处理完成并将图像打包成recordIO
文件后,HDD
应该可以接受训练。
在本教程中,我们将使用AWS
存储实例进行数据预处理。存储实例i3.4xlarge
在两个NVMe SSD
磁盘上有3.8 TB
的磁盘空间。我们将使用软件RAID
将它们组合成一个磁盘并在~/data
上挂载它。
sudo mdadm --create --verbose /dev/md0 --level=stripe --raid-devices=2 \
/dev/nvme0n1 /dev/nvme1n1
sudo mkfs /dev/md0
sudo mkdir ~/data
sudo mount /dev/md0 ~/data
sudo chown ${whoami} ~/data
我们现在有足够的磁盘空间来下载和预处理数据。
下载ImageNet
在本教程中,我们将使用完整的ImageNet
数据集,可以从http://www.image-net.org/download-images下载。fall11_whole.tar包含所有的图像。该文件的大小为1.2 TB,需要很长时间才能下载。
下载后,解压文件。
export ROOT=full
mkdir $ROOT
tar -xvf fall11_whole.tar -C $ROOT
这应该会给您一个tar文件的集合。每个tar文件表示一个类别,并包含属于该类别的所有图像。我们可以解压缩每个tar文件并将图像复制到一个以tar文件名称命名的文件夹中。
for i in $ROOT/*.tar; do j=${i%.*}; echo $j; mkdir -p $j; tar -xf $i -C $j; done
rm $ROOT/*.tar
ls $ROOT | head
n00004475
n00005787
n00006024
n00006484
n00007846
n00015388
n00017222
n00021265
n00021939
n00120010
删除不常见的转移学习类(可选)
在ImageNet数据上训练网络的一个常见原因是用于传输学习(包括特征提取或对其他模型进行微调)。根据这项研究,没有图片的类在转移学习上没有帮助。因此,我们可以删除一些少于一定数量图像的类。下面的代码将删除少于500个图像的类。
BAK=${ROOT}_filtered
mkdir -p ${BAK}
for c in ${ROOT}/n*; do
count=`ls $c/*.JPEG | wc -l`
if [ "$count" -gt "500" ]; then
echo "keep $c, count = $count"
else
echo "remove $c, $count"
mv $c ${BAK}/
fi
done
生成验证组
为了确保我们不超过数据,我们将创建一个独立于训练集的验证集。在训练期间,我们将频繁地监视验证集上的损失。我们通过从每个类中挑选50个随机图像并将它们移动到验证集来创建验证集。
VAL_ROOT=${ROOT}_val
mkdir -p ${VAL_ROOT}
for i in ${ROOT}/n*; do
c=`basename $i`
echo $c
mkdir -p ${VAL_ROOT}/$c
for j in `ls $i/*.JPEG | shuf | head -n 50`; do
mv $j ${VAL_ROOT}/$c/
done
done
将图像压缩到记录文件中
虽然MXNet可以直接读取图像文件,但建议将图像文件打包到一个recordIO文件中以提高性能。MXNet提供了一个工具(tools/im2rec.py
)来完成这个任务。要使用这个工具,需要在系统中安装MXNet
和OpenCV
的python
模块。
将环境变量MXNET设置为指向MXNET安装目录,并将其命名为数据集的名称。在这里,我们假设MXNet安装在~/MXNet
中
MXNET=~/mxnet
NAME=full_imagenet_500_filtered
为了创建recordIO文件,我们首先在recordIO文件中创建我们想要的图像列表,然后使用im2rec将列表中的图像打包到recordIO文件中。我们在train_meta
创建这个列表。培训数据在1TB左右。我们把它分成8个部分,每个部分大约有100 GB大小。
mkdir -p train_meta
python ${MXNET}/tools/im2rec.py --list True --chunks 8 --recursive True \
train_meta/${NAME} ${ROOT}
然后我们调整图像大小,使短边是480像素,并将图像打包成recordIO文件。由于大部分工作是磁盘I/O,所以我们使用多个(16)线程来更快地完成工作。
python ${MXNET}/tools/im2rec.py --resize 480 --quality 90 \
--num-thread 16 train_meta/${NAME} ${ROOT}
完成后,我们将rec文件移动到名为train的文件夹中。
mkdir -p train
mv train_meta/*.rec train/
我们对验证集进行类似的预处理。
mkdir -p val_meta
python ${MXNET}/tools/im2rec.py --list True --recursive True \
val_meta/${NAME} ${VAL_ROOT}
python ${MXNET}/tools/im2rec.py --resize 480 --quality 90 \
--num-thread 16 val_meta/${NAME} ${VAL_ROOT}
mkdir -p val
mv val_meta/*.rec val/
现在,我们已经在训练和val目录中分别使用了recordIO格式的训练和验证图像。我们现在可以用这些了.rec
文件训练。
训练
ResNet已经展示了它在ImageNet竞争中的有效性。我们的实验也重现了报告中的结果。当我们将层数从18层增加到152层时,我们看到验证精度的稳步提高。鉴于这是一个巨大的数据集,我们将使用具有152层的Resnet。
由于计算复杂度很高,即使是最快的GPU也需要超过一天的时间来处理数据。在训练收敛到良好的验证精度之前,我们通常需要几十个epoch。虽然我们可以在机器中使用多个gpu,但机器中gpu的数量通常限制在8或16。为了加快训练,在本教程中,我们将使用多个包含多个gpu的机器来训练模型。
设置
我们将使用16台机器(p2.16 x实例),每个机器包含16个gpu(特斯拉K80)。这些机器通过20 Gbps以太网相互连接。
AWS云的形成使得创建深度学习集群非常容易。我们遵循这个页面的指示,并创建一个具有16个p2.16 x实例的深度学习集群。
我们在第一个机器中加载数据和代码(我们将此机器称为master)。我们将数据和代码共享给其他使用EFS的机器。
如果您正在手动设置集群,而不使用AWS cloud编组,请记住以下步骤:
使用USE_DIST_KVSTORE = 1编译MXNet,以支持分布式培训。
在master中创建一个包含所有集群机器主机名的主机文件。例如,
$ head -3 hosts
deeplearning-worker1
deeplearning-worker2
deeplearning-worker3
通过从文件中调用ssh,可以通过调用ssh来从主ssh到这些机器中的任何一个。例如,
$ ssh deeplearning-worker2
===================================
Deep Learning AMI for Ubuntu
===================================
...
ubuntu@ip-10-0-1-199:~$
其中一种方法是使用ssh
代理转发。请查看本页,了解如何设置。简而言之,您将使用本地机器上的特定证书(mycert.pem
)配置所有计算机登录。然后使用证书和-a
开关登录到主服务器,以启用代理转发。现在,您应该能够通过提供主机名(例如ssh
深度学习- worker2
)登录到集群中的任何其他机器。
运行训练
在集群设置之后,从$ {MXNET}/example/image
分类中登录到master
并运行以下命令
../../tools/launch.py -n 16 -H $DEEPLEARNING_WORKERS_PATH python train_imagenet.py --network resnet \
--num-layers 152 --data-train ~/data/train --data-val ~/data/val/ --gpus 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 \
--batch-size 8192 --model ~/data/model/resnet152 --num-epochs 1 --kv-store dist_sync
launch.py运行集群中所有机器中提供的命令。集群中机器的列表必须通过- h
开关向launch.py提供。这里是用于launch. py的选项的描述。
train_imagenet.py
使用--data-train
和 --data-val
选项提供的数据来训练--network
选项提供的网络。这里是train_imagenet.py
中使用的选项的描述。
训练完成后,--model
选项指定目录中可用的已经训练的模型。模型被保存在两个部分:定义网络的model-symbol.json
和n
次训练后保存参数的model-n.params
。
可伸缩性
使用大量机器进行训练的一个常见问题是可伸缩性。我们在集群上运行几个流行的网络,有多达256个gpu,而且速度非常接近理想。
这个可伸缩性测试运行在16个p2.16 xl的实例上,总共有256个gpu。我们使用了AWS深度学习AMI和CUDA 7.5和CUDNN 5.1安装。
我们固定了每GPU的批量大小,并在以后的测试中增加GPU的数量。同步的SGD(- kv-store dist_device_sync)被使用。所使用的CNNs在这里。
每秒处理的图像数如下表所示:
下图显示了对使用的gpu数量的加速,并将其与理想的加速进行比较。
故障排除指南
验证准确性
实现一个合理的验证精度通常很简单,但要达到报告中所报告的最先进的数字有时是非常困难的。这里有几件事你可以试着提高验证的准确性。
- 增加更多的数据增强通常会减少训练和确认准确度之间的差距。数据增加可以在更接近尾声的时期减少。
- 从一个大的学习速率开始,并保持长时间的学习。例如,在CIFAR10中,您可以将第一个200次训练的学习速率保持在0.1,然后将其降低到0.01。
- 不要使用规模太大的批处理大小,特别是批大小> >的类。
速度
- 分布式培训提高了批量计算成本的速度。所以,要确保你的工作量不是太小(就像在MNIST上的LeNet一样)。确保批量大小相当大。
- 确保数据读取和预处理不是瓶颈。使用
——test-io 1
标志检查每秒处理多少图像。 - 增加- data- nthreads(默认值是4)以使用更多的线程来进行数据预处理。
- 数据预处理是由opencv完成的。如果opencv是从源代码编译的,请检查它是否配置正确。
- 使用
--benchmark 1
使用随机生成的数据,而不是实际数据,以缩小瓶颈所在的位置。 - 查看此页面了解更多细节。
内存
如果批大小太大,就会耗尽GPU
内存。如果发生这种情况,您将看到错误消息“cudaMalloc failed:out of memory”
或类似的东西。有几种方法可以解决这个问题:
- 减少批量大小。
- 将环境变量
MXNET_BACKWARD_DO_MIRROR
设置为1。它通过降低速度来减少内存消耗。例如,在批处理大小为64的情况下,incepa- v3
使用10G内存,在一个K80 GPU
上训练30个图像/秒。当镜像启用时,使用10G GPU内存消耗,我们可以使用128的批大小运行incepa - v3。成本大致是这样,速度降低到27张图片/秒。