├── LICENSE ├── README.md ├── CS231n 3.1:线性分类笔记(上).md ├── CS231n 2.2:图像分类笔记(下).md ├── CS231n 6.1.b:神经网络笔记1(下).md ├── CS231n 0 官方笔记授权翻译总集篇发布.md ├── CS231n 3.3:线性分类笔记(下).md ├── CS231n 4.1:最优化笔记(上).md ├── CS231n 4.2:最优化笔记(下).md ├── CS231n 6.1.a:神经网络笔记1(上).md ├── CS231n 6.3.a 神经网络笔记3(上).md ├── CS231n 3.2:线性分类笔记(中).md ├── CS231n 6.3.b 神经网络笔记3(下).md ├── CS231n 5:反向传播笔记.md ├── CS231n 2.1:图像分类笔记(上).md ├── CS231n 6.2:神经网络笔记 2.md └── CS231n 7 卷积神经网络笔记.md /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Eric Wang 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CS231n-Note-Translation_CN 2 | 3 | ## 入门课程选择 4 | 5 | 开始学习深度学习,迎接人工智能浪潮的到来,希望为时不晚。 6 | 7 | 入门课程查询了一下,比较推荐的有三门课程 8 | - 1. Udacity Machine Learning Nanodegree 9 | - 2. Stanford CS231n class, 李飞飞的课程 10 | - 3. Andrew Ng的机器学习 (Machine Learning - Stanford University | Coursera) 11 | 12 | 当然远远不止以上这些,综合考虑了一下,Udacity的课程需要付费,虽然大多数资源都是免费的,但不是特别考虑。 13 | 吴恩达的课程,大家都推荐,但是想要专门了解一下图像识别相关的知识,所以还是选择了李飞飞的CS231n。 14 | 15 | 具体这里有讲解 [人工智能自学心得 - 知乎专栏](https://zhuanlan.zhihu.com/p/25016075) 16 | 17 | 知乎上面的一个好问题 [普通程序员如何向人工智能靠拢? - 知乎](https://www.zhihu.com/question/51039416) 18 | 19 | ## CS231n相关资源 20 | 21 | 课程官网:[CS231n: Convolutional Neural Networks for Visual Recognition](http://cs231n.stanford.edu/) 22 | 23 | Github:https://github.com/cs231n/cs231n.github.io | http://cs231n.github.io/ 24 | 25 | 教学安排及大纲:[Schedule and Syllabus](http://vision.stanford.edu/teaching/cs231n/syllabus.html) 26 | 课程视频:Youtube上查看Andrej Karpathy创建的播放列表,或者网易云课堂 27 | 28 | 课程pdf及视频下载:[百度网盘下载](https://pan.baidu.com/s/1eRHH4L8),密码是4efx 29 | 30 | 31 | CS231课程笔记翻译 https://zhuanlan.zhihu.com/intelligentunit 32 | 33 | 这里是一个总结:http://www.jianshu.com/p/182baeb82c71, 主要参考的这里 34 | 35 | 搬运过来,自己学习,内容属于原作者 36 | 37 | 学习一点,搬运一点 38 | 39 | 40 | -------------------------------------------------------------------------------- /CS231n 3.1:线性分类笔记(上).md: -------------------------------------------------------------------------------- 1 | 2 | # CS231n课程笔记翻译:线性分类笔记(上) - 知乎专栏 3 | 4 | 5 | ![CS231n课程笔记翻译:线性分类笔记(上)][4] 6 | 7 | [杜客][6] [Source](https://zhuanlan.zhihu.com/p/20918580?refer=intelligentunit "Permalink to CS231n课程笔记翻译:线性分类笔记(上) - 知乎专栏") 8 | 9 | **译者注**:本文[智能单元][2]首发,译自斯坦福CS231n课程笔记[Linear Classification Note__][7],课程教师[Andrej Karpathy__][8]授权翻译。本篇教程由[杜客][6]翻译完成,[巩子嘉][9]和[堃堃][10]进行校对修改。译文含公式和代码,建议PC端阅读。 10 | 11 | ## 原文如下 12 | 13 | 内容列表: 14 | 15 | * 线性分类器简介 16 | * 线性评分函数 17 | * 阐明线性分类器 _**译者注:上篇翻译截止处**_ 18 | * 损失函数 19 | * 多类SVM 20 | * Softmax分类器 21 | * SVM和Softmax的比较 22 | * 基于Web的可交互线性分类器原型 23 | * 小结 24 | 25 | ## 线性分类 26 | 27 | 上一篇笔记介绍了图像分类问题。图像分类的任务,就是从已有的固定分类标签集合中选择一个并分配给一张图像。我们还介绍了k-Nearest Neighbor (k-NN)分类器,该分类器的基本思想是通过将测试图像与训练集带标签的图像进行比较,来给测试图像打上分类标签。k-Nearest Neighbor分类器存在以下不足: 28 | 29 | 30 | 31 | * 分类器必须_记住_所有训练数据并将其存储起来,以便于未来测试数据用于比较。这在存储空间上是低效的,数据集的大小很容易就以GB计。 32 | * 对一个测试图像进行分类需要和所有训练图像作比较,算法计算资源耗费高。 33 | 34 | **概述**:我们将要实现一种更强大的方法来解决图像分类问题,该方法可以自然地延伸到神经网络和卷积神经网络上。这种方法主要有两部分组成:一个是**评分函数(score function)**,它是原始图像数据到类别分值的映射。另一个是**损失函数(loss function)**,它是用来量化预测分类标签的得分与真实标签之间一致性的。该方法可转化为一个最优化问题,在最优化过程中,将通过更新评分函数的参数来最小化损失函数值。 35 | 36 | ## 从图像到标签分值的参数化映射 37 | 38 | 该方法的第一部分就是定义一个评分函数,这个函数将图像的像素值映射为各个分类类别的得分,得分高低代表图像属于该类别的可能性高低。下面会利用一个具体例子来展示该方法。现在假设有一个包含很多图像的训练集![x_iin R^D][11],每个图像都有一个对应的分类标签![y_i][12]。这里![i=1,2...N][13]并且![y_iin 1...K][14]。这就是说,我们有**N**个图像样例,每个图像的维度是**D**,共有**K**种不同的分类。 39 | 40 | 举例来说,在CIFAR-10中,我们有一个**N**=50000的训练集,每个图像有**D**=32x32x3=3072个像素,而**K**=10,这是因为图片被分为10个不同的类别(狗,猫,汽车等)。我们现在定义评分函数为:![f:R^Dto R^K][15],该函数是原始图像像素到分类分值的映射。 41 | 42 | **线性分类器**:在本模型中,我们从最简单的概率函数开始,一个线性映射: 43 | 44 | ![displaystyle f\(x_i,W,b\)=Wx_i+b][16] 45 | 46 | 在上面的公式中,假设每个图像数据都被拉长为一个长度为D的列向量,大小为[D x 1]。其中大小为[K x D]的矩阵**W**和大小为[K x 1]列向量**b**为该函数的**参数(****parameters****)**。还是以CIFAR-10为例,![x_i][17]就包含了第i个图像的所有像素信息,这些信息被拉成为一个[3072 x 1]的列向量,**W**大小为[10x3072],**b**的大小为[10x1]。因此,3072个数字(原始像素数值)输入函数,函数输出10个数字(不同分类得到的分值)。参数**W**被称为**权重(weights)**。**b**被称为**偏差向量(bias vector)**,这是因为它影响输出数值,但是并不和原始数据![x_i][17]产生关联。在实际情况中,人们常常混用**权重**和**参数**这两个术语。 47 | 48 | 需要注意的几点: 49 | 50 | * 首先,一个单独的矩阵乘法![Wx_i][18]就高效地并行评估10个不同的分类器(每个分类器针对一个分类),其中每个类的分类器就是W的一个行向量。 51 | * 注意我们认为输入数据![\(x_i,y_i\)][19]是给定且不可改变的,但参数**W**和**b**是可控制改变的。我们的目标就是通过设置这些参数,使得计算出来的分类分值情况和训练集中图像数据的真实类别标签相符。在接下来的课程中,我们将详细介绍如何做到这一点,但是目前只需要直观地让正确分类的分值比错误分类的分值高即可。 52 | * 该方法的一个优势是训练数据是用来学习到参数**W**和**b**的,一旦训练完成,训练数据就可以丢弃,留下学习到的参数即可。这是因为一个测试图像可以简单地输入函数,并基于计算出的分类分值来进行分类。 53 | * 最后,注意只需要做一个矩阵乘法和一个矩阵加法就能对一个测试数据分类,这比k-NN中将测试图像和所有训练数据做比较的方法快多了。 54 | 55 | > _预告:卷积神经网络映射图像像素值到分类分值的方法和上面一样,但是映射**(f)**就要复杂多了,其包含的参数也更多。_ 56 | 57 | ## 理解线性分类器 58 | 59 | 线性分类器计算图像中3个颜色通道中所有像素的值与权重的矩阵乘,从而得到分类分值。根据我们对权重设置的值,对于图像中的某些位置的某些颜色,函数表现出喜好或者厌恶(根据每个权重的符号而定)。举个例子,可以想象"船"分类就是被大量的蓝色所包围(对应的就是水)。那么"船"分类器在蓝色通道上的权重就有很多的正权重(它们的出现提高了"船"分类的分值),而在绿色和红色通道上的权重为负的就比较多(它们的出现降低了"船"分类的分值)。 60 | 61 | ———————————————————————————————————————— 62 | 63 | ![][20]一个将图像映射到分类分值的例子。为了便于可视化,假设图像只有4个像素(都是黑白像素,这里不考虑RGB通道),有3个分类(红色代表猫,绿色代表狗,蓝色代表船,注意,这里的红、绿和蓝3种颜色仅代表分类,和RGB通道没有关系)。首先将图像像素拉伸为一个列向量,与W进行矩阵乘,然后得到各个分类的分值。需要注意的是,这个W一点也不好:猫分类的分值非常低。从上图来看,算法倒是觉得这个图像是一只狗。 64 | 65 | ———————————————————————————————————————— 66 | 67 | **将图像看做高维度的点**:既然图像被伸展成为了一个高维度的列向量,那么我们可以把图像看做这个高维度空间中的一个点(即每张图像是3072维空间中的一个点)。整个数据集就是一个点的集合,每个点都带有1个分类标签。 68 | 69 | 70 | 71 | 既然定义每个分类类别的分值是权重和图像的矩阵乘,那么每个分类类别的分数就是这个空间中的一个线性函数的函数值。我们没办法可视化3072维空间中的线性函数,但假设把这些维度挤压到二维,那么就可以看看这些分类器在做什么了: 72 | 73 | —————————————————————————————————————————— 74 | 75 | ![][21]图像空间的示意图。其中每个图像是一个点,有3个分类器。以红色的汽车分类器为例,红线表示空间中汽车分类分数为0的点的集合,红色的箭头表示分值上升的方向。所有红线右边的点的分数值均为正,且线性升高。红线左边的点分值为负,且线性降低。 76 | 77 | ————————————————————————————————————————— 78 | 79 | 从上面可以看到,**W**的每一行都是一个分类类别的分类器。对于这些数字的几何解释是:如果改变其中一行的数字,会看见分类器在空间中对应的直线开始向着不同方向旋转。而偏差**b**,则允许分类器对应的直线平移。需要注意的是,如果没有偏差,无论权重如何,在![x_i=0][22]时分类分值始终为0。这样所有分类器的线都不得不穿过原点。 80 | 81 | **将线性分类器看做模板匹配**:关于权重**W**的另一个解释是**它**的每一行对应着一个分类的模板(有时候也叫作_原型_)。一张图像对应不同分类的得分,是通过使用内积(也叫_点积_)来比较图像和模板,然后找到和哪个模板最相似。从这个角度来看,线性分类器就是在利用学习到的模板,针对图像做模板匹配。从另一个角度来看,可以认为还是在高效地使用k-NN,不同的是我们没有使用所有的训练集的图像来比较,而是每个类别只用了一张图片(这张图片是我们学习到的,而不是训练集中的某一张),而且我们会使用(负)内积来计算向量间的距离,而不是使用L1或者L2距离。 82 | 83 | ———————————————————————————————————————— 84 | 85 | ![][23]将课程进度快进一点。这里展示的是以CIFAR-10为训练集,学习结束后的权重的例子。注意,船的模板如期望的那样有很多蓝色像素。如果图像是一艘船行驶在大海上,那么这个模板利用内积计算图像将给出很高的分数。 86 | 87 | ———————————————————————————————————————— 88 | 89 | 可以看到马的模板看起来似乎是两个头的马,这是因为训练集中的马的图像中马头朝向各有左右造成的。线性分类器将这两种情况融合到一起了。类似的,汽车的模板看起来也是将几个不同的模型融合到了一个模板中,并以此来分辨不同方向不同颜色的汽车。这个模板上的车是红色的,这是因为CIFAR-10中训练集的车大多是红色的。线性分类器对于不同颜色的车的分类能力是很弱的,但是后面可以看到神经网络是可以完成这一任务的。神经网络可以在它的隐藏层中实现中间神经元来探测不同种类的车(比如绿色车头向左,蓝色车头向前等)。而下一层的神经元通过计算不同的汽车探测器的权重和,将这些合并为一个更精确的汽车分类分值。 90 | 91 | **偏差和权重的****合并****技巧**:在进一步学习前,要提一下这个经常使用的技巧。它能够将我们常用的参数![W][24]和![b][25]合二为一。回忆一下,分类评分函数定义为: 92 | 93 | ![displaystyle f\(x_i,W,b\)=Wx_i+b][16] 94 | 95 | 分开处理这两个参数(权重参数![W][24]和偏差参数![b][25])有点笨拙,一般常用的方法是把两个参数放到同一个矩阵中,同时![x_i][17]向量就要增加一个维度,这个维度的数值是常量1,这就是默认的_偏差维度_。这样新的公式就简化成下面这样: 96 | 97 | ![displaystyle f\(x_i,W\)=Wx_i][26] 98 | 99 | 还是以CIFAR-10为例,那么![x_i][17]的大小就变成[**3073x1]**,而不是[3072x1]了,多出了包含常量1的1个维度)。W大小就是[**10x3073]**了。![W][24]中多出来的这一列对应的就是偏差值![b][25],具体见下图: 100 | 101 | ———————————————————————————————————————— 102 | ![][27]偏差技巧的示意图。左边是先做矩阵乘法然后做加法,右边是将所有输入向量的维度增加1个含常量1的维度,并且在权重矩阵中增加一个偏差列,最后做一个矩阵乘法即可。左右是等价的。通过右边这样做,我们就只需要学习一个权重矩阵,而不用去学习两个分别装着权重和偏差的矩阵了。 103 | 104 | ————————————————————————————————————————— 105 | 106 | **图像数据预处理**:在上面的例子中,所有图像都是使用的原始像素值(从0到255)。在机器学习中,对于输入的特征做归一化(normalization)处理是常见的套路。而在图像分类的例子中,图像上的每个像素可以看做一个特征。在实践中,对每个特征减去平均值来**中心化**数据是非常重要的。在这些图片的例子中,该步骤意味着根据训练集中所有的图像计算出一个平均图像值,然后每个图像都减去这个平均值,这样图像的像素值就大约分布在[-127, 127]之间了。下一个常见步骤是,让所有数值分布的区间变为[-1, 1]。**零均值的中心化**是很重要的,等我们理解了梯度下降后再来详细解释。 107 | 108 | **线性分类笔记(上)完**。 109 | 110 | 111 | 112 | ## 译者反馈 113 | 114 | 1. 允许转载,须全文转载并注明原文链接; 115 | 2. 请读者们通过评论和私信等方式批评指正,贡献者均会补充提及; 116 | 3. 感谢知友[盛玉娇][28]的细节修改评论,[@霍俊毅][29]的细节错误指正。 117 | 118 | [1]: https://pic4.zhimg.com/4a97d93d652f45ededf2ebab9a13f22b_m.jpeg 119 | [2]: https://zhuanlan.zhihu.com/intelligentunit 120 | [3]: https://zhuanlan.zhihu.com/write 121 | [4]: https://pic1.zhimg.com/86b3f2e3cf390a8319a365846a0f39a8_r.jpg 122 | [5]: https://pic2.zhimg.com/5ab5b93bd_xs.jpg 123 | [6]: https://www.zhihu.com/people/du-ke 124 | [7]: http://link.zhihu.com/?target=http%3A//cs231n.github.io/linear-classify/ 125 | [8]: http://link.zhihu.com/?target=http%3A//cs.stanford.edu/people/karpathy/ 126 | [9]: https://www.zhihu.com/people/gong-zi-jia-57 127 | [10]: https://www.zhihu.com/people/kun-kun-97-81 128 | [11]: http://zhihu.com/equation?tex=x_i%5Cin+R%5ED 129 | [12]: http://zhihu.com/equation?tex=y_i 130 | [13]: http://zhihu.com/equation?tex=i%3D1%2C2...N 131 | [14]: http://zhihu.com/equation?tex=y_i%5Cin+1...K 132 | [15]: http://zhihu.com/equation?tex=f%3AR%5ED%5Cto+R%5EK 133 | [16]: http://zhihu.com/equation?tex=%5Cdisplaystyle+f%28x_i%2CW%2Cb%29%3DWx_i%2Bb 134 | [17]: http://zhihu.com/equation?tex=x_i 135 | [18]: http://zhihu.com/equation?tex=Wx_i 136 | [19]: http://zhihu.com/equation?tex=%28x_i%2Cy_i%29 137 | [20]: http://pic3.zhimg.com/7c204cd1010c0af1e7b50000bfff1d8e_b.jpg 138 | [21]: http://pic2.zhimg.com/cfcb46408daa5353c38cb37e9bb6eb01_b.jpg 139 | [22]: http://zhihu.com/equation?tex=x_i%3D0 140 | [23]: http://pic1.zhimg.com/13e72e4ce83c11b49d36bbbb51d29ab4_b.jpg 141 | [24]: http://zhihu.com/equation?tex=W 142 | [25]: http://zhihu.com/equation?tex=b 143 | [26]: http://zhihu.com/equation?tex=%5Cdisplaystyle+f%28x_i%2CW%29%3DWx_i 144 | [27]: http://pic2.zhimg.com/3c69a5c87a43bfb07e2b59bfcbd2f149_b.jpg 145 | [28]: https://www.zhihu.com/people/sheng-yu-jiao 146 | [29]: http://www.zhihu.com/people/1c12faadea89ae2d36343065cd4d1ba8 147 | -------------------------------------------------------------------------------- /CS231n 2.2:图像分类笔记(下).md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # CS231n课程笔记翻译:图像分类笔记(下) - 知乎专栏 4 | 5 | ![CS231n课程笔记翻译:图像分类笔记(下)][4] 6 | 7 | [杜客][6] [Source](https://zhuanlan.zhihu.com/p/20900216?refer=intelligentunit "Permalink to CS231n课程笔记翻译:图像分类笔记(下) - 知乎专栏") 8 | 9 | 译者注:本文[智能单元][2]首发,翻译自斯坦福CS231n课程笔记[image classification notes__][7],课程教师[Andrej Karpathy__][8]授权翻译。本篇教程由[杜客][6]进行翻译,[ShiqingFan][9]和[巩子嘉][10]进行校对修改。译文含公式和代码,建议PC端阅读。 10 | 11 | 点击[查看图像分类笔记(上)][11]。 12 | 13 | ## 内容列表 14 | 15 | * 图像分类、数据驱动方法和流程 16 | * Nearest Neighbor分类器 17 | * k-Nearest Neighbor 18 | * 验证集、交叉验证集和超参数调优 _**译者注:下篇翻译起始处**_ 19 | * Nearest Neighbor的优劣 20 | * 小结 21 | * 小结:应用kNN实践 22 | * 拓展阅读 23 | 24 | ## 用于超参数调优的验证集 25 | 26 | k-NN分类器需要设定k值,那么选择哪个k值最合适的呢?我们可以选择不同的距离函数,比如L1范数和L2范数等,那么选哪个好?还有不少选择我们甚至连考虑都没有考虑到(比如:点积)。所有这些选择,被称为**超参数(hyperparameter)**。在基于数据进行学习的机器学习算法设计中,超参数是很常见的。一般说来,这些超参数具体怎么设置或取值并不是显而易见的。 27 | 28 | 你可能会建议尝试不同的值,看哪个值表现最好就选哪个。好主意!我们就是这么做的,但这样做的时候要非常细心。特别注意:**决不能使用测试集来进行调优**。当你在设计机器学习算法的时候,应该把测试集看做非常珍贵的资源,不到最后一步,绝不使用它。如果你使用测试集来调优,而且算法看起来效果不错,那么真正的危险在于:算法实际部署后,性能可能会远低于预期。这种情况,称之为算法对测试集**过拟合**。从另一个角度来说,如果使用测试集来调优,实际上就是把测试集当做训练集,由测试集训练出来的算法再跑测试集,自然性能看起来会很好。这其实是过于乐观了,实际部署起来效果就会差很多。所以,最终测试的时候再使用测试集,可以很好地近似度量你所设计的分类器的泛化性能(在接下来的课程中会有很多关于泛化性能的讨论)。 29 | 30 | 31 | 32 | > 测试数据集只使用一次,即在训练完成后评价最终的模型时使用。 33 | 34 | 好在我们有不用测试集调优的方法。其思路是:从训练集中取出一部分数据用来调优,我们称之为**验证集(****validation set****)**。以CIFAR-10为例,我们可以用49000个图像作为训练集,用1000个图像作为验证集。验证集其实就是作为假的测试集来调优。下面就是代码: 35 | 36 | 37 | 38 | 39 | 40 | ```py 41 | # assume we have Xtr_rows, Ytr, Xte_rows, Yte as before 42 | # recall Xtr_rows is 50,000 x 3072 matrix 43 | Xval_rows = Xtr_rows[:1000, :] # take first 1000 for validation 44 | Yval = Ytr[:1000] 45 | Xtr_rows = Xtr_rows[1000:, :] # keep last 49,000 for train 46 | Ytr = Ytr[1000:] 47 | 48 | # find hyperparameters that work best on the validation set 49 | validation_accuracies = [] 50 | for k in [1, 3, 5, 10, 20, 50, 100]: 51 | 52 | # use a particular value of k and evaluation on validation data 53 | nn = NearestNeighbor() 54 | nn.train(Xtr_rows, Ytr) 55 | # here we assume a modified NearestNeighbor class that can take a k as input 56 | Yval_predict = nn.predict(Xval_rows, k = k) 57 | acc = np.mean(Yval_predict == Yval) 58 | print 'accuracy: %f' % (acc,) 59 | 60 | # keep track of what works on the validation set 61 | validation_accuracies.append((k, acc)) 62 | 63 | ``` 64 | 65 | 程序结束后,我们会作图分析出哪个k值表现最好,然后用这个k值来跑真正的测试集,并作出对算法的评价。 66 | 67 | > 把训练集分成训练集和验证集。使用验证集来对所有超参数调优。最后只在测试集上跑一次并报告结果。 68 | 69 | **交叉验证**。有时候,训练集数量较小(因此验证集的数量更小),人们会使用一种被称为**交叉验证**的方法,这种方法更加复杂些。还是用刚才的例子,如果是交叉验证集,我们就不是取1000个图像,而是将训练集平均分成5份,其中4份用来训练,1份用来验证。然后我们循环着取其中4份来训练,其中1份来验证,最后取所有5次验证结果的平均值作为算法验证结果。 70 | 71 | ————————————————————————————————————————— 72 | 73 | ![][12]这就是5份交叉验证对k值调优的例子。针对每个k值,得到5个准确率结果,取其平均值,然后对不同k值的平均表现画线连接。本例中,当k=7的时算法表现最好(对应图中的准确率峰值)。如果我们将训练集分成更多份数,直线一般会更加平滑(噪音更少)。 74 | 75 | 76 | 77 | ————————————————————————————————————————— 78 | 79 | **实际应用**。在实际情况下,人们不是很喜欢用交叉验证,主要是因为它会耗费较多的计算资源。一般直接把训练集按照50%-90%的比例分成训练集和验证集。但这也是根据具体情况来定的:如果超参数数量多,你可能就想用更大的验证集,而验证集的数量不够,那么最好还是用交叉验证吧。至于分成几份比较好,一般都是分成3、5和10份。 80 | 81 | ————————————————————————————————————————— 82 | 83 | ![][13]常用的数据分割模式。给出训练集和测试集后,训练集一般会被均分。这里是分成5份。前面4份用来训练,黄色那份用作验证集调优。如果采取交叉验证,那就各份轮流作为验证集。最后模型训练完毕,超参数都定好了,让模型跑一次(而且只跑一次)测试集,以此测试结果评价算法。 84 | 85 | 86 | 87 | ————————————————————————————————————————— 88 | 89 | ## Nearest Neighbor分类器的优劣 90 | 91 | 现在对Nearest Neighbor分类器的优缺点进行思考。首先,Nearest Neighbor分类器易于理解,实现简单。其次,算法的训练不需要花时间,因为其训练过程只是将训练集数据存储起来。然而测试要花费大量时间计算,因为每个测试图像需要和所有存储的训练图像进行比较,这显然是一个缺点。在实际应用中,我们关注测试效率远远高于训练效率。其实,我们后续要学习的卷积神经网络在这个权衡上走到了另一个极端:虽然训练花费很多时间,但是一旦训练完成,对新的测试数据进行分类非常快。这样的模式就符合实际使用需求。 92 | 93 | Nearest Neighbor分类器的计算复杂度研究是一个活跃的研究领域,若干**Approximate Nearest Neighbor **(ANN)算法和库的使用可以提升Nearest Neighbor分类器在数据上的计算速度(比如:[FLANN__][14])。这些算法可以在准确率和时空复杂度之间进行权衡,并通常依赖一个预处理/索引过程,这个过程中一般包含kd树的创建和k-means算法的运用。 94 | 95 | 96 | 97 | Nearest Neighbor分类器在某些特定情况(比如数据维度较低)下,可能是不错的选择。但是在实际的图像分类工作中,很少使用。因为图像都是高维度数据(他们通常包含很多像素),而高维度向量之间的距离通常是反直觉的。下面的图片展示了基于像素的相似和基于感官的相似是有很大不同的: 98 | 99 | ————————————————————————————————————————— 100 | 101 | ![][15]在高维度数据上,基于像素的的距离和感官上的非常不同。上图中,右边3张图片和左边第1张原始图片的L2距离是一样的。很显然,基于像素比较的相似和感官上以及语义上的相似是不同的。 102 | 103 | ————————————————————————————————————————— 104 | 105 | 这里还有个视觉化证据,可以证明使用像素差异来比较图像是不够的。z这是一个叫做[t-SNE__][16]的可视化技术,它将CIFAR-10中的图片按照二维方式排布,这样能很好展示图片之间的像素差异值。在这张图片中,排列相邻的图片L2距离就小。 106 | 107 | ————————————————————————————————————————— 108 | 109 | ![][17]上图使用t-SNE的可视化技术将CIFAR-10的图片进行了二维排列。排列相近的图片L2距离小。可以看出,图片的排列是被背景主导而不是图片语义内容本身主导。 110 | 111 | —————————————————————————————————————————— 112 | 113 | 具体说来,这些图片的排布更像是一种颜色分布函数,或者说是基于背景的,而不是图片的语义主体。比如,狗的图片可能和青蛙的图片非常接近,这是因为两张图片都是白色背景。从理想效果上来说,我们肯定是希望同类的图片能够聚集在一起,而不被背景或其他不相关因素干扰。为了达到这个目的,我们不能止步于原始像素比较,得继续前进。 114 | 115 | ## 小结 116 | 117 | 简要说来: 118 | 119 | * 介绍了**图像分类**问题。在该问题中,给出一个由被标注了分类标签的图像组成的集合,要求算法能预测没有标签的图像的分类标签,并根据算法预测准确率进行评价。 120 | * 介绍了一个简单的图像分类器:**最近邻分类器(Nearest Neighbor classifier)**。分类器中存在不同的超参数(比如k值或距离类型的选取),要想选取好的超参数不是一件轻而易举的事。 121 | * 选取超参数的正确方法是:将原始训练集分为训练集和**验证集**,我们在验证集上尝试不同的超参数,最后保留表现最好那个。 122 | * 如果训练数据量不够,使用**交叉验证**方法,它能帮助我们在选取最优超参数的时候减少噪音。 123 | * 一旦找到最优的超参数,就让算法以该参数在测试集跑且只跑一次,并根据测试结果评价算法。 124 | * 最近邻分类器能够在CIFAR-10上得到将近40%的准确率。该算法简单易实现,但需要存储所有训练数据,并且在测试的时候过于耗费计算能力。 125 | * 最后,我们知道了仅仅使用L1和L2范数来进行像素比较是不够的,图像更多的是按照背景和颜色被分类,而不是语义主体分身。 126 | 127 | 在接下来的课程中,我们将专注于解决这些问题和挑战,并最终能够得到超过90%准确率的解决方案。该方案能够在完成学习就丢掉训练集,并在一毫秒之内就完成一张图片的分类。 128 | 129 | ## 小结:实际应用k-NN 130 | 131 | 如果你希望将k-NN分类器用到实处(最好别用到图像上,若是仅仅作为练手还可以接受),那么可以按照以下流程: 132 | 133 | 1. 预处理你的数据:对你数据中的特征进行归一化(normalize),让其具有零平均值(zero mean)和单位方差(unit variance)。在后面的小节我们会讨论这些细节。本小节不讨论,是因为图像中的像素都是同质的,不会表现出较大的差异分布,也就不需要标准化处理了。 134 | 2. 如果数据是高维数据,考虑使用降维方法,比如PCA([wiki ref__][18], [CS229ref__][19], [blog ref__][20])或[随机投影__][21]。 135 | 3. 将数据随机分入训练集和验证集。按照一般规律,70%-90% 数据作为训练集。这个比例根据算法中有多少超参数,以及这些超参数对于算法的预期影响来决定。如果需要预测的超参数很多,那么就应该使用更大的验证集来有效地估计它们。如果担心验证集数量不够,那么就尝试交叉验证方法。如果计算资源足够,使用交叉验证总是更加安全的(份数越多,效果越好,也更耗费计算资源)。 136 | 4. 在验证集上调优,尝试足够多的k值,尝试L1和L2两种范数计算方式。 137 | 5. 如果分类器跑得太慢,尝试使用Approximate Nearest Neighbor库(比如[FLANN__][14])来加速这个过程,其代价是降低一些准确率。 138 | 6. 对最优的超参数做记录。记录最优参数后,是否应该让使用最优参数的算法在完整的训练集上运行并再次训练呢?因为如果把验证集重新放回到训练集中(自然训练集的数据量就又变大了),有可能最优参数又会有所变化。在实践中,**不要这样做**。千万不要在最终的分类器中使用验证集数据,这样做会破坏对于最优参数的估计。**直接使用测试集来测试用最优参数设置好的最优模型**,得到测试集数据的分类准确率,并以此作为你的kNN分类器在该数据上的性能表现。 139 | 140 | ## 拓展阅读 141 | 142 | 下面是一些你可能感兴趣的拓展阅读链接: 143 | 144 | * [A Few Useful Things to Know about Machine Learning__][22],文中第6节与本节相关,但是整篇文章都强烈推荐。 145 | * [Recognizing and Learning Object Categories__][23],ICCV 2005上的一节关于物体分类的课程。 146 | 147 | **图像分类笔记全文翻译完毕**。 148 | 149 | 150 | 151 | ## 译者反馈 152 | 153 | 1. 感谢知友们鼓励支持。力争信达雅,敬请批评指正; 154 | 155 | 2. 得知友厚爱而飘飘然。向英语专业的妹纸炫耀,被批翻译腔,力戒之; 156 | 3. 感谢知友[曾家建][24]的仔细阅读和批评指正。 157 | 158 | 159 | 160 | [1]: https://pic4.zhimg.com/4a97d93d652f45ededf2ebab9a13f22b_m.jpeg 161 | [2]: https://zhuanlan.zhihu.com/intelligentunit 162 | [3]: https://zhuanlan.zhihu.com/write 163 | [4]: https://pic3.zhimg.com/4b149e4f05ca3551cadcb07c0963cb6a_r.png 164 | [5]: https://pic2.zhimg.com/5ab5b93bd_xs.jpg 165 | [6]: https://www.zhihu.com/people/du-ke 166 | [7]: http://link.zhihu.com/?target=http%3A//cs231n.github.io/classification 167 | [8]: http://link.zhihu.com/?target=http%3A//cs.stanford.edu/people/karpathy/ 168 | [9]: https://www.zhihu.com/people/sqfan 169 | [10]: https://www.zhihu.com/people/gong-zi-jia-57 170 | [11]: https://zhuanlan.zhihu.com/p/20894041?refer=intelligentunit 171 | [12]: https://pic1.zhimg.com/6a3ceec60cc0a379b4939c37ee3e89e8_b.png 172 | [13]: https://pic1.zhimg.com/cc88207c6c3c5e91df8b6367368f6450_b.jpg 173 | [14]: http://link.zhihu.com/?target=http%3A//www.cs.ubc.ca/research/flann/ 174 | [15]: https://pic3.zhimg.com/fd42d369eebdc5d81c89593ec1082e32_b.png 175 | [16]: http://link.zhihu.com/?target=http%3A//lvdmaaten.github.io/tsne/ 176 | [17]: https://pic1.zhimg.com/0f4980edb8710eaba0f3e661b1cbb830_b.jpg 177 | [18]: http://link.zhihu.com/?target=http%3A//en.wikipedia.org/wiki/Principal_component_analysis 178 | [19]: http://link.zhihu.com/?target=http%3A//cs229.stanford.edu/notes/cs229-notes10.pdf 179 | [20]: http://link.zhihu.com/?target=http%3A//www.bigdataexaminer.com/understanding-dimensionality-reduction-principal-component-analysis-and-singular-value-decomposition/ 180 | [21]: http://link.zhihu.com/?target=http%3A//scikit-learn.org/stable/modules/random_projection.html 181 | [22]: http://link.zhihu.com/?target=http%3A//homes.cs.washington.edu/%257Epedrod/papers/cacm12.pdf 182 | [23]: http://link.zhihu.com/?target=http%3A//people.csail.mit.edu/torralba/shortCourseRLOC/index.html 183 | [24]: https://www.zhihu.com/people/ceng-jia-jian-28 184 | 185 | -------------------------------------------------------------------------------- /CS231n 6.1.b:神经网络笔记1(下).md: -------------------------------------------------------------------------------- 1 | 2 | [Source](https://zhuanlan.zhihu.com/p/21513367?refer=intelligentunit "Permalink to CS231n课程笔记翻译:神经网络笔记1(下) - 知乎专栏") 3 | 4 | # CS231n课程笔记翻译:神经网络笔记1(下) - 知乎专栏 5 | 6 | 7 | ![CS231n课程笔记翻译:神经网络笔记1(下)][4] 8 | 9 | # CS231n课程笔记翻译:神经网络笔记1(下) 10 | 11 | ![杜客][5][杜客][6] 12 | 13 | 9 months ago 14 | 15 | 译者注:本文[智能单元][2]首发,译自斯坦福CS231n课程笔记[Neural Nets notes 1__][7],课程教师[Andrej Karpathy__][8]授权翻译。本篇教程由[杜客][6]翻译完成,[李艺颖][9]和[堃堃][10]进行校对修改。译文含公式和代码,建议PC端阅读。 16 | 17 | ## 原文如下 18 | 19 | 内容列表: 20 | 21 | * 不用大脑做类比的快速简介 22 | * 单个神经元建模 23 | * 生物动机和连接 24 | * 作为线性分类器的单个神经元 25 | * 常用的激活函数 26 | * 神经网络结构 _**译者注:下篇翻译起始处**_ 27 | * 层组织 28 | * 前向传播计算例子 29 | * 表达能力 30 | * 设置层的数量和尺寸 31 | * 小节 32 | * 参考文献 33 | 34 | ## 神经网络结构 35 | 36 | ## 灵活地组织层 37 | 38 | **将神经网络算法以神经元的形式图形化。**神经网络被建模成神经元的集合,神经元之间以无环图的形式进行连接。也就是说,一些神经元的输出是另一些神经元的输入。在网络中是不允许循环的,因为这样会导致前向传播的无限循环。通常神经网络模型中神经元是分层的,而不是像生物神经元一样聚合成大小不一的团状。对于普通神经网络,最普通的层的类型是**全连接层(****fully-connected layer****)**。全连接层中的神经元与其前后两层的神经元是完全成对连接的,但是在同一个全连接层内的神经元之间没有连接。下面是两个神经网络的图例,都使用的全连接层: 39 | 40 | ———————————————————————————————————————— 41 | 42 | ![][11]左边是一个2层神经网络,隐层由4个神经元(也可称为单元(unit))组成,输出层由2个神经元组成,输入层是3个神经元。右边是一个3层神经网络,两个含4个神经元的隐层。注意:层与层之间的神经元是全连接的,但是层内的神经元不连接。 43 | 44 | ———————————————————————————————————————— 45 | 46 | **命名规则。**当我们说N层神经网络的时候,我们没有把输入层算入。因此,单层的神经网络就是没有隐层的(输入直接映射到输出)。因此,有的研究者会说逻辑回归或者SVM只是单层神经网络的一个特例。研究者们也会使用_人工神经网络(_Artificial Neural Networks _缩写ANN)_或者_多层感知器(_Multi-Layer Perceptrons _缩写__MLP)_来指代神经网络。很多研究者并不喜欢神经网络算法和人类大脑之间的类比,他们更倾向于用_单元(unit)_而不是神经元作为术语。 47 | 48 | 49 | 50 | **输出层。**和神经网络中其他层不同,输出层的神经元一般是不会有激活函数的(或者也可以认为它们有一个线性相等的激活函数)。这是因为最后的输出层大多用于表示分类评分值,因此是任意值的实数,或者某种实数值的目标数(比如在回归中)。 51 | 52 | **确定网络尺寸。**用来度量神经网络的尺寸的标准主要有两个:一个是神经元的个数,另一个是参数的个数,用上面图示的两个网络举例: 53 | 54 | * 第一个网络有4+2=6个神经元(输入层不算),[3x4]+[4x2]=20个权重,还有4+2=6个偏置,共26个可学习的参数。 55 | * 第二个网络有4+4+1=9个神经元,[3x4]+[4x4]+[4x1]=32个权重,4+4+1=9个偏置,共41个可学习的参数。 56 | 57 | 58 | 为了方便对比,现代卷积神经网络能包含约1亿个参数,可由10-20层构成(这就是深度学习)。然而,_有效(effective)_连接的个数因为参数共享的缘故大大增多。在后面的卷积神经网络内容中我们将学习更多。 59 | 60 | ## 前向传播计算举例 61 | 62 | _不断重复的矩阵乘法与激活函数交织_。将神经网络组织成层状的一个主要原因,就是这个结构让神经网络算法使用矩阵向量操作变得简单和高效。用上面那个3层神经网络举例,输入是[3x1]的向量。一个层所有连接的强度可以存在一个单独的矩阵中。比如第一个隐层的权重**W1**是[4x3],所有单元的偏置储存在**b1**中,尺寸[4x1]。这样,每个神经元的权重都在**W1**的一个行中,于是矩阵乘法**np.dot(W1, x)**就能计算该层中所有神经元的激活数据。类似的,**W2**将会是[4x4]矩阵,存储着第二个隐层的连接,**W3**是[1x4]的矩阵,用于输出层。完整的3层神经网络的前向传播就是简单的3次矩阵乘法,其中交织着激活函数的应用。 63 | 64 | 65 | 66 | ```py 67 | # 一个3层神经网络的前向传播: 68 | f = lambda x: 1.0/(1.0 + np.exp(-x)) # 激活函数(用的sigmoid) 69 | x = np.random.randn(3, 1) # 含3个数字的随机输入向量(3x1) 70 | h1 = f(np.dot(W1, x) + b1) # 计算第一个隐层的激活数据(4x1) 71 | h2 = f(np.dot(W2, h1) + b2) # 计算第二个隐层的激活数据(4x1) 72 | out = np.dot(W3, h2) + b3 # 神经元输出(1x1) 73 | 74 | ``` 75 | 76 | 在上面的代码中,**W1,W2,W3,b1,b2,b3**都是网络中可以学习的参数。注意**x**并不是一个单独的列向量,而可以是一个批量的训练数据(其中每个输入样本将会是**x**中的一列),所有的样本将会被并行化的高效计算出来。注意神经网络最后一层通常是没有激活函数的(例如,在分类任务中它给出一个实数值的分类评分)。 77 | 78 | > 全连接层的前向传播一般就是先进行一个矩阵乘法,然后加上偏置并运用激活函数。 79 | 80 | ## 表达能力 81 | 82 | 理解具有全连接层的神经网络的一个方式是:可以认为它们定义了一个由一系列函数组成的函数族,网络的权重就是每个函数的参数。如此产生的问题是:该函数族的表达能力如何?存在不能被神经网络表达的函数吗? 83 | 84 | 现在看来,拥有至少一个隐层的神经网络是一个_通用的近似器_。在研究(例如1989年的论文[Approximation by Superpositions of Sigmoidal Function__][12],或者[Michael Nielsen__][13]的这个直观解释。)中已经证明,给出任意连续函数![f\(x\)][14]和任意![\epsilon >0][15],均存在一个至少含1个隐层的神经网络![g\(x\)][16](并且网络中有合理选择的非线性激活函数,比如sigmoid),对于![ orall x][17],使得![|f\(x\)-g\(x\)|<\epsilon][18]。换句话说,神经网络可以近似任何连续函数。 85 | 86 | 87 | 88 | 既然一个隐层就能近似任何函数,那为什么还要构建更多层来将网络做得更深?答案是:虽然一个2层网络在数学理论上能完美地近似所有连续函数,但在实际操作中效果相对较差。在一个维度上,虽然以![a,b,c][19]为参数向量"指示块之和"函数![g\(x\)=\sum_ic_i1\(a_i<x<b_i\) ][20]也是通用的近似器,但是谁也不会建议在机器学习中使用这个函数公式。神经网络在实践中非常好用,是因为它们表达出的函数不仅平滑,而且对于数据的统计特性有很好的拟合。同时,网络通过最优化算法(例如梯度下降)能比较容易地学习到这个函数。类似的,虽然在理论上深层网络(使用了多个隐层)和单层网络的表达能力是一样的,但是就实践经验而言,深度网络效果比单层网络好。 89 | 90 | 91 | 92 | 93 | 94 | 另外,在实践中3层的神经网络会比2层的表现好,然而继续加深(做到4,5,6层)很少有太大帮助。卷积神经网络的情况却不同,在卷积神经网络中,对于一个良好的识别系统来说,深度是一个极端重要的因素(比如数十(以10为量级)个可学习的层)。对于该现象的一种解释观点是:因为图像拥有层次化结构(比如脸是由眼睛等组成,眼睛又是由边缘组成),所以多层处理对于这种数据就有直观意义。 95 | 96 | 97 | 98 | 全面的研究内容还很多,近期研究的进展也很多。如果你对此感兴趣,我么推荐你阅读下面文献: 99 | 100 | 101 | 102 | * [Deep Learning__][21]的[Chapter6.4__][22],作者是Bengio等。 103 | * [Do Deep Nets Really Need to be Deep?__][23] 104 | * [FitNets: Hints for Thin Deep Nets__][24] 105 | 106 | ## 设置层的数量和尺寸 107 | 108 | 在面对一个具体问题的时候该确定网络结构呢?到底是不用隐层呢?还是一个隐层?两个隐层或更多?每个层的尺寸该多大? 109 | 110 | 首先,要知道当我们增加层的数量和尺寸时,网络的容量上升了。即神经元们可以合作表达许多复杂函数,所以表达函数的空间增加。例如,如果有一个在二维平面上的二分类问题。我们可以训练3个不同的神经网络,每个网络都只有一个隐层,但是每层的神经元数目不同: 111 | 112 | 113 | 114 | ———————————————————————————————————————— 115 | 116 | ![][25]更大的神经网络可以表达更复杂的函数。数据是用不同颜色的圆点表示他们的不同类别,决策边界是由训练过的神经网络做出的。你可以在[ConvNetsJS demo__][26]上练练手。 117 | 118 | ———————————————————————————————————————— 119 | 120 | 在上图中,可以看见有更多神经元的神经网络可以表达更复杂的函数。然而这既是优势也是不足,优势是可以分类更复杂的数据,不足是可能造成对训练数据的过拟合。**过拟合****(Overfitting)**是网络对数据中的噪声有很强的拟合能力,而没有重视数据间(假设)的潜在基本关系。举例来说,有20个神经元隐层的网络拟合了所有的训练数据,但是其代价是把决策边界变成了许多不相连的红绿区域。而有3个神经元的模型的表达能力只能用比较宽泛的方式去分类数据。它将数据看做是两个大块,并把个别在绿色区域内的红色点看做噪声。在实际中,这样可以在测试数据中获得更好的**泛****化(generalization)**能力。 121 | 122 | 123 | 124 | 基于上面的讨论,看起来如果数据不是足够复杂,则似乎小一点的网络更好,因为可以防止过拟合。然而并非如此,防止神经网络的过拟合有很多方法(L2正则化,dropout和输入噪音等),后面会详细讨论。在实践中,使用这些方法来控制过拟合比减少网络神经元数目要好得多。 125 | 126 | 不要减少网络神经元数目的主要原因在于小网络更难使用梯度下降等局部方法来进行训练:虽然小型网络的损失函数的局部极小值更少,也比较容易收敛到这些局部极小值,但是这些最小值一般都很差,损失值很高。相反,大网络拥有更多的局部极小值,但就实际损失值来看,这些局部极小值表现更好,损失更小。因为神经网络是非凸的,就很难从数学上研究这些特性。即便如此,还是有一些文章尝试对这些目标函数进行理解,例如[The Loss Surfaces of Multilayer Networks__][27]这篇论文。在实际中,你将发现如果训练的是一个小网络,那么最终的损失值将展现出多变性:某些情况下运气好会收敛到一个好的地方,某些情况下就收敛到一个不好的极值。从另一方面来说,如果你训练一个大的网络,你将发现许多不同的解决方法,但是最终损失值的差异将会小很多。这就是说,所有的解决办法都差不多,而且对于随机初始化参数好坏的依赖也会小很多。 127 | 128 | 重申一下,正则化强度是控制神经网络过拟合的好方法。看下图结果: 129 | 130 | ———————————————————————————————————————— 131 | 132 | ![][28]不同正则化强度的效果:每个神经网络都有20个隐层神经元,但是随着正则化强度增加,它的决策边界变得更加平滑。你可以在[ConvNetsJS demo__][26]上练练手。 133 | 134 | 135 | 136 | ———————————————————————————————————————— 137 | 138 | 需要记住的是:不应该因为害怕出现过拟合而使用小网络。相反,应该进尽可能使用大网络,然后使用正则化技巧来控制过拟合。 139 | 140 | # 小结 141 | 142 | 小结如下: 143 | 144 | * 介绍了生物神经元的粗略模型; 145 | * 讨论了几种不同类型的激活函数,其中ReLU是最佳推荐; 146 | * 介绍了**神经网络**,神经元通过**全连接层**连接,层间神经元两两相连,但是层内神经元不连接; 147 | * 理解了分层的结构能够让神经网络高效地进行矩阵乘法和激活函数运算; 148 | * 理解了神经网络是一个**通用函数近似器**,但是该性质与其广泛使用无太大关系。之所以使用神经网络,是因为它们对于实际问题中的函数的公式能够某种程度上做出"正确"假设。 149 | * 讨论了更大网络总是更好的这一事实。然而更大容量的模型一定要和更强的正则化(比如更高的权重衰减)配合,否则它们就会过拟合。在后续章节中我们讲学习更多正则化的方法,尤其是dropout。 150 | 151 | # 参考资料 152 | 153 | * 使用Theano的[deeplearning.net tutorial__][29] 154 | * [ConvNetJS__][29] 155 | * [Michael Nielsen's tutorials__][30] 156 | 157 | ## 译者反馈 158 | 159 | 1. **转载须全文转载且注明原文链接**,否则保留维权权利; 160 | 2. 请知友们通过评论和私信等方式批评指正,贡献者均会补充提及。 161 | 162 | [1]: https://pic4.zhimg.com/4a97d93d652f45ededf2ebab9a13f22b_m.jpeg 163 | [2]: https://zhuanlan.zhihu.com/intelligentunit 164 | [3]: https://zhuanlan.zhihu.com/write 165 | [4]: https://pic2.zhimg.com/421c2492bfe445a3b7e92e18ced0e8dd_r.jpg 166 | [5]: https://pic2.zhimg.com/5ab5b93bd_xs.jpg 167 | [6]: https://www.zhihu.com/people/du-ke 168 | [7]: http://link.zhihu.com/?target=http%3A//cs231n.github.io/neural-networks-1/ 169 | [8]: http://link.zhihu.com/?target=http%3A//cs.stanford.edu/people/karpathy/ 170 | [9]: https://www.zhihu.com/people/li-yi-ying-73 171 | [10]: https://www.zhihu.com/people/kun-kun-97-81 172 | [11]: http://pic3.zhimg.com/ccb56c1fb267bc632d6d88459eb14ace_b.png 173 | [12]: http://link.zhihu.com/?target=http%3A//www.dartmouth.edu/%257Egvc/Cybenko_MCSS.pdf 174 | [13]: http://link.zhihu.com/?target=http%3A//neuralnetworksanddeeplearning.com/chap4.html 175 | [14]: http://zhihu.com/equation?tex=f%28x%29 176 | [15]: http://zhihu.com/equation?tex=%5Cepsilon+%3E0 177 | [16]: http://zhihu.com/equation?tex=g%28x%29 178 | [17]: http://zhihu.com/equation?tex=%5Cforall+x 179 | [18]: http://zhihu.com/equation?tex=%7Cf%28x%29-g%28x%29%7C%3C%5Cepsilon 180 | [19]: http://zhihu.com/equation?tex=a%2Cb%2Cc 181 | [20]: http://zhihu.com/equation?tex=g%28x%29%3D%5Csum_ic_i1%28a_i%3Cx%3Cb_i%29+ 182 | [21]: http://link.zhihu.com/?target=http%3A//www.deeplearningbook.org/ 183 | [22]: http://link.zhihu.com/?target=http%3A//www.deeplearningbook.org/contents/mlp.html 184 | [23]: http://link.zhihu.com/?target=http%3A//arxiv.org/abs/1312.6184 185 | [24]: http://link.zhihu.com/?target=http%3A//arxiv.org/abs/1412.6550 186 | [25]: http://pic1.zhimg.com/cf3fc543bf1dc81e2083530a4492b0ec_b.png 187 | [26]: http://link.zhihu.com/?target=http%3A//cs.stanford.edu/people/karpathy/convnetjs/demo/classify2d.html 188 | [27]: http://link.zhihu.com/?target=http%3A//arxiv.org/abs/1412.0233 189 | [28]: http://pic1.zhimg.com/4f8af027d6059549d160199a1717df14_b.png 190 | [29]: http://link.zhihu.com/?target=http%3A//www.deeplearning.net/tutorial/mlp.html 191 | [30]: http://link.zhihu.com/?target=http%3A//neuralnetworksanddeeplearning.com/chap1.html -------------------------------------------------------------------------------- /CS231n 0 官方笔记授权翻译总集篇发布.md: -------------------------------------------------------------------------------- 1 | 2 | [Source](https://zhuanlan.zhihu.com/p/21930884?refer=intelligentunit "Permalink to 贺完结!CS231n官方笔记授权翻译总集篇发布 - 知乎专栏") 3 | 4 | # 贺完结!CS231n官方笔记授权翻译总集篇发布 - 知乎专栏 5 | 6 | {"database":{"Post":{"21930884":{"title":"贺完结!CS231n官方笔记授权翻译总集篇发布","author":"du-ke","content":" 7 | 8 | > 哈哈哈!我们也是不谦虚,几个"业余水平"的网友,怎么就"零星"地把这件事给搞完了呢!**总之就是非常开心**,废话不多说,进入正题吧! 9 | 10 | ## CS231n简介 11 | 12 | CS231n的全称是[CS231n: Convolutional Neural Networks for Visual Recognition__][1],即**面向视觉识别的卷积神经网络**。该课程是[斯坦福大学计算机视觉实验室__][2]推出的课程。需要注意的是,目前大家说CS231n,大都指的是2016年冬季学期(一月到三月)的最新版本。 13 | 14 | **课程描述**:请允许我们引用课程主页上的**官方描述**如下。 15 | 16 | > 计算机视觉在社会中已经逐渐普及,并广泛运用于搜索检索、图像理解、手机应用、地图导航、医疗制药、无人机和无人驾驶汽车等领域。而这些应用的核心技术就是图像分类、图像定位和图像探测等视觉识别任务。近期神经网络(也就是"深度学习")方法上的进展极大地提升了这些代表当前发展水平的视觉识别系统的性能。 17 | > 18 | > 本课程将深入讲解深度学习框架的细节问题,聚焦面向视觉识别任务(尤其是图像分类任务)的端到端学习模型。在10周的课程中,学生们将会学习如何实现、训练和调试他们自己的神经网络,并建立起对计算机视觉领域的前沿研究方向的细节理解。最终的作业将包括训练一个有几百万参数的卷积神经网络,并将其应用到最大的图像分类数据库(ImageNet)上。我们将会聚焦于教授如何确定图像识别问题,学习算法(比如反向传播算法),对网络的训练和精细调整(fine-tuning)中的工程实践技巧,指导学生动手完成课程作业和最终的课程项目。本课程的大部分背景知识和素材都来源于[ImageNet Challenge__][3]竞赛。 19 | 20 | **课程内容**:官方课程安排及资源获取请点击[这里__][4],课程视频请在Youtube上查看[Andrej Karpathy__][5]创建的[播放列表__][6],也可私信我们获取云盘视频资源。通过查看官方课程表,我们可以看到:CS231n课程资源主要由**授课视频与PPT**,**授课知识详解笔记**和**课程作业**三部分组成。其中: 21 | 22 | * **授课视频15课**。每节课时约1小时左右,每节课一份PPT。 23 | * **授课知识详解笔记共9份**。光看课程视频是不够的,深入理解课程笔记才能比较扎实地学习到知识。 24 | * **课程作业3次**。其中每次作业中又包含多个小作业,完成作业能确保对于课程关键知识的深入理解和实现。 25 | * **课程项目1个**。这个更多是面向斯坦福的学生,组队实现课程项目。 26 | * **拓展阅读若干**。课程推荐的拓展阅读大多是领域内的经典著作节选或论文,推荐想要深入学习的同学阅读。 27 | 28 | **课程评价**:我们觉得赞!很多人都觉得赞!当然也有人觉得不好。具体如何,大家搜搜CS231n在网络,在知乎上的评价不就好了嘛!**个人认为**:入门深度学习的**一门良心课**。**适合绝大多数**想要学习深度学习知识的人。 29 | 30 | **课程不足**:课程后期从RCNN开始就没有课程笔记。 31 | 32 | 33 | 34 | ## 课程学习方法 35 | 36 | 三句话总结: 37 | 38 | * **看授课视频形成概念,发现个人感兴趣方向。** 39 | * **读课程笔记理解细节,夯实工程实现的基础。 40 | ** 41 | * **码课程作业实现算法,积累实验技巧与经验。** 42 | 43 | 引用一下学习金字塔的图,意思大家都懂的: 44 | 45 | ![][7] 46 | 47 | ## 我们的工作 48 | 49 | * **完成了CS231n全部9篇课程知识详解笔记的翻译**: 50 | 51 | 原文:[[python/numpy tutorial]__][8]。 52 | 53 | 翻译:[Python Numpy教程][9]。 54 | 55 | > 我们将使用Python编程语言来完成本课程的所有作业。Python是一门伟大的通用编程语言,在一些常用库(numpy, scipy, matplotlib)的帮助下,它又会变成一个强大的科学计算环境。我们期望你们中大多数人对于Python语言和Numpy库比较熟悉,而对于没有Python经验的同学,这篇教程可以帮助你们快速了解Python编程环境和如何使用Python作为科学计算工具。 56 | 57 | 原文:[[image classification notes]__][10]。 58 | 59 | 翻译:[图像分类笔记(上)][11][(下)][12]。 60 | 61 | > 该笔记是一篇介绍性教程,面向非计算机视觉领域的同学。教程将向同学们介绍图像分类问题和数据驱动方法,内容列表: 62 | 63 | > 64 | > * 图像分类、数据驱动方法和流程 65 | 66 | > * Nearest Neighbor分类器 67 | > * k-Nearest Neighbor _译者注:上篇翻译截止处_ 68 | 69 | > * 验证集、交叉验证集和超参数调参 70 | 71 | > * Nearest Neighbor的优劣 72 | 73 | > * 小结 74 | 75 | > * 小结:应用kNN实践 76 | 77 | > * 拓展阅读 78 | 79 | 原文:[[linear classification notes]__][13]。 80 | 81 | 翻译:线性分类笔记[(上)][14][(中)][15][(下)][16]。 82 | 83 | > 我们将要实现一种更强大的方法来解决图像分类问题,该方法可以自然地延伸到神经网络和卷积神经网络上。这种方法主要有两部分组成:一个是**评分函数(score function)**,它是原始图像数据到类别分值的映射。另一个是**损失函数(loss function)**,它是用来量化预测分类标签的得分与真实标签之间一致性的。该方法可转化为一个最优化问题,在最优化过程中,将通过更新评分函数的参数来最小化损失函数值。内容列表: 84 | 85 | > 86 | > * 线性分类器简介 87 | > * 线性评分函数 88 | > * 阐明线性分类器 _译者注:上篇翻译截止处_ 89 | > * 损失函数 90 | > * 多类SVM 91 | > * Softmax分类器 92 | > * SVM和Softmax的比较 93 | > * 基于Web的可交互线性分类器原型 94 | > * 小结 95 | 96 | 原文:[[optimization notes]__][17]。 97 | 98 | 翻译:最优化笔记[(上)][18][(下)][19]。 99 | 100 | > 该笔记介绍了图像分类任务的第三个关键部分:最优化。内容列表如下: 101 | 102 | > 103 | > * 简介 104 | 105 | > * 损失函数可视化 106 | > * 最优化 107 | > * 策略#1:随机搜索 108 | > * 策略#2:随机局部搜索 109 | > * 策略#3:跟随梯度 _译者注:上篇截止处_ 110 | > * 梯度计算 111 | > * 使用有限差值进行数值计算 112 | > * 微分计算梯度 113 | > * 梯度下降 114 | > * 小结 115 | 116 | 原文:[[backprop notes]__][20]。 117 | 118 | 翻译:[反向传播笔记][21]。 119 | 120 | > 该笔记本将帮助读者**对反向传播形成直观而专业的理解**。反向传播是利用链式法则递归计算表达式的梯度的方法。理解反向传播过程及其精妙之处,对于理解、实现、设计和调试神经网络非常关键。内容里列表如下: 121 | 122 | > 123 | > * 简介 124 | > * 简单表达式和理解梯度 125 | > * 复合表达式,链式法则,反向传播 126 | > * 直观理解反向传播 127 | > * 模块:Sigmoid例子 128 | > * 反向传播实践:分段计算 129 | > * 回传流中的模式 130 | > * 用户向量化操作的梯度 131 | > * 小结 132 | 133 | 原文:[Neural Nets notes 1__][22]。 134 | 135 | 翻译:神经网络笔记1[(上)][23][(下)][24]。 136 | 137 | > 该笔记介绍了神经网络的建模与结构,内容列表如下: 138 | 139 | > 140 | > * 不用大脑做类比的快速简介 141 | > * 单个神经元建模 142 | > * 生物动机和连接 143 | > * 作为线性分类器的单个神经元 144 | > * 常用的激活函数 145 | > * 神经网络结构 146 | > * 层组织 147 | > * 前向传播计算例子 148 | > * 表达能力 149 | > * 设置层的数量和尺寸 150 | > * 小节 151 | > * 参考文献 152 | 153 | 原文:[Neural Nets notes 2__][25]。 154 | 155 | 翻译:[神经网络笔记2][26]。 156 | 157 | > 该笔记介绍了数据的预处理,正则化和损失函数,内容列表如下: 158 | 159 | > 160 | > * 设置数据和模型 161 | > * 数据预处理 162 | > * 权重初始化 163 | > * 批量归一化(Batch Normalization) 164 | > * 正则化(L2/L1/Maxnorm/Dropout) 165 | > * 损失函数 166 | > * 小结 167 | 168 | 原文:[Neural Nets notes 3__][27]。 169 | 170 | 翻译:神经网络笔记3[(上)][28][(下)][29]。 171 | 172 | > 该笔记讲解了神经网络的动态部分,即神经网络学习参数和搜索最优超参数的过程。内容列表如下: 173 | 174 | > 175 | > * 梯度检查 176 | > * 合理性(Sanity)检查 177 | > * 检查学习过程 178 | > 179 | > * 损失函数 180 | > * 训练集与验证集准确率 181 | > * 权重:更新比例 182 | > * 每层的激活数据与梯度分布 183 | > * 可视化 _译者注:上篇翻译截止处_ 184 | > * 参数更新 185 | > 186 | > * 一阶(随机梯度下降)方法,动量方法,Nesterov动量方法 187 | > * 学习率退火 188 | > * 二阶方法 189 | > * 逐参数适应学习率方法(Adagrad,RMSProp) 190 | > * 超参数调优 191 | > * 评价 192 | > * 总结 193 | > * 拓展引用 194 | 195 | 原文:[ConvNet notes__][30]。 196 | 197 | 翻译:[卷积神经网络笔记][31]。 198 | 199 | > 内容列表: 200 | > 201 | > * **结构概述** 202 | > * **用来构建卷积神经网络的各种层** 203 | 204 | > * 卷积层 205 | > * 汇聚层 206 | > * 归一化层 207 | > * 全连接层 208 | > * 将全连接层转化成卷积层 209 | > * **卷积神经网络的结构** 210 | > * 层的排列规律 211 | > * 层的尺寸设置规律 212 | > * 案例学习(LeNet / AlexNet / ZFNet / GoogLeNet / VGGNet) 213 | > * 计算上的考量 214 | > * **拓展资源** 215 | 216 | 217 | 218 | * **完成了3个课程作业页面的翻译**: 219 | 220 | 原文:[[Assignment #1]__][32]。 221 | 222 | 翻译:[CS231n课程作业#1简介][33]。 223 | 224 | > 作业内容:实现k-NN,SVM分类器,Softmax分类器和两层神经网络,实践一个简单的图像分类流程。 225 | 226 | 原文:[[Assignment #2]__][34]。 227 | 228 | 翻译:[CS231n课程作业#2简介][35]。 229 | 230 | > 作业内容:练习编写反向传播代码,训练神经网络和卷积神经网络。 231 | 232 | 原文:[[Assignment #3]__][36]。 233 | 234 | 翻译:[CS231n课程作业#3简介][37]。 235 | 236 | > 作业内容:实现循环网络,并将其应用于在微软的COCO数据库上进行图像标注。实现DeepDream等有趣应用。 237 | 238 | 239 | 240 | * **帮助知友[@智靖远][38]发起了在Youtube上合力翻译课程字幕的倡议**: 241 | 242 | 原文:[知友智靖远关于CS231n课程字幕翻译的倡议][39]。当时,[@智靖远][38]已经贡献了他对第一课字幕的翻译,目前这个翻译项目仍在进行中,欢迎各位知友积极参与。具体操作方式在倡议原文中有,请大家点击查看。 243 | 244 | 有很多知友私信我们,询问为何不做字幕。现在统一答复:**请大家积极参加[@智靖远][38]的字幕翻译项目。**他先进行的字幕贡献与翻译,我们**不能夺人之美**。**后续,我们也会向该翻译项目进行贡献**。 245 | 246 | ## 翻译团队 247 | 248 | CS231n课程笔记的翻译,始于[@杜客][40]在一次回答问题"[应该选择TensorFlow还是Theano?][41]"中的机缘巧合,在[取得了授权][42]后申请了知乎专栏[智能单元 - 知乎专栏][43]独自翻译。随着翻译的进行,更多的知友参与进来。他们是[@ShiqingFan][44],@[猴子][45],[@堃堃][46]和[@李艺颖][47]。 249 | 250 | **大家因为认同这件事而聚集在一起**,牺牲了很多个人的时间来进行翻译,校对和润色。而翻译的质量,我们不愿意自我表扬,还是**请各位知友自行阅读评价**吧。现在笔记翻译告一段落,下面是**团队成员的简短感言**: 251 | 252 | [@ShiqingFan][44] :一个偶然的机会让自己加入到这个翻译小队伍里来。CS231n给予了我知识的源泉和思考的灵感,前期的翻译工作也督促自己快速了学习了这门课程。虽然科研方向是大数据与并行计算,不过因为同时对深度学习比较感兴趣,于是乎现在的工作与两者都紧密相连。Merci! 253 | 254 | @[猴子][45]:在CS231n翻译小组工作的两个多月的时间非常难忘。我向杜客申请加入翻译小组的时候,才刚接触这门课不久,翻译和校对的工作让我对这门课的内容有了更深刻的理解。作为一个机器学习的初学者,我非常荣幸能和翻译小组一起工作并做一点贡献。希望以后能继续和翻译小组一起工作和学习。 255 | 256 | [@堃堃][46] :感谢组内各位成员的辛勤付出,很幸运能够参与这份十分有意义的工作,希望自己的微小工作能够帮助到大家,谢谢! 257 | 258 | [@李艺颖][47] :当你真正沉下心来要做一件事情的时候才是学习和提高最好的状态;当你有热情做事时,并不会觉得是在牺牲时间,因为那是有意义并能带给你成就感和充实感的;不需要太过刻意地在乎大牛的巨大光芒,你只需像傻瓜一样坚持下去就好了,也许回头一看,你已前进了很多。就像老杜说的,我们就是每一步慢慢走,怎么就"零星"地把这件事给搞完了呢? 259 | 260 | [@杜客][40] :做了一点微小的工作,哈哈。 261 | 262 | ## 未来工作 263 | 264 | 目前通过大家的反馈,之后会有新的创作方向,会更多与大家互动,敬请期待吧! 265 | 266 | ## 感谢 267 | 268 | 感谢**所有给我们的翻译提出过批评指正的知友**,每篇文章末尾处的译者反馈部分我们都列出了大家的具体指正与贡献; 269 | 270 | 感谢**所有给我们的翻译点赞的知友**,你们的赞是我们的精神粮食; 271 | 272 | 感谢**给文章赞赏小钱钱的知友**,谢谢老板们:) 273 | 274 | ## 最后 275 | 276 | **恳请大家点赞和分享到其他社交网络上**,让更多**想要入门与系统学习深度学习**的小伙伴能够看到这篇总集。同时,也欢迎大家在来专栏分享你的知识,发现志同道合的朋友! 277 | 278 | **这个世界需要更多的英雄!** 279 | 280 | 281 | 282 | [Source](https://zhuanlan.zhihu.com/p/20870307?refer=intelligentunit "Permalink to 获得授权翻译斯坦福CS231n课程笔记系列 - 知乎专栏") 283 | 284 | # 获得授权翻译斯坦福CS231n课程笔记系列 - 知乎专栏 285 | 286 | {"database":{"Post":{"20870307":{"title":"获得授权翻译斯坦福CS231n课程笔记系列","author":"du-ke","content":"一切都要从这个回答说起: 287 | 288 | [应该选择TensorFlow还是Theano? - 杜客的回答][1] 289 | 290 | 斯坦福CS231n-Convolutional Neural Networks for Visual Recognition(Winter 2016)是一个很好的课程,个人在学习过程中获益良多。 291 | 292 | 在和大家的交流中,发现菜鸟如自己可以为更多热爱机器学习的同学尽一份力。于是邮件了讲师Andrej Karpathy,表达了翻译的想法,询问是否存在问题。 293 | 294 | Andrej Karpathy表示没有问题,欢迎翻译并表示感谢。回复截图如下: 295 | 296 | ![][2]接下来,我和小伙伴们会利用课余时间,逐步为大家发布CS231n课程的notes翻译文章,欢迎大家批评指正,共同学习提高。 297 | 298 | 啊!真开心!! 299 | -------------------------------------------------------------------------------- /CS231n 3.3:线性分类笔记(下).md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | # CS231n课程笔记翻译:线性分类笔记(下) - 知乎专栏 5 | 6 | 7 | ![CS231n课程笔记翻译:线性分类笔记(下)][4] 8 | 9 | 10 | [杜客][6] [Source](https://zhuanlan.zhihu.com/p/21102293?refer=intelligentunit "Permalink to CS231n课程笔记翻译:线性分类笔记(下) - 知乎专栏") 11 | 12 | 译者注:本文[智能单元][2]首发,译自斯坦福CS231n课程笔记[Linear Classification Note__][7],课程教师[Andrej Karpathy__][8]授权翻译。本篇教程由[杜客][6]翻译完成,[堃堃][9]进行校对修改。译文含公式和代码,建议PC端阅读。 13 | 14 | ## 原文如下 15 | 16 | 内容列表: 17 | 18 | * 线性分类器简介 19 | * 线性评分函数 20 | * 阐明线性分类器 21 | * 损失函数 22 | * 多类SVM 23 | * Softmax分类器 _**译者注:下篇翻译起始处**_ 24 | * SVM和Softmax的比较 25 | * 基于Web的可交互线性分类器原型 26 | * 小结 27 | 28 | ## Softmax分类器 29 | 30 | SVM是最常用的两个分类器之一,而另一个就是**Softmax分类器,**它的损失函数与SVM的损失函数不同。对于学习过二元逻辑回归分类器的读者来说,Softmax分类器就可以理解为逻辑回归分类器面对多个分类的一般化归纳。SVM将输出![f\(x_i,W\)][10]作为每个分类的评分(因为无定标,所以难以直接解释)。与SVM不同,Softmax的输出(归一化的分类概率)更加直观,并且从概率上可以解释,这一点后文会讨论。在Softmax分类器中,函数映射![f\(x_i;W\)=Wx_i][11]保持不变,但将这些评分值视为每个分类的未归一化的对数概率,并且将_折叶损失(hinge loss)_替换为**交叉熵损失**(**cross-entropy loss)**。公式如下: 31 | 32 | ![displaystyle Li=-log\(frac{e^{f_{y_i}}}{sum_je^{f_j}}\)][12] 或等价的 ![L_i=-f_{y_i}+log\(sum_je^{f_j}\)][13] 33 | 34 | 在上式中,使用![f_j][14]来表示分类评分向量![f][15]中的第j个元素。和之前一样,整个数据集的损失值是数据集中所有样本数据的损失值![L_i][16]的均值与正则化损失![R\(W\)][17]之和。其中函数![f_j\(z\)=frac{e^{z_j}}{sum_ke^{z_k}}][18]被称作**softmax 函数**:其输入值是一个向量,向量中元素为任意实数的评分值(![z][19]中的),函数对其进行压缩,输出一个向量,其中每个元素值在0到1之间,且所有元素之和为1。所以,包含softmax函数的完整交叉熵损失看起唬人,实际上还是比较容易理解的。 35 | 36 | **信息理论视角**:在"真实"分布![p][20]和估计分布![q][21]之间的_交叉熵_定义如下: 37 | 38 | ![displaystyle H\(p,q\)=-sum_xp\(x\) logq\(x\)][22] 39 | 40 | 因此,Softmax分类器所做的就是最小化在估计分类概率(就是上面的![e^{f_{y_i}}/sum_je^{f_j}][23])和"真实"分布之间的交叉熵,在这个解释中,"真实"分布就是所有概率密度都分布在正确的类别上(比如:![p=\[0,...1,...,0\]][24]中在![y_i][25]的位置就有一个单独的1)。还有,既然交叉熵可以写成熵和相对熵(Kullback-Leibler divergence)![H\(p,q\)=H\(p\)+D_{KL}\(p||q\)][26],并且delta函数![p][20]的熵是0,那么就能等价的看做是对两个分布之间的相对熵做最小化操作。换句话说,交叉熵损失函数"想要"预测分布的所有_概率密度_都在正确分类上。 41 | 42 | _**译者注**:Kullback-Leibler差异(Kullback-Leibler Divergence)也叫做相对熵(Relative Entropy),它衡量的是相同事件空间里的两个概率分布的差异情况。_ 43 | 44 | **概率论解释**:先看下面的公式: 45 | 46 | ![P\(y_i|x_i,W\)=frac{e^{f_{y_i}}}{sum_je^{f_j}}][27] 47 | 48 | 可以解释为是给定图像数据![x_i][28],以![W][29]为参数,分配给正确分类标签![y_i][25]的归一化概率。为了理解这点,请回忆一下Softmax分类器将输出向量![f][15]中的评分值解释为没有归一化的_对数概率_。那么以这些数值做指数函数的幂就得到了没有归一化的概率,而除法操作则对数据进行了归一化处理,使得这些概率的和为1。从概率论的角度来理解,我们就是在最小化正确分类的负对数概率,这可以看做是在进行_最大似然估计_(MLE)。该解释的另一个好处是,损失函数中的正则化部分![R\(W\)][17]可以被看做是权重矩阵![W][29]的高斯先验,这里进行的是最大后验估计(MAP)而不是最大似然估计。提及这些解释只是为了让读者形成直观的印象,具体细节就超过本课程范围了。 49 | 50 | **实操事项:数值稳定。**编程实现softmax函数计算的时候,中间项![e^{f_{y_i}}][30]和![sum_j e^{f_j}][31]因为存在指数函数,所以数值可能非常大。除以大数值可能导致数值计算的不稳定,所以学会使用归一化技巧非常重要。如果在分式的分子和分母都乘以一个常数![C][32],并把它变换到求和之中,就能得到一个从数学上等价的公式: 51 | 52 | ![frac{e^{f_{y_i}}}{sum_je^{f_j}}=frac{Ce^{f_{y_i}}}{Csum_je^{f_j}}=frac{e^{f_{y_i}+logC}}{sum_je^{f_j+logC}}][33] 53 | 54 | ![C][32]的值可自由选择,不会影响计算结果,通过使用这个技巧可以提高计算中的数值稳定性。通常将![C][32]设为![logC=-max_jf_j][34]。该技巧简单地说,就是应该将向量![f][15]中的数值进行平移,使得最大值为0。代码实现如下: 55 | 56 | 57 | ```py 58 | f = np.array([123, 456, 789]) # 例子中有3个分类,每个评分的数值都很大 59 | p = np.exp(f) / np.sum(np.exp(f)) # 不妙:数值问题,可能导致数值爆炸 60 | 61 | # 那么将f中的值平移到最大值为0: 62 | f -= np.max(f) # f becomes [-666, -333, 0] 63 | p = np.exp(f) / np.sum(np.exp(f)) # 现在OK了,将给出正确结果 64 | 65 | ``` 66 | 67 | **让人迷惑的命名规则**:精确地说,SVM分类器使用的是_折叶损失(hinge loss)_,有时候又被称为_最大边界损失(max-margin loss)_。Softmax分类器使用的是_交叉熵损失(corss-entropy loss)_。Softmax分类器的命名是从_softmax函数_那里得来的,softmax函数将原始分类评分变成正的归一化数值,所有数值和为1,这样处理后交叉熵损失才能应用。注意从技术上说"softmax损失(softmax loss)"是没有意义的,因为softmax只是一个压缩数值的函数。但是在这个说法常常被用来做简称。 68 | 69 | ## SVM和Softmax的比较 70 | 71 | 下图有助于区分这 Softmax和SVM这两种分类器: 72 | 73 | ———————————————————————————————————————— 74 | 75 | ![][35] 76 | 77 | 针对一个数据点,SVM和Softmax分类器的不同处理方式的例子。两个分类器都计算了同样的分值向量**f**(本节中是通过矩阵乘来实现)。不同之处在于对**f**中分值的解释:SVM分类器将它们看做是分类评分,它的损失函数鼓励正确的分类(本例中是蓝色的类别2)的分值比其他分类的分值高出至少一个边界值。Softmax分类器将这些数值看做是每个分类没有归一化的**对数_概率_**,鼓励正确分类的归一化的对数概率变高,其余的变低。SVM的最终的损失值是1.58,Softmax的最终的损失值是0.452,但要注意这两个数值没有可比性。只在给定同样数据,在同样的分类器的损失值计算中,它们才有意义。 78 | 79 | ———————————————————————————————————————— 80 | 81 | **Softmax分类器为每个分类提供了"可能性"**:SVM的计算是无标定的,而且难以针对所有分类的评分值给出直观解释。Softmax分类器则不同,它允许我们计算出对于所有分类标签的可能性。举个例子,针对给出的图像,SVM分类器可能给你的是一个[12.5, 0.6, -23.0]对应分类"猫","狗","船"。而softmax分类器可以计算出这三个标签的"可能性"是[0.9, 0.09, 0.01],这就让你能看出对于不同分类准确性的把握。为什么我们要在"可能性"上面打引号呢?这是因为可能性分布的集中或离散程度是由正则化参数λ直接决定的,λ是你能直接控制的一个输入参数。举个例子,假设3个分类的原始分数是[1, -2, 0],那么softmax函数就会计算: 82 | 83 | 84 | ![\[1,-2,0\]to\[e^1,e^{-2},e^0\]=\[2.71,0.14,1\]to\[0.7,0.04,0.26\]][36] 85 | 86 | 现在,如果正则化参数λ更大,那么权重W就会被惩罚的更多,然后他的权重数值就会更小。这样算出来的分数也会更小,假设小了一半吧[0.5, -1, 0],那么softmax函数的计算就是: 87 | 88 | ![\[0.5,-1,0\]to\[e^{0.5},e^{-1},e^0\]=\[1.65,0.73,1\]to\[0.55,0.12,0.33\]][37] 89 | 90 | 91 | 现在看起来,概率的分布就更加分散了。还有,随着正则化参数λ不断增强,权重数值会越来越小,最后输出的概率会接近于均匀分布。这就是说,softmax分类器算出来的概率最好是看成一种对于分类正确性的自信。和SVM一样,数字间相互比较得出的大小顺序是可以解释的,但其绝对值则难以直观解释**。** 92 | 93 | **在实际使用中,SVM和Softmax经常是相似的**:通常说来,两种分类器的表现差别很小,不同的人对于哪个分类器更好有不同的看法。相对于Softmax分类器,SVM更加"局部目标化(local objective)",这既可以看做是一个特性,也可以看做是一个劣势。考虑一个评分是[10, -2, 3]的数据,其中第一个分类是正确的。那么一个SVM(![Delta =1][38])会看到正确分类相较于不正确分类,已经得到了比边界值还要高的分数,它就会认为损失值是0。SVM对于数字个体的细节是不关心的:如果分数是[10, -100, -100]或者[10, 9, 9],对于SVM来说没设么不同,只要满足超过边界值等于1,那么损失值就等于0。 94 | 95 | 对于softmax分类器,情况则不同。对于[10, 9, 9]来说,计算出的损失值就远远高于[10, -100, -100]的。换句话来说,softmax分类器对于分数是永远不会满意的:正确分类总能得到更高的可能性,错误分类总能得到更低的可能性,损失值总是能够更小。但是,SVM只要边界值被满足了就满意了,不会超过限制去细微地操作具体分数。这可以被看做是SVM的一种特性。举例说来,一个汽车的分类器应该把他的大量精力放在如何分辨小轿车和大卡车上,而不应该纠结于如何与青蛙进行区分,因为区分青蛙得到的评分已经足够低了。 96 | 97 | ## 交互式的网页Demo 98 | 99 | ———————————————————————————————————————— 100 | 101 | ![][39]我们实现了一个交互式的网页原型,来帮助读者直观地理解线性分类器。原型将损失函数进行可视化,画面表现的是对于2维数据的3种类别的分类。原型在课程进度上稍微超前,展现了最优化的内容,最优化将在下一节课讨论。 102 | 103 | ———————————————————————————————————————— 104 | 105 | ## 小结 106 | 107 | 总结如下: 108 | 109 | * 定义了从图像像素映射到不同类别的分类评分的评分函数。在本节中,评分函数是一个基于权重**W**和偏差**b**的线性函数。 110 | * 与kNN分类器不同,**参数方法**的优势在于一旦通过训练学习到了参数,就可以将训练数据丢弃了。同时该方法对于新的测试数据的预测非常快,因为只需要与权重**W**进行一个矩阵乘法运算。 111 | * 介绍了偏差技巧,让我们能够将偏差向量和权重矩阵合二为一,然后就可以只跟踪一个矩阵。 112 | * 定义了损失函数(介绍了SVM和Softmax线性分类器最常用的2个损失函数)。损失函数能够衡量给出的参数集与训练集数据真实类别情况之间的一致性。在损失函数的定义中可以看到,对训练集数据做出良好预测与得到一个足够低的损失值这两件事是等价的。 113 | 114 | 现在我们知道了如何基于参数,将数据集中的图像映射成为分类的评分,也知道了两种不同的损失函数,它们都能用来衡量算法分类预测的质量。但是,如何高效地得到能够使损失值最小的参数呢?这个求得最优参数的过程被称为最优化,将在下节课中进行介绍。 115 | 116 | ## 拓展阅读 117 | 118 | 下面的内容读者可根据兴趣选择性阅读。 119 | 120 | * [Deep Learning using Linear Support Vector Machines__][40]一文的作者是Tang Charlie,论文写于2013年,展示了一些L2SVM比Softmax表现更出色的结果。 121 | 122 | **线性分类笔记全文翻译完毕**。 123 | 124 | 125 | 126 | ## 译者反馈 127 | 128 | 1. 转载须全文转载并注明原文链接,否则保留维权权利; 129 | 2. 接受知友建议,将示例代码中的注释也进行了翻译; 130 | 3. 请知友们通过评论和私信等方式批评指正,贡献者均会补充提及。 131 | 4. 感谢[@马会超][41]和@[Bron][42]的批评指正! 132 | 133 | ## 特别感谢 134 | 135 | **知友[智靖远][43]贡献了课程Lecture 1的字幕,并提出了关于合力进行字幕翻译的倡议,具体情况将专门发一篇短文来进行说明。** 136 | 137 | 「赞赏将用于感谢对本译文校对修改的知友」 138 | 139 | [1]: https://pic4.zhimg.com/4a97d93d652f45ededf2ebab9a13f22b_m.jpeg 140 | [2]: https://zhuanlan.zhihu.com/intelligentunit 141 | [3]: https://zhuanlan.zhihu.com/write 142 | [4]: https://pic1.zhimg.com/86b3f2e3cf390a8319a365846a0f39a8_r.jpg 143 | [5]: https://pic2.zhimg.com/5ab5b93bd_xs.jpg 144 | [6]: https://www.zhihu.com/people/du-ke 145 | [7]: http://link.zhihu.com/?target=http%3A//cs231n.github.io/linear-classify/ 146 | [8]: http://link.zhihu.com/?target=http%3A//cs.stanford.edu/people/karpathy/ 147 | [9]: https://www.zhihu.com/people/kun-kun-97-81 148 | [10]: http://zhihu.com/equation?tex=f%28x_i%2CW%29 149 | [11]: http://zhihu.com/equation?tex=f%28x_i%3BW%29%3DWx_i 150 | [12]: http://zhihu.com/equation?tex=%5Cdisplaystyle+Li%3D-log%28%5Cfrac%7Be%5E%7Bf_%7By_i%7D%7D%7D%7B%5Csum_je%5E%7Bf_j%7D%7D%29 151 | [13]: http://zhihu.com/equation?tex=L_i%3D-f_%7By_i%7D%2Blog%28%5Csum_je%5E%7Bf_j%7D%29 152 | [14]: http://zhihu.com/equation?tex=f_j 153 | [15]: http://zhihu.com/equation?tex=f 154 | [16]: http://zhihu.com/equation?tex=L_i 155 | [17]: http://zhihu.com/equation?tex=R%28W%29 156 | [18]: http://zhihu.com/equation?tex=f_j%28z%29%3D%5Cfrac%7Be%5E%7Bz_j%7D%7D%7B%5Csum_ke%5E%7Bz_k%7D%7D 157 | [19]: http://zhihu.com/equation?tex=z 158 | [20]: http://zhihu.com/equation?tex=p 159 | [21]: http://zhihu.com/equation?tex=q 160 | [22]: http://zhihu.com/equation?tex=%5Cdisplaystyle+H%28p%2Cq%29%3D-%5Csum_xp%28x%29+logq%28x%29 161 | [23]: http://zhihu.com/equation?tex=e%5E%7Bf_%7By_i%7D%7D%2F%5Csum_je%5E%7Bf_j%7D 162 | [24]: http://zhihu.com/equation?tex=p%3D%5B0%2C...1%2C...%2C0%5D 163 | [25]: http://zhihu.com/equation?tex=y_i 164 | [26]: http://zhihu.com/equation?tex=H%28p%2Cq%29%3DH%28p%29%2BD_%7BKL%7D%28p%7C%7Cq%29 165 | [27]: http://zhihu.com/equation?tex=P%28y_i%7Cx_i%2CW%29%3D%5Cfrac%7Be%5E%7Bf_%7By_i%7D%7D%7D%7B%5Csum_je%5E%7Bf_j%7D%7D 166 | [28]: http://zhihu.com/equation?tex=x_i 167 | [29]: http://zhihu.com/equation?tex=W 168 | [30]: http://zhihu.com/equation?tex=e%5E%7Bf_%7By_i%7D%7D 169 | [31]: http://zhihu.com/equation?tex=%5Csum_j+e%5E%7Bf_j%7D 170 | [32]: http://zhihu.com/equation?tex=C 171 | [33]: http://zhihu.com/equation?tex=%5Cfrac%7Be%5E%7Bf_%7By_i%7D%7D%7D%7B%5Csum_je%5E%7Bf_j%7D%7D%3D%5Cfrac%7BCe%5E%7Bf_%7By_i%7D%7D%7D%7BC%5Csum_je%5E%7Bf_j%7D%7D%3D%5Cfrac%7Be%5E%7Bf_%7By_i%7D%2BlogC%7D%7D%7B%5Csum_je%5E%7Bf_j%2BlogC%7D%7D 172 | [34]: http://zhihu.com/equation?tex=logC%3D-max_jf_j 173 | [35]: https://pic1.zhimg.com/a90ce9e0ff533f3efee4747305382064_b.png 174 | [36]: http://zhihu.com/equation?tex=%5B1%2C-2%2C0%5D%5Cto%5Be%5E1%2Ce%5E%7B-2%7D%2Ce%5E0%5D%3D%5B2.71%2C0.14%2C1%5D%5Cto%5B0.7%2C0.04%2C0.26%5D 175 | [37]: http://zhihu.com/equation?tex=%5B0.5%2C-1%2C0%5D%5Cto%5Be%5E%7B0.5%7D%2Ce%5E%7B-1%7D%2Ce%5E0%5D%3D%5B1.65%2C0.73%2C1%5D%5Cto%5B0.55%2C0.12%2C0.33%5D 176 | [38]: http://zhihu.com/equation?tex=%5CDelta+%3D1 177 | [39]: https://pic1.zhimg.com/a68bbfd4465689c6d65b3eae9c24c934_b.jpg 178 | [40]: http://link.zhihu.com/?target=http%3A//arxiv.org/abs/1306.0239 179 | [41]: http://www.zhihu.com/people/8c846dceb4672d13cf38d44ad278bce8 180 | [42]: https://www.zhihu.com/people/bron23 181 | [43]: https://www.zhihu.com/people/zhi-liang-72 182 | -------------------------------------------------------------------------------- /CS231n 4.1:最优化笔记(上).md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # CS231n课程笔记翻译:最优化笔记(上) - 知乎专栏 4 | 5 | 6 | ![CS231n课程笔记翻译:最优化笔记(上)][4] 7 | 8 | [杜客][6] [Source](https://zhuanlan.zhihu.com/p/21360434?refer=intelligentunit "Permalink to CS231n课程笔记翻译:最优化笔记(上) - 知乎专栏") 9 | 10 | 译者注:本文[智能单元][2]首发,译自斯坦福CS231n课程笔记[Optimization Note__][7],课程教师[Andrej Karpathy__][8]授权翻译。本篇教程由[杜客][6]翻译完成,[堃堃][9]和[李艺颖][10]进行校对修改。译文含公式和代码,建议PC端阅读。 11 | 12 | ## 原文如下 13 | 14 | 内容列表: 15 | 16 | * 简介 17 | * 损失函数可视化 18 | * 最优化 19 | * 策略#1:随机搜索 20 | * 策略#2:随机局部搜索 21 | * 策略#3:跟随梯度 **_译者注:上篇截止处_** 22 | * 梯度计算 23 | * 使用有限差值进行数值计算 24 | * 微分计算梯度 25 | * 梯度下降 26 | * 小结 27 | 28 | ## 简介 29 | 30 | 在上一节中,我们介绍了图像分类任务中的两个关键部分: 31 | 32 | 1. 基于参数的**评分函数。**该函数将原始图像像素映射为分类评分值(例如:一个线性函数)。 33 | 2. **损失函数**。该函数能够根据分类评分和训练集图像数据实际分类的一致性,衡量某个具体参数集的质量好坏。损失函数有多种版本和不同的实现方式(例如:Softmax或SVM)。 34 | 35 | 上节中,线性函数的形式是![f\(x_i, W\)=Wx_i][11],而SVM实现的公式是: 36 | 37 | ![L=displaystylefrac{1}{N}sum_isum_{jnot= y_i}\[max\(0,f\(x_i;W\)_j-f\(x_i;W\)_{y_i}+1\)\]+alpha R\(W\)][12] 38 | 39 | 对于图像数据![x_i][13],如果基于参数集![W][14]做出的分类预测与真实情况比较一致,那么计算出来的损失值![L][15]就很低。现在介绍第三个,也是最后一个关键部分:**最优化Optimization**。最优化是寻找能使得损失函数值最小化的参数![W][14]的过程。 40 | 41 | **铺垫**:一旦理解了这三个部分是如何相互运作的,我们将会回到第一个部分(基于参数的函数映射),然后将其拓展为一个远比线性函数复杂的函数:首先是神经网络,然后是卷积神经网络。而损失函数和最优化过程这两个部分将会保持相对稳定。 42 | 43 | ## 损失函数可视化 44 | 45 | 本课中讨论的损失函数一般都是定义在高维度的空间中(比如,在CIFAR-10中一个线性分类器的权重矩阵大小是[10x3073],就有30730个参数),这样要将其可视化就很困难。然而办法还是有的,在1个维度或者2个维度的方向上对高维空间进行切片,就能得到一些直观感受。例如,随机生成一个权重矩阵![W][14],该矩阵就与高维空间中的一个点对应。然后沿着某个维度方向前进的同时记录损失函数值的变化。换句话说,就是生成一个随机的方向![W_1][16]并且沿着此方向计算损失值,计算方法是根据不同的![a][17]值来计算![L\(W+aW_1\)][18]。这个过程将生成一个图表,其x轴是![a][17]值,y轴是损失函数值。同样的方法还可以用在两个维度上,通过改变![a,b][19]来计算损失值![L\(W+aW_1+bW_2\)][20],从而给出二维的图像。在图像中,![a,b][19]可以分别用x和y轴表示,而损失函数的值可以用颜色变化表示: 46 | 47 | 48 | 49 | ———————————————————————————————————————— 50 | 51 | ![][21]一个无正则化的多类SVM的损失函数的图示。左边和中间只有一个样本数据,右边是CIFAR-10中的100个数据。**左**:a值变化在某个维度方向上对应的的损失值变化。**中和右**:两个维度方向上的损失值切片图,蓝色部分是低损失值区域,红色部分是高损失值区域。注意损失函数的分段线性结构。多个样本的损失值是总体的平均值,所以右边的碗状结构是很多的分段线性结构的平均(比如中间这个就是其中之一)。 52 | 53 | 54 | 55 | ————————————————————————————————————————— 56 | 57 | 我们可以通过数学公式来解释损失函数的分段线性结构。对于一个单独的数据,有损失函数的计算公式如下: 58 | 59 | ![Li=sum_{jnot=y_i}\[max\(0,w^T_jx_i-w^T_{y_i}x_i+1\)\]][22] 60 | 61 | 通过公式可见,每个样本的数据损失值是以![W][14]为参数的线性函数的总和(零阈值来源于![max\(0,-\)][23]函数)。![W][14]的每一行(即![w_j][24]),有时候它前面是一个正号(比如当它对应错误分类的时候),有时候它前面是一个负号(比如当它是是正确分类的时候)。为进一步阐明,假设有一个简单的数据集,其中包含有3个只有1个维度的点,数据集数据点有3个类别。那么完整的无正则化SVM的损失值计算如下: 62 | 63 | 64 | ![L_0=max\(0,w^T_1x_0-w^T_0x_0+1\)+max\(0,w^T_2x_0-w^T_0x_0+1\)][25] 65 | ![L_1=max\(0,w^T_0x_1-w^T_1x_1+1\)+max\(0,w^T_2x_1-w^T_1x_1+1\)][26] 66 | ![L_2=max\(0,w^T_0x_2-w^T_2x_2+1\)+max\(0,w^T_1x_2-w^T_2x_2+1\)][27] 67 | ![L=\(L_0+L_1+L_2\)/3][28] 68 | 69 | 因为这些例子都是一维的,所以数据![x_i][13]和权重![w_j][24]都是数字。观察![w_0][29],可以看到上面的式子中一些项是![w_0][29]的线性函数,且每一项都会与0比较,取两者的最大值。可作图如下:—————————————————————————————————————— 70 | 71 | 72 | 73 | ![][30]从一个维度方向上对数据损失值的展示。x轴方向就是一个权重,y轴就是损失值。数据损失是多个部分组合而成。其中每个部分要么是某个权重的独立部分,要么是该权重的线性函数与0阈值的比较。完整的SVM数据损失就是这个形状的30730维版本。 74 | 75 | —————————————————————————————————————— 76 | 77 | 需要多说一句的是,你可能根据SVM的损失函数的碗状外观猜出它是一个[凸函数__][31]。关于如何高效地最小化凸函数的论文有很多,你也可以学习斯坦福大学关于([凸函数最优化__][32])的课程。但是一旦我们将![f][33]函数扩展到神经网络,目标函数就就不再是凸函数了,图像也不会像上面那样是个碗状,而是凹凸不平的复杂地形形状。 78 | 79 | _不可导的损失函数。_作为一个技术笔记,你要注意到:由于max操作,损失函数中存在一些_不可导点(kinks),_这些点使得损失函数不可微,因为在这些不可导点,梯度是没有定义的。但是[次梯度(subgradient)__][34]依然存在且常常被使用。在本课中,我们将交换使用_次梯度_和_梯度_两个术语。 80 | 81 | ## 最优化 Optimization 82 | 83 | 重申一下:损失函数可以量化某个具体权重集**W**的质量。而最优化的目标就是找到能够最小化损失函数值的**W** 。我们现在就朝着这个目标前进,实现一个能够最优化损失函数的方法。对于有一些经验的同学,这节课看起来有点奇怪,因为使用的例子(SVM 损失函数)是一个凸函数问题。但是要记得,最终的目标是不仅仅对凸函数做最优化,而是能够最优化一个神经网络,而对于神经网络是不能简单的使用凸函数的最优化技巧的。 84 | 85 | **策略#1:一个差劲的初始方案:随机搜索** 86 | 87 | 既然确认参数集**W**的好坏蛮简单的,那第一个想到的(差劲)方法,就是可以随机尝试很多不同的权重,然后看其中哪个最好。过程如下: 88 | 89 | 90 | 91 | ```py 92 | # 假设X_train的每一列都是一个数据样本(比如3073 x 50000) 93 | # 假设Y_train是数据样本的类别标签(比如一个长50000的一维数组) 94 | # 假设函数L对损失函数进行评价 95 | 96 | bestloss = float("inf") # Python assigns the highest possible float value 97 | for num in xrange(1000): 98 | W = np.random.randn(10, 3073) * 0.0001 # generate random parameters 99 | loss = L(X_train, Y_train, W) # get the loss over the entire training set 100 | if loss < bestloss: # keep track of the best solution 101 | bestloss = loss 102 | bestW = W 103 | print 'in attempt %d the loss was %f, best %f' % (num, loss, bestloss) 104 | 105 | # 输出: 106 | # in attempt 0 the loss was 9.401632, best 9.401632 107 | # in attempt 1 the loss was 8.959668, best 8.959668 108 | # in attempt 2 the loss was 9.044034, best 8.959668 109 | # in attempt 3 the loss was 9.278948, best 8.959668 110 | # in attempt 4 the loss was 8.857370, best 8.857370 111 | # in attempt 5 the loss was 8.943151, best 8.857370 112 | # in attempt 6 the loss was 8.605604, best 8.605604 113 | # ... (trunctated: continues for 1000 lines) 114 | 115 | 116 | 在上面的代码中,我们尝试了若干随机生成的权重矩阵**W**,其中某些的损失值较小,而另一些的损失值大些。我们可以把这次随机搜索中找到的最好的权重**W**取出,然后去跑测试集: 117 | 118 | 119 | 120 | # 假设X_test尺寸是[3073 x 10000], Y_test尺寸是[10000 x 1] 121 | scores = Wbest.dot(Xte_cols) # 10 x 10000, the class scores for all test examples 122 | # 找到在每列中评分值最大的索引(即预测的分类) 123 | Yte_predict = np.argmax(scores, axis = 0) 124 | # 以及计算准确率 125 | np.mean(Yte_predict == Yte) 126 | # 返回 0.1555 127 | 128 | ``` 129 | 130 | 验证集上表现最好的权重**W**跑测试集的准确率是**15.5%,**而完全随机猜的准确率是10%,如此看来,这个准确率对于这样一个不经过大脑的策略来说,还算不错嘛! 131 | 132 | **核心思路:迭代优化**。当然,我们肯定能做得更好些。核心思路是:虽然找到最优的权重**W**非常困难,甚至是不可能的(尤其当**W**中存的是整个神经网络的权重的时候),但如果问题转化为:对一个权重矩阵集**W**取优,使其损失值稍微减少。那么问题的难度就大大降低了。换句话说,我们的方法从一个随机的**W**开始,然后对其迭代取优,每次都让它的损失值变得更小一点。 133 | 134 | > 我们的策略是从随机权重开始,然后迭代取优,从而获得更低的损失值。 135 | 136 | **蒙眼徒步者的比喻**:一个助于理解的比喻是把你自己想象成一个蒙着眼睛的徒步者,正走在山地地形上,目标是要慢慢走到山底。在CIFAR-10的例子中,这山是30730维的(因为**W**是3073x10)。我们在山上踩的每一点都对应一个的损失值,该损失值可以看做该点的海拔高度。 137 | 138 | **策略#2:随机本地搜索** 139 | 140 | 第一个策略可以看做是每走一步都尝试几个随机方向,如果某个方向是向山下的,就向该方向走一步。这次我们从一个随机![W][14]开始,然后生成一个随机的扰动![delta W][35] ,只有当![W+delta W][36]的损失值变低,我们才会更新。这个过程的具体代码如下: 141 | 142 | 143 | 144 | 145 | 146 | ```py 147 | W = np.random.randn(10, 3073) * 0.001 # 生成随机初始W 148 | bestloss = float("inf") 149 | for i in xrange(1000): 150 | step_size = 0.0001 151 | Wtry = W + np.random.randn(10, 3073) * step_size 152 | loss = L(Xtr_cols, Ytr, Wtry) 153 | if loss < bestloss: 154 | W = Wtry 155 | bestloss = loss 156 | print 'iter %d loss is %f' % (i, bestloss) 157 | 158 | ``` 159 | 160 | 使用同样的数据(1000),这个方法可以得到**21.4%**的分类准确率。这个比策略一好,但是依然过于浪费计算资源。 161 | 162 | **策略#3:跟随梯度** 163 | 164 | 前两个策略中,我们是尝试在权重空间中找到一个方向,沿着该方向能降低损失函数的损失值。其实不需要随机寻找方向,因为可以直接计算出最好的方向,这就是从数学上计算出最陡峭的方向。这个方向就是损失函数的**梯度(gradient)**。在蒙眼徒步者的比喻中,这个方法就好比是感受我们脚下山体的倾斜程度,然后向着最陡峭的下降方向下山。 165 | 166 | 在一维函数中,斜率是函数在某一点的瞬时变化率。梯度是函数的斜率的一般化表达,它不是一个值,而是一个向量。在输入空间中,梯度是各个维度的斜率组成的向量(或者称为导数**derivatives**)。对一维函数的求导公式如下: 167 | 168 | ![displaystylefrac{df\(x\)}{dx}=lim_{hto 0}frac{f\(x+h\)-f\(x\)}{h}][37] 169 | 170 | 当函数有多个参数的时候,我们称导数为偏导数。而梯度就是在每个维度上偏导数所形成的向量。 171 | 172 | 173 | 174 | **最优化笔记(上)完。** 175 | 176 | 177 | 178 | 179 | ## 译者反馈 180 | 181 | 1. **转载须全文转载并注明原文链接,否则保留维权权利**; 182 | 183 | 2. 请知友们通过评论和私信等方式批评指正,贡献者均会补充提及。 184 | 185 | 「小钱钱将用于感谢校对和修改贡献者」 186 | 187 | 188 | [1]: https://pic4.zhimg.com/4a97d93d652f45ededf2ebab9a13f22b_m.jpeg 189 | [2]: https://zhuanlan.zhihu.com/intelligentunit 190 | [3]: https://zhuanlan.zhihu.com/write 191 | [4]: https://pic4.zhimg.com/d43a9c7ffaef1eef1d3f0b434e38dd3b_r.jpg 192 | [5]: https://pic2.zhimg.com/5ab5b93bd_xs.jpg 193 | [6]: https://www.zhihu.com/people/du-ke 194 | [7]: http://link.zhihu.com/?target=http%3A//cs231n.github.io/optimization-1/ 195 | [8]: http://link.zhihu.com/?target=http%3A//cs.stanford.edu/people/karpathy/ 196 | [9]: https://www.zhihu.com/people/kun-kun-97-81 197 | [10]: https://www.zhihu.com/people/li-yi-ying-73 198 | [11]: http://zhihu.com/equation?tex=f%28x_i%2C+W%29%3DWx_i 199 | [12]: http://zhihu.com/equation?tex=L%3D%5Cdisplaystyle%5Cfrac%7B1%7D%7BN%7D%5Csum_i%5Csum_%7Bj%5Cnot%3D+y_i%7D%5Bmax%280%2Cf%28x_i%3BW%29_j-f%28x_i%3BW%29_%7By_i%7D%2B1%29%5D%2B%5Calpha+R%28W%29 200 | [13]: http://zhihu.com/equation?tex=x_i 201 | [14]: http://zhihu.com/equation?tex=W 202 | [15]: http://zhihu.com/equation?tex=L 203 | [16]: http://zhihu.com/equation?tex=W_1 204 | [17]: http://zhihu.com/equation?tex=a 205 | [18]: http://zhihu.com/equation?tex=L%28W%2BaW_1%29 206 | [19]: http://zhihu.com/equation?tex=a%2Cb 207 | [20]: http://zhihu.com/equation?tex=L%28W%2BaW_1%2BbW_2%29 208 | [21]: https://pic2.zhimg.com/94dd0714f65ef94b3cbfff4780b1988d_b.png 209 | [22]: http://zhihu.com/equation?tex=Li%3D%5Csum_%7Bj%5Cnot%3Dy_i%7D%5Bmax%280%2Cw%5ET_jx_i-w%5ET_%7By_i%7Dx_i%2B1%29%5D 210 | [23]: http://zhihu.com/equation?tex=max%280%2C-%29 211 | [24]: http://zhihu.com/equation?tex=w_j 212 | [25]: http://zhihu.com/equation?tex=L_0%3Dmax%280%2Cw%5ET_1x_0-w%5ET_0x_0%2B1%29%2Bmax%280%2Cw%5ET_2x_0-w%5ET_0x_0%2B1%29 213 | [26]: http://zhihu.com/equation?tex=L_1%3Dmax%280%2Cw%5ET_0x_1-w%5ET_1x_1%2B1%29%2Bmax%280%2Cw%5ET_2x_1-w%5ET_1x_1%2B1%29 214 | [27]: http://zhihu.com/equation?tex=L_2%3Dmax%280%2Cw%5ET_0x_2-w%5ET_2x_2%2B1%29%2Bmax%280%2Cw%5ET_1x_2-w%5ET_2x_2%2B1%29 215 | [28]: http://zhihu.com/equation?tex=L%3D%28L_0%2BL_1%2BL_2%29%2F3 216 | [29]: http://zhihu.com/equation?tex=w_0 217 | [30]: https://pic3.zhimg.com/3f6fbcd487b1c214e8fea1ea66eb413e_b.png 218 | [31]: http://link.zhihu.com/?target=https%3A//en.wikipedia.org/wiki/Convex_function 219 | [32]: http://link.zhihu.com/?target=http%3A//stanford.edu/%7Eboyd/cvxbook/ 220 | [33]: http://zhihu.com/equation?tex=f 221 | [34]: http://link.zhihu.com/?target=https%3A//en.wikipedia.org/wiki/Subderivative 222 | [35]: http://zhihu.com/equation?tex=%5Cdelta+W 223 | [36]: http://zhihu.com/equation?tex=W%2B%5Cdelta+W 224 | [37]: http://zhihu.com/equation?tex=%5Cdisplaystyle%5Cfrac%7Bdf%28x%29%7D%7Bdx%7D%3D%5Clim_%7Bh%5Cto+0%7D%5Cfrac%7Bf%28x%2Bh%29-f%28x%29%7D%7Bh%7D -------------------------------------------------------------------------------- /CS231n 4.2:最优化笔记(下).md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | # CS231n课程笔记翻译:最优化笔记(下) - 知乎专栏 5 | 6 | 7 | ![CS231n课程笔记翻译:最优化笔记(下)][4] 8 | 9 | 10 | [杜客][6] [Source](https://zhuanlan.zhihu.com/p/21387326?refer=intelligentunit "Permalink to CS231n课程笔记翻译:最优化笔记(下) - 知乎专栏") 11 | 12 | 13 | 译者注:本文[智能单元][2]首发,译自斯坦福CS231n课程笔记[Optimization Note__][7],课程教师[Andrej Karpathy__][8]授权翻译。本篇教程由[杜客][6]翻译完成,[李艺颖][9]和[堃堃][10]进行校对修改。译文含公式和代码,建议PC端阅读。 14 | 15 | ## 原文如下 16 | 17 | 内容列表: 18 | 19 | * 简介 20 | * 损失函数可视化 21 | * 最优化 22 | * 策略#1:随机搜索 23 | * 策略#2:随机局部搜索 24 | * 策略#3:跟随梯度 25 | * 梯度计算 _**译者注:下篇起始处**_ 26 | * 使用有限差值进行数值计算 27 | * 微分分析计算梯度 28 | * 梯度下降 29 | * 小结 30 | 31 | ## 梯度计算 32 | 33 | 计算梯度有两种方法:一个是缓慢的近似方法(**数值梯度法**),但实现相对简单。另一个方法(**分析梯度法**)计算迅速,结果精确,但是实现时容易出错,且需要使用微分。现在对两种方法进行介绍: 34 | 35 | **利用有限差值计算梯度** 36 | 37 | 上节中的公式已经给出数值计算梯度的方法。下面代码是一个输入为函数**f**和向量**x,**计算**f**的梯度的通用函数,它返回函数**f**在点**x处**的梯度: 38 | 39 | 40 | 41 | 42 | 43 | ```py 44 | def eval_numerical_gradient(f, x): 45 | """ 46 | 一个f在x处的数值梯度法的简单实现 47 | - f是只有一个参数的函数 48 | - x是计算梯度的点 49 | """ 50 | 51 | fx = f(x) # 在原点计算函数值 52 | grad = np.zeros(x.shape) 53 | h = 0.00001 54 | 55 | # 对x中所有的索引进行迭代 56 | it = np.nditer(x, flags=['multi_index'], op_flags=['readwrite']) 57 | while not it.finished: 58 | 59 | # 计算x+h处的函数值 60 | ix = it.multi_index 61 | old_value = x[ix] 62 | x[ix] = old_value + h # 增加h 63 | fxh = f(x) # 计算f(x + h) 64 | x[ix] = old_value # 存到前一个值中 (非常重要) 65 | 66 | # 计算偏导数 67 | grad[ix] = (fxh - fx) / h # 坡度 68 | it.iternext() # 到下个维度 69 | 70 | return grad 71 | 72 | ``` 73 | 74 | 根据上面的梯度公式,代码对所有维度进行迭代,在每个维度上产生一个很小的变化h,通过观察函数值变化,计算函数在该维度上的偏导数。最后,所有的梯度存储在变量**grad**中。 75 | 76 | 77 | 78 | **实践考量**:注意在数学公式中,**h**的取值是趋近于0的,然而在实际中,用一个很小的数值(比如例子中的1e-5)就足够了。在不产生数值计算出错的理想前提下,你会使用尽可能小的h。还有,实际中用**中心差值公式(****centered difference formula)**![\[f\(x+h\)-f\(x-h\)\]/2h][11]效果较好。细节可查看[wiki__][12]。 79 | 80 | 81 | 82 | 可以使用上面这个公式来计算任意函数在任意点上的梯度。下面计算权重空间中的某些随机点上,CIFAR-10损失函数的梯度: 83 | 84 | 85 | 86 | 87 | 88 | ```py 89 | # 要使用上面的代码我们需要一个只有一个参数的函数 90 | # (在这里参数就是权重)所以也包含了X_train和Y_train 91 | def CIFAR10_loss_fun(W): 92 | return L(X_train, Y_train, W) 93 | 94 | W = np.random.rand(10, 3073) * 0.001 # 随机权重向量 95 | df = eval_numerical_gradient(CIFAR10_loss_fun, W) # 得到梯度 96 | 97 | ``` 98 | 99 | 梯度告诉我们损失函数在每个维度上的斜率,以此来进行更新: 100 | 101 | 102 | 103 | ```py 104 | loss_original = CIFAR10_loss_fun(W) # 初始损失值 105 | print 'original loss: %f' % (loss_original, ) 106 | 107 | # 查看不同步长的效果 108 | for step_size_log in [-10, -9, -8, -7, -6, -5,-4,-3,-2,-1]: 109 | step_size = 10 ** step_size_log 110 | W_new = W - step_size * df # 权重空间中的新位置 111 | loss_new = CIFAR10_loss_fun(W_new) 112 | print 'for step size %f new loss: %f' % (step_size, loss_new) 113 | 114 | # 输出: 115 | # original loss: 2.200718 116 | # for step size 1.000000e-10 new loss: 2.200652 117 | # for step size 1.000000e-09 new loss: 2.200057 118 | # for step size 1.000000e-08 new loss: 2.194116 119 | # for step size 1.000000e-07 new loss: 2.135493 120 | # for step size 1.000000e-06 new loss: 1.647802 121 | # for step size 1.000000e-05 new loss: 2.844355 122 | # for step size 1.000000e-04 new loss: 25.558142 123 | # for step size 1.000000e-03 new loss: 254.086573 124 | # for step size 1.000000e-02 new loss: 2539.370888 125 | # for step size 1.000000e-01 new loss: 25392.214036 126 | 127 | ``` 128 | 129 | **在梯度负方向上更新**:在上面的代码中,为了计算**W_new**,要注意我们是向着梯度**df**的负方向去更新,这是因为我们希望损失函数值是降低而不是升高。 130 | 131 | **步长的影响**:梯度指明了函数在哪个方向是变化率最大的,但是没有指明在这个方向上应该走多远。在后续的课程中可以看到,选择步长(也叫作_学习率_)将会是神经网络训练中最重要(也是最头痛)的超参数设定之一。还是用蒙眼徒步者下山的比喻,这就好比我们可以感觉到脚朝向的不同方向上,地形的倾斜程度不同。但是该跨出多长的步长呢?不确定。如果谨慎地小步走,情况可能比较稳定但是进展较慢(这就是步长较小的情况)。相反,如果想尽快下山,那就大步走吧,但结果也不一定尽如人意。在上面的代码中就能看见反例,在某些点如果步长过大,反而可能越过最低点导致更高的损失值。 132 | 133 | 134 | 135 | ———————————————————————————————————————— 136 | 137 | ![][13] 138 | 139 | 将步长效果视觉化的图例。从某个具体的点W开始计算梯度(白箭头方向是负梯度方向),梯度告诉了我们损失函数下降最陡峭的方向。小步长下降稳定但进度慢,大步长进展快但是风险更大。采取大步长可能导致错过最优点,让损失值上升。步长(后面会称其为**学习率**)将会是我们在调参中最重要的超参数之一。 140 | 141 | ———————————————————————————————————————— 142 | 143 | **效率问题**:你可能已经注意到,计算数值梯度的复杂性和参数的量线性相关。在本例中有30730个参数,所以损失函数每走一步就需要计算30731次损失函数的梯度。现代神经网络很容易就有上千万的参数,因此这个问题只会越发严峻。显然这个策略不适合大规模数据,我们需要更好的策略。 144 | 145 | 146 | 147 | ### 微分分析计算梯度 148 | 149 | 使用有限差值近似计算梯度比较简单,但缺点在于终究只是近似(因为我们对于_h_值是选取了一个很小的数值,但真正的梯度定义中_h_趋向0的极限),且耗费计算资源太多。第二个梯度计算方法是利用微分来分析,能得到计算梯度的公式(不是近似),用公式计算梯度速度很快,唯一不好的就是实现的时候容易出错。为了解决这个问题,在实际操作时常常将分析梯度法的结果和数值梯度法的结果作比较,以此来检查其实现的正确性,这个步骤叫做**梯度检查**。 150 | 151 | 用SVM的损失函数在某个数据点上的计算来举例: 152 | 153 | ![L_i=displaystylesum_{jnot =y_i}\[max\(0,w^T_jx_i-w^T_{y_i}x_i+Delta\)\]][14] 154 | 155 | 可以对函数进行微分。比如,对![w_{y_i}][15]进行微分得到: 156 | 157 | ![displaystylenabla_{w_{y_i}}L_i=-\(sum_{jnot=y_i}1\(w^T_jx_i-w^T_{y_i}x_i+Delta>0\)\)x_i][16] 158 | 159 | **_译者注:原公式中1为空心字体,尝试mathbb{}等多种方法仍无法实现,请知友指点。 160 | _** 161 | 162 | 其中![1][17]是一个示性函数,如果括号中的条件为真,那么函数值为1,如果为假,则函数值为0。虽然上述公式看起来复杂,但在代码实现的时候比较简单:只需要计算没有满足边界值的分类的数量(因此对损失函数产生了贡献),然后乘以![x_i][18]就是梯度了。注意,这个梯度只是对应正确分类的W的行向量的梯度,那些![jnot =y_i][19]行的梯度是: 163 | 164 | ![displaystylenabla_{w_j}L_i=1\(w^T_jx_i-w^T_{y_i}x_i+Delta>0\)x_i][20] 165 | 166 | 一旦将梯度的公式微分出来,代码实现公式并用于梯度更新就比较顺畅了。 167 | 168 | ## 梯度下降 169 | 170 | 现在可以计算损失函数的梯度了,程序重复地计算梯度然后对参数进行更新,这一过程称为_梯度下降_,他的**普通**版本是这样的: 171 | 172 | 173 | 174 | ```py 175 | # 普通的梯度下降 176 | 177 | while True: 178 | weights_grad = evaluate_gradient(loss_fun, data, weights) 179 | weights += - step_size * weights_grad # 进行梯度更新 180 | 181 | ``` 182 | 183 | 这个简单的循环在所有的神经网络核心库中都有。虽然也有其他实现最优化的方法(比如LBFGS),但是到目前为止,梯度下降是对神经网络的损失函数最优化中最常用的方法。课程中,我们会在它的循环细节增加一些新的东西(比如更新的具体公式),但是核心思想不变,那就是我们一直跟着梯度走,直到结果不再变化。 184 | 185 | **小批量数据梯度下降(****Mini-batch gradient descent****)**:在大规模的应用中(比如ILSVRC挑战赛),训练数据可以达到百万级量级。如果像这样计算整个训练集,来获得仅仅一个参数的更新就太浪费了。一个常用的方法是计算训练集中的**小批量(batches)**数据。例如,在目前最高水平的卷积神经网络中,一个典型的小批量包含256个例子,而整个训练集是多少呢?一百二十万个。这个小批量数据就用来实现一个参数更新: 186 | 187 | 188 | ```py 189 | # 普通的小批量数据梯度下降 190 | 191 | while True: 192 | data_batch = sample_training_data(data, 256) # 256个数据 193 | weights_grad = evaluate_gradient(loss_fun, data_batch, weights) 194 | weights += - step_size * weights_grad # 参数更新 195 | 196 | ``` 197 | 198 | 这个方法之所以效果不错,是因为训练集中的数据都是相关的。要理解这一点,可以想象一个极端情况:在ILSVRC中的120万个图像是1000张不同图片的复制(每个类别1张图片,每张图片有1200张复制)。那么显然计算这1200张复制图像的梯度就应该是一样的。对比120万张图片的数据损失的均值与只计算1000张的子集的数据损失均值时,结果应该是一样的。实际情况中,数据集肯定不会包含重复图像,那么小批量数据的梯度就是对整个数据集梯度的一个近似。因此,在实践中通过计算小批量数据的梯度可以实现更快速地收敛,并以此来进行更频繁的参数更新。 199 | 200 | 小批量数据策略有个极端情况,那就是每个批量中只有1个数据样本,这种策略被称为**随机梯度下降(****Stochastic Gradient Descent 简称SGD****)**,有时候也被称为在线梯度下降。这种策略在实际情况中相对少见,因为向量化操作的代码一次计算100个数据 比100次计算1个数据要高效很多。即使SGD在技术上是指每次使用1个数据来计算梯度,你还是会听到人们使用SGD来指代小批量数据梯度下降(或者用MGD来指代小批量数据梯度下降,而BGD来指代则相对少见)。小批量数据的大小是一个超参数,但是一般并不需要通过交叉验证来调参。它一般由存储器的限制来决定的,或者干脆设置为同样大小,比如32,64,128等。之所以使用2的指数,是因为在实际中许多向量化操作实现的时候,如果输入数据量是2的倍数,那么运算更快。 201 | 202 | ## 小结 203 | 204 | ———————————————————————————————————————— 205 | 206 | ![][21] 207 | 208 | 信息流的总结图例。数据集中的(x,y)是给定的。权重从一个随机数字开始,且可以改变。在前向传播时,评分函数计算出类别的分类评分并存储在向量**f**中。损失函数包含两个部分:数据损失和正则化损失。其中,数据损失计算的是分类评分f和实际标签y之间的差异,正则化损失只是一个关于权重的函数。在梯度下降过程中,我们计算权重的梯度(如果愿意的话,也可以计算数据上的梯度),然后使用它们来实现参数的更新。 209 | 210 | ————————————————————————————————————————— 211 | 212 | 在本节课中: 213 | 214 | * 将损失函数比作了一个**高维度的最优化地形**,并尝试到达它的最底部。最优化的工作过程可以看做一个蒙着眼睛的徒步者希望摸索着走到山的底部。在例子中,可见SVM的损失函数是分段线性的,并且是碗状的。 215 | * 提出了迭代优化的思想,从一个随机的权重开始,然后一步步地让损失值变小,直到最小。 216 | * 函数的**梯度**给出了该函数最陡峭的上升方向。介绍了利用有限的差值来近似计算梯度的方法,该方法实现简单但是效率较低(有限差值就是_h_,用来计算数值梯度)。 217 | * 参数更新需要有技巧地设置**步长**。也叫学习率。如果步长太小,进度稳定但是缓慢,如果步长太大,进度快但是可能有风险。 218 | * 讨论权衡了数值梯度法和分析梯度法。数值梯度法计算简单,但结果只是近似且耗费计算资源。分析梯度法计算准确迅速但是实现容易出错,而且需要对梯度公式进行推导的数学基本功。因此,在实际中使用分析梯度法,然后使用**梯度检查**来检查其实现正确与否,其本质就是将分析梯度法的结果与数值梯度法的计算结果对比。 219 | 220 | 221 | 222 | * 介绍了**梯度下降**算法,它在循环中迭代地计算梯度并更新参数。 223 | 224 | **预告**:这节课的核心内容是:理解并能计算损失函数关于权重的梯度,是设计、训练和理解神经网络的核心能力。下节中,将介绍如何使用链式法则来高效地计算梯度,也就是通常所说的**反向传播(****backpropagation)机制**。该机制能够对包含卷积神经网络在内的几乎所有类型的神经网络的损失函数进行高效的最优化。 225 | 226 | 227 | 228 | **最优化笔记全文翻译完**。 229 | 230 | 231 | 232 | ## 译者反馈 233 | 234 | 1. **转载须全文转载并注明原文链接**,否则保留维权权利; 235 | 236 | 2. 请知友们通过评论和私信等方式批评指正,贡献者均会补充提及 237 | 3. 感谢知友[roach sinai][22]的评论。 238 | 239 | 「更新加快啦,不来一个鼓励么:)」 240 | 241 | [1]: https://pic4.zhimg.com/4a97d93d652f45ededf2ebab9a13f22b_m.jpeg 242 | [2]: https://zhuanlan.zhihu.com/intelligentunit 243 | [3]: https://zhuanlan.zhihu.com/write 244 | [4]: https://pic4.zhimg.com/d43a9c7ffaef1eef1d3f0b434e38dd3b_r.jpg 245 | [5]: https://pic2.zhimg.com/5ab5b93bd_xs.jpg 246 | [6]: https://www.zhihu.com/people/du-ke 247 | [7]: http://link.zhihu.com/?target=http%3A//cs231n.github.io/optimization-1/ 248 | [8]: http://link.zhihu.com/?target=http%3A//cs.stanford.edu/people/karpathy/ 249 | [9]: https://www.zhihu.com/people/li-yi-ying-73 250 | [10]: https://www.zhihu.com/people/kun-kun-97-81 251 | [11]: http://zhihu.com/equation?tex=%5Bf%28x%2Bh%29-f%28x-h%29%5D%2F2h 252 | [12]: http://link.zhihu.com/?target=https%3A//en.wikipedia.org/wiki/Numerical_differentiation 253 | [13]: https://pic1.zhimg.com/d8b52b9b9ca31e2132c436c39af2943c_b.jpg 254 | [14]: http://zhihu.com/equation?tex=L_i%3D%5Cdisplaystyle%5Csum_%7Bj%5Cnot+%3Dy_i%7D%5Bmax%280%2Cw%5ET_jx_i-w%5ET_%7By_i%7Dx_i%2B%5CDelta%29%5D 255 | [15]: http://zhihu.com/equation?tex=w_%7By_i%7D 256 | [16]: http://zhihu.com/equation?tex=%5Cdisplaystyle%5Cnabla_%7Bw_%7By_i%7D%7DL_i%3D-%28%5Csum_%7Bj%5Cnot%3Dy_i%7D1%28w%5ET_jx_i-w%5ET_%7By_i%7Dx_i%2B%5CDelta%3E0%29%29x_i 257 | [17]: http://zhihu.com/equation?tex=1 258 | [18]: http://zhihu.com/equation?tex=x_i 259 | [19]: http://zhihu.com/equation?tex=j%5Cnot+%3Dy_i 260 | [20]: http://zhihu.com/equation?tex=%5Cdisplaystyle%5Cnabla_%7Bw_j%7DL_i%3D1%28w%5ET_jx_i-w%5ET_%7By_i%7Dx_i%2B%5CDelta%3E0%29x_i 261 | [21]: https://pic2.zhimg.com/03b3eccf18ee3760e219f9f95ec14305_b.png 262 | [22]: https://www.zhihu.com/people/roachsinai 263 | -------------------------------------------------------------------------------- /CS231n 6.1.a:神经网络笔记1(上).md: -------------------------------------------------------------------------------- 1 | 2 | [Source](https://zhuanlan.zhihu.com/p/21462488?refer=intelligentunit "Permalink to CS231n课程笔记翻译:神经网络笔记1(上) - 知乎专栏") 3 | 4 | # CS231n课程笔记翻译:神经网络笔记1(上) - 知乎专栏 5 | 6 | 7 | 8 | ![CS231n课程笔记翻译:神经网络笔记1(上)][4] 9 | 10 | # CS231n课程笔记翻译:神经网络笔记1(上) 11 | 12 | ![杜客][5][杜客][6] 13 | 14 | 9 months ago 15 | 16 | 译者注:本文[智能单元][2]首发,译自斯坦福CS231n课程笔记[Neural Nets notes 1__][7],课程教师[Andrej Karpathy__][8]授权翻译。本篇教程由[杜客][6]翻译完成,[巩子嘉][9]和[堃堃][10]进行校对修改。译文含公式和代码,建议PC端阅读。 17 | 18 | ## 原文如下 19 | 20 | 内容列表: 21 | 22 | * 不用大脑做类比的快速简介 23 | * 单个神经元建模 24 | * 生物动机和连接 25 | * 作为线性分类器的单个神经元 26 | * 常用的激活函数 **_译者注:上篇翻译截止处_** 27 | * 神经网络结构 28 | * 层组织 29 | * 前向传播计算例子 30 | * 表达能力 31 | * 设置层的数量和尺寸 32 | * 小节 33 | * 参考文献 34 | 35 | ## 快速简介 36 | 37 | 在不诉诸大脑的类比的情况下,依然是可以对神经网络算法进行介绍的。在线性分类一节中,在给出图像的情况下,是使用![s=Wx][11]来计算不同视觉类别的评分,其中![W][12]是一个矩阵,![x][13]是一个输入列向量,它包含了图像的全部像素数据。在使用数据库CIFAR-10的案例中,![x][13]是一个[3072x1]的列向量,![W][12]是一个[10x3072]的矩阵,所以输出的评分是一个包含10个分类评分的向量。 38 | 39 | 神经网络算法则不同,它的计算公式是![s=W_2max\(0,W_1x\)][14]。其中![W_1][15]的含义是这样的:举个例子来说,它可以是一个[100x3072]的矩阵,其作用是将图像转化为一个100维的过渡向量。函数![max\(0,-\)][16]是非线性的,它会作用到每个元素。这个非线性函数有多种选择,后续将会学到。但这个形式是一个最常用的选择,它就是简单地设置阈值,将所有小于0的值变成0。最终,矩阵![W_2][17]的尺寸是[10x100],因此将得到10个数字,这10个数字可以解释为是分类的评分。注意非线性函数在计算上是至关重要的,如果略去这一步,那么两个矩阵将会合二为一,对于分类的评分计算将重新变成关于输入的线性函数。这个非线性函数就是_改变_的关键点。参数![W_1,W_2][18]将通过随机梯度下降来学习到,他们的梯度在反向传播过程中,通过链式法则来求导计算得出。 40 | 41 | 42 | 43 | 一个三层的神经网络可以类比地看做![s=W_3max\(0,W_2max\(0,W_1x\)\)][19],其中![W_1,W_2,W_3][20]是需要进行学习的参数。中间隐层的尺寸是网络的超参数,后续将学习如何设置它们。现在让我们先从神经元或者网络的角度理解上述计算。 44 | 45 | # 单个神经元建模 46 | 47 | 神经网络算法领域最初是被对生物神经系统建模这一目标启发,但随后与其分道扬镳,成为一个工程问题,并在机器学习领域取得良好效果。然而,讨论将还是从对生物系统的一个高层次的简略描述开始,因为神经网络毕竟是从这里得到了启发。 48 | 49 | ## 生物动机与连接 50 | 51 | 大脑的基本计算单位是**神经元(****neuron****)**。人类的神经系统中大约有860亿个神经元,它们被大约10^14-10^15个**突触(****synapses****)**连接起来。下面图表的左边展示了一个生物学的神经元,右边展示了一个常用的数学模型。每个神经元都从它的**树突**获得输入信号,然后沿着它唯一的**轴突(****axon****)**产生输出信号。轴突在末端会逐渐分枝,通过突触和其他神经元的树突相连。 52 | 53 | 在神经元的计算模型中,沿着轴突传播的信号(比如![x_0][21])将基于突触的突触强度(比如![w_0][22]),与其他神经元的树突进行乘法交互(比如![w_0x_0][23])。其观点是,突触的强度(也就是权重![w][24]),是可学习的且可以控制一个神经元对于另一个神经元的影响强度(还可以控制影响方向:使其兴奋(正权重)或使其抑制(负权重))。在基本模型中,树突将信号传递到细胞体,信号在细胞体中相加。如果最终之和高于某个阈值,那么神经元将会_激活_,向其轴突输出一个峰值信号。在计算模型中,我们假设峰值信号的准确时间点不重要,是激活信号的频率在交流信息。基于这个_速率编码_的观点,将神经元的激活率建模为**激活函数(****activation function****)![f][25]**,它表达了轴突上激活信号的频率。由于历史原因,激活函数常常选择使用**sigmoid函数![sigma][26]**,该函数输入实数值(求和后的信号强度),然后将输入值压缩到0-1之间。在本节后面部分会看到这些激活函数的各种细节。 54 | 55 | ———————————————————————————————————————— 56 | 57 | ![][27]左边是生物神经元,右边是数学模型。 58 | 59 | ———————————————————————————————————————— 60 | 61 | 一个神经元前向传播的实例代码如下: 62 | 63 | 64 | 65 | ```py 66 | class Neuron(object): 67 | # ... 68 | def forward(inputs): 69 | """ 假设输入和权重是1-D的numpy数组,偏差是一个数字 """ 70 | cell_body_sum = np.sum(inputs * self.weights) + self.bias 71 | firing_rate = 1.0 / (1.0 + math.exp(-cell_body_sum)) # sigmoid激活函数 72 | return firing_rate 73 | 74 | ``` 75 | 76 | 换句话说,每个神经元都对它的输入和权重进行点积,然后加上偏差,最后使用非线性函数(或称为激活函数)。本例中使用的是sigmoid函数![sigma\(x\)=1/\(1+e^{-x}\)][28]。在本节的末尾部分将介绍不同激活函数的细节。 77 | 78 | **粗糙模型**:要注意这个对于生物神经元的建模是非常粗糙的:在实际中,有很多不同类型的神经元,每种都有不同的属性。生物神经元的树突可以进行复杂的非线性计算。突触并不就是一个简单的权重,它们是复杂的非线性动态系统。很多系统中,输出的峰值信号的精确时间点非常重要,说明速率编码的近似是不够全面的。鉴于所有这些已经介绍和更多未介绍的简化,如果你画出人类大脑和神经网络之间的类比,有神经科学背景的人对你的板书起哄也是非常自然的。如果你对此感兴趣,可以看看这份[评论__][29]或者最新的[另一份__][30]。 79 | 80 | ## 作为线性分类器的单个神经元 81 | 82 | 神经元模型的前向计算数学公式看起来可能比较眼熟。就像在线性分类器中看到的那样,神经元有能力"喜欢"(激活函数值接近1),或者不喜欢(激活函数值接近0)输入空间中的某些线性区域。因此,只要在神经元的输出端有一个合适的损失函数,就能让单个神经元变成一个线性分类器。 83 | 84 | **二分类Softmax分类器**。举例来说,可以把![displaystylesigma\(Sigma_iw_ix_i+b\)][31]看做其中一个分类的概率![P\(y_i=1|x_i;w\)][32],其他分类的概率为![P\(y_i=0|x_i;w\)=1-P\(y_i=1|x_i;w\)][33],因为它们加起来必须为1。根据这种理解,可以得到交叉熵损失,这个在线性分一节中已经介绍。然后将它最优化为二分类的Softmax分类器(也就是逻辑回归)。因为sigmoid函数输出限定在0-1之间,所以分类器做出预测的基准是神经元的输出是否大于0.5。 85 | 86 | **二分类SVM分类器**。或者可以在神经元的输出外增加一个最大边界折叶损失(max-margin hinge loss)函数,将其训练成一个二分类的支持向量机。 87 | 88 | **理解正则化**。在SVM/Softmax的例子中,正则化损失从生物学角度可以看做_逐渐遗忘_,因为它的效果是让所有突触权重![w][24]在参数更新过程中逐渐向着0变化。 89 | 90 | > 一个单独的神经元可以用来实现一个二分类分类器,比如二分类的Softmax或者SVM分类器。 91 | 92 | ## 常用激活函数 93 | 94 | 每个激活函数(或非线性函数)的输入都是一个数字,然后对其进行某种固定的数学操作。下面是在实践中可能遇到的几种激活函数: 95 | 96 | ———————————————————————————————————————— 97 | 98 | ![][34]左边是Sigmoid非线性函数,将实数压缩到[0,1]之间。右边是tanh函数,将实数压缩到[-1,1]。 99 | 100 | ———————————————————————————————————————— 101 | 102 | **Sigmoid。**sigmoid非线性函数的数学公式是![displaystylesigma\(x\)=1/\(1+e^{-x}\)][35],函数图像如上图的左边所示。在前一节中已经提到过,它输入实数值并将其"挤压"到0到1范围内。更具体地说,很大的负数变成0,很大的正数变成1。在历史上,sigmoid函数非常常用,这是因为它对于神经元的激活频率有良好的解释:从完全不激活(0)到在求和后的最大频率处的完全饱和(**saturated**)的激活(1)。然而现在sigmoid函数已经不太受欢迎,实际很少使用了,这是因为它有两个主要缺点: 103 | 104 | 105 | 106 | * _ Sigmoid函数饱和使梯度消失_。sigmoid神经元有一个不好的特性,就是当神经元的激活在接近0或1处时会饱和:在这些区域,梯度几乎为0。回忆一下,在反向传播的时候,这个(局部)梯度将会与整个损失函数关于该门单元输出的梯度相乘。因此,如果局部梯度非常小,那么相乘的结果也会接近零,这会有效地"杀死"梯度,几乎就有没有信号通过神经元传到权重再到数据了。还有,为了防止饱和,必须对于权重矩阵初始化特别留意。比如,如果初始化权重过大,那么大多数神经元将会饱和,导致网络就几乎不学习了。 107 | * _Sigmoid函数的输出不是零中心的_。这个性质并不是我们想要的,因为在神经网络后面层中的神经元得到的数据将不是零中心的。这一情况将影响梯度下降的运作,因为如果输入神经元的数据总是正数(比如在![f=w^Tx+b][36]中每个元素都![x>0][37]),那么关于![w][24]的梯度在反向传播的过程中,将会要么全部是正数,要么全部是负数(具体依整个表达式![f][25]而定)。这将会导致梯度下降权重更新时出现z字型的下降。然而,可以看到整个批量的数据的梯度被加起来后,对于权重的最终更新将会有不同的正负,这样就从一定程度上减轻了这个问题。因此,该问题相对于上面的神经元饱和问题来说只是个小麻烦,没有那么严重。 108 | 109 | **Tanh。**tanh非线性函数图像如上图右边所示。它将实数值压缩到[-1,1]之间。和sigmoid神经元一样,它也存在饱和问题,但是和sigmoid神经元不同的是,它的输出是零中心的。因此,在实际操作中,_tanh非线性函数比sigmoid非线性函数更受欢迎_。注意tanh神经元是一个简单放大的sigmoid神经元,具体说来就是:![tanh\(x\)=2sigma\(2x\)-1][38]。 110 | 111 | ———————————————————————————————————————— 112 | 113 | ![][39]左边是ReLU(校正线性单元:Rectified Linear Unit)激活函数,当![x=0][40]时函数值为0。当![x>0][37]函数的斜率为1。右边是从 [Krizhevsky__][41]等的论文中截取的图表,指明使用ReLU比使用tanh的收敛快6倍。 114 | 115 | ———————————————————————————————————————— 116 | 117 | **ReLU。**在近些年ReLU变得非常流行。它的函数公式是![f\(x\)=max\(0,x\)][42]。换句话说,这个激活函数就是一个关于0的阈值(如上图左侧)。使用ReLU有以下一些优缺点: 118 | 119 | * 优点:相较于sigmoid和tanh函数,ReLU对于随机梯度下降的收敛有巨大的加速作用( [Krizhevsky __][41]等的论文指出有6倍之多)。据称这是由它的线性,非饱和的公式导致的。 120 | * 优点:sigmoid和tanh神经元含有指数运算等耗费计算资源的操作,而ReLU可以简单地通过对一个矩阵进行阈值计算得到。 121 | * 缺点:在训练的时候,ReLU单元比较脆弱并且可能"死掉"。举例来说,当一个很大的梯度流过ReLU的神经元的时候,可能会导致梯度更新到一种特别的状态,在这种状态下神经元将无法被其他任何数据点再次激活。如果这种情况发生,那么从此所以流过这个神经元的梯度将都变成0。也就是说,这个ReLU单元在训练中将不可逆转的死亡,因为这导致了数据多样化的丢失。例如,如果学习率设置得太高,可能会发现网络中40%的神经元都会死掉(在整个训练集中这些神经元都不会被激活)。通过合理设置学习率,这种情况的发生概率会降低。 122 | 123 | **Leaky ReLU。**Leaky ReLU是为解决"ReLU死亡"问题的尝试。ReLU中当x<0时,函数值为0。而Leaky ReLU则是给出一个很小的负数梯度值,比如0.01。所以其函数公式为![f\(x\)=1\(x<0\)\(alpha x\)+1\(x>=0\)\(x\)][43]其中![alpha][44]是一个小的常量。有些研究者的论文指出这个激活函数表现很不错,但是其效果并不是很稳定。Kaiming He等人在2015年发布的论文[Delving Deep into Rectifiers__][45]中介绍了一种新方法PReLU,把负区间上的斜率当做每个神经元中的一个参数。然而该激活函数在在不同任务中均有益处的一致性并没有特别清晰。 124 | 125 | 126 | 127 | **Maxout。**一些其他类型的单元被提了出来,它们对于权重和数据的内积结果不再使用![f\(w^Tx+b\)][46]函数形式。一个相关的流行选择是Maxout(最近由[Goodfellow__][47]等发布)神经元。Maxout是对ReLU和leaky ReLU的一般化归纳,它的函数是:![max\(w^T_1x+b_1,w^T_2x+b_2\)][48]。ReLU和Leaky ReLU都是这个公式的特殊情况(比如ReLU就是当![w_1,b_1=0][49]的时候)。这样Maxout神经元就拥有ReLU单元的所有优点(线性操作和不饱和),而没有它的缺点(死亡的ReLU单元)。然而和ReLU对比,它每个神经元的参数数量增加了一倍,这就导致整体参数的数量激增。 128 | 129 | 以上就是一些常用的神经元及其激活函数。最后需要注意一点:在同一个网络中混合使用不同类型的神经元是非常少见的,虽然没有什么根本性问题来禁止这样做。 130 | 131 | **一句话**:"_那么该用那种呢?_"用ReLU非线性函数。注意设置好学习率,或许可以监控你的网络中死亡的神经元占的比例。如果单元死亡问题困扰你,就试试Leaky ReLU或者Maxout,不要再用sigmoid了。也可以试试tanh,但是其效果应该不如ReLU或者Maxout。 132 | 133 | **神经网络笔记1(上)完。** 134 | 135 | ## 译者反馈 136 | 137 | 1. 转载须全文转载注明原文链接,否则保留维权权利; 138 | 2. 请知友们通过评论和私信等方式批评指正,贡献者均会补充提及; 139 | 3. 感谢[张一凡][50]的细节提醒。 140 | 141 | 「欢迎来激活一个:)」 142 | 143 | [1]: https://pic4.zhimg.com/4a97d93d652f45ededf2ebab9a13f22b_m.jpeg 144 | [2]: https://zhuanlan.zhihu.com/intelligentunit 145 | [3]: https://zhuanlan.zhihu.com/write 146 | [4]: https://pic2.zhimg.com/95e9b62e33724863ceed6ca6de68a835_r.jpg 147 | [5]: https://pic2.zhimg.com/5ab5b93bd_xs.jpg 148 | [6]: https://www.zhihu.com/people/du-ke 149 | [7]: http://link.zhihu.com/?target=http%3A//cs231n.github.io/neural-networks-1/ 150 | [8]: http://link.zhihu.com/?target=http%3A//cs.stanford.edu/people/karpathy/ 151 | [9]: https://www.zhihu.com/people/hmonkey 152 | [10]: https://www.zhihu.com/people/kun-kun-97-81 153 | [11]: http://zhihu.com/equation?tex=s%3DWx 154 | [12]: http://zhihu.com/equation?tex=W 155 | [13]: http://zhihu.com/equation?tex=x 156 | [14]: http://zhihu.com/equation?tex=s%3DW_2max%280%2CW_1x%29 157 | [15]: http://zhihu.com/equation?tex=W_1 158 | [16]: http://zhihu.com/equation?tex=max%280%2C-%29 159 | [17]: http://zhihu.com/equation?tex=W_2 160 | [18]: http://zhihu.com/equation?tex=W_1%2CW_2 161 | [19]: http://zhihu.com/equation?tex=s%3DW_3max%280%2CW_2max%280%2CW_1x%29%29 162 | [20]: http://zhihu.com/equation?tex=W_1%2CW_2%2CW_3 163 | [21]: http://zhihu.com/equation?tex=x_0 164 | [22]: http://zhihu.com/equation?tex=w_0 165 | [23]: http://zhihu.com/equation?tex=w_0x_0 166 | [24]: http://zhihu.com/equation?tex=w 167 | [25]: http://zhihu.com/equation?tex=f 168 | [26]: http://zhihu.com/equation?tex=%5Csigma 169 | [27]: http://pic2.zhimg.com/d0cbce2f2654b8e70fe201fec2982c7d_b.png 170 | [28]: http://zhihu.com/equation?tex=%5Csigma%28x%29%3D1%2F%281%2Be%5E%7B-x%7D%29 171 | [29]: http://link.zhihu.com/?target=https%3A//physics.ucsd.edu/neurophysics/courses/physics_171/annurev.neuro.28.061604.135703.pdf 172 | [30]: http://link.zhihu.com/?target=http%3A//www.sciencedirect.com/science/article/pii/S0959438814000130 173 | [31]: http://zhihu.com/equation?tex=%5Cdisplaystyle%5Csigma%28%5CSigma_iw_ix_i%2Bb%29 174 | [32]: http://zhihu.com/equation?tex=P%28y_i%3D1%7Cx_i%3Bw%29 175 | [33]: http://zhihu.com/equation?tex=P%28y_i%3D0%7Cx_i%3Bw%29%3D1-P%28y_i%3D1%7Cx_i%3Bw%29 176 | [34]: http://pic3.zhimg.com/677187e96671a4cac9c95352743b3806_b.png 177 | [35]: http://zhihu.com/equation?tex=%5Cdisplaystyle%5Csigma%28x%29%3D1%2F%281%2Be%5E%7B-x%7D%29 178 | [36]: http://zhihu.com/equation?tex=f%3Dw%5ETx%2Bb 179 | [37]: http://zhihu.com/equation?tex=x%3E0 180 | [38]: http://zhihu.com/equation?tex=tanh%28x%29%3D2%5Csigma%282x%29-1 181 | [39]: http://pic3.zhimg.com/83682a138f6224230f5b0292d9c01bd2_b.png 182 | [40]: http://zhihu.com/equation?tex=x%3D0 183 | [41]: http://link.zhihu.com/?target=http%3A//www.cs.toronto.edu/%7Efritz/absps/imagenet.pdf 184 | [42]: http://zhihu.com/equation?tex=f%28x%29%3Dmax%280%2Cx%29 185 | [43]: http://zhihu.com/equation?tex=f%28x%29%3D1%28x%3C0%29%28%5Calpha+x%29%2B1%28x%3E%3D0%29%28x%29 186 | [44]: http://zhihu.com/equation?tex=%5Calpha 187 | [45]: http://link.zhihu.com/?target=http%3A//arxiv.org/abs/1502.01852 188 | [46]: http://zhihu.com/equation?tex=f%28w%5ETx%2Bb%29 189 | [47]: http://link.zhihu.com/?target=http%3A//www-etud.iro.umontreal.ca/%7Egoodfeli/maxout.html 190 | [48]: http://zhihu.com/equation?tex=max%28w%5ET_1x%2Bb_1%2Cw%5ET_2x%2Bb_2%29 191 | [49]: http://zhihu.com/equation?tex=w_1%2Cb_1%3D0 192 | [50]: https://www.zhihu.com/people/zhang-yifan-34-60 193 | -------------------------------------------------------------------------------- /CS231n 6.3.a 神经网络笔记3(上).md: -------------------------------------------------------------------------------- 1 | 2 | [Source](https://zhuanlan.zhihu.com/p/21741716?refer=intelligentunit "Permalink to CS231n课程笔记翻译:神经网络笔记3(上) - 知乎专栏") 3 | 4 | # CS231n课程笔记翻译:神经网络笔记3(上) - 知乎专栏 5 | 6 | ![CS231n课程笔记翻译:神经网络笔记3(上)][4] 7 | 8 | # CS231n课程笔记翻译:神经网络笔记3(上) 9 | 10 | ![杜客][5][杜客][6] 11 | 12 | 8 months ago 13 | 14 | 译者注:本文[智能单元][2]首发,译自斯坦福CS231n课程笔记[Neural Nets notes 3__][7],课程教师[Andrej Karpathy__][8]授权翻译。本篇教程由[杜客][6]翻译完成,[堃堃][9]和[巩子嘉][10]进行校对修改。译文含公式和代码,建议PC端阅读。 15 | 16 | ## 原文如下 17 | 18 | 内容列表: 19 | 20 | * 梯度检查 21 | * 合理性(Sanity)检查 22 | * 检查学习过程 23 | * 损失函数 24 | * 训练集与验证集准确率 25 | * 权重:更新比例 26 | * 每层的激活数据与梯度分布 27 | * 可视化 **_译者注:上篇翻译截止处_** 28 | * 参数更新 29 | * 一阶(随机梯度下降)方法,动量方法,Nesterov动量方法 30 | * 学习率退火 31 | * 二阶方法 32 | * 逐参数适应学习率方法(Adagrad,RMSProp) 33 | * 超参数调优 34 | * 评价 35 | * 模型集成 36 | * 总结 37 | * 拓展引用 38 | 39 | # 学习过程 40 | 41 | 在前面章节中,我们讨论了神经网络的静态部分:如何创建网络的连接、数据和损失函数。本节将致力于讲解神经网络的动态部分,即神经网络学习参数和搜索最优超参数的过程。 42 | 43 | ## 梯度检查 44 | 45 | 理论上将进行梯度检查很简单,就是简单地把解析梯度和数值计算梯度进行比较。然而从实际操作层面上来说,这个过程更加复杂且容易出错。下面是一些提示、技巧和需要仔细注意的事情: 46 | 47 | **使用中心化公式。**在使用有限差值近似来计算数值梯度的时候,常见的公式是: 48 | 49 | ![displaystyle frac{df\(x\)}{dx}=frac{f\(x+h\)-f\(x\)}{h}\(bad, do not use\)][11] 50 | 51 | 其中![h][12]是一个很小的数字,在实践中近似为1e-5。在实践中证明,使用_中心化_公式效果更好: 52 | 53 | ![displaystyle frac{df\(x\)}{dx}=frac{f\(x+h\)-f\(x-h\)}{2h}\(use instead\)][13] 54 | 55 | 该公式在检查梯度的每个维度的时候,会要求计算两次损失函数(所以计算资源的耗费也是两倍),但是梯度的近似值会准确很多。要理解这一点,对![f\(x+h\)][14]和![f\(x-h\)][15]使用泰勒展开,可以看到第一个公式的误差近似![O\(h\)][16],第二个公式的误差近似![O\(h^2\)][17](是个二阶近似)。_**(译者注:泰勒展开相关内容可阅读《高等数学》第十二章第四节:函数展开成幂级数。)**_ 56 | 57 | **使用相对误差来比较**。比较数值梯度![f'_n][18]和解析梯度![f'_a][19]的细节有哪些?如何得知此两者不匹配?你可能会倾向于监测它们的差的绝对值![|f'_a-f'_n|][20]或者差的平方值,然后定义该值如果超过某个规定阈值,就判断梯度实现失败。然而该思路是有问题的。想想,假设这个差值是1e-4,如果两个梯度值在1.0左右,这个差值看起来就很合适,可以认为两个梯度是匹配的。然而如果梯度值是1e-5或者更低,那么1e-4就是非常大的差距,梯度实现肯定就是失败的了。因此,使用_相对误差_总是更合适一些: 58 | 59 | ![displaystyle frac{|f'_a-f'_n|}{max\(|f'_a|,|f'_n|\)}][21] 60 | 61 | 上式考虑了差值占两个梯度绝对值的比例。注意通常相对误差公式只包含两个式子中的一个(任意一个均可),但是我更倾向取两个式子的最大值或者取两个式子的和。这样做是为了防止在其中一个式子为0时,公式分母为0(这种情况,在ReLU中是经常发生的)。然而,还必须注意两个式子都为零且通过梯度检查的情况。在实践中: 62 | 63 | * 相对误差>1e-2:通常就意味着梯度可能出错。 64 | * 1e-2>相对误差>1e-4:要对这个值感到不舒服才行。 65 | * 1e-4>相对误差:这个值的相对误差对于有不可导点的目标函数是OK的。但如果目标函数中没有kink(使用tanh和softmax),那么相对误差值还是太高。 66 | * 1e-7或者更小:好结果,可以高兴一把了。 67 | 68 | 要知道的是网络的深度越深,相对误差就越高。所以如果你是在对一个10层网络的输入数据做梯度检查,那么1e-2的相对误差值可能就OK了,因为误差一直在累积。相反,如果一个可微函数的相对误差值是1e-2,那么通常说明梯度实现不正确。 69 | 70 | 71 | 72 | **使用双精度。**一个常见的错误是使用单精度浮点数来进行梯度检查。这样会导致即使梯度实现正确,相对误差值也会很高(比如1e-2)。在我的经验而言,出现过使用单精度浮点数时相对误差为1e-2,换成双精度浮点数时就降低为1e-8的情况。 73 | 74 | **保持在浮点数的有效范围。**建议通读《[What Every Computer Scientist Should Konw About Floating-Point Artthmetic__][22]》一文,该文将阐明你可能犯的错误,促使你写下更加细心的代码。例如,在神经网络中,在一个批量的数据上对损失函数进行归一化是很常见的。但是,如果每个数据点的梯度很小,然后又用数据点的数量去除,就使得数值更小,这反过来会导致更多的数值问题。这就是我为什么总是会把原始的解析梯度和数值梯度数据打印出来,确保用来比较的数字的值不是过小(通常绝对值小于1e-10就绝对让人担心)。如果确实过小,可以使用一个常数暂时将损失函数的数值范围扩展到一个更"好"的范围,在这个范围中浮点数变得更加致密。比较理想的是1.0的数量级上,即当浮点数指数为0时。 75 | 76 | 77 | 78 | **目标函数的不可导点(kinks)**。在进行梯度检查时,一个导致不准确的原因是不可导点问题。不可导点是指目标函数不可导的部分,由ReLU(![max\(0,x\)][23])等函数,或SVM损失,Maxout神经元等引入。考虑当![x=-1e6][24]的时,对ReLU函数进行梯度检查。因为![x<0][25],所以解析梯度在该点的梯度为0。然而,在这里数值梯度会突然计算出一个非零的梯度值,因为![f\(x+h\)][14]可能越过了不可导点(例如:如果![h>1e-6][26]),导致了一个非零的结果。你可能会认为这是一个极端的案例,但实际上这种情况很常见。例如,一个用CIFAR-10训练的SVM中,因为有50,000个样本,且根据目标函数每个样本产生9个式子,所以包含有450,000个![max\(0,x\)][23]式子。而一个用SVM进行分类的神经网络因为采用了ReLU,还会有更多的不可导点。 79 | 80 | 81 | 82 | 注意,在计算损失的过程中是可以知道不可导点有没有被越过的。在具有![max\(x,y\)][27]形式的函数中持续跟踪所有"赢家"的身份,就可以实现这一点。其实就是看在前向传播时,到底x和y谁更大。如果在计算![f\(x+h\)][14]和![f\(x-h\)][15]的时候,至少有一个"赢家"的身份变了,那就说明不可导点被越过了,数值梯度会不准确。 83 | 84 | 85 | 86 | **使用少量数据点。**解决上面的不可导点问题的一个办法是使用更少的数据点。因为含有不可导点的损失函数(例如:因为使用了ReLU或者边缘损失等函数)的数据点越少,不可导点就越少,所以在计算有限差值近似时越过不可导点的几率就越小。还有,如果你的梯度检查对2-3个数据点都有效,那么基本上对整个批量数据进行梯度检查也是没问题的。所以使用很少量的数据点,能让梯度检查更迅速高效。 87 | 88 | **谨慎设置步长h。**在实践中h并不是越小越好,因为当![h][12]特别小的时候,就可能就会遇到数值精度问题。有时候如果梯度检查无法进行,可以试试将![h][12]调到1e-4或者1e-6,然后突然梯度检查可能就恢复正常。这篇[维基百科文章__][28]中有一个图表,其x轴为![h][12]值,y轴为数值梯度误差。 89 | 90 | **在操作的特性模式中梯度检查。**有一点必须要认识到:梯度检查是在参数空间中的一个特定(往往还是随机的)的单独点进行的。即使是在该点上梯度检查成功了,也不能马上确保全局上梯度的实现都是正确的。还有,一个随机的初始化可能不是参数空间最优代表性的点,这可能导致进入某种病态的情况,即梯度看起来是正确实现了,实际上并没有。例如,SVM使用小数值权重初始化,就会把一些接近于0的得分分配给所有的数据点,而梯度将会在所有的数据点上展现出某种模式。一个不正确实现的梯度也许依然能够产生出这种模式,但是不能泛化到更具代表性的操作模式,比如在一些的得分比另一些得分更大的情况下就不行。因此为了安全起见,最好让网络学习("预热")一小段时间,等到损失函数开始下降的之后再进行梯度检查。在第一次迭代就进行梯度检查的危险就在于,此时可能正处在不正常的边界情况,从而掩盖了梯度没有正确实现的事实。 91 | 92 | 93 | 94 | **不要让正则化吞没数据。**通常损失函数是数据损失和正则化损失的和(例如L2对权重的惩罚)。需要注意的危险是正则化损失可能吞没掉数据损失,在这种情况下梯度主要来源于正则化部分(正则化部分的梯度表达式通常简单很多)。这样就会掩盖掉数据损失梯度的不正确实现。因此,推荐先关掉正则化对数据损失做单独检查,然后对正则化做单独检查。对于正则化的单独检查可以是修改代码,去掉其中数据损失的部分,也可以提高正则化强度,确认其效果在梯度检查中是无法忽略的,这样不正确的实现就会被观察到了。 95 | 96 | **记得关闭随机失活(dropout)和数据扩张(augmentation)**。在进行梯度检查时,记得关闭网络中任何不确定的效果的操作,比如随机失活,随机数据扩展等。不然它们会在计算数值梯度的时候导致巨大误差。关闭这些操作不好的一点是无法对它们进行梯度检查(例如随机失活的反向传播实现可能有错误)。因此,一个更好的解决方案就是在计算![f\(x+h\)][14]和![f\(x-h\)][15]前强制增加一个特定的随机种子,在计算解析梯度时也同样如此。 97 | 98 | **检查少量的维度。**在实际中,梯度可以有上百万的参数,在这种情况下只能检查其中一些维度然后假设其他维度是正确的。**注意****:**确认在所有不同的参数中都抽取一部分来梯度检查。在某些应用中,为了方便,人们将所有的参数放到一个巨大的参数向量中。在这种情况下,例如偏置就可能只占用整个向量中的很小一部分,所以不要随机地从向量中取维度,一定要把这种情况考虑到,确保所有参数都收到了正确的梯度。 99 | 100 | 101 | 102 | ## 学习之前:合理性检查的提示与技巧 103 | 104 | 在进行费时费力的最优化之前,最好进行一些合理性检查: 105 | 106 | * **寻找特定情况的正确损失值。**在使用小参数进行初始化时,确保得到的损失值与期望一致。最好先单独检查数据损失(让正则化强度为0)。例如,对于一个跑CIFAR-10的Softmax分类器,一般期望它的初始损失值是2.302,这是因为初始时预计每个类别的概率是0.1(因为有10个类别),然后Softmax损失值正确分类的负对数概率:-ln(0.1)=2.302。对于Weston Watkins SVM,假设所有的边界都被越过(因为所有的分值都近似为零),所以损失值是9(因为对于每个错误分类,边界值是1)。如果没看到这些损失值,那么初始化中就可能有问题。 107 | * 第二个合理性检查:提高正则化强度时导致损失值变大。 108 | * **对小数据子集过拟合。**最后也是最重要的一步,在整个数据集进行训练之前,尝试在一个很小的数据集上进行训练(比如20个数据),然后确保能到达0的损失值。进行这个实验的时候,最好让正则化强度为0,不然它会阻止得到0的损失。除非能通过这一个正常性检查,不然进行整个数据集训练是没有意义的。但是注意,能对小数据集进行过拟合并不代表万事大吉,依然有可能存在不正确的实现。比如,因为某些错误,数据点的特征是随机的,这样算法也可能对小数据进行过拟合,但是在整个数据集上跑算法的时候,就没有任何泛化能力。 109 | 110 | 111 | 112 | ## 检查整个学习过程 113 | 114 | 在训练神经网络的时候,应该跟踪多个重要数值。这些数值输出的图表是观察训练进程的一扇窗口,是直观理解不同的超参数设置效果的工具,从而知道如何修改超参数以获得更高效的学习过程。 115 | 116 | 117 | 118 | 在下面的图表中,x轴通常都是表示**_周期(epochs)_**单位,该单位衡量了在训练中每个样本数据都被观察过次数的期望(一个周期意味着每个样本数据都被观察过了一次)。相较于迭代次数(iterations),一般更倾向跟踪周期,这是因为迭代次数与数据的批尺寸(batchsize)有关,而批尺寸的设置又可以是任意的。 119 | 120 | ## 损失函数 121 | 122 | 训练期间第一个要跟踪的数值就是损失值,它在前向传播时对每个独立的批数据进行计算。下图展示的是随着损失值随时间的变化,尤其是曲线形状会给出关于学习率设置的情况: 123 | 124 | ———————————————————————————————————————— 125 | 126 | ![][29]**左图**展示了不同的学习率的效果。过低的学习率导致算法的改善是线性的。高一些的学习率会看起来呈几何指数下降,更高的学习率会让损失值很快下降,但是接着就停在一个不好的损失值上(绿线)。这是因为最优化的"能量"太大,参数在混沌中随机震荡,不能最优化到一个很好的点上。**右图**显示了一个典型的随时间变化的损失函数值,在CIFAR-10数据集上面训练了一个小的网络,这个损失函数值曲线看起来比较合理(虽然可能学习率有点小,但是很难说),而且指出了批数据的数量可能有点太小(因为损失值的噪音很大)。 127 | 128 | ———————————————————————————————————————— 129 | 130 | 损失值的震荡程度和批尺寸(batch size)有关,当批尺寸为1,震荡会相对较大。当批尺寸就是整个数据集时震荡就会最小,因为每个梯度更新都是单调地优化损失函数(除非学习率设置得过高)。 131 | 132 | 有的研究者喜欢用对数域对损失函数值作图。因为学习过程一般都是采用指数型的形状,图表就会看起来更像是能够直观理解的直线,而不是呈曲棍球一样的曲线状。还有,如果多个交叉验证模型在一个图上同时输出图像,它们之间的差异就会比较明显。 133 | 134 | 有时候损失函数看起来很有意思:[lossfunctions.tumblr.com__][30]。 135 | 136 | ### 训练集和验证集准确率 137 | 138 | 在训练分类器的时候,需要跟踪的第二重要的数值是验证集和训练集的准确率。这个图表能够展现知道模型过拟合的程度: 139 | 140 | ———————————————————————————————————————— 141 | 142 | ![][31]在训练集准确率和验证集准确率中间的空隙指明了模型过拟合的程度。在图中,蓝色的验证集曲线显示相较于训练集,验证集的准确率低了很多,这就说明模型有很强的过拟合。遇到这种情况,就应该增大正则化强度(更强的L2权重惩罚,更多的随机失活等)或收集更多的数据。另一种可能就是验证集曲线和训练集曲线如影随形,这种情况说明你的模型容量还不够大:应该通过增加参数数量让模型容量更大些。 143 | 144 | ———————————————————————————————————————— 145 | 146 | ### 权重更新比例 147 | 148 | 最后一个应该跟踪的量是权重中更新值的数量和全部值的数量之间的比例。注意:是_更新的_,而不是原始梯度(比如,在普通sgd中就是梯度乘以学习率)。需要对每个参数集的更新比例进行单独的计算和跟踪。一个经验性的结论是这个比例应该在1e-3左右。如果更低,说明学习率可能太小,如果更高,说明学习率可能太高。下面是具体例子: 149 | 150 | 151 | ```py 152 | # 假设参数向量为W,其梯度向量为dW 153 | param_scale = np.linalg.norm(W.ravel()) 154 | update = -learning_rate*dW # 简单SGD更新 155 | update_scale = np.linalg.norm(update.ravel()) 156 | W += update # 实际更新 157 | print update_scale / param_scale # 要得到1e-3左右 158 | 159 | ``` 160 | 161 | 相较于跟踪最大和最小值,有研究者更喜欢计算和跟踪梯度的范式及其更新。这些矩阵通常是相关的,也能得到近似的结果。 162 | 163 | 164 | 165 | ### 每层的激活数据及梯度分布 166 | 167 | 一个不正确的初始化可能让学习过程变慢,甚至彻底停止。还好,这个问题可以比较简单地诊断出来。其中一个方法是输出网络中所有层的激活数据和梯度分布的柱状图。直观地说,就是如果看到任何奇怪的分布情况,那都不是好兆头。比如,对于使用tanh的神经元,我们应该看到激活数据的值在整个[-1,1]区间中都有分布。如果看到神经元的输出全部是0,或者全都饱和了往-1和1上跑,那肯定就是有问题了。 168 | 169 | ## 第一层可视化 170 | 171 | 最后,如果数据是图像像素数据,那么把第一层特征可视化会有帮助: 172 | 173 | ———————————————————————————————————————— 174 | 175 | ![][32]将神经网络第一层的权重可视化的例子。**左图**中的特征充满了噪音,这暗示了网络可能出现了问题:网络没有收敛,学习率设置不恰当,正则化惩罚的权重过低。**右图**的特征不错,平滑,干净而且种类繁多,说明训练过程进行良好。 176 | 177 | 178 | 179 | ———————————————————————————————————————— 180 | 181 | **神经网络笔记3 (上)结束。** 182 | 183 | ## 译者反馈 184 | 185 | 1. **转载须全文转载且注明原文链接**,否则保留维权权利; 186 | 2. 请知友们通过评论和私信等方式批评指正,贡献者均会补充提及; 187 | 3. CS231n的翻译即将进入尾声,**欢迎知友们建议后续的翻译方向;** 188 | 4. 知友@[猪皮][33]建议下一步的翻译方向是领域内的一些经典论文; 189 | 5. 知友@[一蓑烟灰][34]在评论中详细解释了自己学习CS231n及本科毕设相关情况,建议下一步的翻译方向是课程作业解析。 190 | 191 | 「请大家重点建议接下来的翻译方向!」 192 | 193 | 194 | [1]: https://pic4.zhimg.com/4a97d93d652f45ededf2ebab9a13f22b_m.jpeg 195 | [2]: https://zhuanlan.zhihu.com/intelligentunit 196 | [3]: https://zhuanlan.zhihu.com/write 197 | [4]: https://pic3.zhimg.com/b629f243297cf32d2507bdaa1bc38e12_r.jpg 198 | [5]: https://pic2.zhimg.com/5ab5b93bd_xs.jpg 199 | [6]: https://www.zhihu.com/people/du-ke 200 | [7]: http://link.zhihu.com/?target=http%3A//cs231n.github.io/neural-networks-3/ 201 | [8]: http://link.zhihu.com/?target=http%3A//cs.stanford.edu/people/karpathy/ 202 | [9]: https://www.zhihu.com/people/kun-kun-97-81 203 | [10]: https://www.zhihu.com/people/hmonkey 204 | [11]: http://zhihu.com/equation?tex=%5Cdisplaystyle+%5Cfrac%7Bdf%28x%29%7D%7Bdx%7D%3D%5Cfrac%7Bf%28x%2Bh%29-f%28x%29%7D%7Bh%7D%28bad%2C%5C+do%5C+not%5C+use%29 205 | [12]: http://zhihu.com/equation?tex=h 206 | [13]: http://zhihu.com/equation?tex=%5Cdisplaystyle+%5Cfrac%7Bdf%28x%29%7D%7Bdx%7D%3D%5Cfrac%7Bf%28x%2Bh%29-f%28x-h%29%7D%7B2h%7D%28use%5C+instead%29 207 | [14]: http://zhihu.com/equation?tex=f%28x%2Bh%29 208 | [15]: http://zhihu.com/equation?tex=f%28x-h%29 209 | [16]: http://zhihu.com/equation?tex=O%28h%29 210 | [17]: http://zhihu.com/equation?tex=O%28h%5E2%29 211 | [18]: http://zhihu.com/equation?tex=f%27_n 212 | [19]: http://zhihu.com/equation?tex=f%27_a 213 | [20]: http://zhihu.com/equation?tex=%7Cf%27_a-f%27_n%7C 214 | [21]: http://zhihu.com/equation?tex=%5Cdisplaystyle+%5Cfrac%7B%7Cf%27_a-f%27_n%7C%7D%7Bmax%28%7Cf%27_a%7C%2C%7Cf%27_n%7C%29%7D 215 | [22]: http://link.zhihu.com/?target=http%3A//docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html 216 | [23]: http://zhihu.com/equation?tex=max%280%2Cx%29 217 | [24]: http://zhihu.com/equation?tex=x%3D-1e6 218 | [25]: http://zhihu.com/equation?tex=x%3C0 219 | [26]: http://zhihu.com/equation?tex=h%3E1e-6 220 | [27]: http://zhihu.com/equation?tex=max%28x%2Cy%29 221 | [28]: http://link.zhihu.com/?target=https%3A//en.wikipedia.org/wiki/Numerical_differentiation 222 | [29]: http://pic2.zhimg.com/753f398b46cc28c1916d6703cf2080f5_b.png 223 | [30]: http://link.zhihu.com/?target=http%3A//lossfunctions.tumblr.com 224 | [31]: http://pic3.zhimg.com/05a6960a01c0204ced8d875ac3d91fba_b.jpg 225 | [32]: http://pic3.zhimg.com/96573094f9d7f4b3b188069726840a2e_b.png 226 | [33]: https://www.zhihu.com/people/ksma 227 | [34]: https://www.zhihu.com/people/nan-tian-qi-6 228 | -------------------------------------------------------------------------------- /CS231n 3.2:线性分类笔记(中).md: -------------------------------------------------------------------------------- 1 | # CS231n课程笔记翻译:线性分类笔记(中) - 知乎专栏 2 | 3 | [杜客][6] [Source](https://zhuanlan.zhihu.com/p/20945670?refer=intelligentunit "Permalink to CS231n课程笔记翻译:线性分类笔记(中) - 知乎专栏") 4 | 5 | 译者注:本文[智能单元][1]首发,译自斯坦福CS231n课程笔记[Linear Classification Note__][2],课程教师[Andrej Karpathy__][3]授权翻译。本篇教程由[杜客][4]翻译完成,[ShiqingFan][5]和[堃堃][6]进行校对修改。译文含公式和代码,建议PC端阅读。 6 | 7 | ## 原文如下 8 | 9 | 内容列表: 10 | 11 | * 线性分类器简介 12 | * 线性评分函数 13 | * 阐明线性分类器 14 | * 损失函数 15 | * 多类SVM _**译者注:中篇翻译截止处**_ 16 | * Softmax分类器 17 | * SVM和Softmax的比较 18 | * 基于Web的可交互线性分类器原型 19 | * 小结 20 | 21 | ## 损失函数 Loss function 22 | 23 | 在上一节定义了从图像像素值到所属类别的评分函数(score function),该函数的参数是权重矩阵![W][7]。在函数中,数据![\(x_i,y_i\)][8]是给定的,不能修改。但是我们可以调整权重矩阵这个参数,使得评分函数的结果与训练数据集中图像的真实类别一致,即评分函数在正确的分类的位置应当得到最高的评分(score)。 24 | 25 | 回到之前那张猫的图像分类例子,它有针对"猫","狗","船"三个类别的分数。我们看到例子中权重值非常差,因为猫分类的得分非常低(-96.8),而狗(437.9)和船(61.95)比较高。我们将使用**损失函数(****Loss Function)**(有时也叫**代价函数****Cost Function**或**目标函数****Objective**)来衡量我们对结果的不满意程度。直观地讲,当评分函数输出结果与真实结果之间差异越大,损失函数输出越大,反之越小。 26 | 27 | ## 多类支持向量机损失 Multiclass Support Vector Machine Loss 28 | 29 | 损失函数的具体形式多种多样。首先,介绍常用的多类支持向量机(SVM)损失函数。SVM的损失函数想要SVM在正确分类上的得分始终比不正确分类上的得分高出一个边界值![Delta][9]。我们可以把损失函数想象成一个人,这位SVM先生(或者女士)对于结果有自己的品位,如果某个结果能使得损失值更低,那么SVM就更加喜欢它。 30 | 31 | 让我们更精确一些。回忆一下,第i个数据中包含图像![x_i][10]的像素和代表正确类别的标签![y_i][11]。评分函数输入像素数据,然后通过公式![f\(x_i,W\)][12]来计算不同分类类别的分值。这里我们将分值简写为![s][13]。比如,针对第j个类别的得分就是第j个元素:![s_j=f\(x_i,W\)_j][14]。针对第i个数据的多类SVM的损失函数定义如下: 32 | 33 | 34 | ![displaystyle L_i=sum_{jnot=y_i}max\(0,s_j-s_{y_i}+Delta\)][15] 35 | 36 | **举例**:用一个例子演示公式是如何计算的。假设有3个分类,并且得到了分值![s=\[13,-7,11\]][16]。其中第一个类别是正确类别,即![y_i=0][17]。同时假设![Delta][9]是10(后面会详细介绍该超参数)。上面的公式是将所有不正确分类(![jnot=y_i][18])加起来,所以我们得到两个部分: 37 | 38 | ![displaystyle Li=max\(0,-7-13+10\)+max\(0,11-13+10\)][19] 39 | 40 | 可以看到第一个部分结果是0,这是因为[-7-13+10]得到的是负数,经过![max\(0,-\)][20]函数处理后得到0。这一对类别分数和标签的损失值是0,这是因为正确分类的得分13与错误分类的得分-7的差为20,高于边界值10。而SVM只关心差距至少要大于10,更大的差值还是算作损失值为0。第二个部分计算[11-13+10]得到8。虽然正确分类的得分比不正确分类的得分要高(13>11),但是比10的边界值还是小了,分差只有2,这就是为什么损失值等于8。简而言之,SVM的损失函数想要正确分类类别![y_i][11]的分数比不正确类别分数高,而且至少要高![Delta][9]。如果不满足这点,就开始计算损失值。 41 | 42 | 那么在这次的模型中,我们面对的是线性评分函数(![f\(x_i,W\)=Wx_i][21]),所以我们可以将损失函数的公式稍微改写一下: 43 | 44 | 45 | ![displaystyle L_i=sum_{jnot=y_i}max\(0,w^T_jx_i-w^T_{y_i}x_i+Delta\)][22] 46 | 47 | 其中![w_j][23]是权重![W][7]的第j行,被变形为列向量。然而,一旦开始考虑更复杂的评分函数![f][24]公式,这样做就不是必须的了。 48 | 49 | 在结束这一小节前,还必须提一下的属于是关于0的阀值:![max\(0,-\)][20]函数,它常被称为**折叶损失(hinge loss)**。有时候会听到人们使用平方折叶损失SVM(即L2-SVM),它使用的是![max\(0,-\)^2][25],将更强烈(平方地而不是线性地)地惩罚过界的边界值。不使用平方是更标准的版本,但是在某些数据集中,平方折叶损失会工作得更好。可以通过交叉验证来决定到底使用哪个。 50 | 51 | 52 | 53 | > 我们对于预测训练集数据分类标签的情况总有一些不满意的,而损失函数就能将这些不满意的程度量化。 54 | 55 | ————————————————————————————————————————— 56 | 57 | ![][26]多类SVM"想要"正确类别的分类分数比其他不正确分类类别的分数要高,而且至少高出delta的边界值。如果其他分类分数进入了红色的区域,甚至更高,那么就开始计算损失。如果没有这些情况,损失值为0。我们的目标是找到一些权重,它们既能够让训练集中的数据样例满足这些限制,也能让总的损失值尽可能地低。 58 | 59 | ————————————————————————————————————————— 60 | 61 | **正则化(Regularization):**上面损失函数有一个问题。假设有一个数据集和一个权重集**W**能够正确地分类每个数据(即所有的边界都满足,对于所有的i都有![L_i=0][27])。问题在于这个**W**并不唯一:可能有很多相似的**W**都能正确地分类所有的数据。一个简单的例子:如果**W**能够正确分类所有数据,即对于每个数据,损失值都是0。那么当![lambda>1][28]时,任何数乘![lambda W][29]都能使得损失值为0,因为这个变化将所有分值的大小都均等地扩大了,所以它们之间的绝对差值也扩大了。举个例子,如果一个正确分类的分值和举例它最近的错误分类的分值的差距是15,对**W**乘以2将使得差距变成30。 62 | 63 | 换句话说,我们希望能向某些特定的权重**W**添加一些偏好,对其他权重则不添加,以此来消除模糊性。这一点是能够实现的,方法是向损失函数增加一个**正则化惩罚(regularization penalty)**![R\(W\)][30]部分。最常用的正则化惩罚是L2范式,L2范式通过对所有参数进行逐元素的平方惩罚来抑制大数值的权重: 64 | 65 | ![R\(W\)=sum_k sum_l W^2_{k,l}][31] 66 | 67 | 上面的表达式中,将![W][7]中所有元素平方后求和。注意正则化函数不是数据的函数,仅基于权重。包含正则化惩罚后,就能够给出完整的多类SVM损失函数了,它由两个部分组成:**数据损失(data loss)**,即所有样例的的平均损失![L_i][32],以及**正则化损失(regularization loss)**。完整公式如下所示: 68 | 69 | ![L=displaystyle underbrace{ frac{1}{N}sum_i L_i}_{data loss}+underbrace{lambda R\(W\)}_{regularization loss}][33] 70 | 71 | 将其展开完整公式是: 72 | 73 | ![L=frac{1}{N}sum_isum_{jnot=y_i}\[max\(0,f\(x_i;W\)_j-f\(x_i;W\)_{y_i}+Delta\)\]+lambda sum_k sum_l W^2_{k,l}][34] 74 | 75 | 其中,![N][35]是训练集的数据量。现在正则化惩罚添加到了损失函数里面,并用超参数![lambda][36]来计算其权重。该超参数无法简单确定,需要通过交叉验证来获取。 76 | 77 | 除了上述理由外,引入正则化惩罚还带来很多良好的性质,这些性质大多会在后续章节介绍。比如引入了L2惩罚后,SVM们就有了**最大边界(****max margin)**这一良好性质。(如果感兴趣,可以查看[CS229课程__][37])。 78 | 79 | 其中最好的性质就是对大数值权重进行惩罚,可以提升其泛化能力,因为这就意味着没有哪个维度能够独自对于整体分值有过大的影响。举个例子,假设输入向量![x=\[1,1,1,1\]][38],两个权重向量![w_1=\[1,0,0,0\]][39],![w_2=\[0.25,0.25,0.25,0.25\]][40]。那么![w^T_1x=w^T_2=1][41],两个权重向量都得到同样的内积,但是![w_1][42]的L2惩罚是1.0,而![w_2][43]的L2惩罚是0.25。因此,根据L2惩罚来看,![w_2][43]更好,因为它的正则化损失更小。从直观上来看,这是因为![w_2][43]的权重值更小且更分散。既然L2惩罚倾向于更小更分散的权重向量,这就会鼓励分类器最终将所有维度上的特征都用起来,而不是强烈依赖其中少数几个维度。在后面的课程中可以看到,这一效果将会提升分类器的泛化能力,并避免_过拟合_。 80 | 81 | 需要注意的是,和权重不同,偏差没有这样的效果,因为它们并不控制输入维度上的影响强度。因此通常只对权重![W][7]正则化,而不正则化偏差![b][44]。在实际操作中,可发现这一操作的影响可忽略不计。最后,因为正则化惩罚的存在,不可能在所有的例子中得到0的损失值,这是因为只有当![W=0][45]的特殊情况下,才能得到损失值为0。 82 | 83 | **代码**:下面是一个无正则化部分的损失函数的Python实现,有非向量化和半向量化两个形式: 84 | 85 | ```python 86 | def L_i(x, y, W): 87 | """ 88 | unvectorized version. Compute the multiclass svm loss for a single example (x,y) 89 | - x is a column vector representing an image (e.g. 3073 x 1 in CIFAR-10) 90 | with an appended bias dimension in the 3073-rd position (i.e. bias trick) 91 | - y is an integer giving index of correct class (e.g. between 0 and 9 in CIFAR-10) 92 | - W is the weight matrix (e.g. 10 x 3073 in CIFAR-10) 93 | """ 94 | delta = 1.0 # see notes about delta later in this section 95 | scores = W.dot(x) # scores becomes of size 10 x 1, the scores for each class 96 | correct_class_score = scores[y] 97 | D = W.shape[0] # number of classes, e.g. 10 98 | loss_i = 0.0 99 | for j in xrange(D): # iterate over all wrong classes 100 | if j == y: 101 | # skip for the true class to only loop over incorrect classes 102 | continue 103 | # accumulate loss for the i-th example 104 | loss_i += max(0, scores[j] - correct_class_score + delta) 105 | return loss_i 106 | 107 | def L_i_vectorized(x, y, W): 108 | """ 109 | A faster half-vectorized implementation. half-vectorized 110 | refers to the fact that for a single example the implementation contains 111 | no for loops, but there is still one loop over the examples (outside this function) 112 | """ 113 | delta = 1.0 114 | scores = W.dot(x) 115 | # compute the margins for all classes in one vector operation 116 | margins = np.maximum(0, scores - scores[y] + delta) 117 | # on y-th position scores[y] - scores[y] canceled and gave delta. We want 118 | # to ignore the y-th position and only consider margin on max wrong class 119 | margins[y] = 0 120 | loss_i = np.sum(margins) 121 | return loss_i 122 | 123 | def L(X, y, W): 124 | """ 125 | fully-vectorized implementation : 126 | - X holds all the training examples as columns (e.g. 3073 x 50,000 in CIFAR-10) 127 | - y is array of integers specifying correct class (e.g. 50,000-D array) 128 | - W are weights (e.g. 10 x 3073) 129 | """ 130 | # evaluate loss over all examples in X without using any for loops 131 | # left as exercise to reader in the assignment 132 | 133 | ``` 134 | 135 | 136 | 在本小节的学习中,一定要记得SVM损失采取了一种特殊的方法,使得能够衡量对于训练数据预测分类和实际分类标签的一致性。还有,对训练集中数据做出准确分类预测和让损失值最小化这两件事是等价的。 137 | 138 | > 接下来要做的,就是找到能够使损失值最小化的权重了。 139 | 140 | ## 实际考虑 141 | 142 | **设置Delta**:你可能注意到上面的内容对超参数![Delta][9]及其设置是一笔带过,那么它应该被设置成什么值?需要通过交叉验证来求得吗?现在看来,该超参数在绝大多数情况下设为![Delta=1.0][46]都是安全的。超参数![Delta][9]和![lambda][36]看起来是两个不同的超参数,但实际上他们一起控制同一个权衡:即损失函数中的数据损失和正则化损失之间的权衡。理解这一点的关键是要知道,权重![W][7]的大小对于分类分值有直接影响(当然对他们的差异也有直接影响):当我们将![W][7]中值缩小,分类分值之间的差异也变小,反之亦然。因此,不同分类分值之间的边界的具体值(比如![Delta=1][47]或![Delta=100][48])从某些角度来看是没意义的,因为权重自己就可以控制差异变大和缩小。也就是说,真正的权衡是我们允许权重能够变大到何种程度(通过正则化强度![lambda][36]来控制)。 143 | 144 | **与二元支持向量机(****Binary Support Vector Machine****)的关系**:在学习本课程前,你可能对于二元支持向量机有些经验,它对于第i个数据的损失计算公式是: 145 | 146 | 147 | ![displaystyle L_i=Cmax\(0,1-y_iw^Tx_i\)+R\(W\)][49] 148 | 149 | 其中,![C][50]是一个超参数,并且![y_iin{-1,1}][51]。可以认为本章节介绍的SVM公式包含了上述公式,上述公式是多类支持向量机公式只有两个分类类别的特例。也就是说,如果我们要分类的类别只有两个,那么公式就化为二元SVM公式。这个公式中的![C][50]和多类SVM公式中的![lambda][36]都控制着同样的权衡,而且它们之间的关系是![Cproptofrac{1}{lambda}][52] 150 | 151 | **备注:在初始形式中进行最优化**。如果在本课程之前学习过SVM,那么对kernels,duals,SMO算法等将有所耳闻。在本课程(主要是神经网络相关)中,损失函数的最优化的始终在非限制初始形式下进行。很多这些损失函数从技术上来说是不可微的(比如当![x=y][53]时,![max\(x,y\)][54]函数就不可微分),但是在实际操作中并不存在问题,因为通常可以使用次梯度。 152 | 153 | **备注:其他多类SVM公式**。需要指出的是,本课中展示的多类SVM只是多种SVM公式中的一种。另一种常用的公式是_One-Vs-All_(OVA)SVM,它针对每个类和其他类训练一个独立的二元分类器。还有另一种更少用的叫做_All-Vs-All_(AVA)策略。我们的公式是按照[Weston and Watkins 1999 (pdf)__][55]版本,比OVA性能更强(在构建有一个多类数据集的情况下,这个版本可以在损失值上取到0,而OVA就不行。感兴趣的话在论文中查阅细节)。最后一个需要知道的公式是Structured SVM,它将正确分类的分类分值和非正确分类中的最高分值的边界最大化。理解这些公式的差异超出了本课程的范围。本课程笔记介绍的版本可以在实践中安全使用,而被论证为最简单的OVA策略在实践中看起来也能工作的同样出色(在 Rikin等人2004年的论文[In Defense of One-Vs-All Classification (pdf)__][56]中可查)。 154 | 155 | **线性分类笔记(中)完**。 156 | 157 | 158 | 159 | ## 译者反馈 160 | 161 | 1. **允许转载,须_全文转载并注明原文链接_;** 162 | 2. 近期发现某些**微信公众号转载时有删除贡献者们名字,或不注明原链接,或截取段落等不良转载行为**,请**停止以上不良转载行为,全文转载并注明原文链接**。否则我们保留维权的权利,下一步将委托维权骑士进行版权保护; 163 | 3. 请知友们通过评论和私信等方式批评指正,贡献者均会补充提及。 164 | 165 | [1]: https://zhuanlan.zhihu.com/intelligentunit 166 | [2]: http://link.zhihu.com/?target=http%3A//cs231n.github.io/linear-classify/ 167 | [3]: http://link.zhihu.com/?target=http%3A//cs.stanford.edu/people/karpathy/ 168 | [4]: https://www.zhihu.com/people/du-ke 169 | [5]: https://www.zhihu.com/people/sqfan 170 | [6]: https://www.zhihu.com/people/kun-kun-97-81 171 | [7]: http://zhihu.com/equation?tex=W 172 | [8]: http://zhihu.com/equation?tex=%28x_i%2Cy_i%29 173 | [9]: http://zhihu.com/equation?tex=%5CDelta 174 | [10]: http://zhihu.com/equation?tex=x_i 175 | [11]: http://zhihu.com/equation?tex=y_i 176 | [12]: http://zhihu.com/equation?tex=f%28x_i%2CW%29 177 | [13]: http://zhihu.com/equation?tex=s 178 | [14]: http://zhihu.com/equation?tex=s_j%3Df%28x_i%2CW%29_j 179 | [15]: http://zhihu.com/equation?tex=%5Cdisplaystyle+L_i%3D%5Csum_%7Bj%5Cnot%3Dy_i%7Dmax%280%2Cs_j-s_%7By_i%7D%2B%5CDelta%29 180 | [16]: http://zhihu.com/equation?tex=s%3D%5B13%2C-7%2C11%5D 181 | [17]: http://zhihu.com/equation?tex=y_i%3D0 182 | [18]: http://zhihu.com/equation?tex=j%5Cnot%3Dy_i 183 | [19]: http://zhihu.com/equation?tex=%5Cdisplaystyle+Li%3Dmax%280%2C-7-13%2B10%29%2Bmax%280%2C11-13%2B10%29 184 | [20]: http://zhihu.com/equation?tex=max%280%2C-%29 185 | [21]: http://zhihu.com/equation?tex=f%28x_i%2CW%29%3DWx_i 186 | [22]: http://zhihu.com/equation?tex=%5Cdisplaystyle+L_i%3D%5Csum_%7Bj%5Cnot%3Dy_i%7Dmax%280%2Cw%5ET_jx_i-w%5ET_%7By_i%7Dx_i%2B%5CDelta%29 187 | [23]: http://zhihu.com/equation?tex=w_j 188 | [24]: http://zhihu.com/equation?tex=f 189 | [25]: http://zhihu.com/equation?tex=max%280%2C-%29%5E2 190 | [26]: https://pic1.zhimg.com/f254bd8d072128f1088c8cc47c3dff58_b.jpg 191 | [27]: http://zhihu.com/equation?tex=L_i%3D0 192 | [28]: http://zhihu.com/equation?tex=%5Clambda%3E1 193 | [29]: http://zhihu.com/equation?tex=%5Clambda+W 194 | [30]: http://zhihu.com/equation?tex=R%28W%29 195 | [31]: http://zhihu.com/equation?tex=R%28W%29%3D%5Csum_k+%5Csum_l+W%5E2_%7Bk%2Cl%7D 196 | [32]: http://zhihu.com/equation?tex=L_i 197 | [33]: http://zhihu.com/equation?tex=L%3D%5Cdisplaystyle+%5Cunderbrace%7B+%5Cfrac%7B1%7D%7BN%7D%5Csum_i+L_i%7D_%7Bdata+%5C++loss%7D%2B%5Cunderbrace%7B%5Clambda+R%28W%29%7D_%7Bregularization+%5C+loss%7D 198 | [34]: http://zhihu.com/equation?tex=L%3D%5Cfrac%7B1%7D%7BN%7D%5Csum_i%5Csum_%7Bj%5Cnot%3Dy_i%7D%5Bmax%280%2Cf%28x_i%3BW%29_j-f%28x_i%3BW%29_%7By_i%7D%2B%5CDelta%29%5D%2B%5Clambda+%5Csum_k+%5Csum_l+W%5E2_%7Bk%2Cl%7D 199 | [35]: http://zhihu.com/equation?tex=N 200 | [36]: http://zhihu.com/equation?tex=%5Clambda 201 | [37]: http://link.zhihu.com/?target=http%3A//cs229.stanford.edu/notes/cs229-notes3.pdf 202 | [38]: http://zhihu.com/equation?tex=x%3D%5B1%2C1%2C1%2C1%5D 203 | [39]: http://zhihu.com/equation?tex=w_1%3D%5B1%2C0%2C0%2C0%5D 204 | [40]: http://zhihu.com/equation?tex=w_2%3D%5B0.25%2C0.25%2C0.25%2C0.25%5D 205 | [41]: http://zhihu.com/equation?tex=w%5ET_1x%3Dw%5ET_2%3D1 206 | [42]: http://zhihu.com/equation?tex=w_1 207 | [43]: http://zhihu.com/equation?tex=w_2 208 | [44]: http://zhihu.com/equation?tex=b 209 | [45]: http://zhihu.com/equation?tex=W%3D0 210 | [46]: http://zhihu.com/equation?tex=%5CDelta%3D1.0 211 | [47]: http://zhihu.com/equation?tex=%5CDelta%3D1 212 | [48]: http://zhihu.com/equation?tex=%5CDelta%3D100 213 | [49]: http://zhihu.com/equation?tex=%5Cdisplaystyle+L_i%3DCmax%280%2C1-y_iw%5ETx_i%29%2BR%28W%29 214 | [50]: http://zhihu.com/equation?tex=C 215 | [51]: http://zhihu.com/equation?tex=y_i%5Cin%5C%7B-1%2C1%5C%7D 216 | [52]: http://zhihu.com/equation?tex=C%5Cpropto%5Cfrac%7B1%7D%7B%5Clambda%7D 217 | [53]: http://zhihu.com/equation?tex=x%3Dy 218 | [54]: http://zhihu.com/equation?tex=max%28x%2Cy%29 219 | [55]: http://link.zhihu.com/?target=https%3A//www.elen.ucl.ac.be/Proceedings/esann/esannpdf/es1999-461.pdf 220 | [56]: http://link.zhihu.com/?target=http%3A//www.jmlr.org/papers/volume5/rifkin04a/rifkin04a.pdf 221 | 222 | -------------------------------------------------------------------------------- /CS231n 6.3.b 神经网络笔记3(下).md: -------------------------------------------------------------------------------- 1 | 2 | [Source](https://zhuanlan.zhihu.com/p/21798784?refer=intelligentunit "Permalink to CS231n课程笔记翻译:神经网络笔记3(下) - 知乎专栏") 3 | 4 | # CS231n课程笔记翻译:神经网络笔记3(下) - 知乎专栏 5 | 6 | 7 | 8 | ![CS231n课程笔记翻译:神经网络笔记3(下)][4] 9 | 10 | # CS231n课程笔记翻译:神经网络笔记3(下) 11 | 12 | ![杜客][5][杜客][6] 13 | 14 | 8 months ago 15 | 16 | 译者注:本文[智能单元][2]首发,译自斯坦福CS231n课程笔记[Neural Nets notes 3__][7],课程教师[Andrej Karpathy__][8]授权翻译。本篇教程由[杜客][6]翻译完成,[堃堃][9]和[巩子嘉][10]进行校对修改。译文含公式和代码,建议PC端阅读。 17 | 18 | ## 原文如下 19 | 20 | 内容列表: 21 | 22 | * 梯度检查 23 | * 合理性(Sanity)检查 24 | * 检查学习过程 25 | * 损失函数 26 | * 训练与验证准确率 27 | * 权重:更新比例 28 | * 每层的激活数据与梯度分布 29 | * 可视化 30 | * 参数更新 _**译者注:下篇翻译起始处**_ 31 | * 一阶(随机梯度下降)方法,动量方法,Nesterov动量方法 32 | * 学习率退火 33 | * 二阶方法 34 | * 逐参数适应学习率方法(Adagrad,RMSProp) 35 | * 超参数调优 36 | * 评价 37 | * 模型集成 38 | * 总结 39 | * 拓展引用 40 | 41 | ## 参数更新 42 | 43 | 一旦能使用反向传播计算解析梯度,梯度就能被用来进行参数更新了。进行参数更新有好几种方法,接下来都会进行讨论。 44 | 45 | 深度网络的最优化是现在非常活跃的研究领域。本节将重点介绍一些公认有效的常用的技巧,这些技巧都是在实践中会遇到的。我们将简要介绍这些技巧的直观概念,但不进行细节分析。对于细节感兴趣的读者,我们提供了一些拓展阅读。 46 | 47 | ### 随机梯度下降及各种更新方法 48 | 49 | **普通更新**。最简单的更新形式是沿着负梯度方向改变参数(因为梯度指向的是上升方向,但是我们通常希望最小化损失函数)。假设有一个参数向量**x**及其梯度**dx**,那么最简单的更新的形式是: 50 | 51 | 52 | ```py 53 | # 普通更新 54 | x += - learning_rate * dx 55 | 56 | ``` 57 | 58 | 其中learning_rate是一个超参数,它是一个固定的常量。当在整个数据集上进行计算时,只要学习率足够低,总是能在损失函数上得到非负的进展。 59 | 60 | **动量(****Momentum****)更新**是另一个方法,这个方法在深度网络上几乎总能得到更好的收敛速度。该方法可以看成是从物理角度上对于最优化问题得到的启发。损失值可以理解为是山的高度(因此高度势能是![U=mgh][11],所以有![Upropto h][12])。用随机数字初始化参数等同于在某个位置给质点设定初始速度为0。这样最优化过程可以看做是模拟参数向量(即质点)在地形上滚动的过程。 61 | 62 | 因为作用于质点的力与梯度的潜在能量(![F=-nabla U][13])有关,质点**所受的力**就是损失函数的**(负)梯度**。还有,因为![F=ma][14],所以在这个观点下(负)梯度与质点的加速度是成比例的。注意这个理解和上面的随机梯度下降(SDG)是不同的,在普通版本中,梯度直接影响位置。而在这个版本的更新中,物理观点建议梯度只是影响速度,然后速度再影响位置: 63 | 64 | 65 | 66 | 67 | 68 | ```py 69 | # 动量更新 70 | v = mu * v - learning_rate * dx # 与速度融合 71 | x += v # 与位置融合 72 | 73 | ``` 74 | 75 | 在这里引入了一个初始化为0的变量**v**和一个超参数**mu**。说得不恰当一点,这个变量(mu)在最优化的过程中被看做_动量_(一般值设为0.9),但其物理意义与摩擦系数更一致。这个变量有效地抑制了速度,降低了系统的动能,不然质点在山底永远不会停下来。通过交叉验证,这个参数通常设为[0.5,0.9,0.95,0.99]中的一个。和学习率随着时间退火(下文有讨论)类似,动量随时间变化的设置有时能略微改善最优化的效果,其中动量在学习过程的后阶段会上升。一个典型的设置是刚开始将动量设为0.5而在后面的多个周期(epoch)中慢慢提升到0.99。 76 | 77 | 78 | 79 | > 通过动量更新,参数向量会在任何有持续梯度的方向上增加速度。 80 | 81 | **Nesterov动量**与普通动量有些许不同,最近变得比较流行。在理论上对于凸函数它能得到更好的收敛,在实践中也确实比标准动量表现更好一些。 82 | 83 | 84 | 85 | Nesterov动量的核心思路是,当参数向量位于某个位置**x**时,观察上面的动量更新公式可以发现,动量部分(忽视带梯度的第二个部分)会通过**mu * v**稍微改变参数向量。因此,如果要计算梯度,那么可以将未来的近似位置**x + mu * v**看做是"向前看",这个点在我们一会儿要停止的位置附近。因此,计算**x + mu * v**的梯度而不是"旧"位置**x**的梯度就有意义了。 86 | 87 | ———————————————————————————————————————— 88 | 89 | ![][15] 90 | 91 | Nesterov动量。既然我们知道动量将会把我们带到绿色箭头指向的点,我们就不要在原点(红色点)那里计算梯度了。使用Nesterov动量,我们就在这个"向前看"的地方计算梯度。 92 | 93 | 94 | 95 | ———————————————————————————————————————— 96 | 97 | 也就是说,添加一些注释后,实现代码如下: 98 | 99 | 100 | 101 | ```py 102 | x_ahead = x + mu * v 103 | # 计算dx_ahead(在x_ahead处的梯度,而不是在x处的梯度) 104 | v = mu * v - learning_rate * dx_ahead 105 | x += v 106 | 107 | ``` 108 | 109 | 然而在实践中,人们更喜欢和普通SGD或上面的动量方法一样简单的表达式。通过对**x_ahead = x + mu * v**使用变量变换进行改写是可以做到的,然后用**x_ahead**而不是**x**来表示上面的更新。也就是说,实际存储的参数向量总是向前一步的那个版本。**x_ahead**的公式(将其重新命名为**x**)就变成了: 110 | 111 | 112 | ```py 113 | v_prev = v # 存储备份 114 | v = mu * v - learning_rate * dx # 速度更新保持不变 115 | x += -mu * v_prev + (1 + mu) * v # 位置更新变了形式 116 | 117 | ``` 118 | 119 | 对于NAG(Nesterov's Accelerated Momentum)的来源和数学公式推导,我们推荐以下的拓展阅读: 120 | 121 | * Yoshua Bengio的[Advances in optimizing Recurrent Networks__][16],Section 3.5。 122 | * [Ilya Sutskever's thesis__][17] (pdf)在section 7.2对于这个主题有更详尽的阐述。 123 | 124 | ### 学习率退火 125 | 126 | 在训练深度网络的时候,让学习率随着时间退火通常是有帮助的。可以这样理解:如果学习率很高,系统的动能就过大,参数向量就会无规律地跳动,不能够稳定到损失函数更深更窄的部分去。知道什么时候开始衰减学习率是有技巧的:慢慢减小它,可能在很长时间内只能是浪费计算资源地看着它混沌地跳动,实际进展很少。但如果快速地减少它,系统可能过快地失去能量,不能到达原本可以到达的最好位置。通常,实现学习率退火有3种方式: 127 | 128 | 129 | 130 | * **随步数衰减**:每进行几个周期就根据一些因素降低学习率。典型的值是每过5个周期就将学习率减少一半,或者每20个周期减少到之前的0.1。这些数值的设定是严重依赖具体问题和模型的选择的。在实践中可能看见这么一种经验做法:使用一个固定的学习率来进行训练的同时观察验证集错误率,每当验证集错误率停止下降,就乘以一个常数(比如0.5)来降低学习率。 131 | * **指数衰减**。数学公式是![alpha=alpha_0e^{-kt}][18],其中![alpha_0,k][19]是超参数,![t][20]是迭代次数(也可以使用周期作为单位)。 132 | * **1/t衰减**的数学公式是![alpha=alpha_0/\(1+kt\)][21],其中![alpha_0,k][19]是超参数,t是迭代次数。 133 | 134 | 135 | 在实践中,我们发现随步数衰减的随机失活(dropout)更受欢迎,因为它使用的超参数(衰减系数和以周期为时间单位的步数)比![k][22]更有解释性。最后,如果你有足够的计算资源,可以让衰减更加缓慢一些,让训练时间更长些。 136 | 137 | ### 二阶方法 138 | 139 | 在深度网络背景下,第二类常用的最优化方法是基于[牛顿法__][23]的,其迭代如下: 140 | 141 | ![displaystyle xleftarrow x-\[Hf\(x\)\]^{-1}nabla f\(x\)][24] 142 | 143 | 这里![Hf\(x\)][25]是[Hessian矩阵__][26],它是函数的二阶偏导数的平方矩阵。![nabla f\(x\)][27]是梯度向量,这和梯度下降中一样。直观理解上,Hessian矩阵描述了损失函数的局部曲率,从而使得可以进行更高效的参数更新。具体来说,就是乘以Hessian转置矩阵可以让最优化过程在曲率小的时候大步前进,在曲率大的时候小步前进。需要重点注意的是,在这个公式中是没有学习率这个超参数的,这相较于一阶方法是一个巨大的优势。 144 | 145 | 然而上述更新方法很难运用到实际的深度学习应用中去,这是因为计算(以及求逆)Hessian矩阵操作非常耗费时间和空间。举例来说,假设一个有一百万个参数的神经网络,其Hessian矩阵大小就是[1,000,000 x 1,000,000],将占用将近3,725GB的内存。这样,各种各样的_拟_-牛顿法就被发明出来用于近似转置Hessian矩阵。在这些方法中最流行的是[L-BFGS__][28],该方法使用随时间的梯度中的信息来隐式地近似(也就是说整个矩阵是从来没有被计算的)。 146 | 147 | 然而,即使解决了存储空间的问题,L-BFGS应用的一个巨大劣势是需要对整个训练集进行计算,而整个训练集一般包含几百万的样本。和小批量随机梯度下降(mini-batch SGD)不同,让L-BFGS在小批量上运行起来是很需要技巧,同时也是研究热点。 148 | 149 | **实践**。在深度学习和卷积神经网络中,使用L-BFGS之类的二阶方法并不常见。相反,基于(Nesterov的)动量更新的各种随机梯度下降方法更加常用,因为它们更加简单且容易扩展。 150 | 151 | 参考资料: 152 | 153 | * [Large Scale Distributed Deep Networks__][29] 一文来自谷歌大脑团队,比较了在大规模数据情况下L-BFGS和SGD算法的表现。 154 | * [SFO__][30]算法想要把SGD和L-BFGS的优势结合起来。 155 | 156 | ## 逐参数适应学习率方法 157 | 158 | 前面讨论的所有方法都是对学习率进行全局地操作,并且对所有的参数都是一样的。学习率调参是很耗费计算资源的过程,所以很多工作投入到发明能够适应性地对学习率调参的方法,甚至是逐个参数适应学习率调参。很多这些方法依然需要其他的超参数设置,但是其观点是这些方法对于更广范围的超参数比原始的学习率方法有更良好的表现。在本小节我们会介绍一些在实践中可能会遇到的常用适应算法: 159 | 160 | **Adagrad**是一个由[Duchi等__][31]提出的适应性学习率算法 161 | 162 | 163 | ```py 164 | # 假设有梯度和参数向量x 165 | cache += dx**2 166 | x += - learning_rate * dx / (np.sqrt(cache) + eps) 167 | 168 | ``` 169 | 170 | 注意,变量**cache**的尺寸和梯度矩阵的尺寸是一样的,还跟踪了每个参数的梯度的平方和。这个一会儿将用来归一化参数更新步长,归一化是逐元素进行的。注意,接收到高梯度值的权重更新的效果被减弱,而接收到低梯度值的权重的更新效果将会增强。有趣的是平方根的操作非常重要,如果去掉,算法的表现将会糟糕很多。用于平滑的式子**eps**(一般设为1e-4到1e-8之间)是防止出现除以0的情况。Adagrad的一个缺点是,在深度学习中单调的学习率被证明通常过于激进且过早停止学习。 171 | 172 | **RMSprop**。是一个非常高效,但没有公开发表的适应性学习率方法。有趣的是,每个使用这个方法的人在他们的论文中都引用自Geoff Hinton的Coursera课程的[第六课的第29页PPT__][32]。这个方法用一种很简单的方式修改了Adagrad方法,让它不那么激进,单调地降低了学习率。具体说来,就是它使用了一个梯度平方的滑动平均: 173 | 174 | 175 | ```py 176 | cache = decay_rate * cache + (1 - decay_rate) * dx**2 177 | x += - learning_rate * dx / (np.sqrt(cache) + eps) 178 | 179 | ``` 180 | 181 | 在上面的代码中,decay_rate是一个超参数,常用的值是[0.9,0.99,0.999]。其中**x+=**和Adagrad中是一样的,但是**cache**变量是不同的。因此,RMSProp仍然是基于梯度的大小来对每个权重的学习率进行修改,这同样效果不错。但是和Adagrad不同,其更新不会让学习率单调变小。 182 | 183 | **Adam**。[Adam__][33]是最近才提出的一种更新方法,它看起来像是RMSProp的动量版。简化的代码是下面这样: 184 | 185 | 186 | ```py 187 | m = beta1*m + (1-beta1)*dx 188 | v = beta2*v + (1-beta2)*(dx**2) 189 | x += - learning_rate * m / (np.sqrt(v) + eps) 190 | 191 | ``` 192 | 193 | 注意这个更新方法看起来真的和RMSProp很像,除了使用的是平滑版的梯度**m**,而不是用的原始梯度向量**dx**。论文中推荐的参数值**eps=1e-8, beta1=0.9, beta2=0.999**。在实际操作中,我们推荐Adam作为默认的算法,一般而言跑起来比RMSProp要好一点。但是也可以试试SGD+Nesterov动量。完整的Adam更新算法也包含了一个偏置_(bias)矫正_机制,因为**m,v**两个矩阵初始为0,在没有完全热身之前存在偏差,需要采取一些补偿措施。建议读者可以阅读论文查看细节,或者课程的PPT。 194 | 195 | 拓展阅读: 196 | 197 | * [Unit Tests for Stochastic Optimization__][34]一文展示了对于随机最优化的测试。 198 | 199 | —————————————————————————————————————————— 200 | 201 | ![][35] 202 | 203 | **_译者注:上图原文中为动图,知乎专栏不支持动图,知友可点击[原文链接__][7]查看。_** 204 | 205 | 上面的动画可以帮助你理解学习的动态过程。**左边**是一个损失函数的等高线图,上面跑的是不同的最优化算法。注意基于动量的方法出现了射偏了的情况,使得最优化过程看起来像是一个球滚下山的样子。**右边**展示了一个马鞍状的最优化地形,其中对于不同维度它的曲率不同(一个维度下降另一个维度上升)。注意SGD很难突破对称性,一直卡在顶部。而RMSProp之类的方法能够看到马鞍方向有很低的梯度。因为在RMSProp更新方法中的分母项,算法提高了在该方向的有效学习率,使得RMSProp能够继续前进。图片版权:[Alec Radford__][36]。 206 | 207 | 208 | 209 | —————————————————————————————————————————— 210 | 211 | ## 超参数调优 212 | 213 | 我们已经看到,训练一个神经网络会遇到很多超参数设置。神经网络最常用的设置有: 214 | 215 | * 初始学习率。 216 | * 学习率衰减方式(例如一个衰减常量)。 217 | * 正则化强度(L2惩罚,随机失活强度)。 218 | 219 | 但是也可以看到,还有很多相对不那么敏感的超参数。比如在逐参数适应学习方法中,对于动量及其时间表的设置等。在本节中将介绍一些额外的调参要点和技巧: 220 | 221 | **实现**。更大的神经网络需要更长的时间去训练,所以调参可能需要几天甚至几周。记住这一点很重要,因为这会影响你设计代码的思路。一个具体的设计是用**仆程序**持续地随机设置参数然后进行最优化。在训练过程中,**仆程序**会对每个周期后验证集的准确率进行监控,然后向文件系统写下一个模型的记录点(记录点中有各种各样的训练统计数据,比如随着时间的损失值变化等),这个文件系统最好是可共享的。在文件名中最好包含验证集的算法表现,这样就能方便地查找和排序了。然后还有一个**主程序**,它可以启动或者结束计算集群中的**仆程序**,有时候也可能根据条件查看**仆程序**写下的记录点,输出它们的训练统计数据等。 222 | 223 | **比起交叉验证最好使用一个验证集**。在大多数情况下,一个尺寸合理的验证集可以让代码更简单,不需要用几个数据集来交叉验证。你可能会听到人们说他们"交叉验证"一个参数,但是大多数情况下,他们实际是使用的一个验证集。 224 | 225 | **超参数范围**。在对数尺度上进行超参数搜索。例如,一个典型的学习率应该看起来是这样:**learning_rate = 10 ** uniform(-6, 1)**。也就是说,我们从标准分布中随机生成了一个数字,然后让它成为10的阶数。对于正则化强度,可以采用同样的策略。直观地说,这是因为学习率和正则化强度都对于训练的动态进程有乘的效果。例如:当学习率是0.001的时候,如果对其固定地增加0.01,那么对于学习进程会有很大影响。然而当学习率是10的时候,影响就微乎其微了。这就是因为学习率乘以了计算出的梯度。因此,比起加上或者减少某些值,思考学习率的范围是乘以或者除以某些值更加自然。但是有一些参数(比如随机失活)还是在原始尺度上进行搜索(例如:**dropout=uniform(0,1)**)。 226 | 227 | **随机搜索优于网格搜索**。Bergstra和Bengio在文章[Random Search for Hyper-Parameter Optimization__][37]中说"随机选择比网格化的选择更加有效",而且在实践中也更容易实现。 228 | 229 | —————————————————————————————————————————— 230 | 231 | ![][38]在[Random Search for Hyper-Parameter Optimization__][37]中的核心说明图。通常,有些超参数比其余的更重要,通过随机搜索,而不是网格化的搜索,可以让你更精确地发现那些比较重要的超参数的好数值。 232 | 233 | —————————————————————————————————————————— 234 | 235 | **对于边界上的最优值要小心**。这种情况一般发生在你在一个不好的范围内搜索超参数(比如学习率)的时候。比如,假设我们使用**learning_rate = 10 ** uniform(-6,1)**来进行搜索。一旦我们得到一个比较好的值,一定要确认你的值不是出于这个范围的边界上,不然你可能错过更好的其他搜索范围。 236 | 237 | **从粗到细地分阶段搜索**。在实践中,先进行初略范围(比如10 ** [-6, 1])搜索,然后根据好的结果出现的地方,缩小范围进行搜索。进行粗搜索的时候,让模型训练一个周期就可以了,因为很多超参数的设定会让模型没法学习,或者突然就爆出很大的损失值。第二个阶段就是对一个更小的范围进行搜索,这时可以让模型运行5个周期,而最后一个阶段就在最终的范围内进行仔细搜索,运行很多次周期。 238 | 239 | **贝叶斯超参数最优化**是一整个研究领域,主要是研究在超参数空间中更高效的导航算法。其核心的思路是在不同超参数设置下查看算法性能时,要在探索和使用中进行合理的权衡。基于这些模型,发展出很多的库,比较有名的有: [Spearmint__][39], [SMAC__][40], 和[Hyperopt__][41]。然而,在卷积神经网络的实际使用中,比起上面介绍的先认真挑选的一个范围,然后在该范围内随机搜索的方法,这个方法还是差一些。[这里__][42]有更详细的讨论。 240 | 241 | ## 评价 242 | 243 | ### 模型集成 244 | 245 | 在实践的时候,有一个总是能提升神经网络几个百分点准确率的办法,就是在训练的时候训练几个独立的模型,然后在测试的时候平均它们预测结果。集成的模型数量增加,算法的结果也单调提升(但提升效果越来越少)。还有模型之间的差异度越大,提升效果可能越好。进行集成有以下几种方法: 246 | 247 | * **同一个模型,不同的初始化**。使用交叉验证来得到最好的超参数,然后用最好的参数来训练不同初始化条件的模型。这种方法的风险在于多样性只来自于不同的初始化条件。 248 | * **在交叉验证中发现最好的模型**。使用交叉验证来得到最好的超参数,然后取其中最好的几个(比如10个)模型来进行集成。这样就提高了集成的多样性,但风险在于可能会包含不够理想的模型。在实际操作中,这样操作起来比较简单,在交叉验证后就不需要额外的训练了。 249 | * **一个模型设置多个记录点**。如果训练非常耗时,那就在不同的训练时间对网络留下记录点(比如每个周期结束),然后用它们来进行模型集成。很显然,这样做多样性不足,但是在实践中效果还是不错的,这种方法的优势是代价比较小。 250 | * **在训练的时候跑参数的平均值**。和上面一点相关的,还有一个也能得到1-2个百分点的提升的小代价方法,这个方法就是在训练过程中,如果损失值相较于前一次权重出现指数下降时,就在内存中对网络的权重进行一个备份。这样你就对前几次循环中的网络状态进行了平均。你会发现这个"平滑"过的版本的权重总是能得到更少的误差。直观的理解就是目标函数是一个碗状的,你的网络在这个周围跳跃,所以对它们平均一下,就更可能跳到中心去。 251 | 252 | 模型集成的一个劣势就是在测试数据的时候会花费更多时间。最近Geoff Hinton在"[Dark Knowledge__][43]"上的工作很有启发:其思路是通过将集成似然估计纳入到修改的目标函数中,从一个好的集成中抽出一个单独模型。 253 | 254 | ## 总结 255 | 256 | 训练一个神经网络需要: 257 | 258 | * 利用小批量数据对实现进行梯度检查,还要注意各种错误。 259 | * 进行合理性检查,确认初始损失值是合理的,在小数据集上能得到100%的准确率。 260 | * 在训练时,跟踪损失函数值,训练集和验证集准确率,如果愿意,还可以跟踪更新的参数量相对于总参数量的比例(一般在1e-3左右),然后如果是对于卷积神经网络,可以将第一层的权重可视化。 261 | * 推荐的两个更新方法是SGD+Nesterov动量方法,或者Adam方法。 262 | * 随着训练进行学习率衰减。比如,在固定多少个周期后让学习率减半,或者当验证集准确率下降的时候。 263 | * 使用随机搜索(不要用网格搜索)来搜索最优的超参数。分阶段从粗(比较宽的超参数范围训练1-5个周期)到细(窄范围训练很多个周期)地来搜索。 264 | * 进行模型集成来获得额外的性能提高。 265 | 266 | ## 拓展阅读 267 | 268 | * Leon Bottou的《[SGD要点和技巧__][44]》。 269 | * Yann LeCun的《[Efficient BackProp__][45]》。 270 | * Yoshua Bengio的《[Practical Recommendations for Gradient-Based Training of Deep Architectures__][46]》。 271 | 272 | ## 译者反馈 273 | 274 | 1. **转载须全文转载且注明原文链接**,否则保留维权权利; 275 | 2. 请知友们通过评论和私信等方式批评指正,贡献者均会补充提及。 276 | 277 | 「Yahoo!翻译快要完结啦!」 278 | 279 | 280 | [1]: https://pic4.zhimg.com/4a97d93d652f45ededf2ebab9a13f22b_m.jpeg 281 | [2]: https://zhuanlan.zhihu.com/intelligentunit 282 | [3]: https://zhuanlan.zhihu.com/write 283 | [4]: https://pic4.zhimg.com/940c2e8d2edc3018771c752d977a6f27_r.png 284 | [5]: https://pic2.zhimg.com/5ab5b93bd_xs.jpg 285 | [6]: https://www.zhihu.com/people/du-ke 286 | [7]: http://link.zhihu.com/?target=http%3A//cs231n.github.io/neural-networks-3/ 287 | [8]: http://link.zhihu.com/?target=http%3A//cs.stanford.edu/people/karpathy/ 288 | [9]: https://www.zhihu.com/people/kun-kun-97-81 289 | [10]: https://www.zhihu.com/people/hmonkey 290 | [11]: http://zhihu.com/equation?tex=U%3Dmgh 291 | [12]: http://zhihu.com/equation?tex=U%5Cpropto+h 292 | [13]: http://zhihu.com/equation?tex=F%3D-%5Cnabla+U 293 | [14]: http://zhihu.com/equation?tex=F%3Dma 294 | [15]: http://pic1.zhimg.com/412afb713ddcff0ba9165ab026563304_b.png 295 | [16]: http://link.zhihu.com/?target=http%3A//arxiv.org/pdf/1212.0901v2.pdf 296 | [17]: http://link.zhihu.com/?target=http%3A//www.cs.utoronto.ca/%257Eilya/pubs/ilya_sutskever_phd_thesis.pdf 297 | [18]: http://zhihu.com/equation?tex=%5Calpha%3D%5Calpha_0e%5E%7B-kt%7D 298 | [19]: http://zhihu.com/equation?tex=%5Calpha_0%2Ck 299 | [20]: http://zhihu.com/equation?tex=t 300 | [21]: http://zhihu.com/equation?tex=%5Calpha%3D%5Calpha_0%2F%281%2Bkt%29 301 | [22]: http://zhihu.com/equation?tex=k 302 | [23]: http://link.zhihu.com/?target=https%3A//en.wikipedia.org/wiki/Newton%2527s_method_in_optimization 303 | [24]: http://zhihu.com/equation?tex=%5Cdisplaystyle+x%5Cleftarrow+x-%5BHf%28x%29%5D%5E%7B-1%7D%5Cnabla+f%28x%29 304 | [25]: http://zhihu.com/equation?tex=Hf%28x%29 305 | [26]: http://link.zhihu.com/?target=https%3A//en.wikipedia.org/wiki/Hessian_matrix 306 | [27]: http://zhihu.com/equation?tex=%5Cnabla+f%28x%29 307 | [28]: http://link.zhihu.com/?target=https%3A//en.wikipedia.org/wiki/Limited-memory_BFGS 308 | [29]: http://link.zhihu.com/?target=http%3A//research.google.com/archive/large_deep_networks_nips2012.html 309 | [30]: http://link.zhihu.com/?target=http%3A//arxiv.org/abs/1311.2115 310 | [31]: http://link.zhihu.com/?target=http%3A//jmlr.org/papers/v12/duchi11a.html 311 | [32]: http://link.zhihu.com/?target=http%3A//www.cs.toronto.edu/%257Etijmen/csc321/slides/lecture_slides_lec6.pdf 312 | [33]: http://link.zhihu.com/?target=http%3A//arxiv.org/abs/1412.6980 313 | [34]: http://link.zhihu.com/?target=http%3A//arxiv.org/abs/1312.6055 314 | [35]: http://pic4.zhimg.com/7fd7404711c99456237cdff7b3a3bad7_b.png 315 | [36]: http://link.zhihu.com/?target=https%3A//twitter.com/alecrad 316 | [37]: http://link.zhihu.com/?target=http%3A//www.jmlr.org/papers/volume13/bergstra12a/bergstra12a.pdf 317 | [38]: http://pic4.zhimg.com/d25cf561835c7b96ae6d1c91868bcbff_b.png 318 | [39]: http://link.zhihu.com/?target=https%3A//github.com/JasperSnoek/spearmint 319 | [40]: http://link.zhihu.com/?target=http%3A//www.cs.ubc.ca/labs/beta/Projects/SMAC/ 320 | [41]: http://link.zhihu.com/?target=http%3A//jaberg.github.io/hyperopt/ 321 | [42]: http://link.zhihu.com/?target=http%3A//nlpers.blogspot.com/2014/10/hyperparameter-search-bayesian.html 322 | [43]: http://link.zhihu.com/?target=https%3A//www.youtube.com/watch%3Fv%3DEK61htlw8hY 323 | [44]: http://link.zhihu.com/?target=http%3A//research.microsoft.com/pubs/192769/tricks-2012.pdf 324 | [45]: http://link.zhihu.com/?target=http%3A//yann.lecun.com/exdb/publis/pdf/lecun-98b.pdf 325 | [46]: http://link.zhihu.com/?target=http%3A//arxiv.org/pdf/1206.5533v2.pdf 326 | -------------------------------------------------------------------------------- /CS231n 5:反向传播笔记.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | # CS231n课程笔记翻译:反向传播笔记 - 知乎专栏 5 | 6 | 7 | ![CS231n课程笔记翻译:反向传播笔记][4] 8 | 9 | [杜客][6] [Source](https://zhuanlan.zhihu.com/p/21407711?refer=intelligentunit "Permalink to CS231n课程笔记翻译:反向传播笔记 - 知乎专栏") 10 | 11 | 译者注:本文[智能单元][2]首发,译自斯坦福CS231n课程笔记[Backprop Note__][7],课程教师[Andrej Karpathy__][8]授权翻译。本篇教程由[杜客][6]翻译完成,[堃堃][9]和[巩子嘉][10]进行校对修改。译文含公式和代码,建议PC端阅读。 12 | 13 | 14 | 15 | ## 原文如下: 16 | 17 | 内容列表: 18 | 19 | * 简介 20 | * 简单表达式和理解梯度 21 | * 复合表达式,链式法则,反向传播 22 | * 直观理解反向传播 23 | * 模块:Sigmoid例子 24 | * 反向传播实践:分段计算 25 | * 回传流中的模式 26 | * 用户向量化操作的梯度 27 | * 小结 28 | 29 | ## 简介 30 | 31 | **目标**:本节将帮助读者对**反向传播**形成直观而专业的理解。反向传播是利用**链式法则**递归计算表达式的梯度的方法。理解反向传播过程及其精妙之处,对于理解、实现、设计和调试神经网络非常**关键**。 32 | 33 | **问题陈述**:这节的核心问题是:给定函数![f\(x\)][11] ,其中![x][12]是输入数据的向量,需要计算函数![f][13]关于![x][12]的梯度,也就是![nabla f\(x\)][14]。 34 | 35 | 36 | 37 | **目标**:之所以关注上述问题,是因为在神经网络中![f][13]对应的是损失函数(![L][15]),输入![x][12]里面包含训练数据和神经网络的权重。举个例子,损失函数可以是SVM的损失函数,输入则包含了训练数据![\(x_i,y_i\),i=1...N][16]、权重![W][17]和偏差![b][18]。注意训练集是给定的(在机器学习中通常都是这样),而权重是可以控制的变量。因此,即使能用反向传播计算输入数据![x_i][19] 上的梯度,但在实践为了进行参数更新,通常也只计算参数(比如![W,b][20])的梯度。然而![x_i 38 | ][21] 的梯度有时仍然是有用的:比如将神经网络所做的事情可视化便于直观理解的时候,就能用上。 39 | 40 | 41 | 42 | 如果读者之前对于利用链式法则计算偏微分已经很熟练,仍然建议浏览本篇笔记。因为它呈现了一个相对成熟的反向传播视角,在该视角中能看见基于实数值回路的反向传播过程,而对其细节的理解和收获将帮助读者更好地通过本课程。 43 | 44 | ## 简单表达式和理解梯度 45 | 46 | 从简单表达式入手可以为复杂表达式打好符号和规则基础。先考虑一个简单的二元乘法函数![f\(x,y\)=xy][22]。对两个输入变量分别求偏导数还是很简单的: 47 | 48 | ![displaystyle f\(x,y\)=xy to frac {df}{dx}=y quad frac {df}{dy}=x][23] 49 | 50 | **解释**:牢记这些导数的意义:函数变量在某个点周围的极小区域内变化,而导数就是变量变化导致的函数在该方向上的变化率。 51 | 52 | ![frac{df\(x\)}{dx}= lim_{hto 0}frac{f\(x+h\)-f\(x\)}{h}][24] 53 | 54 | 注意等号左边的分号和等号右边的分号不同,不是代表分数。相反,这个符号表示操作符![frac{d}{dx}][25]被应用于函数![f][13],并返回一个不同的函数(导数)。对于上述公式,可以认为![h][26]值非常小,函数可以被一条直线近似,而导数就是这条直线的斜率。换句话说,每个变量的导数指明了整个表达式对于该变量的值的敏感程度。比如,若![x=4,y=-3][27],则![f\(x,y\)=-12][28],![x][12]的导数![frac{partial f}{partial x}=-3][29]。这就说明如果将变量![x][12]的值变大一点,整个表达式的值就会变小(原因在于负号),而且变小的量是![x][12]变大的量的三倍。通过重新排列公式可以看到这一点(![f\(x+h\)=f\(x\)+h frac{df\(x\)}{dx}][30])。同样,因为![frac{partial f}{partial y}=4][31],可以知道如果将![y][32]的值增加![h][26],那么函数的输出也将增加(原因在于正号),且增加量是![4h][33]。 55 | 56 | > 函数关于每个变量的导数指明了整个表达式对于该变量的敏感程度。 57 | 58 | 如上所述,梯度![nabla f][34]是偏导数的向量,所以有![nabla f\(x\)=\[frac{partial f}{partial x},frac{partial f}{partial y}\]=\[y,x\]][35]。即使是梯度实际上是一个向量,仍然通常使用类似"_x上的梯度_"的术语,而不是使用如"_x的偏导数_"的正确说法,原因是因为前者说起来简单。 59 | 60 | 我们也可以对加法操作求导: 61 | 62 | ![displaystyle f\(x,y\)=x+y to frac {df}{dx}=1quadfrac {df}{dy}=1][36] 63 | 64 | 这就是说,无论其值如何,![x,y][37]的导数均为1。这是有道理的,因为无论增加![x,y][37]中任一个的值,函数![f][13]的值都会增加,并且增加的变化率独立于![x,y][37]的具体值(情况和乘法操作不同)。取最大值操作也是常常使用的: 65 | ![displaystyle f\(x,y\)=max\(x,y\) to frac {df}{dx}=1 \(x>=y\) quadfrac {df}{dy}=1 \(y>=x\)][38] 66 | 67 | 上式是说,如果该变量比另一个变量大,那么梯度是1,反之为0。例如,若![x=4,y=2][39],那么max是4,所以函数对于![y][32]就不敏感。也就是说,在![y][32]上增加![h][26],函数还是输出为4,所以梯度是0:因为对于函数输出是没有效果的。当然,如果给![y][32]增加一个很大的量,比如大于2,那么函数![f][13]的值就变化了,但是导数并没有指明输入量有巨大变化情况对于函数的效果,他们只适用于输入量变化极小时的情况,因为定义已经指明:![lim_{hto 0}][40]。 68 | 69 | ## 使用链式法则计算复合表达式 70 | 71 | 现在考虑更复杂的包含多个函数的复合函数,比如![f\(x,y,z\)=\(x+y\)z][41]。虽然这个表达足够简单,可以直接微分,但是在此使用一种有助于读者直观理解反向传播的方法。将公式分成两部分:![q=x+y][42]和![f=qz][43]。在前面已经介绍过如何对这分开的两个公式进行计算,因为![f][13]是![q][44]和![z][45]相乘,所以![displaystylefrac{partial f}{partial q}=z,frac{partial f}{partial z}=q][46],又因为![q][44]是![x][12]加![y][32],所以![displaystylefrac{partial q}{partial x}=1,frac{partial q}{partial y}=1][47]。然而,并不需要关心中间量![q][44]的梯度,因为![frac{partial f}{partial q}][48]没有用。相反,函数![f][13]关于![x,y,z][49]的梯度才是需要关注的。**链式法则**指出将这些梯度表达式链接起来的正确方式是相乘,比如![displaystylefrac{partial f}{partial x}=frac{partial f}{partial q}frac{partial q}{partial x}][50]。在实际操作中,这只是简单地将两个梯度数值相乘,示例代码如下: 72 | 73 | 74 | 75 | 76 | 77 | ```py 78 | # 设置输入值 79 | x = -2; y = 5; z = -4 80 | 81 | # 进行前向传播 82 | q = x + y # q becomes 3 83 | f = q * z # f becomes -12 84 | 85 | # 进行反向传播: 86 | # 首先回传到 f = q * z 87 | dfdz = q # df/dz = q, 所以关于z的梯度是3 88 | dfdq = z # df/dq = z, 所以关于q的梯度是-4 89 | # 现在回传到q = x + y 90 | dfdx = 1.0 * dfdq # dq/dx = 1. 这里的乘法是因为链式法则 91 | dfdy = 1.0 * dfdq # dq/dy = 1 92 | 93 | ``` 94 | 95 | 最后得到变量的梯度[**dfdx, dfdy, dfdz]**,它们告诉我们函数**f**对于变量[**x, y, z]**的敏感程度。这是一个最简单的反向传播。一般会使用一个更简洁的表达符号,这样就不用写**df**了。这就是说,用**dq**来代替**dfdq**,且总是假设梯度是关于最终输出的。 96 | 97 | 这次计算可以被可视化为如下计算线路图像: 98 | 99 | ———————————————————————————————————————— 100 | 101 | ![][51]上图的真实值计算线路展示了计算的视觉化过程。**前向传播**从输入计算到输出(绿色),**反向传播**从尾部开始,根据链式法则递归地向前计算梯度(显示为红色),一直到网络的输入端。可以认为,梯度是从计算链路中回流。 102 | 103 | 104 | 105 | ———————————————————————————————————————— 106 | 107 | ## 反向传播的直观理解 108 | 109 | 反向传播是一个优美的局部过程。在整个计算线路图中,每个门单元都会得到一些输入并立即计算两个东西:1. 这个门的输出值,和2.其输出值关于输入值的局部梯度。门单元完成这两件事是完全独立的,它不需要知道计算线路中的其他细节。然而,一旦前向传播完毕,在反向传播的过程中,门单元门将最终获得整个网络的最终输出值在自己的输出值上的梯度。链式法则指出,门单元应该将回传的梯度乘以它对其的输入的局部梯度,从而得到整个网络的输出对该门单元的每个输入值的梯度。 110 | 111 | > 这里对于每个输入的乘法操作是基于链式法则的。该操作让一个相对独立的门单元变成复杂计算线路中不可或缺的一部分,这个复杂计算线路可以是神经网络等。 112 | 113 | 下面通过例子来对这一过程进行理解。加法门收到了输入[-2, 5],计算输出是3。既然这个门是加法操作,那么对于两个输入的局部梯度都是+1。网络的其余部分计算出最终值为-12。在反向传播时将递归地使用链式法则,算到加法门(是乘法门的输入)的时候,知道加法门的输出的梯度是-4。如果网络如果想要输出值更高,那么可以认为它会想要加法门的输出更小一点(因为负号),而且还有一个4的倍数。继续递归并对梯度使用链式法则,加法门拿到梯度,然后把这个梯度分别乘到每个输入值的局部梯度(就是让-4乘以**x**和**y**的局部梯度,x和y的局部梯度都是1,所以最终都是-4)。可以看到得到了想要的效果:如果**x,y减小**(它们的梯度为负),那么加法门的输出值减小,这会让乘法门的输出值增大。 114 | 115 | 因此,反向传播可以看做是门单元之间在通过梯度信号相互通信,只要让它们的输入沿着梯度方向变化,无论它们自己的输出值在何种程度上升或降低,都是为了让整个网络的输出值更高。 116 | 117 | ## 模块化:Sigmoid例子 118 | 119 | 上面介绍的门是相对随意的。任何可微分的函数都可以看做门。可以将多个门组合成一个门,也可以根据需要将一个函数分拆成多个门。现在看看一个表达式: 120 | 121 | ![displaystyle f\(w,x\)=frac{1}{1+e^{-\(w_0x_0+w_1x_1+w_2\)}}][52] 122 | 123 | 在后面的课程中可以看到,这个表达式描述了一个含输入**x**和权重**w**的2维的神经元,该神经元使用了_sigmoid激活_函数。但是现在只是看做是一个简单的输入为x和w,输出为一个数字的函数。这个函数是由多个门组成的。除了上文介绍的加法门,乘法门,取最大值门,还有下面这4种: 124 | 125 | 126 | ![displaystyle f\(x\)=frac{1}{x} to frac{df}{dx}=-1/x^2][53] 127 | ![displaystyle f_c\(x\)=c+x to frac{df}{dx}=1][54]![displaystyle f\(x\)=e^x to frac{df}{dx}=e^x][55] 128 | ![displaystyle f_a\(x\)=ax to frac{df}{dx}=a][56] 129 | 130 | 其中,函数![f_c][57]使用对输入值进行了常量![c][58]的平移,![f_a][59]将输入值扩大了常量![a][60]倍。它们是加法和乘法的特例,但是这里将其看做一元门单元,因为确实需要计算常量![c,a][61]的梯度。整个计算线路如下: 131 | 132 | 133 | 134 | ——————————————————————————————————————— 135 | 136 | ![][62] 137 | 138 | 使用sigmoid激活函数的2维神经元的例子。输入是[x0, x1],可学习的权重是[w0, w1, w2]。一会儿会看见,这个神经元对输入数据做点积运算,然后其激活数据被sigmoid函数挤压到0到1之间。 139 | 140 | ———————————————————————————————————————— 141 | 142 | 在上面的例子中可以看见一个函数操作的长链条,链条上的门都对**w**和**x**的点积结果进行操作。该函数被称为sigmoid函数![sigma \(x\)][63]。sigmoid函数关于其输入的求导是可以简化的(使用了在分子上先加后减1的技巧): 143 | 144 | ![displaystylesigma\(x\)=frac{1}{1+e^{-x}}][64] 145 | ![displaystyletofrac{dsigma\(x\)}{dx}=frac{e^{-x}}{\(1+e^{-x}\)^2}=\(frac{1+e^{-x}-1}{1+e^{-x}}\)\(frac{1}{1+e^{-x}}\)=\(1-sigma\(x\)\)sigma\(x\)][65] 146 | 147 | 可以看到梯度计算简单了很多。举个例子,sigmoid表达式输入为1.0,则在前向传播中计算出输出为0.73。根据上面的公式,局部梯度为(1-0.73)*0.73~=0.2,和之前的计算流程比起来,现在的计算使用一个单独的简单表达式即可。因此,在实际的应用中将这些操作装进一个单独的门单元中将会非常有用。该神经元反向传播的代码实现如下: 148 | 149 | 150 | 151 | ```py 152 | w = [2,-3,-3] # 假设一些随机数据和权重 153 | x = [-1, -2] 154 | 155 | # 前向传播 156 | dot = w[0]*x[0] + w[1]*x[1] + w[2] 157 | f = 1.0 / (1 + math.exp(-dot)) # sigmoid函数 158 | 159 | # 对神经元反向传播 160 | ddot = (1 - f) * f # 点积变量的梯度, 使用sigmoid函数求导 161 | dx = [w[0] * ddot, w[1] * ddot] # 回传到x 162 | dw = [x[0] * ddot, x[1] * ddot, 1.0 * ddot] # 回传到w 163 | # 完成!得到输入的梯度 164 | 165 | 166 | ``` 167 | **实现提示:分段反向传播**。上面的代码展示了在实际操作中,为了使反向传播过程更加简洁,把向前传播分成不同的阶段将是很有帮助的。比如我们创建了一个中间变量**dot**,它装着**w**和**x**的点乘结果。在反向传播的时,就可以(反向地)计算出装着**w**和**x**等的梯度的对应的变量(比如**ddot**,**dx**和**dw**)。 168 | 169 | 170 | 171 | 本节的要点就是展示反向传播的细节过程,以及前向传播过程中,哪些函数可以被组合成门,从而可以进行简化。知道表达式中哪部分的局部梯度计算比较简洁非常有用,这样他们可以"链"在一起,让代码量更少,效率更高。 172 | 173 | ## 反向传播实践:分段计算 174 | 175 | 看另一个例子。假设有如下函数: 176 | 177 | ![displaystyle f\(x,y\)=frac{x+sigma\(y\)}{sigma\(x\)+\(x+y\)^2}][66] 178 | 179 | 首先要说的是,这个函数完全没用,读者是不会用到它来进行梯度计算的,这里只是用来作为实践反向传播的一个例子,需要强调的是,如果对![x][12]或![y][32]进行微分运算,运算结束后会得到一个巨大而复杂的表达式。然而做如此复杂的运算实际上并无必要,因为我们不需要一个明确的函数来计算梯度,只需知道如何使用反向传播计算梯度即可。下面是构建前向传播的代码模式: 180 | 181 | 182 | 183 | ```py 184 | x = 3 # 例子数值 185 | y = -4 186 | 187 | # 前向传播 188 | sigy = 1.0 / (1 + math.exp(-y)) # 分子中的sigmoi #(1) 189 | num = x + sigy # 分子 #(2) 190 | sigx = 1.0 / (1 + math.exp(-x)) # 分母中的sigmoid #(3) 191 | xpy = x + y #(4) 192 | xpysqr = xpy**2 #(5) 193 | den = sigx + xpysqr # 分母 #(6) 194 | invden = 1.0 / den #(7) 195 | f = num * invden # 搞定! #(8) 196 | 197 | ``` 198 | 199 | ┗|`O′|┛ 嗷~~,到了表达式的最后,就完成了前向传播。注意在构建代码s时创建了多个中间变量,每个都是比较简单的表达式,它们计算局部梯度的方法是已知的。这样计算反向传播就简单了:我们对前向传播时产生每个变量(**sigy, num, sigx, xpy, xpysqr, den, invden**)进行回传。我们会有同样数量的变量,但是都以**d**开头,用来存储对应变量的梯度。注意在反向传播的每一小块中都将包含了表达式的局部梯度,然后根据使用链式法则乘以上游梯度。对于每行代码,我们将指明其对应的是前向传播的哪部分。 200 | 201 | 202 | 203 | 204 | 205 | ```py 206 | # 回传 f = num * invden 207 | dnum = invden # 分子的梯度 #(8) 208 | dinvden = num #(8) 209 | # 回传 invden = 1.0 / den 210 | dden = (-1.0 / (den**2)) * dinvden #(7) 211 | # 回传 den = sigx + xpysqr 212 | dsigx = (1) * dden #(6) 213 | dxpysqr = (1) * dden #(6) 214 | # 回传 xpysqr = xpy**2 215 | dxpy = (2 * xpy) * dxpysqr #(5) 216 | # 回传 xpy = x + y 217 | dx = (1) * dxpy #(4) 218 | dy = (1) * dxpy #(4) 219 | # 回传 sigx = 1.0 / (1 + math.exp(-x)) 220 | dx += ((1 - sigx) * sigx) * dsigx # Notice += !! See notes below #(3) 221 | # 回传 num = x + sigy 222 | dx += (1) * dnum #(2) 223 | dsigy = (1) * dnum #(2) 224 | # 回传 sigy = 1.0 / (1 + math.exp(-y)) 225 | dy += ((1 - sigy) * sigy) * dsigy #(1) 226 | # 完成! 嗷~~ 227 | 228 | ``` 229 | 230 | 需要注意的一些东西: 231 | 232 | **对前向传播变量进行缓存**:在计算反向传播时,前向传播过程中得到的一些中间变量非常有用。在实际操作中,最好代码实现对于这些中间变量的缓存,这样在反向传播的时候也能用上它们。如果这样做过于困难,也可以(但是浪费计算资源)重新计算它们。 233 | 234 | **在不同分支的梯度要相加**:如果变量x,y在前向传播的表达式中出现多次,那么进行反向传播的时候就要非常小心,使用**+=**而不是**=**来累计这些变量的梯度(不然就会造成覆写)。这是遵循了在微积分中的_多元链式法则_,该法则指出如果变量在线路中分支走向不同的部分,那么梯度在回传的时候,就应该进行累加。 235 | 236 | 237 | 238 | ## 回传流中的模式 239 | 240 | 一个有趣的现象是在多数情况下,反向传播中的梯度可以被很直观地解释。例如神经网络中最常用的加法、乘法和取最大值这三个门单元,它们在反向传播过程中的行为都有非常简单的解释。先看下面这个例子: 241 | 242 | —————————————————————————————————————————— 243 | 244 | ![][67]一个展示反向传播的例子。加法操作将梯度相等地分发给它的输入。取最大操作将梯度路由给更大的输入。乘法门拿取输入激活数据,对它们进行交换,然后乘以梯度。 245 | 246 | —————————————————————————————————————————— 247 | 248 | 从上例可知: 249 | 250 | **加法门单元**把输出的梯度相等地分发给它所有的输入,这一行为与输入值在前向传播时的值无关。这是因为加法操作的局部梯度都是简单的+1,所以所有输入的梯度实际上就等于输出的梯度,因为乘以1.0保持不变。上例中,加法门把梯度2.00不变且相等地路由给了两个输入。 251 | 252 | **取最大值门单元**对梯度做路由。和加法门不同,取最大值门将梯度转给其中一个输入,这个输入是在前向传播中值最大的那个输入。这是因为在取最大值门中,最高值的局部梯度是1.0,其余的是0。上例中,取最大值门将梯度2.00转给了**z**变量,因为**z**的值比**w**高,于是**w**的梯度保持为0。 253 | 254 | **乘法门单元**相对不容易解释。它的局部梯度就是输入值,但是是相互交换之后的,然后根据链式法则乘以输出值的梯度。上例中,**x**的梯度是-4.00x2.00=-8.00。 255 | 256 | _非直观影响及其结果_。注意一种比较特殊的情况,如果乘法门单元的其中一个输入非常小,而另一个输入非常大,那么乘法门的操作将会不是那么直观:它将会把大的梯度分配给小的输入,把小的梯度分配给大的输入。在线性分类器中,权重和输入是进行点积![w^Tx_i][68],这说明输入数据的大小对于权重梯度的大小有影响。例如,在计算过程中对所有输入数据样本![x_i][19]乘以1000,那么权重的梯度将会增大1000倍,这样就必须降低学习率来弥补。这就是为什么数据预处理关系重大,它即使只是有微小变化,也会产生巨大影响。对于梯度在计算线路中是如何流动的有一个直观的理解,可以帮助读者调试网络。 257 | 258 | ## 用向量化操作计算梯度 259 | 260 | 上述内容考虑的都是单个变量情况,但是所有概念都适用于矩阵和向量操作。然而,在操作的时候要注意关注维度和转置操作。 261 | 262 | **矩阵相乘的梯度**:可能最有技巧的操作是矩阵相乘(也适用于矩阵和向量,向量和向量相乘)的乘法操作: 263 | 264 | 265 | 266 | ```py 267 | # 前向传播 268 | W = np.random.randn(5, 10) 269 | X = np.random.randn(10, 3) 270 | D = W.dot(X) 271 | 272 | # 假设我们得到了D的梯度 273 | dD = np.random.randn(*D.shape) # 和D一样的尺寸 274 | dW = dD.dot(X.T) #.T就是对矩阵进行转置 275 | dX = W.T.dot(dD) 276 | 277 | ``` 278 | 279 | _提示:要分析维度!_注意不需要去记忆**dW**和**dX**的表达,因为它们很容易通过维度推导出来。例如,权重的梯度dW的尺寸肯定和权重矩阵W的尺寸是一样的,而这又是由**X**和**dD**的矩阵乘法决定的(在上面的例子中**X**和**W**都是数字不是矩阵)。总有一个方式是能够让维度之间能够对的上的。例如,**X**的尺寸是[10x3],**dD**的尺寸是[5x3],如果你想要dW和W的尺寸是[5x10],那就要**dD.dot(X.T)**。 280 | 281 | **使用小而具体的例子**:有些读者可能觉得向量化操作的梯度计算比较困难,建议是写出一个很小很明确的向量化例子,在纸上演算梯度,然后对其一般化,得到一个高效的向量化操作形式。 282 | 283 | ## 小结 284 | 285 | * 对梯度的含义有了直观理解,知道了梯度是如何在网络中反向传播的,知道了它们是如何与网络的不同部分通信并控制其升高或者降低,并使得最终输出值更高的。 286 | * 讨论了**分段计算**在反向传播的实现中的重要性。应该将函数分成不同的模块,这样计算局部梯度相对容易,然后基于链式法则将其"链"起来。重要的是,不需要把这些表达式写在纸上然后演算它的完整求导公式,因为实际上并不需要关于输入变量的梯度的数学公式。只需要将表达式分成不同的可以求导的模块(模块可以是矩阵向量的乘法操作,或者取最大值操作,或者加法操作等),然后在反向传播中一步一步地计算梯度。 287 | 288 | 在下节课中,将会开始定义神经网络,而反向传播使我们能高效计算神经网络各个节点关于损失函数的梯度。换句话说,我们现在已经准备好训练神经网络了,本课程最困难的部分已经过去了!ConvNets相比只是向前走了一小步。 289 | 290 | ## 参考文献 291 | 292 | * [Automatic differentiation in machine learning: a survey__][69] 293 | 294 | **反向传播笔记全文翻译完**。 295 | 296 | ## 译者反馈 297 | 298 | 1. 转载须全文转载注明原文链接,否则保留维权权利; 299 | 300 | 2. **知乎上关于反向传播的问题很多,希望知友们能点赞帮助本文广泛传播为更多人解惑**; 301 | 3. 请知友们通过评论和私信等方式批评指正,贡献者均会补充提及; 302 | 4. 感谢知友[roach sinai][70]、[郑申海][71]和[陈一][72]的细节修改建议。 303 | 304 | [1]: https://pic4.zhimg.com/4a97d93d652f45ededf2ebab9a13f22b_m.jpeg 305 | [2]: https://zhuanlan.zhihu.com/intelligentunit 306 | [3]: https://zhuanlan.zhihu.com/write 307 | [4]: https://pic2.zhimg.com/6cfac1401554ece6dac25a7ef7f7fe79_r.jpg 308 | [5]: https://pic2.zhimg.com/5ab5b93bd_xs.jpg 309 | [6]: https://www.zhihu.com/people/du-ke 310 | [7]: http://link.zhihu.com/?target=http%3A//cs231n.github.io/optimization-2/ 311 | [8]: http://link.zhihu.com/?target=http%3A//cs.stanford.edu/people/karpathy/ 312 | [9]: https://www.zhihu.com/people/kun-kun-97-81 313 | [10]: https://www.zhihu.com/people/hmonkey 314 | [11]: http://zhihu.com/equation?tex=f%28x%29 315 | [12]: http://zhihu.com/equation?tex=x 316 | [13]: http://zhihu.com/equation?tex=f 317 | [14]: http://zhihu.com/equation?tex=%5Cnabla+f%28x%29 318 | [15]: http://zhihu.com/equation?tex=L 319 | [16]: http://zhihu.com/equation?tex=%28x_i%2Cy_i%29%2Ci%3D1...N 320 | [17]: http://zhihu.com/equation?tex=W 321 | [18]: http://zhihu.com/equation?tex=b 322 | [19]: http://zhihu.com/equation?tex=x_i 323 | [20]: http://zhihu.com/equation?tex=W%2Cb 324 | [21]: http://zhihu.com/equation?tex=x_i%0A 325 | [22]: http://zhihu.com/equation?tex=f%28x%2Cy%29%3Dxy 326 | [23]: http://zhihu.com/equation?tex=%5Cdisplaystyle+f%28x%2Cy%29%3Dxy+%5Cto+%5Cfrac+%7Bdf%7D%7Bdx%7D%3Dy+%5Cquad+%5Cfrac+%7Bdf%7D%7Bdy%7D%3Dx 327 | [24]: http://zhihu.com/equation?tex=%5Cfrac%7Bdf%28x%29%7D%7Bdx%7D%3D+lim_%7Bh%5Cto+0%7D%5Cfrac%7Bf%28x%2Bh%29-f%28x%29%7D%7Bh%7D 328 | [25]: http://zhihu.com/equation?tex=%5Cfrac%7Bd%7D%7Bdx%7D 329 | [26]: http://zhihu.com/equation?tex=h 330 | [27]: http://zhihu.com/equation?tex=x%3D4%2Cy%3D-3 331 | [28]: http://zhihu.com/equation?tex=f%28x%2Cy%29%3D-12 332 | [29]: http://zhihu.com/equation?tex=%5Cfrac%7B%5Cpartial+f%7D%7B%5Cpartial+x%7D%3D-3 333 | [30]: http://zhihu.com/equation?tex=f%28x%2Bh%29%3Df%28x%29%2Bh+%5Cfrac%7Bdf%28x%29%7D%7Bdx%7D 334 | [31]: http://zhihu.com/equation?tex=%5Cfrac%7B%5Cpartial+f%7D%7B%5Cpartial+y%7D%3D4 335 | [32]: http://zhihu.com/equation?tex=y 336 | [33]: http://zhihu.com/equation?tex=4h 337 | [34]: http://zhihu.com/equation?tex=%5Cnabla+f 338 | [35]: http://zhihu.com/equation?tex=%5Cnabla+f%28x%29%3D%5B%5Cfrac%7B%5Cpartial+f%7D%7B%5Cpartial+x%7D%2C%5Cfrac%7B%5Cpartial+f%7D%7B%5Cpartial+y%7D%5D%3D%5By%2Cx%5D 339 | [36]: http://zhihu.com/equation?tex=%5Cdisplaystyle+f%28x%2Cy%29%3Dx%2By+%5Cto+%5Cfrac+%7Bdf%7D%7Bdx%7D%3D1%5Cquad%5Cfrac+%7Bdf%7D%7Bdy%7D%3D1 340 | [37]: http://zhihu.com/equation?tex=x%2Cy 341 | [38]: http://zhihu.com/equation?tex=%5Cdisplaystyle+f%28x%2Cy%29%3Dmax%28x%2Cy%29+%5Cto+%5Cfrac+%7Bdf%7D%7Bdx%7D%3D1+%28x%3E%3Dy%29+%5Cquad%5Cfrac+%7Bdf%7D%7Bdy%7D%3D1+%28y%3E%3Dx%29 342 | [39]: http://zhihu.com/equation?tex=x%3D4%2Cy%3D2 343 | [40]: http://zhihu.com/equation?tex=lim_%7Bh%5Cto+0%7D 344 | [41]: http://zhihu.com/equation?tex=f%28x%2Cy%2Cz%29%3D%28x%2By%29z 345 | [42]: http://zhihu.com/equation?tex=q%3Dx%2By 346 | [43]: http://zhihu.com/equation?tex=f%3Dqz 347 | [44]: http://zhihu.com/equation?tex=q 348 | [45]: http://zhihu.com/equation?tex=z 349 | [46]: http://zhihu.com/equation?tex=%5Cdisplaystyle%5Cfrac%7B%5Cpartial+f%7D%7B%5Cpartial+q%7D%3Dz%2C%5Cfrac%7B%5Cpartial+f%7D%7B%5Cpartial+z%7D%3Dq 350 | [47]: http://zhihu.com/equation?tex=%5Cdisplaystyle%5Cfrac%7B%5Cpartial+q%7D%7B%5Cpartial+x%7D%3D1%2C%5Cfrac%7B%5Cpartial+q%7D%7B%5Cpartial+y%7D%3D1 351 | [48]: http://zhihu.com/equation?tex=%5Cfrac%7B%5Cpartial+f%7D%7B%5Cpartial+q%7D 352 | [49]: http://zhihu.com/equation?tex=x%2Cy%2Cz 353 | [50]: http://zhihu.com/equation?tex=%5Cdisplaystyle%5Cfrac%7B%5Cpartial+f%7D%7B%5Cpartial+x%7D%3D%5Cfrac%7B%5Cpartial+f%7D%7B%5Cpartial+q%7D%5Cfrac%7B%5Cpartial+q%7D%7B%5Cpartial+x%7D 354 | [51]: http://pic4.zhimg.com/213da7f66594510b45989bd134fc2d8b_b.jpg 355 | [52]: http://zhihu.com/equation?tex=%5Cdisplaystyle+f%28w%2Cx%29%3D%5Cfrac%7B1%7D%7B1%2Be%5E%7B-%28w_0x_0%2Bw_1x_1%2Bw_2%29%7D%7D 356 | [53]: http://zhihu.com/equation?tex=%5Cdisplaystyle+f%28x%29%3D%5Cfrac%7B1%7D%7Bx%7D+%5Cto+%5Cfrac%7Bdf%7D%7Bdx%7D%3D-1%2Fx%5E2 357 | [54]: http://zhihu.com/equation?tex=%5Cdisplaystyle+f_c%28x%29%3Dc%2Bx+%5Cto+%5Cfrac%7Bdf%7D%7Bdx%7D%3D1 358 | [55]: http://zhihu.com/equation?tex=%5Cdisplaystyle+f%28x%29%3De%5Ex+%5Cto+%5Cfrac%7Bdf%7D%7Bdx%7D%3De%5Ex 359 | [56]: http://zhihu.com/equation?tex=%5Cdisplaystyle+f_a%28x%29%3Dax+%5Cto+%5Cfrac%7Bdf%7D%7Bdx%7D%3Da 360 | [57]: http://zhihu.com/equation?tex=f_c 361 | [58]: http://zhihu.com/equation?tex=c 362 | [59]: http://zhihu.com/equation?tex=f_a 363 | [60]: http://zhihu.com/equation?tex=a 364 | [61]: http://zhihu.com/equation?tex=c%2Ca 365 | [62]: http://pic1.zhimg.com/0799b3d6e5e92245ee937db3c26d1b80_b.png 366 | [63]: http://zhihu.com/equation?tex=%5Csigma+%28x%29 367 | [64]: http://zhihu.com/equation?tex=%5Cdisplaystyle%5Csigma%28x%29%3D%5Cfrac%7B1%7D%7B1%2Be%5E%7B-x%7D%7D 368 | [65]: http://zhihu.com/equation?tex=%5Cdisplaystyle%5Cto%5Cfrac%7Bd%5Csigma%28x%29%7D%7Bdx%7D%3D%5Cfrac%7Be%5E%7B-x%7D%7D%7B%281%2Be%5E%7B-x%7D%29%5E2%7D%3D%28%5Cfrac%7B1%2Be%5E%7B-x%7D-1%7D%7B1%2Be%5E%7B-x%7D%7D%29%28%5Cfrac%7B1%7D%7B1%2Be%5E%7B-x%7D%7D%29%3D%281-%5Csigma%28x%29%29%5Csigma%28x%29 369 | [66]: http://zhihu.com/equation?tex=%5Cdisplaystyle+f%28x%2Cy%29%3D%5Cfrac%7Bx%2B%5Csigma%28y%29%7D%7B%5Csigma%28x%29%2B%28x%2By%29%5E2%7D 370 | [67]: http://pic2.zhimg.com/39162d0c528144362cc09f1965d710d1_b.jpg 371 | [68]: http://zhihu.com/equation?tex=w%5ETx_i 372 | [69]: http://link.zhihu.com/?target=http%3A//arxiv.org/abs/1502.05767 373 | [70]: https://www.zhihu.com/people/roachsinai 374 | [71]: https://www.zhihu.com/people/zheng-shen-hai 375 | [72]: https://www.zhihu.com/people/chen-yi-91-27 376 | -------------------------------------------------------------------------------- /CS231n 2.1:图像分类笔记(上).md: -------------------------------------------------------------------------------- 1 | 2 | # CS231n课程笔记翻译:图像分类笔记(上) - 知乎专栏 3 | 4 | 5 | ![CS231n课程笔记翻译:图像分类笔记(上)][4] 6 | 7 | 8 | [杜客][6] [Source](https://zhuanlan.zhihu.com/p/20894041?refer=intelligentunit "Permalink to CS231n课程笔记翻译:图像分类笔记(上) - 知乎专栏") 9 | 10 | **译者注**:本文[智能单元][2]首发,译自斯坦福CS231n课程笔记[image classification notes__][7],由课程教师[Andrej Karpathy__][8]授权进行翻译。本篇教程由[杜客][6]翻译完成。[ShiqingFan][9]对译文进行了仔细校对,提出了大量修改建议,态度严谨,帮助甚多。[巩子嘉][10]对几处术语使用和翻译优化也提出了很好的建议。[张欣][11]等亦有帮助。 11 | 12 | ## 原文如下 13 | 14 | 这是一篇介绍性教程,面向非计算机视觉领域的同学。教程将向同学们介绍图像分类问题和数据驱动方法。下面是**内容列表**: 15 | 16 | 17 | 18 | * 图像分类、数据驱动方法和流程 19 | * Nearest Neighbor分类器 20 | * k-Nearest Neighbor _**译者注:上篇翻译截止处**_ 21 | * 验证集、交叉验证集和超参数调参 22 | * Nearest Neighbor的优劣 23 | * 小结 24 | * 小结:应用kNN实践 25 | * 拓展阅读 26 | 27 | ## 图像分类 28 | 29 | **目标**:这一节我们将介绍图像分类问题。所谓图像分类问题,就是已有固定的分类标签集合,然后对于输入的图像,从分类标签集合中找出一个分类标签,最后把分类标签分配给该输入图像。虽然看起来挺简单的,但这可是计算机视觉领域的核心问题之一,并且有着各种各样的实际应用。在后面的课程中,我们可以看到计算机视觉领域中很多看似不同的问题(比如物体检测和分割),都可以被归结为图像分类问题。 30 | 31 | **例子**:以下图为例,图像分类模型读取该图片,并生成该图片属于集合 {cat, dog, hat, mug}中各个标签的概率。需要注意的是,对于计算机来说,图像是一个由数字组成的巨大的3维数组。在这个例子中,猫的图像大小是宽248像素,高400像素,有3个颜色通道,分别是红、绿和蓝(简称RGB)。如此,该图像就包含了248X400X3=297600个数字,每个数字都是在范围0-255之间的整型,其中0表示全黑,255表示全白。我们的任务就是把这些上百万的数字变成一个简单的标签,比如"猫"。 32 | 33 | ————————————————————————————————————————— 34 | 35 | ![][12]图像分类的任务,就是对于一个给定的图像,预测它属于的那个分类标签(或者给出属于一系列不同标签的可能性)。图像是3维数组,数组元素是取值范围从0到255的整数。数组的尺寸是宽度x高度x3,其中这个3代表的是红、绿和蓝3个颜色通道。 36 | 37 | ————————————————————————————————————————— 38 | 39 | **困难和挑战**:对于人来说,识别出一个像"猫"一样视觉概念是简单至极的,然而从计算机视觉算法的角度来看就值得深思了。我们在下面列举了计算机视觉算法在图像识别方面遇到的一些困难,要记住图像是以3维数组来表示的,数组中的元素是亮度值。 40 | 41 | * **视角变化(**Viewpoint variation**)**:同一个物体,摄像机可以从多个角度来展现。 42 | * **大小变化(**Scale variation**)**:物体可视的大小通常是会变化的(不仅是在图片中,在真实世界中大小也是变化的)。 43 | * **形变(**Deformation**)**:很多东西的形状并非一成不变,会有很大变化。 44 | * **遮挡(**Occlusion**)**:目标物体可能被挡住。有时候只有物体的一小部分(可以小到几个像素)是可见的。 45 | * **光照条件(**Illumination conditions**)**:在像素层面上,光照的影响非常大。 46 | * **背景干扰(**Background clutter**)**:物体可能混入背景之中,使之难以被辨认。 47 | * **类内差异(**Intra-class variation**)**:一类物体的个体之间的外形差异很大,比如椅子。这一类物体有许多不同的对象,每个都有自己的外形。 48 | 49 | 面对以上所有变化及其组合,好的图像分类模型能够在维持分类结论稳定的同时,保持对类间差异足够敏感。 50 | 51 | ————————————————————————————————————————— 52 | 53 | ![][13]————————————————————————————————————————— 54 | 55 | **数据驱动方法**:如何写一个图像分类的算法呢?这和写个排序算法可是大不一样。怎么写一个从图像中认出猫的算法?搞不清楚。因此,与其在代码中直接写明各类物体到底看起来是什么样的,倒不如说我们采取的方法和教小孩儿看图识物类似:给计算机很多数据,然后实现学习算法,让计算机学习到每个类的外形。这种方法,就是_数据驱动方法_。既然该方法的第一步就是收集已经做好分类标注的图片来作为训练集,那么下面就看看数据库到底长什么样: 56 | 57 | ————————————————————————————————————————— 58 | 59 | ![][14]一个有4个视觉分类的训练集。在实际中,我们可能有上千的分类,每个分类都有成千上万的图像。 60 | 61 | ————————————————————————————————————————— 62 | 63 | **图像分类流程**。在课程视频中已经学习过,**图像分类**就是输入一个元素为像素值的数组,然后给它分配一个分类标签。完整流程如下: 64 | 65 | * **输入**:输入是包含N个图像的集合,每个图像的标签是K种分类标签中的一种。这个集合称为_训练集。_ 66 | * **学习**:这一步的任务是使用训练集来学习每个类到底长什么样。一般该步骤叫做_训练分类器_或者_学习一个模型_。 67 | * **评价**:让分类器来预测它未曾见过的图像的分类标签,并以此来评价分类器的质量。我们会把分类器预测的标签和图像真正的分类标签对比。毫无疑问,分类器预测的分类标签和图像真正的分类标签如果一致,那就是好事,这样的情况越多越好。 68 | 69 | ## Nearest Neighbor分类器 70 | 71 | 作为课程介绍的第一个方法,我们来实现一个**Nearest Neighbor分类器**。虽然这个分类器和卷积神经网络没有任何关系,实际中也极少使用,但通过实现它,可以让读者对于解决图像分类问题的方法有个基本的认识。 72 | 73 | **图像分类数据集:CIFAR-10。**一个非常流行的图像分类数据集是[CIFAR-10__][15]。这个数据集包含了60000张32X32的小图像。每张图像都有10种分类标签中的一种。这60000张图像被分为包含50000张图像的训练集和包含10000张图像的测试集。在下图中你可以看见10个类的10张随机图片。 74 | 75 | ————————————————————————————————————————— 76 | 77 | ![][16]**左边**:从[CIFAR-10__][15]数据库来的样本图像。**右边**:第一列是测试图像,然后第一列的每个测试图像右边是使用Nearest Neighbor算法,根据像素差异,从训练集中选出的10张最类似的图片。 78 | 79 | ————————————————————————————————————————— 80 | 81 | 假设现在我们有CIFAR-10的50000张图片(每种分类5000张)作为训练集,我们希望将余下的10000作为测试集并给他们打上标签。Nearest Neighbor算法将会拿着测试图片和训练集中每一张图片去比较,然后将它认为最相似的那个训练集图片的标签赋给这张测试图片。上面右边的图片就展示了这样的结果。请注意上面10个分类中,只有3个是准确的。比如第8行中,马头被分类为一个红色的跑车,原因在于红色跑车的黑色背景非常强烈,所以这匹马就被错误分类为跑车了。 82 | 83 | 那么具体如何比较两张图片呢?在本例中,就是比较32x32x3的像素块。最简单的方法就是逐个像素比较,最后将差异值全部加起来。换句话说,就是将两张图片先转化为两个向量![I_1][17]和![I_2][18],然后计算他们的**L1距离:** 84 | 85 | ![displaystyle d_1\(I_1,I_2\)=sum_p|I^p_1-I^p_2|][19] 86 | 87 | 这里的求和是针对所有的像素。下面是整个比较流程的图例: 88 | 89 | ————————————————————————————————————————— 90 | 91 | ![][20]以图片中的一个颜色通道为例来进行说明。两张图片使用L1距离来进行比较。逐个像素求差值,然后将所有差值加起来得到一个数值。如果两张图片一模一样,那么L1距离为0,但是如果两张图片很是不同,那L1值将会非常大。 92 | 93 | ————————————————————————————————————————— 94 | 95 | 下面,让我们看看如何用代码来实现这个分类器。首先,我们将CIFAR-10的数据加载到内存中,并分成4个数组:训练数据和标签,测试数据和标签。在下面的代码中,**Xtr**(大小是50000x32x32x3)存有训练集中所有的图像,**Ytr**是对应的长度为50000的1维数组,存有图像对应的分类标签(从0到9): 96 | 97 | 98 | Xtr, Ytr, Xte, Yte = load_CIFAR10('data/cifar10/') # a magic function we provide 99 | # flatten out all images to be one-dimensional 100 | Xtr_rows = Xtr.reshape(Xtr.shape[0], 32 * 32 * 3) # Xtr_rows becomes 50000 x 3072 101 | Xte_rows = Xte.reshape(Xte.shape[0], 32 * 32 * 3) # Xte_rows becomes 10000 x 3072 102 | 103 | 104 | 现在我们得到所有的图像数据,并且把他们拉长成为行向量了。接下来展示如何训练并评价一个分类器: 105 | 106 | 107 | 108 | nn = NearestNeighbor() # create a Nearest Neighbor classifier class 109 | nn.train(Xtr_rows, Ytr) # train the classifier on the training images and labels 110 | Yte_predict = nn.predict(Xte_rows) # predict labels on the test images 111 | # and now print the classification accuracy, which is the average number 112 | # of examples that are correctly predicted (i.e. label matches) 113 | print 'accuracy: %f' % ( np.mean(Yte_predict == Yte) ) 114 | 115 | 116 | 作为评价标准,我们常常使用**准确率**,它描述了我们预测正确的得分。请注意以后我们实现的所有分类器都需要有这个API:**train(X, y)**函数。该函数使用训练集的数据和标签来进行训练。从其内部来看,类应该实现一些关于标签和标签如何被预测的模型。这里还有个**predict(X)**函数,它的作用是预测输入的新数据的分类标签。现在还没介绍分类器的实现,下面就是使用L1距离的Nearest Neighbor分类器的实现套路: 117 | 118 | 119 | 120 | import numpy as np 121 | 122 | class NearestNeighbor(object): 123 | def __init__(self): 124 | pass 125 | 126 | def train(self, X, y): 127 | """ X is N x D where each row is an example. Y is 1-dimension of size N """ 128 | # the nearest neighbor classifier simply remembers all the training data 129 | self.Xtr = X 130 | self.ytr = y 131 | 132 | def predict(self, X): 133 | """ X is N x D where each row is an example we wish to predict label for """ 134 | num_test = X.shape[0] 135 | # lets make sure that the output type matches the input type 136 | Ypred = np.zeros(num_test, dtype = self.ytr.dtype) 137 | 138 | # loop over all test rows 139 | for i in xrange(num_test): 140 | # find the nearest training image to the i'th test image 141 | # using the L1 distance (sum of absolute value differences) 142 | distances = np.sum(np.abs(self.Xtr - X[i,:]), axis = 1) 143 | min_index = np.argmin(distances) # get the index with smallest distance 144 | Ypred[i] = self.ytr[min_index] # predict the label of the nearest example 145 | 146 | return Ypred 147 | 148 | 149 | 如果你用这段代码跑CIFAR-10,你会发现准确率能达到**38.6%**。这比随机猜测的10%要好,但是比人类识别的水平([据研究推测是94%__][21])和卷积神经网络能达到的95%还是差多了。点击查看基于CIFAR-10数据的[Kaggle算法竞赛排行榜__][22]。 150 | 151 | **距离选择**:计算向量间的距离有很多种方法,另一个常用的方法是**L2距离**,从几何学的角度,可以理解为它在计算两个向量间的欧式距离。L2距离的公式如下: 152 | 153 | ![displaystyle d_2\(I_1,I_2\)=sqrt{ sum_p\(I^p_1-I^p_2\)^2}][23] 154 | 155 | 换句话说,我们依旧是在计算像素间的差值,只是先求其平方,然后把这些平方全部加起来,最后对这个和开方。在Numpy中,我们只需要替换上面代码中的1行代码就行: 156 | 157 | 158 | 159 | distances = np.sqrt(np.sum(np.square(self.Xtr - X[i,:]), axis = 1)) 160 | 161 | 162 | 注意在这里使用了**np.sqrt**,但是在实际中可能不用。因为求平方根函数是一个_单调函数_,它对不同距离的绝对值求平方根虽然改变了数值大小,但依然保持了不同距离大小的顺序。所以用不用它,都能够对像素差异的大小进行正确比较。如果你在CIFAR-10上面跑这个模型,正确率是**35.4%**,比刚才低了一点。 163 | 164 | **L1和L2比较**。比较这两个度量方式是挺有意思的。在面对两个向量之间的差异时,L2比L1更加不能容忍这些差异。也就是说,相对于1个巨大的差异,L2距离更倾向于接受多个中等程度的差异。L1和L2都是在[p-norm__][24]常用的特殊形式。 165 | 166 | ## k-Nearest Neighbor分类器 167 | 168 | 你可能注意到了,为什么只用最相似的1张图片的标签来作为测试图像的标签呢?这不是很奇怪吗!是的,使用**k-Nearest Neighbor分类器**就能做得更好。它的思想很简单:与其只找最相近的那1个图片的标签,我们找最相似的k个图片的标签,然后让他们针对测试图片进行投票,最后把票数最高的标签作为对测试图片的预测。所以当k=1的时候,k-Nearest Neighbor分类器就是Nearest Neighbor分类器。从直观感受上就可以看到,更高的k值可以让分类的效果更平滑,使得分类器对于异常值更有抵抗力。 169 | 170 | ————————————————————————————————————————— 171 | 172 | ![][25]上面示例展示了Nearest Neighbor分类器和5-Nearest Neighbor分类器的区别。例子使用了2维的点来表示,分成3类(红、蓝和绿)。不同颜色区域代表的是使用L2距离的分类器的**决策边界**。白色的区域是分类模糊的例子(即图像与两个以上的分类标签绑定)。需要注意的是,在NN分类器中,异常的数据点(比如:在蓝色区域中的绿点)制造出一个不正确预测的孤岛。5-NN分类器将这些不规则都平滑了,使得它针对测试数据的**泛化(****generalization****)**能力更好(例子中未展示)。注意,5-NN中也存在一些灰色区域,这些区域是因为近邻标签的最高票数相同导致的(比如:2个邻居是红色,2个邻居是蓝色,还有1个是绿色)。 173 | 174 | ————————————————————————————————————————— 175 | 176 | 在实际中,大多使用k-NN分类器。但是k值如何确定呢?接下来就讨论这个问题。 177 | 178 | **图像分类笔记(上)完。** 179 | 180 | 点击查看[图像分类笔记(下)][26]。 181 | 182 | ## **译者反馈**: 183 | 184 | 1. 因CS231n的单篇课程笔记长度长,完整阅读需较长时间。知友[张欣][11]等建议对其进行适当分拆。故本次翻译将[图像分类笔记__][7]拆分为上下篇,每篇阅读量控制在1万字左右,**降低阅读成本**。效果如何,请知友们点评; 185 | 2. 知乎专栏的公式编辑器可以使用LaTeX语法,赞。但**公式居中需手动空格,有无更优雅的方式**?请知友们评论指教; 186 | 3. 翻译中的任何不足之处,请知友们在评论中批评指正,我们会及时讨论并作出反馈; 187 | 4. 本翻译是无偿行为,知乎专栏首发。允许转载,请全文保留并注明出处。 188 | 189 | 「真诚赞赏,手留余香」 190 | 191 | 赞赏 192 | 193 | **8** 人赞赏 194 | 195 | ![废土邮差][27] 196 | 197 | ![无谓][27] 198 | 199 | ![李亚东][28] 200 | 201 | ![李昊][29] 202 | 203 | ![彤墨][30] 204 | 205 | ![蓝色北极星][27] 206 | 207 | ![萌康][31] 208 | 209 | ![Ryan.C][32] 210 | 211 | 机器学习计算机视觉斯坦福大学 (Stanford University) 212 | 213 | [ShiqingFan][9][猴子][33]亦有帮助 214 | 215 | __167 216 | 217 | ![cs kite][27] 218 | 219 | ![5plus21][34] 220 | 221 | ![史书欢][27] 222 | 223 | ![eric][35] 224 | 225 | ![袁野][36] 226 | 227 | __ 228 | 229 | __收藏 230 | 231 | __分享 232 | 233 | __举报 234 | 235 | 51 条评论 236 | 237 | 取消评论 238 | 239 | 1234...6下一页 240 | 241 | {"debug":false,"apiRoot":"","paySDK":"https://pay.zhihu.com/api/js","name":"production","instance":"column","tokens":{"X-XSRF-TOKEN":null,"X-UDID":null,"Authorization":"oauth c3cef7c66a1843f8b3a9e6a1e3160e20"}} {"database":{"Post":{"20894041":{"title":"CS231n课程笔记翻译:图像分类笔记(上)","author":"du-ke","content":"**译者注**:本文[智能单元][2]首发,译自斯坦福CS231n课程笔记[image classification notes__][7],由课程教师[Andrej Karpathy__][8]授权进行翻译。本篇教程由[杜客][6]翻译完成。[ShiqingFan][9]对译文进行了仔细校对,提出了大量修改建议,态度严谨,帮助甚多。[巩子嘉][10]对几处术语使用和翻译优化也提出了很好的建议。[张欣][11]等亦有帮助。 242 | 243 | ## 原文如下 244 | 245 | 这是一篇介绍性教程,面向非计算机视觉领域的同学。教程将向同学们介绍图像分类问题和数据驱动方法。下面是**内容列表**: 246 | 247 | 248 | 249 | * 图像分类、数据驱动方法和流程 250 | * Nearest Neighbor分类器 251 | * k-Nearest Neighbor _**译者注:上篇翻译截止处**_ 252 | * 验证集、交叉验证集和超参数调参 253 | * Nearest Neighbor的优劣 254 | * 小结 255 | * 小结:应用kNN实践 256 | * 拓展阅读 257 | 258 | ## 图像分类 259 | 260 | **目标**:这一节我们将介绍图像分类问题。所谓图像分类问题,就是已有固定的分类标签集合,然后对于输入的图像,从分类标签集合中找出一个分类标签,最后把分类标签分配给该输入图像。虽然看起来挺简单的,但这可是计算机视觉领域的核心问题之一,并且有着各种各样的实际应用。在后面的课程中,我们可以看到计算机视觉领域中很多看似不同的问题(比如物体检测和分割),都可以被归结为图像分类问题。 261 | 262 | **例子**:以下图为例,图像分类模型读取该图片,并生成该图片属于集合 {cat, dog, hat, mug}中各个标签的概率。需要注意的是,对于计算机来说,图像是一个由数字组成的巨大的3维数组。在这个例子中,猫的图像大小是宽248像素,高400像素,有3个颜色通道,分别是红、绿和蓝(简称RGB)。如此,该图像就包含了248X400X3=297600个数字,每个数字都是在范围0-255之间的整型,其中0表示全黑,255表示全白。我们的任务就是把这些上百万的数字变成一个简单的标签,比如"猫"。 263 | 264 | ————————————————————————————————————————— 265 | 266 | ![][12]图像分类的任务,就是对于一个给定的图像,预测它属于的那个分类标签(或者给出属于一系列不同标签的可能性)。图像是3维数组,数组元素是取值范围从0到255的整数。数组的尺寸是宽度x高度x3,其中这个3代表的是红、绿和蓝3个颜色通道。 267 | 268 | ————————————————————————————————————————— 269 | 270 | **困难和挑战**:对于人来说,识别出一个像"猫"一样视觉概念是简单至极的,然而从计算机视觉算法的角度来看就值得深思了。我们在下面列举了计算机视觉算法在图像识别方面遇到的一些困难,要记住图像是以3维数组来表示的,数组中的元素是亮度值。 271 | 272 | * **视角变化(**Viewpoint variation**)**:同一个物体,摄像机可以从多个角度来展现。 273 | * **大小变化(**Scale variation**)**:物体可视的大小通常是会变化的(不仅是在图片中,在真实世界中大小也是变化的)。 274 | * **形变(**Deformation**)**:很多东西的形状并非一成不变,会有很大变化。 275 | * **遮挡(**Occlusion**)**:目标物体可能被挡住。有时候只有物体的一小部分(可以小到几个像素)是可见的。 276 | * **光照条件(**Illumination conditions**)**:在像素层面上,光照的影响非常大。 277 | * **背景干扰(**Background clutter**)**:物体可能混入背景之中,使之难以被辨认。 278 | * **类内差异(**Intra-class variation**)**:一类物体的个体之间的外形差异很大,比如椅子。这一类物体有许多不同的对象,每个都有自己的外形。 279 | 280 | 面对以上所有变化及其组合,好的图像分类模型能够在维持分类结论稳定的同时,保持对类间差异足够敏感。 281 | 282 | ————————————————————————————————————————— 283 | 284 | ![][13]————————————————————————————————————————— 285 | 286 | **数据驱动方法**:如何写一个图像分类的算法呢?这和写个排序算法可是大不一样。怎么写一个从图像中认出猫的算法?搞不清楚。因此,与其在代码中直接写明各类物体到底看起来是什么样的,倒不如说我们采取的方法和教小孩儿看图识物类似:给计算机很多数据,然后实现学习算法,让计算机学习到每个类的外形。这种方法,就是_数据驱动方法_。既然该方法的第一步就是收集已经做好分类标注的图片来作为训练集,那么下面就看看数据库到底长什么样: 287 | 288 | ————————————————————————————————————————— 289 | 290 | ![][14]一个有4个视觉分类的训练集。在实际中,我们可能有上千的分类,每个分类都有成千上万的图像。 291 | 292 | ————————————————————————————————————————— 293 | 294 | **图像分类流程**。在课程视频中已经学习过,**图像分类**就是输入一个元素为像素值的数组,然后给它分配一个分类标签。完整流程如下: 295 | 296 | * **输入**:输入是包含N个图像的集合,每个图像的标签是K种分类标签中的一种。这个集合称为_训练集。_ 297 | * **学习**:这一步的任务是使用训练集来学习每个类到底长什么样。一般该步骤叫做_训练分类器_或者_学习一个模型_。 298 | * **评价**:让分类器来预测它未曾见过的图像的分类标签,并以此来评价分类器的质量。我们会把分类器预测的标签和图像真正的分类标签对比。毫无疑问,分类器预测的分类标签和图像真正的分类标签如果一致,那就是好事,这样的情况越多越好。 299 | 300 | ## Nearest Neighbor分类器 301 | 302 | 作为课程介绍的第一个方法,我们来实现一个**Nearest Neighbor分类器**。虽然这个分类器和卷积神经网络没有任何关系,实际中也极少使用,但通过实现它,可以让读者对于解决图像分类问题的方法有个基本的认识。 303 | 304 | **图像分类数据集:CIFAR-10。**一个非常流行的图像分类数据集是[CIFAR-10__][15]。这个数据集包含了60000张32X32的小图像。每张图像都有10种分类标签中的一种。这60000张图像被分为包含50000张图像的训练集和包含10000张图像的测试集。在下图中你可以看见10个类的10张随机图片。 305 | 306 | ————————————————————————————————————————— 307 | 308 | ![][16]**左边**:从[CIFAR-10__][15]数据库来的样本图像。**右边**:第一列是测试图像,然后第一列的每个测试图像右边是使用Nearest Neighbor算法,根据像素差异,从训练集中选出的10张最类似的图片。 309 | 310 | ————————————————————————————————————————— 311 | 312 | 假设现在我们有CIFAR-10的50000张图片(每种分类5000张)作为训练集,我们希望将余下的10000作为测试集并给他们打上标签。Nearest Neighbor算法将会拿着测试图片和训练集中每一张图片去比较,然后将它认为最相似的那个训练集图片的标签赋给这张测试图片。上面右边的图片就展示了这样的结果。请注意上面10个分类中,只有3个是准确的。比如第8行中,马头被分类为一个红色的跑车,原因在于红色跑车的黑色背景非常强烈,所以这匹马就被错误分类为跑车了。 313 | 314 | 那么具体如何比较两张图片呢?在本例中,就是比较32x32x3的像素块。最简单的方法就是逐个像素比较,最后将差异值全部加起来。换句话说,就是将两张图片先转化为两个向量![I_1][17]和![I_2][18],然后计算他们的**L1距离:** 315 | 316 | ![\displaystyle d_1\(I_1,I_2\)=\sum_p|I^p_1-I^p_2|][19] 317 | 318 | 这里的求和是针对所有的像素。下面是整个比较流程的图例: 319 | 320 | ————————————————————————————————————————— 321 | 322 | ![][20]以图片中的一个颜色通道为例来进行说明。两张图片使用L1距离来进行比较。逐个像素求差值,然后将所有差值加起来得到一个数值。如果两张图片一模一样,那么L1距离为0,但是如果两张图片很是不同,那L1值将会非常大。 323 | 324 | ————————————————————————————————————————— 325 | 326 | 下面,让我们看看如何用代码来实现这个分类器。首先,我们将CIFAR-10的数据加载到内存中,并分成4个数组:训练数据和标签,测试数据和标签。在下面的代码中,**Xtr**(大小是50000x32x32x3)存有训练集中所有的图像,**Ytr**是对应的长度为50000的1维数组,存有图像对应的分类标签(从0到9): 327 | 328 | 329 | Xtr, Ytr, Xte, Yte = load_CIFAR10('data/cifar10/') # a magic function we providen# flatten out all images to be one-dimensionalnXtr_rows = Xtr.reshape(Xtr.shape[0], 32 * 32 * 3) # Xtr_rows becomes 50000 x 3072nXte_rows = Xte.reshape(Xte.shape[0], 32 * 32 * 3) # Xte_rows becomes 10000 x 3072n 330 | 331 | 现在我们得到所有的图像数据,并且把他们拉长成为行向量了。接下来展示如何训练并评价一个分类器: 332 | 333 | 334 | 335 | nn = NearestNeighbor() # create a Nearest Neighbor classifier classnnn.train(Xtr_rows, Ytr) # train the classifier on the training images and labelsnYte_predict = nn.predict(Xte_rows) # predict labels on the test imagesn# and now print the classification accuracy, which is the average numbern# of examples that are correctly predicted (i.e. label matches)nprint 'accuracy: %f' % ( np.mean(Yte_predict == Yte) )n 336 | 337 | 作为评价标准,我们常常使用**准确率**,它描述了我们预测正确的得分。请注意以后我们实现的所有分类器都需要有这个API:**train(X, y)**函数。该函数使用训练集的数据和标签来进行训练。从其内部来看,类应该实现一些关于标签和标签如何被预测的模型。这里还有个**predict(X)**函数,它的作用是预测输入的新数据的分类标签。现在还没介绍分类器的实现,下面就是使用L1距离的Nearest Neighbor分类器的实现套路: 338 | 339 | 340 | 341 | import numpy as npnnclass NearestNeighbor(object):n def __init__(self):n passnn def train(self, X, y):n """ X is N x D where each row is an example. Y is 1-dimension of size N """n # the nearest neighbor classifier simply remembers all the training datan self.Xtr = Xn self.ytr = ynn def predict(self, X):n """ X is N x D where each row is an example we wish to predict label for """n num_test = X.shape[0]n # lets make sure that the output type matches the input typen Ypred = np.zeros(num_test, dtype = self.ytr.dtype)nn # loop over all test rowsn for i in xrange(num_test):n # find the nearest training image to the i'th test imagen # using the L1 distance (sum of absolute value differences)n distances = np.sum(np.abs(self.Xtr - X[i,:]), axis = 1)n min_index = np.argmin(distances) # get the index with smallest distancen Ypred[i] = self.ytr[min_index] # predict the label of the nearest examplenn return Ypredn 342 | 343 | 如果你用这段代码跑CIFAR-10,你会发现准确率能达到**38.6%**。这比随机猜测的10%要好,但是比人类识别的水平([据研究推测是94%__][21])和卷积神经网络能达到的95%还是差多了。点击查看基于CIFAR-10数据的[Kaggle算法竞赛排行榜__][22]。 344 | 345 | **距离选择**:计算向量间的距离有很多种方法,另一个常用的方法是**L2距离**,从几何学的角度,可以理解为它在计算两个向量间的欧式距离。L2距离的公式如下: 346 | 347 | ![\displaystyle d_2\(I_1,I_2\)=\sqrt{ \sum_p\(I^p_1-I^p_2\)^2}][23] 348 | 349 | 换句话说,我们依旧是在计算像素间的差值,只是先求其平方,然后把这些平方全部加起来,最后对这个和开方。在Numpy中,我们只需要替换上面代码中的1行代码就行: 350 | 351 | 352 | 353 | distances = np.sqrt(np.sum(np.square(self.Xtr - X[i,:]), axis = 1))n 354 | 355 | 注意在这里使用了**np.sqrt**,但是在实际中可能不用。因为求平方根函数是一个_单调函数_,它对不同距离的绝对值求平方根虽然改变了数值大小,但依然保持了不同距离大小的顺序。所以用不用它,都能够对像素差异的大小进行正确比较。如果你在CIFAR-10上面跑这个模型,正确率是**35.4%**,比刚才低了一点。 356 | 357 | **L1和L2比较**。比较这两个度量方式是挺有意思的。在面对两个向量之间的差异时,L2比L1更加不能容忍这些差异。也就是说,相对于1个巨大的差异,L2距离更倾向于接受多个中等程度的差异。L1和L2都是在[p-norm__][24]常用的特殊形式。 358 | 359 | ## k-Nearest Neighbor分类器 360 | 361 | 你可能注意到了,为什么只用最相似的1张图片的标签来作为测试图像的标签呢?这不是很奇怪吗!是的,使用**k-Nearest Neighbor分类器**就能做得更好。它的思想很简单:与其只找最相近的那1个图片的标签,我们找最相似的k个图片的标签,然后让他们针对测试图片进行投票,最后把票数最高的标签作为对测试图片的预测。所以当k=1的时候,k-Nearest Neighbor分类器就是Nearest Neighbor分类器。从直观感受上就可以看到,更高的k值可以让分类的效果更平滑,使得分类器对于异常值更有抵抗力。 362 | 363 | ————————————————————————————————————————— 364 | 365 | ![][25]上面示例展示了Nearest Neighbor分类器和5-Nearest Neighbor分类器的区别。例子使用了2维的点来表示,分成3类(红、蓝和绿)。不同颜色区域代表的是使用L2距离的分类器的**决策边界**。白色的区域是分类模糊的例子(即图像与两个以上的分类标签绑定)。需要注意的是,在NN分类器中,异常的数据点(比如:在蓝色区域中的绿点)制造出一个不正确预测的孤岛。5-NN分类器将这些不规则都平滑了,使得它针对测试数据的**泛化(****generalization****)**能力更好(例子中未展示)。注意,5-NN中也存在一些灰色区域,这些区域是因为近邻标签的最高票数相同导致的(比如:2个邻居是红色,2个邻居是蓝色,还有1个是绿色)。 366 | 367 | ————————————————————————————————————————— 368 | 369 | 在实际中,大多使用k-NN分类器。但是k值如何确定呢?接下来就讨论这个问题。 370 | 371 | **图像分类笔记(上)完。** 372 | 373 | 点击查看[图像分类笔记(下)][26]。 374 | 375 | ## **译者反馈**: 376 | 377 | 1. 因CS231n的单篇课程笔记长度长,完整阅读需较长时间。知友[张欣][11]等建议对其进行适当分拆。故本次翻译将[图像分类笔记__][7]拆分为上下篇,每篇阅读量控制在1万字左右,**降低阅读成本**。效果如何,请知友们点评; 378 | 2. 知乎专栏的公式编辑器可以使用LaTeX语法,赞。但**公式居中需手动空格,有无更优雅的方式**?请知友们评论指教; 379 | 3. 翻译中的任何不足之处,请知友们在评论中批评指正,我们会及时讨论并作出反馈; 380 | 4. 本翻译是无偿行为,知乎专栏首发。允许转载,请全文保留并注明出处。 381 | 382 | 383 | [1]: https://pic4.zhimg.com/4a97d93d652f45ededf2ebab9a13f22b_m.jpeg 384 | [2]: https://zhuanlan.zhihu.com/intelligentunit 385 | [3]: https://zhuanlan.zhihu.com/write 386 | [4]: https://pic3.zhimg.com/4b149e4f05ca3551cadcb07c0963cb6a_r.png 387 | [5]: https://pic2.zhimg.com/5ab5b93bd_xs.jpg 388 | [6]: https://www.zhihu.com/people/du-ke 389 | [7]: http://link.zhihu.com/?target=http%3A//cs231n.github.io/classification 390 | [8]: http://link.zhihu.com/?target=http%3A//cs.stanford.edu/people/karpathy/ 391 | [9]: https://www.zhihu.com/people/sqfan 392 | [10]: https://www.zhihu.com/people/gong-zi-jia-57 393 | [11]: https://www.zhihu.com/people/zhangxinnan 394 | [12]: https://pic2.zhimg.com/baab9e4b97aceb77ec70abeda6be022d_b.png 395 | [13]: https://pic2.zhimg.com/1ee9457872f773d671dd5b225647ef45_b.jpg 396 | [14]: https://pic1.zhimg.com/bbbfd2e6878d6f5d2a82f8239addbbc0_b.jpg 397 | [15]: http://link.zhihu.com/?target=http%3A//www.cs.toronto.edu/%7Ekriz/cifar.html 398 | [16]: https://pic1.zhimg.com/fff49fd8cec00f77f657a4c4a679b030_b.jpg 399 | [17]: http://zhihu.com/equation?tex=I_1 400 | [18]: http://zhihu.com/equation?tex=I_2 401 | [19]: http://zhihu.com/equation?tex=%5Cdisplaystyle+d_1%28I_1%2CI_2%29%3D%5Csum_p%7CI%5Ep_1-I%5Ep_2%7C 402 | [20]: https://pic2.zhimg.com/95cfe7d9efb83806299c218e0710a6c5_b.jpg 403 | [21]: http://link.zhihu.com/?target=http%3A//karpathy.github.io/2011/04/27/manually-classifying-cifar10/ 404 | [22]: http://link.zhihu.com/?target=http%3A//www.kaggle.com/c/cifar-10/leaderboard 405 | [23]: http://zhihu.com/equation?tex=%5Cdisplaystyle+d_2%28I_1%2CI_2%29%3D%5Csqrt%7B+%5Csum_p%28I%5Ep_1-I%5Ep_2%29%5E2%7D 406 | [24]: http://link.zhihu.com/?target=http%3A//planetmath.org/vectorpnorm 407 | [25]: https://pic3.zhimg.com/51aef845faa10195e33bdd4657592f86_b.jpg 408 | [26]: https://zhuanlan.zhihu.com/p/20900216 409 | 410 | -------------------------------------------------------------------------------- /CS231n 6.2:神经网络笔记 2.md: -------------------------------------------------------------------------------- 1 | 2 | [Source](https://zhuanlan.zhihu.com/p/21560667?refer=intelligentunit "Permalink to CS231n课程笔记翻译:神经网络笔记 2 - 知乎专栏") 3 | 注:这篇格式可能有较大问题 4 | 5 | # CS231n课程笔记翻译:神经网络笔记 2 - 知乎专栏 6 | 7 | ![CS231n课程笔记翻译:神经网络笔记 2][4] 8 | 9 | # CS231n课程笔记翻译:神经网络笔记 2 10 | 11 | ![杜客][5][杜客][6] 12 | 13 | 8 months ago 14 | 15 | 译者注:本文[智能单元][2]首发,译自斯坦福CS231n课程笔记[Neural Nets notes 2__][7],课程教师[Andrej Karpathy__][8]授权翻译。本篇教程由[杜客][6]翻译完成,[堃堃][9]进行校对修改。译文含公式和代码,建议PC端阅读。 16 | 17 | ## 原文如下 18 | 19 | 内容列表: 20 | 21 | * 设置数据和模型 22 | * 数据预处理 23 | * 权重初始化 24 | * 批量归一化(Batch Normalization) 25 | * 正则化(L2/L1/Maxnorm/Dropout) 26 | * 损失函数 27 | * 小结 28 | 29 | # 设置数据和模型 30 | 31 | 在上一节中介绍了神经元的模型,它在计算内积后进行非线性激活函数计算,神经网络将这些神经元组织成各个层。这些做法共同定义了 **评分函数(score function)** 的新形式,该形式是从前面线性分类章节中的简单线性映射发展而来的。具体来说,神经网络就是进行了一系列的线性映射与非线性激活函数交织的运算。本节将讨论更多的算法设计选项,比如数据预处理,权重初始化和损失函数。 32 | 33 | 34 | 35 | ## 数据预处理 36 | 37 | 关于数据预处理我们有3个常用的符号,数据矩阵 **X**,假设其尺寸是[**N x D]**(**N**是数据样本的数量,**D**是数据的维度)。 38 | 39 | **均值减法(****Mean subtraction****)** 是预处理最常用的形式。它对数据中每个独立_特征_减去平均值,从几何上可以理解为在每个维度上都将数据云的中心都迁移到原点。在numpy中,该操作可以通过代码 **X -= np.mean(X, axis=0)** 实现。而对于图像,更常用的是对所有像素都减去一个值,可以用 **X -= np.mean(X)** 实现,也可以在3个颜色通道上分别操作。 40 | 41 | 42 | 43 | **归一化(****Normalization****)** 是指将数据的所有维度都归一化,使其数值范围都近似相等。有两种常用方法可以实现归一化。第一种是先对数据做零中心化(zero-centered)处理,然后每个维度都除以其标准差,实现代码为 **X /= np.std(X, axis=0)** 。第二种方法是对每个维度都做归一化,使得每个维度的最大和最小值是1和-1。这个预处理操作只有在确信不同的输入特征有不同的数值范围(或计量单位)时才有意义,但要注意预处理操作的重要性几乎等同于学习算法本身。在图像处理中,由于像素的数值范围几乎是一致的(都在0-255之间),所以进行这个额外的预处理步骤并不是很必要。 44 | 45 | 46 | 47 | —————————————————————————————————————————— 48 | 49 | ![][10]一般数据预处理流程:**左边:** 原始的2维输入数据。**中间:** 在每个维度上都减去平均值后得到零中心化数据,现在数据云是以原点为中心的。**右边:** 每个维度都除以其标准差来调整其数值范围。红色的线指出了数据各维度的数值范围,在中间的零中心化数据的数值范围不同,但在右边归一化数据中数值范围相同。 50 | 51 | —————————————————————————————————————————— 52 | 53 | **PCA和白化(****Whitening****)** 是另一种预处理形式。在这种处理中,先对数据进行零中心化处理,然后计算协方差矩阵,它展示了数据中的相关性结构。 54 | 55 | 56 | ```py 57 | # 假设输入数据矩阵X的尺寸为[N x D] 58 | X -= np.mean(X, axis = 0) # 对数据进行零中心化(重要) 59 | cov = np.dot(X.T, X) / X.shape[0] # 得到数据的协方差矩阵 60 | 61 | ``` 62 | 63 | 数据协方差矩阵的第(i, j)个元素是数据第i个和第j个维度的_协方差_。具体来说,该矩阵的对角线上的元素是方差。还有,协方差矩阵是对称和[半正定__][11]的。我们可以对数据协方差矩阵进行SVD(奇异值分解)运算。 64 | 65 | 66 | 67 | ```py 68 | U,S,V = np.linalg.svd(cov) 69 | 70 | ``` 71 | 72 | U的列是特征向量,S是装有奇异值的1维数组(因为cov是对称且半正定的,所以S中元素是特征值的平方)。为了去除数据相关性,将已经零中心化处理过的原始数据投影到特征基准上: 73 | 74 | 75 | 76 | 77 | 78 | ```py 79 | Xrot = np.dot(X,U) # 对数据去相关性 80 | 81 | ``` 82 | 83 | 注意U的列是标准正交向量的集合(范式为1,列之间标准正交),所以可以把它们看做标准正交基向量。因此,投影对应x中的数据的一个旋转,旋转产生的结果就是新的特征向量。如果计算**Xrot**的协方差矩阵,将会看到它是对角对称的。**np.linalg.svd** 的一个良好性质是在它的返回值 **U** 中,特征向量是按照特征值的大小排列的。我们可以利用这个性质来对数据降维,只要使用前面的小部分特征向量,丢弃掉那些包含的数据没有_**方差**_的维度。 这个操作也被称为主成分分析( [Principal Component Analysis__][12] 简称PCA)降维: 84 | 85 | 86 | ```py 87 | Xrot_reduced = np.dot(X, U[:,:100]) # Xrot_reduced 变成 [N x 100] 88 | 89 | ``` 90 | 91 | 经过上面的操作,将原始的数据集的大小由[N x D]降到了[N x 100],留下了数据中包含最大_**方差**_的100个维度。通常使用PCA降维过的数据训练线性分类器和神经网络会达到非常好的性能效果,同时还能节省时间和存储器空间。 92 | 93 | 94 | 95 | 最后一个在实践中会看见的变换是**白化(****whitening****)**。白化操作的输入是特征基准上的数据,然后对每个维度除以其特征值来对数值范围进行归一化。该变换的几何解释是:如果数据服从多变量的高斯分布,那么经过白化后,数据的分布将会是一个均值为零,且协方差相等的矩阵。该操作的代码如下: 96 | 97 | 98 | 99 | 100 | 101 | ```py 102 | # 对数据进行白化操作: 103 | # 除以特征值 104 | Xwhite = Xrot / np.sqrt(S + 1e-5) 105 | 106 | ``` 107 | 108 | _警告:夸大的噪声_。注意分母中添加了1e-5(或一个更小的常量)来防止分母为0。该变换的一个缺陷是在变换的过程中可能会夸大数据中的噪声,这是因为它将所有维度都拉伸到相同的数值范围,这些维度中也包含了那些只有极少差异性(方差小)而大多是噪声的维度。在实际操作中,这个问题可以用更强的平滑来解决(例如:采用比1e-5更大的值)。 109 | 110 | —————————————————————————————————————————— 111 | 112 | ![][13] 113 | 114 | PCA/白化。**左边**是二维的原始数据。**中间**:经过PCA操作的数据。可以看出数据首先是零中心的,然后变换到了数据协方差矩阵的基准轴上。这样就对数据进行了解相关(协方差矩阵变成对角阵)。**右边**:每个维度都被特征值调整数值范围,将数据协方差矩阵变为单位矩阵。从几何上看,就是对数据在各个方向上拉伸压缩,使之变成服从高斯分布的一个数据点分布。 115 | 116 | —————————————————————————————————————————— 117 | 118 | 我们可以使用CIFAR-10数据将这些变化可视化出来。CIFAR-10训练集的大小是50000x3072,其中每张图片都可以拉伸为3072维的行向量。我们可以计算[3072 x 3072]的协方差矩阵然后进行奇异值分解(比较耗费计算性能),那么经过计算的特征向量看起来是什么样子呢? 119 | 120 | ————————————————————————————————————————— 121 | 122 | ![][14] 123 | 124 | **最左**:一个用于演示的集合,含49张图片。**左二**:3072个特征值向量中的前144个。靠前面的特征向量解释了数据中大部分的方差,可以看见它们与图像中较低的频率相关。**第三张**是49张经过了PCA降维处理的图片,展示了144个特征向量。这就是说,展示原始图像是每个图像用3072维的向量,向量中的元素是图片上某个位置的像素在某个颜色通道中的亮度值。而现在每张图片只使用了一个144维的向量,其中每个元素表示了特征向量对于组成这张图片的贡献度。为了让图片能够正常显示,需要将144维度重新变成基于像素基准的3072个数值。因为U是一个旋转,可以通过乘以U.transpose()[:144,:]来实现,然后将得到的3072个数值可视化。可以看见图像变得有点模糊了,这正好说明前面的特征向量获取了较低的频率。然而,大多数信息还是保留了下来。**最右**:将"白化"后的数据进行显示。其中144个维度中的方差都被压缩到了相同的数值范围。然后144个白化后的数值通过乘以U.transpose()[:144,:]转换到图像像素基准上。现在较低的频率(代表了大多数方差)可以忽略不计了,较高的频率(代表相对少的方差)就被夸大了。 125 | 126 | 127 | 128 | —————————————————————————————————————————— 129 | 130 | **实践操作。** 在这个笔记中提到PCA和白化主要是为了介绍的完整性,实际上在卷积神经网络中并不会采用这些变换。然而对数据进行零中心化操作还是非常重要的,对每个像素进行归一化也很常见。 131 | 132 | 133 | 134 | **常见错误。** 进行预处理很重要的一点是:任何预处理策略(比如数据均值)都只能在训练集数据上进行计算,算法训练完毕后再应用到验证集或者测试集上。例如,如果先计算整个数据集图像的平均值然后每张图片都减去平均值,最后将整个数据集分成训练/验证/测试集,那么这个做法是错误的。**应该怎么做呢?应该先分成训练/验证/测试集,只是从训练集中求图片平均值,然后各个集(训练/验证/测试集)中的图像再减去这个平均值。** 135 | 136 | **_译者注:此处确为初学者常见错误,请务必注意!_** 137 | 138 | ## 权重初始化 139 | 140 | 我们已经看到如何构建一个神经网络的结构并对数据进行预处理,但是在开始训练网络之前,还需要初始化网络的参数。 141 | 142 | **错误:全零初始化。** 让我们从应该避免的错误开始。在训练完毕后,虽然不知道网络中每个权重的最终值应该是多少,但如果数据经过了恰当的归一化的话,就可以假设所有权重数值中大约一半为正数,一半为负数。这样,一个听起来蛮合理的想法就是把这些权重的初始值都设为0吧,因为在期望上来说0是最合理的猜测。这个做法错误的!因为如果网络中的每个神经元都计算出同样的输出,然后它们就会在反向传播中计算出同样的梯度,从而进行同样的参数更新。换句话说,如果权重被初始化为同样的值,神经元之间就失去了不对称性的源头。 143 | 144 | **小随机数初始化。** 因此,权重初始值要非常接近0又不能等于0。解决方法就是将权重初始化为很小的数值,以此来_打破对称性_。其思路是:如果神经元刚开始的时候是随机且不相等的,那么它们将计算出不同的更新,并将自身变成整个网络的不同部分。小随机数权重初始化的实现方法是:**W = 0.01 * np.random.randn(D,H)。**其中**randn**函数是基于零均值和标准差的一个高斯分布(**_译者注:国内教程一般习惯称均值参数为期望![mu][15]_**)来生成随机数的。根据这个式子,每个神经元的权重向量都被初始化为一个随机向量,而这些随机向量又服从一个多变量高斯分布,这样在输入空间中,所有的神经元的指向是随机的。也可以使用均匀分布生成的随机数,但是从实践结果来看,对于算法的结果影响极小。 145 | 146 | 147 | 148 | _**警告**。_并不是小数值一定会得到好的结果。例如,一个神经网络的层中的权重值很小,那么在反向传播的时候就会计算出非常小的梯度(因为梯度与权重值是成比例的)。这就会很大程度上减小反向传播中的"梯度信号",在深度网络中,就会出现问题。 149 | 150 | **使用1/sqrt(n)校准方差** 上面做法存在一个问题,随着输入数据量的增长,随机初始化的神经元的输出数据的分布中的方差也在增大。我们可以除以输入数据量的平方根来调整其数值范围,这样神经元输出的方差就归一化到1了。也就是说,建议将神经元的权重向量初始化为:**w = np.random.randn(n) / sqrt(n)。**其中**n**是输入数据的数量。这样就保证了网络中所有神经元起始时有近似同样的输出分布。实践经验证明,这样做可以提高收敛的速度。 151 | 152 | 上述结论的推导过程如下:假设权重![w][16]和输入![x][17]之间的内积为![s=sum^n_iw_ix_i][18],这是还没有进行非线性激活函数运算之前的原始数值。我们可以检查![s][19]的方差: 153 | 154 | ![displaystyle Var\(s\)=Var\(sum^n_iw_ix_i\)][20] 155 | ![displaystyle =sum^n_iVar\(w_ix_i\)][21] 156 | ![displaystyle =sum^n_i\[E\(w_i\)\]^2Var\(x_i\)+E\[\(x_i\)\]^2Var\(w_i\)+Var\(xIi\)Var\(w_i\)][22] 157 | ![displaystyle =sum^n_iVar\(x_i\)Var\(w_i\)][23] 158 | ![displaystyle =\(nVar\(w\)\)Var\(x\)][24] 159 | 160 | 在前两步,使用了[方差的性质__][25]。在第三步,因为假设输入和权重的平均值都是0,所以![E\[x_i\]=E\[w_i\]=0][26]。注意这并不是一般化情况,比如在ReLU单元中均值就为正。在最后一步,我们假设所有的![w_i,x_i][27]都服从同样的分布。从这个推导过程我们可以看见,如果想要![s][19]有和输入![x][17]一样的方差,那么在初始化的时候必须保证每个权重![w][16]的方差是![1/n][28]。又因为对于一个随机变量![X][29]和标量![a][30],有![Var\(aX\)=a^2Var\(X\)][31],这就说明可以基于一个标准高斯分布,然后乘以![a=sqrt{1/n}][32],使其方差为![1/n][28],于是得出:**w = np.random.randn(n) / sqrt(n)**。 161 | 162 | 163 | 164 | Glorot等在论文[Understanding the difficulty of training deep feedforward neural networks__][33]中作出了类似的分析。在论文中,作者推荐初始化公式为![ \( text{Var}\(w\) = 2/\(n_{in} + n_{out}\) \) ][34],其中![\(n_{in}, n_{out}\)][35]是在前一层和后一层中单元的个数。这是基于妥协和对反向传播中梯度的分析得出的结论。该主题下最新的一篇论文是:[Delving Deep into Rectifiers: Surpassing Human-Level Performance on ImageNet Classification__][36],作者是He等人。文中给出了一种针对ReLU神经元的特殊初始化,并给出结论:网络中神经元的方差应该是![2.0/n][37]。代码为**w = np.random.randn(n) * sqrt(2.0/n)**。这个形式是神经网络算法使用ReLU神经元时的当前最佳推荐。 165 | 166 | **稀疏初始化(Sparse initialization)。** 另一个处理非标定方差的方法是将所有权重矩阵设为0,但是为了打破对称性,每个神经元都同下一层固定数目的神经元随机连接(其权重数值由一个小的高斯分布生成)。一个比较典型的连接数目是10个。 167 | 168 | **偏置(biases)的初始化。** 通常将偏置初始化为0,这是因为随机小数值权重矩阵已经打破了对称性。对于ReLU非线性激活函数,有研究人员喜欢使用如0.01这样的小数值常量作为所有偏置的初始值,这是因为他们认为这样做能让所有的ReLU单元一开始就激活,这样就能保存并传播一些梯度。然而,这样做是不是总是能提高算法性能并不清楚(有时候实验结果反而显示性能更差),所以通常还是使用0来初始化偏置参数。 169 | 170 | **实践。** 当前的推荐是使用ReLU激活函数,并且使用**w = np.random.randn(n) * sqrt(2.0/n)** 来进行权重初始化,关于这一点,[这篇文章__][36]有讨论。 171 | 172 | **批量归一化(Batch Normalization)。** [批量归一化][38]是loffe和Szegedy最近才提出的方法,该方法减轻了如何合理初始化神经网络这个棘手问题带来的头痛:),其做法是让激活数据在训练开始前通过一个网络,网络处理数据使其服从标准高斯分布。因为归一化是一个简单可求导的操作,所以上述思路是可行的。在实现层面,应用这个技巧通常意味着全连接层(或者是卷积层,后续会讲)与激活函数之间添加一个BatchNorm层。对于这个技巧本节不会展开讲,因为上面的参考文献中已经讲得很清楚了,需要知道的是在神经网络中使用批量归一化已经变得非常常见。在实践中,使用了批量归一化的网络对于不好的初始值有更强的鲁棒性。最后一句话总结:批量归一化可以理解为在网络的每一层之前都做预处理,只是这种操作以另一种方式与网络集成在了一起。搞定! 173 | 174 | ## 正则化 Regularization 175 | 176 | 有不少方法是通过控制神经网络的容量来防止其过拟合的: 177 | 178 | **L2正则化**可能是最常用的正则化方法了。可以通过惩罚目标函数中所有参数的平方将其实现。即对于网络中的每个权重![w][16],向目标函数中增加一个![frac{1}{2}lambda w^2][39],其中![lambda][40]是正则化强度。前面这个![frac{1}{2}][41]很常见,是因为加上![frac{1}{2}][41]后,该式子关于![w][16]梯度就是![lambda w][42]而不是![2lambda w][43]了。L2正则化可以直观理解为它对于大数值的权重向量进行严厉惩罚,倾向于更加分散的权重向量。在线性分类章节中讨论过,由于输入和权重之间的乘法操作,这样就有了一个优良的特性:使网络更倾向于使用所有输入特征,而不是严重依赖输入特征中某些小部分特征。最后需要注意在梯度下降和参数更新的时候,使用L2正则化意味着所有的权重都以**w += -lambda * W**向着0线性下降。 179 | 180 | **L1正则化**是另一个相对常用的正则化方法。对于每个![w][16]我们都向目标函数增加一个![lambda|w|][44]。L1和L2正则化也可以进行组合:![lambda_1|w|+lambda_2w^2][45],这也被称作[Elastic net regularizaton__][46]。L1正则化有一个有趣的性质,它会让权重向量在最优化的过程中变得稀疏(即非常接近0)。也就是说,使用L1正则化的神经元最后使用的是它们最重要的输入数据的稀疏子集,同时对于噪音输入则几乎是不变的了。相较L1正则化,L2正则化中的权重向量大多是分散的小数字。在实践中,如果不是特别关注某些明确的特征选择,一般说来L2正则化都会比L1正则化效果好。 181 | 182 | **最大范式约束(Max norm constraints)。** 另一种形式的正则化是给每个神经元中权重向量的量级设定上限,并使用投影梯度下降来确保这一约束。在实践中,与之对应的是参数更新方式不变,然后要求神经元中的权重向量![overrightarrow{w}][47]必须满足![||overrightarrow{w}||_20.5][75]或者![w^Tx+b>0][76],那么样本就要被分类成为正样本(y=1)。然后损失函数最大化这个对数似然函数,问题可以简化为: 279 | 280 | ![displaystyle L_i=sum_jy_{ij}log\(sigma\(f_j\)\)+\(1-y_{ij}\)log\(1-sigma\(f_j\)\)][77] 281 | 282 | 上式中,假设标签![y_{ij}][71]非0即1,![sigma\(.\)][78]就是sigmoid函数。上面的公式看起来吓人,但是![f][79]的梯度实际上非常简单:![displaystyle frac{partial L_i}{partial f_j}=y_{ij}-sigma\(f_j\)][80](你可以自己求导来验证)。 283 | 284 | **回归问题**是预测实数的值的问题,比如预测房价,预测图片中某个东西的长度等。对于这种问题,通常是计算预测值和真实值之间的损失。然后用L2平方范式或L1范式度量差异。对于某个样本,L2范式计算如下: 285 | 286 | ![L_i=||f-y_i||^2_2][81] 287 | 288 | 之所以在目标函数中要进行平方,是因为梯度算起来更加简单。因为平方是一个单调运算,所以不用改变最优参数。L1范式则是要将每个维度上的绝对值加起来: 289 | 290 | ![L_i=||f-y_i||_1=sum_j|f_j-\(y_i\)_j|][82] 291 | 292 | 在上式中,如果有多个数量被预测了,就要对预测的所有维度的预测求和,即![sum_j][83]。观察第i个样本的第j维,用![delta_{ij}][84]表示预测值与真实值之间的差异。关于该维度的梯度(也就是![partial L_i/partial f_j][85])能够轻松地通过被求导为L2范式的![delta_{ij}][84]或![sign\(delta_{ij}\)][86]。这就是说,评分值的梯度要么与误差中的差值直接成比例,要么是固定的并从差值中继承sign。 293 | 294 | 295 | 296 | _注意_:L2损失比起较为稳定的Softmax损失来,其最优化过程要困难很多。直观而言,它需要网络具备一个特别的性质,即对于每个输入(和增量)都要输出一个确切的正确值。而在Softmax中就不是这样,每个评分的准确值并不是那么重要:只有当它们量级适当的时候,才有意义。还有,L2损失鲁棒性不好,因为异常值可以导致很大的梯度。所以在面对一个回归问题时,先考虑将输出变成二值化是否真的不够用。例如,如果对一个产品的星级进行预测,使用5个独立的分类器来对1-5星进行打分的效果一般比使用一个回归损失要好很多。分类还有一个额外优点,就是能给出关于回归的输出的分布,而不是一个简单的毫无把握的输出值。如果确信分类不适用,那么使用L2损失吧,但是一定要谨慎:L2非常脆弱,在网络中使用随机失活(尤其是在L2损失层的上一层)不是好主意。 297 | 298 | 299 | 300 | > 当面对一个回归任务,首先考虑是不是必须这样。一般而言,尽量把你的输出变成二分类,然后对它们进行分类,从而变成一个分类问题。 301 | 302 | **结构化预测(s****tructured prediction****)** 结构化损失是指标签可以是任意的结构,例如图表、树或者其他复杂物体的情况。通常这种情况还会假设结构空间非常巨大,不容易进行遍历。结构化SVM背后的基本思想就是在正确的结构![y_i][68]和得分最高的非正确结构之间画出一个边界。解决这类问题,并不是像解决一个简单无限制的最优化问题那样使用梯度下降就可以了,而是需要设计一些特殊的解决方案,这样可以有效利用对于结构空间的特殊简化假设。我们简要地提一下这个问题,但是详细内容就超出本课程范围。 303 | 304 | ## 小结 305 | 306 | 小结如下: 307 | 308 | * 推荐的预处理操作是对数据的每个特征都进行零中心化,然后将其数值范围都归一化到[-1,1]范围之内。 309 | * 使用标准差为![sqrt{2/n}][87]的高斯分布来初始化权重,其中![n][88]是输入的神经元数。例如用numpy可以写作:**w = np.random.randn(n) * sqrt(2.0/n)**。 310 | * 使用L2正则化和随机失活的倒置版本。 311 | * 使用批量归一化。 312 | * 讨论了在实践中可能要面对的不同任务,以及每个任务对应的常用损失函数。 313 | 314 | 现在,我们预处理了数据,初始化了模型。在下一节中,我们将讨论算法的学习过程及其运作特性。 315 | 316 | ## 译者反馈 317 | 318 | 1. **转载须全文转载且注明原文链接**,否则保留维权权利; 319 | 2. 感谢知友@[陈狄][89]和@[韩劼群][90]的建议,本系列对于**model ensemble**将固定翻译为**模型集成**; 320 | 3. 感谢知友@[天堂之拳][91]的细致指正和讨论,本系列对于**pooling**将固定翻译为**汇合;** 321 | 4. 感谢知友@[陈狄][89]和@[韩劼群][90]的建议,本系列对于**dropout**将固定翻译为**随机失活**; 322 | 5. 针对部分知友建议保留英文不做翻译的建议,请参考下方我的回复中关于Emil Cioran名句的引用,以及我的个人态度; 323 | 6. 请知友们通过评论和私信等方式批评指正,贡献者均会补充提及。 324 | 325 | 「这次工作量大,虽然傲娇也可以鼓励下」 326 | 327 | 328 | [1]: https://pic4.zhimg.com/4a97d93d652f45ededf2ebab9a13f22b_m.jpeg 329 | [2]: https://zhuanlan.zhihu.com/intelligentunit 330 | [3]: https://zhuanlan.zhihu.com/write 331 | [4]: https://pic1.zhimg.com/9843b69865ebb95506dfe9b4df48e31c_r.jpg 332 | [5]: https://pic2.zhimg.com/5ab5b93bd_xs.jpg 333 | [6]: https://www.zhihu.com/people/du-ke 334 | [7]: http://link.zhihu.com/?target=http%3A//cs231n.github.io/neural-networks-2/ 335 | [8]: http://link.zhihu.com/?target=http%3A//cs.stanford.edu/people/karpathy/ 336 | [9]: https://www.zhihu.com/people/kun-kun-97-81 337 | [10]: https://pic1.zhimg.com/e743b6777775b1671c3b5503d7afbbc4_b.png 338 | [11]: http://link.zhihu.com/?target=https%3A//en.wikipedia.org/wiki/Positive-definite_matrix%23Negative-definite.2C_semidefinite_and_indefinite_matrices 339 | [12]: http://link.zhihu.com/?target=http%3A//en.wikipedia.org/wiki/Principal_component_analysis 340 | [13]: https://pic3.zhimg.com/aae11de6e6a29f50d46b9ea106fbb02a_b.png 341 | [14]: https://pic2.zhimg.com/8608c06086fc196228f4dda78499a2d9_b.png 342 | [15]: http://zhihu.com/equation?tex=%5Cmu 343 | [16]: http://zhihu.com/equation?tex=w 344 | [17]: http://zhihu.com/equation?tex=x 345 | [18]: http://zhihu.com/equation?tex=s%3D%5Csum%5En_iw_ix_i 346 | [19]: http://zhihu.com/equation?tex=s 347 | [20]: http://zhihu.com/equation?tex=%5Cdisplaystyle+Var%28s%29%3DVar%28%5Csum%5En_iw_ix_i%29 348 | [21]: http://zhihu.com/equation?tex=%5Cdisplaystyle+%3D%5Csum%5En_iVar%28w_ix_i%29 349 | [22]: http://zhihu.com/equation?tex=%5Cdisplaystyle+%3D%5Csum%5En_i%5BE%28w_i%29%5D%5E2Var%28x_i%29%2BE%5B%28x_i%29%5D%5E2Var%28w_i%29%2BVar%28xIi%29Var%28w_i%29 350 | [23]: http://zhihu.com/equation?tex=%5Cdisplaystyle+%3D%5Csum%5En_iVar%28x_i%29Var%28w_i%29 351 | [24]: http://zhihu.com/equation?tex=%5Cdisplaystyle+%3D%28nVar%28w%29%29Var%28x%29 352 | [25]: http://link.zhihu.com/?target=http%3A//en.wikipedia.org/wiki/Variance 353 | [26]: http://zhihu.com/equation?tex=E%5Bx_i%5D%3DE%5Bw_i%5D%3D0 354 | [27]: http://zhihu.com/equation?tex=w_i%2Cx_i 355 | [28]: http://zhihu.com/equation?tex=1%2Fn 356 | [29]: http://zhihu.com/equation?tex=X 357 | [30]: http://zhihu.com/equation?tex=a 358 | [31]: http://zhihu.com/equation?tex=Var%28aX%29%3Da%5E2Var%28X%29 359 | [32]: http://zhihu.com/equation?tex=a%3D%5Csqrt%7B1%2Fn%7D 360 | [33]: http://link.zhihu.com/?target=http%3A//jmlr.org/proceedings/papers/v9/glorot10a/glorot10a.pdf 361 | [34]: http://zhihu.com/equation?tex=+%5C%28+%5Ctext%7BVar%7D%28w%29+%3D+2%2F%28n_%7Bin%7D+%2B+n_%7Bout%7D%29+%5C%29+ 362 | [35]: http://zhihu.com/equation?tex=%5C%28n_%7Bin%7D%2C+n_%7Bout%7D%5C%29 363 | [36]: http://link.zhihu.com/?target=http%3A//arxiv-web3.library.cornell.edu/abs/1502.01852 364 | [37]: http://zhihu.com/equation?tex=2.0%2Fn 365 | [38]: http://link.zhihu.com/?target=http%3A//arxiv.org/abs/1502.03167 366 | [39]: http://zhihu.com/equation?tex=%5Cfrac%7B1%7D%7B2%7D%5Clambda+w%5E2 367 | [40]: http://zhihu.com/equation?tex=%5Clambda 368 | [41]: http://zhihu.com/equation?tex=%5Cfrac%7B1%7D%7B2%7D 369 | [42]: http://zhihu.com/equation?tex=%5Clambda+w 370 | [43]: http://zhihu.com/equation?tex=2%5Clambda+w 371 | [44]: http://zhihu.com/equation?tex=%5Clambda%7Cw%7C 372 | [45]: http://zhihu.com/equation?tex=%5Clambda_1%7Cw%7C%2B%5Clambda_2w%5E2 373 | [46]: http://link.zhihu.com/?target=http%3A//web.stanford.edu/%257Ehastie/Papers/B67.2%2520%25282005%2529%2520301-320%2520Zou%2520%26%2520Hastie.pdf 374 | [47]: http://zhihu.com/equation?tex=%5Coverrightarrow%7Bw%7D 375 | [48]: http://zhihu.com/equation?tex=%7C%7C%5Coverrightarrow%7Bw%7D%7C%7C_2%3Cc 376 | [49]: http://zhihu.com/equation?tex=c 377 | [50]: http://link.zhihu.com/?target=http%3A//www.cs.toronto.edu/%257Ersalakhu/papers/srivastava14a.pdf 378 | [51]: http://zhihu.com/equation?tex=p 379 | [52]: https://pic4.zhimg.com/63fcf4cc655cb04f21a37e86aca333cf_b.png 380 | [53]: http://link.zhihu.com/?target=http%3A//www.cs.toronto.edu/%7Ersalakhu/papers/srivastava14a.pdf 381 | [54]: http://zhihu.com/equation?tex=p%3D0.5 382 | [55]: http://zhihu.com/equation?tex=px%2B%281-p%290 383 | [56]: http://zhihu.com/equation?tex=1-p 384 | [57]: http://zhihu.com/equation?tex=x%5Cto+px 385 | [58]: http://link.zhihu.com/?target=http%3A//papers.nips.cc/paper/4882-dropout-training-as-adaptive-regularization.pdf 386 | [59]: http://link.zhihu.com/?target=https%3A//en.wikipedia.org/wiki/Fisher_information_metric 387 | [60]: http://link.zhihu.com/?target=http%3A//cs.nyu.edu/%257Ewanli/dropc/ 388 | [61]: http://zhihu.com/equation?tex=L%3D%5Cfrac%7B1%7D%7BN%7D%5Csum_iL_i 389 | [62]: http://zhihu.com/equation?tex=N 390 | [63]: http://zhihu.com/equation?tex=f%3Df%28x_i%3BW%29 391 | [64]: http://zhihu.com/equation?tex=%5Cdisplaystyle+L_i%3D%5Csum_%7Bj%5Cnot%3Dy_i%7Dmax%280%2Cf_j-f_%7By_i%7D%2B1%29 392 | [65]: http://zhihu.com/equation?tex=max%280%2Cf_j-f_%7By_i%7D%2B1%29%5E2 393 | [66]: http://zhihu.com/equation?tex=%5Cdisplaystyle+L_i%3D-log%28%5Cfrac%7Be%5E%7Bf_%7By_i%7D%7D%7D%7B%5Csum_je%5E%7Bf_j%7D%7D%29 394 | [67]: http://link.zhihu.com/?target=http%3A//arxiv.org/pdf/1310.4546.pdf 395 | [68]: http://zhihu.com/equation?tex=y_i 396 | [69]: http://zhihu.com/equation?tex=%5Cdisplaystyle+L_i%3D%5Csum_jmax%280%2C1-y_%7Bij%7Df_j%29 397 | [70]: http://zhihu.com/equation?tex=j 398 | [71]: http://zhihu.com/equation?tex=y_%7Bij%7D 399 | [72]: http://zhihu.com/equation?tex=f_j 400 | [73]: http://zhihu.com/equation?tex=%5Cdisplaystyle+P%28y%3D1%7Cx%3Bw%2Cb%29%3D%5Cfrac%7B1%7D%7B1%2Be%5E%7B-%28w%5ETx%2Bb%29%7D%7D%3D%5Csigma%28w%5ETx%2Bb%29 401 | [74]: http://zhihu.com/equation?tex=%5Cdisplaystyle+P%28y%3D0%7Cx%3Bw%2Cb%29%3D1-P%28y%3D1%7Cx%3Bw%2Cb%29 402 | [75]: http://zhihu.com/equation?tex=%5Csigma%28w%5ETx%2Bb%29%3E0.5 403 | [76]: http://zhihu.com/equation?tex=w%5ETx%2Bb%3E0 404 | [77]: http://zhihu.com/equation?tex=%5Cdisplaystyle+L_i%3D%5Csum_jy_%7Bij%7Dlog%28%5Csigma%28f_j%29%29%2B%281-y_%7Bij%7D%29log%281-%5Csigma%28f_j%29%29 405 | [78]: http://zhihu.com/equation?tex=%5Csigma%28.%29 406 | [79]: http://zhihu.com/equation?tex=f 407 | [80]: http://zhihu.com/equation?tex=%5Cdisplaystyle+%5Cfrac%7B%5Cpartial+L_i%7D%7B%5Cpartial+f_j%7D%3Dy_%7Bij%7D-%5Csigma%28f_j%29 408 | [81]: http://zhihu.com/equation?tex=L_i%3D%7C%7Cf-y_i%7C%7C%5E2_2 409 | [82]: http://zhihu.com/equation?tex=L_i%3D%7C%7Cf-y_i%7C%7C_1%3D%5Csum_j%7Cf_j-%28y_i%29_j%7C 410 | [83]: http://zhihu.com/equation?tex=%5Csum_j 411 | [84]: http://zhihu.com/equation?tex=%5Cdelta_%7Bij%7D 412 | [85]: http://zhihu.com/equation?tex=%5Cpartial+L_i%2F%5Cpartial+f_j 413 | [86]: http://zhihu.com/equation?tex=sign%28%5Cdelta_%7Bij%7D%29 414 | [87]: http://zhihu.com/equation?tex=%5Csqrt%7B2%2Fn%7D 415 | [88]: http://zhihu.com/equation?tex=n 416 | [89]: https://www.zhihu.com/people/chen-di-cd 417 | [90]: https://www.zhihu.com/people/han-jie-qun 418 | -------------------------------------------------------------------------------- /CS231n 7 卷积神经网络笔记.md: -------------------------------------------------------------------------------- 1 | 2 | [Source](https://zhuanlan.zhihu.com/p/22038289?refer=intelligentunit "Permalink to CS231n课程笔记翻译:卷积神经网络笔记 - 知乎专栏") 3 | 4 | # CS231n课程笔记翻译:卷积神经网络笔记 - 知乎专栏 5 | 6 | 7 | 8 | ![CS231n课程笔记翻译:卷积神经网络笔记][2] 9 | 10 | # CS231n课程笔记翻译:卷积神经网络笔记 11 | 12 | ![猴子][3][猴子][4] 13 | 14 | 7 months ago 15 | 16 | **译者注**:本文翻译自斯坦福CS231n课程笔记[ConvNet notes__][5],由课程教师[Andrej Karpathy__][6]授权进行翻译。本篇教程由[杜客][7]和[猴子][4]翻译完成,[堃堃][8]和[李艺颖][9]进行校对修改。 17 | 18 | 19 | 20 | 21 | ## 原文如下 22 | 23 | 内容列表: 24 | 25 | * **结构概述** 26 | * **用来构建卷积神经网络的各种层** 27 | 28 | * 卷积层 29 | * 汇聚层 30 | * 归一化层 31 | * 全连接层 32 | * 将全连接层转化成卷积层 33 | * **卷积神经网络的结构** 34 | * 层的排列规律 35 | * 层的尺寸设置规律 36 | * 案例学习(LeNet / AlexNet / ZFNet / GoogLeNet / VGGNet) 37 | * 计算上的考量 38 | * **拓展资源** 39 | 40 | 41 | 42 | ## **卷积神经网络(CNNs / ConvNets)** 43 | 44 | 卷积神经网络和上一章讲的常规神经网络非常相似:它们都是由神经元组成,神经元中有具有学习能力的权重和偏差。每个神经元都得到一些输入数据,进行内积运算后再进行激活函数运算。整个网络依旧是一个可导的评分函数:该函数的输入是原始的图像像素,输出是不同类别的评分。在最后一层(往往是全连接层),网络依旧有一个损失函数(比如SVM或Softmax),并且在神经网络中我们实现的各种技巧和要点依旧适用于卷积神经网络。 45 | 46 | 那么有哪些地方变化了呢?卷积神经网络的结构基于一个假设,即输入数据是图像,基于该假设,我们就向结构中添加了一些特有的性质。这些特有属性使得前向传播函数实现起来更高效,并且大幅度降低了网络中参数的数量。 47 | 48 | 49 | 50 | 51 | ## **结构概述** 52 | 53 | _回顾:常规神经网络_。在上一章中,神经网络的输入是一个向量,然后在一系列的_隐层_中对它做变换。每个隐层都是由若干的神经元组成,每个神经元都与前一层中的所有神经元连接。但是在一个隐层中,神经元相互独立不进行任何连接。最后的全连接层被称为"输出层",在分类问题中,它输出的值被看做是不同类别的评分值。 54 | 55 | _常规神经网络对于大尺寸图像效果不尽人意_。在CIFAR-10中,图像的尺寸是32x32x3(宽高均为32像素,3个颜色通道),因此,对应的的常规神经网络的第一个隐层中,每一个单独的全连接神经元就有32x32x3=3072个权重。这个数量看起来还可以接受,但是很显然这个全连接的结构不适用于更大尺寸的图像。举例说来,一个尺寸为200x200x3的图像,会让神经元包含200x200x3=120,000个权重值。而网络中肯定不止一个神经元,那么参数的量就会快速增加!显而易见,这种全连接方式效率低下,大量的参数也很快会导致网络过拟合。 56 | 57 | _神经元的三维排列_。卷积神经网络针对输入全部是图像的情况,将结构调整得更加合理,获得了不小的优势。与常规神经网络不同,卷积神经网络的各层中的神经元是3维排列的:**宽度**、**高度**和**深度**(这里的**深度**指的是激活数据体的第三个维度,而不是整个网络的深度,整个网络的深度指的是网络的层数)。举个例子,CIFAR-10中的图像是作为卷积神经网络的输入,该数据体的维度是32x32x3(宽度,高度和深度)。我们将看到,层中的神经元将只与前一层中的一小块区域连接,而不是采取全连接方式。对于用来分类CIFAR-10中的图像的卷积网络,其最后的输出层的维度是1x1x10,因为在卷积神经网络结构的最后部分将会把全尺寸的图像压缩为包含分类评分的一个向量,向量是在深度方向排列的。下面是例子: 58 | 59 | ![][10]![][11]左边是一个3层的神经网络。右边是一个卷积神经网络,图例中网络将它的神经元都排列成3个维度(宽、高和深度)。卷积神经网络的每一层都将3D的输入数据变化为神经元3D的激活数据并输出。在这个例子中,红色的输入层装的是图像,所以它的宽度和高度就是图像的宽度和高度,它的深度是3(代表了红、绿、蓝3种颜色通道)。![][10] 60 | 61 | > 卷积神经网络是由层组成的。每一层都有一个简单的API:用一些含或者不含参数的可导的函数,将输入的3D数据变换为3D的输出数据。 62 | 63 | 64 | 65 | ### **用来构建卷积网络的各种层** 66 | 67 | 一个简单的卷积神经网络是由各种层按照顺序排列组成,网络中的每个层使用一个可以微分的函数将激活数据从一个层传递到另一个层。卷积神经网络主要由三种类型的层构成:**卷积层**,**汇聚(Pooling)层**和**全连接层**(全连接层和常规神经网络中的一样)。通过将这些层叠加起来,就可以构建一个完整的卷积神经网络。 68 | 69 | _网络结构例子:_这仅仅是个概述,下面会更详解的介绍细节。一个用于CIFAR-10图像数据分类的卷积神经网络的结构可以是[输入层-卷积层-ReLU层-汇聚层-全连接层]。细节如下: 70 | 71 | * 输入[32x32x3]存有图像的原始像素值,本例中图像宽高均为32,有3个颜色通道。 72 | * 卷积层中,神经元与输入层中的一个局部区域相连,每个神经元都计算自己与输入层相连的小区域与自己权重的内积。卷积层会计算所有神经元的输出。如果我们使用12个滤波器(也叫作核),得到的输出数据体的维度就是[32x32x12]。 73 | * ReLU层将会逐个元素地进行激活函数操作,比如使用以0为阈值的![max\(0,x\)][12]作为激活函数。该层对数据尺寸没有改变,还是[32x32x12]。 74 | * 汇聚层在在空间维度(宽度和高度)上进行降采样(downsampling)操作,数据尺寸变为[16x16x12]。 75 | * 全连接层将会计算分类评分,数据尺寸变为[1x1x10],其中10个数字对应的就是CIFAR-10中10个类别的分类评分值。正如其名,全连接层与常规神经网络一样,其中每个神经元都与前一层中所有神经元相连接。 76 | 77 | 由此看来,卷积神经网络一层一层地将图像从原始像素值变换成最终的分类评分值。其中有的层含有参数,有的没有。具体说来,卷积层和全连接层(CONV/FC)对输入执行变换操作的时候,不仅会用到激活函数,还会用到很多参数(神经元的突触权值和偏差)。而ReLU层和汇聚层则是进行一个固定不变的函数操作。卷积层和全连接层中的参数会随着梯度下降被训练,这样卷积神经网络计算出的分类评分就能和训练集中的每个图像的标签吻合了。 78 | 79 | **小结**: 80 | 81 | * 简单案例中卷积神经网络的结构,就是一系列的层将输入数据变换为输出数据(比如分类评分)。 82 | * 卷积神经网络结构中有几种不同类型的层(目前最流行的有卷积层、全连接层、ReLU层和汇聚层)。 83 | * 每个层的输入是3D数据,然后使用一个可导的函数将其变换为3D的输出数据。 84 | * 有的层有参数,有的没有(卷积层和全连接层有,ReLU层和汇聚层没有)。 85 | * 有的层有额外的超参数,有的没有(卷积层、全连接层和汇聚层有,ReLU层没有)。 86 | ![][10]![][13]一个卷积神经网络的激活输出例子。左边的输入层存有原始图像像素,右边的输出层存有类别分类评分。在处理流程中的每个激活数据体是铺成一列来展示的。因为对3D数据作图比较困难,我们就把每个数据体切成层,然后铺成一列显示。最后一层装的是针对不同类别的分类得分,这里只显示了得分最高的5个评分值和对应的类别。完整的[网页演示__][14]在我们的课程主页。本例中的结构是一个小的VGG网络,VGG网络后面会有讨论。![][10] 87 | 88 | 现在讲解不同的层,层的超参数和连接情况的细节。 89 | 90 | 91 | 92 | #### 卷积层 93 | 94 | 卷积层是构建卷积神经网络的核心层,它产生了网络中大部分的计算量。 95 | 96 | **概述和直观介绍**:首先讨论的是,在没有大脑和生物意义上的神经元之类的比喻下,卷积层到底在计算什么。卷积层的参数是有一些可学习的滤波器集合构成的。每个滤波器在空间上(宽度和高度)都比较小,但是深度和输入数据一致。举例来说,卷积神经网络第一层的一个典型的滤波器的尺寸可以是5x5x3(宽高都是5像素,深度是3是因为图像应为颜色通道,所以有3的深度)。在前向传播的时候,让每个滤波器都在输入数据的宽度和高度上滑动(更精确地说是卷积),然后计算整个滤波器和输入数据任一处的内积。当滤波器沿着输入数据的宽度和高度滑过后,会生成一个2维的激活图(activation map),激活图给出了在每个空间位置处滤波器的反应。直观地来说,网络会让滤波器学习到当它看到某些类型的视觉特征时就激活,具体的视觉特征可能是某些方位上的边界,或者在第一层上某些颜色的斑点,甚至可以是网络更高层上的蜂巢状或者车轮状图案。 97 | 98 | 99 | 100 | 在每个卷积层上,我们会有一整个集合的滤波器(比如12个),每个都会生成一个不同的二维激活图。将这些激活映射在深度方向上层叠起来就生成了输出数据。 101 | 102 | **以大脑做比喻**:如果你喜欢用大脑和生物神经元来做比喻,那么输出的3D数据中的每个数据项可以被看做是神经元的一个输出,而该神经元只观察输入数据中的一小部分,并且和空间上左右两边的所有神经元共享参数(因为这些数字都是使用同一个滤波器得到的结果)。现在开始讨论神经元的连接,它们在空间中的排列,以及它们参数共享的模式。 103 | 104 | **局部连接**:在处理图像这样的高维度输入时,让每个神经元都与前一层中的所有神经元进行全连接是不现实的。相反,我们让每个神经元只与输入数据的一个局部区域连接。该连接的空间大小叫做神经元的**感受野(receptive field)**,它的尺寸是一个超参数(其实就是滤波器的空间尺寸)。在深度方向上,这个连接的大小总是和输入量的深度相等。需要再次强调的是,我们对待空间维度(宽和高)与深度维度是不同的:连接在空间(宽高)上是局部的,但是在深度上总是和输入数据的深度一致。 105 | 106 | _例1_:假设输入数据体尺寸为[32x32x3](比如CIFAR-10的RGB图像),如果感受野(或滤波器尺寸)是5x5,那么卷积层中的每个神经元会有输入数据体中[5x5x3]区域的权重,共5x5x3=75个权重(还要加一个偏差参数)。注意这个连接在深度维度上的大小必须为3,和输入数据体的深度一致。 107 | 108 | _例2_:假设输入数据体的尺寸是[16x16x20],感受野尺寸是3x3,那么卷积层中每个神经元和输入数据体就有3x3x20=180个连接。再次提示:在空间上连接是局部的(3x3),但是在深度上是和输入数据体一致的(20)。 109 | 110 | ![][10]![][15] 111 | 112 | **左边**:红色的是输入数据体(比如CIFAR-10中的图像),蓝色的部分是第一个卷积层中的神经元。卷积层中的每个神经元都只是与输入数据体的一个局部在空间上相连,但是与输入数据体的所有深度维度全部相连(所有颜色通道)。在深度方向上有多个神经元(本例中5个),它们都接受输入数据的同一块区域(**感受野**相同)。至于深度列的讨论在下文中有。 113 | 114 | 115 | 116 | **右边**:神经网络章节中介绍的神经元保持不变,它们还是计算权重和输入的内积,然后进行激活函数运算,只是它们的连接被限制在一个局部空间。 117 | 118 | ![][10] 119 | 120 | **空间排列**:上文讲解了卷积层中每个神经元与输入数据体之间的连接方式,但是尚未讨论输出数据体中神经元的数量,以及它们的排列方式。3个超参数控制着输出数据体的尺寸:**深度(depth),步长(stride)**和**零填充(zero-padding)**。下面是对它们的讨论: 121 | 122 | 1. 首先,输出数据体的深度是一个超参数:它和使用的滤波器的数量一致,而每个滤波器在输入数据中寻找一些不同的东西。举例来说,如果第一个卷积层的输入是原始图像,那么在深度维度上的不同神经元将可能被不同方向的边界,或者是颜色斑点激活。我们将这些沿着深度方向排列、感受野相同的神经元集合称为**深度列(depth column)**,也有人使用纤维(fibre)来称呼它们。 123 | 2. 其次,在滑动滤波器的时候,必须指定步长。当步长为1,滤波器每次移动1个像素。当步长为2(或者不常用的3,或者更多,这些在实际中很少使用),滤波器滑动时每次移动2个像素。这个操作会让输出数据体在空间上变小。 124 | 3. 在下文可以看到,有时候将输入数据体用0在边缘处进行填充是很方便的。这个**零填充(zero-padding)**的尺寸是一个超参数。零填充有一个良好性质,即可以控制输出数据体的空间尺寸(最常用的是用来保持输入数据体在空间上的尺寸,这样输入和输出的宽高都相等)。 125 | 126 | 输出数据体在空间上的尺寸可以通过输入数据体尺寸(W),卷积层中神经元的感受野尺寸(F),步长(S)和零填充的数量(P)的函数来计算。(_**译者注**:这里假设输入数组的空间形状是正方形,即高度和宽度相等_)输出数据体的空间尺寸为(W-F +2P)/S+1。比如输入是7x7,滤波器是3x3,步长为1,填充为0,那么就能得到一个5x5的输出。如果步长为2,输出就是3x3。下面是例子: 127 | 128 | ![][10]![][16] 129 | 130 | 空间排列的图示。在本例中只有一个空间维度(x轴),神经元的感受野尺寸F=3,输入尺寸W=5,零填充P=1。左边:神经元使用的步长S=1,所以输出尺寸是(5-3+2)/1+1=5。右边:神经元的步长S=2,则输出尺寸是(5-3+2)/2+1=3。注意当步长S=3时是无法使用的,因为它无法整齐地穿过数据体。从等式上来说,因为(5-3+2)=4是不能被3整除的。 131 | 132 | 本例中,神经元的权重是[1,0,-1],显示在图的右上角,偏差值为0。这些权重是被所有黄色的神经元共享的(参数共享的内容看下文相关内容)。 133 | 134 | ![][10] 135 | 136 | _使用零填充_:在上面左边例子中,注意输入维度是5,输出维度也是5。之所以如此,是因为感受野是3并且使用了1的零填充。如果不使用零填充,则输出数据体的空间维度就只有3,因为这就是滤波器整齐滑过并覆盖原始数据需要的数目。一般说来,当步长![S=1][17]时,零填充的值是![P=\(F-1\)/2][18],这样就能保证输入和输出数据体有相同的空间尺寸。这样做非常常见,在介绍卷积神经网络的结构的时候我们会详细讨论其原因。 137 | 138 | _步长的限制_:注意这些空间排列的超参数之间是相互限制的。举例说来,当输入尺寸![W=10][19],不使用零填充则![P=0][20],滤波器尺寸![F=3][21],这样步长![S=2][22]就行不通,因为![\(W-F+2P\)/S+1=\(10-3+0\)/2+1=4.5][23],结果不是整数,这就是说神经元不能整齐对称地滑过输入数据体。因此,这些超参数的设定就被认为是无效的,一个卷积神经网络库可能会报出一个错误,或者修改零填充值来让设置合理,或者修改输入数据体尺寸来让设置合理,或者其他什么措施。在后面的卷积神经网络结构小节中,读者可以看到合理地设置网络的尺寸让所有的维度都能正常工作,这件事可是相当让人头痛的。而使用零填充和遵守其他一些设计策略将会有效解决这个问题。 139 | 140 | _真实案例_:[Krizhevsky__][24]构架赢得了2012年的ImageNet挑战,其输入图像的尺寸是[227x227x3]。在第一个卷积层,神经元使用的感受野尺寸![F=11][25],步长![S=4][26],不使用零填充![P=0][20]。因为(227-11)/4+1=55,卷积层的深度![K=96][27],则卷积层的输出数据体尺寸为[55x55x96]。55x55x96个神经元中,每个都和输入数据体中一个尺寸为[11x11x3]的区域全连接。在深度列上的96个神经元都是与输入数据体中同一个[11x11x3]区域连接,但是权重不同。有一个有趣的细节,在原论文中,说的输入图像尺寸是224x224,这是肯定错误的,因为(224-11)/4+1的结果不是整数。这件事在卷积神经网络的历史上让很多人迷惑,而这个错误到底是怎么发生的没人知道。我的猜测是Alex忘记在论文中指出自己使用了尺寸为3的额外的零填充。 141 | 142 | **参数共享**:在卷积层中使用参数共享是用来控制参数的数量。就用上面的例子,在第一个卷积层就有55x55x96=290,400个神经元,每个有11x11x3=364个参数和1个偏差。将这些合起来就是290400x364=105,705,600个参数。单单第一层就有这么多参数,显然这个数目是非常大的。 143 | 144 | 作一个合理的假设:如果一个特征在计算某个空间位置(x,y)的时候有用,那么它在计算另一个不同位置(x2,y2)的时候也有用。基于这个假设,可以显著地减少参数数量。换言之,就是将深度维度上一个单独的2维切片看做**深度切片(depth slice)**,比如一个数据体尺寸为[55x55x96]的就有96个深度切片,每个尺寸为[55x55]。在每个深度切片上的神经元都使用同样的权重和偏差。在这样的参数共享下,例子中的第一个卷积层就只有96个不同的权重集了,一个权重集对应一个深度切片,共有96x11x11x3=34,848个不同的权重,或34,944个参数(+96个偏差)。在每个深度切片中的55x55个权重使用的都是同样的参数。在反向传播的时候,都要计算每个神经元对它的权重的梯度,但是需要把同一个深度切片上的所有神经元对权重的梯度累加,这样就得到了对共享权重的梯度。这样,每个切片只更新一个权重集。 145 | 146 | 注意,如果在一个深度切片中的所有权重都使用同一个权重向量,那么卷积层的前向传播在每个深度切片中可以看做是在计算神经元权重和输入数据体的**卷积**(这就是"卷积层"名字由来)。这也是为什么总是将这些权重集合称为**滤波器(filter)**(或**卷积核(kernel)**),因为它们和输入进行了卷积。 147 | 148 | ![][10]![][28]Krizhevsky等学习到的滤波器例子。这96个滤波器的尺寸都是[11x11x3],在一个深度切片中,每个滤波器都被55x55个神经元共享。注意参数共享的假设是有道理的:如果在图像某些地方探测到一个水平的边界是很重要的,那么在其他一些地方也会同样是有用的,这是因为图像结构具有平移不变性。所以在卷积层的输出数据体的55x55个不同位置中,就没有必要重新学习去探测一个水平边界了。![][10] 149 | 150 | 注意有时候参数共享假设可能没有意义,特别是当卷积神经网络的输入图像是一些明确的中心结构时候。这时候我们就应该期望在图片的不同位置学习到完全不同的特征。一个具体的例子就是输入图像是人脸,人脸一般都处于图片中心。你可能期望不同的特征,比如眼睛特征或者头发特征可能(也应该)会在图片的不同位置被学习。在这个例子中,通常就放松参数共享的限制,将层称为**局部连接层**(Locally-Connected Layer)。 151 | 152 | **Numpy例子**:为了让讨论更加的具体,我们用代码来展示上述思路。假设输入数据体是numpy数组**X**。那么: 153 | 154 | * 一个位于**(x,y)**的深度列(或纤维)将会是**X[x,y,:]**。 155 | * 在深度为**d**处的深度切片,或激活图应该是**X[:,:,d]**。 156 | 157 | _卷积层例子_:假设输入数据体**X**的尺寸**X.shape:(11,11,4)**,不使用零填充(![P=0][20]),滤波器的尺寸是![F=5][29],步长![S=2][22]。那么输出数据体的空间尺寸就是(11-5)/2+1=4,即输出数据体的宽度和高度都是4。那么在输出数据体中的激活映射(称其为**V**)看起来就是下面这样(在这个例子中,只有部分元素被计算): 158 | 159 | * **V[0,0,0] = np.sum(X[:5,:5,:] * W0) + b0 160 | ** 161 | * **V[1,0,0] = np.sum(X[2:7,:5,:] * W0) + b0 162 | ** 163 | * **V[2,0,0] = np.sum(X[4:9,:5,:] * W0) + b0 164 | ** 165 | * **V[3,0,0] = np.sum(X[6:11,:5,:] * W0) + b0** 166 | 167 | 168 | 169 | 在numpy中,*****操作是进行数组间的逐元素相乘。权重向量**W0**是该神经元的权重,**b0**是其偏差。在这里,**W0**被假设尺寸是**W0.shape: (5,5,4)**,因为滤波器的宽高是5,输入数据量的深度是4。注意在每一个点,计算点积的方式和之前的常规神经网络是一样的。同时,计算内积的时候使用的是同一个权重和偏差(因为参数共享),在宽度方向的数字每次上升2(因为步长为2)。要构建输出数据体中的第二张激活图,代码应该是: 170 | 171 | * **V[0,0,1] = np.sum(X[:5,:5,:] * W1) + b1 172 | ** 173 | * **V[1,0,1] = np.sum(X[2:7,:5,:] * W1) + b1 174 | ** 175 | * **V[2,0,1] = np.sum(X[4:9,:5,:] * W1) + b1 176 | ** 177 | * **V[3,0,1] = np.sum(X[6:11,:5,:] * W1) + b1** 178 | * **V[0,1,1] = np.sum(X[:5,2:7,:] * W1) + b1 **(在y方向上) 179 | * **V[2,3,1] = np.sum(X[4:9,6:11,:] * W1) + b1 **(或两个方向上同时) 180 | 181 | 我们访问的是**V**的深度维度上的第二层(即index1),因为是在计算第二个激活图,所以这次试用的参数集就是**W1**了。在上面的例子中,为了简洁略去了卷积层对于输出数组**V**中其他部分的操作。还有,要记得这些卷积操作通常后面接的是ReLU层,对激活图中的每个元素做激活函数运算,这里没有显示。 182 | 183 | **小结**: 我们总结一下卷积层的性质: 184 | 185 | * 输入数据体的尺寸为![W_1times H_1times D_1][30] 186 | * 4个超参数: 187 | * 滤波器的数量![K][31] 188 | * 滤波器的空间尺寸![F][32] 189 | * 步长![S][33] 190 | * 零填充数量![P][34] 191 | * 输出数据体的尺寸为![W_2times H_2times D_2][35] ,其中: 192 | ![W_2=\(W_1-F+2P\)/S+1][36] 193 | * ![H_2=\(H_1-F+2P\)/S+1][37] (宽度和高度的计算方法相同) 194 | ![D_2=K][38] 195 | * 由于参数共享,每个滤波器包含![Fcdot Fcdot D_1][39]个权重,卷积层一共有![Fcdot Fcdot D_1cdot K][40]个权重和![K][31]个偏置。 196 | * 在输出数据体中,第![d][41]个深度切片(空间尺寸是![W_2times H_2][42]),用第![d][41]个滤波器和输入数据进行有效卷积运算的结果(使用步长![S][33]),最后在加上第![d][41]个偏差。 197 | 198 | 对这些超参数,常见的设置是![F=3][21],![S=1][17],![P=1][43]。同时设置这些超参数也有一些约定俗成的惯例和经验,可以在下面的卷积神经网络结构章节中查看。 199 | 200 | 卷积层演示:下面是一个卷积层的运行演示。因为3D数据难以可视化,所以所有的数据(输入数据体是蓝色,权重数据体是红色,输出数据体是绿色)都采取将深度切片按照列的方式排列展现。输入数据体的尺寸是![W_1=5,H_1=5,D_1=3][44],卷积层参数![K=2,F=3,S=2,P=1][45]。就是说,有2个滤波器,滤波器的尺寸是![3cdot 3][46],它们的步长是2.因此,输出数据体的空间尺寸是(5-3+2)/2+1=3。注意输入数据体使用了零填充![P=1][43],所以输入数据体外边缘一圈都是0。下面的例子在绿色的输出激活数据上循环演示,展示了其中每个元素都是先通过蓝色的输入数据和红色的滤波器逐元素相乘,然后求其总和,最后加上偏差得来。 201 | 202 | ![][10]![][47] 203 | 204 | _**译者注**:请点击图片查看动画演示。如果gif不能正确播放,请读者前往[斯坦福课程官网__][5]查看此演示。_ 205 | 206 | 207 | ![][10] 208 | 209 | **用矩阵乘法实现**:卷积运算本质上就是在滤波器和输入数据的局部区域间做点积。卷积层的常用实现方式就是利用这一点,将卷积层的前向传播变成一个巨大的矩阵乘法: 210 | 211 | 1. 输入图像的局部区域被**im2col**操作拉伸为列。比如,如果输入是[227x227x3],要与尺寸为11x11x3的滤波器以步长为4进行卷积,就取输入中的[11x11x3]数据块,然后将其拉伸为长度为11x11x3=363的列向量。重复进行这一过程,因为步长为4,所以输出的宽高为(227-11)/4+1=55,所以得到_im2col_操作的输出矩阵**X_col**的尺寸是[363x3025],其中每列是拉伸的感受野,共有55x55=3,025个。注意因为感受野之间有重叠,所以输入数据体中的数字在不同的列中可能有重复。 212 | 213 | 2. 卷积层的权重也同样被拉伸成行。举例,如果有96个尺寸为[11x11x3]的滤波器,就生成一个矩阵**W_row**,尺寸为[96x363]。 214 | 215 | 3. 现在卷积的结果和进行一个大矩阵乘**np.dot(W_row, X_col)**是等价的了,能得到每个滤波器和每个感受野间的点积。在我们的例子中,这个操作的输出是[96x3025],给出了每个滤波器在每个位置的点积输出。 216 | 217 | 4. 结果最后必须被重新变为合理的输出尺寸[55x55x96]。 218 | 219 | 这个方法的缺点就是占用内存太多,因为在输入数据体中的某些值在**X_col**中被复制了多次。但是,其优点是矩阵乘法有非常多的高效实现方式,我们都可以使用(比如常用的[BLAS__][48] API)。还有,同样的_im2col_思路可以用在汇聚操作中。 220 | 221 | 反向传播:卷积操作的反向传播(同时对于数据和权重)还是一个卷积(但是是和空间上翻转的滤波器)。使用一个1维的例子比较容易演示。 222 | 223 | **1x1卷积**:一些论文中使用了1x1的卷积,这个方法最早是在论文[Network in Network__][49]中出现。人们刚开始看见这个1x1卷积的时候比较困惑,尤其是那些具有信号处理专业背景的人。因为信号是2维的,所以1x1卷积就没有意义。但是,在卷积神经网络中不是这样,因为这里是对3个维度进行操作,滤波器和输入数据体的深度是一样的。比如,如果输入是[32x32x3],那么1x1卷积就是在高效地进行3维点积(因为输入深度是3个通道)。 224 | 225 | **扩张卷积**:最近一个研究([Fisher Yu和Vladlen Koltun的论文__][50])给卷积层引入了一个新的叫_扩张(dilation)_的超参数。到目前为止,我们只讨论了卷积层滤波器是连续的情况。但是,让滤波器中元素之间有间隙也是可以的,这就叫做扩张。举例,在某个维度上滤波器**w**的尺寸是3,那么计算输入**x**的方式是:**w[0]*x[0] + w[1]*x[1] + w[2]*x[2]**,此时扩张为0。如果扩张为1,那么计算为: **w[0]*x[0] + w[1]*x[2] + w[2]*x[4]**。换句话说,操作中存在1的间隙。在某些设置中,扩张卷积与正常卷积结合起来非常有用,因为在很少的层数内更快地汇集输入图片的大尺度特征。比如,如果上下重叠2个3x3的卷积层,那么第二个卷积层的神经元的感受野是输入数据体中5x5的区域(可以成这些神经元的_有效感受野_是5x5)。如果我们对卷积进行扩张,那么这个有效感受野就会迅速增长。 226 | 227 | 228 | 229 | #### 汇聚层 230 | 231 | 通常,在连续的卷积层之间会周期性地插入一个汇聚层。它的作用是逐渐降低数据体的空间尺寸,这样的话就能减少网络中参数的数量,使得计算资源耗费变少,也能有效控制过拟合。汇聚层使用MAX操作,对输入数据体的每一个深度切片独立进行操作,改变它的空间尺寸。最常见的形式是汇聚层使用尺寸2x2的滤波器,以步长为2来对每个深度切片进行降采样,将其中75%的激活信息都丢掉。每个MAX操作是从4个数字中取最大值(也就是在深度切片中某个2x2的区域)。深度保持不变。汇聚层的一些公式: 232 | 233 | * 输入数据体尺寸![W_1cdot H_1cdot D_1][51] 234 | * 有两个超参数: 235 | 236 | * 空间大小![F][32] 237 | * 步长![S][33] 238 | * 输出数据体尺寸![W_2cdot H_2cdot D_2][52],其中 239 | ![ W_2=\(W_1-F\)/S+1][53] 240 | ![H_2=\(H_1-F\)/S+1][54] 241 | ![D_2=D_1][55] 242 | 243 | * 因为对输入进行的是固定函数计算,所以没有引入参数 244 | * 在汇聚层中很少使用零填充 245 | 246 | 在实践中,最大汇聚层通常只有两种形式:一种是![F=3,S=2][56],也叫重叠汇聚(overlapping pooling),另一个更常用的是![F=2,S=2][57]。对更大感受野进行汇聚需要的汇聚尺寸也更大,而且往往对网络有破坏性。 247 | 248 | **普通汇聚(General Pooling)**:除了最大汇聚,汇聚单元还可以使用其他的函数,比如_平均_汇聚_(average pooling)_或_L-2范式_汇聚_(L2-norm pooling)_。平均汇聚历史上比较常用,但是现在已经很少使用了。因为实践证明,最大汇聚的效果比平均汇聚要好。 249 | 250 | ![][10] 251 | 252 | ![][58] 253 | 汇聚层在输入数据体的每个深度切片上,独立地对其进行空间上的降采样。左边:本例中,输入数据体尺寸[224x224x64]被降采样到了[112x112x64],采取的滤波器尺寸是2,步长为2,而深度不变。右边:最常用的降采样操作是取最大值,也就是最大汇聚,这里步长为2,每个取最大值操作是从4个数字中选取(即2x2的方块区域中)。 254 | 255 | ![][10] 256 | 257 | **反向传播:**回顾一下反向传播的内容,其中![max\(x,y\)][59]函数的反向传播可以简单理解为将梯度只沿最大的数回传。因此,在向前传播经过汇聚层的时候,通常会把池中最大元素的索引记录下来(有时这个也叫作**道岔(switches)**),这样在反向传播的时候梯度的路由就很高效。 258 | 259 | **不使用汇聚层**:很多人不喜欢汇聚操作,认为可以不使用它。比如在[Striving for Simplicity: The All Convolutional Net__][60]一文中,提出使用一种只有重复的卷积层组成的结构,抛弃汇聚层。通过在卷积层中使用更大的步长来降低数据体的尺寸。有发现认为,在训练一个良好的生成模型时,弃用汇聚层也是很重要的。比如变化自编码器(VAEs:variational autoencoders)和生成性对抗网络(GANs:generative adversarial networks)。现在看起来,未来的卷积网络结构中,无汇聚层的结构不太可能扮演重要的角色。 260 | 261 | 262 | 263 | #### 归一化层 264 | 265 | 在卷积神经网络的结构中,提出了很多不同类型的归一化层,有时候是为了实现在生物大脑中观测到的抑制机制。但是这些层渐渐都不再流行,因为实践证明它们的效果即使存在,也是极其有限的。对于不同类型的归一化层,可以看看Alex Krizhevsky的关于[cuda-convnet library API__][61]的讨论。 266 | 267 | 268 | 269 | #### 全连接层 270 | 271 | 在全连接层中,神经元对于前一层中的所有激活数据是全部连接的,这个常规神经网络中一样。它们的激活可以先用矩阵乘法,再加上偏差。更多细节请查看_神经网络_章节。 272 | 273 | 274 | 275 | ## 把全连接层转化成卷积层 276 | 277 | 全连接层和卷积层之间唯一的不同就是卷积层中的神经元只与输入数据中的一个局部区域连接,并且在卷积列中的神经元共享参数。然而在两类层中,神经元都是计算点积,所以它们的函数形式是一样的。因此,将此两者相互转化是可能的: 278 | 279 | * 对于任一个卷积层,都存在一个能实现和它一样的前向传播函数的全连接层。权重矩阵是一个巨大的矩阵,除了某些特定块(这是因为有局部连接),其余部分都是零。而在其中大部分块中,元素都是相等的(因为参数共享)。 280 | * 相反,任何全连接层都可以被转化为卷积层。比如,一个![K=4096][62]的全连接层,输入数据体的尺寸是![7times 7times 512][63],这个全连接层可以被等效地看做一个![F=7,P=0,S=1,K=4096][64]的卷积层。换句话说,就是将滤波器的尺寸设置为和输入数据体的尺寸一致了。因为只有一个单独的深度列覆盖并滑过输入数据体,所以输出将变成![1times 1times 4096][65],这个结果就和使用初始的那个全连接层一样了。 281 | 282 | 283 | **全连接层转化为卷积层**:在两种变换中,将全连接层转化为卷积层在实际运用中更加有用。假设一个卷积神经网络的输入是224x224x3的图像,一系列的卷积层和汇聚层将图像数据变为尺寸为7x7x512的激活数据体(在AlexNet中就是这样,通过使用5个汇聚层来对输入数据进行空间上的降采样,每次尺寸下降一半,所以最终空间尺寸为224/2/2/2/2/2=7)。从这里可以看到,AlexNet使用了两个尺寸为4096的全连接层,最后一个有1000个神经元的全连接层用于计算分类评分。我们可以将这3个全连接层中的任意一个转化为卷积层: 284 | 285 | * 针对第一个连接区域是[7x7x512]的全连接层,令其滤波器尺寸为![F=7][66],这样输出数据体就为[1x1x4096]了。 286 | * 针对第二个全连接层,令其滤波器尺寸为![F=1][67],这样输出数据体为[1x1x4096]。 287 | * 对最后一个全连接层也做类似的,令其![F=1][67],最终输出为[1x1x1000] 288 | 289 | 实际操作中,每次这样的变换都需要把全连接层的权重W重塑成卷积层的滤波器。那么这样的转化有什么作用呢?它在下面的情况下可以更高效:让卷积网络在一张更大的输入图片上滑动(_**译者注**:即把一张更大的图片的不同区域都分别带入到卷积网络,得到每个区域的得分_),得到多个输出,这样的转化可以让我们在单个向前传播的过程中完成上述的操作。 290 | 291 | 举个例子,如果我们想让224x224尺寸的浮窗,以步长为32在384x384的图片上滑动,把每个经停的位置都带入卷积网络,最后得到6x6个位置的类别得分。上述的把全连接层转换成卷积层的做法会更简便。如果224x224的输入图片经过卷积层和汇聚层之后得到了[7x7x512]的数组,那么,384x384的大图片直接经过同样的卷积层和汇聚层之后会得到[12x12x512]的数组(因为途径5个汇聚层,尺寸变为384/2/2/2/2/2 = 12)。然后再经过上面由3个全连接层转化得到的3个卷积层,最终得到[6x6x1000]的输出(因为(12 - 7)/1 + 1 = 6)。这个结果正是浮窗在原图经停的6x6个位置的得分!(_**译者注**:这一段的翻译与原文不同,经过了译者较多的修改,使更容易理解_) 292 | 293 | > 面对384x384的图像,让(含全连接层)的初始卷积神经网络以32像素的步长独立对图像中的224x224块进行多次评价,其效果和使用把全连接层变换为卷积层后的卷积神经网络进行一次前向传播是一样的。 294 | 295 | 自然,相较于使用被转化前的原始卷积神经网络对所有36个位置进行迭代计算,使用转化后的卷积神经网络进行一次前向传播计算要高效得多,因为36次计算都在共享计算资源。这一技巧在实践中经常使用,一次来获得更好的结果。比如,通常将一张图像尺寸变得更大,然后使用变换后的卷积神经网络来对空间上很多不同位置进行评价得到分类评分,然后在求这些分值的平均值。 296 | 297 | 最后,如果我们想用步长小于32的浮窗怎么办?用多次的向前传播就可以解决。比如我们想用步长为16的浮窗。那么先使用原图在转化后的卷积网络执行向前传播,然后分别沿宽度,沿高度,最后同时沿宽度和高度,把原始图片分别平移16个像素,然后把这些平移之后的图分别带入卷积网络。(_**译者注**:这一段的翻译与原文不同,经过了译者较多的修改,使更容易理解_) 298 | 299 | * [Net Surgery__][68]上一个使用Caffe演示如何在进行变换的IPython Note教程。 300 | 301 | 302 | 303 | 304 | ### **卷积神经网络的结构** 305 | 306 | 卷积神经网络通常是由三种层构成:卷积层,汇聚层(除非特别说明,一般就是最大值汇聚)和全连接层(简称FC)。ReLU激活函数也应该算是是一层,它逐元素地进行激活函数操作。在本节中将讨论在卷积神经网络中这些层通常是如何组合在一起的。 307 | 308 | 309 | 310 | #### 层的排列规律 311 | 312 | 卷积神经网络最常见的形式就是将一些卷积层和ReLU层放在一起,其后紧跟汇聚层,然后重复如此直到图像在空间上被缩小到一个足够小的尺寸,在某个地方过渡成成全连接层也较为常见。最后的全连接层得到输出,比如分类评分等。换句话说,最常见的卷积神经网络结构如下: 313 | 314 | **INPUT -> [[CONV -> RELU]*N -> POOL?]*M -> [FC -> RELU]*K -> FC** 315 | 316 | 其中*****指的是重复次数,**POOL?**指的是一个可选的汇聚层。其中**N >=0**,通常**N<=3**,**M>=0**,**K>=0**,通常**K<3**。例如,下面是一些常见的网络结构规律: 317 | 318 | * **INPUT -> FC**,实现一个线性分类器,此处**N = M = K = 0**。 319 | * **INPUT -> CONV -> RELU -> FC** 320 | * **INPUT -> [CONV -> RELU -> POOL]*2 -> FC -> RELU -> FC**。此处在每个汇聚层之间有一个卷积层。 321 | * **INPUT -> [CONV -> RELU -> CONV -> RELU -> POOL]*3 -> [FC -> RELU]*2 -> FC**。此处每个汇聚层前有两个卷积层,这个思路适用于更大更深的网络,因为在执行具有破坏性的汇聚操作前,多重的卷积层可以从输入数据中学习到更多的复杂特征。 322 | 323 | _几个小滤波器卷积层的组合比一个大滤波器卷积层好_:假设你一层一层地重叠了3个3x3的卷积层(层与层之间有非线性激活函数)。在这个排列下,第一个卷积层中的每个神经元都对输入数据体有一个3x3的视野。第二个卷积层上的神经元对第一个卷积层有一个3x3的视野,也就是对输入数据体有5x5的视野。同样,在第三个卷积层上的神经元对第二个卷积层有3x3的视野,也就是对输入数据体有7x7的视野。假设不采用这3个3x3的卷积层,二是使用一个单独的有7x7的感受野的卷积层,那么所有神经元的感受野也是7x7,但是就有一些缺点。首先,多个卷积层与非线性的激活层交替的结构,比单一卷积层的结构更能提取出深层的更好的特征。其次,假设所有的数据有![C][69]个通道,那么单独的7x7卷积层将会包含![Ctimes \(7times 7times C\)=49C^2][70]个参数,而3个3x3的卷积层的组合仅有![3times \(Ctimes \(3times 3times C\)\)=27C^2][71]个参数。直观说来,最好选择带有小滤波器的卷积层组合,而不是用一个带有大的滤波器的卷积层。前者可以表达出输入数据中更多个强力特征,使用的参数也更少。唯一的不足是,在进行反向传播时,中间的卷积层可能会导致占用更多的内存。 324 | 325 | 最新进展:传统的将层按照线性进行排列的方法已经受到了挑战,挑战来自谷歌的Inception结构和微软亚洲研究院的残差网络(Residual Net)结构。这两个网络(下文案例学习小节中有细节)的特征更加复杂,连接结构也不同。 326 | 327 | 328 | 329 | #### 层的尺寸设置规律 330 | 331 | 到现在为止,我们都没有提及卷积神经网络中每层的超参数的使用。现在先介绍设置结构尺寸的一般性规则,然后根据这些规则进行讨论: 332 | 333 | **输入层**(包含图像的)应该能被2整除很多次。常用数字包括32(比如CIFAR-10),64,96(比如STL-10)或224(比如ImageNet卷积神经网络),384和512。 334 | 335 | **卷积层**应该使用小尺寸滤波器(比如3x3或最多5x5),使用步长![S=1][17]。还有一点非常重要,就是对输入数据进行零填充,这样卷积层就不会改变输入数据在空间维度上的尺寸。比如,当![F=3][21],那就使用![P=1][43]来保持输入尺寸。当![F=5,P=2][72],一般对于任意![F][32],当![P=\(F-1\)/2][18]的时候能保持输入尺寸。如果必须使用更大的滤波器尺寸(比如7x7之类),通常只用在第一个面对原始图像的卷积层上。 336 | 337 | 338 | 339 | **汇聚层**负责对输入数据的空间维度进行降采样。最常用的设置是用用2x2感受野(即![F=2][73])的最大值汇聚,步长为2(![S=2][22])。注意这一操作将会把输入数据中75%的激活数据丢弃(因为对宽度和高度都进行了2的降采样)。另一个不那么常用的设置是使用3x3的感受野,步长为2。最大值汇聚的感受野尺寸很少有超过3的,因为汇聚操作过于激烈,易造成数据信息丢失,这通常会导致算法性能变差。 340 | 341 | _减少尺寸设置的问题_:上文中展示的两种设置是很好的,因为所有的卷积层都能保持其输入数据的空间尺寸,汇聚层只负责对数据体从空间维度进行降采样。如果使用的步长大于1并且不对卷积层的输入数据使用零填充,那么就必须非常仔细地监督输入数据体通过整个卷积神经网络结构的过程,确认所有的步长和滤波器都尺寸互相吻合,卷积神经网络的结构美妙对称地联系在一起。 342 | 343 | 344 | 345 | _为什么在卷积层使用1的步长_?在实际应用中,更小的步长效果更好。上文也已经提过,步长为1可以让空间维度的降采样全部由汇聚层负责,卷积层只负责对输入数据体的深度进行变换。 346 | 347 | _为何使用零填充_?使用零填充除了前面提到的可以让卷积层的输出数据保持和输入数据在空间维度的不变,还可以提高算法性能。如果卷积层值进行卷积而不进行零填充,那么数据体的尺寸就会略微减小,那么图像边缘的信息就会过快地损失掉。 348 | 349 | _因为内存限制所做的妥协_:在某些案例(尤其是早期的卷积神经网络结构)中,基于前面的各种规则,内存的使用量迅速飙升。例如,使用64个尺寸为3x3的滤波器对224x224x3的图像进行卷积,零填充为1,得到的激活数据体尺寸是[224x224x64]。这个数量就是一千万的激活数据,或者就是72MB的内存(每张图就是这么多,激活函数和梯度都是)。因为GPU通常因为内存导致性能瓶颈,所以做出一些妥协是必须的。在实践中,人们倾向于在网络的第一个卷积层做出妥协。例如,可以妥协可能是在第一个卷积层使用步长为2,尺寸为7x7的滤波器(比如在ZFnet中)。在AlexNet中,滤波器的尺寸的11x11,步长为4。 350 | 351 | 352 | 353 | #### 案例学习 354 | 355 | 下面是卷积神经网络领域中比较有名的几种结构: 356 | 357 | * **LeNet**: 第一个成功的卷积神经网络应用,是Yann LeCun在上世纪90年代实现的。当然,最著名还是被应用在识别数字和邮政编码等的[LeNet__][74]结构。 358 | * **AlexNet**:[AlexNet__][24]卷积神经网络在计算机视觉领域中受到欢迎,它由Alex Krizhevsky,Ilya Sutskever和Geoff Hinton实现。AlexNet在2012年的[ImageNet ILSVRC 竞赛__][75]中夺冠,性能远远超出第二名(16%的top5错误率,第二名是26%的top5错误率)。这个网络的结构和LeNet非常类似,但是更深更大,并且使用了层叠的卷积层来获取特征(之前通常是只用一个卷积层并且在其后马上跟着一个汇聚层)。 359 | * **ZF Net**:Matthew Zeiler和Rob Fergus发明的网络在ILSVRC 2013比赛中夺冠,它被称为 [ZFNet__][76](Zeiler & Fergus Net的简称)。它通过修改结构中的超参数来实现对AlexNet的改良,具体说来就是增加了中间卷积层的尺寸,让第一层的步长和滤波器尺寸更小。 360 | * **GoogLeNet**:ILSVRC 2014的胜利者是谷歌的[Szeged等__][77]实现的卷积神经网络。它主要的贡献就是实现了一个_奠基模块_,它能够显著地减少网络中参数的数量(AlexNet中有60M,该网络中只有4M)。还有,这个论文中没有使用卷积神经网络顶部使用全连接层,而是使用了一个平均汇聚,把大量不是很重要的参数都去除掉了。GooLeNet还有几种改进的版本,最新的一个是[Inception-v4__][78]。 361 | * **VGGNet**:ILSVRC 2014的第二名是Karen Simonyan和 Andrew Zisserman实现的卷积神经网络,现在称其为[VGGNet__][79]。它主要的贡献是展示出网络的深度是算法优良性能的关键部分。他们最好的网络包含了16个卷积/全连接层。网络的结构非常一致,从头到尾全部使用的是3x3的卷积和2x2的汇聚。他们的[预训练模型__][79]是可以在网络上获得并在Caffe中使用的。VGGNet不好的一点是它耗费更多计算资源,并且使用了更多的参数,导致更多的内存占用(140M)。其中绝大多数的参数都是来自于第一个全连接层。后来发现这些全连接层即使被去除,对于性能也没有什么影响,这样就显著降低了参数数量。 362 | * **ResNet**:[残差网络__][80](Residual Network)是ILSVRC2015的胜利者,由何恺明等实现。它使用了特殊的_跳跃链接_,大量使用了[批量归一化__][81](batch normalization)。这个结构同样在最后没有使用全连接层。读者可以查看何恺明的的演讲([视频__][82],[PPT__][82]),以及一些使用Torch重现网络的[实验__][82]。ResNet当前最好的卷积神经网络模型(2016年五月)。何开明等最近的工作是对原始结构做一些优化,可以看论文[Identity Mappings in Deep Residual Networks__][83],2016年3月发表。 363 | 364 | **VGGNet的细节:**我们进一步对[VGGNet__][79]的细节进行分析学习。整个VGGNet中的卷积层都是以步长为1进行3x3的卷积,使用了1的零填充,汇聚层都是以步长为2进行了2x2的最大值汇聚。可以写出处理过程中每一步数据体尺寸的变化,然后对数据尺寸和整体权重的数量进行查看: 365 | 366 | 367 | 368 | 369 | 370 | ```py 371 | INPUT: [224x224x3] memory: 224*224*3=150K weights: 0 372 | CONV3-64: [224x224x64] memory: 224*224*64=3.2M weights: (3*3*3)*64 = 1,728 373 | CONV3-64: [224x224x64] memory: 224*224*64=3.2M weights: (3*3*64)*64 = 36,864 374 | POOL2: [112x112x64] memory: 112*112*64=800K weights: 0 375 | CONV3-128: [112x112x128] memory: 112*112*128=1.6M weights: (3*3*64)*128 = 73,728 376 | CONV3-128: [112x112x128] memory: 112*112*128=1.6M weights: (3*3*128)*128 = 147,456 377 | POOL2: [56x56x128] memory: 56*56*128=400K weights: 0 378 | CONV3-256: [56x56x256] memory: 56*56*256=800K weights: (3*3*128)*256 = 294,912 379 | CONV3-256: [56x56x256] memory: 56*56*256=800K weights: (3*3*256)*256 = 589,824 380 | CONV3-256: [56x56x256] memory: 56*56*256=800K weights: (3*3*256)*256 = 589,824 381 | POOL2: [28x28x256] memory: 28*28*256=200K weights: 0 382 | CONV3-512: [28x28x512] memory: 28*28*512=400K weights: (3*3*256)*512 = 1,179,648 383 | CONV3-512: [28x28x512] memory: 28*28*512=400K weights: (3*3*512)*512 = 2,359,296 384 | CONV3-512: [28x28x512] memory: 28*28*512=400K weights: (3*3*512)*512 = 2,359,296 385 | POOL2: [14x14x512] memory: 14*14*512=100K weights: 0 386 | CONV3-512: [14x14x512] memory: 14*14*512=100K weights: (3*3*512)*512 = 2,359,296 387 | CONV3-512: [14x14x512] memory: 14*14*512=100K weights: (3*3*512)*512 = 2,359,296 388 | CONV3-512: [14x14x512] memory: 14*14*512=100K weights: (3*3*512)*512 = 2,359,296 389 | POOL2: [7x7x512] memory: 7*7*512=25K weights: 0 390 | FC: [1x1x4096] memory: 4096 weights: 7*7*512*4096 = 102,760,448 391 | FC: [1x1x4096] memory: 4096 weights: 4096*4096 = 16,777,216 392 | FC: [1x1x1000] memory: 1000 weights: 4096*1000 = 4,096,000 393 | 394 | TOTAL memory: 24M * 4 bytes ~= 93MB / image (only forward! ~*2 for bwd) 395 | TOTAL params: 138M parameters 396 | 397 | ``` 398 | 399 | 注意,大部分的内存和计算时间都被前面的卷积层占用,大部分的参数都用在后面的全连接层,这在卷积神经网络中是比较常见的。在这个例子中,全部参数有140M,但第一个全连接层就包含了100M的参数。 400 | 401 | 402 | 403 | ## 计算上的考量 404 | 405 | 在构建卷积神经网络结构时,最大的瓶颈是内存瓶颈。大部分现代GPU的内存是3/4/6GB,最好的GPU大约有12GB的内存。要注意三种内存占用来源: 406 | 407 | * 来自中间数据体尺寸:卷积神经网络中的每一层中都有激活数据体的原始数值,以及损失函数对它们的梯度(和激活数据体尺寸一致)。通常,大部分激活数据都是在网络中靠前的层中(比如第一个卷积层)。在训练时,这些数据需要放在内存中,因为反向传播的时候还会用到。但是在测试时可以聪明点:让网络在测试运行时候每层都只存储当前的激活数据,然后丢弃前面层的激活数据,这样就能减少巨大的激活数据量。 408 | * 来自参数尺寸:即整个网络的参数的数量,在反向传播时它们的梯度值,以及使用momentum、Adagrad或RMSProp等方法进行最优化时的每一步计算缓存。因此,存储参数向量的内存通常需要在参数向量的容量基础上乘以3或者更多。 409 | * 卷积神经网络实现还有各种零散的内存占用,比如成批的训练数据,扩充的数据等等。 410 | 411 | 一旦对于所有这些数值的数量有了一个大略估计(包含激活数据,梯度和各种杂项),数量应该转化为以GB为计量单位。把这个值乘以4,得到原始的字节数(因为每个浮点数占用4个字节,如果是双精度浮点数那就是占用8个字节),然后多次除以1024分别得到占用内存的KB,MB,最后是GB计量。如果你的网络工作得不好,一个常用的方法是降低批尺寸(batch size),因为绝大多数的内存都是被激活数据消耗掉了。 412 | 413 | 414 | 415 | 416 | ## **拓展资源** 417 | 418 | 和实践相关的拓展资源: 419 | 420 | * [Soumith benchmarks for CONV performance__][84] 421 | * [ConvNetJS CIFAR-10 demo__][85] 可以让你在服务器上实时地调试卷积神经网络的结构,观察计算结果。 422 | * [Caffe__][86],一个流行的卷积神经网络库。 423 | * [State of the art ResNets in Torch7__][87] 424 | 425 | **卷积神经网络笔记**结束。 426 | 427 | 428 | 429 | 430 | ## **译者反馈** 431 | 432 | 1. **转载须全文转载且注明原文链接,否则保留维权权利**; 433 | 434 | 2. 各位知友如果发现翻译不当的地方,欢迎通过评论和私信等方式批评指正,我们会在文中补充感谢贡献者; 435 | 3. CS231n的翻译进入尾声,**欢迎知友们建议后续的翻译方向**; 436 | 4. 本文最初的译稿由杜客和我于五月底完成,为了保证质量,我们两人每人翻译了一个版本,然后结合两个译稿的长处来编辑最终的版本。本文的绝大部分都保留了杜客的版本,在少数段落和语句上采用了我的版本。整个翻译小组在校对工作上付出了很多努力,为译稿提出了近百条修改意见,使得译稿逐渐完善。杜客为了鼓励新手,让此文以我的ID投稿发表。这是我第一次发表文章,非常激动^_^; 437 | 5. 感谢知友@[陈一][88] , @[maxint][89]和 @[刘大絮][90]对细节的指正; 438 | 6. 感谢知友@[钟小祺][91] 对翻译细节的建议。 439 | 440 | 「点赞足矣^_^」 441 | 442 | 443 | 444 | [1]: https://zhuanlan.zhihu.com/write 445 | [2]: https://pic3.zhimg.com/5b83bc8331994f47fedb1459d1424872_r.png 446 | [3]: https://pic1.zhimg.com/f0c45ebc982d64ea0c4822517e7285ac_xs.jpg 447 | [4]: https://www.zhihu.com/people/hmonkey 448 | [5]: http://link.zhihu.com/?target=http%3A//cs231n.github.io/convolutional-networks/ 449 | [6]: http://link.zhihu.com/?target=http%3A//cs.stanford.edu/people/karpathy/ 450 | [7]: https://www.zhihu.com/people/du-ke 451 | [8]: https://www.zhihu.com/people/kun-kun-97-81 452 | [9]: https://www.zhihu.com/people/li-yi-ying-73 453 | [10]: https://pic1.zhimg.com/307530cfd15f5ca2461a2b6f633f93b8_b.png 454 | [11]: https://pic2.zhimg.com/2ef08bb4cf60805d726b2d6db39dd985_b.jpg 455 | [12]: http://zhihu.com/equation?tex=max%280%2Cx%29 456 | [13]: https://pic3.zhimg.com/d9259be829b1cdb3d98a399ebc56defa_b.jpg 457 | [14]: http://link.zhihu.com/?target=http%3A//cs231n.stanford.edu/ 458 | [15]: https://pic4.zhimg.com/ba9dcfa847a71cb695c2653230ea9147_b.jpg 459 | [16]: https://pic3.zhimg.com/90af0bd67ba498239688c81fd61bbc66_b.jpg 460 | [17]: http://zhihu.com/equation?tex=S%3D1 461 | [18]: http://zhihu.com/equation?tex=P%3D%28F-1%29%2F2 462 | [19]: http://zhihu.com/equation?tex=W%3D10 463 | [20]: http://zhihu.com/equation?tex=P%3D0 464 | [21]: http://zhihu.com/equation?tex=F%3D3 465 | [22]: http://zhihu.com/equation?tex=S%3D2 466 | [23]: http://zhihu.com/equation?tex=%28W-F%2B2P%29%2FS%2B1%3D%2810-3%2B0%29%2F2%2B1%3D4.5 467 | [24]: http://link.zhihu.com/?target=http%3A//papers.nips.cc/paper/4824-imagenet-classification-with-deep-convolutional-neural-networks 468 | [25]: http://zhihu.com/equation?tex=F%3D11 469 | [26]: http://zhihu.com/equation?tex=S%3D4 470 | [27]: http://zhihu.com/equation?tex=K%3D96 471 | [28]: https://pic3.zhimg.com/dd62e1d75bda9b592dabb91627d68aa6_b.jpg 472 | [29]: http://zhihu.com/equation?tex=F%3D5 473 | [30]: http://zhihu.com/equation?tex=W_1%5Ctimes+H_1%5Ctimes+D_1 474 | [31]: http://zhihu.com/equation?tex=K 475 | [32]: http://zhihu.com/equation?tex=F 476 | [33]: http://zhihu.com/equation?tex=S 477 | [34]: http://zhihu.com/equation?tex=P 478 | [35]: http://zhihu.com/equation?tex=W_2%5Ctimes+H_2%5Ctimes+D_2 479 | [36]: http://zhihu.com/equation?tex=W_2%3D%28W_1-F%2B2P%29%2FS%2B1 480 | [37]: http://zhihu.com/equation?tex=H_2%3D%28H_1-F%2B2P%29%2FS%2B1 481 | [38]: http://zhihu.com/equation?tex=D_2%3DK 482 | [39]: http://zhihu.com/equation?tex=F%5Ccdot+F%5Ccdot+D_1 483 | [40]: http://zhihu.com/equation?tex=F%5Ccdot+F%5Ccdot+D_1%5Ccdot+K 484 | [41]: http://zhihu.com/equation?tex=d 485 | [42]: http://zhihu.com/equation?tex=W_2%5Ctimes+H_2 486 | [43]: http://zhihu.com/equation?tex=P%3D1 487 | [44]: http://zhihu.com/equation?tex=W_1%3D5%2CH_1%3D5%2CD_1%3D3 488 | [45]: http://zhihu.com/equation?tex=K%3D2%2CF%3D3%2CS%3D2%2CP%3D1 489 | [46]: http://zhihu.com/equation?tex=3%5Ccdot+3 490 | [47]: https://pic2.zhimg.com/333077b83ed421d6bd53eb7a44fd5799_b.jpg 491 | [48]: http://link.zhihu.com/?target=http%3A//www.netlib.org/blas/ 492 | [49]: http://link.zhihu.com/?target=http%3A//arxiv.org/abs/1312.4400 493 | [50]: http://link.zhihu.com/?target=https%3A//arxiv.org/abs/1511.07122 494 | [51]: http://zhihu.com/equation?tex=W_1%5Ccdot+H_1%5Ccdot+D_1 495 | [52]: http://zhihu.com/equation?tex=W_2%5Ccdot+H_2%5Ccdot+D_2 496 | [53]: http://zhihu.com/equation?tex=+W_2%3D%28W_1-F%29%2FS%2B1 497 | [54]: http://zhihu.com/equation?tex=H_2%3D%28H_1-F%29%2FS%2B1 498 | [55]: http://zhihu.com/equation?tex=D_2%3DD_1 499 | [56]: http://zhihu.com/equation?tex=F%3D3%2CS%3D2 500 | [57]: http://zhihu.com/equation?tex=F%3D2%2CS%3D2 501 | [58]: https://pic4.zhimg.com/641c8846abcb02d35938660cf96cef1b_b.jpg 502 | [59]: http://zhihu.com/equation?tex=max%28x%2Cy%29 503 | [60]: http://link.zhihu.com/?target=http%3A//arxiv.org/abs/1412.6806 504 | [61]: http://link.zhihu.com/?target=https%3A//code.google.com/p/cuda-convnet/wiki/LayerParams%23Local_response_normalization_layer_%28same_map%29 505 | [62]: http://zhihu.com/equation?tex=K%3D4096 506 | [63]: http://zhihu.com/equation?tex=7%5Ctimes+7%5Ctimes+512 507 | [64]: http://zhihu.com/equation?tex=F%3D7%2CP%3D0%2CS%3D1%2CK%3D4096 508 | [65]: http://zhihu.com/equation?tex=1%5Ctimes+1%5Ctimes+4096 509 | [66]: http://zhihu.com/equation?tex=F%3D7 510 | [67]: http://zhihu.com/equation?tex=F%3D1 511 | [68]: http://link.zhihu.com/?target=https%3A//github.com/BVLC/caffe/blob/master/examples/net_surgery.ipynb 512 | [69]: http://zhihu.com/equation?tex=C 513 | [70]: http://zhihu.com/equation?tex=C%5Ctimes+%287%5Ctimes+7%5Ctimes+C%29%3D49C%5E2 514 | [71]: http://zhihu.com/equation?tex=3%5Ctimes+%28C%5Ctimes+%283%5Ctimes+3%5Ctimes+C%29%29%3D27C%5E2 515 | [72]: http://zhihu.com/equation?tex=F%3D5%2CP%3D2 516 | [73]: http://zhihu.com/equation?tex=F%3D2 517 | [74]: http://link.zhihu.com/?target=http%3A//yann.lecun.com/exdb/publis/pdf/lecun-98.pdf 518 | [75]: http://link.zhihu.com/?target=http%3A//www.image-net.org/challenges/LSVRC/2014/ 519 | [76]: http://link.zhihu.com/?target=http%3A//arxiv.org/abs/1311.2901 520 | [77]: http://link.zhihu.com/?target=http%3A//arxiv.org/abs/1409.4842 521 | [78]: http://link.zhihu.com/?target=http%3A//arxiv.org/abs/1602.07261 522 | [79]: http://link.zhihu.com/?target=http%3A//www.robots.ox.ac.uk/%7Evgg/research/very_deep/ 523 | [80]: http://link.zhihu.com/?target=http%3A//arxiv.org/abs/1512.03385 524 | [81]: http://link.zhihu.com/?target=http%3A//arxiv.org/abs/1502.03167 525 | [82]: http://link.zhihu.com/?target=https%3A//github.com/gcr/torch-residual-networks 526 | [83]: http://link.zhihu.com/?target=https%3A//arxiv.org/abs/1603.05027 527 | [84]: http://link.zhihu.com/?target=https%3A//github.com/soumith/convnet-benchmarks 528 | [85]: http://link.zhihu.com/?target=http%3A//cs.stanford.edu/people/karpathy/convnetjs/demo/cifar10.html 529 | [86]: http://link.zhihu.com/?target=http%3A//caffe.berkeleyvision.org/ 530 | [87]: http://link.zhihu.com/?target=http%3A//torch.ch/blog/2016/02/04/resnets.html 531 | [88]: https://www.zhihu.com/people/chen-yi-91-27 532 | [89]: https://www.zhihu.com/people/maxint 533 | [90]: https://www.zhihu.com/people/liu-da-xu 534 | [91]: https://www.zhihu.com/people/zhong-xiao-qi-98 535 | 536 | 537 | 538 | 539 | --------------------------------------------------------------------------------