【计算机视觉之二】人工神经网络

来源:互联网 发布:youtube 批量下载软件 编辑:程序博客网 时间:2024/05/16 17:33

目录
1. 线性分类器
1.1 线性分类器分类原理
1.2学习的误差—损失函数
2. 神经网络初步
2.1 什么是神经网络?
2.2 非线性可分问题
2.3 激活函数
3. 算法初步
3.1 BP算法
3.2 SGD(随机梯度下降)
3.3 反向传播详细栗子与运算过程
4. 练习案例—感知器案例+寒老师写的人工神经网络

1.线性分类器
1.1 分类原理

在分类问题中,提供了很多算法,比如LR,决策树,SVM,其中有一类称为线性分类器。比如,你要识别一张图片中的是猫,还是狗,还是图片中两者都有:

这个猫还可爱呀。

一般会把这张图片转变成[32x32x3]的向量矩阵,3为颜色通道,每一个维度的范围在0-255左右,然后把它拉成3072X1 的长列向量,用来表征这张图片中信息,用X表示,通过映射函数

f(X,W)=WX+b
,其中w为权重参数,代表每个维度的重要性,最后会输出这张图片属于每个类别的概率。

小栗子:
这里写图片描述
我们假设一张图片仅有图中xi的值,w是权重矩阵。
w中每一行代表了不同类别的权重参数,最后得到每个类别的得分。比如:

=96.8=0.2560.5231+0.124+22+1.1

另外的理解:W的每一行,相当与其中一个类别的模版;得出每类的得分,相当于像素点与模版的匹配;匹配的方式为内积。

1.2学习的误差—损失函数

损失函数相当于一个衡量标准答案和模型学习的答案之间的差距,我们希望不断的调整W,使得模型学习的答案与标准的答案是一致的。

小栗子:
hinge loss/线性SVM的损失函数
假设上面那张猫的图片数据为xi,其他还有狗和船的,在W下有一个得分向量

f(x,W)=[13,7,11]
,分别代表猫,船,狗的得分,但正确答案是猫,也就是第一个,hinge loss希望正确答案与错误答案之间的得分差距在某一阀值范围内,假设为10,就可以得到
Li=max(0,713+10)+max(0,1113+10)=0+7=7
因为猫和狗的得分之间的差距不满足阀值,就会增加一个损失,而猫和船之间的差距符合阀值10,所以船这个分类就不会带来任何损失。
用公式表示:
Li=max(0,+)

代码实现:

def L_i(x, y, W):  """  计算svm中一个样本的多分类问题中的损失函数   -  x是代表一张图片的一列向量(eg:3073 X 1 in CIFAR-10)  同时在第3073的位置上加上偏执值的维度  - y 是一个整型的类别标签 (e.g. between 0 and 9 in CIFAR-10)  - W 是权值矩阵 (e.g. 10 x 3073 in CIFAR-10)  """  delta = 1.0 # 相当于一个阀值  scores = W.dot(x) # 为每个类别打分  correct_class_score = scores[y]  D = W.shape[0] # 标签的类别数量, e.g. 10  loss_i = 0.0  for j in xrange(D): # 迭代所有的错误类别    if j == y:      # 跳过真正的类别标签(因为对的是没有损失的)      continue    # 计算所有样本的损失    loss_i += max(0, scores[j] - correct_class_score + delta)  return loss_idef L_i_vectorized(x, y, W):  """  A faster half-vectorized implementation. half-vectorized  refers to the fact that for a single example the implementation contains  no for loops, but there is still one loop over the examples (outside this function)  """  delta = 1.0  scores = W.dot(x)  # compute the margins for all classes in one vector operation  margins = np.maximum(0, scores - scores[y] + delta)  # on y-th position scores[y] - scores[y] canceled and gave delta. We want  # to ignore the y-th position and only consider margin on max wrong class  margins[y] = 0  loss_i = np.sum(margins)  return loss_idef L(X, y, W):  """  fully-vectorized implementation :  - X holds all the training examples as columns (e.g. 3073 x 50,000 in CIFAR-10)  - y is array of integers specifying correct class (e.g. 50,000-D array)  - W are weights (e.g. 10 x 3073)  """  # evaluate loss over all examples in X without using any for loops  # left as exercise to reader in the assignment

交叉熵损失(softmax分类器)
交叉熵损失函数会把得分向量转化为概率向量,转化方法如下:

p()=e13e13+e7+e11
,求船和狗的概率一样,然后把他们组合成概率向量
P=P()Pp
然后和
R=(1,0,0)
这个标准答案比较。得到
RlogP

工程小技巧:

p()=Ce13Ce13+Ce7+Ce11=e13+logCe13+logC+e7+logC+e11+logC

C的选取一般可以选取分数最高的那个

f = np.array([123, 456, 789]) # example with 3 classes and each having large scoresp = np.exp(f) / np.sum(np.exp(f)) # Bad: Numeric problem, potential blowup# instead: first shift the values of f so that the highest number is 0:f -= np.max(f) # f becomes [-666, -333, 0]p = np.exp(f) / np.sum(np.exp(f)) # safe to do, gives the correct answer

本质:评估两个概率向量之间的距离
更加详细的推导和动画演示可以参考:Michael Nielsen大牛的书

2.神经网络初步

2.1 什么是神经网络?

图为一个全连接的神经网络结构,数据在input layer中数据,通过一系列的隐藏层处理,然后在output layer中输出。

到底什么才是神经网络,我们可以拿一个简单,但本质性的东西出来看一下。

我们把右边的东西称之为感知器,x1,x2代表两个维度的数据,然后处理之后,通过一个S型函数,把

z=w1x1+w2x2+b
得到的值代入函数,z的值越大,g(z)就越接近1。表征概率。

2.2 非线性可分问题
我们已经认识的LR处理的是线性可分的问题,但非线性问题应该怎么办呢?

如图所示,找不到一条直线,把原点和x点完全分开,但是可以用两条直线,就可以把他们完全分开了。这个操作,正是神经网络可以做的。

逻辑与

如图所示,神经网络可以在每个神经节点处训练一条边界线,然后通过最后的激活函数把这两条线合并在一起,让他们一起在分类任务中发挥作用。

逻辑或

用(-10,20,20)这组参数来计算,由右下表可以发现,只要由1,结果就会为1。以

x1=1,x2=0
为例,用这组参数计算,可以发现:
10+20+0=10
结果为正数,分类的时候也会分为正类。
即只要有1,就能分为正类,完成了逻辑或的操作。

神经网络对他们进行组合,最后可以得到:

利用and的操作可以取得很多分割的空间区域,然后用or的操作,可以把这些分割的区域中,颜色一样的区域作为同一类。

非常完美得解决了非线性可分问题。

2.3 激活函数
如图

为两种激活函数图,这种激活函数会分布在我们网络中的各个节点。
可以从两个角度来理解这样的激活函数:
A. 信号传递
假如现在有一阵风过来,你正在打电话,如果是微风,你会停止打电话这个动作吗?假如是龙卷风+雷阵雨,你会停止打电话吗?
用在这里,可以把激活函数理解为一种过滤网,它能把一些像微风这个的噪声数据去除掉,而让龙卷风这样的数据通过网络,让人最后作出合理的行动。

B.非线性变换
如果我们不在中间加一些非线性的变换,那如果是两层的神经元:

W2(W1X+b1)+b2=W2W1X+(W2b1+b2)=WX+b
可以发现,最终仍然是一个线性变换,只是参数的表示不太一样,但这样的变换用一个函数也可以变换,所以激活函数就是为了把线性变换转为非线性变换。

3.算法初步

3.1 BP算法
BP算法的本质有两个方面:正向传播求损失,反向传播回传误差。
举个小栗子:
假如你在做高考模拟题的时候发现有一道数列的题不会做,然后仔细看一下到底是哪些知识点没掌握呢?这时候就是损失的计算。计算完之后,考完了,再回去看一下到底是哪里不会,然后再学习一下,争取在下一次考试的时候,再遇到类似这道题可以做好。回去复习就类似回传误差。
整体的过程就是下面的图示了:
这里写图片描述

好吧,估计这个小栗子不怎么好吃,再来一个好吃一点的栗子吧。

假如这是一个回归的问题,最后预测的结果是一个连续值,分别是

[O1,O2,O3,,Ol]
而真正的结果是
[d1,d2,d3,,dl]
,最直接计算他们之间的差距的方式就是用L2损失函数:
E=12(dO)2=12k=1l(dkOk)2
误差展开至隐层:
E=12k=1l(dkf(netk))=12k=1l(dkf(j=0m(wjkyj)))2=12k=1l()2
其实反向传播就这么个原理,一直传到输入层。
本想用白话来说的,但还是数学表达式更形象。

