cs231n深度学习与计算机视觉结合

一、卷积介绍

众所周知,计算机视觉 是一个多学科融合的领域,从计算机科学到数学,从生物学到心理学,计算机视觉都有很大的用武之地:

视觉的由来与机器视觉的演变

地球诞生生命之初,谁都不知道地球是什么样子的------因为没有生物有眼睛,慢慢的,为了更好的捕食,5亿年前第一批生物进化出了最基础的视觉,又经过漫长的时间,等到人类已经可以制造出机器,最初的机器视觉物体产生了:照相机! 而后,在20世纪,计算机视觉(机器视觉)的发展空前迅速,时间来到20世纪中叶这个重要的节点,两名哈弗的学生为了了解视觉神经的处理机制,做了一个实验:将金属探针接入猫的基础视觉皮质层中(primary visual cortex,处理大量和视觉相关的工作,但是位置在后脑勺处,并且大脑中有接近50%的神经元都参与着视觉处理的过程),并记录神经元的状态,发现猫在注视照片时并不会引起神经元的活动,但是当他们在切换照片的过程中,会激活部分神经元,这是开启深度学习的一个重大发现,他们得到的结论是:视觉处理流程的第一步,是对简单的形状结构处理,如边缘,排列等,并且凭借这一发现获得了1981年的诺贝尔医学奖。

计算机视觉在这一发现之后有了突飞猛进的发展:

而现代计算机视觉领域的先驱是谁呢?是Lary Roberts在1963年的论文《Block world》,他的论文中提到边缘是决定物体形状的关键,并且解析出物体边缘的信息,属于行业内的开创性文章;

而后1966年,麻省理工成立人工智能研究室(MIT AI lab),使得计算机视觉成为人工智能中最为发展快速的领域;

接下来是David Marr,他在1970年的Vision一书中提出了另一个可以称之为深度学习基石的理论:视觉是分层的,并且我们可以建立一个分层的模型,将图像分为边缘结构->2.5D结构(因为物体之间是存在遮挡的,但是人类的大脑是可以分辨出来的,而且世界是三维的,但是我们的视觉成像是二维的)->3D结构,这是一个最基础但是也很抽象的视觉认知模型;

而后MIT与斯坦福分别对视觉模型进行研究,并且建立了简单的模型,MIT模型认为一切物体都是由简单的形状组成,例如圆柱体,只是观察角度不同;而斯坦福则认为物体是由简单形状构成,但是形状之间是由弹簧连接起来的;

接下来进入90年代,计算机视觉进入彩色世界,Normalized Cut被提出用来进行图像分割,人类视觉对于图形的分类是很奇特的,而计算机却没有办法做到完美的分组,这也使得感知分组变成视觉领域最为重要的问题,即使到现在也没有得到很好的答案;

接下来计算机视觉跳入了一个新的领域:物体识别领域,1999年的物体识别与2001年的人脸检测是这一领域的两大标志性产物,这一领域也变成目前人工智能主攻的课题;

计算机视觉的崛起

接下来进入20世纪,很多的挑战比赛加速了深度学习的进程,2006-2012年的PASCAL Vsiual Object Challenge 是一个将图片进行20分类任务的挑战,比赛持续的几年分类错误率在持续下降;

到了2009年,IMAGENET挑战横空出世,包含1000种类别的140万张标注图像提供给参赛者进行认知分类,而IMAGENET比赛进行的第三年,也就是2012年,卷积神经网络一举夺魁拿下当年比赛的桂冠,这也就是深度学习理论的开端,并且以后每一年的IMAGENET冠军都是卷积神经网络显示出最好的成绩;

其实早在1998年,LeCun就使用了卷积神经网络来进行了手写字的识别,而2012年冠军的AlexNet几乎是照搬的LeCun的网络,除了激活函数由Sigmoid变成了ReLU,而能够让卷积神经网络能有如此之进化的效果很大一部分程度上要归功于硬件的革新;

计算机视觉接下来的挑战

计算机视觉所要专注的问题其实远远不止物体识别,对图片进行密集标记,动作识别,识别与3D整合,这些都是深度学习面临的挑战;计算机视觉针对图像,若是可以让计算机进行"看图说话",或者让计算机理解图片中的深层语义,这些都是计算机视觉可以达到且应该达到的目标;

