飞桨领航团AI创造营:深度学习模型训练和关键参数调优详解

学习内容来源

模型训练

模型训练通用配置基本原则

  1. 每个输入数据的维度要保持一致,且一定要和模型输入保持一致。
  2. 配置学习率衰减策略时,训练的上限轮数一定要计算正确。
  3. BatchSize不宜过大,太大容易内存溢出,且一般为2次幂。

模型训练流程

  • 加载数据集
  • 模型封装
model = paddle.Model(gmlp_vision)
  • 训练参数配置

    用paddle.Model完成模型的封装后,在训练前,需要对模型进行配置,通过Model.prepare接口来对训练进行提前的配置准备工作,包括设置模型优化器,Loss计算方法,精度计算方法等。

# 调用飞桨框架的VisualDL模块,保存信息到目录中。
callback = paddle.callbacks.VisualDL(log_dir='gMLP_log_dir')

def create_optim(parameters):
    step_each_epoch = len(trainloader) // 128
    lr = paddle.optimizer.lr.CosineAnnealingDecay(learning_rate=0.25,
                                                  T_max=step_each_epoch * 120)

    return paddle.optimizer.Adam(learning_rate=lr,
                                 parameters=parameters,
                                 weight_decay=paddle.regularizer.L2Decay(3e-4))

model.prepare(create_optim(model.parameters()),  # 优化器
              paddle.nn.CrossEntropyLoss(),        # 损失函数
              paddle.metric.Accuracy(topk=(1, 5))) # 评估指标
  • 模型训练

    做好模型训练的前期准备工作后,调用fit()接口来启动训练过程,需要指定至少3个关键参数:训练数据集,训练轮次和单次训练数据批次大小。
    Model.prepare接口来对训练进行提前的配置准备工作,包括设置模型优化器,Loss计算方法,精度计算方法等。

import paddle

# 使用paddle.Model完成模型的封装
model = paddle.Model(Net)

# 为模型训练做准备,设置优化器,损失函数和精度计算方式
model.prepare(optimizer=paddle.optimizer.Adam(parameters=model.parameters()),
              loss=paddle.nn.CrossEntropyLoss(),
              metrics=paddle.metric.Accuracy())

# 调用fit()接口来启动训练过程
model.fit(trainloader,
          testloader,
          epochs=120,
          eval_freq=2,
          shuffle=True, 
          save_dir='gMLP_case1_chk_points/',
          save_freq=20,
          batch_size=128,
          callbacks=callback,
          verbose=1)

超参优化

1.超参优化的基本概念

参数

参数是机器学习算法的关键,是从训练数据中学习到的,属于模型的一部分。

输入一个值(x),乘以权重,结果就是网络的输出值。权重可以随着网络的训练进行更新,从而找到最佳的值,这样网络就能尝试匹配输出值与目标值。

这里的权重其实就是一种参数。

超参数

模型的超参数指的是模型外部的配置变量,是不能通过训练的进行来估计其取值不同的,且不同的训练任务往往需要不同的超参数。

超参数不同,最终得到的模型也是不同的。

一般来说,超参数有:学习率迭代次数网络的层数每层神经元的个数等等。

常见的超参数有以下三类:

  1. 网络结构,包括神经元之间的连接关系、层数、每层的神经元数量、激活函数的类型等 .
  2. 优化参数,包括优化方法、学习率、小批量的样本数量等 .
  3. 正则化系数

2.手动调整超参数的四大方法

在使用某一网络时,一般是比较好的论文中出现过的,是证明过的,当然也可以直接套用,然后在这个基础上,调参。

可是如果识别的领域不同,比如同样是LeNet网络,在解决手写数字识别时使用的超参数能得到很好的效果,但是在做眼疾识别时,因为数据集的不同,虽然使用同样的超参数,但是效果可能并不理想。

在<< Neural Network and Deep Learning >>这本书中,作者给出⼀些⽤于设定超参数的启发式想法。

1)使用提前停止来确定训练的迭代次数

做一个判断,满足条件时退出循环,终止训练:

for epoch in range(MAX_EPOCH):
	// 训练代码
	print('{}[TRAIN]epoch {}, iter {}, output loss: {}'.format(timestring, epoch, i, loss.numpy()))
	if ():
		break
	model.train()

那么这个if条件判断就十分重要了,这里有两种方案:

  1. 分类准确率不再提升时
  2. loss降到一个想要的范围时
