neural networks
神经网络
为了进行更复杂的预测,我们可以使用神经网络(又称多层感知机multilayer perceptron)。如图所示为一简单的神经网络,该神经网络有4层,其中layer1-3是隐藏层,layer4是输出层,最左边的input也可以算作layer0作为输入层,但一般说层数时不将其算在内。每层中的圆是一个神经元,这些神经元承担了神经网络的计算任务。神经元中可以使用不同的算法进行计算,这里假设每个神经元使用了逻辑回归模型其中.当然,同一层中的不同神经元有不同的参数.
为了区别同一层中的不同神经元的参数,可以用下表表示该参数属于哪个神经元,如右侧放的的layer3中,有三个神经元,不同神经元参数的下标分别是1、2和3,表示他们分别是神经元1、2和3的参数;为了区别不同层神经元的参数,可以用上标表示该参数属于哪个layer,比如图中放大的layer3,其实可以给每个神经元的参数加上上标[3],就像这样,表示他们都是layer3的参数,只不过图中未标出。
通过该图也可以大概了解神经网络的计算过程:将特征输入给layer1,经过计算后layer1得到结果(每一层输出的计算结果称为activations),将它作为layer2的输入,以此类推,最终的output层会通过上一层的输入,计算出最终的结果,该结果是一个标量,根据它我们就可以做出相应的预测,这种方式称为向前传播。
个人思考:不同层中每个神经元参数的数量应该与上一层输出向量的维数有关。假设输入是4纬向量,为了layer1中的每个神经元能够正常计算,明显应该也是4维的;再如layer3中每个神经元参数的维度,应该是layer2输出的activation的维度,layer2中有5个神经元,显然输出的是5维向量,那应该都是5维的。
如图所示为一人脸识别的应用,将一张图片分解为1000*1000个像素点,将这一百万个像素点作为输入特征,输入到一个有3个隐藏层的神经网络中,层层计算后,输出层会输出一个概率,来判断这个人是否匹配的概率。
如果进一步看一下每一层的输出是什么,可以发现:第一层的输出是一个个细小的边缘,第二层的输出是范一些的小整体部分,像是耳朵眼睛什么的,第三层的输出范更大一些了,大概能看到一张脸。但是我们并没有告诉这个神经网络每一层应该做什么,他好像自己知道自己应该做什么一样。
使用tensorflow搭建神经网络
训练模型
step1创建模型
1 | # 1使用Sequential创建神经网络 |
这里调用了Sequential()
函数,创建了一个三层神经网络并自动完成了向前传播。对于每一层中的所有神经元,都使用了sigmoid作为激活函数。
step2编译模型
1 | # 2编译模型并指定二元交叉熵损失函数 |
二元交叉熵函数实际上就是course1中,逻辑回归模型使用的代价函数,它是sigmoid函数常用的损失函数:
step3训练模型
1 | # 3调用fit函数,使用step2中的损失函数拟合step1中的模型,epochs指定梯度下降运行次数 |
这里调用的fit()
函数实现了反向传播,它使得计算偏导数更加高效。
step4利用模型预测
1 | # 4利用模型进行预测 |
为什么需要激活函数以及如何选择
激活函数是每一层中的神经元用于计算的函数,常见的激活函数有三种:线性函数、sigmoid函数和ReLU函数。
下面对这几个函数简单介绍,其中
- 线性函数
最简单的,当所有隐藏层都使用线性函数作为激活函数:
- 输出层也使用线性函数作为激活函数时,输出将作为下一层的输入,因此下一层的输出为.就是说构建了这么复杂的神经网络,得到的效果和线性回归模型一样,这显然是没有必要的;
- 输出层使用sigmoid激活函数,同样能够证明,该神经网络也只能做到逻辑回归模型能做到的事情而已。
基于上述两点,可以说当隐藏层使用线性函数作为激活函数时,该神经网络没有激活函数,因此需要选择其他合适的激活函数。
- sigmoid激活函数
,只能得到0和1之间的数值,因此常用于二元分类问题。
- 整流线性函数ReLU
,可以看出,该函数能得到大于等于0的值,因此可以用于多元分类。
除此之外,可以看到sigmoid函数与ReLU函数的另一个区别:sigmoid函数在z较小和较大时,函数图像较为平坦,也就是说自变量即使有较大的变化,函数值变化依然很小,这就导致了代价函数对于参数w的偏导数很小,因此w每次更新的就会很慢,也就是梯度下降的很慢。相比之下,ReLU函数只在z<0处平坦,另一边没有平坦的地方,因此梯度下降的会快一些。
综上,对于隐藏层和输出层的激活函数的选择可以参考以下方案:
隐藏层:使用ReLU较多,原因:1函数简单,计算更快; 2.只有左边是平坦的,而sigmoid两边都是平坦的,梯度下降遇到平坦的时候运行的很慢。
输出层:根据输出的结果选,二元分类可以选sigmoid,输出有正有负可以选线性激活,输出非负可以选ReLU;
如
1 | from tensorflow.keras.layers import Dense |
多分类和多标签
多分类
二元分类y只有两个结果,多元分类y仍是离散值,只不过有多种结果。在多分类问题中,常使用softmax回归模型。
假设输出值y有N个离散值(像数字识别0-9,y就有10个不同的离散值),softmax回归模型可以定义如下:
特别的,当N=2时:,于是softmax就变成了sogmoid(自己想的,不知道对不对,应该对吧).所以softmax是sogmoid的一般化。
如y有4个输出值,则
softmax的损失函数
其实和二元逻辑回归很类似,如果将二元回归中y=1的概率记为,那么y=0的概率则二元逻辑回归损失函数就变成了:
即
将softmax函数作为输出层,则输出层有10个单元,不同于sigmoid作为输出层函数,只有一个神经元。而且线性激活函数、ReLU激活函数、sigmoid激活函数作为输出层时,每个输出结果只与有关,而softmax的每个与所有的都有关。
tensorflow实现
1 | import tensorflow as tf |
上边的代码可以运行softmax但是不推荐,下边的代码实现的softmax神经网络可以减少舍入误差。
改进后:将输出层的激活函数换成linear,同时改变compile中SparseCategoricalCrossentrop的参数。
1 | import tensorflow as tf |
参数from_logits默认为False,那么对应的输出层此时激活函数为softmax,此时输出层的结果是经过了softmax处理的,最后的概率,然后将作为中间量传递给损失函数,这就导致了误差的产生。而若将参数设置为True,那么对应的此时输出层的激活函数为linear,他所计算的是的,而不是最后的概率.此时tensorflow做的是将整个softmax函数作为参数传递给损失函数,于是损失函数就变成了
也就没有了中间变量带来的误差。然后对于上边的式子,tensorflow会重新排列其顺序,使误差更小(重新排列会避免一些很大或很小的值,从而避免一些舍入,因此精度也会提高)。
参考:keras.losses中from_logits的作用
关于舍入误差
可以看出,使用不同的形式计算同一个值会出现不同的结果,原因是精度问题。由于存储字长的限制,很多小数是无法精确在计算机内部表示的,所以如果存在中间变量,那么存到这个中间变量中的结果是经过舍入的。如b中的1+1/10000和1-1/10000,这两部分是经过舍入后的结果,因此最终结果会有一定偏差。
多标签
多分类中,以识别数字为例,输出y是一个标量,对于一个输入x,他要做的事判断x是什么。而多标签问题中,输出y是一个向量,对于一个输入x,他想表达的是x的一些属性,比如:
对于同一张图片,我们想要知道该图片中是否有行人、汽车和公交。可以将这三个视为该图片的属性。可以看出来,判断每个属性其实就是一个二元分类问题,我们可以根据属性个数构建对应个数的神经网络,但这很繁琐,我们完全可以构建一个神经网络,只不过让输出层有3个输出就可以了。由于每个属性都是二元分类,因此输出层的每个神经元使用sigmoid就可以了。
代价函数高级优化方法
梯度下降算法中,选择合适的学习率很关键,太大太小都不好。Adam算法可以在梯度下降的过程中自动调整的大小:小了让它大一些;大了则让他变小。因此他比梯度下降算法快很多。除此之外,梯度下降算法中,所有的参数共用一个,但是Adam算法中,每个参数有自己的.即
1 | # model |
其他网络层类型
密集层类型Dense:之前代码中,我们使用Dense函数构建的每一层的类型是密集层,密集层中每个神经元都使用了input全部的特征。
卷积层类型Convolutional:卷积层中的每个神经元仅仅使用input的一部分特征。这种做法更快、需要的训练数据更少而且不太容易过拟合。但是输入窗口的大小需要合理选择。
优化模型
模型评估
在训练模型的时候,我们会通过带有正则化项的损失函数来训练参数,但是在评估模型性能的时候,往往通过没有正则化项的损失函数来评估模型的性能。
我们可以将数据集分为两部分,一部分用作训练,一部分用作测试,比例可以是7:3或者8:2等。在评估模型的过程中需要做三个事情:
1.损失函数,带正则化项
2.计算test error:Jtest,用测试样本计算J,不带正则化项。Jtest用于判断该模型表现如何
3.计算train error:Jtrain,用训练样本计算J,不带正则化项。Jtrain衡量了该模型在训练集上表现如何
对于分类问题,Jtest和Jtrain的定义有另一种更为常见的方式:不用逻辑回归的损失函数来计算二者,而分别用二者的错误分类分数来衡量。如Jtest是测试集中将0判断为1,将1判断为0的分数;Jtrain是训练集中将0判断为1,将1判断为0的分数。
模型选择
在一个问题中,有时我们不确定需要什么样子的模型,比如是用1次的线性模型还是更为高次的方程呢?此时我们可以构建多个模型,然后用训练集训练这些模型,训练好以后用测试集来评估这些模型的性能,选择一个Jtest最低的模型。此时Jtest其实做了两件事情:他通过评估每个模型的Jtest(第一件事)来选择了一个性能最好的模型(第二件事)。但是此时说Jtest起到了评估模型的作用其实有点儿不合适,此时Jtest对模型的评估往往比实际误差更小,因为Jtest参与了模型选择的工作,用它来评估自己选择出来的模型损失当然比较小。所以应该把Jtest仅仅作为模型选择的方式,而不应该用它继续做模型评估。
那对于这种情况,就需要新的数据集对已经选择出来的模型评估,所以上述将整个数据集划分为2部分已经不够用了,我们可以将整个数据集划分为三部分:训练集、交叉验证集(AKA验证集AKA开发集AKA dev集)和测试集(比例可以为0.6、0.2、0.2.),并用这三部分分别计算Jtrain、Jcv和Jtest.其中Jtrain用来训练模型,Jcv用来选择模型,到此为止模型已经选择完成了,然后再用Jtest用来评估泛化误差。由于Jtest并未参与模型选择之前的一切工作,因此用它来评估泛化误差会更为准确。
这种方法也可以用来选择神经网络架构:有几层?每层几个神经元?等。
再次理解Jtest和Jcv都是20%的样本,为什么Jtest能更准确的得到误差?
因为用Jtrain训练好模型以后,我们使用Jcv来选择了一个损失最低的模型,就是说我们选择的模型是对应于Jcv这几个样本下的最好模型。至此模型就选择好了。
选择好以后再用Jtest来测试最终选择的模型的好坏,是因为Jtest的这几个样本全程没有参与,因此得到的模型的泛化损失更准确。
正则化、偏差、方差
高偏差的表现:Jtrain很高,如果模型的bias高,那么仅仅通过增加训练集,无法使模型得到优化。
高方差的表现:Jcv远高于Jtrain,如果模型的variance高,那么可以通过仅仅增加训练集来优化模型。
模型不错的表现:Jtrain低且Jcv没有远高于Jtrain.
通过下图所示的学习曲线可以较直观看出模型的偏差和方差(绘制学习曲线不一定用到整个训练集,可以取训练集的子集做一个预判)。
要注意,有时候Jtrain较高并不一定意味着模型不好,如语音识别,有时语音中有噪音,这导致了即使人工识别也会有误差,因此可以允许Jtrain稍大,此时需要与人工识别的误差做比较而不是仅仅关注Jtrain的表现,这其实将人工识别的准确性作为了评估性能的基准。
正则化参数 对bias和variance的影响: 过大,会导致w很小,导致f(x)趋向于b; 过小,导致w很大,则相当于没有正则化。
所以要为模型选择合适的:选择的方法和前面选择模型的方法很类似,也需要借助于Jcv.
偏差和方差作为的函数有如下特性:
几个解决高偏差和高方差的方法:
1.神经网络可以解决high bias和high variance的均衡(tradeoff)问题
只要训练集不是很大,大型神经网络都是low bias的。
大型神经网络会比小的慢,但是如果正则化得当,其表现只会比小的更好。
2.可以参考如下的几种方式
机器学习开发的迭代
第一次构建好一个机器学习的架构以后,往往该模型性能有待提高,可以通过如下方式循环提高模型的性能
其中误差分析是一种手动分析模型的方法:假设你的模型用于判断一个邮件是否为垃圾邮件,该模型误判断了100封邮件,此时为了进一步针对性地提高模型性能,你需要手动查看这100封邮件,看看该模型误判的这些邮件都是什么类型的。比如其中40封是医药相关的、7封是故意拼写错误的(故意拼写错误有时可以避免被当作垃圾邮件)、35封是钓鱼邮件等等。显然该模型对于医药相关邮件和钓鱼邮件的判断准确度不够,因此可以针对这两类邮件选择相应的方法来提高模型的准确性,像收集更多的数据等等。
增加数据的方法:
1.针对性的添加数据集,如上边的例子中,你当然可以在数据集中添加各种类型的垃圾邮件,但是如果针对性的添加模型表现不好的类型的数据,如添加医药相关的垃圾邮件和钓鱼邮件的数据,会更有性价比。
2.数据增强(由于对于图像和音频处理时):通过修改已有的数据集来创建新的数据集。
如在图像识别中,训练集中已有一个A的图像,那么我们可以将该图像旋转、放大、缩小等,这实际上就差生了新的训练集(通过原来的x产生了新的x),但是y仍然没有改变(A还是A)。
除此之外,还可以将图像放置于网格中,然后扭曲该网格图来获取更多的训练集,这种做法可以提高程序的健壮性。
类似的,在语音识别中,可以通过给语音添加背景噪声的方法或者用稍微差一些的设备录音已获得新的训练集。
3.数据合成:人工创造新的训练集而不是将已有的数据集修改为新的。
如下图的OCR应用中,左图为在真实照片中识别到的数据,右图是人工合成的数据。右图的数据是通过在文本编辑器中,用不同的字体打字,然后截屏,再通过调整对比度等等得到的,这样就得到了可以用于ORC训练的数据集
4.迁移学习(transfer learning):使用不同任务的数据来训练模型。
如有模型一用于识别图片中的猫狗等1000个类别,而你想搭建一个用于识别数字的模型二,你可以将模型一的输出层修改为自己需要的,比如数字识别中,输出层只需要10个units.于是只需要将模型一的输出层的1000个units改为10个units就得到了模型二。接下来有两种做法可以选择:第一种是保持模型二复制来的隐藏层参数不变,仅训练输出层的参数;另一种做法是将复制过来的所有隐藏层参数作为初始值,训练模型二的全部层的参数。在本例中,对模型一的训练称为监督预训练(Supervised pretraining),对模型二的训练称为微调(Fine tuning).
这么做是因为可能你用于模型二训练的数据集不够多,而用于训练模型一的数据集充足。而且迁移学习的一个好处是你也许不用亲自训练模型一,可以直接copy别人的。
迁移学习之所以有效是因为在图像识别模型中,第一个隐藏层总是识别边,第二个识别角,第三个识别范围更大一些的基本形状,这对识别任何图片都是有帮助的。因此若想有效的迁移学习,需要保证用于预训练的模型与用于微调的模型要有相同类型的输入。如你的任务是计算机视觉相关,那么预训练的模型的输入图片x需要与你的输入图片x有相同的维度。同样的,你的任务是语音识别,那预训练的模型也得是用语音数据训练的。
机器学习项目的完整周期可以用下图表示:
关于部署:
其中MLOps指的是构建,部署和维护机器学习系统,他也是机器学习的一个领域。
倾斜数据集的误差指标、精确率与召回率
倾斜数据集指的是数据集中的正例样本和负例样本差别非常大,远远不是55开,此时若使用准确度作为误差指标,结果往往不好。比如如果现在有一个病人的数据集,在该数据集中,仅有0.5%的患者患有一种罕见病,那么如果你的模型判断一个病人是否有这种罕见病的逻辑是y=0
(一直预测病人没得这个病),那该模型的准确率也会达到99.5%,一个看起来不错的表现,但实际上这个模型并不行对吧。此时就需要其他的误差指标来衡量该模型的性能。
一对常用的指标是精确率和召回率。为了理解这两个概念,需要引入混淆矩阵。
上图中的22矩阵就是混淆矩阵(以22为例,可以是n*n的,主对角线是预测对的,其余都是预测错的)。可以看出,精确率其实就是模型预测患病的病人中,多少人是真正患病的;召回率就是在所有真正患病病人中,该模型找到了多少。因此我们要追求这两个指标都高的模型。若一个模型仅仅用y=0
作为预测,那么TP=0,进一步的精确率和召回率均为0,所以该模型并不是一个好模型,是个小垃圾。
Trading off precision and recall:
在之前的例子中,我们通常选0.5作为门槛,但是如果想更强调精确度的话,可以将threhold提高;若想强调召回率,可以将threhold降低。观察精确度和召回率的公式:若将threhold提高,那其实预测为1的数量就会变低,因此TP就会变低,那precision的分子分母都会变小,不好判断。但从另一个角度,若提高threhold,说明该模型只在有较高把握的情况下才会做出y=1的判断,因此precision会提高;而实际上的y=1是不会变化的,因此recall会变低。下图反应了precision和recall对于threhold的关系:
如果想要自动均衡精确度和召回率,可以使用另一种误差指标F1 score,实际上就是precision和recall的调和平均值,该值更强调相对较小的数(若一个数很小,他在分母上就会变的很大,所以整体也会偏小,接近小的值)。这样就不需在二者之间做出均衡只看F1 score就可以了。
决策树模型
下图为一个数据集,其输入特征x都是二元的,输出y也是二元的:
如下图所示为几个不同的决策树,其中的椭圆节点称为决策节点(decision nodes),下边的矩形节点就是叶子结点(leaf nodes)。这些决策树可能是同一数据集训练出来的不同模型,决策树学习算法就是从这些模型中选择一个较好的。
建立决策树的关键问题
首先,从输入的特征中选择一个特征作为决策树的根节点。比如此处将耳朵形状作为根节点;
然后,关注一个子树并确定该子树的根节点;
接着,重复上边的操作将数据集划分为合适的子集,并将这些子集作为叶子结点;
最后,回到step2并选择另外一个子树,重复上面的动作。
这其中有两个关键的问题:决策节点的选择和叶节点什么时候该出现。
在选择决策节点的时候,尽量选择一些可以将数据集划分为两个高纯度的子集:如本例中,可以在耳朵形状、脸型、是否有胡须中选择一个作为根 节点,他们的效果如下图所示。
但是如果有一个特征是DNA,那么我们可以用DNA百分之百将整个数据集分为猫和非猫两个子集,所以DNA这个特征就可以作为一个很不错的决策节点。
而对于什么时候该出现叶节点了,通常有四个参考标准:第一是数据集已经完全划分为目标子集了,比如当前的所有子集都是要么全是猫,要么全部是猫;第二是如果继续向下分裂或导致超过决策树的最大高度。决策树的高度是有限制的,做出限制的原因有两个:其一是不会变的太大而笨重,其二是小树不容易过拟合。很多时候其实也是希望树高尽可能小,像二叉排序树这种的,树高往往代表的查找效率;第三是纯度分数的提高低于某个阈值;第四是某个节点的样本数量小于某个阈值。
熵(entropy)和信息增益(information gain)
一个数据集若全是猫,则该数据集很纯;一个数据集若全不是猫,则该数据集同样很纯;如果一个数据集有猫有其他的,则就可以用熵来衡量该数据集的纯度,熵越高,则数据集越不纯。
若将数据集中猫的比例记为,则不是猫的比例,则的熵可以定义为,其中取2为底是因为当时(二元分类二者相等只能为0.5),可以为.这样的意义看起来更明确方便一些。同时注意到熵的定义和逻辑回归模型的损失函数挺像的。
有了熵的帮助后,就可以更好的选择决策节点:应该选择使熵尽可能小的特征作为决策节点。
现在分别计算以不同特征为决策节点,得到的决策树的两个分支的,由于每个树有两个熵,为了便于选择,求出两个熵的加权平均熵,选择最低的即可。
为了遵循决策树的惯例,上边的计算还没做完,需要进一步计算信息增益,但这并不会影响结果。决策树学习中,熵的减少称为信息增益(information gain),他衡量了由于分裂而导致的树的熵的减少的量。
最初始的根节点中有5只猫和5只其他,那么,这是没有分裂时树的熵,用这个值减去树分裂后的加权平均熵即可得到信息增益,信息增益最大的决策树就是我们想要的。
此外,信息增益还可以帮助我们判断事都要继续分裂还是将当前节点作为叶子结点。若信息增益太小了,那表示即使分裂也不会使熵减少的太多,但是分裂导致的树高增加会导致过拟合,因此此时可以停止分裂,将当前数据集作为叶子结点。
下面给出了信息增益的严格定义:
建立决策树的步骤
可以看出其实构建决策树是一个迭代的过程。one-hot编码
上边的数据集中,每个特征的取值只有两种情况。下边的数据集中,耳朵形状的取值有3个,若采用之前的方法将其作为决策节点,则可以构建出一个有三个子树的决策树:
若将数据集稍作更改,其实可以将数据集变成和之前的数据集一样,每个特征只有两个取值:
如果一个特征有k种取值,那么通过one-hot编码可以将该特征转换为k个2进制特征。同样的,若将Face shape的两种取值和Whiskers的两种取值分别记做0和1,那么该数据集就可以用来训练神经网络。
有连续值特征的决策树
若一个特征是有连续值的而不是离散值,我们可以为该连续特征选择一个阈值,以该阈值作为决策节点划分子树。
选择阈值时,需要多尝试几次,计算一个最高的信息增益,用它来分割连续值的特征。
回归树
决策树可以预测离散的值,将其推广就可以得到可以解决回归问题(即预测连续值)的回归树。
比如此时想要预测一个动物的体重,假设此时已经有一个回归树,该回归树的叶子结点分别保存了不同的子数据集。在做出决策的时候,如果该样本落入了其中的一个节点,那么回归树会计算该节点中的所有数据的体重平均值,并预测此次样本的体重为该平均值。
回归树在选择划分节点的时候,不是以信息增益作为标准的,而是以子集的方差作为标准。计算好以不同特征划分的树的子集的平均加权方差后,选择最低的值作为划分特征。同样的,再平均加权方差的基础上,再算一下方差减少,选择最大的方差减少,这在选择结果上和选择最低的平均加权方差的特征是一样的。
决策树集合
单个决策树对数据的微小变化很敏感。比如一个数据集中原本的根节点是耳朵形状,但是把数据集中的一个样本换一下,就可能导致根节点变为了胡须,递归下去就会得到两个完全不一样的决策树。为了解决这个问题,可以使用树集合,也就是建立多个决策树。
训练好决策树集合后,对于新样本的预测,可以将该样本再所有树上都预测一遍,然后选择最多的预测结果作为最终的预测结果,如下图中2棵树认为它是猫,1棵认为它不是猫,那么最终的结果就是它是猫。
替换采样
使用替换采样可以构建一个和原始数据集不同的数据集,这是构建树集合的关键一步。比如原数据集有10个动物,我们每次从这10个动物中随机选一个,然后将其放回,再随机选。这样选10次以后我们就会得到一个和原数据集不同的数据集,当然这个新数据集会有重复的数据,这无所谓。
随机森林算法
有了替换采样后,我们可以得到不同的数据集,进而可以构建出B个决策树。其中B的取值可以为64-228中的任何值。更大的取值虽然不会对模型的性能有损害,但是在超过某个临界点的时候,他的性能提升已经不明显了但是速度却下降了,性价比低,所以也不建议太大。这种又特定实例树组成的集合有时也称为袋装决策树。
尽管已经构建了B个不同的树,但是在所有的B棵树中,也会遇到相同的根节点以及根节点附近的子树的根节点相同的情况。为了解决这个情况,可以进一步将数据集随机化。具体的做法是:每想选择一个特征作为决策节点的时候,若原数据集有n个特征,就随机选择其中k个子特征。每个节点选择的k个子特征都是随机选择,不一样的,不是说只选择一次,然后每个决策节点都用这k个。当n比较大时,k往往取n的平方根。这就是随机森林算法。
由于数据集选择的随机性,随机森林算法在构建树的时候就已经考虑到了很多微小的变化,因此整个模型再经过随机的数据集训练后,对一些小变化会有更好的健壮性。
增强决策树
随机森林算法在构建新数据集上进一步增加了随机性,增强决策树则是在构建新数据集上更有针对性。对于之前构建的决策树分类失败的样本,增强决策树在选择新的数据集时给予这些样本更高的被选择到权重,这样就一步步加强了该模型原本的缺点。
可以看到,第一棵树的数据集使用了替换采样,然后用原数据集测试这棵树,会发现几个分类错误的数据,那么接下来选择样本的时候,这些判断错误的数据将会有更大的概率被选中。具体大多少,为什么更大以后有时间深入研究一下吧。这样当构建了前B-1棵树后,第B棵树就有很多的前边错误分类的样本来参考。
SGBoost tree就是一种很强的增强决策树
决策树VS神经网络
决策树一次只能训练一个,神经网络一次可以训练很多;
单个决策树成本低于决策树集合;
结构化数据如放假预测中,特征x可以存放在电子表格中。非结构化数据如图像声音文本等,不太方便存在表格中。
等等。
遇到的问题
为什么神经网络的每一层能自动知道自己需要做什么?
梯度下降,week1/TensorFlow/C2_W1_Lab02_CoffeeRoasting_TF.ipynb中最后部分提到了。
为什么通过反向传播计算导数更高效?
查阅了相关资料加上自己的一点儿思考,对于代价函数,现在有3种方法求导:
- 利用导数定义求导数(以对求导为例):
若有n个w,则需要计算n次.
- 反向传播求导,其实就是链式法则:
反向传播需要借助计算图
如图所示中间部分就是一个计算图。在第一种方法中,计算每个参数的导数的时候都需要将计算图中的4个框都走一遍,假设有N个框,P个参数,那么总次数就为NP次。
而若利用计算图求导,在第一次从左至右计算出之后,就不需要重复计算了,只需要从右至左选择一条路径利用链式法则求偏导数即可求出每一个参数的导数,而这个过程中需要的计算数值,已经在第一次的从左至右计算中得到了。如J对d的导数为d,在正向传播中已经把d=2传递给了J对应的框中。
其中这一项只计算一次即可,而这一项可以直接用于计算j对w和b的偏导数,因此总共需要计算N+P次。
- 利用公式求导计算
其实最开始思考为什么反向传播快的时候,我第一反应是跟用求导公式比,但查资料的时候没发现有人用公式求导,疑惑了很久,这难道不应该是最先想到的办法吗?后来发现用公式计算应该就是反向传播
以计算w的偏导数为例:
1 | import numpy as np |
参考:
反向传播的直观理解
如何用计算图计算逻辑回归的偏导数
为什么不同型的矩阵相加没报错?
在JupyterLab的C2_W1_Assignment.ipynb(9)中,实现一个简单函数过程中,虽然能运行,但中间有个小细节有个疑问:
1 | def my_dense_v(A_in, W, b, g): |
查阅资料后发现NumPy可以通过广播(broadcasting)来扩展不同型的矩阵,使得两个矩阵可以进行逐元素运算如矩阵相加。他的操作过程是从两个矩阵的最后一个维度开始,向前比较两个矩阵的维度(即从右向左),如果比较的两个维度相等或者其中一个是1,那么这两个矩阵的维度是相容的,可以扩展他们使得二者可以运算,规则是低维向高维扩展。
矩阵相乘问题
在选择激活函数的小节提到的使用线性函数作为激活函数没有做用推倒的公式是用标量推导的,但是应该能推广到矩阵,暂时留着,以后有空推导一下怎么推广以及矩阵乘的意义。