CS231n学习笔记(上)

Posted by Kriz on 2017-04-25

开新坑的时候总有一种罪恶感【扶额

感觉自己之前为了赶论文和demo,涉及的CNN知识比较乱,所以打算系统地整理一下。

计算机视觉历史回顾与介绍

David Marr的关于视觉的模型架构:

  1. 输入图像
  2. 边缘结构(原始草图)
  3. 2.5D(认识层次关系)
  4. 3D模型

感知分组是视觉领域极为重要的问题,目前仍然没有得到彻底解决。

Normalized cut(1997):运用现实图片进行感知分组的第一次有效尝试

ImageNet数据集:5000万张图,标注了2万个分类,人工清洗数据。可以作为合适的训练集

2012年的ImageNet竞赛获胜者,错误率比2011年减少了约一半。使用了CNN

  • before 2010:特征+支持向量机
  • after 2012:全都是深度学习网络
  • 2015:151层CNN,深度残差网络

CNN是具有压倒性优势的深度学习架构。

深度学习架构的复兴:

  • 摩尔定律(硬件提升)
  • 大数据

愿景:输入图片,输出文字版的图片描述(即完成计算机的“视觉理解”)。【容我讲一句woc

K最近邻与线性分类器

软工答辩之前还专门研究了下K临近算法来着,居然派上用场了【

CNN标配:python+numpy

图片分类

要求:对所有相机调整都具有鲁棒性(光线,形变,景深)

其他干扰:遮蔽,背景杂斑,分类等

目前的图片分类趋势:数据驱动

CIFAR-10数据集

包括10个标签,50000张训练图,10000张测试图,32*32。

目前的测试:假设有10个不同的图像例子,在训练集上寻找与这些图像中的每一个独立图像最相近的近邻。输出结果是已经分类好的图像列表,显示的是在训练数据中,和那10个类别最相似的每一种测试图像。

如何定义距离的度量?最简单的方式:曼哈顿距离算法(L1 distance)。将test image和training image(单一图像)的像素值进行逐个比较,形成差值的绝对值矩阵,然后求各个元素之和。得出的结果就是距离。

pic1

减慢的速度是线性的,因为是在进行独立的比较。

近邻算法是一个即时的训练方法,同时也是一个昂贵的测试方法。

加速近邻算法的方法:近似近邻算法

然而曼哈顿距离太辣鸡了因此在实践中我们选用欧氏距离(L2 distance),计算图像差值的平方和。

这个距离的选择被称为超参数(hyperparameter)。

k-NN

讨论另一种超参数

将近邻推广为k-NN(最近邻规则分类器),在k-NN中检索每一张测试图像。

单一实例会检索k个最邻近的实例,我们将让它们在所有的类中做多数的表决,从而对每一个测试实例进行分类。

举例:在训练集中检索到k张最相似的图像,然后对它们的标签进行多数表决。

pic2

对于k值的选择是一个超参数。

回到刚刚CIFAR-10,输出部分选择了十个最相似的样本,它们是通过距离来排序的。

pic3

对这些训练样本进行多数投票,来给每个测试样本进行分类。

超参数的选取只能使用大量参数进行实验:

5折验证:验证集取训练集的1/5,其他4折进行训练,取不同数量的近邻值做多数投票测试。

交叉验证法:在5折里反复设定不同的验证集。

最后作折线图来寻找最优。

k临近算法的缺点

嗯……k-NN好像在这方面很少使用的样子。

  • 效率低
  • 不自然直观(?)

线性分类器

啊终于开始正题了【

仍然考虑上面提到的10个标签的那个数据集,接下来会通过一种参数化方法得到分类结果(k-NN是一个非参数方法的实例,整个过程中不需要进行参数优化)。

在这个过程中,我们要做的是构造一个函数,输入一张图片,对每一类输出一组数值(scores),对应10个标签的匹配度。

表达式:f(x,W)。x是输入图像(通常是维度为像素个数的列向量),W是权值。在初期,我们希望把W设定成为对训练集中每张图像都可以实现正确输出的值。