深度学习有着很好的发展前景,即使目前正是深度学习的"瓶颈期",可它在图像领域仍然走在各种方法的前列,学好深度学习,走向美好人生,我们的梦想是星辰与大海!

二、图像分类

分类图片的多变性

目前的感知分类问题最重要的就是标签与图像,通常图像都是由庞大的数字列表组成,例如一张800x600x3的图片(其中3是指颜色的三个通道,一般医学图像为单独的1个灰度通道),数值在0-255之间:

而且在现实情况下,相机在拍照过程中也会对物体进行旋转,平移,缩放,增加亮度等操作;不止如此,一些同一类别物体也会有不同的造型,姿势,或者部分被遮挡,我们在进行分类过程中要对这些问题具有很好的鲁棒性:

图片分类器的原型

图像分类器是什么样子的呢,我们要构建一个三维空间,定义一个函数,使用算法将猫的图片输进去,得到猫的标签。但是,普通的算法很难达到,通常我们想到的是构建猫的轮廓,或者某一部分的特点:

但是当给你一个其他的类别,再进行轮廓识别然后再寻找特点会使情况变得过于复杂,这时,机器学习体现了它的能力,我们可以通过训练数据训练一个分类模型,当你把一个新的测试数据带入模型中时,可以得到测试数据最接近的类别:

Machine Learning: Data-Driven Approach\

机器学习:数据驱动的方法

1.收集图像和标签的数据集。

2.使用机器学习训练分类器。

3.对新图像进行分类器的评估。

Example training set

示例训练设置

1.近邻算法分类器

1.记忆所有数据和标签

python 复制代码
def train( images, labels):
#Machine learning机器学习
  return model

2.预测最相似的训练图像的标签

python 复制代码
def predict(model, test_images):
#Use model to predict labels使用模型预测标签
  return test_labels

这里举一个例子:记住所有训练数据与标签,然后当测试数据预测时,计算预测数据与每一张训练数据的每一个像素的差值,然后求和,得到的数值就是两张图片的L1距离(曼哈顿距离),然后得到的那个距离最小的差值,就将测试数据分入那个类别之中,这就是一个简单的近邻算法分类器:

比较图像的距离度量Distance Metric to compare images

L1 距离: <math xmlns="http://www.w3.org/1998/Math/MathML"> d 1 ( I 1 , I 2 ) = ∑ p ∣ I 1 p − I 2 p ∣ d_1(I_1,I_2)=\sum_p|I_1^p-I_2^p| </math>d1(I1,I2)=∑p∣I1p−I2p∣

test image 测试图像 training image训练图像 pixel-wise absolute value differences 像素绝对值差值

但是,根据刚才的例子,可以看出测试时候的速度是非常缓慢的,如何能够提高测试速度呢(这里可以使训练速度相对的慢一些)?

2.K近邻分类器

什么是K近邻分类器呢?上面例子是将测试数据归类为最邻近训练数据的标签,为什么只用最相似的1张图片的标签来作为测试图像的标签呢?这不是很奇怪吗!是的,使用K近邻分类器就能做得更好。它的思想很简单:与其只找最相近的那1个图片的标签,我们找最相似的k个图片的标签,然后让他们针对测试图片进行投票,最后把票数最高的标签作为对测试图片的预测。所以当k=1的时候,K近邻分类器就是近邻分类器。

上图可以看出每个训练数据的图片区域分类情况,其中k=1时找到两个不同分类的中点来分类区域;当k增大时,分类区域由临近的k张训练数据共同决定,从直观感受上就可以看到,更高的k值可以让分类的效果更平滑,使得分类器对于异常值更有抵抗力。其中白色区域为最邻近的几个区域投票数相同,无法准确分类的区域。

除去k值,还有在近邻选择中使用L2距离(欧式距离)进行分类:

K-最近邻:距离度量

L1(曼哈顿)距离= <math xmlns="http://www.w3.org/1998/Math/MathML"> d 1 ( I 1 , I 2 ) = ∑ p ∣ I 1 p − I 2 p ∣ d_1(I_1,I_2)=\sum_p|I_1^p-I_2^p| </math>d1(I1,I2)=∑p∣I1p−I2p∣

