机器学习基础

机器学习基础

前言

因为本人之前选修的是机器学习方向,所以上过「机器学习」「数据挖掘」「计算机视觉」等课程。学习「机器学习」的时候比较认真,还是知道一些模型的,但是学「计算机视觉」的时候没有怎么听,而且这门课又是主要讲cv的,并没有对深度学习有一个系统的讲解,学到的知识是比较零碎的。所以,打算好好学习一下深度学习的理论知识,并做一个整理。

内容不会写成教程那样详细,大部分都将会是概括性的,总结性的,主要目的是做一个系统的梳理,原理什么的网上太多了!

因为深度学习是机器学习的一个分支,学习深度学习之前有必要先对机器学习有一个深入的了解。总之,如果入坑的话,建议先学机器学习,推荐「西瓜书」+「机器学习实战」,一本理论一本实践,这也是我们上课用的书。西瓜书公式推导不是很详细,如果自学的话,可以再补充一本「统计学习方法」,「机器学习实战」用的代码是基于陈旧的python2.7,在github上找一份python3版本的作为练习。同时可以访问sklearn官网,这是一个机器学习库,看它的文档学习,这个库封装的很好,学起来很简单。

不过,一切的前提是有数学基础和编程基础,即:学过微积分、线性代数、概率论的课程,掌握C/C++,Java或者python等,有一定编程功底。不然…

因为之前学过机器学习,这里只介绍机器学习的基本知识以及和深度学习紧密联系的内容。开始进入正题!

1.机器学习的基本任务

先放一个图镇楼!
机器学习基础

机器学习基本任务分为四大类:

定义 任务
监督学习 使用已知正确答案的实例来训练模型 分类,回归,结构化学习(目标检测、识别、语义分割…)
无监督学习 在无标签的数据集中查找规则的模型 聚类、降维
半监督学习 结合分类的聚类的思想生成新模型 自编码,生成式对抗,推荐
强化学习 对没有标注数据集,但知是否更近目标来构建模型 分类、回归

其中监督学习是目前最常用的一种机器学习类型,其一般过程如下图:

机器学习基础

2. 机器学习一般流程

机器学习基础

图片上方完整概述了机器学习的一般流程,不过我们重点关注建模和评估两步。因为机器学习的三要素是:模型学习准则优化算法,这也是我们学习机器学习课程的核心。前面的数据预处理等部分其实特别重要,可以说决定机器学习模型上限,不过这部分是特征工程、数据挖掘的重点,我们的重点还是这三要素。

在监督学习中,模型就是我们要学习的条件分布(概率模型)或决策函数(非概率模型)。机器学习的目的就是找到一个模型来近似真实映射函数或条件分布。

什么是学习准则呢?我们知道,从输入空间到输出空间构成了一个样本空间,我们认为样本空间就是真实空间[ 这里涉及到机器学习理论的一个前提,就是我们假设样本集Q和世界W是独立同分布的,且Q在W中随机分布,因此具有足够的泛化能力 ] ,因为我们不知道真实的映射函数或条件分布,只能根据经验确定一个函数集合,称为假设空间 [选择不同模型,就有不同的假设空间,一般分为线性模型和非线性模型] ,而学习准则就是衡量当前模型好坏的一种手段,也就是当前模型和真实模型之间的差异、距离。一般用损失函数表示。

而优化算法就是用于求解最优模型的计算方法,因为确定了训练集,假设空间和学习准则后,如何找到最优模型就成为了一个最优化问题。分为参数优化和超参数优化,超参数用于定义模型结构或优化策略,一般人为调整。

确定模型后,还需要评估模型性能,评估方法包括:留出法交叉验证法自助法

3. 损失函数

可以参考文尾链接:Pytorch模型训练实用教程 和 pytorch loss function 总结
这里罗列了所有的损失函数,用来占坑,这些函数主要用于深度学习中。到时候用到哪个了再来详细补充~

L1范数损失 nn.L1Loss

公式:
(x,y)=L={l1,,lN},ln=xnyn, \ell(x, y) = L = \{l_1,\dots,l_N\}^\top, \quad l_n = \left| x_n - y_n \right|,

