飞桨百度架构师手把手带你零基础实践深度学习——手写数字识别训练调试与优化
其实对于这个模型,我们还有很多优化的方向。
有一些关键问题:
-
计算分类准确率,观测模型训练效果。
(交叉熵损失函数只能作为优化目标,无法直接准确衡量模型的训练效果。准确率可以直接衡量训练效果,但由于其离散性质,不适合做为损失函数优化神经网络。) -
检查模型训练过程,识别潜在问题。
(如果模型的损失或者评估指标表现异常,通常需要打印模型每一层的输入和输出来定位问题,分析每一层的内容来获取错误的原因。) -
加入校验或测试,更好评价模型效果。
(理想的模型训练结果是在训练集和验证集上均有较高的准确率,如果训练集上的准确率高于验证集,说明网络训练程度不够;如果验证集的准确率高于训练集,可能是发生了过拟合现象。通过在优化目标中加入正则化项的办法,解决过拟合的问题。) -
加入正则化项,避免模型过拟合。
(飞桨框架支持为整体参数加入正则化项,这是通常的做法。此外,飞桨框架也支持为某一层或某一部分的网络单独加入正则化项,以达到精细调整参数训练的效果。若测试集表现不好) -
可视化分析。
(用户不仅可以通过打印或使用matplotlib库作图,飞桨还提供了更专业的可视化分析工具VisualDL,提供便捷的可视化分析方法。)
评估分类分准率
分类准确率accuracy:测量直观,但是不适合作为loss,公平比较两种损失函数的优劣。
实现方案:
在forward函数中加入acc计算并返回结果。
训练过程中取得该批次样本的acc
打印acc
if label is not None: acc = fluid.layers.accuracy(input=x, label=label) return x, acc else: return x ······ #前向计算的过程,同时拿到模型输出值和分类准确率 predict, acc = model(image, label)
检查模型训练过程
若模型报错或loss不下降。
实现方案:
在forward函数中,打印模型每一层的参数和输出
打印尺寸和内容值。
通过尺寸验证网络结构是否正确,通过内容值验证数据分布是否合理。
在合适时机打印即可
# 选择是否打印神经网络每层的参数尺寸和输出尺寸,验证网络结构是否设置正确 if check_shape: # 打印每层网络设置的超参数-卷积核尺寸,卷积步长,卷积padding,池化核尺寸 print("\n########## print network layer's superparams ##############") print("conv1-- kernel_size:{}, padding:{}, stride:{}".format(self.conv1.weight.shape, self.conv1._padding, self.conv1._stride)) print("conv2-- kernel_size:{}, padding:{}, stride:{}".format(self.conv2.weight.shape, self.conv2._padding, self.conv2._stride)) print("pool1-- pool_type:{}, pool_size:{}, pool_stride:{}".format(self.pool1._pool_type, self.pool1._pool_size, self.pool1._pool_stride)) print("pool2-- pool_type:{}, poo2_size:{}, pool_stride:{}".format(self.pool2._pool_type, self.pool2._pool_size, self.pool2._pool_stride)) print("fc-- weight_size:{}, bias_size_{}, activation:{}".format(self.fc.weight.shape, self.fc.bias.shape, self.fc._act)) # 打印每层的输出尺寸 print("\n########## print shape of features of every layer ###############") print("inputs_shape: {}".format(inputs.shape)) print("outputs1_shape: {}".format(outputs1.shape)) print("outputs2_shape: {}".format(outputs2.shape)) print("outputs3_shape: {}".format(outputs3.shape)) print("outputs4_shape: {}".format(outputs4.shape)) print("outputs5_shape: {}".format(outputs5.shape)) # 选择是否打印训练过程中的参数和输出内容,可用于训练过程中的调试 if check_content: # 打印卷积层的参数-卷积核权重,权重参数较多,此处只打印部分参数 print("\n########## print convolution layer's kernel ###############") print("conv1 params -- kernel weights:", self.conv1.weight[0][0]) print("conv2 params -- kernel weights:", self.conv2.weight[0][0]) # 创建随机数,随机打印某一个通道的输出值 idx1 = np.random.randint(0, outputs1.shape[1]) idx2 = np.random.randint(0, outputs3.shape[1]) # 打印卷积-池化后的结果,仅打印batch中第一个图像对应的特征 print("\nThe {}th channel of conv1 layer: ".format(idx1), outputs1[0][idx1]) print("The {}th channel of conv2 layer: ".format(idx2), outputs3[0][idx2]) print("The output of last layer:", outputs5[0], '\n')
若打印的参数一直不变,说明参数没有加入梯度下降模型。
加入校验或测试,评价模型效果
校验:未参与训练,决策模型超参数
测试:未参与训练和校验,评估模型效果
实现方案:
加载参数,eval状态
读取校验的样本集
根据模型预测计算评估指标,注意不同批次评估结果取平均。
一定要先保存
with fluid.dygraph.guard(): print('start evaluation .......') #加载模型参数 model = MNIST() model_state_dict, _ = fluid.load_dygraph('mnist') model.load_dict(model_state_dict) model.eval() eval_loader = load_data('eval') acc_set = [] avg_loss_set = [] for batch_id, data in enumerate(eval_loader()): x_data, y_data = data img = fluid.dygraph.to_variable(x_data) label = fluid.dygraph.to_variable(y_data) prediction, acc = model(img, label) loss = fluid.layers.cross_entropy(input=prediction, label=label) avg_loss = fluid.layers.mean(loss) acc_set.append(float(acc.numpy())) avg_loss_set.append(float(avg_loss.numpy())) #计算多个batch的平均损失和准确率 acc_val_mean = np.array(acc_set).mean() avg_loss_val_mean = np.array(avg_loss_set).mean() print('loss={}, acc={}'.format(avg_loss_val_mean, acc_val_mean))
差别不大只不过数据不用训练数据,用校验的数据
过拟合的原理和解决方案
过拟合:模型在训练集数据表现良好,测试集表现差(泛化能力差)
原因:模型过于复杂,或学习能力敏感,数据较少,或噪音多。
一般测试误差先降低后上升。
回归问题模型:
图1 过拟合 图3 欠拟合
分类问题模型:
过拟合成因
- 训练数据存在噪音->数据清洗和修正
- 强大模型(表示空间大)+训练数据少=在训练数据上表现良好的候选假设太多
可以限制模型表示能力or更多训练数据
加入正则化项
为了防止过拟合,我们一般限制模型表示能力。给参数加入反胃。
正则化项
- 防止模型过度拟合
- 优化目标中加入正则化项,惩罚参数
- 模型在参数大小和训练集loss间取得平衡->在预测时效果最好
实现方案:
在优化目标中整体加入;
对某一层的参数加入。
#各种优化算法均可以加入正则化项,避免过拟合,参数regularization_coeff调节正则化项的权重 #optimizer = fluid.optimizer.SGDOptimizer(learning_rate=0.01, regularization=fluid.regularizer.L2Decay(regularization_coeff=0.1),parameter_list=model.parameters())) optimizer = fluid.optimizer.AdamOptimizer(learning_rate=0.01, regularization=fluid.regularizer.L2Decay(regularization_coeff=0.1),parameter_list=model.parameters())
*regularization_coeff为权重系数,参数和loss谁更小的权重
可视化
使用PLT库制作变化曲线
Matplotlib库
2D
实现方案:
- 引入PLT库
- 批次编号作为x轴,记录在列表iters
- 该批次的训练损失作为y轴,记录在loses
- 训练后将数据以参数灌入plt.plot
#画出训练过程中Loss的变化曲线 plt.figure() plt.title("train loss", fontsize=24) plt.xlabel("iter", fontsize=14) plt.ylabel("loss", fontsize=14) plt.plot(iters, losses,color='red',label='train loss') plt.grid() plt.show()
Visual DL分析工具
- 创建LogWriter对象,设置数据存放路径
from visualdl import LogWriter log_writer = LogWriter("./log")
- 训练过程中插入作图语句
#每训练一百批次的数据,打印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.add_scalar(tag = 'acc', step = iter, value = avg_acc.numpy()) log_writer.add_scalar(tag = 'loss', step = iter, value = avg_loss.numpy()) iter = iter + 100
- 命令行输入 $visualdl --logdir ./log
$ visualdl --logdir ./log --port 8080 -
打开浏览器,查看作图结果。
查阅的网址在第三步的启动命令后会打印出来(如http://127.0.0.1:8080/),将该网址输入浏览器地址栏刷新页面的效果如下图所示。除了右侧对数据点的作图外,左侧还有一个控制板,可以调整诸多作图的细节。
- 飞桨PaddlePaddle百度架构师手把手带你零基础实践深度学习 第一周心得
- PaddlePaddle-百度架构师手把手带你零基础实践深度学习-笔记02(代码详解)
- PaddlePaddle-百度架构师手把手带你零基础实践深度学习-笔记01(代码详解)
- 2使用Python语言和Numpy库来构建神经网络模型-波士顿房价预测任务实战案例(百度架构师手把手带你零基础实践深度学习原版笔记系列)
- 1机器学习和深度学习综述(百度架构师手把手带你零基础实践深度学习原版笔记系列)
- 深度学习与TensorFlow实战(六)全连接网络基础—MNIST数据集输出手写数字识别准确率
- 机器学习深度学习基础笔记(2)——梯度下降之手写数字识别算法实现
- 直播提醒 | 「百度架构师手把手带你实践深度学习」开课啦!
- 深度学习与TensorFlow实战(七)全连接网络基础—真实图片输出手写数字识别准确率
- 深度学习入门实践_十行搭建手写数字识别神经网络
- Java分布式神经网络库Deeplearning4j之上手实践手写数字图像识别与模型训练
- 深度学习进阶之第5章 手写数字识别
- mnist手写数字识别——深度学习入门项目(tensorflow+keras+Sequential模型)
- 深度学习-随机梯度下降算法应用-手写数字识别
- 深度学习入门(八):完整地实现全连接层并进行手写数字识别
- 深度学习-灰度平均值算法和支持向量机算法(SVM)进行手写数字识别
- 用MXnet入门实战深度学习之一:安装GPU版mxnet并跑一个MNIST手写数字识别
- [TensorFlow深度学习入门]实战五·用RNN(LSTM)做手写数字识别准确率98%+
- 神经网络与深度学习: 使用神经网络识别手写数字1
- 飞浆深度学习——百度架构师手把手教你深度学习