3.2 SGD(随机梯度下降)
这里写图片描述
这个方法主要是为了优化损失函数,假设损失函数是凸函数(也就是极值点就是最值点的函数)。随机梯度下降主要把握三个方面的内容:
当前所在的位置:也就是参数的取值与损失的表征。
方向:因为每次下山,可爱的孩子为了不迷路,都要看一下四周,那边是最快下山的,所以方向很重要。在数学上用梯度来表征方向。
步长:假设孩子是一个大个,如果步长太大了,有可能会就走几步,就走过最低点了,导致离最低点的比较远。也可能是孩子腿太短,哎呀,搞得走了很久才走到山脚。用计算机语言来说,就是步长太小,时间复杂度太高;步长太大,找不到山底究竟在哪里。这里表示学习率。

SGD:每个样本求损失
GD:所有样本求损失
minibatch:在一批数据上求损失

3.3 反向传播详细栗子与运算过程
为了简单起见,我们用个简单的网络结果:分别有两个输入节点,两个隐藏节点,两个输出节点,而且还带了偏执值,结构如图:

为了有一些数值运算,我们线初始化我们的输入,权重参数值如下:

反向传播的目标是优化权重参数,使得学习出一个最好的映射函数把输入映射到输出。
在本例中,我们给定了输入0.05,0.10,希望可以得到输出0.01,0.99。使用sigmoid函数作为激活函数,来算一下每个节点的值是怎么变化的。

第一步-计算节点输出值

计算隐层:

neth1=0.150.05+0.200.10+0.35=0.3775
然后用激活函数激活:
outh1=11+e0.3775=0.5932
用同样的方法计算可得
outh2=0.5968

计算输出层:
把h1的输出作为o1的输入,再用同样的方法:

neto1=w5outh1+w6outh2+b21=0.400.5932+0.450.5968+0.60=1.1059
再用sigmoid函数激活一下:
outo1=11+e1.1059=0.7513
用同样的方法计算可得:
outo2=0.7729

第二步-计算误差

得到输出之后,学的到底怎么样,还得和标准答案对比一下,因此计算一下它与标准答案的差距:

Etotal=12()2

想学一下更高深的:这本书讲神经网络中的数学还是很不错的

我们的标准答案分别是:0.01,0.99,可以计算一下误差:

Eo1=12(0.10.7513)2=0.2748
同理可得:
E02=12(0.990.7729)=0.0235
可得总的误差(损失)是:
Etotal=Eo1+Eo2=0.2748+0.0235=0.2983

第三步-反向传播

我们的目标是调整权重参数,使得输出值接近我们的标准答案,因此最小化损失函数(误差)。
先考虑w5,它对应的输出直接就是outo1,我们希望这个误差(损失)中,w5到底影响了多少,因此根据链式法则:

Etotalw5=Etotalouto1outo1neto1neto1w5
我们做的就是如下图所示:
这里写图片描述
我们需要确定这条链中的每一个部分:
先看
Etotal=12(o1outo1)2+12(o2outo2)
Etotalouto1=212(0.01outo2)(1)+0=(0.010.7513)=0.7413

然后再来算第二个:
outo1=11+eneto1
求偏导:
outo1neto1=outo1(1outo1)=0.7513(10.7513)=0.1868

再算最后一个:
neto1=w5outh1+w5outh2+b21
求偏导:
neto1w5=outh1=0.5932

终于得到总的了:
Etotalw5=Etotalouto1outo1neto1neto1w5
代入数值计算:
Etotalw5=0.74130.18680.5932=0.0821
学习率设置为0.5,可得
w+5=w5θEtotalw5=0.40.50.0821=0.0358

这样就能更新w5了。跟它同一层上的其他参数用同样的方法可以得到:
w+6=0.4086,w+7=0.5113,w+8=0.5613

计算隐层的时候方法也类似:

需要注意的是计算隐层的时候,误差是由两个结果的,因为隐层对两个输出均有影响。
这个栗子更加详细的推导可以查看:反向传播的详细栗子(英文的)

反向传播实例:python实现反向传播

反向传播可视化:点击start,看一下怎么传播的

4.练习案例
有一位大牛手写的,感觉挺不错
感知器实现

手写人工神经网络
参考:
七月深度学习课
斯坦福大学cs231n
反向传播栗子

原创粉丝点击