平滑版L1损失 nn.SmoothL1Loss

公式:
loss(x,y)=1nizizi={0.5(xiyi)2,if xiyi<1xiyi0.5,otherwise  \text{loss}(x, y) = \frac{1}{n} \sum_{i} z_{i} ,z_{i} = \begin{cases} 0.5 (x_i - y_i)^2, & \text{if } |x_i - y_i| < 1 \\ |x_i - y_i| - 0.5, & \text{otherwise } \end{cases}

二进制交叉熵损失 nn.BCELoss

公式:
(x,y)=L={l1,,lN},ln=wn[ynlogxn+(1yn)log(1xn)] \ell(x, y) = L = \{l_1,\dots,l_N\}^\top, \quad l_n = - w_n \left[ y_n \cdot \log x_n + (1 - y_n) \cdot \log (1 - x_n) \right]

带有logistic函数的二进制交叉熵损失 nn.BCEWithLogitsLoss

公式:
(x,y)=L={l1,,lN},ln=wn[ynlogσ(xn)+(1yn)log(1σ(xn))] \ell(x, y) = L = \{l_1,\dots,l_N\}^\top, \quad l_n = - w_n \left[ y_n \cdot \log \sigma(x_n) + (1 - y_n) \cdot \log (1 - \sigma(x_n)) \right]

均方误差损失 nn.MSELoss

公式:
(x,y)=L={l1,,lN},ln=(xnyn)2 \ell(x, y) = L = \{l_1,\dots,l_N\}^\top, \quad l_n = \left( x_n - y_n \right)^2

交叉熵损失函数 nn.CrossEntropyLoss

公式:
loss(x,class)=log(exp(x[class])jexp(x[j]))=x[class]+log(jexp(x[j])) \text{loss}(x, class) = -\log\left(\frac{\exp(x[class])}{\sum_j \exp(x[j])}\right) = -x[class] + \log\left(\sum_j \exp(x[j])\right)
可以看出pytorch中对预测class进行了softmax操作,保证将预测值映射到0-1之间,且和为1。
关于交叉熵的理解可以看:一文搞懂交叉熵在机器学习中的使用
关于softmax可以参考:手打例子一步一步带你看懂softmax函数以及相关求导过程

KL 散度损失 nn.KLDivLoss

公式:
l(x,y)=L={l1,,lN},ln=yn(logynxn) l(x,y) = L = \{ l_1,\dots,l_N \}, \quad l_n = y_n \cdot \left( \log y_n - x_n \right)

负对数似然损失函数 nn.NLLLoss

公式:
(x,y)=L={l1,,lN},ln=wynxn,yn,wc=weight[c]1{cignore_index} \ell(x, y) = L = \{l_1,\dots,l_N\}^\top, \quad l_n = - w_{y_n} x_{n,y_n}, \quad w_{c} = \text{weight}[c] \cdot \mathbb{1}\{c \not= \text{ignore\_index}\}

nn.MarginRankingLoss

公式:
loss(x,y)=max(0,y(x1x2)+margin) \text{loss}(x, y) = \max(0, -y * (x1 - x2) + \text{margin})

nn.HingeEmbeddingLoss

公式:
ln={xn,if  yn=1,max{0,Δxn},if  yn=1, l_n = \begin{cases} x_n, & \text{if}\; y_n = 1,\\ \max \{0, \Delta - x_n\}, & \text{if}\; y_n = -1, \end{cases}

多分类Hinge损失 nn.MultiMarginLoss

公式:
loss(x,y)=imax(0,marginx[y]+x[i]))px.size(0),x{0,  ,  x.size(0)1},iy \text{loss}(x, y) = \frac{\sum_i \max(0, \text{margin} - x[y] + x[i]))^p}{\text{x.size}(0)},x \in \left\{0, \; \cdots , \; \text{x.size}(0) - 1\right\} ,i \neq y

多标签分类损失 nn.MultiLabelMarginLoss

公式:
loss(x,y)=ijmax(0,1(x[y[j]]x[i]))x.size(0) \text{loss}(x, y) = \sum_{ij}\frac{\max(0, 1 - (x[y[j]] - x[i]))}{\text{x.size}(0)}

