此处给出了基于 NGC PyTorch 实现的 Bert Base Pre-Training 任务的详细复现流程,包括执行环境、PyTorch版本、环境搭建、复现脚本、测试结果和测试日志。
我们使用了同一个物理机环境,对 NGC PyTorch 的 Bert 模型进行了测试,详细物理机配置,见Paddle Bert Base 性能测试。
-
单机V100(单卡、8卡)
- 系统:CentOS release 7.5 (Final)
- GPU:Tesla V100-SXM2-32GB * 8
- CPU:Intel(R) Xeon(R) Gold 6271C CPU @ 2.60GHz * 80
- Driver Version: 525.60.11
- 内存:630 GB
-
单机A100(单卡、8卡)
-
系统:CentOS release 7.5 (Final)
-
GPU:NVIDIA A100-SXM4-40GB * 8
-
CPU:Intel(R) Xeon(R) Gold 6148 CPU @ 2.40GHz * 160
-
Driver Version: 525.60.13
-
内存:1510 GB
-
多机(32卡)
- 系统:CentOS release 6.3 (Final)
- GPU:Tesla V100-SXM2-32GB * 8
- CPU:Intel(R) Xeon(R) Gold 6271C CPU @ 2.60GHz * 48
- Driver Version: 450.80.02
- 内存:502 GB
NGC PyTorch 的代码仓库提供了自动构建 Docker 镜像的的 shell 脚本,
- 镜像版本:
nvcr.io/nvidia/pytorch:21.11-py3
- PyTorch 版本:
1.11.0a0+b6df043
- CUDA 版本:
11.0.167
- cuDnn 版本:
8.3.0.96
我们遵循了 NGC PyTorch 官网提供的 Quick Start Guide 教程搭建了测试环境,主要过程如下:
-
拉取代码
git clone https://github.com/NVIDIA/DeepLearningExamples cd DeepLearningExamples/PyTorch/LanguageModeling/BERT # 本次测试是在如下版本下完成的: git checkout fc9c09b08d6d39fb13c79c8a7e08f85b03dbf3d1
-
构建镜像
bash scripts/docker/build.sh # 构建镜像 bash scripts/docker/launch.sh # 启动容器
我们将
launch.sh
脚本中的docker
命令换为了nvidia-docker
启动的支持 GPU 的容器,其他均保持不变,脚本如下:#!/bin/bash CMD=${1:-/bin/bash} NV_VISIBLE_DEVICES=${2:-"all"} DOCKER_BRIDGE=${3:-"host"} nvidia-docker run --name test_bert_torch -it \ --net=$DOCKER_BRIDGE \ --shm-size=1g \ --ulimit memlock=-1 \ --ulimit stack=67108864 \ -e LD_LIBRARY_PATH='/workspace/install/lib/' \ -v $PWD:/workspace/bert \ -v $PWD/results:/results \ bert $CMD
-
准备数据
NGC PyTorch 提供单独的数据下载和预处理脚本 data/create_datasets_from_start.sh。在容器中执行如下命令,可以下载和制作
wikicorpus_en
的 hdf5 数据集。bash data/create_datasets_from_start.sh wiki_only
由于数据集比较大,且容易受网速的影响,上述命令执行时间较长。因此,为了更方便复现竞品的性能数据,我们提供了已经处理好的 seq_len=128 的 hdf5 格式样本数据集,共100个 part hdf5 数据文件,约 3.1G。
数据下载后,会得到一个
hdf5_lower_case_1_seq_len_128_max_pred_20_masked_lm_prob_0.15_random_seed_12345_dupe_factor_5.tar.gz
压缩文件:# 解压数据集 tar -xzvf benchmark_sample_hdf5_lower_case_1_seq_len_128_max_pred_20_masked_lm_prob_0.15_random_seed_12345_dupe_factor_5.tar.gz # 放到 data/ 目录下 mv benchmark_sample_hdf5_lower_case_1_seq_len_128_max_pred_20_masked_lm_prob_0.15_random_seed_12345_dupe_factor_5 bert/data/
修改 scripts/run_pretraining.sh脚本的
DATASET
变量为上述数据集地址即可。
为了更准确的测试 NGC PyTorch 在 NVIDIA DGX-1 (8x V100 32GB)
上的性能数据,我们严格按照官方提供的模型代码配置、启动脚本,进行了的性能测试。
官方提供的 scripts/run_pretraining.sh 执行脚本中,默认配置的是两阶段训练。我们此处统一仅执行 第一阶段训练,并根据日志中的输出的数据计算吞吐。
重要的配置参数:
- train_batch_size: 用于第一阶段的单卡总 batch_size, 单卡每步有效
batch_size = train_batch_size / gradient_accumulation_steps
- precision: 用于指定精度训练模式,fp32 或 fp16
- use_xla: 是否开启 XLA 加速,我们统一开启此选项
- num_gpus: 用于指定 GPU 卡数
- gradient_accumulation_steps: 每次执行 optimizer 前的梯度累加步数
- BERT_CONFIG: 用于指定 base 或 large 模型的参数配置文件 (line:49)
- bert_model: 用于指定模型类型,默认为
bert-large-uncased
由于官方默认给出的是支持两阶段训练的 Bert Large 模型的训练配置,若要测Bert Base模型,需要对 run_pretraining.sh
进行如下改动:
-
在
bert
项目根目录新建一个bert_config_base.json
配置文件,内容如下:{ "attention_probs_dropout_prob": 0.1, "hidden_act": "gelu", "hidden_dropout_prob": 0.1, "hidden_size": 768, "initializer_range": 0.02, "intermediate_size": 3072, "max_position_embeddings": 512, "num_attention_heads": 12, "num_hidden_layers": 12, "type_vocab_size": 2, "vocab_size": 30522 }
-
修改
run_pretraining.sh
的第39行内容为:BERT_CONFIG=bert_config_base.json
-
修改
run_pretraining.sh
的第110行内容为:CMD+=" --bert_model=bert-base-uncased"
-
由于不需要执行第二阶段训练,故需要注释
run_pretraining.sh
的第154行到最后,即:#Start Phase2 # PREC="" # if [ "$precision" = "fp16" ] ; then # PREC="--fp16" # ......(此处省略中间部分) # echo "finished phase2"
同时,为了更方便地测试不同 batch_size、num_gpus、precision组合下的 Pre-Training 性能,我们单独编写了 run_benchmark.sh
脚本,并放在scripts
目录下。
-
shell 脚本内容如下:
#!/bin/bash set -x batch_size=$1 # batch size per gpu num_gpus=$2 # number of gpu precision=$3 # fp32 | fp16 gradient_accumulation_steps=$(expr 67584 \/ $batch_size \/ $num_gpus) train_batch_size=$(expr 67584 \/ $num_gpus) # total batch_size per gpu train_steps=${4:-250} # max train steps # NODE_RANK主要用于多机,单机可以不用这行。 export NODE_RANK=`python get_mpi_rank.py` # 防止checkpoints冲突 rm -rf results/checkpoints # run pre-training bash scripts/run_pretraining.sh $train_batch_size 6e-3 $precision $num_gpus 0.2843 $train_steps 200 false true true $gradient_accumulation_steps
注:由于原始 global_batch_size=65536 对于 batch_size=48/96 时出现除不尽情况。因此我们按照就近原则,选取 67584 作为 global_batch_size.
计算公式:global_batch_size = batch_size_per_gpu * num_gpu * num_accumulation_steps -
单卡启动脚本:
若测试单机单卡 batch_size=96、FP32 的训练性能,执行如下命令:
bash scripts/run_benchmark.sh 96 1 fp32 20
-
8卡启动脚本:
若测试单机8卡 batch_size=96、FP16 的训练性能,执行如下命令:
bash scripts/run_benchmark.sh 96 8 fp16 20
基础配置和上文所述的单机配置相同,多机这部分主要侧重于多机和单机的差异部分。
-
简介
NGC Pytorch是使用Pytorch的自带的
torch.distributed.launch
来启动单机多卡的。为了支持多机多卡,需要把多机的参数传递给launch脚本,修改为:python3 -m torch.distributed.launch --nproc_per_node=$num_gpus --nnodes ${NUM_NODES} \ --node_rank=${NODE_RANK} --master_addr=${MASTER_NODE} --master_port=${MASTER_PORT} $CMD
我们需要把环境变量
${NUM_NODES}
${NODE_RANK}
${MASTER_NODE}
${MASTER_PORT}
传递给run_pretraining.sh
脚本,即可在单机的基础上完成多机的启动。 -
多机启动脚本
$mpirun
命令请参考这里# fp32 echo "begin run bs:96 fp32 on 32 gpus" $mpirun bash ./run_benchmark.sh 96 32 fp32 # fp16 echo "begin run bs:96 fp16 on 32 gpus" $mpirun bash ./run_benchmark.sh 96 32 fp16
卡数 | FP32(BS=96) | AMP(BS=96) |
---|---|---|
1 | 158.611 | 639.16 |
8 | 1232.11 | 5055.56 |
32 | 3496.94 | 16610.6 |
卡数 | FP32(BS=128) | AMP(BS=128) |
---|---|---|
1 | 873.714 | 1542.296 |
8 | 6846.0356 | 12075.6292 |