近10万字的机器学习理论知识点文章汇集,满足你对machine learning理论知识的学习~
MLK11 | 一文理清集成学习知识点(Boosting&Bagging)
以下是我平时找论文资源的方法,如果各位还有其他好用的办法,也欢迎推荐给我哈~
简单介绍:arXiv是个提交论文预印本(preprint)的平台,里面的论文都没有经过同行评审(peer review),所以文章质量参差不齐,但却会比较新颖,可以从里面看下别人研究的新玩意。
简单介绍:NIPS(NeurIPS),全称神经信息处理系统大会(Conference and Workshop on Neural Information Processing Systems),是一个关于机器学习和计算神经科学的国际会议,该网站收录相关paper。
传送门:https://paperswithcode.com/
简单介绍: 压轴登场!这个是我强力推荐的一个网站,它不仅收录了很多机器学习的论文,而且还把相关论文的代码也一并收录,大多数也都配备了数据集,可以拿来直接操作一波,而且,它还可以按照热度给我们排序,这样子我们可以挑着一些重要热门的来看,十分友好!
好了,授之以渔了,那接下来就看你们的计划力和行动力了,行动起来吧,下面我就先把我觉得要读的论文贴一贴,这些论文是基于我自己的工作需求找的,我个人觉得大家可以按照自己的工作内容或者是自己想要去发展深造的方法去找相关paper,这样子会更加地有效哦!
[1] XGBoost: A Scalable Tree Boosting System
Download:https://arxiv.org/pdf/1603.02754v3.pdf
[2] CatBoost: gradient boosting with categorical features support
Download:https://arxiv.org/pdf/1810.11363v1.pdf
[3] Tune: A Research Platform for Distributed Model Selection and Training
Download:https://arxiv.org/pdf/1807.05118v1.pdf
[4] Practical Bayesian Optimization of Machine Learning Algorithms
Download:https://arxiv.org/pdf/1206.2944v2.pdf
[5] Hyperopt: A Python Library for Optimizing the Hyperparameters of Machine Learning Algorithms
Download:https://pdfs.semanticscholar.org/d4f4/9717c9adb46137f49606ebbdf17e3598b5a5.pdf
[6] TensorFlow: Large-Scale Machine Learning on Heterogeneous Distributed Systems
Download:https://arxiv.org/pdf/1603.04467v2.pdf
[7] Semi-Supervised Sequence Modeling with Cross-View Training
Download:https://arxiv.org/pdf/1809.08370v1.pdf
[8] Automatic Differentiation in PyTorch
Download:https://openreview.net/pdf?id=BJJsrmfCZ
[9] Caffe: Convolutional Architecture for Fast Feature Embedding
Download:https://arxiv.org/pdf/1408.5093v1.pdf
[10] Bag of Tricks for Efficient Text Classification
Download:https://arxiv.org/pdf/1607.01759v3.pdf
以上的论文我已经下载好了的,大家感兴趣的可以下载来看看哦~
前些天在同行交流群里,有个话题一直在群里热烈地讨论,那就是 如何解释机器学习模型 ,因为在风控领域,一个模型如果不能得到很好的解释一般都不会被通过的,在银行里会特别的常见,所以大多数同行都是会用 LR 来建模。但是,机器学习的模型算法这么多,不用岂不是很浪费?而且有些算法还十分好用的,至少在效果上,如XGBoost、GBDT、Adaboost。
那么,有同学就会问了,为什么这些算法会没有解释性呢?其实是这样子的,刚刚所说的那些模型都是一些集成模型,都是由复杂的树结构去组成的模型,对于人类来说我们很难直观地去解释为什么这个客户就是烂,到底是什么特征导致他烂?
其实像XGBoost之类的模型还算是有解释性的了,我们常常都会看到有人用信息增益、节点分裂数来衡量特征的重要度,但是这真的是合理的吗?
在解释是否合理前,有2个概念需要先给大家普及一下:
1)一致性
指的是一个模型的特征重要度,不会因为我们更改了某个特征,而改变其重要度。比如A模型的特征X1的重要度是10,那么如果我们在模型里给特征X2加些权重以增大其重要度,重新计算重要度后,特征X1的重要度仍是10。不一致性可能会导致具有重要度较大的特征比具有重要度较小的特征更不重要。
2)个体化
指的是重要度的计算是可以针对个体,而不需要整个数据集一起计算。
好了,有了上面的认识,下面就来盘点一下目前常见的特征重要度计算的方法:
1)Tree SHAP:
即 shapley加法解释,基于博弈论和局部解释的统一思想,通过树集成和加法方法激活shap值用于特征归因。
2)Saabas:
一种个性化启发式特征归因方法。
3)mean(| Tree SHAP |):
基于个性化的启发式SHAP平均的全局属性方法。
4)Gain:
即增益,由Breiman等人提出的一种全局的特征重要度计算方法,在XGBoost、scikit learn等包中都可以调用,它是给定特征在分裂中所带来的不纯度的减少值,经常会被用来做特征选择。
5)Split Count:
即分裂次数统计,指的是给定特征被用于分裂的次数(因为越重要的越容易被引用,和论文引用差不多一个道理吧)。
6)Permutation:
即排序置换,指的是随机排列某个特征,看下模型效果误差的变化,如果特征重要的话,模型误差会变化得特别大。
其中,属于个体化的仅有1-2,3-6均属于全局性统计,也就是说需要整个数据集进去计算的。
而对于一致性情况,我们有一个例子来证明:
有2个模型,Model A 和 Model B,其中A和B完全一致,但是我们在计算预测值的时候,强行给 Model B 的 特征 Cough 加上 10分。如下图所示(点击看大图):
从实验结果可以看出以上6种方法的差别:
1)Saabas、Gain、Split Count均不满足 一致性 的要求,在改变了某个特征的权重之后,原先的特征重要度发生了改变,也直接导致重要度排序的改变。
2)而满足一致性要求的方法只有 Tree SHAP 和 Permutation了,而Permutation又是全局的方法,因此就只剩下了 Tree SHAP了。
SHAP(Shapley Additive exPlanation)是解释任何机器学习模型输出的统一方法。SHAP将博弈论与局部解释联系起来,根据期望表示唯一可能的一致和局部精确的加性特征归属方法。
以上是官方的定义,乍一看不知所云,可能还是要结合论文(Consistent Individualized Feature Attribution for Tree Ensembles)来看了。
Definition 2.1. Additive feature attribution methods have an explanation model g that is a linear function of binary variables
M是输入特征的个数, ϕi’ 就是特征的贡献度。ϕ0 是一个常数(指的是所有样本的预测均值)。SHAP 值有唯一的解,也具有3个特性:Local Accuracy、Missingness、Consistency。
1)Local Accuracy:
即局部准确性,表示每个特征的重要度之和等于整个Function的重要度
2)Missingness:
即缺失性,表示缺失值对于特征的重要度没有贡献。
3)Consistency:
即一致性,表示改变模型不会对特征的重要度造成改变。
简单来说,SHAP值可能是唯一能够满足我们要求的方法,而我们上面讲到的XGBoost、GBDT等都是树模型,所以这里会用到 TREE SHAP。
安装还是蛮简单的,可以通过终端的pip安装或者conda安装
pip install shap
or
conda install -c conda-forge shap
目前TREE SHAP可以支持的树集成模型有XGBoost, LightGBM, CatBoost, and scikit-learn tree models,可以看看下面的demo:
import xgboost
import shap
# load JS visualization code to notebook
shap.initjs()
"""训练 XGBoost 模型,SHAP里提供了相关数据集"""
X,y = shap.datasets.boston()
model = xgboost.train({"learning_rate": 0.01}, xgboost.DMatrix(X, label=y), 100)
"""
通过SHAP值来解释预测值
(同样的方法也适用于 LightGBM, CatBoost, and scikit-learn models)
"""
explainer = shap.TreeExplainer(model)
shap_values = explainer.shap_values(X)
# 可视化解释性 (use matplotlib=True to avoid Javascript)
shap.force_plot(explainer.expected_value, shap_values[0,:], X.iloc[0,:])
上面的图展示了每个特征的重要度,会预先计算好一个均值,将预测值变得更高的偏向于红色这边,反之蓝色。
这个数据集有这些特征:'CRIM', 'ZN', 'INDUS', 'CHAS', 'NOX', 'RM', 'AGE', 'DIS', 'RAD', 'TAX', 'PTRATIO', 'B', 'LSTAT'
# visualize the training set predictions
shap.force_plot(explainer.expected_value, shap_values, X)
上图可以看出每个特征之间的相互作用(输出图是可以交互的)。
但是为了理解单个特性如何影响模型的输出,我们可以将该特性的SHAP值与数据集中所有示例的特性值进行比较。由于SHAP值代表了模型输出中的一个特性的变化,下面的图代表了预测的房价随着RM(一个区域中每栋房子的平均房间数)的变化而变化的情况。
单一RM值的垂直色散表示与其他特征的相互作用。要帮助揭示这些交互依赖关系,dependence_plot 自动选择 另一个特征来着色。比如使用RAD着色,突显了RM(每户平均房数)对RAD的值较高地区的房价影响较小。
"""创建一个SHAP图用于展示 单一特征在整个数据集的表现情况,每个点代表一个样本"""
shap.dependence_plot("RM", shap_values, X)
为了得到整体水平上每个特征的重要度情况,我们可以画出所有特征对于所有sample的SHAP值,然后根据SHAP值之和来降序排序,颜色代表特征重要度(红色代表高,蓝色代表低),每个点代表一个样本。
"""画出所有特征的重要度排序图"""
shap.summary_plot(shap_values, X)
我们也可以只是显示SHAP值的所有样本的均值,画出bar图。
shap.summary_plot(shap_values, X, plot_type="bar")
[1] A Unified Approach to Interpreting Model Predictions
http://papers.nips.cc/paper/7062-a-unified-approach-to-interpreting-model-predictions.pdf
[2] Consistent Individualized Feature Attribution for Tree Ensembles
https://arxiv.org/pdf/1802.03888.pdf
[3] Interpretable Machine Learning
https://christophm.github.io/interpretable-ml-book/
[4] shap 官方文档
https://github.com/slundberg/shap
MLK,即Machine Learning Knowledge,本专栏在于对机器学习的重点知识做一次梳理,便于日后温习,内容主要来自于《百面机器学习》一书,结合自己的经验与思考做的一些总结语归纳。
- 特征归一化
- 类别特征处理
- 高维组合的处理
- 文本表示模型
- Word2Vec
- 图像数据不足的处理
为了消除不同数据特征之间的量纲影响,我们需要对数据特征进行归一化处理,使得不同指标之间有一定的可比性。常用的归一化方法有:
- 线性函数归一化(Min-Max Scaling): 对数据进行线性变换,使之映射到0~1之内,其公式为:
- 零均值归一化(Z-Score Normalization): 对数据进行转换映射到均值为0,标准差为1的分布上。
那么,特征归一化的原因是什么呢?一般可以参考下面的随机梯度下降的例子:
![image-20190630220646075](./assets/feature Scaling.png)
其中,上图中X1的取值范围为[0, 10],X2的取值范围为[0, 3],当不做任何数据归一化处理的时候,在学习率相同的情况下,X1的更新速度会大于X2,需要较多次的迭代才会找到最优解,就如左图所示。相反如果归一化后,则会像右图一样,更加容易找到最优解。
所以,我们可以得出一种常见的结论,就是 通过梯度下降法求解的模型一般都是需要特征归一化的,如线性回归、逻辑回归、支持向量机、神经网络等等。
类别变量,又叫Categorical Feature,比如性别、教育水平之类的,一般模型都是无法直接用这些变量的,都需要经过一些转换,一般常用的方法如下:
-
序号编码(Ordinal Encoding):通过用来处理有序变量,如成绩,可以分为高分、中等、低分,可以按照高分>中等>低分的顺序来进行编码。
-
独热编码(One-hot Encoding):通过用来处理类别间没有大小关系的特征,如血型,比如A、B、O、AB,通过独热编码可以变成一个4维稀疏向量,A(1,0,0,0)、B(0,1,0,0)、O(0,0,1,0)、AB(0,0,0,1)。但是,一般如果遇到了类别特别多的类别变量,如城市,可就要注意:
1)利用稀疏向量来作为输入,从而节省空间;
2)配合特征选择降低维度。因为高维度特征在K-means算法中会很难衡量距离,在逻辑回归中很容易出现过拟合现象。
-
二进制编码(Binary Encoding):二进制编码主要分两步,先用序号编码给每个类别赋予新的类别ID,然后对类别ID进行二进制编码,还是血型A、B、O、AB,分别赋予为1,2,3,4,对应的二进制为001、010、011、100,其相比于独热编码还是可以节省一些空间。
高维组合指的就是变量组合与衍生,如近6个月金融类产品的使用次数(时间+产品类别),当交叉维度特别大的时候,则几乎没法训练模型。所以很多时候我们都是需要向低维度去分解,比如mxn规模的参数,可以分别用k维的低维度向量表示(k<<m, k<<n)。
而且,并不是所有的特征组合都有意义,盲目地去组合会出现参数过多,过拟合的情况,所以我们需要一个方法去有效地找到组合特征,一般常用地有基于决策树的特征组合寻找方法,从根节点出发到叶子节点的每一条路径都是一种特征组合,那如何构建有效的决策树?一般用梯度提升决策树,就是每次都在之前构建的决策树的残差上构建下一棵决策树。
文本在机器学习领域是一个十分常见的非结构化数据,如何表示文本数据是十分重要的研究领域,常见的概念有:
-
词袋模型(Bag of Words):指的是将整段文本以词为单位切分开,然后每篇文章可以表示成一个长向量,向量中的每一维代表一个单词,而该维对应的权重则反映了这个词语在原文章中的重要程度。
权重TF-IDF(Term Frequency-Inverse Document Frequency)的计算公式:
- IDF(t) 为逆文档频率,用来衡量单词t对表达语义所起的重要性,如果一个词在非常多的文章中都出现过,那么它可能是一个比较通用的词,那么贡献会较小,权重需要做惩罚。
- N-gram模型:将连续出现的n个词(n<=N)组成的词组(N-gram)作为一个单独的特征放到向量表示中去构成模型。另外,同一个词可能有多种词性变化,所以一般会对单词进行词干抽取(Word Stemming),统一为同一词干的形式。
- 主题模型(Topic Model):用于从文本库中发现有代表性的主题,并且能够计算出每篇文章的主题分布。
- 词嵌入模型(Word Embedding):词嵌入是一类将词向量化的模型的统称,核心思想是将每个词都映射成低维空间(通常K = 50~300)上的一个稠密向量(Dense Vector)。
Word2Vec上Google在2013年提出的词嵌入模型,其实就是一种浅层的神经网络模型,有两种网络结构:CBOW(Continues Bag of Word) 和 Skip-gram,都可以表示为由输入层(Input)、映射层(Projection)和输出层(Output)组成的神经网络。
CBOW(Continues Bag of Word)
根据上下文出现的词语来预测当前词语的生成概率。
Skip-gram
根据当前词语来预测上下文中各个词语的生成概率。
输入层
每个词都由独热编码方式表示,即所有词均表示为一个N维向量,其中N为词汇表中单词的总数,在向量中,每个词都将与之对应的维度置为1,其余维度的值均设为0。
映射层
又被叫做隐含层,K个隐含单元的取值可以由N维输入向量以及连接输入和隐含单元之间的NxK维 权重矩阵计算得到,在CBOW中,还需要将各个输入词所计算出的隐含单位求和。
输出层
通过隐含层向量(K维),以及连接隐含层和输出层之间的KxN维的权重矩阵计算得到,输出层是一个N维向量,每维与词汇表中的一个单词相对应,最后对输出层向量应用Softmax激活函数,可以计算出每个单词的生成概率。
Softmax公式:(其中X代表N维的原始输出向量,Xn为在原始输出向量中,与单词Wn所对应维度的取值。
一个模型所能提供的信息一般由两个来源:
- 训练数据中所蕴含的信息
- 人们提供的先验信息
一般,当你的图像数据不足的时候,可能会出现的情况就是模型过拟合,一般过拟合的处理办法有两种:
-
基于模型的方法: 采用降低过拟合风险的措施,如简化模型、添加正则项、boosting、Dropout超参数等等;
-
基于数据的方法: 主要包括数据扩充(Data Augmentation),即根据一些先验知识,在保持特定信息的前提下对原始数据进行适当变换,因此,对于图像,我们可以有下面的方法去进行变换。
-
一定程度内的随机旋转、平移、缩放、裁剪、填充、左右翻转;
-
对图像中的像素添加噪声,如椒盐噪声、高斯白噪声;
-
颜色变换;
-
改变图像的亮度、清晰度、对比度、锐度等等。
-
MLK,即Machine Learning Knowledge,本专栏在于对机器学习的重点知识做一次梳理,便于日后温习,内容主要来自于《百面机器学习》一书,结合自己的经验与思考做的一些总结与归纳。本次主要讲解的内容就是特征降维,主要涉及PCA以及一些常见分析方法。
- PCA降维算法
- 内积与投影
- 基与基变换
- 方差
- 协方差
- 协方差矩阵
- 协方差矩阵对角化
- PCA算法步骤
- PCA实例
- PCA的Python操作
- LDA降维算法
- LDA介绍
- LDA的优缺点
- LDA的Python操作
在机器学习中,我们有的时候会遇到维度灾难,当模型的训练入参有很多的时候,往往是需要很多的时间和资源去训练的,而这不是我们想要看到的结果。一般情况下,我们都是会对源数据进行特征处理,提取对预测更加有效的特征。
有的时候,我们会得到比较高维的特征向量,而这里面往往包含很多的噪声与冗余数据,所以我们需要通过降维的方式去获取特征更加有效的信息,一来提高特征表达能力,二来提高模型训练的效率。
PCA(Principal Components Analysis),即主成分分析,是降维操作中最经典的方法,它是一种线性的、无监督、全局性的降维算法,旨在找到数据中的"主要成分",提取主成分从而达到降维的目的。PCA是一种无监督算法,也就是我们不需要标签也能对数据做降维,这就使得其应用范围更加广泛了,但是PCA也有一个问题,原来的数据中比如包括了年龄,性别,身高等指标降维后的数据既然维度变小了,那么每一维都是什么含义呢?这个就很难解释了,所以PCA本质来说是无法解释降维后的数据的物理含义。
在了解PCA之前,有一些基础的名词需要温习一下:
1. 内积与投影
内积运算将两个向量映射为一个实数,下面是两个维数相同的向量的内积:
假设存在两个点A,B,其在坐标轴的位置如下图:
我们从A向B引一条垂线,也就是A在B上的投影,其夹角为a,则投影的矢量长度为|A|cos(a),其中是向量A的模,也就是A线段的标量长度。
而内积的另一种表现形式为:
也就是说,当B的模为1的时候,也就是单位向量的时候,内积可以表示为:
也就是A与B的内积值等于A向B所在直线投影的矢量长度。
2. 基与基变换
基可以理解为单位向量,基都是正交的(即内积为0,直观来说就是相互垂直),并且是线性无关的。
基变换指的是当前向量和一个基进行内积运算,得到的结果作为新的坐标分量。
假设存在一个点(3,2),一般我们都会取(1,0)和(0,1)为基,也就是我们的X和Y轴方向。如果我们取(1,1)和(-1,1)为我们的基,但我们希望基的模为1,这样子会方便计算,所以可以除以当前的模长,所以上面的基就变成了:
如下图所示:
所以,进行基变换,只需要进行一次内积运算:
3. 方差
一个字段的方差可以看做是每个元素与字段均值的差的平方和的均值,即:
一般我们都会把均值为化为0,即进行一次变换,所以方差可以表示为:
4. 协方差
如果单纯地选择方差最大的方向,则无法保证两个字段之间相互独立,因为我们需要的是尽可能多地保留原始信息,但又是相互独立,这里我们引入一下概念,协方差,用来表示两个字段的相关性,公式为:
协方差:度量各个维度偏离其均值的程度。协方差的值如果为正值,则说明两者是正相关的(从协方差可以引出“相关系数”的定义),结果为负值就说明负相关的,如果为0,也是就是统计上说的“相互独立”。
所以,我们的目标就是让两个字段的协方差为0,为了协方差为0,选择第二个基的时候,必须要在第一个基的正交方向上选择。
我们说的PCA降维,就是把N维的特征,降到K维(0 < K < N),也就是说要选择k个单位正交基,并且尽可能让方差最大化。
5. 协方差矩阵
在统计学与概率论中,协方差矩阵的每个元素是各个向量元素之间的协方差,是从标量随机变量到高维度随机向量的自然推广。
可以看出,协方差矩阵的对角线元素为两个字段的方差,而其他元素为矩阵的协方差,按照我们之前的说法,我们需要得到协方差为0,并且方差最大的转换。
6. 协方差矩阵对角化
根据上述推导,我们发现要达到优化目前,等价于将协方差矩阵对角化:即除对角线外的其它元素化为0,并且在对角线上将元素按大小从上到下排列,这样我们就达到了优化目的。这样说可能还不是很明晰,我们进一步看下原矩阵与基变换后矩阵协方差矩阵的关系。
设原始数据矩阵X对应的协方差矩阵为C,而P是一组基按行组成的矩阵,设Y=PX,则Y为X对P做基变换后的数据。设Y的协方差矩阵为D,我们推导一下D与C的关系:
我们要找的P不是别的,而是能让原始协方差矩阵对角化的P。换句话说,优化目标变成了寻找一个矩阵P,满足PCP^T是一个对角矩阵,并且对角元素按从大到小依次排列,那么P的前K行就是要寻找的基,用P的前K行组成的矩阵乘以X就使得X从N维降到了K维并满足上述优化条件。
7. PCA算法步骤
设有mXn维数据。
1)将原始数据按列组成n行m列矩阵X
2)将X的每一行(代表一个属性字段)进行零均值化,即减去这一行的均值
3)求出协方差矩阵C=1mXXT
4)求出协方差矩阵的特征值及对应的特征向量
5)将特征向量按对应特征值大小从上到下按行排列成矩阵,取前k行组成矩阵P
6)Y=PX即为降维到k维后的数据
8. PCA实例
1)均值归0:目前每个维度的均值均为0,无需变换。
2)求协方差矩阵
3)求解特征值以及特征向量
可以参考:https://jingyan.baidu.com/article/27fa7326afb4c146f8271ff3.html
4)标准化特征向量
5)得到对角矩阵P并验证对角化
6)因为需要得到1维矩阵,因此用P的第一行乘以原矩阵即可:
降维投影如下图所示:
9. Python操作
# 使用sklearn进行PCA降维
import numpy as np
from sklearn.decomposition import PCA
X = np.array([[-1,2,66,-1], [-2,6,58,-1], [-3,8,45,-2], [1,9,36,1], [2,10,62,1], [3,5,83,2]]) #导入数据,维度为4
print('原矩阵X:\n', X)
pca = PCA(n_components=2) #降到2维
pca.fit(X) #训练
newX=pca.fit_transform(X) #降维后的数据
print('贡献率:', pca.explained_variance_ratio_)
print('降维后矩阵:\n', newX)
'''
参数解释:
n_components: 我们可以利用此参数设置想要的特征维度数目,可以是int型的数字,也可以是阈值百分比,如95%,让PCA类根据样本特征方差来降到合适的维数,也可以指定为string类型,MLE。
copy: bool类型,TRUE或者FALSE,是否将原始数据复制一份,这样运行后原始数据值不会改变,默认为TRUE。
whiten:bool类型,是否进行白化(就是对降维后的数据进行归一化,使方差为1),默认为FALSE。如果需要后续处理可以改为TRUE。
explained_variance_: 代表降为后各主成分的方差值,方差值越大,表明越重要。
explained_variance_ratio_: 代表各主成分的贡献率。
inverse_transform(): 将降维后的数据转换成原始数据,X=pca.inverse_transform(newX)。
'''
线性判别分析(Linear Discriminant Analysis,LDA)是一种有监督学习算法,也是经常被拿来降维,它和PCA的区别在于是否存在标签,其中心思想就是—— 最大化类间距离和最小化类内距离。
而PCA的不足在于不能很好地分开不同类别的数据,如下图:
LDA算法既可以用来降维,又可以用来分类,但是目前来说,主要还是用于降维。在我们进行图像识别图像识别相关的数据分析时,LDA是一个有力的工具。下面总结下LDA算法的优缺点:
优点:
1)在降维过程中可以使用类别的先验知识经验,而像PCA这样的无监督学习则无法使用类别先验知识。
2)LDA在样本分类信息依赖均值而不是方差的时候,比PCA之类的算法较优。
缺点:
1)LDA不适合对非高斯分布样本进行降维,PCA也有这个问题。
2)LDA降维最多降到类别数k-1的维数,如果我们降维的维度大于k-1,则不能使用LDA。当然目前有一些LDA的进化版算法可以绕过这个问题。
3)LDA在样本分类信息依赖方差而不是均值的时候,降维效果不好。
4)LDA可能过度拟合数据。
Reference十分钟搞定PCA主成分分析
https://blog.csdn.net/tangyudi/article/details/80188302#comments
PCA的数学原理
http://blog.codinglabs.org/articles/pca-tutorial.html
MLK,即Machine Learning Knowledge,本专栏在于对机器学习的重点知识做一次梳理,便于日后温习,内容主要来自于《百面机器学习》一书,结合自己的经验与思考做的一些总结与归纳。本次主要讲解的内容就是数据采样的内容,主要介绍一些常见的数据采样方法以及理论。
- 数据采样的原因
- 常见的采样算法
- 失衡样本的采样
- 采样的Python实现
其实我们在训练模型的过程,都会经常进行数据采样,为了就是让我们的模型可以更好的去学习数据的特征,从而让效果更佳。但这是比较浅层的理解,更本质上,数据采样就是对随机现象的模拟,根据给定的概率分布从而模拟一个随机事件。另一说法就是用少量的样本点去近似一个总体分布,并刻画总体分布中的不确定性。
因为我们在现实生活中,大多数数据都是庞大的,所以总体分布可能就包含了无数多的样本点,模型是无法对这些海量的数据进行直接建模的(至少目前而言),而且从效率上也不推荐。
因此,我们一般会从总体样本中抽取出一个子集来近似总体分布,这个子集被称为**“训练集”,然后模型训练的目的就是最小化训练集上的损失函数,训练完成后,需要另一个数据集来评估模型,也被称为“测试集”**。
采样的一些高级用法,比如对样本进行多次重采样,来估计统计量的偏差与方法,也可以对目标信息保留不变的情况下,不断改变样本的分布来适应模型训练与学习(经典的应用如解决样本不均衡的问题)。
采样的原因在上面已经阐述了,现在我们来了解一下采样的一些算法:
有的时候一些分布不好直接采样,可以用函数转换法,如果存在随机变量x和u的变换关系:u=ϕ(x),则它们的概率密度函数如下所示:
p(u)|ϕ′(x)|=p(x)
因此,如果从目标分布p(x)中不好采样x,可以构造一个变换u=ϕ(x),使得从变换后地分布p(u)中采样u比较容易,这样可以通过对u进行采样然后通过反函数$$x = \phi ^{-1}(u) $$ 来间接得到x。如果是高维空间地随机变量,则ϕ′(x)对应Jacobian行列式。
而且,如果变换关系ϕ(·)是x的累积分布函数的话,则就是我们说的 逆变换采样(Inverse Transform Sampling), 我们假设待采样的目标分布的概率密度函数为p(x), 它的累积分布函数为: $$ u = \phi(x)=\int_{-\infty}^x p(t) dt $$ 逆变换采样法的过程:
- 从均匀分布U(0,1)产生一个随机数
- 计算逆函数
来间接得到x
但并不是所有的目标分布的累积分布函数的逆函数都是可以求解的(or容易计算),这个时候逆变换采样法就不太适用,可以考虑拒绝采样(Rejection Sampling)和重要度采样(Importance Sampling)。
拒绝采样,也被称为接受采样(Accept Sampling),对于目标分布p(x),选取一个容易采样的参考分布q(x),使得对于任意的x都有
可以知道,包络函数越“紧”,$$p(x_i)$$与$$M \cdot q(x_i)$$的大小越接近,那么$$ \frac {p(x_i)}{M \cdot q(x_i)} $$就越接近1,那么更容易接受采样样本A,这样子采样的效率就越高。
除了上面的形式,还有一种叫自适应拒绝采样(Adaptive Rejection Sampling),在目标分布是对数凹函数时,用分段的线性函数来做包络函数,如下图所示:
还有一种采样方法,是计算函数f(x)在目标分布p(x)上的积分(函数期望),即:
$$
E[f] = \int f(x)p(x)dx
$$
我们先找一个比较容易抽样的参考分布q(x),并令
在高维空间中,拒绝采样和重要性采样很难寻找到合适参考分布,而且采样的效率是很低的,这个时候是可以考虑一下马尔科夫蒙特卡洛(Markov Chain Monte Carlo,MCMC)采样法。
可能有一些同学对这个名词还是比较陌生,那么先来讲解一下MCMC。
1. 主要思想
MCMC采样法主要包括两个MC,即Monte Carlo和Markov Chain。Monte Carlo是指基于采样的数值型近似求解方法,Markov Chain则是用于采样,MCMC的基本思想是:针对待采样的目标分布,构造一个马尔科夫链,使得该马尔科夫链的平稳分布就是目标分布,然后从任何一个初始状态出发,沿着马尔科夫链进行状态转移,最终得到的状态转移序列会收敛到目标分布,由此得到目标分布的一系列样本。
MCMC有着不同的马尔科夫链(Markov Chain),不同的链对应不用的采样法,常见的两种就是Metropolis-Hastings采样法和吉布斯采样法。
2. Metropolis-Hastings采样法
对于目标分布p(x),首先选择一个容易采样的参考条件分布
1)随机选取一个初始样本 $$ x^{(0)} $$
2)For t =1, 2, 3, ...:
{ 根据参考条件分布 $$ q(x^|x^{(t-1)}) $$抽取一个样本 $$x^$$
根据均匀分布U(0,1)产生随机数u
若 $$u < A(x^{(t-1)}, x^) $$,则令 $$x^{(t)}=x^$$,否则令
上面的图是Metropolis-Hastings的示意过程图,其中红线代表被拒绝的移动(维持旧样本),绿线代表被接受的移动(采纳新样本)。
3. 吉布斯采样法
吉布斯采样法是Metropolis-Hastings的一个特例,其核心是每次只对样本的一个维度进行采样和更新,对于目标分布p(x),其中
1)随机选择初始状态 $$ x^{(0)} = (x^{(0)}_1, x^{(0)}_2,..., x^{(0)}_d)$$
2)for t = 1, 2, 3, ...:
{ 对前一步产生的样本 $$ x^{(t-1)} = (x^{(t-1)}_1, x^{(t-1)}_2,..., x^{(t-1)}_d)$$,依次采样和更新每个维度的值,即依次抽取分量 $$ x^{(t)}_1 p(x_1 | x^{(t-1)}_2, x^{(t-1)}_3,..., x^{(t-1)}_d)$$
形成新的样本 $$ x^{(t)} = (x^{(t)}_1, x^{(t)}_2,..., x^{(t)}_d)$$
}
同样的上述过程得到的样本序列会收敛到目标分布p(x),另外步骤2中对样本每个维度的抽样和更新操作,不是必须要按照下标顺序进行的,可以是随机进行的。
在拒绝采样中,如果在某一步得到的样本被拒绝,则该步不会产生新样本,需要重新进行采样,如在MCMC中,每一步都是会产生一个样本的,只是有的时候是保留旧样本罢了,而且MCMC是会在不断迭代过程中逐渐收敛到平稳分布的。
我们在实际的建模中总会遇到很多失衡的数据集,比如点击率模型、营销模型、反欺诈模型等等,往往坏样本(or好样本)的占比才千分之几。虽然目前有些机器学习算法会解决失衡问题,比如XGBoost,但是很多时候还是需要我们去根据业务实际情况,对数据进行采样处理,主要还是分两种方式:
过采样(over-sampling):从占比较少的那一类样本中重复随机抽样,使得最终样本的目标类别不太失衡;
欠采样(under-sampling):从占比较多的那一类样本中随机抽取部分样本,使得最终样本的目标类别不太失衡;
科学家们根据上述两类,衍生出了很多方法,如下:
1)Random Oversampling
也就是随机过采样,我们现在很少用它了,因为它是从样本少的类别中随机抽样,再将抽样得来的样本添加到数据集中,从而达到类别平衡的目的,这样子做很多时候会出现过拟合情况。
2)SMOTE
SMOTE,全称是Synthetic Minority Oversampling Technique,其思想就是在少数类的样本之间,进行插值操作来产生额外的样本。对于一个少数类样本$\mathbf{x}i$,使用K-Mean法(K值需要人工确定)求出距离$\mathbf{x}i$ 距离最近的k个少数类样本,其中距离定义为样本之间n维特征空间的欧式距离,然后从k个样本点钟随机抽取一个,使用下面的公式生成新的样本点: $$ \mathbf{x}{new}=\mathbf{x}{i}+(\mathbf{\hat{x}}{i}-\mathbf{x}{i}) \times \delta $$ 其中,$\mathbf{\hat{x}}$ 为选出的k近邻点,$\delta\in[0,1]$是一个随机数。下图就是一个SMOTE生成样本的例子,使用的是3-近邻,可以看出SMOTE生成的样本一般就在 $\mathbf{x}{i}$和$ \mathbf{\hat{x}}{i}$相连的直线上:
从图中可以看出
(1)如果选取的少数类样本周围都是少数类样本,那么新合成的样本可能不会提供太多有用的信息;
(2)如果选取的少数类样本周围都是多数类样本,那么这可能会是噪声,也无法提升分类效果。
其实,最好的新样本最好是在两个类别的边界附近,这样子最有利于分类,所以下面介绍一个新算法——Border-Line SMOTE。
3)Border-Line SMOTE
这个算法一开始会先将少数类样本分成3类,分别DANGER、SAFE、NOISE,如下图:
而Border-line SMOTE算法只会在“DANGER”状态的少数类样本中去随机选择,然后利用SMOTE算法产生新样本。
4)ADASYN
ADASYN名为自适应合成抽样(Adaptive Synthetic Sampling),其最大的特点是采用某种机制自动决定每个少数类样本需要产生多少合成样本,而不是像SMOTE那样对每个少数类样本合成同数量的样本。ADASYN的缺点是易受离群点的影响,如果一个少数类样本的K近邻都是多数类样本,则其权重会变得相当大,进而会在其周围生成较多的样本。
1)Random Undersampling
这类也是比较简单的,就是随机从多数类中删除一些样本,这样子的缺失也是很明显,那就是造成部分信息丢失,整体模型分类效果不理想。
2)EasyEnsemble 和 BalanceCascade
这两个算法放在一起的原因是因为都用到了集成思想来处理随机欠采样的信息丢失问题。
- EasyEnsemble :将多数类样本随机划分成n份,每份的数据等于少数类样本的数量,然后对这n份数据分别训练模型,最后集成模型结果。
- BalanceCascade:这类算法采用了有监督结合boosting的方式,在每一轮中,也是从多数类中抽取子集与少数类结合起来训练模型,然后下一轮中丢弃此轮被正确分类的样本,使得后续的基学习器能够更加关注那些被分类错误的样本。
3)NearMiss
NearMiss本质上是一种原型选择(prototype selection)方法,即从多数类样本中选取最具代表性的样本用于训练,主要是为了缓解随机欠采样中的信息丢失问题。NearMiss采用一些启发式的规则来选择样本,根据规则的不同可分为3类:
- NearMiss-1:选择到最近的K个少数类样本平均距离最近的多数类样本
- NearMiss-2:选择到最远的K个少数类样本平均距离最近的多数类样本
- NearMiss-3:对于每个少数类样本选择K个最近的多数类样本,目的是保证每个少数类样本都被多数类样本包围
NearMiss-1和NearMiss-2的计算开销很大,因为需要计算每个多类别样本的K近邻点。另外,NearMiss-1易受离群点的影响,如下面第二幅图中合理的情况是处于边界附近的多数类样本会被选中,然而由于右下方一些少数类离群点的存在,其附近的多数类样本就被选择了。相比之下NearMiss-2和NearMiss-3不易产生这方面的问题。
《百面机器学习》—— Chapter 7
机器学习之类别不平衡问题 (3) —— 采样方法
https://nbviewer.jupyter.org/github/massquantity/Class-Imbalance/blob/master/Code_Sampling.ipynb
MLK,即Machine Learning Knowledge,本专栏在于对机器学习的重点知识做一次梳理,便于日后温习,内容主要来自于《百面机器学习》一书,结合自己的经验与思考做的一些总结与归纳。本次主要讲解的内容是机器学习里的非监督学习经典原理与算法,非监督,也就是没有target(标签)的算法模型。
- K-Mean聚类算法
- 高斯混合模型
- 自组织映射神经网络
- 聚类算法的评估指标
- 常见聚类算法对比
- 常见聚类算法的Python实现
在机器学习中存在一种问题,那就是模型是没有target的,给机器输入大量的特征数据,期望机器可以学习出当中的共性或者结构又或者是关联,并不需要像监督学习那样输出某个预测值。
K-Mean的基本思想就是通过迭代的方式寻找K个簇(Cluster)的一种划分方案,使得聚类结果对应的Cost Function最小,一般K-Mean的Cost Function为各个样本距离所属簇中心点的误差平方和,公式为:
其中Xi代表第i个样本,Ci是Xi所属的簇,μci代表簇对应的中心点,M是样本总数。
首先先来看一下K-Mean算法的具体步骤描述:
1)数据预处理,如归一化、异常值处理;
2)随机抽取K个簇(K由人工设定);
4)不断迭代下面👇步骤,直到CF收敛:
1)对于大数据集,算法还是相对高效的,计算复杂度为O(NKt),其中N为样本数,K为聚类数,t为迭代的论数;
2)一般情况下都可以满足聚类的需求。
1)需要人工确定K值,人工对大数据的K值预判有的时候不太好;
2)K-Mean很容易局部最优,所以效果很受一开始的初始值影响;
3)容易受到异常值,噪点的影响。
1)数据归一化和异常值处理。
因为K-Mean本质上是基于欧式距离度量的数据聚类方法,所以少量的极端值会影响聚类效果的,而且不同量纲的数据也会有不一样的影响,所以需要做一下预处理。
2)合理选择K值。
K值并不是拍脑袋拍出来的,需要用科学的办法去确定。一般可以通过多次试验结果决定,如采用手肘法:
其中,横轴为K的取值,纵轴为误差平方和所定义的Loss Function。
可以看出,K值越大,距离和越小,我们看到当K=3的时候,曲线出现"拐点",因此一般我们选择这个点作为我们的K值。
此外,这里还介绍一个GS(Gap Statistic)方法,可参考:
https://blog.csdn.net/baidu_17640849/article/details/70769555
3)采用核函数。
传统的欧式距离度量方式使得K-Mean算法本质上是假设各个簇的数据具有一样的先验概率,并呈现球形或者高维球形分布,但这种分布在现实中不太常见,这个时候我们引入一个核K-Mean算法,主要面对非凸的数据分布。
这类核聚类方法主要是通过一个非线性映射,将输入控件中的数据点映射到高位的特征空间中,并在新的特征空间中进行聚类,非线性映射增加了数据点线性可分的概率,从而达到更高精度的聚类结果。
1)K-Mean++算法
这个从名字上看,就是K-Mean的改良版,主要是在初始值的选取上作了改进。原先的K-Mean是随机选择初始值,而K-Mean++算法则是:
- 第1个聚类中心也是随机;
- 接下来的聚类中心,也就是第2个,按照距离当前聚类中心越远越好;
- 按照上述思想,选择了k个初始的聚类中心;
- 初始值选取完毕后,后续的流程和K-Mean是一样的。
2)ISODATA算法
当K值的大小不确定的时候,可以使用ISODATA算法,全称叫迭代自组织数据分析法。ISODATA算法在K-Mean算法的基础上增加了两个操作:
- 分裂操作,对应着增加聚类中心数
- 合并操作,对应着减少聚类中心数
ISODATA的应用也是比较复杂的,需要填比较多的参数:
- 预期的聚类中心数据K0:在ISODATA运行过程中聚类中心数可以自动变化,这里的K0只是一个参考值;
- 每个类所要求的的最少样本数Nmin:如果分裂后会导致某个子类别所包含的样本数量少于该阈值,会拒绝本次分裂操作;
- 最大方差Sigma:用于控制某个类别中样本的分散程度,当样本的分散程度超过某个阈值时,且分裂后满足第一条要求,则进行分裂操作;
- 两个聚类中心之间所允许的最小距离Dmin:如果两个簇靠得很近,就会被进行合并操作。
高斯模型,对应着高斯分布,高斯分布也就是我们平时常说的正态分布,高斯混合模型(Gaussian Mixed Model,GMM)也是一种聚类算法,和K-Mean算法类似,都是用了EM算法进行迭代计算。高斯混合模型是假设每个簇的数据都符合正态分布,当前数据呈现的分布则是每个正态分布的混合结果。
高斯混合模型的核心思想,每个单独的分模型都是标准高斯分布模型,其均值和方差都是待估计的参数,还有一个参数π,可以理解为权重(or 生成数据的概率),其公式为:
它是一个生成式模型,并且通过EM算法框架来求解,具体的迭代过程如下:
首先,初始随机选择各个参数的值(总共3个参数,均值、方差和权重),然后迭代下面两步,直到收敛:
1)E步骤:根据当前的参数,计算每个点由某个分模型生成的概率。
2)M步骤:使用E步骤估计出来的概率,来改进每个分模型的均值、方差和权重。
高斯混合模型与K-Mean算法的相同点:
1)他们都是用于聚类的算法,都需要指定K值;
2)都是使用EM算法来求解;
3)往往都是得到局部最优。
而它相比于K-Mean算法的优点,就是它还可以用于概率密度的估计,而且可以用于生成新的样本点。
生成式模型(Generative Model):对联合分布概率p(x,y)进行建模,常见生成式 模型有:隐马尔可夫模型HMM、朴素贝叶斯模型、高斯混合模型GMM、LDA 等。
判别式模型(Discriminative Model):直接对条件概率p(y|x)进行建模,常见判 别模型有:线性回归、决策树、支持向量机SVM、k近邻、神经网络等。
自组织映射神经网络(Self-Organizing Map,SOM)是无监督学习方法中的一类重要方法,可以用于聚类、高维可视化、数据压缩、特征提取等等用途,因为提出者是Teuvo Kohonen教授,因此也被称为Kohonen网络。
讲SOM之前,先科普一些生物学研究:
1)在人脑的感知通道上,神经元组织是有序排列的;
2)大脑皮层会对外界特定的信息在特定的区域产生兴奋;
3)在生物神经系统中存在着一种侧抑制现象,即一个神经细胞兴奋后,会对周围其他神经细胞产生抑制作用,这种抑制作用会使得神经细胞之间出现竞争,其结果是某些获胜,某些失败,表现则为获胜细胞兴奋,失败细胞抑制。
而我们的SOM就是对以上的生物神经系统功能的一种人工神经网络模型。
SOM本质上是一个两层神经网络,包含输入层和输出层。输入层模拟感知外界输入信息,输出层模拟做出响应的大脑皮层。
1)输出层中,神经元的个数就是聚类的个数;
2)训练时采用"竞争学习"的方式,每个输入的样本,都会在输出层中找到与之最为匹配的节点,这个节点被称之为**"激活节点"**(winning neuron);
3)紧接着采用随机梯度下降法更新激活节点的参数,同时适当地更新激活节点附近的节点(会根据距离远近选择更新的"力度");
4)上面说到的"竞争学习",可以通过神经元之间的横向抑制连接(负反馈路径)来实现。
一般,SOM模型的常见网络结构有两种,分别是一维和二维的:
SOM的自组织学习过程,可以归纳为下面几个子过程:
1)初始化:所有连接权重都用小的随机值进行初始化。
2)竞争:神经元计算每一个输入模式各自的判别函数值,并宣布具有最小判别函数值的特定神经元为胜利者,每个神经元j的判别函数为:
3)合作:获胜的神经元决定了兴奋神经元拓扑邻域的空间位置,确定了激活节点后,更新临近的节点。
4)适应:适当调整相关兴奋神经元的连接权重,使得获胜神经元对相似输入模式的后续应用的响应增强。
5)迭代第2-4步,直到特征映射趋于稳定。
等到最后迭代结束之后,每个样本所激活的神经元就是它对应的类别。
1)K-Mean算法需要事先确定好K值,而SOM不需要;
2)K-Mean算法为每个输入数据找到一个最相似的类,只更新这个类的参数;而SOM则会更新临近的节点,所以,K-Mean算法受噪声影响比较大,SOM则可能准确性方面会差一些;
3)SOM的可视化很好,有优雅的拓扑关系图。
1)设定输出层神经元的数量:如果不清楚,可以尽可能设定较多的节点数。
2)设计输出节点的排列:对于不同的问题,事先选择好模式。
3)初始化权值。
4)设计拓扑邻域:拓扑邻域的设计原则是使得邻域不断缩小,从而输出平面上相邻神经元对应的权向量既有区别又有相当的相似度,从而保证获胜节点对某一类模式产生最大响应时,其邻域节点也产生较大响应。
5)设计学习率:学习率是一个递减函数,可以结合拓扑邻域一起考虑。在训练开始时,可以选择较大的值,这样子比较快下降,后面慢慢减少。
聚类算法不像有监督学习有一个target,更多的都是没有目标的,所以评估指标也是不一样的,下面介绍几种常用的评估指标:
1)轮廓系数(Silhouette Coefficient)
silhouette 是一个衡量一个结点与它属聚类相较于其它聚类的相似程度,取值范围-1到1,值越大表明这个结点更匹配其属聚类而不与相邻的聚类匹配。如果大多数结点都有很高的silhouette value,那么聚类适当。若许多点都有低或者负的值,说明分类过多或者过少。
定义 轮廓系数结合了凝聚度和分离度,其计算步骤如下:
- 对于第i个对象,计算它到所属簇中所有其他对象的平均距离,记为ai(体现凝聚度)
- 对于第i个对象和不包含该对象的任意簇,记为bi(体现分离度)
- 第i个对象的轮廓系数为si=(bi-ai)/max(ai,bi)
2)Calinski-Harabaz指数
如果标签是未知的,sklearn.metrics.calinski_harabaz_score则可以使用Calinski-Harabaz指数来评估模型,其中较高的Calinski-Harabaz分数与具有更好定义的聚类的模型相关。
优点:
- 当集群密集且分离好时,分数更高,这与集群的标准概念有关。
- 得分快速计算
缺点:
- 凸群的Calinski-Harabaz指数通常高于簇的其他概念,例如通过DBSCAN获得的基于密度的集群。
3)Adjusted Rand index(调整后兰德指数)
该指标是衡量两个赋值相似度的函数,忽略排列组合
优点:
- 随机(统一)标签分配 对于任何值的ARI分数接近0.0n_clusters,n_samples(对于原始的兰德指数或V度量,情况不是这样)。
- 有界范围[-1,1]:负值是坏的(独立标注),相似的聚类具有正的ARI,1.0是完美的匹配得分。
- 对集群结构没有作出任何假设:可以用于比较聚类算法,例如k-means,其假设各向同性斑点形状与可以找到具有“折叠”形状的聚类的频谱聚类算法的结果。
缺点:
- 与惯性相反,ARI需要对地面真相类的知识,而在实践中几乎不可用,或者需要人工注释者的人工分配(如在受监督的学习环境中)。
- 然而,ARI也可以在纯无人监控的设置中用作可用于聚类模型选择(TODO)的共识索引的构建块。
4)Mutual Information based scores(基于相互信息的分数)
鉴于labels_true相同样本的基本真实类分配和我们的聚类算法分配的知识labels_pred, 互信息是衡量两个分配的一致性的函数,忽略排列。这种措施的两个不同的标准化版本是可用的,归一化互信息(NMI)和调整的相互信息(AMI)。文献中经常使用NMI,而最近提出了AMI,并针对机会进行归一化:
优点:
- 随机的(均匀的)标签指定具有AMI得分接近0.0 为任何值n_clusters和n_samples(其不是生互信息或V-措施例如的情况下)。
- 有界范围[0,1]:接近零的值表示两个主要独立的标签分配,而接近1的值表示重要的一致性。此外,恰好为0的值表示纯独立的标签分配,并且恰好为1的AMI表示两个标签分配是相等的(有或没有排列)。
- 对集群结构没有作出任何假设:可以用于比较聚类算法,例如k-means,其假设各向同性斑点形状与可以找到具有“折叠”形状的聚类的频谱聚类算法的结果。
缺点:
- 与惯性相反,基于MI的措施需要了解地面真相类,而在实践中几乎不可用,或需要人为注释者的人工分配(如在受监督的学习环境中)。 然而,基于MI的措施也可用于纯粹无监督的设置,作为可用于聚类模型选择的共识索引的构建块。
下面一张图介绍几种Scikit learn的常用聚类算法的比较:
上面说了这么多聚类算法,还是在最后面,把算法的Python实现代码给大家贴一下:
1)K-Means聚类
2)分层聚类(Hierarchical clustering)
3)t-SNE聚类
4)DBSCAN聚类
5)MiniBatchKMeans
6)Affinity Propagation(近邻传播)
《百面机器学习》——chapter5
MLK,即Machine Learning Knowledge,本专栏在于对机器学习的重点知识做一次梳理,便于日后温习,这篇文章很久之前在本公众号发过,现在拿回来整理下,也算是一种温故而知新了。
-
决策树算法
-
分类算法
-
聚类算法
-
集成算法(AdaBoost算法)
-
人工神经网络算法
-
排序算法
-
关联规则算法(Apriori算法)
1、决策树易于理解和解释,可以可视化分析,容易提取出规则。
2、可以同时处理标称型和数值型数据。
3、测试数据集时,运行速度比较快。
4、决策树可以很好的扩展到大型数据库中,同时它的大小独立于数据库大小。
1、对缺失数据处理比较困难。
2、容易出现过拟合问题。
3、忽略数据集中属性的相互关联。
4、ID3算法计算信息增益时结果偏向数值比较多的特征。
1、对决策树进行剪枝。可以采用交叉验证法和加入正则化的方法。
2、使用基于决策树的combination算法,如bagging算法,randomforest算法,可以解决过拟合的问题。
ID3算法是以信息论为基础,以信息熵和信息增益度为衡量标准,从而实现对数据的归纳分类。ID3算法计算每个属性的信息增益,并选取具有最高增益的属性作为给定的测试属性。C4.5算法核心思想是ID3算法,是ID3算法的改进,改进方面有:
- 用信息增益率来选择属性,克服了用信息增益选择属性时偏向选择取值多的属性的不足;
- 在树构造过程中进行剪枝;
- 能处理非离散的数据;
- 能处理不完整的数据。
优点:
产生的分类规则易于理解,准确率较高。
缺点:
1)在构造树的过程中,需要对数据集进行多次的顺序扫描和排序,因而导致算法的低效;
2)C4.5只适合于能够驻留于内存的数据集,当训练集大得无法在内存容纳时程序无法运行。
是一种决策树分类方法,采用基于最小距离的基尼指数估计函数,用来决定由该子数
据集生成的决策树的拓展形。如果目标变量是标称的,称为分类树;如果目标变量是连续的,称为回归树。分类树是使用树结构算法将数据分成离散类的方法。
优点:
1)非常灵活,可以允许有部分错分成本,还可指定先验概率分布,可使用自动的成本复杂性剪枝来得到归纳性更强的树。
2)在面对诸如存在缺失值、变量数多等问题时CART 显得非常稳健。
优点 :
1)KNN是一种在线技术,新数据可以直接加入数据集而不必进行重新训练
2)KNN理论简单,容易实现
缺点:
1)对于样本容量大的数据集计算量比较大。
2)样本不平衡时,预测偏差比较大。如:某一类的样本比较少,而其它类样本比较多。
3)KNN每一次分类都会重新进行一次全局运算。
4)k值大小的选择。
应用领域:
文本分类、模式识别、聚类分析,多分类领域
支持向量机是一种基于分类边界的方法。其基本原理是(以二维数据为例):如果训练数据分布在二维平面上的点,它们按照其分类聚集在不同的区域。基于分类边界的分类算法的目标是,通过训练,找到这些分类之间的边界(直线的――称为线性划分,曲线的――称为非线性划分)。对于多维数据(如N维),可以将它们视为N维空间中的点,而分类边界就是N维空间中的面,称为超面(超面比N维空间少一维)。线性分类器使用超平面类型的边界,非线性分类器使用超曲面。
支持向量机的原理是将低维空间的点映射到高维空间,使它们成为线性可分,再使用线性划分的原理来判断分类边界。在高维空间中是一种线性划分,而在原有的数据空间中,是一种非线性划分。
优点:
1)解决小样本下机器学习问题。
2)解决非线性问题。
3)无局部极小值问题。(相对于神经网络等算法)
4)可以很好的处理高维数据集。
5)泛化能力比较强。
缺点:
1)对于核函数的高维映射解释力不强,尤其是径向基函数。
2)对缺失数据敏感。
应用领域:
文本分类、图像识别、主要二分类领域
优点:
1)对大数量训练和查询时具有较高的速度。即使使用超大规模的训练集,针对每个项目通常也只会有相对较少的特征数,并且对项目的训练和分类也仅仅是特征概率的数学运算而已。
2)支持增量式运算。即可以实时的对新增的样本进行训练。
3)朴素贝叶斯对结果解释容易理解。
缺点:
由于使用了样本属性独立性的假设,所以如果样本属性有关联时其效果不好。
应用领域:
文本分类、欺诈检测中使用较多
优点:
计算代价不高,易于理解和实现
缺点:
1)容易产生欠拟合。
2)分类精度不高。
应用领域:
用于二分类领域,可以得出概率值,适用于根据分类概率排名的领域,如搜索排名等。
Logistic回归的扩展softmax可以应用于多分类领域,如手写字识别等。
是一个简单的聚类算法,把n的对象根据他们的属性分为k个分割,k< n。 算法的核心就是要优化失真函数J,使其收敛到局部最小值但不是全局最小值。
其中N为样本数,K是簇数,rnk b表示n属于第k个簇,uk 是第k个中心点的值。然后求出最优的uk
**优点:**算法速度很快
**缺点:**分组的数目k是一个输入参数,不合适的k可能返回较差的结果。
EM算法是基于模型的聚类方法,是在概率模型中寻找参数最大似然估计的算法,其中概率模型依赖于无法观测的隐藏变量。E步估计隐含变量,M步估计其他参数,交替将极值推向最大。
EM算法比K-means算法计算复杂,收敛也较慢,不适于大规模数据集和高维数据,但比K-means算法计算结果稳定、准确。EM经常用在机器学习和计算机视觉的数据集聚(Data Clustering)领域。
1)很好的利用了弱分类器进行级联。
2)可以将不同的分类算法作为弱分类器。
3)AdaBoost具有很高的精度。
4)相对于bagging算法和Random Forest算法,AdaBoost充分考虑的每个分类器的权重。
1)AdaBoost迭代次数也就是弱分类器数目不太好设定,可以使用交叉验证来进行确定。
2)数据不平衡导致分类精度下降。
3)训练比较耗时,每次重新选择当前分类器最好切分点。
模式识别、计算机视觉领域,用于二分类和多分类场景
1)分类准确度高,学习能力极强。
2)对噪声数据鲁棒性和容错性较强。
3)有联想能力,能逼近任意非线性关系。
1)神经网络参数较多,权值和阈值。
2)黑盒过程,不能观察中间结果。
3)学习过程比较长,有可能陷入局部极小值。
目前深度神经网络已经应用与计算机视觉,自然语言处理,语音识别等领域并取得很好的效果。
PageRank是google的页面排序算法,是基于从许多优质的网页链接过来的网页,必定还是优质网页的回归关系,来判定所有网页的重要性。(也就是说,一个人有着越多牛X朋友的人,他是牛X的概率就越大。)
完全独立于查询,只依赖于网页链接结构,可以离线计算。
1)PageRank算法忽略了网页搜索的时效性。
2)旧网页排序很高,存在时间长,积累了大量的in-links,拥有最新资讯的新网页排名却很低,因为它们几乎没有in-links。
Apriori算法是一种挖掘关联规则的算法,用于挖掘其内含的、未知的却又实际存在的数据关系,其核心是基于两阶段频集思想的递推算法 。
Apriori算法分为两个阶段:
1)寻找频繁项集
2)由频繁项集找关联规则
1) 在每一步产生侯选项目集时循环产生的组合过多,没有排除不应该参与组合的元素;
2) 每次计算项集的支持度时,都对数据库中 的全部记录进行了一遍扫描比较,需要很大的I/O负载。
MLK,即Machine Learning Knowledge,本专栏在于对机器学习的重点知识做一次梳理,便于日后温习,内容主要来自于《百面机器学习》一书,结合自己的经验与思考做的一些总结与归纳。
- 评估指标的局限
- ROC曲线与AUC
- 余弦距离应用
- A/B Test的必要
- 模型评估的方法
为了对模型的效果进行评估,我们就需要各种各样的指标,不同的问题需要不同的指标来评估,而且大部分的指标都是有局限性的,那么,我们就来盘点一下吧。
Accuracy(准确率)
首先,我们得知道准确率的定义,它指的是分类正确的样本占总样本个数的比例,公式为:
所以,从公式上可以看出明显缺陷,那就是当我们的样本极度不平衡的时候,比如99%都是正样本,那么分类器只要把样本都预测为正样本,那么准确率就有99%了,但这样子的分类器其实意义不大。
Precision与Recall(精确率与召回率)
Precision:指的是分类正确的正样本个数占分类器判定为正样本的样本个数的比例
Recall:指的是分类正确的正样本个数占真正的正样本个数的比例
这两个指标是矛盾的,为了提高Precision,分类器需要尽量把"更有把握"的样本预测为正样本,但这样子会漏掉一些"不怎么有把握"的正样本,导致Recall比较低。
所以当我们在评估一个排序模型的时候,需要绘制一个P-R曲线(即Precision-Recall曲线),曲线的横坐标为召回率,纵坐标为精确率,我们评估模型的时候就要整体的PR曲线表现。
RMSE(平方根误差)
RMSE,Root Mean Squared Error,一般都是用来衡量回归模型的好坏,但是这个指标往往对离群点特别地敏感,即便大多数的预测都很准,但如果存在小部分的离群点,都会把这个指标变得很大,公式为:
MSE(均方误差)
MSE (Mean Squared Error)叫做均方误差,这个往往都是用于线性回归的损失函数,就是让这个指标最小化,公式为:
MAE(平均绝对误差)
MAE(Mean Absolute Error),其实和MSE差不多。
MAPE(平均绝对百分比误差)
MAPE,Mean Absolute Percent Error,它相比于RMSE有更强的鲁棒性,它会把每个点的误差进行归一化,降低了个别离群点带来的绝对误差的影响,公式为:
ROC曲线(Receiver Operating Characteristic Curve)在模型评估上是值得专门用一小节来整理一下的,对于风险评分卡等二值分类器特别常用也是最重要的一个指标。
横轴:负正类率(false postive rate FPR),又被叫作特异度,划分实例中所有负例占所有负例的比例。
纵轴:真正类率(true postive rate TPR),又被叫作灵敏度。
混淆矩阵:
AUC指的是ROC曲线下的面积大小,可以量化地反映出基于ROC曲线衡量出的模型性能,一般取值就是0.5~1,越高越好。
余弦定理我们在高中的时候就学过了,一般都是用来计算角度的,而在机器学习问题中,也是一样来计算夹角,因为通常我们的特征都会表示为向量形式,那分析两个特征相似度的时候,都会用余弦相似度来表示:
余弦相似度,其取值范围为[-1, 1],当两个相同方向的向量比较,其取值为1,相反方向的取值为-1。
而余弦距离,则是1-余弦相似度,所以其取值范围为[0, 2],相同向量之间的余弦距离为0。
可能有些同学不太了解A/B Test,其实就是验证新产品是否有效,而设置了实验组和对照组,而进行A/B Test的原因有几点:
- 线下评估无法完全消除模型过拟合的情况,因此需要实际线上的陪跑结果来评估模型;
- 线下评估往往不会考虑线上的延迟、数据丢失、标签数据缺失、默认值丢失等情况;
- 线上系统的某些商业指标在离线环境中无法评估计算,比如用户点击率、PV的优化提升、留存市场改善等。
那么如何进行线上的A/B Test呢?一般的方法就是进行用户分桶,将用户分成实验组和对照组,对实验组的用户使用新模型,对照组的用户使用旧模型,而且,要注意分组样本的独立性和无偏性。
机器学习中,我们通常会把数据划分成训练和测试集,而这个过程有着各种不同的抽样方法和验证方法。
-
Holdout检验
其实就是我们常用的37分,把数据集随机分成3:7,分别用于训练模型和验证模型,但这存在明显问题,那就是随机性比较大,你换一个随机种子,可能会得到完全不一样的结论。
-
交叉检验
1)k-fold交叉验证:将全部样本划分为k个大小相等的样本子集,依次遍历所有子集,每次把当前子集作为验证集,其余的作为训练集,最后将k次评估结果求一个平均值(k一般取5~10次)。
2)留一验证:每次留下1个样本作为验证集,其余所有样本作为训练集。样本总量为n,依次对n个样本进行遍历,进行n次验证,再将评估指标求均值得到最终评估指标。
-
自助法
当样本比较少的时候,使用自助法会比较好,它是基于自动采样法的检验方法,对于总数为m的样本集合,进行m次有放回的随机抽样,得到大小为n的训练集,n次采样过程中,有的样本会被抽过很多次,有的样本会没被抽到过,我们把没有被抽到过的作为验证集即可。一般当n趋于很大的时候,大约有36.8%的样本从未被抽过。
MLK,即Machine Learning Knowledge,本专栏在于对机器学习的重点知识做一次梳理,便于日后温习,内容主要来自于《百面机器学习》一书,结合自己的经验与思考做的一些总结与归纳。本次主要讲解的深度学习方面的知识,先说一下最为常见的前馈神经网络的知识点。
- 多层感知机(MLP)介绍
- 深度神经网络的激活函数
- 深度神经网络的损失函数
- 多层感知机的反向传播算法
- 神经网络的训练技巧
- 深度卷积神经网络
前馈神经网络(feedforward neural network)是一种最简单的神经网络,各神经元分层排列。每个神经元只与前一层的神经元相连。接收前一层的输出,并输出给下一层.各层间没有反馈。是目前应用最广泛、发展最迅速的人工神经网络之一。研究从20世纪60年代开始,目前理论研究和实际应用达到了很高的水平
——百度百科
而深度学习模型,类似的模型统称是叫 深度前馈网络(Deep Feedforward Network),其目标是拟合某个函数f,由于从输入到输出的过程中不存在与模型自身的反馈连接,因此被称为“前馈”。常见的深度前馈网络有:多层感知机、自编码器、限制玻尔兹曼机、卷积神经网络等等。
说起多层感知器(Multi-Later Perceptron),不得不先介绍下单层感知器(Single Layer Perceptron),它是最简单的神经网络,包含了输入层和输出层,没有所谓的中间层(隐含层),可看下图:
也就是说,将输入向量赋予不同的权重向量,整合后加起来,并通过激活函数输出1或-1,一般单层感知机只能解决线性可分的问题,如下图:
我选择了0个隐含层,也就是我们介绍的单层感知机,对于可以线性可分的数据,效果还是可以的。如果我换成线性不可分的数据集,如下图,那么跑半天都跑不出个什么结果来。
这个时候就引入多层感知器,它相比单层感知器多了一个隐含层的东西,同样的数据集,我加入两层 隐含层,瞬间就可以被分类得很好。
对于上面直观的了解,我这里还是要深入介绍一下多层感知机的原理。Multi-Layer Perceptron(我们后面都叫MLP),MLP并没有规定隐含层的数量,因此我们可以根据自己的需求选择合适的层数,也对输出层神经元没有个数限制。
感知机算法中包含了前向传播(FP)和反向传播(BP)算法,但在介绍它们之前,我们先来了解一下深度神经网络的激活函数。
为了解决非线性的分类或回归问题,我们的激活函数必须是非线性的函数,另外我们使用基于梯度的方式来训练模型,因此激活函数也必须是连续可导的。 @ 磐创 AI
常用的激活函数主要是:
Sigmoid函数就是Logistic函数,其数学表达式为: $$ f(z) = \frac{1}{1+e^{-z}} $$ 对应函数图像为:
对应的导函数为: $$ f^{'}(z) = f(z)(1-f(z)) $$ 可以看出,Sigmoid激活函数在定义域上是单调递增的,越靠近两端变化越平缓,而这会导致我们在使用BP算法的时候出现梯度消失的问题。
Tanh激活函数中文名叫双曲正切激活函数,其数学表达式为: $$ f(z)=tanh(z)=\frac{\sin hz}{\cos hz}=\frac{e^z-e^{-z}}{e^z+e^{-z}} $$ 对应函数图像为:
对应的导函数为: $$ f^{'}(z)=1-(f(z))^2 $$ 同样的,tanh激活函数和sigmoid激活函数一样存在梯度消失的问题,但是tanh激活函数整体效果会优于Sigmoid激活函数。
Q:为什么Sigmoid和Tanh激活函数会出现梯度消失的现象?
A:两者在z很大(正无穷)或者很小(负无穷)的时候,其导函数都会趋近于0,造成梯度消失的现象。
ReLU激活函数又称为修正线性单元或整流性单元函数,是目前使用比较多的激活函数,其数学表达式为: $$ f(z)=max(0,z) $$ 对应函数图像为(a):
对应的导函数为: $$ f^{'}=\begin{cases} 1,z>0; \ 0,z \leq0 \end{cases} $$ ReLU激活函数的收敛速度要比上面两种要快得多,ReLU激活函数的X轴左侧值恒为0,使得网络具有一定的稀疏性,从而减少参数之间的依存关系,缓解了过拟合的情况,而且它的导函数有部分为常数1,因此不存在梯度消失的问题。但ReLU激活函数也有弊端,那就是会丢失一些特征信息。
上面可以看到LReLU激活函数的图像了,它和ReLU激活函数的区别在于当z<0时,其值不为0,而是一个斜率为a的线性函数(一般a会是一个十分小的正数),这样子即起到了单侧抑制,也不完全丢失负梯度信息,其导函数表达式为: $$ f^{'}=\begin{cases} z,z>0; \ az,z \leq0 \end{cases} $$
损失函数(Loss Function)又被称为Cost Function,作用是用来表示预测值与真实值之间的误差,深度学习模型的训练是基于梯度的方法最小化Loss Function的过程,下面就介绍几种常见的损失函数。
均方误差(Mean Squared Error,MSE)是比较常用的损失函数,其数学表达式如下: $$ MSE=\frac{1}{2N}\sum_{k=1}^n (y_k- \hat{y_k})^2 $$
交叉熵(Crocs Entropy)损失函数使用训练数据的预测值与真实值之间的交叉熵来作为损失函数,其数学表达式如下: $$ H(p,q)=E_p[\frac{1}{log(q)}] = - \sum_xp(x)log(q(x)) $$
一般来说,MSE更适合输出值为连续值,并且最后一层不含Sigmoid或Softmax激活函数的神经网络;而交叉熵则适合二分类或者多分类的场景。
在MLP中,输入信号通过各个网络层的隐节点产生输出的过程,我们称之为“前向传播“,而前向传播最终是产生一个标量损失函数。而反向传播算法(Backpropagation)则是将损失函数的信息沿着网络层向后传播用以计算梯度,达到优化网络参数的目的。
因为这篇文章还是主要以引导了解为主,关于BP算法原理的讲解和推导就不展开,有兴趣的可以参考下面两篇文章(来自公众号 @磐创AI):
神经网络的训练,常常会遇到的问题就是过拟合,而解决过拟合问题的方法也有很多,简单罗列下:Data Augmentation(数据增广)、Regularization(正则化)、Model Ensemble(模型集成)、Dropout等等。此外,训练深度学习网络还有学习率、权重衰减系数、Dropout比例的调参等。还有Batch Normalization,BN(批量归一化)也可以加速训练过程的收敛,有效规避复杂参数对网络训练效率的影响。
Data Augmentation也就是数据增广的意思,就是在不改变数据类别的情况下,这里主要针对图像数据来说,主要包括但不限于:
1)角度旋转
2)随机裁剪
3)颜色抖动:指的是对颜色的数据增强,包括图像亮度、饱和度、对比度变化等
4)增加噪声:主要是高斯噪声,在图像中随机加入
5)水平翻转
6)竖直翻转
考虑到全连接的深度神经网络,同一层中的任意神经元都是同构的,所以拥有相同的输入和输出,如果参数全部初始化为同一个值,无论是前向传播还是反向传播的取值都会是一样的,学习的过程将无法打破这种情况。因此,我们需要随机地初始化神经网络的参数值,简单的一般会在
学习率我们通常设为0.1,但是如果在实践中验证集上的loss或者accuracy不变的时候,可以考虑增加2~5倍的学习率。
Dropout在深度学习网络训练中是十分常用的,指的是以一定的概率p随机丢弃一部分神经元节点,而这个“丢弃”只是临时的,是针对每一次小批量的训练数据而言,由于是随机丢弃,所以每一次的神经网络结构都会不一样,相当于每次迭代都是在训练不同结构的神经网络,有点像传统机器学习中的Bagging方法。
具体实现上,在训练过程中,神经元的节点激活值以一定的概率p被“丢弃”,也就是“停工”。因此,对于包含N个神经元节点的网络,在Dropout的作用下可以看做是生成 2的N次方个模型的集合,这个过程会减弱全体神经元之间的联合适应性,减少过拟合的风险,增强泛化能力。
因为神经网络的训练过程本质就是对数据分布的学习,因此训练前对输入数据进行归一化处理显得很重要。我们知道,神经网络有很多层,每经过一个隐含层,训练数据的分布会因为参数的变化而发生改变,导致网络在每次迭代中都需要拟合不同的数据分布,这样子会增加训练的复杂度以及过拟合的风险。
因此我们需要对数据进行归一化处理(均值为0,标准差为1),把数据分布强制统一再一个数据分布下,而且这一步不是一开始做的,而是在每次进行下一层之前都需要做的。也就是说,在网路的每一层输入之前增加一个当前数据归一化处理,然后再输入到下一层网路中去训练。
这个我们见多了,一般就是L1、L2比较常见,也是用来防止过拟合的。
L1正则化会使得权重向量w在优化期间变得稀疏(例如非常接近零向量)。 带有L1正则化项结尾的神经网络仅仅使用它的最重要的并且接近常量的噪声的输入的一个稀疏的子集。相比之下,最终的权重向量从L2正则化通常是分散的、小数字。在实践中,如果你不关心明确的特征选择,可以预计L2正则化在L1的性能优越。
L2正则化也许是最常用的正则化的形式。它可以通过将模型中所有的参数的平方级作为惩罚项加入到目标函数(objective)中来实现,L2正则化对尖峰向量的惩罚很强,并且倾向于分散权重的向量。
模型集成在现实中很常用,通俗来说就是针对一个目标,训练多个模型,并将各个模型的预测结果进行加权,输出最后结果。主要有3种方式:
1)相同模型,不同的初始化参数;
2)集成几个在验证集上表现效果较好的模型;
3)直接采用相关的Boosting和Bagging算法。
终于来到了我们耳熟能详的CNN了,也就是卷积神经网络(Convolutional Neural Network,CNN),它也是属于前馈神经网络的一种,其特点是每层的神经元节点只响应前一层局部区域范围内的神经元(全连接网络中每个神经元节点则是响应前一层的全部节点)。
一个深度卷积神经网络模型,一般由若干卷积层叠加若干全连接层组成,中间包含各种的非线性操作、池化操作。卷积运算主要用于处理网格结构的数据,因此CNN天生对图像数据的分析与处理有着优势,简单地来理解,那就是CNN是利用滤波器(Filter)将相邻像素之间的轮廓过滤出来。
卷积的滤波器(Filter)我们可以看做是一个window,可以观察下面的案例,有一个6X6的网络以及一个3X3的Filter,其中Filter的每个格子上有权值。拿着FIlter在网络上去移动,直到所有的小格子都被覆盖到,每次移动,都将Filter“观察”到的内容,与之权值相乘作为结果输出。最后,我们可以得到一个4X4的网格矩阵。(下面的6张图来自参考文献5,侵删)
卷积后的矩阵大小与一开始的不一致,那么我们需要对边缘进行填充,以保证尺寸一致。
也就是Filter移动的步伐大小,上面的例子为1,其实可以由我们自己来指定,有点像是学习率。
深度指的是图片的深度,一张6X6X3大小的图片经过3X3X3的Filter过滤后会得到一个4X4X1大小的图片,因此深度为1。我们也可以通过增加Filter的个数来增加深度,如下:
因为滤波器在进行窗口移动的过程中会有很多冗余计算,效率很慢,池化操作的目的在于加速卷积操作,最常用的有Maxpooling,其原理如下图所示:
1)Sparse Interaction(稀疏交互)
因为卷积核的尺度会小于输入的维度,也就是我们的FIlter会小于网络大小一样,这样子每个输出神经元仅仅会与部分特定局部区域内的神经元存在连接权重(也就是产生交互),这种操作特性我们就叫稀疏交互。稀疏交互会把时间复杂度减少好几个数量级,同时对过拟合的情况也有一定的改善。
2)Parameter Sharing(参数共享)
指的是在同一个模型的不同模块使用相同的参数,它是卷积运算的固有属性。和我们上面说的Filter上的权值大小应用于所有网格一样。
0)《百面机器学习》(文中未标明出处的图片均来自此书)
1)Tensorflow系列专题(四):神经网络篇之前馈神经网络综述
https://blog.csdn.net/fendouaini/article/details/83626441
2)深度学习之(神经网络)单层感知器(python)(一)
https://www.jianshu.com/p/d7189cbd0983?from=groupmessage
3)多层感知机及其BP算法(Multi-Layer Perception)
https://www.cnblogs.com/ooon/p/5577241.html
4)深度神经网络训练的必知技巧
https://www.cnblogs.com/mengmengmiaomiao/p/7852948.html
5)AI学习笔记——卷积神经网络(CNN)
https://www.jianshu.com/p/49b70f6480d1
MLK,即Machine Learning Knowledge,本专栏在于对机器学习的重点知识做一次梳理,便于日后温习,内容主要来自于《百面机器学习》一书,结合自己的经验与思考做的一些总结与归纳。本次主要讲解的深度学习循环神经网络方面的知识。
在开始讲循环神经网络之前,我们可以简单来回顾一下前向神经网络的知识点,因为这一块的知识是有一些互通的呢(请戳《》)。
简单来说吧,循环神经网络(Recurrent Neural Network)也就是我们常见的RNN了,它是用来构建序列化模型的一种主流深度学习模型,我们传统的前馈神经网络一般的输入都是定长的向量,无法处理会变长的序列信息,有些同学会说我把它转换成定长向量不就好了吗?但其实不然,即便转换了,模型也很难去捕捉到序列中的长距离依赖关系。
因此,这里就提出了RNN的方法,RNN通过将神经元串行起来处理序列化的数据,由于每个神经元能用它的内部变量保存之前输入的序列信息,因此整个序列就可以被进行抽象表示,并据此进行分类or生成新序列。所以这个RNN也经常会被应用在机器翻译、序列标注、图像描述、推荐系统、AI机器人等等。
- RNN与CNN的区别与联系
- RNN存在梯度消失or梯度爆炸?
- 重点深入了解下LSTM
- 重点深入了解下Seq2Seq
###🔍 RNN与CNN的区别与联系
在我们处理文本数据的时候,通过会做的操作就是把语料所对应的的TF-IDF向量作为输入,其中TF-IDF向量的维度是词汇表的大小。
TF-IDF: 一种统计方法,用以评估一字词对于一个文件集或一个语料库中的其中一份文件的重要程度。字词的重要性随着它在文件中出现的次数成正比增加,但同时会随着它在语料库中出现的频率成反比下降。
传统做法,就是使用CNN接收TF-IDF向量作为特征输入,然后通过滑动窗口加池化的方法将原先的输入转换成一个固定长度的向量表示,虽然这样子也会捕捉到局部的特征,但长距离单词之间的依赖信息就会丢失了。
卷积神经网络(Convolutional Neural Network,CNN),它也是属于前馈神经网络的一种,其特点是每层的神经元节点只响应前一层局部区域范围内的神经元(全连接网络中每个神经元节点则是响应前一层的全部节点)。
RNN就可以避免这种情况,它可以很好地处理文本数据变长并且有序的输入序列,简单来说它是模拟了一个人在阅读文章的情景,从开始读到最后读完,并且拥有”记忆“能力(把前面阅读到的有用信息编码到状态变量里去)。
梯度消失(Gradient Vanishing),也就是梯度的反向传播过程中,后层的梯度以连乘方式叠加到前层,而一般我们的神经网络的激活函数都是用的Sigmoid函数,它具有饱和特征,即在输入达到一定值的时候,输出就几乎不会发生明显改变了,而后层的误差梯度反传回前层的时候,几乎就会衰减为0,因此前层的参数无法得到有效的学习。
梯度爆炸则是相反,大于1的值不断连乘带来一个很大的误差返回。
Sigmoid函数就是Logistic函数,其数学表达式、对应函数图像、导函数和导函数图像为:
可以看出,Sigmoid激活函数在定义域上是单调递增的,越靠近两端变化越平缓,从导数图像可以看出,Sigmoid函数的导数取值范围在0-0.25之间,如果我们初始化的网络权值∣w∣小于1(一般也是这么操作),随着层数不断增多,每次连乘后逐渐变小,梯度就逐渐消失了。
同理,梯度爆炸也是类似,当我们的初始化的网络权值过大,导致 ∣σ′(z)w∣>1,不断连乘后就会得到一个很大的值了。
最直观的解释就是,当在模型训练过程中出现了梯度消失,接近输出层的隐含层的梯度是正常的,所以权值更新的值也是正常的,但是越往回传递,出现了梯度消失的问题,这个时候输入层附近的隐含层的权值更新就会缓慢甚至停滞,所以就相当于前面的几个隐含层是”形同虚设“,深度网络其实就不再”深度“了,而可能只是后面几个隐含层构成的浅层网络。
对于这种常见的问题,当然解决办法也是很常见的了,下面罗列几条:
1)更换激活函数
比如几种常见的激活函数,对于避免上述的问题很有效。
ReLU:使得我们的激活函数导数为1
LeakyReLU:ReLU的优化,同时解决了ReLu中0区间带来的影响
2)使用ResNet残差结构
其实为了解决梯度消失和爆炸问题,BN(Batch Normalization)结构也可以顺利解决,BN层对每层的输出做归一化,这样梯度在反向层层传递后仍可以保持大小稳定,不会出现过小或过大的问题,但BN在深度不断增大后会出现一个问题:Degradation Problem(准确率下降问题)。这个问题在我们的网络层级达到一定深度的时候就会出现,准确率饱和,然后迅速下降,这个问题不是由于过拟合或是梯度问题导致的,而是由于网络结构太过于复杂导致的,换句话说就是如果不加约束的放羊式训练很难达到理想的准确率的。
ResNet的提出就是为了解决这个问题的。
3)预训练加微调
Step1:pre-training(预训练)
此方法来自Hinton在2006年发表的一篇论文,Hinton为了解决梯度的问题,提出采取无监督逐层训练方法,其基本思想是每次训练一层隐节点,训练时将上一层隐节点的输出作为输入,而本层隐节点的输出作为下一层隐节点的输入,此过程就是逐层“预训练”(pre-training);
Step2:fine-tunning(微调)
在预训练完成后,再对整个网络进行“微调”(fine-tunning)。Hinton在训练深度信念网络(Deep Belief Networks中,使用了这个方法,在各层预训练完成后,再利用BP算法对整个网络进行训练。此思想相当于是先寻找局部最优,然后整合起来寻找全局最优。
4)梯度剪切、权重正则化
梯度剪切这个主要是针对梯度爆炸而设计的解决方案,其核心思想就是设置一个梯度剪切的阈值,在更新梯度的时候对超出阈值的限制为该阈值,防止梯度爆炸。
权重正则化也是为了解决梯度爆炸问题而提出的,常见的就是L1、L2正则化,在各个深度框架中都有对应的API可以使用正则化,正则化是通过对网络权重做正则限制过拟合,如下面的Loss Function:
其中α指的是正则化系数,当发生梯度爆炸的时候,权重的范数就会变得很大,通过正则项则可以防止部分梯度爆炸的发生。
5)LSTM
LSTM全称是长短期记忆网络(long-short term memory networks),是不那么容易发生梯度消失的,主要原因在于LSTM内部复杂的“门”(gates),如下图,LSTM通过它内部的“门”可以接下来更新的时候“记住”前几次训练的”残留记忆“,因此,经常用于生成文本中。目前也有基于CNN的LSTM,感兴趣的可以尝试一下。
长短期记忆网络(long-short term memory networks,LSTM)是循环神经网络的最知名和成功的扩展,可以对有价值的信息进行长期记忆,从而减小循环神经网络的学习难度,因此在语音识别、语言建模、机器翻译、命名实体识别、图像描述文本生成等问题中有着广泛应用。
还是上面的图,与传统循环神经网络相似,但是对内部结构进行精心设计,加入了输入门、遗忘门以及输出门,还有一个内部记忆单元。
1)输入门控制当前计算的新状况以多大程度更新到记忆单元中;
2)遗忘门控制前一步记忆单元中的信息有多大程度被遗忘;
3)输出门控制当前的输出有多大程度上取决于当前的以及单元。
进一步解释,也就是说LSTM的状态转移不一定全部由激活函数的计算结果,还得依赖于输入门与遗忘门来共同控制,如:
在一个训练好的网络中,当输入的序列中没有重要的信息,LSTM的遗忘门的值会接近于1,输入门的值接近于0,此时过去的记忆仍会被保留,从而实现了长期记忆功能;但如果输入的序列中出现了重要信息的时候,LSTM就会把它存入记忆中,此时输入门的值会更新为1,而遗忘门的值会接近于0,这样子旧的记忆就会被遗忘,新的信息就会被记忆。
在LSTM中,遗忘门、输入门和输出门使用SIgmoid函数作为激活函数,在生成候选记忆时候,使用双曲正切函数Tanh作为激活函数。因为Sigmoid函数的输出值在01之间,符合门控的物理定理,即输入较大or较小的时候其输出会非常接近1or0,从而保证了门的开关。在生成候选记忆的时候,使用Tanh函数的原因是因为其取值范围为-11之间,与大多数场景下特征分布是0中心吻合,同时Tanh函数在输入为0附近相比于Sigmoid函数有更大的梯度,通常使得模型收敛更快。
Seq2Seq,全称是Sequence to Sequence模型,大致是意思就是将一个序列信号通过编码和解码生成一个新的序列信息,通过会用于机器翻译、语音识别、自动对话等任务。它的核心思想就是通过深度神经网络,将一个作为输入的序列映射为一个作为输出的序列,这一过程由编码输入和编码输出两个环节构成,在经典的实现中,编码器和解码器各有一个循环神经网络来构成,既可以是传统循环神经网络结构,也可以是LSTM、门控循环单元等。
这里有一个简单形象的例子:
在一次期末考试,我们将需要复习的知识经过复习(加工),形成了知识体系(结构),这就是编码过程。在考试的时候,将高度抽象的知识体系应用到具体的问题中去求解,这就是解码过程。
对于学霸,在复习过程就可以构建成一个比较强大的网络,可以对很长(很难很久远)的信息进行抽象理解,加工内化为编码向量,在考试中从容应答问题。
对于一般人,很难记忆长距离、高难度的信息,一般都只好”临时抱佛脚“,编码很短期的序列信号,考试时候就听天由命,能答多少就写多少。
Seq2Seq的核心在于解码部分,大量的改进也是在解码环节衍生的,其最基本的解码方法就是贪心法,即选取一种度量标准后,每次都在当前状态下选择最佳的一个结果,直到结束。这种方法有一个最大的弊端就是面对复杂的问题的时候,很难得到最优解。
那么,这里有一个改良的算法,叫做集束搜索,它是一个启发式算法,该方法会保存beamsize个当前的较优选择,然后解码时每一步根据保存的选择进行下一步扩展和排序,接着继续选择前beamsize个进行保存,循环迭代,直到结束时选择最佳的一个作为解码的结果。
Attention Mechanism的提出源自于一个问题。在实际的使用中,随着输入序列的增长,模型的性能发生了显著下降,因为编码时输入序列的全部信息被压缩到了一个向量表示中,随着序列增长,句子越前面的词的信息丢失就越严重。
引入注意力机制就是为了解决上述问题的,在注意力机制中,仍可以用普通的循环神经网络对输入序列进行编码,得到隐状态h1,h2,h3...,但是在解码时,每一个输出词都依赖于前一个隐状态以及输入序列每一个对应的隐状态。
更加直观的理解,就是我们在生成一个输出词时,会考虑每一个输入词和当前输出词的对齐关系,对齐越好的词,会有更大的权重,对生成当前输出词的影响就越大。
[1] 《百面机器学习》第10章
[2] 梯度消失和梯度爆炸问题详解
http://www.sohu.com/a/332473808_468740
[3] 残差网络ResNet解读(原创)
https://blog.csdn.net/docrazy5351/article/details/78993347
[4] 详解机器学习中的梯度消失、爆炸原因及其解决方法
https://blog.csdn.net/qq_25737169/article/details/78847691
MLK,即Machine Learning Knowledge,本专栏在于对机器学习的重点知识做一次梳理,便于日后温习,内容主要来自于《百面机器学习》一书,结合自己的经验与思考做的一些总结与归纳。本次主要讲解的集成学习方面的知识。
相信这个环节的内容大家都会比较熟悉的,因为我们经常用到的XGBoost、GBDT就是集成模型,今天这里就给大家系统地梳理一下知识点和原理,做到了然于胸。
- 集成学习的主要类型
- 集成学习的基本步骤
- 谈谈基分类器
- GBDT与XGBoost的区别与联系
- 算法实践Demo
集成学习是一大类模型融合策略和方法的统称,我们经常用到的两类是Boosting和Bagging,这两者的区别与联系经常会被问到,在回答这些问题前,需要对两者的原理进行统一了解。
Boosting方法在训练基分类器时采用的是串行的方法,每一个基分类器依赖前面的结果。它的基本思路就是将基分类器层层叠加,每层在训练时都会对前一层基分类器的分类错误情况去改变当前样本的分布,具体来说就是将分类错误的样本给予更高的权重,所以每一次的迭代,数据分布都是不一样的。
Boosting的迭代过程与人类的学习过程有点类似,也就是说我们在学习新知识的时候,会记住部分信息,也会遗忘部分信息,所以在下一次中会着重去关注没记住的内容,加强训练,这样子不断地去循环学习,直到我们能够全部吸收。
Boosting通过逐步聚焦于基分类器分错的样本,减少集成分类器的偏差。
而对于Bagging,它则是并行训练的,各个基分类器之间无依赖,而且每个基分类器训练的样本都是一样的(也可以不同),但由于每个基分类器的"学习能力"不同,会出现很多的学习结果,最终的决策会参考这些基分类器的结果,一般是采用投票的方式,基分类器之间的权重都是一样的。
Bagging采取分而治之的策略,通过对训练样本多次采样,并分别训练出多个不同模型,然后做综合,来减少集成分类器的方差。
集成学习一般可以分为以下3个步骤:
1、找到误差互相独立的基分类器
2、训练基分类器
3、合并基分类器的结果
合并基分类器的方法有voting和stacking两种,前者是用投票的方法,将获得最多选票的结果作为最终的结果。后者则是使用串行的方法,把前一个基分类器的结果输出到下一个基分类器中,将所有基分类器的输出结果相加融合作为输出。
比如,针对Adaboost,大致的步骤如下:
(1) 确定基分类器:一般都是采用树形模型,因为它结构简单且随机性强。
(2) 训练基分类器:假设有T个基分类器,则可以按照如下过程来训练基分类器:
(3) 合并基分类器:给定一个未知样本z,输出分诶结果为加权投票的结果。
从上面的例子中我们可以看出来Boosting一个很重要的思想,那就是它会对分类错误的样本进行权重的加强,对分类正确的样本降低权重,在最后的模型融合时根据错误率对基分类器进行加权融合,错误率低的分类器也拥有更大的"话语权"。
还有一种比较流行的Boosting模型,那就是梯度提升决策树(GBDT)。 其核心思想就是每一棵树学的是之前所有树结论和的残差,这个残差是一个加预测值后能得到真实值的累加(减)量。
基分类器作为Boosting的基本单元,而且一般也是会采用决策树来作为分类器,原因有三:
(1) 决策树可以较为方便地将样本的权重整合到训练过程中,而不需要使用过采样的方法来调整样本权重;
(2) 决策树的表达能力和泛化能力都是有很大的调节性,比如可以通过数的深度来调整;
(3) 决策树的随机性较强,所以不同的训练集都会比较随机地生成不同的决策树模型,这样子的"不稳定学习器"更能胜任基分类器的职责,很好的解决了数据样本扰动的影响,同时解决过拟合情况。
Q:可否将RF中的决策树基分类器,替换为K-Mean或者线性分类器呢?
有了上面我们对于基分类器的认识,因为RF属于Bagging,它要求的基分类器最好是对样本分布较为敏感,这样子基分类器之间的方差就会较大,然后综合起来之后就可以达到一个较优的结果。而如果换成K-Mean或者线性分类器,这些分类器本身会非常稳定,这样子的话其实基分类器训练出来的模型都是十分相似,方差很小,即便Bagging之后不能获得更好的表现,失去了Bagging的优势。
Gradient Boosting Decision Tree,简称GBDT,中文名为梯度提升决策树,作为"网红"算法,时常出现在各大竞赛平台和商业应用,它的核心思想就是从错误中学习,基于决策树预测的残差进行迭代优化学习,具体做法就是根据当前模型损失函数的负梯度信息来训练新加入的弱分类器,然后将训练好的弱分类器以累加的形式结合到现有模型中。
作为一个比GBDT更加"网红"的机器学习算法,XGBoost可谓是鼎鼎大名,它高效地实现了GBDT算法并进行算法和工程层面上的优化改进,它直接并行训练模型(这里的并行指的是节点分裂上的并行,模型的训练还是串行的,毕竟还是属于Boosting),然后对过拟合做了一些优化措施,也优化了Cost Function。
这里就罗列一些内容:
(1) 在使用CART作为基分类器的时候,XGBoost显式地加入了正则项来控制模型的复杂度,有利于改善模型的过拟合情况,从而提高模型的泛化能力;
(2) GBDT在训练模型的时候只是使用Cost Function的一阶导数部分信息,而XGBoost则是进行二阶泰勒展开,用到了二阶导数;
(3) 传统的GBDT只是采用CART作为基分类器,而XGBoost支持多种基分类器,比如线性分类器;
(4) GBDT每次训练模型的样本都是一样的,但是XGBoost则支持对数据进行采用,数据分布有可能会发生改变;
(5) GBDT没有对缺失值进行处理,XGBoost对这块有针对性的解决措施。
先前的一篇文章中,有读者在咨询有没有调用这些算法的例子,这边的话就根据算法的官方文档,整理出一份demo,希望也可以帮助到正在初学的朋友👬。
我们在Python里用XGBoost,主要就是通过调用Scikit_learn的包,里面有一个类叫 xgboost。当我们对样本进行处理后,得到一个很规范的DataFrame格式的数据集,这个时候就可以调用这个算法类来进行模型构建,具体参数如下:
Scikit-Learn Wrapper interface for XGBoost.
- class xgboost.XGBRegressor(max_depth=3, learning_rate=0.1, n_estimators=100, verbosity=1, objective='reg:squarederror', booster='gbtree', tree_method='auto', n_jobs=1, gamma=0, min_child_weight=1, max_delta_step=0, subsample=1, colsample_bytree=1, colsample_bylevel=1, colsample_bynode=1, reg_alpha=0, reg_lambda=1, scale_pos_weight=1, base_score=0.5, random_state=0, missing=None, num_parallel_tree=1, importance_type='gain', **kwargs)
下面是一个具体的实例,大家可以结合代码里的注释来理解这段代码:
# 导入相关库
import xgboost as xgb
from xgboost.sklearn import XGBClassifier
# 初始化xgb
xgb = XGBClassifier(learning_rate =0.1,eta=0.5, max_depth=3,min_child_weight=2,gamma=0.2, subsample=0.7, colsample_bytree=0.9,
objective= 'binary:logistic', scale_pos_weight=10, seed=10)
# 用样本数据训练模型
xgb.fit(X_train, y_train)
# 对训练好的模型进行预测应用,分别对训练集和测试集进行计算
train_y_pred = xgb.predict(X_train)
train_y_predprob = xgb.predict_proba(X_train)[:,1]
test_y_pred = xgb.predict(X_test)
test_y_predprob = xgb.predict_proba(X_test)[:,1]
# 计算KS值,并打印出来,看模型效果(这里除了KS值,还有很多其他的指标,具体根据实际情况选择)
get_ks = lambda y_pred,y_true: ks_2samp(y_pred[y_true==1], y_pred[y_true!=1]).statistic
print('训练KS值: %s' %get_ks(train_y_predprob,y_train))
print('验证KS值: %s' %get_ks(test_y_predprob,y_test))
我们还是使用 MNIST 数据集,这一次训练和测试数据的样本量都一样,都是10000。
# 导入相关库
import numpy as np
from keras.models import Sequential
from keras.layers.core import Dense,Dropout,Activation
from keras.optimizers import SGD,Adam
from keras.utils import np_utils
from keras.datasets import mnist
# 封装数据读取及预处理的代码
def load_data():
(x_train,y_train),(x_test,y_test)=mnist.load_data()
number=10000
x_train=x_train[0:number]
y_train=y_train[0:number]
x_train=x_train.reshape(number,28*28)
x_test=x_test.reshape(x_test.shape[0],28*28)
x_train=x_train.astype('float32')
x_test=x_test.astype('float32')
y_train=np_utils.to_categorical(y_train,10)
y_test=np_utils.to_categorical(y_test,10)
x_train=x_train
x_test=x_test
x_train=x_train/255
x_test=x_test/255
return (x_train,y_train),(x_test,y_test)
# 调用方法
(x_train,y_train),(x_test,y_test)=load_data()
print(x_train.shape)
print(x_test.shape)
'''
随便初始化一个NN模型
'''
model=Sequential()
model.add(Dense(input_dim=28*28,units=633,activation='sigmoid'))
model.add(Dense(units=633,activation='sigmoid'))
model.add(Dense(units=633,activation='sigmoid'))
model.add(Dense(units=10,activation='softmax'))
model.compile(loss='mse',optimizer=SGD(lr=0.1),metrics=['accuracy'])
model.fit(x_train,y_train,batch_size=100,epochs=20)
train_result = model.evaluate(x_train,y_train,batch_size=10000)
test_result = model.evaluate(x_test,y_test)
print('TRAIN Accuracy:',train_result[1])
print('TEST Accuracy:',test_result[1])
可以看出结果还是很烂的,Train 和 Test都只是有13%左右的准确度。
尝试着从损失函数开始入手,原模型参数的Loss Function为 MSE,如果对损失函数的原理比较清晰的同学可能就会发现了问题,MSE为均方误差,往往都是用于线性回归的损失函数,而这里是多分类问题,当然就不是十分适合了,所以我们可以换成 categorical_crossentropy 。
'''
修改下 Loss Function
'''
model=Sequential()
model.add(Dense(input_dim=28*28,units=633,activation='sigmoid'))
model.add(Dense(units=633,activation='sigmoid'))
model.add(Dense(units=633,activation='sigmoid'))
model.add(Dense(units=10,activation='softmax'))
model.compile(loss='categorical_crossentropy',
optimizer=SGD(lr=0.1),
metrics=['accuracy'])
model.fit(x_train,y_train,
batch_size=100,
epochs=20)
train_result = model.evaluate(x_train,y_train)
test_result = model.evaluate(x_test,y_test)
print('TRAIN Accuracy:',train_result[1])
print('TEST Accuracy:',test_result[1])
可以看出,换了合适的Loss Function,模型效果有了很大的提升,看来机器学习还是需要懂些理论知识的,不然盲目调参并不是明智的选择。
这个参数在Keras深度学习模型中还是蛮重要的,我们在深度学习模型中做 梯度下降,并不是真的就是 minimize total loss(最小化总损失),而通常的做法是会把训练数据随机分成 N 个 mini-batch,并行训练模型。在了解这个参数前,先介绍下 mini-batch 的原理。
Mini-batch 指的是从一堆训练数据中,随机取出 N/batch_size 个数据来计算偏微分并更新参数,可以参考下面的步骤:
1)随机初始化神经网络的参数(与 Stochastic gradient descent一样)
2)随机选择第一个batch,计算其 loss,计算偏微分,根据 L` 更新参数
3)继续随机选择一个batch,计算其 loss,计算偏微分,根据 L`` 更新参数
4)重复上述2-3步,直到所有的batch都被更新了一次,一个epoch才算结束
'''
增大 batch_size
'''
model=Sequential()
model.add(Dense(input_dim=28*28,units=633,activation='sigmoid'))
model.add(Dense(units=633,activation='sigmoid'))
model.add(Dense(units=633,activation='sigmoid'))
model.add(Dense(units=10,activation='softmax'))
model.compile(loss='categorical_crossentropy',
optimizer=SGD(lr=0.1),
metrics=['accuracy'])
model.fit(x_train,y_train,
batch_size=1000,
epochs=20)
train_result = model.evaluate(x_train,y_train)
test_result = model.evaluate(x_test,y_test)
print('TRAIN Accuracy:',train_result[1])
print('TEST Accuracy:',test_result[1])
设置太大的batch_size,训练效率是超级快了,但是效果却很差。而按照batch_size的原理,如果减小batch_size的值,效率会变慢很多,但效果还蛮不错。
'''减小 batch_size'''
model.fit(x_train,y_train, batch_size=10, epochs=20)
所谓深度学习,正常来说“越深越好”,但也要看实际情况,太深的话其实对资源的消耗也很大,同时也不一定可以得到比较好的结果,也就是所谓的“性价比低”。先前的隐含层都只有2层,下面我们用for循环增加隐含层到 10 层 ,看看效果。
'''
增加隐含层数量至10
'''
model=Sequential()
model.add(Dense(input_dim=28*28,units=633,activation='sigmoid'))
for _ in range(10):
model.add(Dense(units=633,activation='sigmoid'))
model.add(Dense(units=10,activation='softmax'))
model.compile(loss='categorical_crossentropy',
optimizer=SGD(lr=0.1),
metrics=['accuracy'])
model.fit(x_train,y_train,
batch_size=100,
epochs=20)
train_result = model.evaluate(x_train,y_train)
test_result = model.evaluate(x_test,y_test)
print('TRAIN Accuracy:',train_result[1])
print('TEST Accuracy:',test_result[1])
效果是出奇的差,从原先的85%左右掉到11%左右,于是我试着变少一些,比如3层、5层什么的,效果也都还是不行,看来并不是盲目地增加隐含层数量来提升效果的哦。
这里是激活函数,还是建议阅读先前的理论文章《MLK | 一文理清 深度学习前馈神经网络》,看下几种激活函数的差异,主要有Sigmoid、Tanh、ReLU激活函数,这里我把 Sigmoid都换成了 relu。
'''
修改下 Loss Function
'''
model=Sequential()
model.add(Dense(input_dim=28*28,units=633,activation='relu'))
for _ in range(2):
model.add(Dense(units=633,activation='relu'))
model.add(Dense(units=10,activation='softmax'))
model.compile(loss='categorical_crossentropy',
optimizer=SGD(lr=0.1),
metrics=['accuracy'])
model.fit(x_train,y_train,
batch_size=100,
epochs=20)
train_result = model.evaluate(x_train,y_train)
test_result = model.evaluate(x_test,y_test)
print('TRAIN Accuracy:',train_result[1])
print('TEST Accuracy:',test_result[1])
效果杠杠的,可以达到95%+了。
优化器的选择有好多种,比如我们一开始用的 SGD,除此之外还有:Adam、RMSprop、Adagrad、Adamax、Nadam,这些都是gradient descent的变形体,我们换另一个优化器看看,比如Adam:
model.compile(loss='categorical_crossentropy',
optimizer='Adam',
metrics=['accuracy'])
效果还是蛮不错的。
dropout其实就是为了减少过拟合情况,是最简单的神经网络正则化方法,可以应用于输入层和隐含层,取值在0-1之间,一般会在0.2-0.7之间比较好。
'''
修改下 Dropout
'''
model=Sequential()
model.add(Dense(input_dim=28*28,units=633,activation='relu'))
model.add(Dropout(0.7))
for _ in range(2):
model.add(Dense(units=633,activation='relu'))
model.add(Dropout(0.7))
model.add(Dense(units=10,activation='softmax'))
model.compile(loss='categorical_crossentropy',
optimizer='Adam',
metrics=['accuracy'])
model.fit(x_train,y_train,
batch_size=100,
epochs=20)
train_result = model.evaluate(x_train,y_train)
test_result = model.evaluate(x_test,y_test)
print('TRAIN Accuracy:',train_result[1])
print('TEST Accuracy:',test_result[1])
我拿的是上面小节的代码,加了0.7的Dropout,效果有所下降,但确实Train和Test的差距会变小很多。
[1] 【Keras】减少过拟合的秘诀——Dropout正则化
https://www.jianshu.com/p/3745827decdf
[2] 台大 李宏毅机器学习 19节
[1] 百面机器学习 Chapter12 (文中为标识来源的图片均来自本书内容)
[2] XGBoost Documentation