赞
踩
模型训练通用配置基本原则
模型训练流程
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)
参数
参数是机器学习算法的关键,是从训练数据中学习到的,属于模型的一部分。
输入一个值(x),乘以权重,结果就是网络的输出值。权重可以随着网络的训练进行更新,从而找到最佳的值,这样网络就能尝试匹配输出值与目标值。
这里的权重其实就是一种参数。
超参数
模型的超参数指的是模型外部的配置变量,是不能通过训练的进行来估计其取值不同的,且不同的训练任务往往需要不同的超参数。
超参数不同,最终得到的模型也是不同的。
一般来说,超参数有:学习率,迭代次数,网络的层数,每层神经元的个数等等。
常见的超参数有以下三类:
在使用某一网络时,一般是比较好的论文中出现过的,是证明过的,当然也可以直接套用,然后在这个基础上,调参。
可是如果识别的领域不同,比如同样是LeNet网络,在解决手写数字识别时使用的超参数能得到很好的效果,但是在做眼疾识别时,因为数据集的不同,虽然使用同样的超参数,但是效果可能并不理想。
在<< Neural Network and Deep Learning >>这本书中,作者给出⼀些⽤于设定超参数的启发式想法。
做一个判断,满足条件时退出循环,终止训练:
for epoch in range(MAX_EPOCH):
// 训练代码
print('{}[TRAIN]epoch {}, iter {}, output loss: {}'.format(timestring, epoch, i, loss.numpy()))
if ():
break
model.train()
那么这个if条件判断就十分重要了,这里有两种方案:
我们需要再明确⼀下什么叫做分类准确率不再提升,这样方可实现提前停止。
我们知道,分类准确率在整体趋势下降的时候仍旧会抖动或者震荡。如果我们在准确度刚开始下降的时候就停止,那么肯定会错过更好的选择。⼀种不错的解决方案是如果分类准确率在⼀段时间内不再提升的时候终止。
当然这块用loss也是可以的,loss也是一个评判标准。
因为网络有时候会在很长时间内于⼀个特定的分类准确率附近形成平缓的局面,然后才会有提升。如果你想获得相当好的性能,第一种方案(分类准确率不再提升时)的规则可能就会太过激进了 —— 停止得太草率。
学习率动态变化对网络训练非常重要
如果学习率设置的过低,在训练的前期,训练速度会非常慢;而学习率设置地过高,在训练的后期,又会产生震荡,降低模型的精度:
所以最好是在前期使用一个较大的学习速率让权重变化得更快。越往后,我们可以降低学习速率,这样可以作出更加精良的调整。
⼀种自然的观点是使用提前终止的想法。就是保持学习速率为⼀个常量直到验证准确率开始变差,然后按照某个量下降学习速率。我们重复此过程若干次,直到学习速率是初始值的 1/1024(或者1/1000),然后终止训练。
通过简化网络来加速实验进行更有意义的学习
比如将问题简化,将十分类问题转化成二分类问题。丢开训练和验证集中的那些除了 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()))
观察输出,及时发现训练过程中的问题
选择最好的小批量数据大小是⼀种折中。小批量数据太小会加长训练时间;而小批量数据太大是不能够足够频繁地更新权重的。选择⼀个折中的值,可以最大化学习的速度。
创建日志文件:
为了快速找到最佳超参,训练9个不同组合的超参实验,创建方式均相同如下:
writer = LogWriter("./log/lenet/run1")
writer.add_hparams({'learning rate':0.0001, 'batch size':64, 'optimizer':'Adam'}, ['train/loss', 'train/acc'])
writer.add_scalar(tag="train/loss", step=step, value=cost)
writer.add_scalar(tag="train/acc", step=step, value=accuracy)
img = np.reshape(batch[0][0], [28, 28, 1]) * 255
writer.add_image(tag="train/input", step=step, img=img)
writer.add_histogram(tag='train/{}'.format(param), step=step, values=values)
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)
fluid.io.save_inference_model(dirname='./model', feeded_var_names=['img'],target_vars=[predictions], executor=exe)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。