大数据学习——TensorFlow学习笔记2—多分类问题、反向传播算法、过拟合问题
一、逻辑回归的概述与实现
1、概述
回归一般用于解决那些连续变量的问题,如:线性回归,它是通过最小化误差函数,来不断拟合一条直线,以计算出权重 w 和 偏置b 的过程,它的目标是基于一个连续方程去预测一个值。
Logistic 回归常用于分类问题,也就是将观测值贴上某个标签,或者是分入某个预先定义的类别之中。回归应该是寻找一个连续值,而分类是寻找一个离散值。故理解常用于分类问题的 Logistic 回归的关键在于,我们是将先寻找到的该样本属于某个类可能性的连续值映射到了某一个类(我们一般将某一个类的 label 建模成离散值)。这就是 Logistic 常用于分类却叫做回归的原因 。
Logistic函数的逆函数 Logit 函数,即对数几率函数。正如我们所了解的一样逆函数之间关于 y = x 直线对称,自变量 x 和因变量 y 互为对偶位置,因此,Logit 函数和 Logistic 函数有很多性质都有关联。
Logit 函数的变量需要一个概率值 p 作为自变量,如果是二分类问题,确切一点是伯努利分布(即二项分布),如果是多分类问题,则是多项分布。
2、原理
简单来说,线性回归预测的是一个连续的值,逻辑回归则预测“是”或“否”。
通过Sigmoid**函数(概率函数得出概率值)将权值*特征得到的输出值映射到-1与1之间,得出在0~1之间的值,Sigmoid函数的值小于0.5则为负面回答,大于0.5则为正面回答。
由于神经网络本质上是一个映射网络,输入特征后会经过多层感知器一层一层向下映射,当映射到最后时通过Sigmoid**函数映射到0~1之间的值,则该网络为输出逻辑回归值的网络,即输出一个0~1的概率值。
适用情景:1、分类问题,当判断一只动物是否为猫时,需要得出的结果更应该是使用交叉熵损失函数输出的0或1,而不是均方差所擅长的刻画的损失结果0.3或0.7。2、数据集量级,均方差适用于原有数据集与损失数据在同一数量级时,假如特征值数据集十分庞大但损失数据极小时,那么训练速度慢、训练次数多的特点导致均方差不适用于刻画此类问题,因此可将该类问题转化为使用交叉熵刻画概率损失问题。
下图可见,靠近0时交叉熵logistic损失非常大(概率分布损失放大了实际损失),而L2的损失却非常小
交叉熵刻画的是实际输出(概率)与期望输出(概率)的距离,也就是交叉熵的值越小,两个概率分布就越接近。假设概率分布p为期望输出,概率分布q为实际输出,H(p,q)为交D叉熵,则:
在keras里,使用binary_ crossentropy来计算二元交叉熵。
3、问题描述
通过已知数据建立输入的一系列特征值与目标值的预测模型,再次输入14个特征值时即可预测目标值(目标值只有-1和1,可将输出结果抽象为“真”、“假”,或“是”、“否”欺诈)
4、数据分析
获取前5行数据观察,有14个特征值,第15列为目标值
获取第15列目标值观察,可看出目标值有357个为1,有296个为-1
5、建立模型
目标:当输入14个特征值时可得出第15列的特征值为1或-1(可抽象为是否欺诈)
上图中先获取数据,然后建立模型并构模型框架,该模型包含三层(两个隐含层与一个输出层)
6、训练与预测
训练模型并得出训练结果与正确率,且将训练结果收集到history里面
调用history方法,将容器Container中的数据项关键字显示在字典中,然后绘图观察训练时的loss值变化情况,可观察到在训练一定次数之后loss值几乎不再变化,那么后面的训练就已经意义不大了。
下面的正确率图像可看到,训练一定次数之后正确率达到0.66以上,则一直徘徊在0.66~0.7之间
以上实现了一个简单的逻辑回归,逻辑回归最后一定要用到Sigmoid函数。
二、softmax多分类
1、概述
对数几率回归(逻辑回归)解决的是二分类的问题,对于多个选项的问题,我们可以使用softmax函数它是对数几率回归在N个可能不同的值上的推广
Softmax层的作用:神经网络的原始输出不是一个概率值,实质上只是输入的数值做了复杂的加权(权值a、偏置b)和与非线性处理(**函数relu)之后的一个值而已,那么就需要用到Softmax层将这个输出变为概率分布。
公式:
softmax要求每个样本必须属于某个类别,且所有可能的样本均被覆盖。softmax个样本分量之和为1 ,当只有两个类别时,与对数几率回归完全相同
tf.keras使用categorical_crossentropy和sparse_ categorical_crossentropy计算多分类问题的softmax交叉熵
2、问题描述
Fashion MNIST的作用是成为经典MNIST数据集的简易替换,MNIST数据集包含手写数字(0、1、2等)的图像,这些图像的格式与下面服饰图像的格式相同。Fashion MNIST比常规MNIST手写数据集更具挑战性。这两个数据集都相对较小,用于验证某个算法能否如期正常运行。它们都是测试和调试代码的良好起点。
Fashion MNIST数据集包含70000张灰度图像,涵盖10个类别。如下
使用60000张图像训练网络,并使用10000张图像评估经过学习的网络分类图像的准确率。可以从TensorFlow直接访问Fashion MNIST,只需导入和加载数据即可
2、配置fashion-mnist数据集
若是第一次使用该数据集,则会自动从国外一个网站下载,速度十分缓慢,可以自己将下载好的“fashion-mnist”文件放到C:\Users\Uername\.keras\datasets文件夹下,则可直接使用
3、数据分析
获取数据并观察数据结构:
输出单个图片观察:
输出train_image第一项的数据,可看到train_image[0]记录的是0-255的RGB数据
输出标签数据,train_labe是以单个数值作为标签,一个数值表示一种类型的物品
4、建立模型
数据归一化,为了进行回归分析,将训练图片和测试图片中的数据全部转换为0和1
由于每张图片都是28*28的二维数据,所以需要建立Flatten层,而不能直接建立将一维数据映射到一维的Dense层
隐藏层:隐藏单元数要足够大否则会舍弃有用的信息但也不能太大,添加relu**
输出层:输出10个概率值,**函数softmax是关键
5、训练模型与评价(evaluate)
编译模型:
由于标签“train_labe”是数字的顺序编码,因此损失函数用sparse_ categorical_crossentropy
训练模型:正确率从0.82提高到0.89
评价与预测(evaluate):可看到预测结果的准确率是0.87,还算不错的正确率
问题:这里出现一个小题,训练数据集是6W条数据,测试数据集是1W条数据,可是上面显示用到的训练与测试数据分别是1875条与313条,在确定代码没有问题之后我十分的疑惑为什么训练和测试用到数据量不同与视频 中的值。不知道是否是本电脑安装的是CPU版本的TensorFlow所导致的,安装GPU版TensorFlow后再来测试。
6、独热编码与交叉熵损失函数
顺序编码使用sparse_ categorical_crossentropy作为损失函数
独热编码使用categorical_crossentropy作为损失函数
使用tf.keras.utils.to_categorical(train_lable)使用将label的顺序编码转换为独热编码
顺序编码与独热编码对应关系,顺序编码的9、2、1分别对应独热编码三行下标9为1、下标2为1、下标1为1
7、以独热编码方式训练模型
重新构建网络后编译模型使用categorical_crossentrop函数,并使用独热编码的标签train_label_onehot训练模型,可观察到两种编码方式对正确率的影响并不大。
8、预测(predict)
评价模型使用evaluate,预测数据使用predict
由下图可观察到,模型预测之后将test_image中1W张28*28的图片转换为了1W个长度为10(10表示图片被分为10个类别)的向量。从第一个图片的预测结果可看到下标9的数值最大,因此该图片预测结果为标签9,与实际标签相同
三、反向传播算法、学习速率、优化函数
1、多层感知器输出层小结
预测连续值:使用relu**函数或者不使用**函数直接输出
预测“是”或“否”的二分类问题:使用sigmoid**函数计算
预测多分类问题:使用softmax**函数计算多分类的概率分布
2、优化算法——梯度下降算法
梯度的输出是一个由若干偏导数构成的向量,它的每个分量对应于函数对输入向量的相应分量的偏导:
梯度的输出向量表明了在每个位置损失函数增长最快的方向,可将它视为表示了在函数的每个位置向哪个方向移动函数值可以增长。因此沿着梯度相反的方向移动可以快速找到极值点。
学习速率:梯度就是表明损失函数相对参数的变化率,对梯度进行缩放的参数被称为学习速率(learning rate)。学习速率是一种超参数或对模型的一种手工可配置的设置需要为它指定正确的值。
如果学习速率太小,则找到损失函数极小值点时可能需要许多轮迭代;如果太大,则算法可能会“跳过”极小值点并且因周期性的"跳跃”而永远无法找到极小值点。
在具体实践中,可通过查看损失函数值随时间的变化曲线,来判断学习速率的选取是合适的。
学习速率选取原则:在调整学习速率时,既需要使其足够小,保证不至于发生超调,也要保证它足够大,以使损失函数能够尽快下降,从而可通过较少次数的迭代更快地完成学习
3、多层网络求解梯度——反向传播算法
反向传播算法是一种高效计算数据流图中梯度的技术,每一层的导数都是后一层的导数与前一层输出之积,这正是链式法则的奇妙之处,误差反向传播算法利用的正是这一特点。
前馈时,从输入开始,逐一计算每个隐含层的输出,直到输出层并计算出loss值。然后开始计算导数,并从输出层经各隐含层逐一反向传播。为了减少计算量,还需对所有已完成计算的元素进行复用。。
4、常见优化函数
优化器(optimizer)是编译模型的所需的两个参数之一。可以先实例化一个优化器对象,然后将它传入model.compile(),或者可以通过名称来调用优化器。在后后种情况下,将使用优化器的默认参数。
Adam优化器:
1.Adam算法可以看做是修正后的Momentum+ RMSProp算法.
2.Adam通常被认为对超参数的选择相当鲁棒(不敏感)
3.学习率建议为0.001
使用学习速率为0.01的adam优化器
使用默认学习速率0.001的adam优化器
对比训练结果可观察到学习速率为0.01的模型正确率更快达到饱和且没有学习速率为0.001的正确率高。
RMSprop优化器(常用于处理序列问题,例如文本分类、一维卷积、序列预测):
RMSProp被证明有效且实用的深度学习网络优化算法。RMSProp增加了一个衰减系数来控制历史信息的获取多少,RMSProp会对学习率进行衰减。
SGD随机梯度下降优化器:
随机梯度下降优化器SGD和min-batch是同一个意思,抽取m个小批量(独立同分布)样本,通过计算他们平梯度均值。
四、网络优化与超参数选择
网络容量
可以认为网络容量与网络中的可训练参数成正比。网络中的神经单元数越多以及层数越多,经网络的拟合能力越强,但是训练速度越慢、难度越大,越容易产生过拟合。
如何选择超参数?
所谓超参数,也就是搭建神经网络中,需要我们自己选择(而不是通过梯度下降算法去优化)的那些参数。比如,中间层的神经元个数、学习速率
增加拟合能力的两种办法:1、增加隐藏神经元个数(对网络性能的提高并不明显)。2、增加层(会大大提高网络的拟合能力,因此深度学习越来越深)。
注意:
单层的神经元个数不能太小,否则会造成信息瓶颈,使得模型欠拟合(顺序模型传递信息时可能某层的神经元个数过少以致于下一层不能完全接收上一层的信息,导致信息丢失)
添加隐藏层提高拟合能力提高准确率:
五、Dropout抑制过拟合与超参数选择总原则
1、过拟合
过拟合:在训练数据上得分很高, 在测试数据上得分相对比较低
欠拟合(非主要):在训练数据上得分比较低, 在测试数据上得分相对比较低
观察过拟合:
训练模型时添加validation_data参数,可生成测试数据集的loss、准确率等情况
查看history中记录的关键字,包含训练集与测试集的loss、acc
过拟合现象一:绘图观察训练集与测试集的loss变化情况,图中存在val_loss在7个epoch后不但没有下降而且上升了的
过拟合现象二:绘图观察训练集与测试集的acc变化情况,图中测试集正确率远低于训练集正确率为过拟合现象
2、Dropout方法抑制过拟合原理
添加Dropout层后训练时可人为或随机的丢弃一些单元。测试时会使用所有的训练结果,以此达到抑制过拟合。
(1)取平均的作用:标准模型下(即没有dropout),用相同的训练数据去训练5个不同的神经网络一般会得到5个不同的结果,此时可以采用“5个结果取均值”或者“多数取胜的投票策略”去决定最终结果。
(2) 减少神经元之间复杂的共适应关系: 因为dropout程序导致两个神经元不一定每次都在一个dropout网络中出现。这样权值的更新不再依赖于有固定关系的隐含节点的共同作用,阻止了某些特征仅仅在其它特定特征下才有效果的情况。
3、参数选择原则
理想的模型是刚好在欠拟合和过拟合的界线上,也就是正好拟合数据。
首先,开发出过拟合的模型(保证网络有足够的拟合能力,再去调参):
(1)添加更多的层(增加深度)。
(2)让每一层变得更大(增加神经单元数)。
(3)训练更多的轮次。
然后,抑制过拟合:(出现过拟合表示网络的容量足够)
(1)dropout。
(2)正则化。
(3)图像增强。
(4)增加训练数据(最佳)。
(5)使用更小的网络容量(减少神经单元、减少隐藏层)
再次调节超参数以获得更好的结果: 学习速率、隐藏层单元数、训练轮次
构建网络的总原则:
(1)增大网络容量,直到过拟合
(2)采取措施抑制过拟合
(3)继续增大网络容量,直到过拟合
4、Dropout层运用举例
建立模型时在每个Dense层后添加一个Dropout层
编译、训练后观察训练集与测试集新的正确率,未出现训练集正确率高于测试集的情况
观察loss值,同样未出现测试集loss值上升的情况
六、Keras函数式api
函数式API与函数的调用相同,将每一层看作一个函数来调用这一层。
优点:使用函数API可以自定义网络结构。
例如Sequential只有一个输入和输出,中间层只是顺序地一层连接一层的单一结构,如果想将输入直接连接到输出,则需要引入另外一个路径,这时候可以使用函数式API来实现。
1、使用API函数构建模型实例
建立输入后开始调用,
用keras.layers.Flatten()(input1)调用Flatten层,input1作为参数。
用keras.layers.Dense(32, activation='relu')(x)调用Dense层并说明有32个隐藏单元与**函数为relu,x作为参数
用keras.layers.Dropout(0.5)(x)添加Dropout层,比率为0.5,x作为参数
input参数与output参数将输入层、隐藏层、输出层包裹在中间
用keras.Model(inputs=input, outputs=output)建立模型,并说明输入input输出output
查看模型框架,该框架同样可以用Sequential模型建立
2、多输入模型构建实例
假如要判断两张图片上的物体是否为同一类,则模型输入为列表包含两个输入,并且运用逻辑回归得到是或否,如下图:
查看模型框架可观察到模型有两个输入并且两条路径在Concatenate层合并