[笔记]飞浆PaddlePaddle-百度架构师手把手带你零基础实践深度学习-21日学习打卡(Day 5)

[笔记]飞浆PaddlePaddle-百度架构师手把手带你零基础实践深度学习-21日学习打卡(Day 5)

logo

(Credit: https://gitee.com/paddlepaddle/Paddle/raw/develop/doc/imgs/logo.png)


资源配置

使用GPU进行训练

  • CPU: fluid.CPUPlace()设置
  • GPU: fluid.CUDAPlace(0)设置,参数0是GPU编号,比如拥有四个GPU卡的机器编号为0,1,2,3
  • dygraph.guard函数的参数传入声明的place资源,with语句作用域下的代码在该资源上运行
    # 仅前3行代码有所变化,在使用GPU机器时,可以将use_gpu变量设置成True
    use_gpu = True
    place = fluid.CUDAPlace(0) if use_gpu else fluid.CPUPlace()
    
    with fluid.dygraph.guard(place):
    	model = MNIST('mnist')
    	model.train()
    	# 调用加载数据的函数
    	train_loader = laod_data('train')
    

分布式训练(多卡)

  1. 两种并行计算方式
    1. 模型并行:节省内存,应用较为首先
    2. 数据并行:飞桨框架采用的实现方式
      • CPU: Pserver通信方式
      • GPU: NCCL通行方式
      • 训练节点上运行同样的程序,以不同的数据做训练
      • 不同训练节点计算的梯度需要聚合
  2. 实现“多GPU卡”的分布式训练
    1. 程序修改
    2. 命令行调用

分布式训练(多卡),程序修改

程序修改(四点)

  • 启动训练前
    • 获取环境变量定义的GPU序号,感知自己
    • 对原模型做并行化预处理
    • 定义过GPU训练的reader,不同ID的GPU加载不同的数据集
    # 修改1 - 从环境变量获取使用GPU的序号
    place = fluid.CUDAPlace(fliud.dygraph.parallel.Env().dev_id)
    
    with fluid.dygraph.guard(place):
    	# 修改2 - 对原模型做并行化预处理
    	strategy = fluid.dygraph.paralle.prepare_context()
    	model = MNIST('mnist')
    	model = fluid.dygraph.paralle.DataParallel(model, strategy)
    
    	model.train()
    	
    	# 调用加载数据的函数
    	train_loader = load_data('train')
    	# 修改3 - 多GPU数据读取,必须确保每个进程读取的数据是不同的
    	train_loader = fluid.contrib.reader.distributed_batch_reader(train_loader)
    
  • 训练过程中
    • 对计算的loss做调整,并收集参数的梯度
    # 修改4 - 多GPU训练需要对Loss做出调整,并聚合不同设备上的参数梯度
    avg_loss = mnist.scale_loss(avg_loss)
    avg_loss.backward()
    model.apply_collective_grads()
    

分布式训练(多卡),命令行调用

命令行调用L制定具体在哪些GPU上运行

$ python -m paddle.distributed.launch --selected_gpus=0,1,2,3 --log_dir ./mylog train_multi_gpu.py
  • paddle.distributed.launch: 启动分布式运行
  • selected_gpus: 设置使用的GPU的序号(需要是多GPU卡的机器,命令watch nvidia-smi查看)
  • log_dir: 存放训练Log,如果不设置,每个GPU寻默认输出到屏幕
  • train_multi_gpu.py: 多GPU训练的程序,包含修改过的train_multi_gpu()函数

训练过程:关键问题

  • 加入更多的评估指标:分类准确率
    实现方案:
    • Forward函数加入acc计算并返回结果
    • 训练过程中去的该批次样本的acc(与loss不同,无需在做平均)
    • 打印acc(分类准确率)
  • 加入对训练过程的检查,确保正确执行
    实现方案:
    • 在Forward函数中,打印模型每一层的参数和输出
      • check_shape控制打印“尺寸”
      • check_content控制打印“内容值”
    • 通过“尺寸”验证网络结构是否正确,通过“内容值”验证数据分布是否合理
  • 在测试数据集上评测,更好评价模型效果
    实现方案:
    • 加载参数,模型设置成eval状态
    • 读取校验的样本集
    • 根据模型预测计算评估指标,注意需要将不同批次的评估结果取平均
  • 在优化目标中加入正则化项,避免模型过拟合
    实现方案:
    • 在优化目标中整体加入正则化项
    • 对某一层的参数加入正则化项
  • 加入作图,更好的分析训练效果
    实现方案:
    • 引入PLT库
    • 彼此编号作为X轴,记录在列表iters
    • 该批次的训练损失作为Y轴,记录在列表loses
    • 训练后将数据以参数灌入plt.plot作图

训练过程:飞桨可视化分析工具VisualDL

VisualDL:飞桨原装,辅助模型优化
模式:生产数据文件,启动Web服务展现

  1. 创建LogWriter对象,设置试验结果(数据)存放路径
    # coding=utf-8
    from visualdl import LogWriter
    
    # 创建LogWriter对象,实验结果存放在'./log/train'路径下
    log_writer_1 = LogWriter('./log/train')
    
  2. 训练过程中插入作图语句
    # 每训练了100批次的数据,打印下当前Loss的情况
    if batch_id % 100 == 0:
    	print ("epoch: {}, batch: {}, loss is: {}, acc is {}".format(
    		epoch_id, batch_id, avg_loss.numpy(), avg_acc.numpy()
    	))
    	log_writer_1.add_scalar(tag='acc', step=iter, value=avg_acc.numpy())
    	log_writer_1.add_scalar(tag='loss', step=iter, value=avg_loss.numpy())
    	iter = iter + 100
    
  3. 命令行输入:$ visualdl --logdir ./log
    上述命令执行后会给出可查的网址:http://0.0.0.0:8040 (默认本机),可通过参数修改网卡的配置:--host 168.225.0.1 --port 8080
  4. 打开浏览器输入网址即可查看

保存和加载模型:从预测场景到恢复训练场景

  • 预测场景:
    只保存模型参数

  • 保存训练场景:
    保存模型参数和优化器参数

    • 使用存在参数变化的Adam优化器(学习率以多项式曲线从0.01 -> 0.001衰减),方便校验恢复训练的过程是否正常
    • 每一轮训练保存一次,轮次号区分保存的模型状态
    # 定义学习率
    total_steps = (int(60000/BATCH_SIZE) + 1)*EPOCH_NUM
    lr = fluid.dygraph.PolynomialDecay(0.01, total_steps, 0.001)
    optimizer = fluid.optimizer.Adam(learning_rate=lr)
    
    for epoch_id in range(EPOCH_NUM):
    	pass
    # 保存模型参数和优化器的参数
    fluid.save_dygraph(model.state_dict(), './checkpoint/mnist_epoch{}'.format(epoch_id))
    fluid.save_dygraph(optimizer.state_dict(), './checkpoint/mnist_epoch{}'.format(epoch_id))
    
  • 恢复训练场景

    • 声明相同模型,加载模型参数
    • 声明相同优化器,加载优化器参数
    • 模型设置成“训练”状态
    • 加载第0轮训练后的状态,从第1轮回复训练(效果与未中断完全一致)
    # 加载模型参数到模型中
    params_dict, opt_dict = fluid.load_dygraph(params_path)
    model = MNIST('mnist')
    model.load_dict(params_dict)
    
    # 定义学习率,并加载优化器参数到模型中
    total_steps = (int(60000/BATCH_SIZE) + 1)*EPOCH_NUM
    lr = fluid.dygraph.PolynomialDecay(0.01, total_steps, 0.001)
    optimizer = fluid.optimizer.Adam(learning_rate=lr)
    optimizer.set_dict(opt_dict)
    
    # 从第一个epoch开始重新训练
    for epoch_id in range(1, EPOCH_NUM):
    	pass
    

你可能感兴趣的:(paddlepaddle)