全自动调参环境部署

全自动调参环境部署

昨天终于完成了 snode5 上的全自动调参环境部署,目前 docker + fitlog 调参体验良好(雾),记录一下过程。

先安装 nvidia-container-toolkit 提供容器中的 GPU 支持:

1
2
3
4
5
6
7
# Add the package repositories
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

sudo apt-get update && sudo apt-get install -y nvidia-container-toolkit
sudo systemctl restart docker

根据自己的 NVIDIA driver 版本以及对应的 pytorch 需要的 CUDA 版本选择正确的 CUDA 镜像,然后拉取:

1
docker pull nvidia/cuda:10.0-base

测试是否安装成功:

1
2
#### Test nvidia-smi with the latest official CUDA image
docker run --gpus all nvidia/cuda:10.0-base nvidia-smi

之后可以启动一个容器,并在容器里配置 pytorch 环境:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
### 启动一个容器,-i 交换模式 -t 启动一个终端 -d 后台运行,此时默认不会进入容器 -p 跟主机进行端口映射,之后会用到 --gpus all 允许使用所有 GPU
docker run -itd -p 5000:5000 --gpus all nvidia/cuda:10.0-base /bin/bash

### 查看所有容器
docker ps -a

### 启动已经停止的容器
docker restart [CONTAINER-ID]

### 进入一个后台容器
docker exec -it [CONTAINER-ID] [Command]

### 向容器中拷贝文件
docker cp [SRC] [CONTAINER-ID:Dest_dir]

当我们把环境差不多配置好之后,可以将这个容器 commit 为一个新的镜像,方便之后使用:

1
2
### -a author -m message 
docker commit -a "author" -m "Save" [CONTAINER-ID] [REPOSITORY[:TAG]]

这样环境基本上就没有问题了,但我们还需要一个能记录调参过程的工具,因为手动管理非常容易乱,正好最近复旦大学 fastNLP 组开源了他们实验室的 fitlog 调参管理记录工具,实践体验很赞。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
pip3 install fitlog

Usage:
fitlog <command> [<args>...]
fitlog help <command>
fitlog -h | --help
fitlog --version

Supported commands
init Initialize a fitlog project
list List committed versions
revert Revert to a specific version
log Visualize logs by a server

See "fitlog help <command>" for more information on a specific command

目前看起来 fitlog list 功能还未实现,不过有其他的命令基本够用了。

1
2
### 新建一个 fitlog 项目
fitlog init

在主要的入口文件,比如 run.py 中加入一些 fitlog 代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import fitlog

fitlog.commit(__file__)

### Some code below

### 添加需要记录的超参数
fitlog.add_hyper(args.per_gpu_train_batch_size, name="per_gpu_train_batch_size")
fitlog.add_hyper(args.num_train_epochs, name="epochs")
fitlog.add_hyper(args.learning_rate, name="learning_rate")
fitlog.add_hyper(args.max_seq_length, name="max_seq_length")
fitlog.add_hyper(args.doc_stride, name="doc_stride")
fitlog.add_hyper(args.weight_decay, name="weight_decay")
fitlog.add_hyper(args.adam_epsilon, name="adam_epsilon")
fitlog.add_hyper(args.max_grad_norm, name="max_grad_norm")
fitlog.add_hyper(args.warmup_steps, name="warmup_steps")
fitlog.add_hyper(args.gradient_accumulation_steps, name="gradient_accumulation_steps")

### 添加最后的指标(一般是验证集上的表现)
fitlog.add_best_metric(results['exact'], name="eval_em")
fitlog.add_best_metric(results['f1'], name="eval_f1")

### 如果训练过程中有验证,也可以记录对应的指标
fitlog.add_metric(results['exact'], name="em", step=global_step)
fitlog.add_metric(results['f1'], name="f1", step=global_step)

### 可以记录损失函数的变化
fitlog.add_loss((tr_loss - logging_loss) / args.logging_steps, name="Loss", step=global_step)

### 最后需要的一步
fitlog.finish()

之后可以 fitlog log [path to logs] 启动一个本地管理日志(可视化)的网页,可以方便地查看各种参数以及表现。

配合暴力的 grid_search.py,炼丹环境就基本上构建完成了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import os

def grid_search():
lrs = [1e-4, 5e-5, 3e-5, 1e-5, 5e-6]
epochs = [1, 2, 3]
batch_sizes = [12, 16, 18, 20]
weight_decay = [0, 1e-8, 1e-9, 1e-7]
warmup_steps = [100, 500]
for lr in lrs:
for ep in epochs:
for bs in batch_sizes:
for wd in weight_decay:
for wstp in warmup_steps:
command = "python3.6 ./examples/run_squad.py --model_type bert --model_name_or_path ./examples/bert_base --do_train --do_eval --train_file $SQUAD_DIR/train-v1.1.json --predict_file $SQUAD_DIR/dev-v1.1.json --learning_rate {0} --num_train_epochs {1} --max_seq_length 384 --doc_stride 128 --output_dir ../models/finetuned_squad_with_fitlog/ --per_gpu_eval_batch_size={2} --per_gpu_train_batch_size=16 --overwrite_output_dir --do_lower_case --evaluate_during_training --weight_decay {3} --warmup_steps {4}".format(
lr, ep, bs, wd, wstp)
# print(command)
os.system(command)

if __name__ == "__main__":
grid_search()

参考文献

[1] nvidia-docker

[2] fitlog 中文文档

打赏
  • 版权声明: 本博客所有文章除特别声明外,均采用 Apache License 2.0 许可协议。转载请注明出处!
  • © 2020 Bowen
  • Powered by Hexo Theme Ayer

请我喝杯咖啡吧~

支付宝
微信