L2(欧几里得)距离= <math xmlns="http://www.w3.org/1998/Math/MathML"> d 1 ( I 1 , I 2 ) = ∑ p ( I 1 p − I 2 p ) 2 d_1(I_1,I_2)= \sqrt{\sum_p(I_1^p-I_2^p)^2} </math>d1(I1,I2)=∑p(I1p−I2p)2

k与L1、L2距离选择这两个参数就决定了分类器的泛化能力,那么如何对这两个超参数进行选择呢?需要从我们的数据入手,首先将数据分为训练数据与测试数据:

当整个训练数据被我们用来训练并且k = 1时,整个训练数据的准确率都是100%的,这样没办法看出我们算法的表现能力,所以我们要将训练数据分为训练数据与验证数据,并且只训练训练数据,在验证数据上进行验证,以了解我们训练数据的算法泛化能力:

再进一步,我们可以将训练数据分为x份,使每一份数据都做一次验证数据,这样我们就得到了x个准确率,取其中的平均值,就得到了当k取任意值时的准确率如何,这样再选择准确率最高时的k值,就得到了一个表现最为良好的算法:

所得到的准确率随k的选择变化折线图如下图所示,可以看到当k取7时准确率达到最高,所以这个模型的话,取k=7可以达到效果最好的分类结果:

设置超参数 Setting Hyperparamete

虽然K近邻算法在理论上可行性很高,但是实际问题中一般不会被使用,一是因为它计算的像素之间的差值会因为物体在图像内的平移,遮盖,变色而产生很大的差别,即使还是原来的物体;另一个原因是它的计算复杂度非常之高,当检测的维度升高以后参数的个数呈指数上涨;最后一个也是最重要的原因,通过这个方法进行分类时更多注意的是背景信息(背景信息在图片中一般比物体更多),并不是我们需要的语义信息。

维数灾难 curse of dimensionality

线性分类器

线性分类器就是我们所认识的神经网络,要识别一个物体属于哪一种类别(假设10类),我们需要将输入图片(假设图片为32x32x3的数组,一共3072个数字)通过包含权重参数的线性变换,得到10种类别所得到的分数,让它在它的标签下的类别得到很高的分数,其他类别表现很低的分数,我们所要学习的就是这个线性变换的函数,或者准确说学习w的权重值,一般我们要在学习中加入一个偏置参数b,以让图片在分类时对它属于的标签有更大的偏置:

参数化方法:线性分类器 Parametric Approach: Linear Classifier


以下是一个具体例子:

将像素拉伸成列 Stretch pixels into column

上面的方法将原图的2x2个像素排列成一列,也可以直接使用矩阵相乘方法:

因为猫得到的分数不是很高,所以这并不是一个很好的分类器,需要重新设置w与b;下图是一个将设置权重可视化的图片,可以看出10个类别权重都有各自的特点,比如飞机的权重中蓝色通道分量高于其他分量,使得蓝色通道权重可以取得更高的分数,红色与绿色通道取得较低的分数,更容易找到在天空中的飞机:

从几何观点来看,下图中三条颜色的线分别表示在三类分类中分数为0的位置,但是当向各自的箭头方向延伸时,那么对应类别的分数也会越来越高:

评价分类分数

接下来是针对输出结果的评价指标,看到下图种使用10个分类权重分别对三张图片得到的结果:

三、损失函数与优化

损失函数

说到损失,损失一定要很好的体现出来使用权值而产生结果与最优结果的差值,我们将使用损失函数(Loss Function)(有时也叫代价函数Cost Function或目标函数Objective)来衡量我们对结果的不满意程度。直观地讲,当评分函数输出结果与真实结果之间差异越大,损失函数输出越大,反之越小。针对多个测试数据,损失是整体数据损失的平均值。

损失函数告诉我们当前的分类器

有多好给定一个示例数据集 <math xmlns="http://www.w3.org/1998/Math/MathML"> ( x i , y i ) i = 1 N {(x_i,y_i)}^N_{i=1} </math>(xi,yi)i=1N

