[CS231n 2017]笔记
第一课:
图像、视觉很重要,N年前生物出现视觉以后物种大爆发,互联网上80%以上的数据(按传输的字节数算)都是视频数据。
imagenet2012出现AlexNet以后层数越来越多。
卷积神经网络早在1998年由Lecun提出,后来重新兴起是因为:1、运算性能的提升,得益于摩尔效应,CPU有更多的晶体管,出现了擅长并行运算的GPU;2、大量的数据。
第二课:
由于存在语义鸿沟(semantic gap),计算机理解图像有困难。以前是用硬编码的方式,通过提取边缘、角点再各种处理分类,但是这样的话只能处理一类图像,而遇到新的情况又要重新编码,另外由于情况复杂,硬编码比较容易出错,所以要有新的方法,引出由数据驱动的机器学习的方法,一个更通用的方法以普遍适用于新的情况。
KNN不适用于图像(never used),因为:1、推断慢;2、距离在这里没意义。
理想的方法在推断时是快的,以便部署在轻量级的设备和应用上,而在训练时消耗更长时间是可以接受的,因为可以在设备外预训练。
数据划分为训练集、验证集和测试集。训练集、验证集交叉验证(Cross-Validation),测试集在最最最后才使用,不参与训练过程,只为测试算法性能。
线性分类器—— \(f(x, W) = Wx + b\) (更宽泛一点直接用\(Wx\),其中\(W\)最后一项为\(b\),\(x\)最后一项为1,或者互换过来),有N类结果就为N行1列,最终\(W\)呈现为训练数据的平均。也可以从高维理解,每个图像是一个点,分类器是超平面。但是遇到以下情况时,线性分类器会失效:1、异或;2、一类完全被另一类划分开(同心圆间的夹层);3、一类只是离散的几个点。
第三课:
如果使用线性分类器,就要有一个好的\(W\)来达到更好的性能。为此需要一个方法来衡量\(W\)的好坏,引出损失函数(loss function)来描述当前的\(W\)有多不好,下一步就是想办法找到能让损失函数达到最小的\(W\),那么这个\(W\)就是想要得到的“好的\(W\)”。
通过损失函数可以的值当前的分类器性能,例:有如下数据集\({\{(x_i,y_i)\}}_{i=1}^{N}\),其中\(x_i\)是图像,\(y_i\)是(以整数表示的)标签,那么这个数据集的损失值就是每个样本损失值之和:\(L=\frac{1}{N}\sum\limits_i L_i (f(x_i,W),y_i)\),是否除以N不那么重要,只是等比例缩放。
多类别SVM(Multiclass SVM)的损失函数:\(L_i=\sum\limits_{j\neq y_i}\begin{cases}0 & {\rm if}\ s_{y_i}\geq s_j+1\\ s_j-s_{y_i}+1 & {\rm otherwise}\end{cases}=\sum\limits_{j\neq y_i}\max (0,s_j-s_{y_i}+1)\),其中\(s=f(x_i;W)\)。称为合页损失(Hinge loss),因为其图像形状形如合页。此处的\(+1\)是设置的阈值(margin),意思是正确分类对应的值要比其他类得到的值大至少1,否则就会有“损失”,具体设置视乎实际情况而定。
为降低过拟合风险,损失函数引入正则化项。标准损失函数包含数据损失项和正则化项:\(L(W)=\frac{1}{N}\sum\limits_{i=1}^N L_i(f(x_i,W),y_i)+\lambda R(W)\),式子中的超参数\(\lambda\)(regularization strength)用来平衡这两项。引入正则化项体现了奥卡姆剃刀(Occam's Razor)思想。常用的有L2 :\(R(W)=\sum_k \sum_l W_{k,l}^2\)、L1:\(R(W)=\sum_k \sum_l |W_{k,l}|\)、Elastic net(L1+L2):\(R(W)=\sum_k \sum_l \beta W_{k,l}^2 +|W_{k,l}|\)、Max norm、Dropout。
多项逻辑斯蒂回归(multinomial logistic regression)或者叫Softmax loss(又叫交叉熵损失cross-entropy loss)\(L_i=-{\rm log}P(Y=y_i|X=x_i)\)其中\(P(Y=k|X=x_i)=\frac{e^{s_k}}{\sum_j e^{s_j}} \ {\rm where} \ s=f(x_i;W)\),即\(L_i=-{\rm log}(\frac{e^{s_{y_i}}}{\sum_j e^{s_j}})\)。Softmax指的是这个操作:\(\frac{e^{s_k}}{\sum_j e^{s_j}}\)。其赋予得到的数字(就是\(Wx\)得到的那一列,不是计算得到的损失的数字)额外的含义——unnormalized log probabilities。最好的情况是\(P\)是1,然后\(L_i\)是0啦。
对比Softmax和SVM:SVM由于有阈值,数据点发生微小变化不会有影响,而Softmax则会体现出来。
至此,有数据集\((x,y)\),有值函数\(s=f(x;W)\overset{e.g.}{=}Wx\),有损失函数\(L=\frac{1}{N} \sum_{i=1}^N L_i+R(W)\)其中\(L_i=\)(Softmax或者SVM)。
接下来是优化问题,策略1:随机取\(W\)(???),策略2:跟随梯度。
梯度:1、数值方法,\(W\)每个维度分别增加微小量,看最后结果的变化情况,用于调试;2、解析方法,实际使用的方法。
梯度下降(Gradient Descent):
1 while True: 2 weights_grad = evaluate_gradient(loss_fun, data, weights) 3 weights += - step_size * weights_grad
步长(step size)或学习率(learning rate)是第一个检查的超参数。
另外还有带动量的梯度下降(gradient descent with momentum)和Adam优化器(optimizer)。
实际应用中由于N太大,不可能一次使用所有N计算损失,因此需要使用随机梯度下降(Stochastic Gradient Descent, SDG),分成一个个minibatch进行训练:
1 while True: 2 data_batch = sample_training_data(data, 256) 3 weights_grad = evaluate_gradient(loss_fun, data_batch, weights) 4 weights += - step_size * weights_grad
对真实数值期望的一种蒙特卡洛计算。
过去是提取图像的特征(如:HoG),再根据特征进行分类,类似词袋,而不是使用图像的原始像素值。现在直接端到端,连需要提取的特征也会在训练中更新。
第四课:
为计算任意复杂函数的解析梯度,要用到计算图(computational graphs),用到链式法则。
计算图练习:
\(f(x,y,z)=(x+y)z\)若\(x=-2,y=5,z=-4\)求\(\frac{\partial f}{\partial x},\frac{\partial f}{\partial y},\frac{\partial f}{\partial z}\)。答案:-4,-4,3
\(f(w,x)=\frac{1}{1+e^{-(w_0 x_0 + w_1 x_1 + w_2)}}\)若\(w_0=2,x_0=-1,w_1=-3,x_1=-2,w_2=-3\)分别求\(f\)对\(w_0,x_0,w_1,x_1,w_2\)偏导。答案:-0.2,0.4,-0.4,-0.6,0.2
可以发现sigmoid函数:\(\sigma (x)=\frac{1}{1+e^{-x}}\)对\(x\)求导可以封装起来,\(\frac{d\sigma (x)}{dx}=...=(1-\sigma (x))\sigma (x)\),实际上啥都可以封装起来,便于使用。
加门:梯度分配;最大门:梯度路由;乘门:梯度交换。
雅可比矩阵(还不是很懂),对角阵。
继续练习:
\(f(x,W)=\left \| W\cdot x \right \|^2=\sum_{i=1}^n(W\cdot x)_i^2\)若\(W=\begin{bmatrix}0.1 & 0.5\\ -0.3 & 0.8\end{bmatrix},x=\begin{bmatrix}0.2 \\ 0.4 \end{bmatrix}\)分别求\(f\)对\(W,x\)偏导。答案:\(\begin{bmatrix}0.088 & 0.176\\ 0.104 & 0.208\end{bmatrix},\begin{bmatrix} -0.112\\ 0.636 \end{bmatrix}\)(课件上面\(W\)的答案错了,需要转置)(对\(x\)求偏导需要分别求再求和)
神经网络,之前是线性值函数:\(f=Wx\),现在是2层神经网络:\(f=W_2 \max (0,W_1 x)\)或者3层神经网络:\(f=W_3 \max(0,W_2 \max (0,W_1 x))\),引入非线性。
激活函数,sigmoid:\(\sigma (x)=\frac{1}{1+e^{-x}}\),tanh:\({\rm tanh}(x)\),ReLu:\(\max (0,x)\),Leaky ReLU:\(\max (0.1x,x)\),Maxout:\(\max (w_1^T x+b_1,w_2^T x+b_2)\),ELU:\(\left\{\begin{matrix}x & x\geq 0\\ \alpha (e^x -1) & x < 0\end{matrix}\right.\)
实际生物的神经元复杂得多:类型,多种非线性,不是简单权重等。
2层神经网络=1隐藏层神经网络,3层神经网络=2隐藏层神经网络。
第五课:
卷积神经网络,卷积层更能保留输入的空间结构。(全连接层应该也是可以的,只是关系没有那么明显,不便于可视化,使用卷积应该是为了降低运算量和参数数量吧)
介绍神经网络的历史……,到2012年开始取得惊人的成果(first strong results),语音和图像。再从生物学角度讲,皮层识别边角。最后到Lecun和AlexNet。到现在到处存在的各种应用。
全连接层,输入的\(32\times 32\times 3\)图像展成\(3072\times 1\)向量,然后\(W\)是\(10\times 3072\),那么结果就是\(10\times 1\)的了。
卷积层,输入的\(32\times 32\times 3\)图像保留空间结构而不展开,卷积核是\(5\times 5\times 3\)的,这样卷积得到的每个元素结果是\(w^T x+b\)(然后还要经过激活函数,如ReLU),一个卷积核得到一个二维平面,很多个卷积核得到很多个二维平面,如6个,那么后面层的卷积核的厚度就要等于6。一般卷积核的数量是2的N次幂。
前面层的卷积核表示的是低阶的图像特征(如边缘),越到后面表示的越复杂。
不同于信号处理卷积的定义,卷积核翻转180°。但是在这里不重要,而且卷积核在这里是通过学习更新的,那就更没影响了。
卷积输出的大小(边长):(N - F + 2P) / S+ 1,其中N、F分别是原图和卷积核边长,P是边缘填充,S是卷积步长。一般用0填充边缘,使得图像不至于缩小得太快。
例子:输入\(32\times 32\times 3\),有10个\(5\times 5\)的卷积核,步长为1,填充为2。输出为\(32\times 32\times 10\)。这一层的参数数量是\(10\times (5\times 5\times 3+1)=760\)。
\(1\times 1\)的卷积核可以用于改变厚度。
使用一个\(5\times 5\)的卷积核相当于一个神经元拥有\(5\times 5\)的感受野。
池化层,下采样,数据量变少,更易处理。
最大池化,\(2\times 2\)步长为2。
全连接层,跟普通神经网络一样。
卷积神经网络是卷积层、池化层和全连接层的堆叠,趋势是更小的卷积核和更深的结构,有放弃池化层和全连接层的趋势,只使用卷积层。
典型的结构:[(CONV - RELU) * N - POOL?] * M - (FC - RELU) * K, SOFTMAX,其中N一般最大为5, M可以很大,0 <= K <= 2。更新的网络,如ResNet/GoogLeNet开始挑战这个范式。
第六课:
激活函数:
sigmoid:\(\sigma (x)=\frac{1}{1+e^{-x}}\)值域压缩到[0, 1],曾经流行过,因为可以解释为神经放电从0到1,后来认为ReLU更合理。问题:1、饱和神经元使梯度消失(输入稍大就会让梯度为0);2、非0中心(这会使得对\(w\)求导总为正数,优化时\(w\)的更新路径呈Z字形,比较低效)(不是太理解);3、exp()计算代价比较大。
tanh:\({\rm tanh}(x)\)值域压缩到[-1, 1],0中心,但还是会有梯度消失问题。
ReLu(Rectified Linear Uint):\(f(x)=\max (0,x)\),在正半轴不会饱和,易于计算,收敛快,更符合生物学。但是非0中心,并且负半轴饱和梯度消失挂掉。
Leaky ReLU:\(f(x)=\max (0.1x,x)\),不会饱和,易于计算,收敛快,不会挂掉。也有\(f(x)=\max (\alpha x,x)\),\(\alpha\)作为学习的参数。
ELU(Exponential Linear Uints):\(f(x)=\left\{\begin{matrix}x & x\geq 0\\ \alpha (e^x -1) & x < 0\end{matrix}\right.\),有ReLU的所有优点,接近0均值输出,相对Leaky ReLU在负轴方向对噪声有更强鲁棒性,但是需要计算exp()。
Maxout:\(\max (w_1^T x+b_1,w_2^T x+b_2)\),泛华的ReLU和Leaky LeLU,线性,不会饱和,不会挂掉,但是需要两倍的参数数量。
一般使用ReLU,需要注意学习率,可以尝试Leaky ReLU、Maxout、ELU,可以尝试tanh但是不要抱有期望,不要使用sigmoid。
数据预处理:零均值化(减去均值),归一化(除以标准差),PCA,Whitening。对于图像一般只使用零均值化。推断时也做同样的操作。可以三通道减全图(AlexNet),也可以三通道分别做(VGGNet)。
权重初始化:如果全为0,那么所有神经元做相同事情。激活函数为tanh时,可以:1、使用较小的随机值(小网络可以,但更深的网络有问题,后面的层会变成全0);2、使用更大的随机值,那么几乎所有神经元都饱和了,梯度变为0;3、使用Xavier初始化。激活函数为ReLU时,加一个除以二的东西(He et al., 2015)?
批量归一化(Batch Normalization):\(\hat{x}^{(k)}=\frac{x^{(k)}-E[x^{(k)}]}{\sqrt{{\rm Var}[x^{(k)}]}}\),一般用在卷积层或者全连接层后,在非线性(激活函数)之前。
\(y^{(k)}=\gamma ^{(k)}\hat{x}^{(k)}+\beta ^{(k)}\)里面的缩放项\(\gamma ^{(k)}\)和平移项\(\beta ^{(k)}\)可以学习到\(\gamma ^{(k)}=\sqrt{{\rm Var}[x^{(k)}]}\)和\(\beta ^{(k)}=E[x^{(k)}]\),因此其有足够弹性甚至足以恢复到批量归一化前的模样,实现学习控制tanh具有更高或者更低饱和度的能力。
在测试时(at test time),归一化层中并不重新计算均值和方差,而是使用固定的训练时得到的数值。
开始训练后需要检查损失值(loss),检查不加正则项的过拟合和加了正则项的情况,如果损失值不下降,说明学习率太低,相反的,如果损失值变大,说明学习率过大。一般范围是[1e-3...1e-5]。
超参数优化(Hyperparameter Optimization):先训练试试,再用更长时间训练试试,如果损失值大于原来的3倍,可以不用继续训练了。还有一些没有实践经验不是很明白。如果训练和验证的精度有很大的差值(big gap),说明过可能过拟合,需要增大正则项,如果几乎没有差值,说明没有过拟合,可以增大模型容量。
总结:激活函数(使用ReLU),数据处理(图像:减去均值),加权初始化(使用Xavier初始化),批量归一化,查看学习过程,超参数优化(随机采样,在对数空间?不太懂)。
第七课:
批量归一化(Batch Normalization):输入:\(x:N\times D\),线性参数:\(\gamma ,\beta :D\),中间参数:\(\mu ,\sigma :D\) \(\hat{x}:N\times D\),输出:\(y:N\times D\)。\(\mu_j=\frac{1}{N}\sum_{i=1}^N x_{i,j}\), \(\sigma_j^2 =\frac{1}{N}\sum_{i=1}^N (x_{i,j}-\mu_j)^2\), \(\hat{x}_{i,j}=\frac{x_{i,j}-\sigma_j}{\sqrt{\sigma_j^2+\varepsilon}}\), \(y_{i,j}=\gamma_j \hat{x}_{i,j}+\beta_j\)。
优化(Optimization):SGD可能会走“之”字形,在多维的时候问题更为显著,并且可能会陷在局部最低点或者鞍点(高维时概率很高)。由于实际梯度计算来源于小批量(minibatches)而非整个数据集,因此对梯度的估计含有噪声,路径方向并非始终指向最低点。
SGD+动量项(Momentum):SGD:\(x_{t+1}=x_t -\alpha \nabla f(x_t)\);SGD+动量项:\(v_{t+1}=\rho v_t+\nabla f(x_t)\), \(x_{t+1}=x_t -\alpha v_{t+1}\)。
Nesterov动量(Nesterov Momentum, Nesterov accelerated gradient):\(v_{t+1}=\rho v_t -\alpha \nabla f(x_t+\rho v_t)\), \(x_{t+1}=x_t +v_{t+1}\)。换元\(\tilde{x}_t = x_t +\rho v_t\),得到\((v_{t+1}=\rho v_t -\alpha \nabla f(\tilde{x}_t)\), \(\tilde{x}_{t+1}=\tilde{x}_t -\rho v_t+(1+\rho)v_{t+1}=\tilde{x}_t +v_{t+1}+\rho (v_{t+1}-v_t)\)。
AdaGrad:
RMSProp:
Adam:RMSProp+动量
所有优化方法都有学习率,学习率最好是随时间衰减。步数衰减,指数衰减,1/t衰减。属于二阶参数,不应该一上来就使用衰减。
之前所说都是一阶优化,都是线性近似,实际也可以二阶,但是存储和计算量巨大,效果不是很好,实际不用。Adam是绝大部分情况的默认选择。
缩小训练和测试的差距可以使用模型集成(Model Ensembles):1、训练多个独立模型;2、在测试时取几个结果的平均。一般有几个百分点的提升。甚至不需要训练多个模型,只需要取训练时的几个快照做模型集成。使用学习率快慢跳动变换的训练方法收敛到不同的地方,取快照。
正则化:L2正则化意义并不是很明确。
Dropout:随机神经元置零(使用激活函数)。合理性:解释1:避免特征相互适应;解释2:相当于单一模型中进行模型集成。在测试时不dropout(变大),而是乘以dropout的概率(变小),以使得输入下一层的数值与训练时相当。
训练时加入随机(噪声)防止过拟合,测试时平均掉随机。
数据增强(Data Augmentation):旋转、翻转、随机裁剪、随机缩放、对比度、亮度、PCA、颜色偏移、所有像素偏移、镜头畸变等等,以及它们的组合。
DropConnect:置零的是权重。
部分最大池化(Fractional Max Pooling):变换的的池化区域。不常用。
随机深度(Stochastic Depth)。
迁移学习(Transfer Learning):不需要大量数据来训练。前面的卷积层已经在提取特征方面做好了。如果是较小的数据集,只改变最后的全连接层,如果再大一点的数据集,可以改后面基层全连接层。
第八课:
硬件和深度学习框架。
TensorFlow静态计算图,PyTorch动态计算图。
第九课:
CNN架构,AlexNet、VGG、GoogLeNet、ResNet,还有NiN、Wide ResNet、ResNeXT、Stochastic Depth、DenseNet、FractalNet、SqueezeNet。
使用小的卷积核,三层步长均为1的\(3\times 3\)卷积层效果跟\(7\times 7\)的卷积层相当,因为第一层感受野是\(3\times 3\),第二层是\(5\times 5\),第三层是\(7\times 7\),但是参数数量少了很多。
大部分内存占用在卷积层,绝大部分参数在全连接层。
GoogLeNet有inception模块,无全连接层,参数少只有AlexNet的1/12。并行应用不同卷积、池化操作,再把结果串接起来。由于厚度会不断增大,使用\(1\times 1\)的卷积操作实现瓶颈,减少厚度。
ResNet超级深,使用残差连接。更深的网络理应表现不差于浅的网络,更多的参数更可能过拟合,实际更差,也不过拟合。可能的原因是更深的网络更难训练(优化)。常规网络的做法是直接学习,结果是\(H(x)\),ResNet的做法是认为\(H(x)=F(x)+x\),然后学习的是\(F(x)\),即认为输出\(H(x)\)是输入\(x\)加上或减去的东西\(F(x)\),是对输入的修饰。