二分类logistic损失 nn.SoftMarginLoss

公式:
loss(x,y)=ilog(1+exp(y[i]x[i]))x.nelement() \text{loss}(x, y) = \sum_i \frac{\log(1 + \exp(-y[i]*x[i]))}{\text{x.nelement}()}

多标签损失 nn.MultiLabelSoftMarginLoss

公式:
loss(x,y)=1Ciy[i]log((1+exp(x[i]))1)+(1y[i])log(exp(x[i])(1+exp(x[i]))) loss(x, y) = - \frac{1}{C} * \sum_i y[i] * \log((1 + \exp(-x[i]))^{-1}) + (1-y[i]) * \log\left(\frac{\exp(-x[i])}{(1 + \exp(-x[i]))}\right)

cosine损失 nn.CosineEmbeddingLoss

公式:
loss(x,y)={1cos(x1,y),if y=1max(0,cos(x1,y)margin),if y=1 \text{loss}(x, y) = \begin{cases} 1 - \cos(x_1, y), & \text{if } y = 1 \\ \max(0, \cos(x_1, y) - \text{margin}), & \text{if } y = -1 \end{cases}

三元组损失 nn.TripletMarginLoss

公式:
L(a,p,n)=max{d(ai,pi)d(ai,ni)+margin,0},d(xi,yi)=xiyip L(a, p, n) = \max \{d(a_i, p_i) - d(a_i, n_i) + {\rm margin}, 0\}, d(x_i, y_i) = \left\lVert {\bf x}_i - {\bf y}_i \right\rVert_p

连接时序分类损失 nn.CTCLoss

公式:无

目标值为泊松分布的负对数似然损失 nn.PoissonNLLLoss

公式:
targetPoisson(input)loss(input,target)=inputtargetlog(input)+log(target!) \text{target} \sim \mathrm{Poisson}(\text{input}) \text{loss}(\text{input}, \text{target}) = \text{input} - \text{target} * \log(\text{input}) + \log(\text{target!})

4.优化器

确定了模型和损失函数,接下来就要确定优化算法了。最常用、最简单的优化算法就是梯度下降法。传统梯度下降法公式:θθλδ\theta \leftarrow \theta -\lambda \delta 。不过这个简洁表示有很多不足,比如:

  1. 学习速率λ\lambda不易控制,过小收敛慢或陷入局部最优,过大又容易振荡
  2. 容易卡在鞍点或平坦区域,造成提前结束训练
    从公式可知,影响优化的有两个因素:梯度方向以及学习率,因此从这两个方面入手来克服这些问题。
动量算法(Momentum)

引入动量算法可以改变梯度下降方向
其实就是模拟了物理学中动量的概念,认为物体的运动有一个惯性。因此计算当前点的梯度后,和前一个点的梯度来进行合成,得到实际的梯度。这样做可以减小振幅,轨迹更加稳定,提高了算法的稳定性和收敛速度
当然还有一种叫做NAG的改进算法,它先按前一个点的梯度方向前进一小步,然后再修正这一步的梯度方向,进一步防止大幅度振荡,同时不会错过最小值,对参数更新也更加敏感

下面几种优化算法同时从梯度方向和学习率进行优化,效果更好!

AdaGrad算法

核心就是增加一个梯度累积变量r,用于保存累积平方梯度,随着迭代次数增加,r的值变大,导致学习速率λσ+r\frac{\lambda }{{\sigma {\rm{ + }}\sqrt {\rm{r}} }}逐渐变小,同时算法中更新不同参数的学习速率不同,对稀疏参数大幅度更新对频繁参数小幅更新,因此提高了算法稳定性,不会因学习速率过大越过极值点,也不容易卡在鞍点。不过缺点就是,有时候学习速率减小太快导致训练不足。

RMSProp算法

通过修改AdaGrad算法而来,使用指数加权的移动平均代替梯度平方和,引入了超参数ρ\rho来控制移动平均的长度范围

Adam算法

Adam本质上是带有动量项的RMSProp算法,利用梯度的一阶矩估计二阶矩估计动态调整每个参数

pytoch中定义了这些优化器,每种优化算法具体细节以后用到再来补充~

5.其它问题

权重正则化

欠拟合原因:训练不够或模型太简单
过拟合原因:训练过度或模型太复杂

一个好的模型,应该有一个较小的期望错误,但是我们只有训练集,并不知道真实的数据分布和映射函数,无法计算期望风险,所以只能计算经验风险,即根据训练集上的预测值和标签值之间的差值定义的损失函数值。所以原来的损失函数遵循经验风险最小化准则

但是我们的训练集只是真实数据一小部分,且包含噪声,所以经验风险最小化就会导致我们的模型过度学习训练集,导致过拟合,泛化性能不好。

所以我们就在经验风险最小化的基础上引入参数的正则化,来限制模型能力,不要过度的经验最小化,这就称为结构风险最小化
机器学习基础

后面一项就是正则化项,这里是正则化项用的L2L2范数,也可以用L0L0L1L1等。其中引入了超参数λ\lambda,称为 权重衰减值,用于平衡经验风险和正则化项的作用。

我们知道过拟合就是我们的模型学习能力太强了,即模型太复杂了,模型的参数太多了。而通过引入正则化项,就可以稀疏化我们的参数,因为要使结构风险最小化,就必须保证参数和不能太大,这样一些参数的值就要尽可能的小,因此防止了模型过度复杂。

下面几个问题重点关注深度学习,这里简略写一下,以后专门介绍

Dropout正则化

这是一种针对神经网络模型的正则化方法,在训练过程中随机屏蔽或忽略一些神经元,这样在正向传播中这些神经元对下游神经元作用消失,反向传播时它们的权重也不会更新。产生权重收缩的效果,避免模型过拟合。

批量标准化

可以参考:
批量标准化BN
Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift全文翻译

在较复杂的神经网络中,随着前一层的参数的变化,各层的输入分布也会发生变化,这样就容易发生内部协变量移位(internal Covariate Shift),使训练变得困难。通俗来说,比如隐藏层用sigmoidsigmoid作为**层,如果前一层参数变化,导致后一层的数据输入分布在两侧,根据sigmoidsigmoid曲线特点,可以知道此时梯度接近于0,所以就会产生梯度消失现象,导致参数不能更新了。批量标准化就是在隐藏层的输入前加入一个标准化层,解决这个问题的。

机器学习基础

可以看到使隐藏层的输入数据归一化了,均值为0,方差为1,然后反标准化操作,引入了γ\gammaβ\beta这两个可以学习的参数,对标准化后的值进行缩放和平移,因为靠近0的区域在**函数上往往是线性区域,不利于训练好的非线性网络,同时也增加了网络的表达能力,使中间层输出不限制于标准正态分布,而是自己通过学习确定。

批量标准化优点很多,比如避免了梯度消失梯度爆炸,加速网络收敛,并且提高了泛化能力

权重初始化

因为神经网络参数多,层数多,所以参数的初始化会影响模型的效果。
比如初始化值特别小,那么可能传到后面都没什么信息了。或者初始值特别大,可能在传播过程中产生爆炸的值。亦或是陷入了局部最优…
一般有哪些初始化方法呢?零值初始化随机初始化均匀初始化正态分布初始化正交分布初始化

关于**函数

正是因为**函数,才让神经网络具有了非线性建模能力,否则无论多少层,也只能处理线性可分问题。常见的**函数包括:sigmoid、tanh、relu、LeakyReLU、softmax等
可以参考文尾链接~

总结

写得比较乱,有一些关于深度学习的比如损失函数、**函数、优化器、dropout等写的比较简洁,其实这里面单独一个主题都可以写很多,因为才刚刚开始,虽然参考了很多资料,不过理解不深,以后遇到再详写。

参考链接:

  1. Pytorch模型训练实用教程
  2. pytorch loss function 总结
  3. 一文搞懂交叉熵在机器学习中的使用
  4. 手打例子一步一步带你看懂softmax函数以及相关求导过程
  5. 批量标准化BN
  6. Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift全文翻译
  7. Visualising Activation Functions in Neural Networks
  8. wiki-**函数