本文主要总结模型的求解方法,包括优化目标的构造及根据优化目标求解模型参数。
这部分摘自:机器学习中的范数规则化之(一)L0、L1与L2范数
一般来说,监督学习可以看做最小化下面的目标函数:
其中,第一项 衡量我们的模型(分类或者回归)对第 i 个样本的预测值 和真实的标签 之间的误差。因为我们的模型是要拟合我们的训练样本的嘛,所以我们要求这一项最小,也就是要求我们的模型尽量的拟合我们的训练数据。但正如上面说言,我们不仅要保证训练误差最小,我们更希望我们的模型测试误差小,所以我们需要加上第二项,也就是对参数 w 的规则化函数 Ω(w) 去约束我们的模型尽量的简单。
机器学习的大部分带参模型都和这个不但形似,而且神似。是的,其实大部分无非就是变换这两项而已。对于第一项Loss函数,如果是Square loss,那就是最小二乘了;如果是Hinge Loss,那就是著名的SVM了;如果是exp-Loss,那就是牛逼的 Boosting了;如果是log-Loss,那就是Logistic Regression了;还有等等。不同的 loss函数,具有不同的拟合特性,这个也得就具体问题具体分析的。规则化函数 Ω(w) 也有很多种选择,一般是模型复杂度的单调递增函数,模型越复杂,规则化值就越大。比如,规则化项可以是模型参数向量的范数。然而,不同的选择对参数w的约束不同,取得的效果也不同,但我们在论文中常见的都聚集在:零范数、一范数、二范数、迹范数、Frobenius范数和核范数等等。
普通线性回归的哲学思想是使MSE最小(等价于 Square Loss),是求导解一次线性方程的问题,可以采用线性运算OLS(普通最小二乘法)求解;Logistic 回归的哲学思想是使似然函数最大即MLE(等价于 log-Loss),是求导解方程的问题,常采用梯度下降法求解;SVM的哲学思想是使间隔最大(等价于 Hinge Loss),是二次规划问题,常采用SMO算法求解。
这些是一般的优化目标,还有一些其他的优化目标,如 MCE(最小错误分类)等。另外,如上文所述,有的优化目标会包含正则化项,此时优化目标就不再仅是损失函数了。正则化在机器学习和深度学习中是普遍使用的防止过拟合的技巧,正则化的解读可以参考:LASSO回归
另外有些模型是不设定参数假设的,直接进行投影变换及解释成分的分解,最终合并各个解释成分得到各个变量的权重,比如PLS 模型,其求解过程本质上还是进行各种线性运算,属于广义的最小二乘法。
本文关注的是损失函数及根据损失函数求解模型参数。除了损失函数,还有评价函数。损失函数可以当成评价函数使用,此外,还有一些其他评价函数,如回归中的:,RMSE 和 MAE等;分类中的 AUC 等;其他的还有 AIC、BIC等等。具体可参考:模型评价方法总结
普通线性模型中采用OLS使得MSE最小,主要是利用了线性代数的知识进行求解,这是重要的基础知识,本文不再赘述。而SVM的优化求解比较复杂,属于二次规划问题,笔者目前也没完全研究透,写起来费劲并且缺少自己的思考总结,本文也暂时不作总结。因此本文以 Logistic 模型为例,对模型求解进行梳理。值得注意的是,神经网络的参数求解与 Logistic 回归中的求解思路有很多共通的地方。因此,本文也有助于理解神经网络的训练思路。
最大似然估计(MLE)是一种求解模型参数的策略(或者说思想),其思想是,对于模型中参数 ,存在一种情况: 时,可以使得现有数据(更准确地说是 数据关系: )出现的可能性最大( 取其他值时,使得现有数据出现的可能性都没这种情况大)。存在这种情况时,概率学派认为,在现有数据存在的情况下,模型中参数 的可能性最大。
MLE 是一种指导思想,MLE本身不涉及具体如何求解参数的最大似然估计值,求解 MLE 问题需要求导及解方程(似然函数的最大值问题属于优化问题,等价于:似然函数的导数等于0的问题。但是准确说,这是极大似然法,因为有可能求解到局部最优),而解方程其实不是一件容易的事(一次线性方程可以用线性代数的方法求解,但非线性方程 [ 如五次方程、指数方程、对数方程等 ] 求解就很难,最笨的方法是搜索解空间)。对于优化问题,目前最常使用的方法是梯度下降法。下面以 Logistic 回归模型的参数求解为例进行介绍。
本部分为笔者的个人总结和推导,转载请注明出处。
Logistic 回归模型(二分类)本身就不作过多介绍了,可以写成如下形式:
如何理解上面这堆等式呢?z 表示这个模型的因变量,其取值时是0~1之间的实数,表示使用参数 构建的模型 进行预测,且当输入的自变量为 x 时,输出 y 的值为1 的概率。如果要预测输出 y的值为0的概率,计算 1-z 就行了。当然,我们经常看到的最终模型输出的是类别,这是因为模型最后还加了个变换:z>0.5时输出1,否则输出0。
[ 思考一个问题:我们是否有必要修改最后的变换中采用的0.5这个界值呢?其实是没有必要的,使用0.5是很好解释的,预测哪类的概率大,就认为是哪类嘛。但如果很想修改界值,其实也可以调整线性回归部分 的结果的拟合界值,甚至可以直接修改损失函数 ]
我们把 称为sigmoid函数,其将连续性变量转成了0~1之间的实数,并且在x=0处的导数最大(最陡峭)。
如何用 MLE 来求解 Logistic 回归的参数呢?首先我们回归一下Bernoulli试验。
Bernoulli试验中,对于随机事件 y,其发生(取值为1)或不发生(取值为0)的概率为:
将上述两个式子合并,表示为:
我们可以看到,Bernoulli分布是与自变量X无关的概率分布函数,即 中的X其实是空的,且 。因此Bernoulli分布可以看作是特殊的分类函数。
我们假设 Logistic 模型已经构建好了(,模型表示为 ),那么对于样本1(自变量为 ),
其预测输出为 1 的概率为:
其预测输出为 0 的概率为:
由于我们已经知道样本1的标签为 ,因此使用模型 预测样本1的输出值正确(即输出 )的概率为:
这个式子是由刚刚回顾的 Bernoulli 试验推导而来的。
以上所有的参数都是确定的,得到的概率是确定值。若模型的参数不确定,那么就应该从从似然的角度来理解了,即在样本1存在的情况下,模型的似然函数为:
其中,模型 常略去已知参数,简写为关于参数 的函数 。
由于多个样本互相独立,那么对于给定的 n个样本,其采用假定已知的模型进行预测,其预测正确的概率为:
对应的,当模型参数未知时也有似然函数,即在n个样本存在的情况下,模型的似然函数为:
MLE 的哲学思想认为,使得 最大的 便是模型的最可能的参数,即:
如何求最大的 ,最直接的想法是求导,令导函数为 0 ,解方程即可(看上去是一个最优化问题,其实也是个解方程的问题)。但实际上,解方程并不是一件容易的事情,线性方程可以用线性代数的理论进行求解,但是非线性方程就比较难了。对于最小值的求解(准确说是极小值),往往采用梯度下降法进行求解(极大值问题可以用梯度上升法,当然还有其他优化的方法)。
梯度下降的简单理解(以一维情况中的导数为例):若要求解一维函数 的极小值,先任取函数上一点 ,求其导数 ,若 ,则进行迭代运算 ,稍微想想就知道为何如此迭代可以逼近极值,其中 称为步长(学习率)、一般取较小的数字;再在 上进行与 上相同的操作,反复迭代,直至 (其实终止条件往往是 小于一个很小的数)。这是在一维函数的情况下,以此类推多维变量的函数情况,导数此时被称为梯度,因此也就得名“梯度下降法”。
回过头来看各个的似然函数 ,为了简化求解,并且基于“函数取log后的极值点不变”,我们令“对数似然函数”为:
这个式子就是我们熟知的“交叉熵”了。
往往再变换一下:
常被称为损失函数,采用梯度下降法求解 的最小值即可。
我们已经知道了在单变量函数中的梯度下降(求导下降)的方法,即对参数 求导后,用迭代公式更新 的取值。那么在多变量(为一个向量的情景)里,如何实现梯度下降呢?比如 Logistic 中 , 那么如何更新各个参数的值呢?在这个问题中,我们需要用到3个策略:偏导 、 链式求导 和 导函数可加性。
首先理解偏导在这个问题中的作用。比如,对于函数 ,求解一组变量值 使得 y 取最小值。我们首选随机选取一组初始值 ,在该点处对x1求偏导 ,是一个关于x1的函数,则偏导数值为 ;同理对x2求偏导,是一个关于x2的函数,则偏导数值为 。我们称 为 y 在点 处的梯度值。使用梯度值的各个分量分别对相应的变量进行迭代更新即可,即:,。反复迭代,直到梯度值的各个分量都极小,便到达了 y 的较小值点,这便是“梯度下降”。
然后理解链式求导在这个问题中的作用。回到 Logistic 模型的损失函数 的求解任务,我们知道 是可以写成一个关于 的函数(仅以 作为自变量的函数),而 ,那么也就是说,可以写成一个关于 的多变量函数,采用上述的偏导策略即可。为何要提到链式求导呢?然而实际建模过程中,我们是采用了嵌套函数的建模策略,直接求导略显麻烦(当然是可以直接求导的),我们可以采取更简单的策略来分解求导任务:嵌套函数的求导可以使用链式求导来等价求解。上述对 的推导的过程中,我们可以知道存在: ,那么 (注:h对 部分的求导应当采取求偏导的策略),其中,我们可以令 表示 g 对 h 求导这部分,令 表示 h 对 求导的部分(由于是偏导,所以其值是一个向量)。比如样本1的链式第二部分的导函数为:
如何求链式第一部分的导数值呢?比如样本1,对于当前的参数 ,
第二部分的求导值为:
且正向传递的过程中,可以计算出
将 代入 ,即可求出样本1的第一部分导数值。然后将两部分的导数值相乘,即可得到样本1部分的梯度贡献:
最后是导函数可加性。所谓的导函数可加性,指的是原函数可以分解成几个部分之和(对于同一个自变量将权重分拆),对各个部分进行求导后,可以再将各个部分的导数值相加合并得到完整的导数值。举个栗子: 这个函数可以写成两部分之和,,两部分分别求导得: 。
回顾一下损失函数的形式,可以发现其实是各个样本累加所得,因此其导数也是各个样本部分累加所得。因此,对于当前参数 ,完整梯度值为:
因此,对于 的每个分量的值的更新,就可以直接利用完整梯度的各个分量代入公式更新。比如 的更新为:
整个过程的参数更新,其实利用了BP算法(反向传播算法)的思想,也就是利用损失函数的梯度,来更新修改模型参数的值。回顾一下这个过程,我们在正向传播的过程中,对于当前参数取值为 时,可以计算出各个样本的 ,我们常常称为当前层的激活值,而这个值可以用来帮助计算链式求导的第一部分的导数值,而在返向回去要更新参数的时候,这个第一部分导数值又可以帮助计算完整的梯度值。
但是仅修改了一层的参数(第二层的参数是固定不变的,因为sigmoid函数的参数固定不变),所以实际上反向传播仅影响了1层,因为反向传播的看上去不像真正的“反向传播”,大家也就不把此处称为反向传播。
[ 真正的反向传播:正向传播时,对于每层都可以计算出当前层的激活值,直至最后一层;反向传播的时候,最后一层可以根据最后一层的激活值计算出末层部分的梯度、并更新最后一层的参数(如果有参数的话),倒数第二层则可以根据倒数第二层的激活值和最后一层的梯度计算出最后两层的累积梯度、并更新倒数第二层的参数,...,第k层可以根据第k层的激活值和“第k+1层至最后一层的累积梯度”计算出“第k层至最后一层的累积梯度”的累积梯度、并更新第k层的参数,依次类推,直至第一层,从而计算出完整的梯度并更新第一层的参数。这便是神经网络的BP算法 ]
最近和小伙伴讨论多分类问题,发现自己理解不够深入,于是找了些 softmax 函数讲解的资料进行了下研究,并对本文进行更新。——2019年7月
多分类 Logistic 回归模型本身就不作过多介绍了,与二分类 Logistic回归的主要区别是将 sigmoid 函数改成了 softmax 函数,多分类模型可以写成如下形式:
表示该样本预测为第 i 类的概率(总共有C个类别); 表示上一层的输出。由此可见,对于每一个样本,上一层需要输出一个长度为C的向量,输入到 softmax 层后,将输出一个长度为C的向量 p(并且向量 p 的各个分量值之和为1),根据这个向量 p,可以选择值最大的分量作为预测的分类结果。下图是一个示例(变量名的表示与上述表述有区别,理解就行)
本来想模仿二分类问题的方法进行推导,笔者还构造了一个矩阵来推导模型的似然函数。失败的示范如下:
令矩阵 为单位矩阵,如 的值如下:
若模型为 ,则样本1的似然函数(类比二分类的推导)为:
从而全体样本(样本数为N)的似然函数为:
则对数似然函数为:
发现矩阵H是不可导的(H矩阵是二维离散变量映射到一维离散变量的关系),推导不下去了。
那就换个思路。在网上看到一个推导思路(softmax函数详解与推导),借鉴整理至此。其实关键还是利用了导函数可加性。对于每个样本分开求似然函数的导数,最后将所有样本的似然函数相加,得到全体样本的似然函数,并求出损失函数。
对于样本 ,其似然函数为:
其中,仅当 时, 的值为 1 ,否则为0。
则对数似然函数为:
从而全体样本的对数似然函数为:
到这一步,其实和刚刚的“失败推导”基本上一模一样,但是之后主要采取的策略是仍然将各样本的似然函数分开,并进行“分类讨论”,最后再加起来进行合并!
对于样本 ,总可找到一个 使得 ,则对数似然函数为:
根据链式求导,我们可以计算对数似然函数对上一层的输出变量 求导(其实是对变量 的各个分量求偏导),这个任务又可以根据链式求导分解成两部分:第一部分是对数似然函数对 变量 求导(其实是对变量 的各个分量求偏导),第二部分是变量 求导对 变量 求导(其实是变量 的各个分量对变量 的各个分量求偏导,最后变量 的每个分量 领取属于自己的部分,偏导值相加得到最终的偏导值 )。简单举例如下(假如是3分类情况):
[ 注:这只是求出来样本 i 部分似然函数对 的各个分量的偏导值,全体样本的偏导值全部相加才能得到最终该分量的完整的偏导值。 ]
下面我们约定: , 。
第一部分:对数似然函数对 变量 求导
情况1 对数似然函数对分量 求偏导的结果为:
情况2 对数似然函数对分量 求偏导的结果为:0
[ 因为对数似然函数仅与分量 相关,其他分量上的系数都为0 ]
第二部分:变量 求导对 变量 求导
情况1 对 上一层的输出变量 的第 分量 求偏导为:
[ 求导详细步骤可参考:softmax函数详解与推导 ]
由于指数函数求导的特殊性,兜兜转转最终得到的导数结果奇迹般地仍然可以用 表示。
因此对数似然函数对变量 的第 分量 在样本i 部分的梯度在为
情况2 对 上一层的输出变量 的第 分量 求偏导为:
[ 求导详细步骤可参考:softmax函数详解与推导 ]
因此对数似然函数对变量 的第 分量 在样本i 部分的梯度在为
这意味着,在正向传播计算的过程中,算出 值便算出了 对数似然函数对上一层的输出变量 的导数值,梯度的计算变得很简单了。
将所有的样本的梯度再相加(求均数),即可得到变量 的各个分量在全体样本中的完整梯度。
多分类问题和二分类不同的地方也就在“对数似然函数对变量 求导”的计算上,其余部分的计算是一样的,综合各部分的计算结果,可以计算出模型参数 的完整梯度,从而更新参数的各个分量 ,直至更新至各个分量 的偏导值都很小(即各个分量都不能继续更新),便找到了损失函数( )的极小值。
上述推导中,涉及了很多与神经网络共通的思路。其实,神经网络的最后一层就是 Logistic。这里就对比一下。神经网络与 Logistic 的主要区别在于:各层都有参数需要更新、各层都采用非线性变换进行激活输出。
多层参数的简单示例:
当然这个多层关系极其简单,是可以合并成一层关系的,但不影响计算推演。
[ 注:对于一个缺少非线性变换的神经网络,都可以压缩成一层变换函数。 ]
可以从2种角度来理解多层参数的情况:全局的参数同等对待、各层只关心当前层的局部计算规则。
先理解全局的参数同等对待。
对于示例,损失函数可以写成:
假定当前参数为 ,现在反向求导:
由此可见,各层参数实际上是互不影响的,梯度值的计算都是基于目前的参数值,所有参数的梯度计算好之后,再一起进行迭代更新。这便是全局的参数同等对待。
再理解各层只关心当前层的局部计算规则。
值得注意的是,第 k 层参数的梯度值的计算,与 1~(k-1) 层的梯度值无关,而和 (k-1) 层的激活输出值有关,并与 (k+1) 层及之后的梯度值有关(链式求导)。可以发现,第 k 层进行运算时,需要的数据其实可以归结于第 (k-1) 层和第 (k+1) 层:仅需要第(k-1) 层的激活输出值作为输入,及第 (k+1) 层的累积梯度值(即从最后一层反推至第 (k+1) 层的梯度的累乘)。那么问题就简化了,每层就是一个单独的“社会”,仅与相邻层有简单的联系。这便是各层只关心当前层的局部计算规则。
如果各层的输出值都未采用非线性变换作为激活函数,则全局的神经网络可以合并成一个一层的线性变换函数;若仅最后一层进行了 sigmoid 或 softmax 非线性变换,则全局的神经网络就是一个 Logistic 模型。真正有效的神经网络需要再各层的输出值上进行非线性变换,非线性变换函数有很多,比如 sigmoid,ReLU等,目前一般在中间层使用ReLU,在最后一层使用 sigmoid。
中间层使用 sigmoid被认为不如ReLU,因为sigmoid会将数据转换成接近 0 或 1 的数值,这容易过早损失信息,并且反向求导时,绝大部分情况的导数值是接近 0 的(回想下 sigmoid 函数的形状),容易导致梯度消失。而 ReLU更新一个过滤器,需要过滤的部分就全部过滤,不需要过滤的部分就完整保留;也有点像神经生物的原理:未达到阈值的信号直接无视,达到阈值的信号则保留输出。基于这种思想,神经网络的训练过程中,便是在训练处哪种强度的信号是需要过滤无视的,哪种强度的信号是有必要继续处理下去的。
笔者在使用数据模拟测试 Logistic 回归时,发现当没有数据噪声(即自变量根据公式生成因变量,不加任何噪声)时,Logistic 回归拟合结果会显示所有参数估计值的方差都很大 ( p值也较大,Wald 检验不拒绝H0假设),而在 Python的scikit-learn包中会给出警告:系数无法收敛 [ converge ] 。但是模型的拟合效果很好,这种情况像极了共线性导致的结果。但是想来想去,实在不可能存在共线性啊。最终在网上差到了一篇文章:关于Logistic Regression对于线性可分的数据集的不收敛性的分析,发现这竟然是Stanford 机器学习的一道思考题。在这篇文章的提示下,终于想明白了背后的原因。
此处以两个自变量的情况为例进行分析,我们需要求解的参数就是两个自变量的系数和一个截距值。线性可分的情况,如果可视化其实类似于下图的情况(虽然是三维数据,但是因变量维度可以用颜色或形状表示,而两个自变量分别用横坐标和纵坐标来表示):
[ 图片来源:关于Logistic Regression对于线性可分的数据集的不收敛性的分析 ]
其实问题也就等价于,找出一种 与 的关系,使得如下不等式对于任意 i 都成立:
当数据线性可分时,我们可以找到类似于图中的那条直线,假设那条直线的方程可以写成 成立。当然,其中 与 的取值范围不属于当前数据样本。由图可知,这组 是可以满足上述不等式组的。既然 可以满足 ,那么对于任意 ,都存在 可以满足 ,从而使得不等式组成立。这些参数解,其实代表的都是同一条直线,本质上是因为一条直线只需要2个参数即可确定,当存在第3个参数时,将会使得参数的组合变得很多。比如, 与 表示的是同一条直线。但是,这并不影响梯度下降的参数收敛,因为梯度下降法其实不涉及到截距变量 的实质性梯度更新,因此刚刚的情景中,参数并不冗余。那么究竟是什么原因造成了参数不能收敛呢?
我们注意到,根据不等式组的特点,这条直线附近的直线也是一系列解(因为不等式存在一个开区间,那么直线往开区间方向平移极小的距离,也可以使得不等式组仍然成立)。当然,上图中的参数解更多,因为可以移动的范围很大,而且甚至可以旋转角度。因此,当数据线性可分时,Logistic 回归的参数解有无穷组。
而数据不是线性可分时,总会找到一条更合适的直线,这条直线平行移动微小距离会使模型变差,旋转微小的角度也会使模型变差。造成直线唯一确定的,其实是特定的几个样本,这种特定样本在直线上,如果微小的偏差,会使得整体的分类出错变多。这种情况的理解不能单纯依赖上面那个图了(不太好理解了),因为变量之间需要进行映射变换,得到一个区分度较好的一维的变量后,再以该变量的均值作为分界,进行概率的推断。由于这种情况下,不可能拟合到一个完美的新变量,也就可以找到尽可能好的那个拟合方式(前提是变量之间不存在较严重的共线性)。
1、对于无意义变量,梯度下降过程中是如何处理的?
其实无意义的变量,就是权重为0 的变量,在梯度下降时,其参数更新迭代逐渐逼近 0,到达 0 之后,该分量的偏导值接近0,也就不再进行迭代更新。
2、我们常说的一个 epoch 就是指进行了一次迭代,即全局参数进行了一次更新。
3、训练数据分批次训练,有什么好处?分批次训练的过程是怎样的?Batch Normalization 为什么具有优势?
首先,批次训练的过程是,每一批数据单独计算损失函数,并进行参数更新迭代,也就是说,每一批数据占用一个epoch,批次间是串行运算的。
传统的做法是一次性将所有的样本的损失值计算并相加求平均,得到总的损失值,如果结合梯度下降法,则被称为批量梯度下降(注意:此处说的批量和批次的概念不同,批量就是不分批次) 。但是当内存资源有限时,这种做法变得不可行。因此引出分批训练的策略。
分批次训练有几个好处。第一,可以避免内存限制。第二,可以实现批次梯度下降。我们知道梯度下降可能会陷入局部极小值,主要是因为损失函数是针对全体样本而计算的,其形状是确定的。如果分批次,每批次有自己的损失函数,损失函数可能不同,也就有可能可以避开局部极小值。但是如果每个样本单独作为一个批次(此时被称为 随机梯度下降SGD),会导致损失函数失真严重,从而导致梯度下降的效率变低。因此更合理的做法是采取 mini-batch 的策略,用小样本组成一个批次,并配合随机梯度梯度下降(此时被称为 小批量梯度下降MBGD,也就是我们常说的分批训练)。
Batch Normalization 的优势:吸收了分批训练(Batch)带来的好处,同时也吸收了数据标准化(Normalization)带来的好处(提高梯度下降的效率)。当然应该还有其他优势,笔者的总结可能不全面。
4、神经网络相比 Logistic 模型的优势在哪?神经网络的非线性变换,是否有助于过滤无关变量?神经网络在表格数据(表达谱数据)场景中,能否优于 XGBoost ?CNN 为什么在处理序列数据时具备独特的优势?在超大样本的序列数据(如图片、语音文字等)情景中,机器学习模型是否非劣于深度学习模型。
参考资料:
机器学习中的范数规则化之(一)L0、L1与L2范数
softmax函数详解与推导
三分钟带你对 Softmax 划重点
小白都能看懂的softmax详解
logistic回归损失函数与梯度下降
统计学知识6:逻辑回归的极大似然求解(梯度下降实现)
简单的交叉熵损失函数,你真的懂了吗?