假设我们是用的是最简单的线性分类方法f=Wx+b,手工一个一个调权值就好了(并不是。

线性分类器的实际含义:所有的分数都是一个所有的像素点值的加权和——实际上是不同空间位置的颜色之和。W分类器类似于模板匹配,即颜色等类似的图片会有明显的加分。

损失函数

损失函数(loss function)可以定量地测定分类器工作的好坏:通过一个数学表达式给出对于一个确定的分类器W,在测试中得到的结果如何。

通过这个函数,我们容易找到可以确切定义能最小化这种损失的W。换句话说,一旦能找到一个W使得损失值非常低(最好的情况:损失值低到了0),那么就能说这个分类器能够正确地分类所有的图片。

因此接下来要做的就是优化W啦。

线性分类器损失函数与最优化

先确认目的:找到一个损失函数来衡量W,使得得到的损失最小。

多类SVM损失

是一个两分类支持向量机的泛化(???)

SVM loss的公式(hinge loss):

pic4

一个计算的例子:

pic5

最终的多类损失值即为所有losses的平均值。

正则化

用来优化W。(权衡训练损失和用于测试集的泛化损失)

正则化的最常见形式是L2 regularization:

pic6

和L1相比,L2可以有效地分散权值,能够很好地利用所有的输入,最后效果往往会更好。(相比之下L1可以更好地实现稀疏,之后会讲到)

Softmax分类器

在分数基础上表明损失的一种不同的函数形式。

pic7

Softmax vs. SVM

SVM具有附加的稳定性,一旦样例点满足边界条件,这个样例点就不会影响损失函数。而softmax会将所有的样例点都纳入考量。

那么到目前为止的内容大概是这样的:

pic8

梯度下降

(这里先略,我觉得讲bp的时候应该会详细点?)

学习速率

每个循环中移动的大小。

如果学习速率太高,损失函数就很容易乱搞事,不会收敛甚至会越来越大(因为在空间里移动得太剧烈了),就算收敛也很可能卡在一个比较高的位置;如果学习速率太低,损失函数达到收敛则需要很长时间。

一般来说是先选一个比较高的,再慢慢减小。

常见的优化损失函数的方法:SGD,NAG,momentum,Adagrad,RMSProp,Adam等。

HOG/SIFT特征

先让我手动再见一下,SIFT简直阴影【

一般的图像识别:计算图像不同的特征和描述,最后通过总结来描述图片内容是什么。

SIFT/HOG是个常用的特征。它会使用图片中不同物体之间边缘的方向来做分类,将不同方向上的边缘做总结。

(这里讲得非常概括,有空专门记录一下SIFT的流程)

反向传播与神经网络初步

先看一眼目前的进度

pic9

计算梯度

数值计算:慢,不精确,但是好写

微积分计算:快,准确,然而容易出错

一般用微积分计算方法,用数值计算进行梯度检查。

反向传播

是一种通过链式法则来进行(反向)递推的计算过程。这个链路中的每一个中间变量都会对最终的损失函数产生影响。

举例说明:

一个数学表达式,最后一步的输入x为1.37,得出结果的方法是取倒数。

知道f(x)=1/x → df/dx=-1/x^2^,所以局部梯度乘后一层梯度即为所求,此例中即为(-1/1.37^2^)*1.00=-0.53。

得到的结果是负值,说明它对结果有相反的影响。

假设再前一步得出结果的方式是+1s,我们知道f(x)=a+x → df/dx=1,所以这里的梯度是1*(-0.53)=-0.53,说明这一步仍然对最终结果的影响是相反的。

再假设再前一步得出结果的方式是exp,啊好烦啊看图好了。

pic10

带参的加法就如同“梯度分发器”,等号左边每一项的梯度和右边都相同;

max函数就如同“梯度路由”,较大一方是1,较小一方是0;

乘法就如同“梯度转换器”,如果有异号出现,则效果会立刻改变。

大的函数也可以直接视作一个整体来计算梯度。

如果一个值通过分支被用于各个部分的计算中,通过多元的链式法则,正确的计算方法是把它们的结果相加。

了解梯度的传递方式能让人更加高效地调整网络,而不会把网络单纯当一个黑盒子用。

代码实现的时候,前向运算过程中要把中间值存储下来,因为在反向传播中会用到。每次改变参数,都要重新更新各梯度值。

做个小总结

目前为止的网络数据量相当庞大,我们记录中间值,对每个节点应用前馈API构成图结构。

图结构是对所有层以及层与层之间连接的包装(Graph structure and infrastructure is usually a very thin wrapper on all these layers),层与层之间的连接是通过向量的传递完成的。

实际应用中传递的是n维数组,数组在各层之间传递,每层都独自处理前向和后向的传播。

神经网络初步

之前使用的一直是f=Wx,下面要把它搞得复杂一点才行。

使用一个两层神经网络:f=W~2~max(0,W~1~x)

代表的操作:给出一个x,用W~1~矩阵乘以x(W~1~x的结果是中间的隐含层),接下来应用一个阈值为0的激活方程(ReLU),再乘以W~2~得到结果。

这个神经网络只有两层有权,所以是两层神经网络。

神经元的每个突触都有一个属于自己的权重,用来表达两个神经元的相似度(??)。输入值和权重之积传向细胞主体,细胞主体执行操作,再应用轴突上的激活方程,数据经过这一系列操作得到这个神经元的输出。

常用的激活方程是sigmoid函数,1/(1+e^-x^)。(它能保证输出结果介于0和1之间)

激活函数实质上是神经元对某个输入的处理比率。如果神经元在上个神经元的输出里找到了它喜欢的东西,它会把数值上涨许多。

一些常见的非线性激活函数:

  • sigmoid
  • tanh:tanh(x)
  • ReLU:max(0, x)
  • Leaky ReLU:max(0.1x, x)
  • Maxout
  • ELU

pic11

神经网络结构

先看这张slide:

pic12

每个神经元都连着下一层的所有神经元,则称这些层为全连接层。

神经元数量越多越好,因为在机器学习中经常出现模型表达能力不足的问题。但要注意适当地加入正则化,以及注意正确的防止神经网络过拟合的方法。

怎样衡量深度和宽度,目前还没有标准答案。但一般来说,如果是图片问题的话,层数会更重要一些

整个神经网络一般都使用同样的激活函数。