星期六, 01. 六月 2019 03:22下午
- 注: 博客关于监督学习内容参考李航《统计学习方法》第一版,目前该书已经于5月份已经出了第二版,在原来监督学习的基础上加入了非监督学习的内容。
- 深度学习内容为笔者实践中总结出来的些许经验,与大家一起分享。
- 理解基本概念对以后的学习很重要。
一、监督学习基本概念
1 问题的形式化
统计学习包括监督学习、半监督学习、非监督学习和强化学习。
监督学习假设输入与输出的随机变量和
遵循联合概率分布
,但是实际中,联合概率分布的定义是未知的。但是,统计学习认为数据存在一定的统计规律---数据(训练数据和测试数据)是由联合概率分布
独立同发布产生的。这是监督学习关于数据的基本假设。
监督学习的目的在于学习一个由输入到输出的映射(模型),这个模型可以是概率模型,也可以是非概率模型
,非概率模型也就是决策函数。在预测时(假设测试集输入为
,概率模型的输出为
, 决策函数的输出为
。
2 损失函数(结构风险与经验风险)
损失函数是用来度量预测错误的程度,常用的有0-1损失函数,平方损失函数,绝对值损失函数和对数损失函数,损失函数由记号表示。显然损失函数越小,模型就越好,由于模型输入输出遵循联合概率分布,损失函数的期望为:
这是理论上模型关于联合分布在平均意义下的损失,称为风险函数。实际中,在给定训练集,模型关于训练集的平均损失为经验风险:
按照经验风险模型最小化求最优模型就是求解最优化问题:
但是,当样本容量很小时,经验风险最小化学习的效果未必好,会产生过拟合,结构化风险是为了防止过拟合而提出来的策略。结构化风险等价于正则化,结构化风险的定义为:
其中为模型复杂度,
是系数,用以权衡经验风险和模型复杂度。结构风险小的模型往往对训练数据以及未知数据有较好的预测,它的最优化问题为:
3 正则化与S折交叉验证
即为正则项,正则项一般是模型复杂度的单调递增函数。例如回归问题中,损失函数是平方损失函数,正则项可以是参数向量的
范数:
正则项可以是参数向量的范数:
S折交叉验证为应用最多的交叉验证方法(主要用于选参数),方法如下:
- 首相随机地将已知数据切分为S个互不相交的大小相同的子集;
- 然后利用S-1个子集的数据训练模型,利用余下的子集训练模型;
- 将这一过程重复S次
- 最后选择S次测评中平均测试误差最小的模型
二、深度学习训练模型基础
深度学习训练模型笔者也是刚刚开始,笔者这次用的模型是多层LSTM+FC,主要用于时间序列(故障信号)的分类,这次讲的主要是一些如何控制过拟合和如何提高训练的速度。
1 提高GPU的利用率
GPU的利用率高低对于合理利用GPU很重要,在训练模型时,非常有必要将利用率提高到80%以上,主要有两个方法:
(1) 控制GPU内存,用如下代码实现
import os
os.environ["CUDA_VISIBLE_DEVICES"] = '0' # 使用GPU: 0
config = tf.ConfigProto()
# config.gpu_options.per_process_gpu_memory_fraction = 0.5 # 程序最多只能占用指定gpu50%的显存
config.gpu_options.allow_growth = True # 根据运行需求分配GPU内存
sess = tf.Session(config=config)
(2) 减少数据频繁读写
数据频繁读写会使得GPU的利用率在0~100%之间快速的变化,此时GPU平均的利用率就很低,遇到这种情况,需要增加batch_size,减慢数据的频繁读写,增大GPU的利用率。
2 train loss 与 validation loss 结果分析
- train loss 不断下降,validation loss不断下降,说明网络仍在学习;
- train loss 不断下降,validation loss趋于不变,说明网络过拟合;
- train loss 趋于不变,validation loss不断下降,说明数据集100%有问题;
- train loss 趋于不变,validation loss趋于不变,说明学习遇到瓶颈,需要减小学习率或批量数目;
- train loss 不断上升,validation loss不断上升,说明网络结构设计不当,训练超参数设置不当,数据集经过清洗等问题。
3 采用early stop 控制过拟合
常用控制过拟合的方式有drop regularization (增加数据量),笔者这次主要讲early stop中的一种常用的实现方法:即当网络在连续多次训练中,validation loss趋于不变,网络就停止。具体的代码实现如下:
# previous_loss 前一次的loss
# current_loss 当前的loss
# Max_N 可以允许的n最大值
# Th_loss 可以允许的最大loss差值
# epoch 迭代周期
# best_iteration 最佳迭代次数
if abs(current_loss - previous_loss) < Th_loss:
n += 1
if n > Max_N:
best_iteration = epoch + 1
break
else:
n = 0
previous_loss = current_loss
4 归一化和shuffle+(repeat)
采用归一化和shuffle主要目的是为了提高网络的训练速度。
采用StandardScaler()归一化的代码如下:
from sklearn.preprocessing import StandardScaler
ss = StandardScaler().fit(train_x)
train_x = ss.transform(train_x)
test_x = ss.transform(test_x)
shuffle的代码实现有很多种方式,可以是一周期shuffle一次或多次,也可以是每个batch shuffle一次或者多次
5 模型保存与加载
笔者这里只介绍保存全部模型(图和变量),加载整个模型的方式。
首先是保存整个模型:
saver = tf.train.Saver()
saver.save(sess, "./my_model_20190528/my_model_20190528")
保存结束后,在文件夹 my_model_20190528下面有4个子文件,分别为checkpoint my_model_20190528.data-00000-of-00001 my_model_20190528.index my_model_20190528.meta
然后在另一张图上加载刚刚保存的模型:
# 导入保存的图
new_saver = tf.train.import_meta_graph('./my_model_20190528/my_model_20190528.meta')
# 加载需要run的变量
graph = tf.get_default_graph()
accuracy = graph.get_tensor_by_name("Mean_1:0")
X = graph.get_tensor_by_name("Placeholder:0")
y = graph.get_tensor_by_name("Placeholder_1:0")
keep_prob = graph.get_tensor_by_name("Placeholder_2:0")
# 加载保存的模型
sess = tf.Session()
new_saver.restore(sess, './my_model/my_model')
keep_prob 在测试的时候应该设置为1.0
下次继续分享,欢迎留言