其中 <math xmlns="http://www.w3.org/1998/Math/MathML"> x i x_i </math>xi是图像, <math xmlns="http://www.w3.org/1998/Math/MathML"> y i y_i </math>yi是(整数)标签

数据集损失是示例损失的总和:
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> L = 1 N ∑ i L i ( f ( x i , W ) , y i ) L=\frac{1}{N}\sum_iL_i(f(x_i,W),y_i) </math>L=N1i∑Li(f(xi,W),yi)

多类支持向量机损失

多类SVM损失:一种两分类支持向量机的泛化,具体的损失函数如下:
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> L i = ∑ j ≠ y i { 0 i f s y i ⩾ s j + 1 s j − s y i + 1 o t h e r w i s e = ∑ j ≠ y i m a x ( 0 , s j − s y i + 1 ) L_i=\sum_{j \neq y_i} \left\{\begin{matrix}0 \qquad \qquad \qquad if \quad s_{y_i}\geqslant s_j +1 \\s_j-s_{y_i}+1 \qquad otherwise \end{matrix}\right. =\sum_{j \neq y_i}max(0,s_j-s_{y_i}+1) </math>Li=j=yi∑{0ifsyi⩾sj+1sj−syi+1otherwise=j=yi∑max(0,sj−syi+1)

其中 <math xmlns="http://www.w3.org/1998/Math/MathML"> s j s_{j} </math>sj 为非正确类的分数, <math xmlns="http://www.w3.org/1998/Math/MathML"> s y i s_{y_i} </math>syi 为分类正确的分数,这两者的差值再加上偏置参数1的结果与0取大值,最后对所有得分结果取和,就可以得到该图片最后所得损失结果,注意不计算 <math xmlns="http://www.w3.org/1998/Math/MathML"> j = y i j=y_i </math>j=yi ,具体例子如下:

最后得到的损失为平均值:

提出几个问题来巩固一下这个损失函数的知识:

  1. 当车辆的分数改变一些会发生什么?
    答:当某一类别的分数升高时,在最终结果上只会改变相应的很小一部分。
  2. 当 <math xmlns="http://www.w3.org/1998/Math/MathML"> j = y i j=y_i </math>j=yi也被记入损失时,结果会如何?
    答:结果只会增加偏置参数的值(最后平均后),一般在写程序时会直接将这一项取0,为不影响损失函数判断。
  3. 在每次结果使用平均代替相加会有什么变化?
    答:最后的损失函数表示的是此分类器的W权重设置优劣,当选择平均时,虽然最后的损失值变小了,但是这也只是在原来的结果上加了一个类别个数的倒数的系数(此例为1/3),并不会对最终的结果产生影响,我们最后想要得到的其实是使W/loss最小化。
  4. 当我们使用平方时有什么影响?即 <math xmlns="http://www.w3.org/1998/Math/MathML"> L i = ∑ j ≠ y i max ⁡ ( 0 , s j − s y i + 1 ) 2 L_i = \sum_{{j} \ne {y_i}}\max(0,s_j - s_{y_i} + 1)^2 </math>Li=∑j=yimax(0,sj−syi+1)2(公式内为j不等于 <math xmlns="http://www.w3.org/1998/Math/MathML"> y i y_i </math>yi 答:说到这里必须提一下SVM损失: <math xmlns="http://www.w3.org/1998/Math/MathML"> m a x ( 0 , − ) max(0,−) </math>max(0,−)函数,它常被称为折叶损失(hinge loss)。 有时候会听到人们使用平方折叶SVM损失(即L2-SVM),它使用的是 <math xmlns="http://www.w3.org/1998/Math/MathML"> m a x ( 0 , − ) 2 max(0,-)^2 </math>max(0,−)2,将更强烈(平方地而不是线性地)地惩罚过界的边界值。不使用平方是更标准的版本,但是在某些数据集中,平方折叶损失会工作得更好。可以通过交叉验证来决定到底使用哪个。
  5. 当在初始化权重矩阵时,w的数值都是很小的所得到的分数也是很小,约等于0,这样得到的损失是多少?
    答:是分类数减去1,因为除了正确分类本身,其他每一次max的结果都为1。
python 复制代码
#代码实现方法
def L_i_vectorized(x, y, W):
  delta = 1.0
  scores = W.dot(x)
  margins = np.maximum(0, scores - scores[y] + delta)
  margins[y] = 0                           #将j = yi的损失设为0
  loss_i = np.sum(margins)
  return loss_i

正则化

当我发现一个权重矩阵,使得损失降为0,这个权重矩阵是唯一的吗?答案是并不是唯一的,因为可以从SVM损失函数中看出,当分类正确的数值大于其他数值时,损失为0,可是当W取λW(λ>1)时,会使各个分数都乘以λ,这样最终结果损失都为0,可是这样的λ W会使其他分类错误的的损失也相应的扩大了λ倍:

这显然不是我们想要的,因为不同的W会使其他分类错误的误差成比例增大,那么我们可不可以对W也加一些偏好来消除其他分类所带来的模糊性?这个方法就是向损失函数添加一个正则化惩罚R ( w ) ,正则化惩罚有很多种方式,常见的有L1正则化、L2正则化、Dropout、BatchNomalization等等:

简单实例:

L2正则化: <math xmlns="http://www.w3.org/1998/Math/MathML"> R ( w ) = ∑ k ∑ l W k , l 2 R(w)=\sum_k\sum_lW^2_{k,l} </math>R(w)=∑k∑lWk,l2

L1正则化: <math xmlns="http://www.w3.org/1998/Math/MathML"> R ( w ) = ∑ k ∑ l ∣ W k , l ∣ R(w)=\sum_k\sum_l|W_{k,l}| </math>R(w)=∑k∑l∣Wk,l∣

弹性网(L1+L2): <math xmlns="http://www.w3.org/1998/Math/MathML"> R ( w ) = ∑ k ∑ l β W k , l 2 + ∣ W k , l ∣ R(w)=\sum_k\sum_l\beta W^2_{k,l}+|W_{k,l}| </math>R(w)=∑k∑lβWk,l2+∣Wk,l∣

更复杂:

丢弃

批量规范化

随机深度、分数池等

这样我们的损失函数就由两部分组成:数据损失(data loss),即所有样例的的平均损失 <math xmlns="http://www.w3.org/1998/Math/MathML"> L i L_i </math>Li,以及正则化损失(regularization loss)。完整公式如下所示: 也可以将其展开:
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> L = 1 N ∑ i ∑ j ≠ y i [ m a x ( 0 , f ( x i ; W ) j − f ( x i ; W ) y i + Δ ) ] + λ ∑ k ∑ l W k , l 2 L=\frac{1}{N}\sum_i\sum_{j \neq y_i}[max(0,f(x_i;W)j-f(x_i;W){y_i}+\Delta )]+\lambda\sum_k\sum_lW_{k,l}^2 </math>L=N1i∑j=yi∑[max(0,f(xi;W)j−f(xi;W)yi+Δ)]+λk∑l∑Wk,l2

正则化是为了权衡训练损失和用于测试集的泛化损失,最常用的正则化惩罚是L 2 L2L2范式,L 2 L2L2范式通过对所有参数进行逐元素的平方加和惩罚来抑制大数值的权重,举个例子,假设输入向量 x=[1,1,1,1],两个权重向量 <math xmlns="http://www.w3.org/1998/Math/MathML"> w 1 = [ 1 , 0 , 0 , 0 ] w_1=[1,0,0,0] </math>w1=[1,0,0,0], <math xmlns="http://www.w3.org/1998/Math/MathML"> w 2 = [ 0.25 , 0.25 , 0.25 , 0.25 ] w_2=[0.25,0.25,0.25,0.25] </math>w2=[0.25,0.25,0.25,0.25]。那么 <math xmlns="http://www.w3.org/1998/Math/MathML"> w 1 T x = w 2 T = 1 w^T_1x=w^T_2=1 </math>w1Tx=w2T=1,两个权重向量都得到同样的内积,但是 <math xmlns="http://www.w3.org/1998/Math/MathML"> w 1 w_1 </math>w1 的 L2惩罚是1.0,而 <math xmlns="http://www.w3.org/1998/Math/MathML"> w 2 4 的 L 2 惩罚是 0.25 。因此,根据 L 2 惩罚来看, w_24 的L2 惩罚是0.25。因此,根据 L2惩罚来看, </math>w24的L2惩罚是0.25。因此,根据L2惩罚来看, w_2 <math xmlns="http://www.w3.org/1998/Math/MathML"> 更好,因为它的正则化损失更小。从直观上来看,这是因为 更好,因为它的正则化损失更小。从直观上来看,这是因为 </math>更好,因为它的正则化损失更小。从直观上来看,这是因为w_2$ 的权重值更小且更分散。既然L 2 L2L2惩罚倾向于更小更分散的权重向量,这就会鼓励分类器最终将所有维度上的特征都用起来,而不是强烈依赖其中少数几个维度,这样可以防止过拟合。

Softmax分类器

Softmax分类器又被称为二元逻辑回归分类器(Multinomial Logistic Regression),与SVM分类器相比,Softmax的输出(归一化的分类概率)更加直观,并且从概率上可以解释,在Softmax分类器中,函数映射 <math xmlns="http://www.w3.org/1998/Math/MathML"> f ( x i ; W ) = W x i f(x_i;W)=Wx_i </math>f(xi;W)=Wxi 保持不变,但将这些评分值视为每个分类的未归一化的对数概率,并且将折叶损失(hinge loss)替换为交叉熵损失(cross-entropy loss)。公式如下:
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> L i = − l o g P ( Y = y i ∣ X = x i ) L_i=-logP(Y=y_i|X=x_i) </math>Li=−logP(Y=yi∣X=xi)
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> P ( Y = k ∣ X = x i ) = e s k ∑ j e s k P(Y=k|X=x_i)=\frac{e^sk}{\sum_je^sk} </math>P(Y=k∣X=xi)=∑jeskesk

这里举一个例子便于理解:

小结

损失函数作为衡量权重参数的效果函数,需要根据情况来选择,本节主要讨论了两个损失函数:

  1. 多分类SVM损失:
    <math xmlns="http://www.w3.org/1998/Math/MathML"> L i = ∑ j ≠ y i m a x ( 0 , s j − s y i + 1 ) L_i=\sum_{j \neq y_i}max(0,s_j-s_{y_i}+1) </math>Li=∑j=yimax(0,sj−syi+1)

  2. Softmax分类器:\

<math xmlns="http://www.w3.org/1998/Math/MathML"> L i = − l o g ( e s k ∑ j e s k ) L_i=-log(\frac{e^sk}{\sum_je^sk}) </math>Li=−log(∑jeskesk)

两者的比较可以看出Softmax更加关注全局分数。

最优化操作是为了寻找最优权重使损失函数最小化的过程,从随机搜索到随机梯度下降,再到后来的Momentum、NAG、Adagrad、Adadelta、RMSprop、Adam越来越多的梯度下降算法应运而生,以后有机会要好好讨论一下这些梯度下降的优缺点(目前别人总结的都很全面了hh)

相关推荐
徐行tag2 小时前
深度学习基础——神经网络优化算法
深度学习·神经网络·算法
灬0灬灬0灬5 小时前
pytorch训练可视化工具---TensorBoard
人工智能·pytorch·深度学习
平和男人杨争争6 小时前
山东大学计算机图形学期末复习15——CG15
人工智能·算法·计算机视觉·图形渲染
lucky_lyovo6 小时前
OpenCV图像边缘检测
人工智能·opencv·计算机视觉
恩喜玛生物6 小时前
深度学习实战 04:卷积神经网络之 VGG16 复现三(训练)
人工智能·深度学习·cnn
那雨倾城7 小时前
使用 OpenCV 实现万花筒效果
图像处理·人工智能·opencv·计算机视觉
MorleyOlsen8 小时前
【数字图像处理】半开卷复习提纲
图像处理·计算机视觉
羑悻的小杀马特8 小时前
从神经架构到万物自动化的 AI 革命:解码深度学习驱动的智能自动化新范式
深度学习·自动化
ghie90909 小时前
matlab编写的BM3D图像去噪方法
计算机视觉·matlab·3d
liuyang-neu9 小时前
目标检测DN-DETR(2022)详细解读
人工智能·深度学习·目标检测