分类准确率不再提升时

我们需要再明确⼀下什么叫做分类准确率不再提升,这样方可实现提前停止。

我们知道,分类准确率在整体趋势下降的时候仍旧会抖动或者震荡。如果我们在准确度刚开始下降的时候就停止,那么肯定会错过更好的选择。⼀种不错的解决方案是如果分类准确率在⼀段时间内不再提升的时候终止。

当然这块用loss也是可以的,loss也是一个评判标准。

loss降到一个想要的范围时

因为网络有时候会在很长时间内于⼀个特定的分类准确率附近形成平缓的局面,然后才会有提升。如果你想获得相当好的性能,第一种方案(分类准确率不再提升时)的规则可能就会太过激进了 —— 停止得太草率。

2)让学习率从高逐渐降低

学习率动态变化对网络训练非常重要

如果学习率设置的过低,在训练的前期,训练速度会非常慢;而学习率设置地过高,在训练的后期,又会产生震荡,降低模型的精度:

所以最好是在前期使用一个较大的学习速率让权重变化得更快。越往后,我们可以降低学习速率,这样可以作出更加精良的调整。

⼀种自然的观点是使用提前终止的想法。就是保持学习速率为⼀个常量直到验证准确率开始变差,然后按照某个量下降学习速率。我们重复此过程若干次,直到学习速率是初始值的 1/1024(或者1/1000),然后终止训练。

3)宽泛策略

  1. 通过简化网络来加速实验进行更有意义的学习
  2. 通过更加频繁的监控验证准确率来获得反馈

通过简化网络来加速实验进行更有意义的学习

比如将问题简化,将十分类问题转化成二分类问题。丢开训练和验证集中的那些除了 0 和 1的那些图像,即我们只识别0和1。然后试着训练⼀个网络来区分 0 和 1。

以此来快速进行实验,也能给予你关于如何构建好的网络更快的洞察。

通过更加频繁的监控验证准确率来获得反馈

这个方法调的其实是输出:

if i % 200 == 0:
	timestring = time.strftime("%Y-%m-%d %H:%M:%S",time.localtime(time.time()))
	print('{}[VALID]epoch {}, iter {}, output loss: {}'.format(timestring, epoch, i, loss.numpy()))

观察输出,及时发现训练过程中的问题

4)小批量数据(mini-batch)大小不必最优

选择最好的小批量数据大小是⼀种折中。小批量数据太小会加长训练时间;而小批量数据太大是不能够足够频繁地更新权重的。选择⼀个折中的值,可以最大化学习的速度。

效果展示

  • 可视化输入输出
  • 使用VisualDL
    VisualDL可视化流程
  1. 创建日志文件:

    为了快速找到最佳超参,训练9个不同组合的超参实验,创建方式均相同如下:

writer = LogWriter("./log/lenet/run1")
  1. 训练前记录每组实验的超参数名称和数值,且记录想要展示的模型指标名称
writer.add_hparams({'learning rate':0.0001, 'batch size':64, 'optimizer':'Adam'}, ['train/loss', 'train/acc'])
  1. 训练过程中插入作图语句,记录accuracy和loss的变化趋势,同时将展示于Scalar和HyperParameters两个界面中:
writer.add_scalar(tag="train/loss", step=step, value=cost)

writer.add_scalar(tag="train/acc", step=step, value=accuracy)
  1. 记录每一批次中的第一张图片:
img = np.reshape(batch[0][0], [28, 28, 1]) * 255

writer.add_image(tag="train/input", step=step, img=img)
  1. 记录训练过程中每一层网络权重(weight)、偏差(bias)的变化趋势:
writer.add_histogram(tag='train/{}'.format(param), step=step, values=values)
  1. 记录分类效果–precision & recall曲线:
writer.add_pr_curve(tag='train/class_{}_pr_curve'.format(i),
                     labels=label_i,
                     predictions=prediction_i,
                     step=step,
                     num_thresholds=20)

writer.add_roc_curve(tag='train/class_{}_pr_curve'.format(i),
                     labels=label_i,
                     predictions=prediction_i,
                     step=step,
                     num_thresholds=20)
  1. 保存模型结构:
fluid.io.save_inference_model(dirname='./model', feeded_var_names=['img'],target_vars=[predictions], executor=exe)

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值