http://ufldl.stanford.edu/wiki/index.php?title=Special:Contributions&feed=atom&limit=50&target=Kandeng&year=&month=
Ufldl - User contributions [en]
2024-03-29T15:10:26Z
From Ufldl
MediaWiki 1.16.2
http://ufldl.stanford.edu/wiki/index.php/%E5%8F%8D%E5%90%91%E4%BC%A0%E5%AF%BC%E7%AE%97%E6%B3%95
反向传导算法
2016-12-02T01:30:31Z
<p>Kandeng: </p>
<hr />
<div>假设我们有一个固定样本集 <math>\textstyle \{ (x^{(1)}, y^{(1)}), \ldots, (x^{(m)}, y^{(m)}) \}</math>,它包含 <math>\textstyle m</math> 个样例。我们可以用批量梯度下降法来求解神经网络。具体来讲,对于单个样例 <math>\textstyle (x,y)</math>,其代价函数为:<br />
<br />
:<math><br />
\begin{align}<br />
J(W,b; x,y) = \frac{1}{2} \left\| h_{W,b}(x) - y \right\|^2.<br />
\end{align}<br />
</math><br />
<br />
这是一个(二分之一的)方差代价函数。给定一个包含 <math>\textstyle m</math> 个样例的数据集,我们可以定义整体代价函数为:<br />
<br />
:<math> <br />
\begin{align}<br />
J(W,b)<br />
&= \left[ \frac{1}{m} \sum_{i=1}^m J(W,b;x^{(i)},y^{(i)}) \right]<br />
+ \frac{\lambda}{2} \sum_{l=1}^{n_l-1} \; \sum_{i=1}^{s_l} \; \sum_{j=1}^{s_{l+1}} \left( W^{(l)}_{ji} \right)^2<br />
\\<br />
&= \left[ \frac{1}{m} \sum_{i=1}^m \left( \frac{1}{2} \left\| h_{W,b}(x^{(i)}) - y^{(i)} \right\|^2 \right) \right]<br />
+ \frac{\lambda}{2} \sum_{l=1}^{n_l-1} \; \sum_{i=1}^{s_l} \; \sum_{j=1}^{s_{l+1}} \left( W^{(l)}_{ji} \right)^2<br />
\end{align}<br />
</math><br />
<br />
以上关于<math>\textstyle J(W,b)</math>定义中的第一项是一个均方差项。第二项是一个规则化项(也叫'''权重衰减项'''),其目的是减小权重的幅度,防止过度拟合。<br />
<br />
<br />
[注:通常权重衰减的计算并不使用偏置项 <math>\textstyle b^{(l)}_i</math>,比如我们在 <math>\textstyle J(W, b)</math> 的定义中就没有使用。一般来说,将偏置项包含在权重衰减项中只会对最终的神经网络产生很小的影响。如果你在斯坦福选修过CS229(机器学习)课程,或者在YouTube上看过课程视频,你会发现这个权重衰减实际上是课上提到的贝叶斯规则化方法的变种。在贝叶斯规则化方法中,我们将高斯先验概率引入到参数中计算MAP(极大后验)估计(而不是极大似然估计)。]<br />
<br />
<br />
'''权重衰减参数''' <math>\textstyle \lambda</math> 用于控制公式中两项的相对重要性。在此重申一下这两个复杂函数的含义:<math>\textstyle J(W,b;x,y)</math> 是针对单个样例计算得到的方差代价函数;<math>\textstyle J(W,b)</math> 是整体样本代价函数,它包含权重衰减项。<br />
<br />
<br />
以上的代价函数经常被用于分类和回归问题。在分类问题中,我们用 <math>\textstyle y = 0</math> 或 <math>\textstyle 1</math>,来代表两种类型的标签(回想一下,这是因为 sigmoid激活函数的值域为 <math>\textstyle [0,1]</math>;如果我们使用双曲正切型激活函数,那么应该选用 <math>\textstyle -1</math> 和 <math>\textstyle +1</math> 作为标签)。对于回归问题,我们首先要变换输出值域(译者注:也就是 <math>\textstyle y</math>),以保证其范围为 <math>\textstyle [0,1]</math> (同样地,如果我们使用双曲正切型激活函数,要使输出值域为 <math>\textstyle [-1,1]</math>)。<br />
<br />
<br />
我们的目标是针对参数 <math>\textstyle W</math> 和 <math>\textstyle b</math> 来求其函数 <math>\textstyle J(W,b)</math> 的最小值。为了求解神经网络,我们需要将每一个参数 <math>\textstyle W^{(l)}_{ij}</math> 和 <math>\textstyle b^{(l)}_i</math> 初始化为一个很小的、接近零的随机值(比如说,使用正态分布 <math>\textstyle {Normal}(0,\epsilon^2)</math> 生成的随机值,其中 <math>\textstyle \epsilon</math> 设置为 <math>\textstyle 0.01</math> ),之后对目标函数使用诸如批量梯度下降法的最优化算法。因为 <math>\textstyle J(W, b)</math> 是一个非凸函数,梯度下降法很可能会收敛到局部最优解;但是在实际应用中,梯度下降法通常能得到令人满意的结果。最后,需要再次强调的是,要将参数进行随机初始化,而不是全部置为 <math>\textstyle 0</math>。如果所有参数都用相同的值作为初始值,那么所有隐藏层单元最终会得到与输入值有关的、相同的函数(也就是说,对于所有 <math>\textstyle i</math>,<math>\textstyle W^{(1)}_{ij}</math>都会取相同的值,那么对于任何输入 <math>\textstyle x</math> 都会有:<math>\textstyle a^{(2)}_1 = a^{(2)}_2 = a^{(2)}_3 = \ldots</math> )。随机初始化的目的是使'''对称失效'''。<br />
<br />
<br />
梯度下降法中每一次迭代都按照如下公式对参数 <math>\textstyle W</math> 和<math>\textstyle b</math> 进行更新:<br />
<br />
:<math><br />
\begin{align}<br />
W_{ij}^{(l)} &= W_{ij}^{(l)} - \alpha \frac{\partial}{\partial W_{ij}^{(l)}} J(W,b) \\<br />
b_{i}^{(l)} &= b_{i}^{(l)} - \alpha \frac{\partial}{\partial b_{i}^{(l)}} J(W,b)<br />
\end{align}<br />
</math> <br />
<br />
其中 <math>\textstyle \alpha</math> 是学习速率。其中关键步骤是计算偏导数。我们现在来讲一下'''反向传播'''算法,它是计算偏导数的一种有效方法。<br />
<br />
<br />
我们首先来讲一下如何使用反向传播算法来计算 <math>\textstyle \frac{\partial}{\partial W_{ij}^{(l)}} J(W,b; x, y)</math> 和 <math>\textstyle \frac{\partial}{\partial b_{i}^{(l)}} J(W,b; x, y)</math>,这两项是单个样例 <math>\textstyle (x,y)</math> 的代价函数 <math>\textstyle J(W,b;x,y)</math> 的偏导数。一旦我们求出该偏导数,就可以推导出整体代价函数 <math>\textstyle J(W,b)</math> 的偏导数:<br />
<br />
<br />
:<math><br />
\begin{align}<br />
\frac{\partial}{\partial W_{ij}^{(l)}} J(W,b) &=<br />
\left[ \frac{1}{m} \sum_{i=1}^m \frac{\partial}{\partial W_{ij}^{(l)}} J(W,b; x^{(i)}, y^{(i)}) \right] + \lambda W_{ij}^{(l)} \\<br />
\frac{\partial}{\partial b_{i}^{(l)}} J(W,b) &=<br />
\frac{1}{m}\sum_{i=1}^m \frac{\partial}{\partial b_{i}^{(l)}} J(W,b; x^{(i)}, y^{(i)})<br />
\end{align}<br />
</math> <br />
<br />
以上两行公式稍有不同,第一行比第二行多出一项,是因为权重衰减是作用于 <math>\textstyle W</math> 而不是 <math>\textstyle b</math>。<br />
<br />
<br />
反向传播算法的思路如下:给定一个样例 <math>\textstyle (x,y)</math>,我们首先进行“前向传导”运算,计算出网络中所有的激活值,包括 <math>\textstyle h_{W,b}(x)</math> 的输出值。之后,针对第 <math>\textstyle l</math> 层的每一个节点 <math>\textstyle i</math>,我们计算出其“残差” <math>\textstyle \delta^{(l)}_i</math>,该残差表明了该节点对最终输出值的残差产生了多少影响。对于最终的输出节点,我们可以直接算出网络产生的激活值与实际值之间的差距,我们将这个差距定义为 <math>\textstyle \delta^{(n_l)}_i</math> (第 <math>\textstyle n_l</math> 层表示输出层)。对于隐藏单元我们如何处理呢?我们将基于节点(译者注:第 <math>\textstyle l+1</math> 层节点)残差的加权平均值计算 <math>\textstyle \delta^{(l)}_i</math>,这些节点以 <math>\textstyle a^{(l)}_i</math> 作为输入。下面将给出反向传导算法的细节:<br />
<br />
<br />
<ol><br />
<li>进行前馈传导计算,利用前向传导公式,得到 <math>\textstyle L_2, L_3, \ldots </math> 直到输出层 <math>\textstyle L_{n_l}</math> 的激活值。<br />
<li>对于第 <math>\textstyle n_l</math> 层(输出层)的每个输出单元 <math>\textstyle i</math>,我们根据以下公式计算残差:<br />
<br />
<br />
:<math><br />
\begin{align}<br />
\delta^{(n_l)}_i<br />
= \frac{\partial}{\partial z^{(n_l)}_i} \;\;<br />
\frac{1}{2} \left\|y - h_{W,b}(x)\right\|^2 = - (y_i - a^{(n_l)}_i) \cdot f'(z^{(n_l)}_i)<br />
\end{align}<br />
</math><br />
<br />
[译者注:<br />
:<math> <br />
\begin{align}<br />
\delta^{(n_l)}_i &= \frac{\partial}{\partial z^{n_l}_i}J(W,b;x,y)<br />
= \frac{\partial}{\partial z^{n_l}_i}\frac{1}{2} \left\|y - h_{W,b}(x)\right\|^2 \\<br />
&= \frac{\partial}{\partial z^{n_l}_i}\frac{1}{2} \sum_{j=1}^{S_{n_l}} (y_j-a_j^{(n_l)})^2<br />
= \frac{\partial}{\partial z^{n_l}_i}\frac{1}{2} \sum_{j=1}^{S_{n_l}} (y_j-f(z_j^{(n_l)}))^2 \\<br />
&= - (y_i - f(z_i^{(n_l)})) \cdot f'(z^{(n_l)}_i)<br />
= - (y_i - a^{(n_l)}_i) \cdot f'(z^{(n_l)}_i)<br />
\end{align}<br />
</math> <br />
]<br />
<br />
<li>对 <math>\textstyle l = n_l-1, n_l-2, n_l-3, \ldots, 2</math> 的各个层,第 <math>\textstyle l</math> 层的第 <math>\textstyle i</math> 个节点的残差计算方法如下:<br />
: <math> <br />
\delta^{(l)}_i = \left( \sum_{j=1}^{s_{l+1}} W^{(l)}_{ji} \delta^{(l+1)}_j \right) f'(z^{(l)}_i)<br />
</math> <br />
<br />
{译者注:<br />
:<math> <br />
\begin{align}<br />
\delta^{(n_l-1)}_i &=\frac{\partial}{\partial z^{n_l-1}_i}J(W,b;x,y)<br />
= \frac{\partial}{\partial z^{n_l-1}_i}\frac{1}{2} \left\|y - h_{W,b}(x)\right\|^2 <br />
= \frac{\partial}{\partial z^{n_l-1}_i}\frac{1}{2} \sum_{j=1}^{S_{n_l}}(y_j-a_j^{(n_l)})^2 \\<br />
&= \frac{1}{2} \sum_{j=1}^{S_{n_l}}\frac{\partial}{\partial z^{n_l-1}_i}(y_j-a_j^{(n_l)})^2<br />
= \frac{1}{2} \sum_{j=1}^{S_{n_l}}\frac{\partial}{\partial z^{n_l-1}_i}(y_j-f(z_j^{(n_l)}))^2 \\<br />
&= \sum_{j=1}^{S_{n_l}}-(y_j-f(z_j^{(n_l)})) \cdot \frac{\partial}{\partial z_i^{(n_l-1)}}f(z_j^{(n_l)})<br />
= \sum_{j=1}^{S_{n_l}}-(y_j-f(z_j^{(n_l)})) \cdot f'(z_j^{(n_l)}) \cdot \frac{\partial z_j^{(n_l)}}{\partial z_i^{(n_l-1)}} \\<br />
&= \sum_{j=1}^{S_{n_l}} \delta_j^{(n_l)} \cdot \frac{\partial z_j^{(n_l)}}{\partial z_i^{n_l-1}}<br />
= \sum_{j=1}^{S_{n_l}} \left(\delta_j^{(n_l)} \cdot \frac{\partial}{\partial z_i^{n_l-1}}\sum_{k=1}^{S_{n_l-1}}f(z_k^{n_l-1}) \cdot W_{jk}^{n_l-1}\right) \\<br />
&= \sum_{j=1}^{S_{n_l}} \delta_j^{(n_l)} \cdot W_{ji}^{n_l-1} \cdot f'(z_i^{n_l-1})<br />
= \left(\sum_{j=1}^{S_{n_l}}W_{ji}^{n_l-1}\delta_j^{(n_l)}\right)f'(z_i^{n_l-1})<br />
\end{align}<br />
</math> <br />
<br />
将上式中的<math>\textstyle n_l-1</math>与<math>\textstyle n_l</math>的关系替换为<math>\textstyle l</math>与<math>\textstyle l+1</math>的关系,就可以得到:<br />
: <math> <br />
\delta^{(l)}_i = \left( \sum_{j=1}^{s_{l+1}} W^{(l)}_{ji} \delta^{(l+1)}_j \right) f'(z^{(l)}_i)<br />
</math> <br />
以上逐次从后向前求导的过程即为“反向传导”的本意所在。<br />
<br />
]<br />
<br />
<br />
<br />
<li>计算我们需要的偏导数,计算方法如下:<br />
:<math> <br />
\begin{align}<br />
\frac{\partial}{\partial W_{ij}^{(l)}} J(W,b; x, y) &= a^{(l)}_j \delta_i^{(l+1)} \\<br />
\frac{\partial}{\partial b_{i}^{(l)}} J(W,b; x, y) &= \delta_i^{(l+1)}.<br />
\end{align}<br />
</math> <br />
</ol><br />
<br />
<br />
最后,我们用矩阵-向量表示法重写以上算法。我们使用“<math>\textstyle \bullet</math>” 表示向量乘积运算符(在Matlab或Octave里用“<tt>.*</tt>”表示,也称作阿达马乘积)。若 <math>\textstyle a = b \bullet c</math>,则 <math>\textstyle a_i = b_ic_i</math>。在上一个教程中我们扩展了 <math>\textstyle f(\cdot)</math> 的定义,使其包含向量运算,这里我们也对偏导数 <math>\textstyle f'(\cdot)</math> 也做了同样的处理(于是又有 <math> \textstyle f'([z_1, z_2, z_3]) = [f'(z_1), f'(z_2), f'(z_3)]</math> )。<br />
<br />
<br />
那么,反向传播算法可表示为以下几个步骤:<br />
<br />
<ol><br />
<li>进行前馈传导计算,利用前向传导公式,得到 <math>\textstyle L_2, L_3, \ldots</math>直到输出层 <math>\textstyle L_{n_l}</math> 的激活值。<br />
<br />
<li>对输出层(第 <math>\textstyle n_l</math> 层),计算:<br />
<br />
:<math> \begin{align}<br />
\delta^{(n_l)}<br />
= - (y - a^{(n_l)}) \bullet f'(z^{(n_l)})<br />
\end{align}</math> <br />
<br />
<li>对于 <math>\textstyle l = n_l-1, n_l-2, n_l-3, \ldots, 2</math> 的各层,计算:<br />
:<math> \begin{align}<br />
\delta^{(l)} = \left((W^{(l)})^T \delta^{(l+1)}\right) \bullet f'(z^{(l)})<br />
\end{align}</math> <br />
<br />
<li>计算最终需要的偏导数值:<br />
:<math> \begin{align}<br />
\nabla_{W^{(l)}} J(W,b;x,y) &= \delta^{(l+1)} (a^{(l)})^T, \\<br />
\nabla_{b^{(l)}} J(W,b;x,y) &= \delta^{(l+1)}.<br />
\end{align}</math> <br />
</ol><br />
<br />
<br />
'''实现中应注意:'''在以上的第2步和第3步中,我们需要为每一个 <math>\textstyle i</math> 值计算其 <math>\textstyle f'(z^{(l)}_i)</math>。假设 <math>\textstyle f(z)</math> 是sigmoid函数,并且我们已经在前向传导运算中得到了 <math>\textstyle a^{(l)}_i</math>。那么,使用我们早先推导出的 <math>\textstyle f'(z)</math>表达式,就可以计算得到 <math>\textstyle f'(z^{(l)}_i) = a^{(l)}_i (1- a^{(l)}_i)</math>。<br />
<br />
<br />
最后,我们将对梯度下降算法做个全面总结。在下面的伪代码中,<math>\textstyle \Delta W^{(l)}</math> 是一个与矩阵 <math>\textstyle W^{(l)}</math> 维度相同的矩阵,<math>\textstyle \Delta b^{(l)}</math> 是一个与 <math>\textstyle b^{(l)}</math> 维度相同的向量。注意这里“<math>\textstyle \Delta W^{(l)}</math>”是一个矩阵,而不是“<math>\textstyle \Delta</math> 与 <math>\textstyle W^{(l)}</math> 相乘”。下面,我们实现批量梯度下降法中的一次迭代:<br />
<br />
<br />
<ol><br />
<li>对于所有 <math>\textstyle l</math>,令 <math>\textstyle \Delta W^{(l)} := 0</math> , <math>\textstyle \Delta b^{(l)} := 0</math> (设置为全零矩阵或全零向量)<br />
<br />
<li>对于 <math>\textstyle i = 1</math> 到 <math>\textstyle m</math>,<br />
<br />
<ol type="a"><br />
<li>使用反向传播算法计算 <math>\textstyle \nabla_{W^{(l)}} J(W,b;x,y)</math> 和 <math>\textstyle \nabla_{b^{(l)}} J(W,b;x,y)</math>。<br />
<li>计算 <math>\textstyle \Delta W^{(l)} := \Delta W^{(l)} + \nabla_{W^{(l)}} J(W,b;x,y)</math>。<br />
<li>计算 <math>\textstyle \Delta b^{(l)} := \Delta b^{(l)} + \nabla_{b^{(l)}} J(W,b;x,y)</math>。 <br />
</ol><br />
<br />
<li>更新权重参数:<br />
:<math> \begin{align}<br />
W^{(l)} &= W^{(l)} - \alpha \left[ \left(\frac{1}{m} \Delta W^{(l)} \right) + \lambda W^{(l)}\right] \\<br />
b^{(l)} &= b^{(l)} - \alpha \left[\frac{1}{m} \Delta b^{(l)}\right]<br />
\end{align}</math> <br />
</ol><br />
<br />
现在,我们可以重复梯度下降法的迭代步骤来减小代价函数 <math>\textstyle J(W,b)</math> 的值,进而求解我们的神经网络。<br />
<br />
<br />
==中英文对照==<br />
<br />
:反向传播算法 Backpropagation Algorithm<br />
:(批量)梯度下降法 (batch) gradient descent<br />
:(整体)代价函数 (overall) cost function<br />
:方差 squared-error<br />
:均方差 average sum-of-squares error<br />
:规则化项 regularization term<br />
:权重衰减 weight decay<br />
:偏置项 bias terms<br />
:贝叶斯规则化方法 Bayesian regularization method<br />
:高斯先验概率 Gaussian prior<br />
:极大后验估计 MAP<br />
:极大似然估计 maximum likelihood estimation<br />
:激活函数 activation function<br />
:双曲正切函数 tanh function<br />
:非凸函数 non-convex function<br />
:隐藏层单元 hidden (layer) units<br />
:对称失效 symmetry breaking<br />
:学习速率 learning rate<br />
:前向传导 forward pass<br />
:假设值 hypothesis <br />
:残差 error term<br />
:加权平均值 weighted average <br />
:前馈传导 feedforward pass<br />
:阿达马乘积 Hadamard product<br />
:前向传播 forward propagation<br />
<br />
<br />
==中文译者==<br />
<br />
王方(fangkey@gmail.com),林锋(xlfg@yeah.net),许利杰(csxulijie@gmail.com)<br />
<br />
<br />
{{稀疏自编码器}}<br />
<br />
<br />
<br />
{{Languages|Backpropagation_Algorithm|English}}</div>
Kandeng
http://ufldl.stanford.edu/wiki/index.php/%E7%A8%80%E7%96%8F%E7%BC%96%E7%A0%81%E8%87%AA%E7%BC%96%E7%A0%81%E8%A1%A8%E8%BE%BE
稀疏编码自编码表达
2014-05-14T06:22:34Z
<p>Kandeng: /* 稀疏编码 */</p>
<hr />
<div>== 稀疏编码 ==<br />
<br />
<br />
在稀疏自编码算法中,我们试着学习得到一组权重参数 <math>W</math>(以及相应的截距 <math>b</math>),通过这些参数可以使我们得到稀疏特征向量 <math>\sigma(Wx + b)</math> ,这些特征向量对于重构输入样本非常有用。<br />
<br />
[[File:STL_SparseAE.png | 240px]]<br />
<br />
<br />
稀疏编码可以看作是稀疏自编码方法的一个变形,该方法试图直接学习数据的特征集。利用与此特征集相应的基向量,将学习得到的特征集从特征空间转换到样本数据空间,这样我们就可以用学习得到的特征集重构样本数据。 <br />
<br />
<br />
确切地说,在稀疏编码算法中,有样本数据 <math>x</math> 供我们进行特征学习。特别是,学习一个用于表示样本数据的稀疏特征集 <math>s</math>, 和一个将特征集从特征空间转换到样本数据空间的基向量 <math>A</math>, 我们可以构建如下目标函数:<br />
<br />
:<math><br />
J(A, s) = \lVert As - x \rVert_2^2 + \lambda \lVert s \rVert_1<br />
</math><br />
<br />
(<math>\lVert x \rVert_k</math>是x的Lk范数,等价于 <math>\left( \sum{ \left| x_i^k \right| } \right) ^{\frac{1}{k}}</math>。L2 范数即大家熟知的欧几里得范数,L1 范数是向量元素的绝对值之和)<br />
<br />
<br />
上式前第一部分是利用基向量将特征集重构为样本数据所产生的误差,第二部分为稀疏性惩罚项(sparsity penalty term),用于保证特征集的稀疏性。 <br />
<br />
<br />
但是,如目标函数所示,它的约束性并不强――按常数比例缩放<math>A</math>的同时再按这个常数的倒数缩放 <math>s</math>,结果不会改变误差大小,却会减少稀疏代价(表达式第二项)的值。因此,需要为 <math>A</math> 中每项 <math>A_j</math> 增加额外约束 <math>A_j^TA_j \le 1</math>。问题变为:<br />
<br />
:<math><br />
\begin{array}{rcl}<br />
{\rm minimize} & \lVert As - x \rVert_2^2 + \lambda \lVert s \rVert_1 \\<br />
{\rm s.t.} & A_j^TA_j \le 1 \; \forall j \\<br />
\end{array} <br />
</math><br />
<br />
<br />
遗憾的是,因为目标函数并不是一个凸函数,所以不能用梯度方法解决这个优化问题。但是,在给定 <math>A</math> 的情况下,最小化 <math>J(A, s)</math> 求解 <math>s</math> 是凸的。同理,给定 <math>s</math> 最小化 <math>J(A, s)</math> 求解 <math>A</math> 也是凸的。这表明,可以通过交替固定 <math>s</math >和 A 分别求解 <math>A</math>和<math>s</math>。实践表明,这一策略取得的效果非常好。 <br />
<br />
<br />
但是,以上表达式带来了另一个难题:不能用简单的梯度方法来实现约束条件 <math>A_j^TA_j \le 1 \; \forall j</math>。因此在实际问题中,此约束条件还不足以成为“权重衰变”("weight decay")项以保证 A 的每一项值够小。这样我们就得到一个新的目标函数: <br />
<br />
:<math><br />
J(A, s) = \lVert As - x \rVert_2^2 + \lambda \lVert s \rVert_1 + \gamma \lVert A \rVert_2^2<br />
</math><br />
<br />
(注意上式中第三项, <math>\lVert A \rVert_2^2</math>等价于<math>\sum_r{\sum_c{A_{rc}^2}}</math>,是A各项的平方和)<br />
<br />
<br />
这一目标函数带来了最后一个问题,即 L1 范数在 0 点处不可微影响了梯度方法的应用。尽管可以通过其他非梯度下降方法避开这一问题,但是本文通过使用近似值“平滑” L1 范数的方法解决此难题。使用 <math>\sqrt{x^2 + \epsilon}</math> 代替 <math>\left| x \right|</math>, 对 L1 范数进行平滑,其中 <math>\epsilon</math> 是“平滑参数”("smoothing parameter")或者“稀疏参数”("sparsity parameter") (如果 <math>\epsilon</math>远大于<math>x</math>, 则 <math>x + \epsilon</math> 的值由 <math>\epsilon</math> 主导,其平方根近似于<math>\epsilon</math>)。在下文提及拓扑稀疏编码时,“平滑”会派上用场。 <br />
<br />
<br />
因此,最终的目标函数是:<br />
<br />
:<math><br />
J(A, s) = \lVert As - x \rVert_2^2 + \lambda \sqrt{s^2 + \epsilon} + \gamma \lVert A \rVert_2^2<br />
</math><br />
<br />
( <math>\sqrt{s^2 + \epsilon}</math> 是 <math>\sum_k{\sqrt{s_k^2 + \epsilon}}</math> 的简写)<br />
<br />
<br />
该目标函数可以通过以下过程迭代优化: <br />
<br />
<ol><br />
<li>随机初始化<math>A</math><br />
<li>重复以下步骤直至收敛:<br />
<ol><br />
<li>根据上一步给定的<math>A</math>,求解能够最小化<math>J(A, s)</math>的<math>s</math><br />
<li>根据上一步得到的<math>s</math>,,求解能够最小化<math>J(A, s)</math>的<math>A</math> </ol><br />
</ol><br />
<br />
<br />
观察修改后的目标函数 <math>J(A, s)</math>,给定 <math>s</math> 的条件下,目标函数可以简化为 <math>J(A; s) = \lVert As - x \rVert_2^2 + \gamma \lVert A \rVert_2^2</math>(因为 <math>s</math> 的 L1 范式不是 <math>A</math> 的函数,所以可以忽略)。简化后的目标函数是一个关于 <math>A</math> 的简单二次项式,因此对 <math>A</math> 求导是很容易的。这种求导的一种快捷方法是矩阵微积分([[Useful Links | 相关链接]]部分列出了跟矩阵演算有关的内容)。遗憾的是,在给定 <math>A</math> 的条件下,目标函数却不具备这样的求导方法,因此目标函数的最小化步骤只能用梯度下降或其他类似的最优化方法。 <br />
<br />
<br />
理论上,通过上述迭代方法求解目标函数的最优化问题最终得到的特征集(A 的基向量)与通过稀疏自编码学习得到的特征集是差不多的。但是实际上,为了获得更好的算法收敛性需要使用一些小技巧,后面的[[ Sparse Coding: Autoencoder Interpretation#Sparse coding in practice | 稀疏编码实践]] 稀疏编码实践章节会详细介绍这些技巧。用梯度下降方法求解目标函数也略需技巧,另外使用矩阵演算或[[Deriving gradients using the backpropagation idea | 反向传播算法]]则有助于解决此类问题。<br />
<br />
== 拓扑稀疏编码 ==<br />
<br />
<br />
通过稀疏编码,我们能够得到一组用于表示样本数据的特征集。不过,让我们来找些灵感,我们希望学习得到一组有某种“秩序”的特征集。举个例子,视觉特征,如前面所提到的,大脑皮层 V1 区神经元能够按特定的方向对边缘进行检测,同时,这些神经元(在生理上)被组织成超柱(hypercolumns),在超柱中,相邻神经元以相似的方向对边缘进行检测,一个神经元检测水平边缘,其相邻神经元检测到的边缘就稍微偏离水平方向,沿着超柱,神经元就可以检测到与水平方向相差更大的边缘了。 <br />
<br />
<br />
受该例子的启发,我们希望学习到的特征也具有这样“拓扑秩序”的性质。这对于我们要学习的特征意味着什么呢?直观的讲,如果“相邻”的特征是“相似”的,就意味着如果某个特征被激活,那么与之相邻的特征也将随之被激活。 <br />
<br />
<br />
具体而言,假设我们(随意地)将特征组织成一个方阵。我们就希望矩阵中相邻的特征是相似的。实现这一点的方法是将相邻特征按经过平滑的L1范式惩罚进行分组,如果按 3x3 方阵分组,则用 <math>\sqrt{s_{1,1}^2 + s_{1,2}^2 + s_{1,3}^2 + s_{2,1}^2 + s_{2,2}^2 + s_{3,2}^2 + s_{3,1}^2 + s_{3,2}^2 + s_{3,3}^2 + \epsilon}</math> 代替 <math>\sqrt{s_{1,1}^2 + \epsilon}</math>, 其分组通常是重合的,因此从第 1 行第 1 列开始的 3x3 区域是一个分组,从第 1 行第 2 列开始的 3x3 区域是另一个分组,以此类推。最终,这样的分组会形成环绕,就好像这个矩阵是个环形曲面,所以每个特征都以同样的次数进行了分组。<br />
于是,将经过平滑的所有分组的 L1 惩罚值之和代替经过平滑的 L1 惩罚值,得到新的目标函数如下:<br />
<br />
:<math><br />
J(A, s) = \lVert As - x \rVert_2^2 + \lambda \sum_{\text{all groups } g}{\sqrt{ \left( \sum_{\text{all } s \in g}{s^2} \right) + \epsilon} } + \gamma \lVert A \rVert_2^2<br />
</math><br />
<br />
<br />
实际上,“分组”可以通过“分组矩阵”<math>V</math> 完成,于是矩阵 <math>V</math> 的第 <math>r</math> 行标识了哪些特征被分到第 <math>r</math> 组中,即如果第 <math>r</math> 组包含特征 <math>c</math> 则 <math>V_{r, c} = 1</math>。通过分组矩阵实现分组使得梯度的计算更加直观,使用此分组矩阵,目标函数被重写为: <br />
<br />
:<math><br />
J(A, s) = \lVert As - x \rVert_2^2 + \lambda \sum{ \sqrt{Vss^T + \epsilon} } + \gamma \lVert A \rVert_2^2<br />
</math><br />
<br />
(令 <math>D = \sqrt{Vss^T + \epsilon}</math>,<math>\sum{ \sqrt{Vss^T + \epsilon} }</math> 等价于 <math>\sum_r{ \sum_c { D_{r, c} } } </math>)<br />
<br />
<br />
该目标函数能够使用之前部分提到的迭代方法进行求解。拓扑稀疏编码得到的特征与稀疏编码得到的类似,只是拓扑稀疏编码得到的特征是以某种方式有“秩序”排列的。 <br />
<br />
<br />
== 稀疏编码实践 ==<br />
<br />
<br />
如上所述,虽然稀疏编码背后的理论十分简单,但是要写出准确无误的实现代码并能快速又恰到好处地收敛到最优值,则需要一定的技巧。 <br />
<br />
<br />
回顾一下之前提到的简单迭代算法:<br />
<br />
<ol><br />
<li>随机初始化<math>A</math><br />
<li>重复以下步骤直至收敛到最优值:<br />
<ol><br />
<li>根据上一步给定的<math>A</math>,求解能够最小化<math>J(A, s)</math>的<math>s</math> <br />
<li>根据上一步得到的<math>s</math>,求解能够最小化<math>J(A, s)</math>的<math>A</math> <br />
</ol><br />
</ol><br />
<br />
<br />
这样信手拈来地执行这个算法,结果并不会令人满意,即使确实得到了某些结果。以下是两种更快更优化的收敛技巧:<br />
<br />
<ol><br />
<li>将样本分批为“迷你块”<br />
<li>良好的<math>s</math>初始值<br />
</ol><br />
<br />
<br />
=== 将样本分批为“迷你块” ===<br />
<br />
<br />
如果你一次性在大规模数据集(比如,有10000 个patch)上执行简单的迭代算法,你会发现每次迭代都要花很长时间,也因此这算法要花好长时间才能达到收敛结果。为了提高收敛速度,可以选择在迷你块上运行该算法。每次迭代的时候,不是在所有的 10000 个 patchs 上执行该算法,而是使用迷你块,即从 10000 个 patch 中随机选出 2000 个 patch,再在这个迷你块上执行这个算法。这样就可以做到一石二鸟――第一,提高了每次迭代的速度,因为现在每次迭代只在 2000 个 patch 上执行而不是 10000个;第二,也是更重要的,它提高了收敛的速度(原因见[[TODO]])。<br />
<br />
<br />
=== 良好的<math>s</math>初始值 ===<br />
<br />
另一个能获得更快速更优化收敛的重要技巧是:在给定 <math>A</math> 的条件下,根据目标函数使用梯度下降(或其他方法)求解 <math>s</math> 之前找到良好的特征矩阵 <math>s</math> 的初始值。实际上,除非在优化 <math>A</math> 的最优值前已找到一个最佳矩阵 <math>s</math>,不然每次迭代过程中随机初始化 <math>s</math> 值会导致很差的收敛效果。下面给出一个初始化 <math>s</math> 的较好方法: <br />
<br />
<ol><br />
<li>令<math>s \leftarrow W^Tx</math> (<math>x</math> 是迷你块中patches的矩阵表示)<br />
<li><math>s</math>中的每个特征(<math>s</math>的每一列),除以其在<math>A</math>中对应基向量的范数。即,如果<math>s_{r, c}</math>表示第<math>c</math>个样本的第<math>r</math>个特征,则<math>A_c</math>表示<math>A</math>中的第<math>c</math>个基向量,则令<br />
<math>s_{r, c} \leftarrow \frac{ s_{r, c} } { \lVert A_c \rVert }.</math><br />
</ol><br />
<br />
<br />
无疑,这样的初始化有助于算法的改进,因为上述的第一步希望找到满足 <math>Ws \approx x</math> 的矩阵 <math>s</math>;第二步对 <math>s</math> 作规范化处理是为了保持较小的稀疏惩罚值。这也表明,只采用上述步骤的某一步而不是两步对 <math>s</math> 做初始化处理将严重影响算法性能。([[TODO]]: 此链接将会对为什么这样的初始化能改进算法作出更详细的解释)<br />
<br />
<br />
=== 可运行算法 ===<br />
<br />
有了以上两种技巧,稀疏编码算法修改如下: <br />
<br />
<ol><br />
<li>随机初始化<math>A</math><br />
<li>重复以下步骤直至收敛<br />
<ol><br />
<li>随机选取一个有2000个patches的迷你块 <br />
<li>如上所述,初始化<math>s</math><br />
<li>根据上一步给定的<math>A</math>,求解能够最小化<math>J(A, s)</math>的<math>s</math><br />
<li>根据上一步得到的<math>s</math>,求解能够最小化<math>J(A, s)</math>的<math>A</math> <br />
</ol><br />
</ol><br />
<br />
通过上述方法,可以相对快速的得到局部最优解。<br />
<br />
<br />
<br />
==中英文对照==<br />
<br />
:稀疏编码 sparse coding<br />
:自编码 autoencoder<br />
:目标函数 objective function<br />
:稀疏代价 sparsity cost<br />
:反向传播 backpropagation <br />
:基于梯度的 gradient-based<br />
:非凸的 non-convex<br />
:权重衰变 weight decay<br />
:拓扑稀疏编码 topographic sparse coding<br />
:拓扑秩序 topographically ordered<br />
:平滑的一范数惩罚 smoothed L1 penalty<br />
:迷你块 mini-batches<br />
:收敛速度 the rate of convergence<br />
:梯度下降 gradient descent<br />
:局部最优解 local optima<br />
<br />
<br />
<br />
==中文译者==<br />
<br />
许超(xuchaowill@gmail.com), 张睿卿(zrqjennifer@gmail.com), 林锋(xlfg@yeah.net)<br />
<br />
<br />
{{Sparse_Autoencoder}}<br />
<br />
<br />
{{Languages|Sparse_Coding:_Autoencoder_Interpretation|English}}</div>
Kandeng
http://ufldl.stanford.edu/wiki/index.php/%E5%8F%8D%E5%90%91%E4%BC%A0%E5%AF%BC%E7%AE%97%E6%B3%95
反向传导算法
2013-07-31T04:46:55Z
<p>Kandeng: </p>
<hr />
<div>假设我们有一个固定样本集 <math>\textstyle \{ (x^{(1)}, y^{(1)}), \ldots, (x^{(m)}, y^{(m)}) \}</math>,它包含 <math>\textstyle m</math> 个样例。我们可以用批量梯度下降法来求解神经网络。具体来讲,对于单个样例 <math>\textstyle (x,y)</math>,其代价函数为:<br />
<br />
:<math><br />
\begin{align}<br />
J(W,b; x,y) = \frac{1}{2} \left\| h_{W,b}(x) - y \right\|^2.<br />
\end{align}<br />
</math><br />
<br />
这是一个(二分之一的)方差代价函数。给定一个包含 <math>\textstyle m</math> 个样例的数据集,我们可以定义整体代价函数为:<br />
<br />
:<math> <br />
\begin{align}<br />
J(W,b)<br />
&= \left[ \frac{1}{m} \sum_{i=1}^m J(W,b;x^{(i)},y^{(i)}) \right]<br />
+ \frac{\lambda}{2} \sum_{l=1}^{n_l-1} \; \sum_{i=1}^{s_l} \; \sum_{j=1}^{s_{l+1}} \left( W^{(l)}_{ji} \right)^2<br />
\\<br />
&= \left[ \frac{1}{m} \sum_{i=1}^m \left( \frac{1}{2} \left\| h_{W,b}(x^{(i)}) - y^{(i)} \right\|^2 \right) \right]<br />
+ \frac{\lambda}{2} \sum_{l=1}^{n_l-1} \; \sum_{i=1}^{s_l} \; \sum_{j=1}^{s_{l+1}} \left( W^{(l)}_{ji} \right)^2<br />
\end{align}<br />
</math><br />
<br />
以上公式中的第一项 <math>\textstyle J(W,b)</math> 是一个均方差项。第二项是一个规则化项(也叫'''权重衰减项'''),其目的是减小权重的幅度,防止过度拟合。<br />
<br />
<br />
[注:通常权重衰减的计算并不使用偏置项 <math>\textstyle b^{(l)}_i</math>,比如我们在 <math>\textstyle J(W, b)</math> 的定义中就没有使用。一般来说,将偏置项包含在权重衰减项中只会对最终的神经网络产生很小的影响。如果你在斯坦福选修过CS229(机器学习)课程,或者在YouTube上看过课程视频,你会发现这个权重衰减实际上是课上提到的贝叶斯规则化方法的变种。在贝叶斯规则化方法中,我们将高斯先验概率引入到参数中计算MAP(极大后验)估计(而不是极大似然估计)。]<br />
<br />
<br />
'''权重衰减参数''' <math>\textstyle \lambda</math> 用于控制公式中两项的相对重要性。在此重申一下这两个复杂函数的含义:<math>\textstyle J(W,b;x,y)</math> 是针对单个样例计算得到的方差代价函数;<math>\textstyle J(W,b)</math> 是整体样本代价函数,它包含权重衰减项。<br />
<br />
<br />
以上的代价函数经常被用于分类和回归问题。在分类问题中,我们用 <math>\textstyle y = 0</math> 或 <math>\textstyle 1</math>,来代表两种类型的标签(回想一下,这是因为 sigmoid激活函数的值域为 <math>\textstyle [0,1]</math>;如果我们使用双曲正切型激活函数,那么应该选用 <math>\textstyle -1</math> 和 <math>\textstyle +1</math> 作为标签)。对于回归问题,我们首先要变换输出值域(译者注:也就是 <math>\textstyle y</math>),以保证其范围为 <math>\textstyle [0,1]</math> (同样地,如果我们使用双曲正切型激活函数,要使输出值域为 <math>\textstyle [-1,1]</math>)。<br />
<br />
<br />
我们的目标是针对参数 <math>\textstyle W</math> 和 <math>\textstyle b</math> 来求其函数 <math>\textstyle J(W,b)</math> 的最小值。为了求解神经网络,我们需要将每一个参数 <math>\textstyle W^{(l)}_{ij}</math> 和 <math>\textstyle b^{(l)}_i</math> 初始化为一个很小的、接近零的随机值(比如说,使用正态分布 <math>\textstyle {Normal}(0,\epsilon^2)</math> 生成的随机值,其中 <math>\textstyle \epsilon</math> 设置为 <math>\textstyle 0.01</math> ),之后对目标函数使用诸如批量梯度下降法的最优化算法。因为 <math>\textstyle J(W, b)</math> 是一个非凸函数,梯度下降法很可能会收敛到局部最优解;但是在实际应用中,梯度下降法通常能得到令人满意的结果。最后,需要再次强调的是,要将参数进行随机初始化,而不是全部置为 <math>\textstyle 0</math>。如果所有参数都用相同的值作为初始值,那么所有隐藏层单元最终会得到与输入值有关的、相同的函数(也就是说,对于所有 <math>\textstyle i</math>,<math>\textstyle W^{(1)}_{ij}</math>都会取相同的值,那么对于任何输入 <math>\textstyle x</math> 都会有:<math>\textstyle a^{(2)}_1 = a^{(2)}_2 = a^{(2)}_3 = \ldots</math> )。随机初始化的目的是使'''对称失效'''。<br />
<br />
<br />
梯度下降法中每一次迭代都按照如下公式对参数 <math>\textstyle W</math> 和<math>\textstyle b</math> 进行更新:<br />
<br />
:<math><br />
\begin{align}<br />
W_{ij}^{(l)} &= W_{ij}^{(l)} - \alpha \frac{\partial}{\partial W_{ij}^{(l)}} J(W,b) \\<br />
b_{i}^{(l)} &= b_{i}^{(l)} - \alpha \frac{\partial}{\partial b_{i}^{(l)}} J(W,b)<br />
\end{align}<br />
</math> <br />
<br />
其中 <math>\textstyle \alpha</math> 是学习速率。其中关键步骤是计算偏导数。我们现在来讲一下'''反向传播'''算法,它是计算偏导数的一种有效方法。<br />
<br />
<br />
我们首先来讲一下如何使用反向传播算法来计算 <math>\textstyle \frac{\partial}{\partial W_{ij}^{(l)}} J(W,b; x, y)</math> 和 <math>\textstyle \frac{\partial}{\partial b_{i}^{(l)}} J(W,b; x, y)</math>,这两项是单个样例 <math>\textstyle (x,y)</math> 的代价函数 <math>\textstyle J(W,b;x,y)</math> 的偏导数。一旦我们求出该偏导数,就可以推导出整体代价函数 <math>\textstyle J(W,b)</math> 的偏导数:<br />
<br />
<br />
:<math><br />
\begin{align}<br />
\frac{\partial}{\partial W_{ij}^{(l)}} J(W,b) &=<br />
\left[ \frac{1}{m} \sum_{i=1}^m \frac{\partial}{\partial W_{ij}^{(l)}} J(W,b; x^{(i)}, y^{(i)}) \right] + \lambda W_{ij}^{(l)} \\<br />
\frac{\partial}{\partial b_{i}^{(l)}} J(W,b) &=<br />
\frac{1}{m}\sum_{i=1}^m \frac{\partial}{\partial b_{i}^{(l)}} J(W,b; x^{(i)}, y^{(i)})<br />
\end{align}<br />
</math> <br />
<br />
以上两行公式稍有不同,第一行比第二行多出一项,是因为权重衰减是作用于 <math>\textstyle W</math> 而不是 <math>\textstyle b</math>。<br />
<br />
<br />
反向传播算法的思路如下:给定一个样例 <math>\textstyle (x,y)</math>,我们首先进行“前向传导”运算,计算出网络中所有的激活值,包括 <math>\textstyle h_{W,b}(x)</math> 的输出值。之后,针对第 <math>\textstyle l</math> 层的每一个节点 <math>\textstyle i</math>,我们计算出其“残差” <math>\textstyle \delta^{(l)}_i</math>,该残差表明了该节点对最终输出值的残差产生了多少影响。对于最终的输出节点,我们可以直接算出网络产生的激活值与实际值之间的差距,我们将这个差距定义为 <math>\textstyle \delta^{(n_l)}_i</math> (第 <math>\textstyle n_l</math> 层表示输出层)。对于隐藏单元我们如何处理呢?我们将基于节点(译者注:第 <math>\textstyle l+1</math> 层节点)残差的加权平均值计算 <math>\textstyle \delta^{(l)}_i</math>,这些节点以 <math>\textstyle a^{(l)}_i</math> 作为输入。下面将给出反向传导算法的细节:<br />
<br />
<br />
<ol><br />
<li>进行前馈传导计算,利用前向传导公式,得到 <math>\textstyle L_2, L_3, \ldots </math> 直到输出层 <math>\textstyle L_{n_l}</math> 的激活值。<br />
<li>对于第 <math>\textstyle n_l</math> 层(输出层)的每个输出单元 <math>\textstyle i</math>,我们根据以下公式计算残差:<br />
<br />
<br />
:<math><br />
\begin{align}<br />
\delta^{(n_l)}_i<br />
= \frac{\partial}{\partial z^{(n_l)}_i} \;\;<br />
\frac{1}{2} \left\|y - h_{W,b}(x)\right\|^2 = - (y_i - a^{(n_l)}_i) \cdot f'(z^{(n_l)}_i)<br />
\end{align}<br />
</math><br />
<br />
[译者注:<br />
:<math> <br />
\begin{align}<br />
\delta^{(n_l)}_i &= \frac{\partial}{\partial z^{n_l}_i}J(W,b;x,y)<br />
= \frac{\partial}{\partial z^{n_l}_i}\frac{1}{2} \left\|y - h_{W,b}(x)\right\|^2 \\<br />
&= \frac{\partial}{\partial z^{n_l}_i}\frac{1}{2} \sum_{j=1}^{S_{n_l}} (y_j-a_j^{(n_l)})^2<br />
= \frac{\partial}{\partial z^{n_l}_i}\frac{1}{2} \sum_{j=1}^{S_{n_l}} (y_j-f(z_j^{(n_l)}))^2 \\<br />
&= - (y_i - f(z_i^{(n_l)})) \cdot f'(z^{(n_l)}_i)<br />
= - (y_i - a^{(n_l)}_i) \cdot f'(z^{(n_l)}_i)<br />
\end{align}<br />
</math> <br />
]<br />
<br />
<li>对 <math>\textstyle l = n_l-1, n_l-2, n_l-3, \ldots, 2</math> 的各个层,第 <math>\textstyle l</math> 层的第 <math>\textstyle i</math> 个节点的残差计算方法如下:<br />
: <math> <br />
\delta^{(l)}_i = \left( \sum_{j=1}^{s_{l+1}} W^{(l)}_{ji} \delta^{(l+1)}_j \right) f'(z^{(l)}_i)<br />
</math> <br />
<br />
{译者注:<br />
:<math> <br />
\begin{align}<br />
\delta^{(n_l-1)}_i &=\frac{\partial}{\partial z^{n_l-1}_i}J(W,b;x,y)<br />
= \frac{\partial}{\partial z^{n_l-1}_i}\frac{1}{2} \left\|y - h_{W,b}(x)\right\|^2 <br />
= \frac{\partial}{\partial z^{n_l-1}_i}\frac{1}{2} \sum_{j=1}^{S_{n_l}}(y_j-a_j^{(n_l)})^2 \\<br />
&= \frac{1}{2} \sum_{j=1}^{S_{n_l}}\frac{\partial}{\partial z^{n_l-1}_i}(y_j-a_j^{(n_l)})^2<br />
= \frac{1}{2} \sum_{j=1}^{S_{n_l}}\frac{\partial}{\partial z^{n_l-1}_i}(y_j-f(z_j^{(n_l)}))^2 \\<br />
&= \sum_{j=1}^{S_{n_l}}-(y_j-f(z_j^{(n_l)})) \cdot \frac{\partial}{\partial z_i^{(n_l-1)}}f(z_j^{(n_l)})<br />
= \sum_{j=1}^{S_{n_l}}-(y_j-f(z_j^{(n_l)})) \cdot f'(z_j^{(n_l)}) \cdot \frac{\partial z_j^{(n_l)}}{\partial z_i^{(n_l-1)}} \\<br />
&= \sum_{j=1}^{S_{n_l}} \delta_j^{(n_l)} \cdot \frac{\partial z_j^{(n_l)}}{\partial z_i^{n_l-1}}<br />
= \sum_{j=1}^{S_{n_l}} \left(\delta_j^{(n_l)} \cdot \frac{\partial}{\partial z_i^{n_l-1}}\sum_{k=1}^{S_{n_l-1}}f(z_k^{n_l-1}) \cdot W_{jk}^{n_l-1}\right) \\<br />
&= \sum_{j=1}^{S_{n_l}} \delta_j^{(n_l)} \cdot W_{ji}^{n_l-1} \cdot f'(z_i^{n_l-1})<br />
= \left(\sum_{j=1}^{S_{n_l}}W_{ji}^{n_l-1}\delta_j^{(n_l)}\right)f'(z_i^{n_l-1})<br />
\end{align}<br />
</math> <br />
<br />
将上式中的<math>\textstyle n_l-1</math>与<math>\textstyle n_l</math>的关系替换为<math>\textstyle l</math>与<math>\textstyle l+1</math>的关系,就可以得到:<br />
: <math> <br />
\delta^{(l)}_i = \left( \sum_{j=1}^{s_{l+1}} W^{(l)}_{ji} \delta^{(l+1)}_j \right) f'(z^{(l)}_i)<br />
</math> <br />
以上逐次从后向前求导的过程即为“反向传导”的本意所在。<br />
<br />
]<br />
<br />
<br />
<br />
<li>计算我们需要的偏导数,计算方法如下:<br />
:<math> <br />
\begin{align}<br />
\frac{\partial}{\partial W_{ij}^{(l)}} J(W,b; x, y) &= a^{(l)}_j \delta_i^{(l+1)} \\<br />
\frac{\partial}{\partial b_{i}^{(l)}} J(W,b; x, y) &= \delta_i^{(l+1)}.<br />
\end{align}<br />
</math> <br />
</ol><br />
<br />
<br />
最后,我们用矩阵-向量表示法重写以上算法。我们使用“<math>\textstyle \bullet</math>” 表示向量乘积运算符(在Matlab或Octave里用“<tt>.*</tt>”表示,也称作阿达马乘积)。若 <math>\textstyle a = b \bullet c</math>,则 <math>\textstyle a_i = b_ic_i</math>。在上一个教程中我们扩展了 <math>\textstyle f(\cdot)</math> 的定义,使其包含向量运算,这里我们也对偏导数 <math>\textstyle f'(\cdot)</math> 也做了同样的处理(于是又有 <math> \textstyle f'([z_1, z_2, z_3]) = [f'(z_1), f'(z_2), f'(z_3)]</math> )。<br />
<br />
<br />
那么,反向传播算法可表示为以下几个步骤:<br />
<br />
<ol><br />
<li>进行前馈传导计算,利用前向传导公式,得到 <math>\textstyle L_2, L_3, \ldots</math>直到输出层 <math>\textstyle L_{n_l}</math> 的激活值。<br />
<br />
<li>对输出层(第 <math>\textstyle n_l</math> 层),计算:<br />
<br />
:<math> \begin{align}<br />
\delta^{(n_l)}<br />
= - (y - a^{(n_l)}) \bullet f'(z^{(n_l)})<br />
\end{align}</math> <br />
<br />
<li>对于 <math>\textstyle l = n_l-1, n_l-2, n_l-3, \ldots, 2</math> 的各层,计算:<br />
:<math> \begin{align}<br />
\delta^{(l)} = \left((W^{(l)})^T \delta^{(l+1)}\right) \bullet f'(z^{(l)})<br />
\end{align}</math> <br />
<br />
<li>计算最终需要的偏导数值:<br />
:<math> \begin{align}<br />
\nabla_{W^{(l)}} J(W,b;x,y) &= \delta^{(l+1)} (a^{(l)})^T, \\<br />
\nabla_{b^{(l)}} J(W,b;x,y) &= \delta^{(l+1)}.<br />
\end{align}</math> <br />
</ol><br />
<br />
<br />
'''实现中应注意:'''在以上的第2步和第3步中,我们需要为每一个 <math>\textstyle i</math> 值计算其 <math>\textstyle f'(z^{(l)}_i)</math>。假设 <math>\textstyle f(z)</math> 是sigmoid函数,并且我们已经在前向传导运算中得到了 <math>\textstyle a^{(l)}_i</math>。那么,使用我们早先推导出的 <math>\textstyle f'(z)</math>表达式,就可以计算得到 <math>\textstyle f'(z^{(l)}_i) = a^{(l)}_i (1- a^{(l)}_i)</math>。<br />
<br />
<br />
最后,我们将对梯度下降算法做个全面总结。在下面的伪代码中,<math>\textstyle \Delta W^{(l)}</math> 是一个与矩阵 <math>\textstyle W^{(l)}</math> 维度相同的矩阵,<math>\textstyle \Delta b^{(l)}</math> 是一个与 <math>\textstyle b^{(l)}</math> 维度相同的向量。注意这里“<math>\textstyle \Delta W^{(l)}</math>”是一个矩阵,而不是“<math>\textstyle \Delta</math> 与 <math>\textstyle W^{(l)}</math> 相乘”。下面,我们实现批量梯度下降法中的一次迭代:<br />
<br />
<br />
<ol><br />
<li>对于所有 <math>\textstyle l</math>,令 <math>\textstyle \Delta W^{(l)} := 0</math> , <math>\textstyle \Delta b^{(l)} := 0</math> (设置为全零矩阵或全零向量)<br />
<br />
<li>对于 <math>\textstyle i = 1</math> 到 <math>\textstyle m</math>,<br />
<br />
<ol type="a"><br />
<li>使用反向传播算法计算 <math>\textstyle \nabla_{W^{(l)}} J(W,b;x,y)</math> 和 <math>\textstyle \nabla_{b^{(l)}} J(W,b;x,y)</math>。<br />
<li>计算 <math>\textstyle \Delta W^{(l)} := \Delta W^{(l)} + \nabla_{W^{(l)}} J(W,b;x,y)</math>。<br />
<li>计算 <math>\textstyle \Delta b^{(l)} := \Delta b^{(l)} + \nabla_{b^{(l)}} J(W,b;x,y)</math>。 <br />
</ol><br />
<br />
<li>更新权重参数:<br />
:<math> \begin{align}<br />
W^{(l)} &= W^{(l)} - \alpha \left[ \left(\frac{1}{m} \Delta W^{(l)} \right) + \lambda W^{(l)}\right] \\<br />
b^{(l)} &= b^{(l)} - \alpha \left[\frac{1}{m} \Delta b^{(l)}\right]<br />
\end{align}</math> <br />
</ol><br />
<br />
现在,我们可以重复梯度下降法的迭代步骤来减小代价函数 <math>\textstyle J(W,b)</math> 的值,进而求解我们的神经网络。<br />
<br />
<br />
==中英文对照==<br />
<br />
:反向传播算法 Backpropagation Algorithm<br />
:(批量)梯度下降法 (batch) gradient descent<br />
:(整体)代价函数 (overall) cost function<br />
:方差 squared-error<br />
:均方差 average sum-of-squares error<br />
:规则化项 regularization term<br />
:权重衰减 weight decay<br />
:偏置项 bias terms<br />
:贝叶斯规则化方法 Bayesian regularization method<br />
:高斯先验概率 Gaussian prior<br />
:极大后验估计 MAP<br />
:极大似然估计 maximum likelihood estimation<br />
:激活函数 activation function<br />
:双曲正切函数 tanh function<br />
:非凸函数 non-convex function<br />
:隐藏层单元 hidden (layer) units<br />
:对称失效 symmetry breaking<br />
:学习速率 learning rate<br />
:前向传导 forward pass<br />
:假设值 hypothesis <br />
:残差 error term<br />
:加权平均值 weighted average <br />
:前馈传导 feedforward pass<br />
:阿达马乘积 Hadamard product<br />
:前向传播 forward propagation<br />
<br />
<br />
==中文译者==<br />
<br />
王方(fangkey@gmail.com),林锋(xlfg@yeah.net),许利杰(csxulijie@gmail.com)<br />
<br />
<br />
{{稀疏自编码器}}<br />
<br />
<br />
<br />
{{Languages|Backpropagation_Algorithm|English}}</div>
Kandeng
http://ufldl.stanford.edu/wiki/index.php/%E5%8F%8D%E5%90%91%E4%BC%A0%E5%AF%BC%E7%AE%97%E6%B3%95
反向传导算法
2013-07-23T08:59:53Z
<p>Kandeng: </p>
<hr />
<div>假设我们有一个固定样本集 <math>\textstyle \{ (x^{(1)}, y^{(1)}), \ldots, (x^{(m)}, y^{(m)}) \}</math>,它包含 <math>\textstyle m</math> 个样例。我们可以用批量梯度下降法来求解神经网络。具体来讲,对于单个样例 <math>\textstyle (x,y)</math>,其代价函数为:<br />
<br />
:<math><br />
\begin{align}<br />
J(W,b; x,y) = \frac{1}{2} \left\| h_{W,b}(x) - y \right\|^2.<br />
\end{align}<br />
</math><br />
<br />
这是一个(二分之一的)方差代价函数。给定一个包含 <math>\textstyle m</math> 个样例的数据集,我们可以定义整体代价函数为:<br />
<br />
:<math> <br />
\begin{align}<br />
J(W,b)<br />
&= \left[ \frac{1}{m} \sum_{i=1}^m J(W,b;x^{(i)},y^{(i)}) \right]<br />
+ \frac{\lambda}{2} \sum_{l=1}^{n_l-1} \; \sum_{i=1}^{s_l} \; \sum_{j=1}^{s_{l+1}} \left( W^{(l)}_{ji} \right)^2<br />
\\<br />
&= \left[ \frac{1}{m} \sum_{i=1}^m \left( \frac{1}{2} \left\| h_{W,b}(x^{(i)}) - y^{(i)} \right\|^2 \right) \right]<br />
+ \frac{\lambda}{2} \sum_{l=1}^{n_l-1} \; \sum_{i=1}^{s_l} \; \sum_{j=1}^{s_{l+1}} \left( W^{(l)}_{ji} \right)^2<br />
\end{align}<br />
</math><br />
<br />
以上公式中的第一项 <math>\textstyle J(W,b)</math> 是一个均方差项。第二项是一个规则化项(也叫'''权重衰减项'''),其目的是减小权重的幅度,防止过度拟合。<br />
<br />
<br />
[注:通常权重衰减的计算并不使用偏置项 <math>\textstyle b^{(l)}_i</math>,比如我们在 <math>\textstyle J(W, b)</math> 的定义中就没有使用。一般来说,将偏置项包含在权重衰减项中只会对最终的神经网络产生很小的影响。如果你在斯坦福选修过CS229(机器学习)课程,或者在YouTube上看过课程视频,你会发现这个权重衰减实际上是课上提到的贝叶斯规则化方法的变种。在贝叶斯规则化方法中,我们将高斯先验概率引入到参数中计算MAP(极大后验)估计(而不是极大似然估计)。]<br />
<br />
<br />
'''权重衰减参数''' <math>\textstyle \lambda</math> 用于控制公式中两项的相对重要性。在此重申一下这两个复杂函数的含义:<math>\textstyle J(W,b;x,y)</math> 是针对单个样例计算得到的方差代价函数;<math>\textstyle J(W,b)</math> 是整体样本代价函数,它包含权重衰减项。<br />
<br />
<br />
以上的代价函数经常被用于分类和回归问题。在分类问题中,我们用 <math>\textstyle y = 0</math> 或 <math>\textstyle 1</math>,来代表两种类型的标签(回想一下,这是因为 sigmoid激活函数的值域为 <math>\textstyle [0,1]</math>;如果我们使用双曲正切型激活函数,那么应该选用 <math>\textstyle -1</math> 和 <math>\textstyle +1</math> 作为标签)。对于回归问题,我们首先要变换输出值域(译者注:也就是 <math>\textstyle y</math>),以保证其范围为 <math>\textstyle [0,1]</math> (同样地,如果我们使用双曲正切型激活函数,要使输出值域为 <math>\textstyle [-1,1]</math>)。<br />
<br />
<br />
我们的目标是针对参数 <math>\textstyle W</math> 和 <math>\textstyle b</math> 来求其函数 <math>\textstyle J(W,b)</math> 的最小值。为了求解神经网络,我们需要将每一个参数 <math>\textstyle W^{(l)}_{ij}</math> 和 <math>\textstyle b^{(l)}_i</math> 初始化为一个很小的、接近零的随机值(比如说,使用正态分布 <math>\textstyle {Normal}(0,\epsilon^2)</math> 生成的随机值,其中 <math>\textstyle \epsilon</math> 设置为 <math>\textstyle 0.01</math> ),之后对目标函数使用诸如批量梯度下降法的最优化算法。因为 <math>\textstyle J(W, b)</math> 是一个非凸函数,梯度下降法很可能会收敛到局部最优解;但是在实际应用中,梯度下降法通常能得到令人满意的结果。最后,需要再次强调的是,要将参数进行随机初始化,而不是全部置为 <math>\textstyle 0</math>。如果所有参数都用相同的值作为初始值,那么所有隐藏层单元最终会得到与输入值有关的、相同的函数(也就是说,对于所有 <math>\textstyle i</math>,<math>\textstyle W^{(1)}_{ij}</math>都会取相同的值,那么对于任何输入 <math>\textstyle x</math> 都会有:<math>\textstyle a^{(2)}_1 = a^{(2)}_2 = a^{(2)}_3 = \ldots</math> )。随机初始化的目的是使'''对称失效'''。<br />
<br />
<br />
梯度下降法中每一次迭代都按照如下公式对参数 <math>\textstyle W</math> 和<math>\textstyle b</math> 进行更新:<br />
<br />
:<math><br />
\begin{align}<br />
W_{ij}^{(l)} &= W_{ij}^{(l)} - \alpha \frac{\partial}{\partial W_{ij}^{(l)}} J(W,b) \\<br />
b_{i}^{(l)} &= b_{i}^{(l)} - \alpha \frac{\partial}{\partial b_{i}^{(l)}} J(W,b)<br />
\end{align}<br />
</math> <br />
<br />
其中 <math>\textstyle \alpha</math> 是学习速率。其中关键步骤是计算偏导数。我们现在来讲一下'''反向传播'''算法,它是计算偏导数的一种有效方法。<br />
<br />
<br />
我们首先来讲一下如何使用反向传播算法来计算 <math>\textstyle \frac{\partial}{\partial W_{ij}^{(l)}} J(W,b; x, y)</math> 和 <math>\textstyle \frac{\partial}{\partial b_{i}^{(l)}} J(W,b; x, y)</math>,这两项是单个样例 <math>\textstyle (x,y)</math> 的代价函数 <math>\textstyle J(W,b;x,y)</math> 的偏导数。一旦我们求出该偏导数,就可以推导出整体代价函数 <math>\textstyle J(W,b)</math> 的偏导数:<br />
<br />
<br />
:<math><br />
\begin{align}<br />
\frac{\partial}{\partial W_{ij}^{(l)}} J(W,b) &=<br />
\left[ \frac{1}{m} \sum_{i=1}^m \frac{\partial}{\partial W_{ij}^{(l)}} J(W,b; x^{(i)}, y^{(i)}) \right] + \lambda W_{ij}^{(l)} \\<br />
\frac{\partial}{\partial b_{i}^{(l)}} J(W,b) &=<br />
\frac{1}{m}\sum_{i=1}^m \frac{\partial}{\partial b_{i}^{(l)}} J(W,b; x^{(i)}, y^{(i)})<br />
\end{align}<br />
</math> <br />
<br />
以上两行公式稍有不同,第一行比第二行多出一项,是因为权重衰减是作用于 <math>\textstyle W</math> 而不是 <math>\textstyle b</math>。<br />
<br />
<br />
反向传播算法的思路如下:给定一个样例 <math>\textstyle (x,y)</math>,我们首先进行“前向传导”运算,计算出网络中所有的激活值,包括 <math>\textstyle h_{W,b}(x)</math> 的输出值。之后,针对第 <math>\textstyle l</math> 层的每一个节点 <math>\textstyle i</math>,我们计算出其“残差” <math>\textstyle \delta^{(l)}_i</math>,该残差表明了该节点对最终输出值的残差产生了多少影响。对于最终的输出节点,我们可以直接算出网络产生的激活值与实际值之间的差距,我们将这个差距定义为 <math>\textstyle \delta^{(n_l)}_i</math> (第 <math>\textstyle n_l</math> 层表示输出层)。对于隐藏单元我们如何处理呢?我们将基于节点(译者注:第 <math>\textstyle l+1</math> 层节点)残差的加权平均值计算 <math>\textstyle \delta^{(l)}_i</math>,这些节点以 <math>\textstyle a^{(l)}_i</math> 作为输入。下面将给出反向传导算法的细节:<br />
<br />
<br />
<ol><br />
<li>进行前馈传导计算,利用前向传导公式,得到 <math>\textstyle L_2, L_3, \ldots </math> 直到输出层 <math>\textstyle L_{n_l}</math> 的激活值。<br />
<li>对于第 <math>\textstyle n_l</math> 层(输出层)的每个输出单元 <math>\textstyle i</math>,我们根据以下公式计算残差:<br />
<br />
<br />
:<math><br />
\begin{align}<br />
\delta^{(n_l)}_i<br />
= \frac{\partial}{\partial z^{(n_l)}_i} \;\;<br />
\frac{1}{2} \left\|y - h_{W,b}(x)\right\|^2 = - (y_i - a^{(n_l)}_i) \cdot f'(z^{(n_l)}_i)<br />
\end{align}<br />
</math><br />
<br />
[译者注:<br />
:<math> <br />
\begin{align}<br />
\delta^{(n_l)}_i &= \frac{\partial}{\partial z^{n_l}_i}J(W,b;x,y)<br />
= \frac{\partial}{\partial z^{n_l}_i}\frac{1}{2} \left\|y - h_{W,b}(x)\right\|^2 \\<br />
&= \frac{\partial}{\partial z^{n_l}_i}\frac{1}{2} \sum_{j=1}^{S_{n_l}} (y_j-a_j^{(n_l)})^2<br />
= \frac{\partial}{\partial z^{n_l}_i}\frac{1}{2} \sum_{j=1}^{S_{n_l}} (y_j-f(z_j^{(n_l)}))^2 \\<br />
&= - (y_i - f(z_i^{(n_l)})) \cdot f'(z^{(n_l)}_i)<br />
= - (y_i - a^{(n_l)}_i) \cdot f'(z^{(n_l)}_i)<br />
\end{align}<br />
</math> <br />
]<br />
<br />
<li>对 <math>\textstyle l = n_l-1, n_l-2, n_l-3, \ldots, 2</math> 的各个层,第 <math>\textstyle l</math> 层的第 <math>\textstyle i</math> 个节点的残差计算方法如下:<br />
: <math> <br />
\delta^{(l)}_i = \left( \sum_{j=1}^{s_{l+1}} W^{(l)}_{ji} \delta^{(l+1)}_j \right) f'(z^{(l)}_i)<br />
</math> <br />
<br />
{译者注:<br />
:<math> <br />
\begin{align}<br />
\delta^{(n_l-1)}_i &=\frac{\partial}{\partial z^{n_l-1}_i}J(W,b;x,y)<br />
= \frac{\partial}{\partial z^{n_l-1}_i}\frac{1}{2} \left\|y - h_{W,b}(x)\right\|^2 <br />
= \frac{\partial}{\partial z^{n_l-1}_i}\frac{1}{2} \sum_{j=1}^{S_{n_l}}(y_j-a_j^{(n_l)})^2 \\<br />
&= \frac{1}{2} \sum_{j=1}^{S_{n_l}}\frac{\partial}{\partial z^{n_l-1}_i}(y_j-a_j^{(n_l)})^2<br />
= \frac{1}{2} \sum_{j=1}^{S_{n_l}}\frac{\partial}{\partial z^{n_l-1}_i}(y_j-f(z_j^{(n_l)}))^2 \\<br />
&= \sum_{j=1}^{S_{n_l}}-(y_j-f(z_j^{(n_l)})) \cdot \frac{\partial}{\partial z_i^{(n_l-1)}}f(z_j^{(n_l)})<br />
= \sum_{j=1}^{S_{n_l}}-(y_j-f(z_j^{(n_l)})) \cdot f'(z_j^{(n_l)}) \cdot \frac{\partial z_j^{(n_l)}}{\partial z_i^{(n_l-1)}} \\<br />
&= \sum_{j=1}^{S_{n_l}} \delta_j^{(n_l)} \cdot \frac{\partial z_j^{(n_l)}}{\partial z_i^{n_l-1}}<br />
= \sum_{j=1}^{S_{n_l}} \left(\delta_j^{(n_l)} \cdot \frac{\partial}{\partial z_i^{n_l-1}}\sum_{k=1}^{S_{n_l-1}}f(z_k^{n_l-1}) \cdot W_{jk}^{n_l-1}\right) \\<br />
&= \sum_{j=1}^{S_{n_l}} \delta_j^{(n_l)} \cdot W_{ji}^{n_l-1} \cdot f'(z_i^{n_l-1})<br />
= \left(\sum_{j=1}^{S_{n_l-1}}W_{ji}^{n_l-1}\delta_j^{(n_l)}\right)f'(z_i^{n_l-1})<br />
\end{align}<br />
</math> <br />
<br />
将上式中的<math>\textstyle n_l-1</math>与<math>\textstyle n_l</math>的关系替换为<math>\textstyle l</math>与<math>\textstyle l+1</math>的关系,就可以得到:<br />
: <math> <br />
\delta^{(l)}_i = \left( \sum_{j=1}^{s_{l+1}} W^{(l)}_{ji} \delta^{(l+1)}_j \right) f'(z^{(l)}_i)<br />
</math> <br />
以上逐次从后向前求导的过程即为“反向传导”的本意所在。<br />
<br />
]<br />
<br />
<br />
<br />
<li>计算我们需要的偏导数,计算方法如下:<br />
:<math> <br />
\begin{align}<br />
\frac{\partial}{\partial W_{ij}^{(l)}} J(W,b; x, y) &= a^{(l)}_j \delta_i^{(l+1)} \\<br />
\frac{\partial}{\partial b_{i}^{(l)}} J(W,b; x, y) &= \delta_i^{(l+1)}.<br />
\end{align}<br />
</math> <br />
</ol><br />
<br />
<br />
最后,我们用矩阵-向量表示法重写以上算法。我们使用“<math>\textstyle \bullet</math>” 表示向量乘积运算符(在Matlab或Octave里用“<tt>.*</tt>”表示,也称作阿达马乘积)。若 <math>\textstyle a = b \bullet c</math>,则 <math>\textstyle a_i = b_ic_i</math>。在上一个教程中我们扩展了 <math>\textstyle f(\cdot)</math> 的定义,使其包含向量运算,这里我们也对偏导数 <math>\textstyle f'(\cdot)</math> 也做了同样的处理(于是又有 <math> \textstyle f'([z_1, z_2, z_3]) = [f'(z_1), f'(z_2), f'(z_3)]</math> )。<br />
<br />
<br />
那么,反向传播算法可表示为以下几个步骤:<br />
<br />
<ol><br />
<li>进行前馈传导计算,利用前向传导公式,得到 <math>\textstyle L_2, L_3, \ldots</math>直到输出层 <math>\textstyle L_{n_l}</math> 的激活值。<br />
<br />
<li>对输出层(第 <math>\textstyle n_l</math> 层),计算:<br />
<br />
:<math> \begin{align}<br />
\delta^{(n_l)}<br />
= - (y - a^{(n_l)}) \bullet f'(z^{(n_l)})<br />
\end{align}</math> <br />
<br />
<li>对于 <math>\textstyle l = n_l-1, n_l-2, n_l-3, \ldots, 2</math> 的各层,计算:<br />
:<math> \begin{align}<br />
\delta^{(l)} = \left((W^{(l)})^T \delta^{(l+1)}\right) \bullet f'(z^{(l)})<br />
\end{align}</math> <br />
<br />
<li>计算最终需要的偏导数值:<br />
:<math> \begin{align}<br />
\nabla_{W^{(l)}} J(W,b;x,y) &= \delta^{(l+1)} (a^{(l)})^T, \\<br />
\nabla_{b^{(l)}} J(W,b;x,y) &= \delta^{(l+1)}.<br />
\end{align}</math> <br />
</ol><br />
<br />
<br />
'''实现中应注意:'''在以上的第2步和第3步中,我们需要为每一个 <math>\textstyle i</math> 值计算其 <math>\textstyle f'(z^{(l)}_i)</math>。假设 <math>\textstyle f(z)</math> 是sigmoid函数,并且我们已经在前向传导运算中得到了 <math>\textstyle a^{(l)}_i</math>。那么,使用我们早先推导出的 <math>\textstyle f'(z)</math>表达式,就可以计算得到 <math>\textstyle f'(z^{(l)}_i) = a^{(l)}_i (1- a^{(l)}_i)</math>。<br />
<br />
<br />
最后,我们将对梯度下降算法做个全面总结。在下面的伪代码中,<math>\textstyle \Delta W^{(l)}</math> 是一个与矩阵 <math>\textstyle W^{(l)}</math> 维度相同的矩阵,<math>\textstyle \Delta b^{(l)}</math> 是一个与 <math>\textstyle b^{(l)}</math> 维度相同的向量。注意这里“<math>\textstyle \Delta W^{(l)}</math>”是一个矩阵,而不是“<math>\textstyle \Delta</math> 与 <math>\textstyle W^{(l)}</math> 相乘”。下面,我们实现批量梯度下降法中的一次迭代:<br />
<br />
<br />
<ol><br />
<li>对于所有 <math>\textstyle l</math>,令 <math>\textstyle \Delta W^{(l)} := 0</math> , <math>\textstyle \Delta b^{(l)} := 0</math> (设置为全零矩阵或全零向量)<br />
<br />
<li>对于 <math>\textstyle i = 1</math> 到 <math>\textstyle m</math>,<br />
<br />
<ol type="a"><br />
<li>使用反向传播算法计算 <math>\textstyle \nabla_{W^{(l)}} J(W,b;x,y)</math> 和 <math>\textstyle \nabla_{b^{(l)}} J(W,b;x,y)</math>。<br />
<li>计算 <math>\textstyle \Delta W^{(l)} := \Delta W^{(l)} + \nabla_{W^{(l)}} J(W,b;x,y)</math>。<br />
<li>计算 <math>\textstyle \Delta b^{(l)} := \Delta b^{(l)} + \nabla_{b^{(l)}} J(W,b;x,y)</math>。 <br />
</ol><br />
<br />
<li>更新权重参数:<br />
:<math> \begin{align}<br />
W^{(l)} &= W^{(l)} - \alpha \left[ \left(\frac{1}{m} \Delta W^{(l)} \right) + \lambda W^{(l)}\right] \\<br />
b^{(l)} &= b^{(l)} - \alpha \left[\frac{1}{m} \Delta b^{(l)}\right]<br />
\end{align}</math> <br />
</ol><br />
<br />
现在,我们可以重复梯度下降法的迭代步骤来减小代价函数 <math>\textstyle J(W,b)</math> 的值,进而求解我们的神经网络。<br />
<br />
<br />
==中英文对照==<br />
<br />
:反向传播算法 Backpropagation Algorithm<br />
:(批量)梯度下降法 (batch) gradient descent<br />
:(整体)代价函数 (overall) cost function<br />
:方差 squared-error<br />
:均方差 average sum-of-squares error<br />
:规则化项 regularization term<br />
:权重衰减 weight decay<br />
:偏置项 bias terms<br />
:贝叶斯规则化方法 Bayesian regularization method<br />
:高斯先验概率 Gaussian prior<br />
:极大后验估计 MAP<br />
:极大似然估计 maximum likelihood estimation<br />
:激活函数 activation function<br />
:双曲正切函数 tanh function<br />
:非凸函数 non-convex function<br />
:隐藏层单元 hidden (layer) units<br />
:对称失效 symmetry breaking<br />
:学习速率 learning rate<br />
:前向传导 forward pass<br />
:假设值 hypothesis <br />
:残差 error term<br />
:加权平均值 weighted average <br />
:前馈传导 feedforward pass<br />
:阿达马乘积 Hadamard product<br />
:前向传播 forward propagation<br />
<br />
<br />
==中文译者==<br />
<br />
王方(fangkey@gmail.com),林锋(xlfg@yeah.net),许利杰(csxulijie@gmail.com)<br />
<br />
<br />
{{稀疏自编码器}}<br />
<br />
<br />
<br />
{{Languages|Backpropagation_Algorithm|English}}</div>
Kandeng
http://ufldl.stanford.edu/wiki/index.php/%E5%8F%AF%E8%A7%86%E5%8C%96%E8%87%AA%E7%BC%96%E7%A0%81%E5%99%A8%E8%AE%AD%E7%BB%83%E7%BB%93%E6%9E%9C
可视化自编码器训练结果
2013-05-07T15:50:48Z
<p>Kandeng: /* 中英文对照 */</p>
<hr />
<div>训练完(稀疏)自编码器,我们还想把这自编码器学到的函数可视化出来,好弄明白它到底学到了什么。我们以在10×10图像(即n=100)上训练自编码器为例。在该自编码器中,每个隐藏单元i对如下关于输入的函数进行计算:<br />
:<math>\begin{align}<br />
a^{(2)}_i = f\left(\sum_{j=1}^{100} W^{(1)}_{ij} x_j + b^{(1)}_i \right).<br />
\end{align}</math><br />
<!-- This is the activation function <math>\textstyle g(\cdot)</math> applied to an affine function of the input.!--><br />
<br />
我们将要可视化的函数,就是上面这个以2D图像为输入、并由隐藏单元i计算出来的函数。它是依赖于参数<math>\textstyle W^{(1)}_{ij}</math>的(暂时忽略偏置项<math>b_i</math>)。需要注意的是,<math>\textstyle a^{(2)}_i</math>可看作输入<math>\textstyle x</math>的非线性特征。不过还有个问题:什么样的输入图像<math>\textstyle x</math>可让<math>\textstyle a^{(2)}_i</math>得到最大程度的激励?(通俗一点说,隐藏单元<math>\textstyle i</math>要找个什么样的特征?)。这里我们必须给<math>\textstyle x</math>加约束,否则会得到平凡解。若假设输入有范数约束<math>\textstyle ||x||^2 = \sum_{i=1}^{100} x_i^2 \leq 1</math>,则可证(请读者自行推导)令隐藏单元<math>\textstyle i</math>得到最大激励的输入应由下面公式计算的像素<math>\textstyle x_j</math>给出(共需计算100个像素,j=1,…,100):<br />
:<math>\begin{align}<br />
x_j = \frac{W^{(1)}_{ij}}{\sqrt{\sum_{j=1}^{100} (W^{(1)}_{ij})^2}}.<br />
\end{align}</math><br />
<br />
当我们用上式算出各像素的值、把它们组成一幅图像、并将图像呈现在我们面前之时,隐藏单元<math>\textstyle i</math>所追寻特征的真正含义也渐渐明朗起来。<br />
<br />
假如我们训练的自编码器有100个隐藏单元,可视化结果就会包含100幅这样的图像——每个隐藏单元都对应一幅图像。审视这100幅图像,我们可以试着体会这些隐藏单元学出来的整体效果是什么样的。<br />
<br />
<br />
当我们对稀疏自编码器(100个隐藏单元,在10X10像素的输入上训练 )进行上述可视化处理之后,结果如下所示:<br />
<br />
[[Image:ExampleSparseAutoencoderWeights.png|thumb|400px|center]]<br />
<br />
上图的每个小方块都给出了一个(带有有界范数 的)输入图像<math>\textstyle x</math>,它可使这100个隐藏单元中的某一个获得最大激励。我们可以看到,不同的隐藏单元学会了在图像的不同位置和方向进行边缘检测。<br />
<br />
显而易见,这些特征对物体识别等计算机视觉任务是十分有用的。若将其用于其他输入域(如音频),该算法也可学到对这些输入域有用的表示或特征。<br />
<br />
<br />
==中英文对照==<br />
<br />
:可视化 Visualizing<br />
:自编码器 Autoencoder<br />
:隐藏单元 hidden unit<br />
:非线性特征 non-linear feature<br />
:激励 activate<br />
:平凡解 trivial answer<br />
:范数约束 norm constrained<br />
:稀疏自编码器 sparse autoencoder<br />
:有界范数 norm bounded<br />
:输入域 input domains<br />
<br />
==中文译者==<br />
<br />
王方(fangkey@gmail.com),胡伦(hulun499@gmail.com),谢宇(msforbus@sina.com),@小琳爱肉肉(新浪微博账号), 余凯(kai.yu.cool@gmail.com)<br />
<br />
<br />
{{稀疏自编码器}}<br />
<br />
<br />
<br />
{{Languages|Visualizing_a_Trained_Autoencoder|English}}</div>
Kandeng
http://ufldl.stanford.edu/wiki/index.php/%E5%8F%8D%E5%90%91%E4%BC%A0%E5%AF%BC%E7%AE%97%E6%B3%95
反向传导算法
2013-04-21T16:08:41Z
<p>Kandeng: </p>
<hr />
<div>假设我们有一个固定样本集 <math>\textstyle \{ (x^{(1)}, y^{(1)}), \ldots, (x^{(m)}, y^{(m)}) \}</math>,它包含 <math>\textstyle m</math> 个样例。我们可以用批量梯度下降法来求解神经网络。具体来讲,对于单个样例 <math>\textstyle (x,y)</math>,其代价函数为:<br />
<br />
:<math><br />
\begin{align}<br />
J(W,b; x,y) = \frac{1}{2} \left\| h_{W,b}(x) - y \right\|^2.<br />
\end{align}<br />
</math><br />
<br />
这是一个(二分之一的)方差代价函数。给定一个包含 <math>\textstyle m</math> 个样例的数据集,我们可以定义整体代价函数为:<br />
<br />
:<math> <br />
\begin{align}<br />
J(W,b)<br />
&= \left[ \frac{1}{m} \sum_{i=1}^m J(W,b;x^{(i)},y^{(i)}) \right]<br />
+ \frac{\lambda}{2} \sum_{l=1}^{n_l-1} \; \sum_{i=1}^{s_l} \; \sum_{j=1}^{s_{l+1}} \left( W^{(l)}_{ji} \right)^2<br />
\\<br />
&= \left[ \frac{1}{m} \sum_{i=1}^m \left( \frac{1}{2} \left\| h_{W,b}(x^{(i)}) - y^{(i)} \right\|^2 \right) \right]<br />
+ \frac{\lambda}{2} \sum_{l=1}^{n_l-1} \; \sum_{i=1}^{s_l} \; \sum_{j=1}^{s_{l+1}} \left( W^{(l)}_{ji} \right)^2<br />
\end{align}<br />
</math><br />
<br />
以上公式中的第一项 <math>\textstyle J(W,b)</math> 是一个均方差项。第二项是一个规则化项(也叫'''权重衰减项'''),其目的是减小权重的幅度,防止过度拟合。<br />
<br />
<br />
[注:通常权重衰减的计算并不使用偏置项 <math>\textstyle b^{(l)}_i</math>,比如我们在 <math>\textstyle J(W, b)</math> 的定义中就没有使用。一般来说,将偏置项包含在权重衰减项中只会对最终的神经网络产生很小的影响。如果你在斯坦福选修过CS229(机器学习)课程,或者在YouTube上看过课程视频,你会发现这个权重衰减实际上是课上提到的贝叶斯规则化方法的变种。在贝叶斯规则化方法中,我们将高斯先验概率引入到参数中计算MAP(极大后验)估计(而不是极大似然估计)。]<br />
<br />
<br />
'''权重衰减参数''' <math>\textstyle \lambda</math> 用于控制公式中两项的相对重要性。在此重申一下这两个复杂函数的含义:<math>\textstyle J(W,b;x,y)</math> 是针对单个样例计算得到的方差代价函数;<math>\textstyle J(W,b)</math> 是整体样本代价函数,它包含权重衰减项。<br />
<br />
<br />
以上的代价函数经常被用于分类和回归问题。在分类问题中,我们用 <math>\textstyle y = 0</math> 或 <math>\textstyle 1</math>,来代表两种类型的标签(回想一下,这是因为 sigmoid激活函数的值域为 <math>\textstyle [0,1]</math>;如果我们使用双曲正切型激活函数,那么应该选用 <math>\textstyle -1</math> 和 <math>\textstyle +1</math> 作为标签)。对于回归问题,我们首先要变换输出值域(译者注:也就是 <math>\textstyle y</math>),以保证其范围为 <math>\textstyle [0,1]</math> (同样地,如果我们使用双曲正切型激活函数,要使输出值域为 <math>\textstyle [-1,1]</math>)。<br />
<br />
<br />
我们的目标是针对参数 <math>\textstyle W</math> 和 <math>\textstyle b</math> 来求其函数 <math>\textstyle J(W,b)</math> 的最小值。为了求解神经网络,我们需要将每一个参数 <math>\textstyle W^{(l)}_{ij}</math> 和 <math>\textstyle b^{(l)}_i</math> 初始化为一个很小的、接近零的随机值(比如说,使用正态分布 <math>\textstyle {Normal}(0,\epsilon^2)</math> 生成的随机值,其中 <math>\textstyle \epsilon</math> 设置为 <math>\textstyle 0.01</math> ),之后对目标函数使用诸如批量梯度下降法的最优化算法。因为 <math>\textstyle J(W, b)</math> 是一个非凸函数,梯度下降法很可能会收敛到局部最优解;但是在实际应用中,梯度下降法通常能得到令人满意的结果。最后,需要再次强调的是,要将参数进行随机初始化,而不是全部置为 <math>\textstyle 0</math>。如果所有参数都用相同的值作为初始值,那么所有隐藏层单元最终会得到与输入值有关的、相同的函数(也就是说,对于所有 <math>\textstyle i</math>,<math>\textstyle W^{(1)}_{ij}</math>都会取相同的值,那么对于任何输入 <math>\textstyle x</math> 都会有:<math>\textstyle a^{(2)}_1 = a^{(2)}_2 = a^{(2)}_3 = \ldots</math> )。随机初始化的目的是使'''对称失效'''。<br />
<br />
<br />
梯度下降法中每一次迭代都按照如下公式对参数 <math>\textstyle W</math> 和<math>\textstyle b</math> 进行更新:<br />
<br />
:<math><br />
\begin{align}<br />
W_{ij}^{(l)} &= W_{ij}^{(l)} - \alpha \frac{\partial}{\partial W_{ij}^{(l)}} J(W,b) \\<br />
b_{i}^{(l)} &= b_{i}^{(l)} - \alpha \frac{\partial}{\partial b_{i}^{(l)}} J(W,b)<br />
\end{align}<br />
</math> <br />
<br />
其中 <math>\textstyle \alpha</math> 是学习速率。其中关键步骤是计算偏导数。我们现在来讲一下'''反向传播'''算法,它是计算偏导数的一种有效方法。<br />
<br />
<br />
我们首先来讲一下如何使用反向传播算法来计算 <math>\textstyle \frac{\partial}{\partial W_{ij}^{(l)}} J(W,b; x, y)</math> 和 <math>\textstyle \frac{\partial}{\partial b_{i}^{(l)}} J(W,b; x, y)</math>,这两项是单个样例 <math>\textstyle (x,y)</math> 的代价函数 <math>\textstyle J(W,b;x,y)</math> 的偏导数。一旦我们求出该偏导数,就可以推导出整体代价函数 <math>\textstyle J(W,b)</math> 的偏导数:<br />
<br />
<br />
:<math><br />
\begin{align}<br />
\frac{\partial}{\partial W_{ij}^{(l)}} J(W,b) &=<br />
\left[ \frac{1}{m} \sum_{i=1}^m \frac{\partial}{\partial W_{ij}^{(l)}} J(W,b; x^{(i)}, y^{(i)}) \right] + \lambda W_{ij}^{(l)} \\<br />
\frac{\partial}{\partial b_{i}^{(l)}} J(W,b) &=<br />
\frac{1}{m}\sum_{i=1}^m \frac{\partial}{\partial b_{i}^{(l)}} J(W,b; x^{(i)}, y^{(i)})<br />
\end{align}<br />
</math> <br />
<br />
以上两行公式稍有不同,第一行比第二行多出一项,是因为权重衰减是作用于 <math>\textstyle W</math> 而不是 <math>\textstyle b</math>。<br />
<br />
<br />
反向传播算法的思路如下:给定一个样例 <math>\textstyle (x,y)</math>,我们首先进行“前向传导”运算,计算出网络中所有的激活值,包括 <math>\textstyle h_{W,b}(x)</math> 的输出值。之后,针对第 <math>\textstyle l</math> 层的每一个节点 <math>\textstyle i</math>,我们计算出其“残差” <math>\textstyle \delta^{(l)}_i</math>,该残差表明了该节点对最终输出值的残差产生了多少影响。对于最终的输出节点,我们可以直接算出网络产生的激活值与实际值之间的差距,我们将这个差距定义为 <math>\textstyle \delta^{(n_l)}_i</math> (第 <math>\textstyle n_l</math> 层表示输出层)。对于隐藏单元我们如何处理呢?我们将基于节点(译者注:第 <math>\textstyle l+1</math> 层节点)残差的加权平均值计算 <math>\textstyle \delta^{(l)}_i</math>,这些节点以 <math>\textstyle a^{(l)}_i</math> 作为输入。下面将给出反向传导算法的细节:<br />
<br />
<br />
<ol><br />
<li>进行前馈传导计算,利用前向传导公式,得到 <math>\textstyle L_2, L_3, \ldots </math> 直到输出层 <math>\textstyle L_{n_l}</math> 的激活值。<br />
<li>对于第 <math>\textstyle n_l</math> 层(输出层)的每个输出单元 <math>\textstyle i</math>,我们根据以下公式计算残差:<br />
<br />
<br />
:<math><br />
\begin{align}<br />
\delta^{(n_l)}_i<br />
= \frac{\partial}{\partial z^{(n_l)}_i} \;\;<br />
\frac{1}{2} \left\|y - h_{W,b}(x)\right\|^2 = - (y_i - a^{(n_l)}_i) \cdot f'(z^{(n_l)}_i)<br />
\end{align}<br />
</math><br />
<br />
[译者注:<br />
:<math> <br />
\begin{align}<br />
\delta^{(n_l)}_i &= \frac{\partial}{\partial z^{n_l}_i}J(W,b;x,y)<br />
= \frac{\partial}{\partial z^{n_l}_i}\frac{1}{2} \left\|y - h_{W,b}(x)\right\|^2 \\<br />
&= \frac{\partial}{\partial z^{n_l}_i}\frac{1}{2} \sum_{j=1}^{S_{n_l}} (y_j-a_j^{(n_l)})^2<br />
= \frac{\partial}{\partial z^{n_l}_i}\frac{1}{2} \sum_{j=1}^{S_{n_l}} (y_j-f(z_j^{(n_l)}))^2 \\<br />
&= - (y_i - f(z_j^{(n_l)})) \cdot f'(z^{(n_l)}_i)<br />
= - (y_i - a^{(n_l)}_i) \cdot f'(z^{(n_l)}_i)<br />
\end{align}<br />
</math> <br />
]<br />
<br />
<li>对 <math>\textstyle l = n_l-1, n_l-2, n_l-3, \ldots, 2</math> 的各个层,第 <math>\textstyle l</math> 层的第 <math>\textstyle i</math> 个节点的残差计算方法如下:<br />
: <math> <br />
\delta^{(l)}_i = \left( \sum_{j=1}^{s_{l+1}} W^{(l)}_{ji} \delta^{(l+1)}_j \right) f'(z^{(l)}_i)<br />
</math> <br />
<br />
{译者注:<br />
:<math> <br />
\begin{align}<br />
\delta^{(n_l-1)}_i &=\frac{\partial}{\partial z^{n_l-1}_i}J(W,b;x,y)<br />
= \frac{\partial}{\partial z^{n_l-1}_i}\frac{1}{2} \left\|y - h_{W,b}(x)\right\|^2 <br />
= \frac{\partial}{\partial z^{n_l-1}_i}\frac{1}{2} \sum_{j=1}^{S_{n_l}}(y_j-a_j^{(n_l)})^2 \\<br />
&= \frac{1}{2} \sum_{j=1}^{S_{n_l}}\frac{\partial}{\partial z^{n_l-1}_i}(y_j-a_j^{(n_l)})^2<br />
= \frac{1}{2} \sum_{j=1}^{S_{n_l}}\frac{\partial}{\partial z^{n_l-1}_i}(y_j-f(z_j^{(n_l)}))^2 \\<br />
&= \sum_{j=1}^{S_{n_l}}-(y_j-f(z_j^{(n_l)})) \cdot \frac{\partial}{\partial z_i^{(n_l-1)}}f(z_j^{(n_l)})<br />
= \sum_{j=1}^{S_{n_l}}-(y_j-f(z_j^{(n_l)})) \cdot f'(z_j^{(n_l)}) \cdot \frac{\partial z_j^{(n_l)}}{\partial z_i^{(n_l-1)}} \\<br />
&= \sum_{j=1}^{S_{n_l}} \delta_j^{(n_l)} \cdot \frac{\partial z_j^{(n_l)}}{\partial z_i^{n_l-1}}<br />
= \sum_{j=1}^{S_{n_l}} \left(\delta_j^{(n_l)} \cdot \frac{\partial}{\partial z_i^{n_l-1}}\sum_{k=1}^{S_{n_l-1}}f(z_k^{n_l-1}) \cdot W_{jk}^{n_l-1}\right) \\<br />
&= \sum_{j=1}^{S_{n_l}} \delta_j^{(n_l)} \cdot W_{ji}^{n_l-1} \cdot f'(z_i^{n_l-1})<br />
= \left(\sum_{j=1}^{S_{n_l-1}}W_{ji}^{n_l-1}\delta_j^{(n_l)}\right)f'(z_i^{n_l-1})<br />
\end{align}<br />
</math> <br />
<br />
将上式中的<math>\textstyle n_l-1</math>与<math>\textstyle n_l</math>的关系替换为<math>\textstyle l</math>与<math>\textstyle l+1</math>的关系,就可以得到:<br />
: <math> <br />
\delta^{(l)}_i = \left( \sum_{j=1}^{s_{l+1}} W^{(l)}_{ji} \delta^{(l+1)}_j \right) f'(z^{(l)}_i)<br />
</math> <br />
以上逐次从后向前求导的过程即为“反向传导”的本意所在。<br />
<br />
]<br />
<br />
<br />
<br />
<li>计算我们需要的偏导数,计算方法如下:<br />
:<math> <br />
\begin{align}<br />
\frac{\partial}{\partial W_{ij}^{(l)}} J(W,b; x, y) &= a^{(l)}_j \delta_i^{(l+1)} \\<br />
\frac{\partial}{\partial b_{i}^{(l)}} J(W,b; x, y) &= \delta_i^{(l+1)}.<br />
\end{align}<br />
</math> <br />
</ol><br />
<br />
<br />
最后,我们用矩阵-向量表示法重写以上算法。我们使用“<math>\textstyle \bullet</math>” 表示向量乘积运算符(在Matlab或Octave里用“<tt>.*</tt>”表示,也称作阿达马乘积)。若 <math>\textstyle a = b \bullet c</math>,则 <math>\textstyle a_i = b_ic_i</math>。在上一个教程中我们扩展了 <math>\textstyle f(\cdot)</math> 的定义,使其包含向量运算,这里我们也对偏导数 <math>\textstyle f'(\cdot)</math> 也做了同样的处理(于是又有 <math> \textstyle f'([z_1, z_2, z_3]) = [f'(z_1), f'(z_2), f'(z_3)]</math> )。<br />
<br />
<br />
那么,反向传播算法可表示为以下几个步骤:<br />
<br />
<ol><br />
<li>进行前馈传导计算,利用前向传导公式,得到 <math>\textstyle L_2, L_3, \ldots</math>直到输出层 <math>\textstyle L_{n_l}</math> 的激活值。<br />
<br />
<li>对输出层(第 <math>\textstyle n_l</math> 层),计算:<br />
<br />
:<math> \begin{align}<br />
\delta^{(n_l)}<br />
= - (y - a^{(n_l)}) \bullet f'(z^{(n_l)})<br />
\end{align}</math> <br />
<br />
<li>对于 <math>\textstyle l = n_l-1, n_l-2, n_l-3, \ldots, 2</math> 的各层,计算:<br />
:<math> \begin{align}<br />
\delta^{(l)} = \left((W^{(l)})^T \delta^{(l+1)}\right) \bullet f'(z^{(l)})<br />
\end{align}</math> <br />
<br />
<li>计算最终需要的偏导数值:<br />
:<math> \begin{align}<br />
\nabla_{W^{(l)}} J(W,b;x,y) &= \delta^{(l+1)} (a^{(l)})^T, \\<br />
\nabla_{b^{(l)}} J(W,b;x,y) &= \delta^{(l+1)}.<br />
\end{align}</math> <br />
</ol><br />
<br />
<br />
'''实现中应注意:'''在以上的第2步和第3步中,我们需要为每一个 <math>\textstyle i</math> 值计算其 <math>\textstyle f'(z^{(l)}_i)</math>。假设 <math>\textstyle f(z)</math> 是sigmoid函数,并且我们已经在前向传导运算中得到了 <math>\textstyle a^{(l)}_i</math>。那么,使用我们早先推导出的 <math>\textstyle f'(z)</math>表达式,就可以计算得到 <math>\textstyle f'(z^{(l)}_i) = a^{(l)}_i (1- a^{(l)}_i)</math>。<br />
<br />
<br />
最后,我们将对梯度下降算法做个全面总结。在下面的伪代码中,<math>\textstyle \Delta W^{(l)}</math> 是一个与矩阵 <math>\textstyle W^{(l)}</math> 维度相同的矩阵,<math>\textstyle \Delta b^{(l)}</math> 是一个与 <math>\textstyle b^{(l)}</math> 维度相同的向量。注意这里“<math>\textstyle \Delta W^{(l)}</math>”是一个矩阵,而不是“<math>\textstyle \Delta</math> 与 <math>\textstyle W^{(l)}</math> 相乘”。下面,我们实现批量梯度下降法中的一次迭代:<br />
<br />
<br />
<ol><br />
<li>对于所有 <math>\textstyle l</math>,令 <math>\textstyle \Delta W^{(l)} := 0</math> , <math>\textstyle \Delta b^{(l)} := 0</math> (设置为全零矩阵或全零向量)<br />
<br />
<li>对于 <math>\textstyle i = 1</math> 到 <math>\textstyle m</math>,<br />
<br />
<ol type="a"><br />
<li>使用反向传播算法计算 <math>\textstyle \nabla_{W^{(l)}} J(W,b;x,y)</math> 和 <math>\textstyle \nabla_{b^{(l)}} J(W,b;x,y)</math>。<br />
<li>计算 <math>\textstyle \Delta W^{(l)} := \Delta W^{(l)} + \nabla_{W^{(l)}} J(W,b;x,y)</math>。<br />
<li>计算 <math>\textstyle \Delta b^{(l)} := \Delta b^{(l)} + \nabla_{b^{(l)}} J(W,b;x,y)</math>。 <br />
</ol><br />
<br />
<li>更新权重参数:<br />
:<math> \begin{align}<br />
W^{(l)} &= W^{(l)} - \alpha \left[ \left(\frac{1}{m} \Delta W^{(l)} \right) + \lambda W^{(l)}\right] \\<br />
b^{(l)} &= b^{(l)} - \alpha \left[\frac{1}{m} \Delta b^{(l)}\right]<br />
\end{align}</math> <br />
</ol><br />
<br />
现在,我们可以重复梯度下降法的迭代步骤来减小代价函数 <math>\textstyle J(W,b)</math> 的值,进而求解我们的神经网络。<br />
<br />
<br />
==中英文对照==<br />
<br />
:反向传播算法 Backpropagation Algorithm<br />
:(批量)梯度下降法 (batch) gradient descent<br />
:(整体)代价函数 (overall) cost function<br />
:方差 squared-error<br />
:均方差 average sum-of-squares error<br />
:规则化项 regularization term<br />
:权重衰减 weight decay<br />
:偏置项 bias terms<br />
:贝叶斯规则化方法 Bayesian regularization method<br />
:高斯先验概率 Gaussian prior<br />
:极大后验估计 MAP<br />
:极大似然估计 maximum likelihood estimation<br />
:激活函数 activation function<br />
:双曲正切函数 tanh function<br />
:非凸函数 non-convex function<br />
:隐藏层单元 hidden (layer) units<br />
:对称失效 symmetry breaking<br />
:学习速率 learning rate<br />
:前向传导 forward pass<br />
:假设值 hypothesis <br />
:残差 error term<br />
:加权平均值 weighted average <br />
:前馈传导 feedforward pass<br />
:阿达马乘积 Hadamard product<br />
:前向传播 forward propagation<br />
<br />
<br />
==中文译者==<br />
<br />
王方(fangkey@gmail.com),林锋(xlfg@yeah.net),许利杰(csxulijie@gmail.com)<br />
<br />
<br />
{{稀疏自编码器}}<br />
<br />
<br />
<br />
{{Languages|Backpropagation_Algorithm|English}}</div>
Kandeng
http://ufldl.stanford.edu/wiki/index.php/%E7%A8%80%E7%96%8F%E7%BC%96%E7%A0%81%E8%87%AA%E7%BC%96%E7%A0%81%E8%A1%A8%E8%BE%BE
稀疏编码自编码表达
2013-04-19T03:36:46Z
<p>Kandeng: /* 稀疏编码 */</p>
<hr />
<div>== 稀疏编码 ==<br />
<br />
<br />
在稀疏自编码算法中,我们试着学习得到一组权重参数 <math>W</math>(以及相应的截距 <math>b</math>),通过这些参数可以使我们得到稀疏特征向量 <math>\sigma(Wx + b)</math> ,这些特征向量对于重构输入样本非常有用。<br />
<br />
[[File:STL_SparseAE.png | 240px]]<br />
<br />
<br />
稀疏编码可以看作是稀疏自编码方法的一个变形,该方法试图直接学习数据的特征集。利用与此特征集相应的基向量,将学习得到的特征集从特征空间转换到样本数据空间,这样我们就可以用学习得到的特征集重构样本数据。 <br />
<br />
<br />
确切地说,在稀疏编码算法中,有样本数据 <math>x</math> 供我们进行特征学习。特别是,学习一个用于表示样本数据的稀疏特征集 <math>s</math>, 和一个将特征集从特征空间转换到样本数据空间的基向量 <math>A</math>, 我们可以构建如下目标函数:<br />
<br />
:<math><br />
J(A, s) = \lVert As - x \rVert_2^2 + \lambda \lVert s \rVert_1<br />
</math><br />
<br />
(<math>\lVert x \rVert_k</math>是x的Lk范数,等价于 <math>\left( \sum{ \left| x_i^k \right| } \right) ^{\frac{1}{k}}</math>。L2 范数即大家熟知的欧几里得范数,L1 范数是向量元素的绝对值之和)<br />
<br />
<br />
上式前第一部分是利用基向量将特征集重构为样本数据所产生的误差,第二部分为稀疏性惩罚项(sparsity penalty term),用于保证特征集的稀疏性。 <br />
<br />
<br />
但是,如目标函数所示,它的约束性并不强――按常数比例缩放<math>A</math>的同时再按这个常数的倒数缩放 <math>s</math>,结果不会改变误差大小,却会减少稀疏代价(表达式第二项)的值。因此,需要为 <math>A</math> 中每项 <math>A_j</math> 增加额外约束 <math>A_j^TA_j \le 1</math>。问题变为:<br />
<br />
:<math><br />
\begin{array}{rcl}<br />
{\rm minimize} & \lVert As - x \rVert_2^2 + \lambda \lVert s \rVert_1 \\<br />
{\rm s.t.} & A_j^TA_j \le 1 \; \forall j \\<br />
\end{array} <br />
</math><br />
<br />
<br />
遗憾的是,因为目标函数并不是一个凸函数,所以不能用梯度方法解决这个优化问题。但是,在给定 <math>A</math> 的情况下,最小化 <math>J(A, s)</math> 求解 <math>s</math> 是凸的。同理,给定 <math>s</math> 最小化 <math>J(A, s)</math> 求解 <math>A</math> 也是凸的。这表明,可以通过交替固定 <math>s</math >和 A 分别求解 <math>A</math>和<math>s</math>。实践表明,这一策略取得的效果非常好。 <br />
<br />
<br />
但是,以上表达式带来了另一个难题:不能用简单的梯度方法来实现约束条件 <math>A_j^TA_j \le 1 \; \forall j</math>。因此在实际问题中,此约束条件还不足以成为“权重衰变”("weight decay")项以保证 A 的每一项值够小。这样我们就得到一个新的目标函数: <br />
<br />
:<math><br />
J(A, s) = \lVert As - x \rVert_2^2 + \lambda \lVert s \rVert_1 + \gamma \lVert A \rVert_2^2<br />
</math><br />
<br />
(注意上式中第三项, <math>\lVert A \rVert_2^2</math>等价于<math>\sum_r{\sum_c{A_{rc}^2}}</math>,是A各项的平方和)<br />
<br />
<br />
这一目标函数带来了最后一个问题,即 L1 范数在 0 点处不可微影响了梯度方法的应用。尽管可以通过其他非梯度下降方法避开这一问题,但是本文通过使用近似值“平滑” L1 范数的方法解决此难题。使用 <math>\sqrt{x^2 + \epsilon}</math> 代替 <math>\left| x \right|</math>, 对 L1 范数进行平滑,其中 <math>\epsilon</math> 是“平滑参数”("smoothing parameter")或者“稀疏参数”("sparsity parameter") (如果 <math>\epsilon</math>远大于<math>x</math>, 则 <math>x + \epsilon</math> 的值由 <math>\epsilon</math> 主导,其平方根近似于 )。在下文提及拓扑稀疏编码时,“平滑”会派上用场。 <br />
<br />
<br />
因此,最终的目标函数是:<br />
<br />
:<math><br />
J(A, s) = \lVert As - x \rVert_2^2 + \lambda \sqrt{s^2 + \epsilon} + \gamma \lVert A \rVert_2^2<br />
</math><br />
<br />
( <math>\sqrt{s^2 + \epsilon}</math> 是 <math>\sum_k{\sqrt{s_k^2 + \epsilon}}</math> 的简写)<br />
<br />
<br />
该目标函数可以通过以下过程迭代优化: <br />
<br />
<ol><br />
<li>随机初始化<math>A</math><br />
<li>重复以下步骤直至收敛:<br />
<ol><br />
<li>根据上一步给定的<math>A</math>,求解能够最小化<math>J(A, s)</math>的<math>s</math><br />
<li>根据上一步得到的<math>s</math>,,求解能够最小化<math>J(A, s)</math>的<math>A</math> </ol><br />
</ol><br />
<br />
<br />
观察修改后的目标函数 <math>J(A, s)</math>,给定 <math>s</math> 的条件下,目标函数可以简化为 <math>J(A; s) = \lVert As - x \rVert_2^2 + \gamma \lVert A \rVert_2^2</math>(因为 <math>s</math> 的 L1 范式不是 <math>A</math> 的函数,所以可以忽略)。简化后的目标函数是一个关于 <math>A</math> 的简单二次项式,因此对 <math>A</math> 求导是很容易的。这种求导的一种快捷方法是矩阵微积分([[Useful Links | 相关链接]]部分列出了跟矩阵演算有关的内容)。遗憾的是,在给定 <math>A</math> 的条件下,目标函数却不具备这样的求导方法,因此目标函数的最小化步骤只能用梯度下降或其他类似的最优化方法。 <br />
<br />
<br />
理论上,通过上述迭代方法求解目标函数的最优化问题最终得到的特征集(A 的基向量)与通过稀疏自编码学习得到的特征集是差不多的。但是实际上,为了获得更好的算法收敛性需要使用一些小技巧,后面的[[ Sparse Coding: Autoencoder Interpretation#Sparse coding in practice | 稀疏编码实践]] 稀疏编码实践章节会详细介绍这些技巧。用梯度下降方法求解目标函数也略需技巧,另外使用矩阵演算或[[Deriving gradients using the backpropagation idea | 反向传播算法]]则有助于解决此类问题。<br />
<br />
== 拓扑稀疏编码 ==<br />
<br />
<br />
通过稀疏编码,我们能够得到一组用于表示样本数据的特征集。不过,让我们来找些灵感,我们希望学习得到一组有某种“秩序”的特征集。举个例子,视觉特征,如前面所提到的,大脑皮层 V1 区神经元能够按特定的方向对边缘进行检测,同时,这些神经元(在生理上)被组织成超柱(hypercolumns),在超柱中,相邻神经元以相似的方向对边缘进行检测,一个神经元检测水平边缘,其相邻神经元检测到的边缘就稍微偏离水平方向,沿着超柱,神经元就可以检测到与水平方向相差更大的边缘了。 <br />
<br />
<br />
受该例子的启发,我们希望学习到的特征也具有这样“拓扑秩序”的性质。这对于我们要学习的特征意味着什么呢?直观的讲,如果“相邻”的特征是“相似”的,就意味着如果某个特征被激活,那么与之相邻的特征也将随之被激活。 <br />
<br />
<br />
具体而言,假设我们(随意地)将特征组织成一个方阵。我们就希望矩阵中相邻的特征是相似的。实现这一点的方法是将相邻特征按经过平滑的L1范式惩罚进行分组,如果按 3x3 方阵分组,则用 <math>\sqrt{s_{1,1}^2 + s_{1,2}^2 + s_{1,3}^2 + s_{2,1}^2 + s_{2,2}^2 + s_{3,2}^2 + s_{3,1}^2 + s_{3,2}^2 + s_{3,3}^2 + \epsilon}</math> 代替 <math>\sqrt{s_{1,1}^2 + \epsilon}</math>, 其分组通常是重合的,因此从第 1 行第 1 列开始的 3x3 区域是一个分组,从第 1 行第 2 列开始的 3x3 区域是另一个分组,以此类推。最终,这样的分组会形成环绕,就好像这个矩阵是个环形曲面,所以每个特征都以同样的次数进行了分组。<br />
于是,将经过平滑的所有分组的 L1 惩罚值之和代替经过平滑的 L1 惩罚值,得到新的目标函数如下:<br />
<br />
:<math><br />
J(A, s) = \lVert As - x \rVert_2^2 + \lambda \sum_{\text{all groups } g}{\sqrt{ \left( \sum_{\text{all } s \in g}{s^2} \right) + \epsilon} } + \gamma \lVert A \rVert_2^2<br />
</math><br />
<br />
<br />
实际上,“分组”可以通过“分组矩阵”<math>V</math> 完成,于是矩阵 <math>V</math> 的第 <math>r</math> 行标识了哪些特征被分到第 <math>r</math> 组中,即如果第 <math>r</math> 组包含特征 <math>c</math> 则 <math>V_{r, c} = 1</math>。通过分组矩阵实现分组使得梯度的计算更加直观,使用此分组矩阵,目标函数被重写为: <br />
<br />
:<math><br />
J(A, s) = \lVert As - x \rVert_2^2 + \lambda \sum{ \sqrt{Vss^T + \epsilon} } + \gamma \lVert A \rVert_2^2<br />
</math><br />
<br />
(令 <math>D = \sqrt{Vss^T + \epsilon}</math>,<math>\sum{ \sqrt{Vss^T + \epsilon} }</math> 等价于 <math>\sum_r{ \sum_c { D_{r, c} } } </math>)<br />
<br />
<br />
该目标函数能够使用之前部分提到的迭代方法进行求解。拓扑稀疏编码得到的特征与稀疏编码得到的类似,只是拓扑稀疏编码得到的特征是以某种方式有“秩序”排列的。 <br />
<br />
<br />
== 稀疏编码实践 ==<br />
<br />
<br />
如上所述,虽然稀疏编码背后的理论十分简单,但是要写出准确无误的实现代码并能快速又恰到好处地收敛到最优值,则需要一定的技巧。 <br />
<br />
<br />
回顾一下之前提到的简单迭代算法:<br />
<br />
<ol><br />
<li>随机初始化<math>A</math><br />
<li>重复以下步骤直至收敛到最优值:<br />
<ol><br />
<li>根据上一步给定的<math>A</math>,求解能够最小化<math>J(A, s)</math>的<math>s</math> <br />
<li>根据上一步得到的<math>s</math>,求解能够最小化<math>J(A, s)</math>的<math>A</math> <br />
</ol><br />
</ol><br />
<br />
<br />
这样信手拈来地执行这个算法,结果并不会令人满意,即使确实得到了某些结果。以下是两种更快更优化的收敛技巧:<br />
<br />
<ol><br />
<li>将样本分批为“迷你块”<br />
<li>良好的<math>s</math>初始值<br />
</ol><br />
<br />
<br />
=== 将样本分批为“迷你块” ===<br />
<br />
<br />
如果你一次性在大规模数据集(比如,有10000 个patch)上执行简单的迭代算法,你会发现每次迭代都要花很长时间,也因此这算法要花好长时间才能达到收敛结果。为了提高收敛速度,可以选择在迷你块上运行该算法。每次迭代的时候,不是在所有的 10000 个 patchs 上执行该算法,而是使用迷你块,即从 10000 个 patch 中随机选出 2000 个 patch,再在这个迷你块上执行这个算法。这样就可以做到一石二鸟――第一,提高了每次迭代的速度,因为现在每次迭代只在 2000 个 patch 上执行而不是 10000个;第二,也是更重要的,它提高了收敛的速度(原因见[[TODO]])。<br />
<br />
<br />
=== 良好的<math>s</math>初始值 ===<br />
<br />
另一个能获得更快速更优化收敛的重要技巧是:在给定 <math>A</math> 的条件下,根据目标函数使用梯度下降(或其他方法)求解 <math>s</math> 之前找到良好的特征矩阵 <math>s</math> 的初始值。实际上,除非在优化 <math>A</math> 的最优值前已找到一个最佳矩阵 <math>s</math>,不然每次迭代过程中随机初始化 <math>s</math> 值会导致很差的收敛效果。下面给出一个初始化 <math>s</math> 的较好方法: <br />
<br />
<ol><br />
<li>令<math>s \leftarrow W^Tx</math> (<math>x</math> 是迷你块中patches的矩阵表示)<br />
<li><math>s</math>中的每个特征(<math>s</math>的每一列),除以其在<math>A</math>中对应基向量的范数。即,如果<math>s_{r, c}</math>表示第<math>c</math>个样本的第<math>r</math>个特征,则<math>A_c</math>表示<math>A</math>中的第<math>c</math>个基向量,则令<br />
<math>s_{r, c} \leftarrow \frac{ s_{r, c} } { \lVert A_c \rVert }.</math><br />
</ol><br />
<br />
<br />
无疑,这样的初始化有助于算法的改进,因为上述的第一步希望找到满足 <math>Ws \approx x</math> 的矩阵 <math>s</math>;第二步对 <math>s</math> 作规范化处理是为了保持较小的稀疏惩罚值。这也表明,只采用上述步骤的某一步而不是两步对 <math>s</math> 做初始化处理将严重影响算法性能。([[TODO]]: 此链接将会对为什么这样的初始化能改进算法作出更详细的解释)<br />
<br />
<br />
=== 可运行算法 ===<br />
<br />
有了以上两种技巧,稀疏编码算法修改如下: <br />
<br />
<ol><br />
<li>随机初始化<math>A</math><br />
<li>重复以下步骤直至收敛<br />
<ol><br />
<li>随机选取一个有2000个patches的迷你块 <br />
<li>如上所述,初始化<math>s</math><br />
<li>根据上一步给定的<math>A</math>,求解能够最小化<math>J(A, s)</math>的<math>s</math><br />
<li>根据上一步得到的<math>s</math>,求解能够最小化<math>J(A, s)</math>的<math>A</math> <br />
</ol><br />
</ol><br />
<br />
通过上述方法,可以相对快速的得到局部最优解。<br />
<br />
<br />
<br />
==中英文对照==<br />
<br />
:稀疏编码 sparse coding<br />
:自编码 autoencoder<br />
:目标函数 objective function<br />
:稀疏代价 sparsity cost<br />
:反向传播 backpropagation <br />
:基于梯度的 gradient-based<br />
:非凸的 non-convex<br />
:权重衰变 weight decay<br />
:拓扑稀疏编码 topographic sparse coding<br />
:拓扑秩序 topographically ordered<br />
:平滑的一范数惩罚 smoothed L1 penalty<br />
:迷你块 mini-batches<br />
:收敛速度 the rate of convergence<br />
:梯度下降 gradient descent<br />
:局部最优解 local optima<br />
<br />
<br />
<br />
==中文译者==<br />
<br />
许超(xuchaowill@gmail.com), 张睿卿(zrqjennifer@gmail.com), 林锋(xlfg@yeah.net)<br />
<br />
<br />
{{Sparse_Autoencoder}}<br />
<br />
<br />
{{Languages|Sparse_Coding:_Autoencoder_Interpretation|English}}</div>
Kandeng
http://ufldl.stanford.edu/wiki/index.php/%E5%8F%8D%E5%90%91%E4%BC%A0%E5%AF%BC%E7%AE%97%E6%B3%95
反向传导算法
2013-04-18T08:22:15Z
<p>Kandeng: </p>
<hr />
<div>假设我们有一个固定样本集 <math>\textstyle \{ (x^{(1)}, y^{(1)}), \ldots, (x^{(m)}, y^{(m)}) \}</math>,它包含 <math>\textstyle m</math> 个样例。我们可以用批量梯度下降法来求解神经网络。具体来讲,对于单个样例 <math>\textstyle (x,y)</math>,其代价函数为:<br />
<br />
:<math><br />
\begin{align}<br />
J(W,b; x,y) = \frac{1}{2} \left\| h_{W,b}(x) - y \right\|^2.<br />
\end{align}<br />
</math><br />
<br />
这是一个(二分之一的)方差代价函数。给定一个包含 <math>\textstyle m</math> 个样例的数据集,我们可以定义整体代价函数为:<br />
<br />
:<math> <br />
\begin{align}<br />
J(W,b)<br />
&= \left[ \frac{1}{m} \sum_{i=1}^m J(W,b;x^{(i)},y^{(i)}) \right]<br />
+ \frac{\lambda}{2} \sum_{l=1}^{n_l-1} \; \sum_{i=1}^{s_l} \; \sum_{j=1}^{s_{l+1}} \left( W^{(l)}_{ji} \right)^2<br />
\\<br />
&= \left[ \frac{1}{m} \sum_{i=1}^m \left( \frac{1}{2} \left\| h_{W,b}(x^{(i)}) - y^{(i)} \right\|^2 \right) \right]<br />
+ \frac{\lambda}{2} \sum_{l=1}^{n_l-1} \; \sum_{i=1}^{s_l} \; \sum_{j=1}^{s_{l+1}} \left( W^{(l)}_{ji} \right)^2<br />
\end{align}<br />
</math><br />
<br />
以上公式中的第一项 <math>\textstyle J(W,b)</math> 是一个均方差项。第二项是一个规则化项(也叫'''权重衰减项'''),其目的是减小权重的幅度,防止过度拟合。<br />
<br />
<br />
[注:通常权重衰减的计算并不使用偏置项 <math>\textstyle b^{(l)}_i</math>,比如我们在 <math>\textstyle J(W, b)</math> 的定义中就没有使用。一般来说,将偏置项包含在权重衰减项中只会对最终的神经网络产生很小的影响。如果你在斯坦福选修过CS229(机器学习)课程,或者在YouTube上看过课程视频,你会发现这个权重衰减实际上是课上提到的贝叶斯规则化方法的变种。在贝叶斯规则化方法中,我们将高斯先验概率引入到参数中计算MAP(极大后验)估计(而不是极大似然估计)。]<br />
<br />
<br />
'''权重衰减参数''' <math>\textstyle \lambda</math> 用于控制公式中两项的相对重要性。在此重申一下这两个复杂函数的含义:<math>\textstyle J(W,b;x,y)</math> 是针对单个样例计算得到的方差代价函数;<math>\textstyle J(W,b)</math> 是整体样本代价函数,它包含权重衰减项。<br />
<br />
<br />
以上的代价函数经常被用于分类和回归问题。在分类问题中,我们用 <math>\textstyle y = 0</math> 或 <math>\textstyle 1</math>,来代表两种类型的标签(回想一下,这是因为 sigmoid激活函数的值域为 <math>\textstyle [0,1]</math>;如果我们使用双曲正切型激活函数,那么应该选用 <math>\textstyle -1</math> 和 <math>\textstyle +1</math> 作为标签)。对于回归问题,我们首先要变换输出值域(译者注:也就是 <math>\textstyle y</math>),以保证其范围为 <math>\textstyle [0,1]</math> (同样地,如果我们使用双曲正切型激活函数,要使输出值域为 <math>\textstyle [-1,1]</math>)。<br />
<br />
<br />
我们的目标是针对参数 <math>\textstyle W</math> 和 <math>\textstyle b</math> 来求其函数 <math>\textstyle J(W,b)</math> 的最小值。为了求解神经网络,我们需要将每一个参数 <math>\textstyle W^{(l)}_{ij}</math> 和 <math>\textstyle b^{(l)}_i</math> 初始化为一个很小的、接近零的随机值(比如说,使用正态分布 <math>\textstyle {Normal}(0,\epsilon^2)</math> 生成的随机值,其中 <math>\textstyle \epsilon</math> 设置为 <math>\textstyle 0.01</math> ),之后对目标函数使用诸如批量梯度下降法的最优化算法。因为 <math>\textstyle J(W, b)</math> 是一个非凸函数,梯度下降法很可能会收敛到局部最优解;但是在实际应用中,梯度下降法通常能得到令人满意的结果。最后,需要再次强调的是,要将参数进行随机初始化,而不是全部置为 <math>\textstyle 0</math>。如果所有参数都用相同的值作为初始值,那么所有隐藏层单元最终会得到与输入值有关的、相同的函数(也就是说,对于所有 <math>\textstyle i</math>,<math>\textstyle W^{(1)}_{ij}</math>都会取相同的值,那么对于任何输入 <math>\textstyle x</math> 都会有:<math>\textstyle a^{(2)}_1 = a^{(2)}_2 = a^{(2)}_3 = \ldots</math> )。随机初始化的目的是使'''对称失效'''。<br />
<br />
<br />
梯度下降法中每一次迭代都按照如下公式对参数 <math>\textstyle W</math> 和<math>\textstyle b</math> 进行更新:<br />
<br />
:<math><br />
\begin{align}<br />
W_{ij}^{(l)} &= W_{ij}^{(l)} - \alpha \frac{\partial}{\partial W_{ij}^{(l)}} J(W,b) \\<br />
b_{i}^{(l)} &= b_{i}^{(l)} - \alpha \frac{\partial}{\partial b_{i}^{(l)}} J(W,b)<br />
\end{align}<br />
</math> <br />
<br />
其中 <math>\textstyle \alpha</math> 是学习速率。其中关键步骤是计算偏导数。我们现在来讲一下'''反向传播'''算法,它是计算偏导数的一种有效方法。<br />
<br />
<br />
我们首先来讲一下如何使用反向传播算法来计算 <math>\textstyle \frac{\partial}{\partial W_{ij}^{(l)}} J(W,b; x, y)</math> 和 <math>\textstyle \frac{\partial}{\partial b_{i}^{(l)}} J(W,b; x, y)</math>,这两项是单个样例 <math>\textstyle (x,y)</math> 的代价函数 <math>\textstyle J(W,b;x,y)</math> 的偏导数。一旦我们求出该偏导数,就可以推导出整体代价函数 <math>\textstyle J(W,b)</math> 的偏导数:<br />
<br />
<br />
:<math><br />
\begin{align}<br />
\frac{\partial}{\partial W_{ij}^{(l)}} J(W,b) &=<br />
\left[ \frac{1}{m} \sum_{i=1}^m \frac{\partial}{\partial W_{ij}^{(l)}} J(W,b; x^{(i)}, y^{(i)}) \right] + \lambda W_{ij}^{(l)} \\<br />
\frac{\partial}{\partial b_{i}^{(l)}} J(W,b) &=<br />
\frac{1}{m}\sum_{i=1}^m \frac{\partial}{\partial b_{i}^{(l)}} J(W,b; x^{(i)}, y^{(i)})<br />
\end{align}<br />
</math> <br />
<br />
以上两行公式稍有不同,第一行比第二行多出一项,是因为权重衰减是作用于 <math>\textstyle W</math> 而不是 <math>\textstyle b</math>。<br />
<br />
<br />
反向传播算法的思路如下:给定一个样例 <math>\textstyle (x,y)</math>,我们首先进行“前向传导”运算,计算出网络中所有的激活值,包括 <math>\textstyle h_{W,b}(x)</math> 的输出值。之后,针对第 <math>\textstyle l</math> 层的每一个节点 <math>\textstyle i</math>,我们计算出其“残差” <math>\textstyle \delta^{(l)}_i</math>,该残差表明了该节点对最终输出值的残差产生了多少影响。对于最终的输出节点,我们可以直接算出网络产生的激活值与实际值之间的差距,我们将这个差距定义为 <math>\textstyle \delta^{(n_l)}_i</math> (第 <math>\textstyle n_l</math> 层表示输出层)。对于隐藏单元我们如何处理呢?我们将基于节点(译者注:第 <math>\textstyle l+1</math> 层节点)残差的加权平均值计算 <math>\textstyle \delta^{(l)}_i</math>,这些节点以 <math>\textstyle a^{(l)}_i</math> 作为输入。下面将给出反向传导算法的细节:<br />
<br />
<br />
<ol><br />
<li>进行前馈传导计算,利用前向传导公式,得到 <math>\textstyle L_2, L_3, \ldots </math> 直到输出层 <math>\textstyle L_{n_l}</math> 的激活值。<br />
<li>对于第 <math>\textstyle n_l</math> 层(输出层)的每个输出单元 <math>\textstyle i</math>,我们根据以下公式计算残差:<br />
<br />
<br />
:<math><br />
\begin{align}<br />
\delta^{(n_l)}_i<br />
= \frac{\partial}{\partial z^{(n_l)}_i} \;\;<br />
\frac{1}{2} \left\|y - h_{W,b}(x)\right\|^2 = - (y_i - a^{(n_l)}_i) \cdot f'(z^{(n_l)}_i)<br />
\end{align}<br />
</math><br />
<br />
[译者注:<br />
:<math> <br />
\begin{align}<br />
\delta^{(n_l)}_i &= \frac{\partial}{\partial z^{n_l}_i}J(W,b;x,y)<br />
= \frac{\partial}{\partial z^{n_l}_i}\frac{1}{2} \left\|y - h_{W,b}(x)\right\|^2 \\<br />
&= \frac{\partial}{\partial z^{n_l}_i}\frac{1}{2} \sum_{j=1}^{S_{n_l}} (y_j-a_j^{(n_l)})^2<br />
= \frac{\partial}{\partial z^{n_l}_i}\frac{1}{2} \sum_{j=1}^{S_{n_l}} (y_j-f(z_j^{(n_l)}))^2 \\<br />
&= - (y_i - f(z_j^{(n_l)})) \cdot f'(z^{(n_l)}_i)<br />
= - (y_i - a^{(n_l)}_i) \cdot f'(z^{(n_l)}_i)<br />
\end{align}<br />
</math> <br />
]<br />
<br />
<li>对 <math>\textstyle l = n_l-1, n_l-2, n_l-3, \ldots, 2</math> 的各个层,第 <math>\textstyle l</math> 层的第 <math>\textstyle i</math> 个节点的残差计算方法如下:<br />
: <math> <br />
\delta^{(l)}_i = \left( \sum_{j=1}^{s_{l+1}} W^{(l)}_{ji} \delta^{(l+1)}_j \right) f'(z^{(l)}_i)<br />
</math> <br />
<br />
{译者注:<br />
:<math> <br />
\begin{align}<br />
\delta^{(n_l-1)}_i &=\frac{\partial}{\partial z^{n_l-1}_i}J(W,b;x,y)<br />
= \frac{\partial}{\partial z^{n_l-1}_i}\frac{1}{2} \left\|y - h_{W,b}(x)\right\|^2 <br />
= \frac{\partial}{\partial z^{n_l-1}_i}\frac{1}{2} \sum_{j=1}^{S_{n_l}}(y_j-a_j^{(n_l)})^2 \\<br />
&= \frac{1}{2} \sum_{j=1}^{S_{n_l}}\frac{\partial}{\partial z^{n_l-1}_i}(y_j-a_j^{(n_l)})^2<br />
= \frac{1}{2} \sum_{j=1}^{S_{n_l}}\frac{\partial}{\partial z^{n_l-1}_i}(y_j-f(z_j^{(n_l)}))^2 \\<br />
&= \sum_{j=1}^{S_{n_l}}-(y_j-f(z_j^{(n_l)})) \cdot \frac{\partial}{\partial z_i^{(n_l-1)}}f(z_j^{(n_l)})<br />
= \sum_{j=1}^{S_{n_l}}-(y_j-f(z_j^{(n_l)})) \cdot f'(z_j^{(n_l)}) \cdot \frac{\partial z_j^{(n_l)}}{\partial z_i^{(n_l-1)}} \\<br />
&= \sum_{j=1}^{S_{n_l}} \delta_j^{(n_l)} \cdot \frac{\partial z_j^{(n_l)}}{z_i^{n_l-1}}<br />
= \sum_{j=1}^{S_{n_l}} \left(\delta_j^{(n_l)} \cdot \frac{\partial}{\partial z_i^{n_l-1}}\sum_{k=1}^{S_{n_l-1}}f(z_k^{n_l-1}) \cdot W_{jk}^{n_l-1}\right) \\<br />
&= \sum_{j=1}^{S_{n_l}} \delta_j^{(n_l)} \cdot W_{ji}^{n_l-1} \cdot f'(z_i^{n_l-1})<br />
= \left(\sum_{j=1}^{S_{n_l-1}}W_{ji}^{n_l-1}\delta_j^{(n_l)}\right)f'(z_i^{n_l-1})<br />
\end{align}<br />
</math> <br />
<br />
将上式中的<math>\textstyle n_l-1</math>与<math>\textstyle n_l</math>的关系替换为<math>\textstyle l</math>与<math>\textstyle l+1</math>的关系,就可以得到:<br />
: <math> <br />
\delta^{(l)}_i = \left( \sum_{j=1}^{s_{l+1}} W^{(l)}_{ji} \delta^{(l+1)}_j \right) f'(z^{(l)}_i)<br />
</math> <br />
以上逐次从后向前求导的过程即为“反向传导”的本意所在。<br />
<br />
]<br />
<br />
<br />
<br />
<li>计算我们需要的偏导数,计算方法如下:<br />
:<math> <br />
\begin{align}<br />
\frac{\partial}{\partial W_{ij}^{(l)}} J(W,b; x, y) &= a^{(l)}_j \delta_i^{(l+1)} \\<br />
\frac{\partial}{\partial b_{i}^{(l)}} J(W,b; x, y) &= \delta_i^{(l+1)}.<br />
\end{align}<br />
</math> <br />
</ol><br />
<br />
<br />
最后,我们用矩阵-向量表示法重写以上算法。我们使用“<math>\textstyle \bullet</math>” 表示向量乘积运算符(在Matlab或Octave里用“<tt>.*</tt>”表示,也称作阿达马乘积)。若 <math>\textstyle a = b \bullet c</math>,则 <math>\textstyle a_i = b_ic_i</math>。在上一个教程中我们扩展了 <math>\textstyle f(\cdot)</math> 的定义,使其包含向量运算,这里我们也对偏导数 <math>\textstyle f'(\cdot)</math> 也做了同样的处理(于是又有 <math> \textstyle f'([z_1, z_2, z_3]) = [f'(z_1), f'(z_2), f'(z_3)]</math> )。<br />
<br />
<br />
那么,反向传播算法可表示为以下几个步骤:<br />
<br />
<ol><br />
<li>进行前馈传导计算,利用前向传导公式,得到 <math>\textstyle L_2, L_3, \ldots</math>直到输出层 <math>\textstyle L_{n_l}</math> 的激活值。<br />
<br />
<li>对输出层(第 <math>\textstyle n_l</math> 层),计算:<br />
<br />
:<math> \begin{align}<br />
\delta^{(n_l)}<br />
= - (y - a^{(n_l)}) \bullet f'(z^{(n_l)})<br />
\end{align}</math> <br />
<br />
<li>对于 <math>\textstyle l = n_l-1, n_l-2, n_l-3, \ldots, 2</math> 的各层,计算:<br />
:<math> \begin{align}<br />
\delta^{(l)} = \left((W^{(l)})^T \delta^{(l+1)}\right) \bullet f'(z^{(l)})<br />
\end{align}</math> <br />
<br />
<li>计算最终需要的偏导数值:<br />
:<math> \begin{align}<br />
\nabla_{W^{(l)}} J(W,b;x,y) &= \delta^{(l+1)} (a^{(l)})^T, \\<br />
\nabla_{b^{(l)}} J(W,b;x,y) &= \delta^{(l+1)}.<br />
\end{align}</math> <br />
</ol><br />
<br />
<br />
'''实现中应注意:'''在以上的第2步和第3步中,我们需要为每一个 <math>\textstyle i</math> 值计算其 <math>\textstyle f'(z^{(l)}_i)</math>。假设 <math>\textstyle f(z)</math> 是sigmoid函数,并且我们已经在前向传导运算中得到了 <math>\textstyle a^{(l)}_i</math>。那么,使用我们早先推导出的 <math>\textstyle f'(z)</math>表达式,就可以计算得到 <math>\textstyle f'(z^{(l)}_i) = a^{(l)}_i (1- a^{(l)}_i)</math>。<br />
<br />
<br />
最后,我们将对梯度下降算法做个全面总结。在下面的伪代码中,<math>\textstyle \Delta W^{(l)}</math> 是一个与矩阵 <math>\textstyle W^{(l)}</math> 维度相同的矩阵,<math>\textstyle \Delta b^{(l)}</math> 是一个与 <math>\textstyle b^{(l)}</math> 维度相同的向量。注意这里“<math>\textstyle \Delta W^{(l)}</math>”是一个矩阵,而不是“<math>\textstyle \Delta</math> 与 <math>\textstyle W^{(l)}</math> 相乘”。下面,我们实现批量梯度下降法中的一次迭代:<br />
<br />
<br />
<ol><br />
<li>对于所有 <math>\textstyle l</math>,令 <math>\textstyle \Delta W^{(l)} := 0</math> , <math>\textstyle \Delta b^{(l)} := 0</math> (设置为全零矩阵或全零向量)<br />
<br />
<li>对于 <math>\textstyle i = 1</math> 到 <math>\textstyle m</math>,<br />
<br />
<ol type="a"><br />
<li>使用反向传播算法计算 <math>\textstyle \nabla_{W^{(l)}} J(W,b;x,y)</math> 和 <math>\textstyle \nabla_{b^{(l)}} J(W,b;x,y)</math>。<br />
<li>计算 <math>\textstyle \Delta W^{(l)} := \Delta W^{(l)} + \nabla_{W^{(l)}} J(W,b;x,y)</math>。<br />
<li>计算 <math>\textstyle \Delta b^{(l)} := \Delta b^{(l)} + \nabla_{b^{(l)}} J(W,b;x,y)</math>。 <br />
</ol><br />
<br />
<li>更新权重参数:<br />
:<math> \begin{align}<br />
W^{(l)} &= W^{(l)} - \alpha \left[ \left(\frac{1}{m} \Delta W^{(l)} \right) + \lambda W^{(l)}\right] \\<br />
b^{(l)} &= b^{(l)} - \alpha \left[\frac{1}{m} \Delta b^{(l)}\right]<br />
\end{align}</math> <br />
</ol><br />
<br />
现在,我们可以重复梯度下降法的迭代步骤来减小代价函数 <math>\textstyle J(W,b)</math> 的值,进而求解我们的神经网络。<br />
<br />
<br />
==中英文对照==<br />
<br />
:反向传播算法 Backpropagation Algorithm<br />
:(批量)梯度下降法 (batch) gradient descent<br />
:(整体)代价函数 (overall) cost function<br />
:方差 squared-error<br />
:均方差 average sum-of-squares error<br />
:规则化项 regularization term<br />
:权重衰减 weight decay<br />
:偏置项 bias terms<br />
:贝叶斯规则化方法 Bayesian regularization method<br />
:高斯先验概率 Gaussian prior<br />
:极大后验估计 MAP<br />
:极大似然估计 maximum likelihood estimation<br />
:激活函数 activation function<br />
:双曲正切函数 tanh function<br />
:非凸函数 non-convex function<br />
:隐藏层单元 hidden (layer) units<br />
:对称失效 symmetry breaking<br />
:学习速率 learning rate<br />
:前向传导 forward pass<br />
:假设值 hypothesis <br />
:残差 error term<br />
:加权平均值 weighted average <br />
:前馈传导 feedforward pass<br />
:阿达马乘积 Hadamard product<br />
:前向传播 forward propagation<br />
<br />
<br />
==中文译者==<br />
<br />
王方(fangkey@gmail.com),林锋(xlfg@yeah.net),许利杰(csxulijie@gmail.com)<br />
<br />
<br />
{{稀疏自编码器}}<br />
<br />
<br />
<br />
{{Languages|Backpropagation_Algorithm|English}}</div>
Kandeng
http://ufldl.stanford.edu/wiki/index.php/%E6%B7%B1%E5%BA%A6%E7%BD%91%E7%BB%9C%E6%A6%82%E8%A7%88
深度网络概览
2013-04-17T14:30:30Z
<p>Kandeng: /* 局部极值问题 */</p>
<hr />
<div>==概述==<br />
<br />
在之前的章节中,你已经构建了一个包括输入层、隐藏层以及输出层的三层神经网络。虽然该网络对于MNIST手写数字数据库非常有效,但是它还是一个非常“浅”的网络。这里的“浅”指的是特征(隐藏层的激活值 <math>\textstyle {a}^{(2)}</math>)只使用一层计算单元(隐藏层)来得到的。<br />
<br />
<br />
在本节中,我们开始讨论深度神经网络,即含有多个隐藏层的神经网络。通过引入深度网络,我们可以计算更多复杂的输入特征。因为每一个隐藏层可以对上一层的输出进行非线性变换,因此深度神经网络拥有比“浅层”网络更加优异的表达能力(例如可以学习到更加复杂的函数关系)。<br />
<br />
<br />
值得注意的是当训练深度网络的时候,每一层隐层应该使用非线性的激活函数 <math>\textstyle f(x)</math>。这是因为多层的线性函数组合在一起本质上也只有线性函数的表达能力(例如,将多个线性方程组合在一起仅仅产生另一个线性方程)。因此,在激活函数是线性的情况下,相比于单隐藏层神经网络,包含多隐藏层的深度网络并没有增加表达能力。<br />
<br />
<br />
==深度网络的优势==<br />
<br />
为什么我们要使用深度网络呢?使用深度网络最主要的优势在于,它能以更加紧凑简洁的方式来表达比浅层网络大得多的函数集合。正式点说,我们可以找到一些函数,这些函数可以用 <math>\textstyle k</math> 层网络简洁地表达出来(这里的简洁是指隐层单元的数目只需与输入单元数目呈多项式关系)。但是对于一个只有 <math>\textstyle k-1 </math> 层的网络而言,除非它使用与输入单元数目呈指数关系的隐层单元数目,否则不能简洁表达这些函数。<br />
<br />
<br />
举一个简单的例子,比如我们打算构建一个布尔网络来计算 <math>\textstyle n</math> 个输入比特的奇偶校验码(或者进行异或运算)。假设网络中的每一个节点都可以进行逻辑“或”运算(或者“与非”运算),亦或者逻辑“与”运算。如果我们拥有一个仅仅由一个输入层、一个隐层以及一个输出层构成的网络,那么该奇偶校验函数所需要的节点数目与输入层的规模 <math>\textstyle n</math> 呈指数关系。但是,如果我们构建一个更深点的网络,那么这个网络的规模就可做到仅仅是 <math>\textstyle n</math> 的多项式函数。<br />
<br />
<br />
当处理对象是图像时,我们能够使用深度网络学习到“部分-整体”的分解关系。例如,第一层可以学习如何将图像中的像素组合在一起来检测边缘(正如我们在前面的练习中做的那样)。第二层可以将边缘组合起来检测更长的轮廓或者简单的“目标的部件”。在更深的层次上,可以将这些轮廓进一步组合起来以检测更为复杂的特征。<br />
<br />
<br />
最后要提的一点是,大脑皮层同样是分多层进行计算的。例如视觉图像在人脑中是分多个阶段进行处理的,首先是进入大脑皮层的“V1”区,然后紧跟着进入大脑皮层“V2”区,以此类推。<br />
<br />
<br />
==训练深度网络的困难==<br />
<br />
虽然几十年前人们就发现了深度网络在理论上的简洁性和较强的表达能力,但是直到最近,研究者们也没有在训练深度网络方面取得多少进步。<br />
问题原因在于研究者们主要使用的学习算法是:首先随机初始化深度网络的权重,然后使用有监督的目标函数在有标签的训练集 <math>\textstyle \left\{ \left( x_{l}^{\left( 1 \right)},{{y}^{\left( 1 \right)}} \right),...,\left( x_{l}^{\left( {{m}_{l}} \right)},{{y}^{\left( {{m}_{l}} \right)}} \right) \right\}</math> 上进行训练。例如通过使用梯度下降法来降低训练误差。然而,这种方法通常不是十分奏效。这其中有如下几方面原因:<br />
<br />
<br />
===数据获取问题===<br />
<br />
使用上面提到的方法,我们需要依赖于有标签的数据才能进行训练。然而有标签的数据通常是稀缺的,因此对于许多问题,我们很难获得足够多的样本来拟合一个复杂模型的参数。例如,考虑到深度网络具有强大的表达能力,在不充足的数据上进行训练将会导致过拟合。<br />
<br />
<br />
===局部极值问题===<br />
<br />
使用监督学习方法来对浅层网络(只有一个隐藏层)进行训练通常能够使参数收敛到合理的范围内。但是当用这种方法来训练深度网络的时候,并不能取得很好的效果。特别的,使用监督学习方法训练神经网络时,通常会涉及到求解一个高度非凸的优化问题(例如最小化训练误差 <math>\textstyle \sum\nolimits_{i}{||{{h}_{W}}\left( {{x}^{\left( i \right)}} \right)-{{y}^{\left( i \right)}}|{{|}^{2}}}</math>,其中参数 <math>\textstyle W</math> 是要优化的参数。对深度网络而言,这种非凸优化问题的搜索区域中充斥着大量“坏”的局部极值,因而使用梯度下降法(或者像共轭梯度下降法,L-BFGS等方法)效果并不好。<br />
<br />
===梯度弥散问题===<br />
<br />
梯度下降法(以及相关的L-BFGS算法等)在使用随机初始化权重的深度网络上效果不好的技术原因是:梯度会变得非常小。具体而言,当使用反向传播方法计算导数的时候,随着网络的深度的增加,反向传播的梯度(从输出层到网络的最初几层)的幅度值会急剧地减小。结果就造成了整体的损失函数相对于最初几层的权重的导数非常小。这样,当使用梯度下降法的时候,最初几层的权重变化非常缓慢,以至于它们不能够从样本中进行有效的学习。这种问题通常被称为“梯度的弥散”.<br />
<br />
<br />
与梯度弥散问题紧密相关的问题是:当神经网络中的最后几层含有足够数量神经元的时候,可能单独这几层就足以对有标签数据进行建模,而不用最初几层的帮助。因此,对所有层都使用随机初始化的方法训练得到的整个网络的性能将会与训练得到的浅层网络(仅由深度网络的最后几层组成的浅层网络)的性能相似。<br />
<br />
<br />
==逐层贪婪训练方法==<br />
<br />
那么,我们应该如何训练深度网络呢?逐层贪婪训练方法是取得一定成功的一种方法。我们会在后面的章节中详细阐述这种方法的细节。简单来说,逐层贪婪算法的主要思路是每次只训练网络中的一层,即我们首先训练一个只含一个隐藏层的网络,仅当这层网络训练结束之后才开始训练一个有两个隐藏层的网络,以此类推。在每一步中,我们把已经训练好的前 <math>\textstyle k-1 </math> 层固定,然后增加第 <math>\textstyle k </math> 层(也就是将我们已经训练好的前 <math>\textstyle k-1 </math> 的输出作为输入)。每一层的训练可以是有监督的(例如,将每一步的分类误差作为目标函数),但更通常使用无监督方法(例如自动编码器,我们会在后边的章节中给出细节)。这些各层单独训练所得到的权重被用来初始化最终(或者说全部)的深度网络的权重,然后对整个网络进行“微调”(即把所有层放在一起来优化有标签训练集上的训练误差).<br />
<br />
<br />
逐层贪婪的训练方法取得成功要归功于以下几方面:<br />
<br />
<br />
===数据获取===<br />
<br />
虽然获取有标签数据的代价是昂贵的,但获取大量的无标签数据是容易的。自学习方法(self-taught learning)的潜力在于它能通过使用大量的无标签数据来学习到更好的模型。具体而言,该方法使用无标签数据来学习得到所有层(不包括用于预测标签的最终分类层)<math>\textstyle {{W}^{\left( l \right)}}</math> 的最佳初始权重。相比纯监督学习方法,这种自学习方法能够利用多得多的数据,并且能够学习和发现数据中存在的模式。因此该方法通常能够提高分类器的性能。<br />
<br />
<br />
===更好的局部极值===<br />
<br />
当用无标签数据训练完网络后,相比于随机初始化而言,各层初始权重会位于参数空间中较好的位置上。然后我们可以从这些位置出发进一步微调权重。从经验上来说,以这些位置为起点开始梯度下降更有可能收敛到比较好的局部极值点,这是因为无标签数据已经提供了大量输入数据中包含的模式的先验信息。<br />
<br />
<br />
在下一节中,我们将会具体阐述如何进行逐层贪婪训练。<br />
<br />
<br />
==中英文对照==<br />
<br />
:深度网络 Deep Networks <br />
<br />
:深度神经网络 deep neural networks <br />
<br />
:非线性变换 non-linear transformation <br />
<br />
:激活函数 activation function <br />
<br />
:简洁地表达 represent compactly <br />
<br />
:“部分-整体”的分解 part-whole decompositions <br />
<br />
:目标的部件 parts of objects <br />
<br />
:高度非凸的优化问题 highly non-convex optimization problem <br />
<br />
:共轭梯度 conjugate gradient <br />
<br />
:梯度的弥散 diffusion of gradients <br />
<br />
:逐层贪婪训练方法 Greedy layer-wise training <br />
<br />
:自动编码器 autoencoder <br />
<br />
:微调 fine-tuned <br />
<br />
:自学习方法 self-taught learning <br />
<br />
<br />
<br />
==中文译者==<br />
<br />
郑胤(yzheng3xg@gmail.com), 谭晓阳(x.tan@nuaa.edu.cn), 许利杰(csxulijie@gmail.com)<br />
<br />
<br />
<br />
{{建立分类用深度网络}}<br />
<br />
<br />
{{Languages|Deep_Networks:_Overview|English}}</div>
Kandeng
http://ufldl.stanford.edu/wiki/index.php/%E5%8F%8D%E5%90%91%E4%BC%A0%E5%AF%BC%E7%AE%97%E6%B3%95
反向传导算法
2013-04-15T02:42:27Z
<p>Kandeng: </p>
<hr />
<div>假设我们有一个固定样本集 <math>\textstyle \{ (x^{(1)}, y^{(1)}), \ldots, (x^{(m)}, y^{(m)}) \}</math>,它包含 <math>\textstyle m</math> 个样例。我们可以用批量梯度下降法来求解神经网络。具体来讲,对于单个样例 <math>\textstyle (x,y)</math>,其代价函数为:<br />
<br />
:<math><br />
\begin{align}<br />
J(W,b; x,y) = \frac{1}{2} \left\| h_{W,b}(x) - y \right\|^2.<br />
\end{align}<br />
</math><br />
<br />
这是一个(二分之一的)方差代价函数。给定一个包含 <math>\textstyle m</math> 个样例的数据集,我们可以定义整体代价函数为:<br />
<br />
:<math> <br />
\begin{align}<br />
J(W,b)<br />
&= \left[ \frac{1}{m} \sum_{i=1}^m J(W,b;x^{(i)},y^{(i)}) \right]<br />
+ \frac{\lambda}{2} \sum_{l=1}^{n_l-1} \; \sum_{i=1}^{s_l} \; \sum_{j=1}^{s_{l+1}} \left( W^{(l)}_{ji} \right)^2<br />
\\<br />
&= \left[ \frac{1}{m} \sum_{i=1}^m \left( \frac{1}{2} \left\| h_{W,b}(x^{(i)}) - y^{(i)} \right\|^2 \right) \right]<br />
+ \frac{\lambda}{2} \sum_{l=1}^{n_l-1} \; \sum_{i=1}^{s_l} \; \sum_{j=1}^{s_{l+1}} \left( W^{(l)}_{ji} \right)^2<br />
\end{align}<br />
</math><br />
<br />
以上公式中的第一项 <math>\textstyle J(W,b)</math> 是一个均方差项。第二项是一个规则化项(也叫'''权重衰减项'''),其目的是减小权重的幅度,防止过度拟合。<br />
<br />
<br />
[注:通常权重衰减的计算并不使用偏置项 <math>\textstyle b^{(l)}_i</math>,比如我们在 <math>\textstyle J(W, b)</math> 的定义中就没有使用。一般来说,将偏置项包含在权重衰减项中只会对最终的神经网络产生很小的影响。如果你在斯坦福选修过CS229(机器学习)课程,或者在YouTube上看过课程视频,你会发现这个权重衰减实际上是课上提到的贝叶斯规则化方法的变种。在贝叶斯规则化方法中,我们将高斯先验概率引入到参数中计算MAP(极大后验)估计(而不是极大似然估计)。]<br />
<br />
<br />
'''权重衰减参数''' <math>\textstyle \lambda</math> 用于控制公式中两项的相对重要性。在此重申一下这两个复杂函数的含义:<math>\textstyle J(W,b;x,y)</math> 是针对单个样例计算得到的方差代价函数;<math>\textstyle J(W,b)</math> 是整体样本代价函数,它包含权重衰减项。<br />
<br />
<br />
以上的代价函数经常被用于分类和回归问题。在分类问题中,我们用 <math>\textstyle y = 0</math> 或 <math>\textstyle 1</math>,来代表两种类型的标签(回想一下,这是因为 sigmoid激活函数的值域为 <math>\textstyle [0,1]</math>;如果我们使用双曲正切型激活函数,那么应该选用 <math>\textstyle -1</math> 和 <math>\textstyle +1</math> 作为标签)。对于回归问题,我们首先要变换输出值域(译者注:也就是 <math>\textstyle y</math>),以保证其范围为 <math>\textstyle [0,1]</math> (同样地,如果我们使用双曲正切型激活函数,要使输出值域为 <math>\textstyle [-1,1]</math>)。<br />
<br />
<br />
我们的目标是针对参数 <math>\textstyle W</math> 和 <math>\textstyle b</math> 来求其函数 <math>\textstyle J(W,b)</math> 的最小值。为了求解神经网络,我们需要将每一个参数 <math>\textstyle W^{(l)}_{ij}</math> 和 <math>\textstyle b^{(l)}_i</math> 初始化为一个很小的、接近零的随机值(比如说,使用正态分布 <math>\textstyle {Normal}(0,\epsilon^2)</math> 生成的随机值,其中 <math>\textstyle \epsilon</math> 设置为 <math>\textstyle 0.01</math> ),之后对目标函数使用诸如批量梯度下降法的最优化算法。因为 <math>\textstyle J(W, b)</math> 是一个非凸函数,梯度下降法很可能会收敛到局部最优解;但是在实际应用中,梯度下降法通常能得到令人满意的结果。最后,需要再次强调的是,要将参数进行随机初始化,而不是全部置为 <math>\textstyle 0</math>。如果所有参数都用相同的值作为初始值,那么所有隐藏层单元最终会得到与输入值有关的、相同的函数(也就是说,对于所有 <math>\textstyle i</math>,<math>\textstyle W^{(1)}_{ij}</math>都会取相同的值,那么对于任何输入 <math>\textstyle x</math> 都会有:<math>\textstyle a^{(2)}_1 = a^{(2)}_2 = a^{(2)}_3 = \ldots</math> )。随机初始化的目的是使'''对称失效'''。<br />
<br />
<br />
梯度下降法中每一次迭代都按照如下公式对参数 <math>\textstyle W</math> 和<math>\textstyle b</math> 进行更新:<br />
<br />
:<math><br />
\begin{align}<br />
W_{ij}^{(l)} &= W_{ij}^{(l)} - \alpha \frac{\partial}{\partial W_{ij}^{(l)}} J(W,b) \\<br />
b_{i}^{(l)} &= b_{i}^{(l)} - \alpha \frac{\partial}{\partial b_{i}^{(l)}} J(W,b)<br />
\end{align}<br />
</math> <br />
<br />
其中 <math>\textstyle \alpha</math> 是学习速率。其中关键步骤是计算偏导数。我们现在来讲一下'''反向传播'''算法,它是计算偏导数的一种有效方法。<br />
<br />
<br />
我们首先来讲一下如何使用反向传播算法来计算 <math>\textstyle \frac{\partial}{\partial W_{ij}^{(l)}} J(W,b; x, y)</math> 和 <math>\textstyle \frac{\partial}{\partial b_{i}^{(l)}} J(W,b; x, y)</math>,这两项是单个样例 <math>\textstyle (x,y)</math> 的代价函数 <math>\textstyle J(W,b;x,y)</math> 的偏导数。一旦我们求出该偏导数,就可以推导出整体代价函数 <math>\textstyle J(W,b)</math> 的偏导数:<br />
<br />
<br />
:<math><br />
\begin{align}<br />
\frac{\partial}{\partial W_{ij}^{(l)}} J(W,b) &=<br />
\left[ \frac{1}{m} \sum_{i=1}^m \frac{\partial}{\partial W_{ij}^{(l)}} J(W,b; x^{(i)}, y^{(i)}) \right] + \lambda W_{ij}^{(l)} \\<br />
\frac{\partial}{\partial b_{i}^{(l)}} J(W,b) &=<br />
\frac{1}{m}\sum_{i=1}^m \frac{\partial}{\partial b_{i}^{(l)}} J(W,b; x^{(i)}, y^{(i)})<br />
\end{align}<br />
</math> <br />
<br />
以上两行公式稍有不同,第一行比第二行多出一项,是因为权重衰减是作用于 <math>\textstyle W</math> 而不是 <math>\textstyle b</math>。<br />
<br />
<br />
反向传播算法的思路如下:给定一个样例 <math>\textstyle (x,y)</math>,我们首先进行“前向传导”运算,计算出网络中所有的激活值,包括 <math>\textstyle h_{W,b}(x)</math> 的输出值。之后,针对第 <math>\textstyle l</math> 层的每一个节点 <math>\textstyle i</math>,我们计算出其“残差” <math>\textstyle \delta^{(l)}_i</math>,该残差表明了该节点对最终输出值的残差产生了多少影响。对于最终的输出节点,我们可以直接算出网络产生的激活值与实际值之间的差距,我们将这个差距定义为 <math>\textstyle \delta^{(n_l)}_i</math> (第 <math>\textstyle n_l</math> 层表示输出层)。对于隐藏单元我们如何处理呢?我们将基于节点(译者注:第 <math>\textstyle l+1</math> 层节点)残差的加权平均值计算 <math>\textstyle \delta^{(l)}_i</math>,这些节点以 <math>\textstyle a^{(l)}_i</math> 作为输入。下面将给出反向传导算法的细节:<br />
<br />
<br />
<ol><br />
<li>进行前馈传导计算,利用前向传导公式,得到 <math>\textstyle L_2, L_3, \ldots </math> 直到输出层 <math>\textstyle L_{n_l}</math> 的激活值。<br />
<li>对于第 <math>\textstyle n_l</math> 层(输出层)的每个输出单元 <math>\textstyle i</math>,我们根据以下公式计算残差:<br />
<br />
<br />
:<math><br />
\begin{align}<br />
\delta^{(n_l)}_i<br />
= \frac{\partial}{\partial z^{(n_l)}_i} \;\;<br />
\frac{1}{2} \left\|y - h_{W,b}(x)\right\|^2 = - (y_i - a^{(n_l)}_i) \cdot f'(z^{(n_l)}_i)<br />
\end{align}<br />
</math><br />
<br />
[译者注:<br />
:<math> <br />
\begin{align}<br />
\delta^{(n_l)}_i &= \frac{\partial}{\partial z^{n_l}_i}J(W,b;x,y)<br />
= \frac{\partial}{\partial z^{n_l}_i}\frac{1}{2} \left\|y - h_{W,b}(x)\right\|^2 \\<br />
&= \frac{\partial}{\partial z^{n_l}_i}\frac{1}{2} \sum_{j=1}^{S_{n_l}} (y_j-a_j^{(n_l)})^2<br />
= \frac{\partial}{\partial z^{n_l}_i}\frac{1}{2} \sum_{j=1}^{S_{n_l}} (y_j-f(z_j^{(n_l)}))^2 \\<br />
&= - (y_i - f(z_j^{(n_l)})) \cdot f'(z^{(n_l)}_i)<br />
= - (y_i - a^{(n_l)}_i) \cdot f'(z^{(n_l)}_i)<br />
\end{align}<br />
</math> <br />
]<br />
<br />
<li>对 <math>\textstyle l = n_l-1, n_l-2, n_l-3, \ldots, 2</math> 的各个层,第 <math>\textstyle l</math> 层的第 <math>\textstyle i</math> 个节点的残差计算方法如下:<br />
: <math> <br />
\delta^{(l)}_i = \left( \sum_{j=1}^{s_{l+1}} W^{(l)}_{ji} \delta^{(l+1)}_j \right) f'(z^{(l)}_i)<br />
</math> <br />
<br />
{译者注:<br />
:<math> <br />
\begin{align}<br />
\delta^{(n_l-1)}_i &=\frac{\partial}{\partial z^{n_l-1}_i}J(W,b;x,y)<br />
= \frac{\partial}{\partial z^{n_l-1}_i}\frac{1}{2} \left\|y - h_{W,b}(x)\right\|^2 <br />
= \frac{\partial}{\partial z^{n_l-1}_i}\frac{1}{2} \sum_{j=1}^{S_{n_l}}(y_j-a_j^{(n_l)})^2 \\<br />
&= \frac{1}{2} \sum_{j=1}^{S_{n_l}}\frac{\partial}{\partial z^{n_l-1}_i}(y_j-a_j^{(n_l)})^2<br />
= \frac{1}{2} \sum_{j=1}^{S_{n_l}}\frac{\partial}{\partial z^{n_l-1}_i}(y_j-f(z_j^{(n_l)}))^2 \\<br />
&= \sum_{j=1}^{S_{n_l}}(y_j-f(z_j^{(n_l)})) \cdot \frac{\partial}{\partial z_i^{(n_l-1)}}f(z_j^{(n_l)})<br />
= \sum_{j=1}^{S_{n_l}}(y_j-f(z_j^{(n_l)})) \cdot f'(z_j^{(n_l)}) \cdot \frac{\partial z_j^{(n_l)}}{\partial z_i^{(n_l-1)}} \\<br />
&= \sum_{j=1}^{S_{n_l}} \delta_j^{(n_l)} \cdot \frac{\partial z_j^{(n_l)}}{z_i^{n_l-1}}<br />
= \sum_{j=1}^{S_{n_l}} \left(\delta_j^{(n_l)} \cdot \frac{\partial}{\partial z_i^{n_l-1}}\sum_{k=1}^{S_{n_l-1}}f(z_k^{n_l-1}) \cdot W_{jk}^{n_l-1}\right) \\<br />
&= \sum_{j=1}^{S_{n_l}} \delta_j^{(n_l)} \cdot W_{ji}^{n_l-1} \cdot f'(z_i^{n_l-1})<br />
= \left(\sum_{j=1}^{S_{n_l-1}}W_{ji}^{n_l-1}\delta_j^{(n_l)}\right)f'(z_i^{n_l-1})<br />
\end{align}<br />
</math> <br />
<br />
将上式中的<math>\textstyle n_l-1</math>与<math>\textstyle n_l</math>的关系替换为<math>\textstyle l</math>与<math>\textstyle l+1</math>的关系,就可以得到:<br />
: <math> <br />
\delta^{(l)}_i = \left( \sum_{j=1}^{s_{l+1}} W^{(l)}_{ji} \delta^{(l+1)}_j \right) f'(z^{(l)}_i)<br />
</math> <br />
以上逐次从后向前求导的过程即为“反向传导”的本意所在。<br />
<br />
]<br />
<br />
<br />
<br />
<li>计算我们需要的偏导数,计算方法如下:<br />
:<math> <br />
\begin{align}<br />
\frac{\partial}{\partial W_{ij}^{(l)}} J(W,b; x, y) &= a^{(l)}_j \delta_i^{(l+1)} \\<br />
\frac{\partial}{\partial b_{i}^{(l)}} J(W,b; x, y) &= \delta_i^{(l+1)}.<br />
\end{align}<br />
</math> <br />
</ol><br />
<br />
<br />
最后,我们用矩阵-向量表示法重写以上算法。我们使用“<math>\textstyle \bullet</math>” 表示向量乘积运算符(在Matlab或Octave里用“<tt>.*</tt>”表示,也称作阿达马乘积)。若 <math>\textstyle a = b \bullet c</math>,则 <math>\textstyle a_i = b_ic_i</math>。在上一个教程中我们扩展了 <math>\textstyle f(\cdot)</math> 的定义,使其包含向量运算,这里我们也对偏导数 <math>\textstyle f'(\cdot)</math> 也做了同样的处理(于是又有 <math> \textstyle f'([z_1, z_2, z_3]) = [f'(z_1), f'(z_2), f'(z_3)]</math> )。<br />
<br />
<br />
那么,反向传播算法可表示为以下几个步骤:<br />
<br />
<ol><br />
<li>进行前馈传导计算,利用前向传导公式,得到 <math>\textstyle L_2, L_3, \ldots</math>直到输出层 <math>\textstyle L_{n_l}</math> 的激活值。<br />
<br />
<li>对输出层(第 <math>\textstyle n_l</math> 层),计算:<br />
<br />
:<math> \begin{align}<br />
\delta^{(n_l)}<br />
= - (y - a^{(n_l)}) \bullet f'(z^{(n_l)})<br />
\end{align}</math> <br />
<br />
<li>对于 <math>\textstyle l = n_l-1, n_l-2, n_l-3, \ldots, 2</math> 的各层,计算:<br />
:<math> \begin{align}<br />
\delta^{(l)} = \left((W^{(l)})^T \delta^{(l+1)}\right) \bullet f'(z^{(l)})<br />
\end{align}</math> <br />
<br />
<li>计算最终需要的偏导数值:<br />
:<math> \begin{align}<br />
\nabla_{W^{(l)}} J(W,b;x,y) &= \delta^{(l+1)} (a^{(l)})^T, \\<br />
\nabla_{b^{(l)}} J(W,b;x,y) &= \delta^{(l+1)}.<br />
\end{align}</math> <br />
</ol><br />
<br />
<br />
'''实现中应注意:'''在以上的第2步和第3步中,我们需要为每一个 <math>\textstyle i</math> 值计算其 <math>\textstyle f'(z^{(l)}_i)</math>。假设 <math>\textstyle f(z)</math> 是sigmoid函数,并且我们已经在前向传导运算中得到了 <math>\textstyle a^{(l)}_i</math>。那么,使用我们早先推导出的 <math>\textstyle f'(z)</math>表达式,就可以计算得到 <math>\textstyle f'(z^{(l)}_i) = a^{(l)}_i (1- a^{(l)}_i)</math>。<br />
<br />
<br />
最后,我们将对梯度下降算法做个全面总结。在下面的伪代码中,<math>\textstyle \Delta W^{(l)}</math> 是一个与矩阵 <math>\textstyle W^{(l)}</math> 维度相同的矩阵,<math>\textstyle \Delta b^{(l)}</math> 是一个与 <math>\textstyle b^{(l)}</math> 维度相同的向量。注意这里“<math>\textstyle \Delta W^{(l)}</math>”是一个矩阵,而不是“<math>\textstyle \Delta</math> 与 <math>\textstyle W^{(l)}</math> 相乘”。下面,我们实现批量梯度下降法中的一次迭代:<br />
<br />
<br />
<ol><br />
<li>对于所有 <math>\textstyle l</math>,令 <math>\textstyle \Delta W^{(l)} := 0</math> , <math>\textstyle \Delta b^{(l)} := 0</math> (设置为全零矩阵或全零向量)<br />
<br />
<li>对于 <math>\textstyle i = 1</math> 到 <math>\textstyle m</math>,<br />
<br />
<ol type="a"><br />
<li>使用反向传播算法计算 <math>\textstyle \nabla_{W^{(l)}} J(W,b;x,y)</math> 和 <math>\textstyle \nabla_{b^{(l)}} J(W,b;x,y)</math>。<br />
<li>计算 <math>\textstyle \Delta W^{(l)} := \Delta W^{(l)} + \nabla_{W^{(l)}} J(W,b;x,y)</math>。<br />
<li>计算 <math>\textstyle \Delta b^{(l)} := \Delta b^{(l)} + \nabla_{b^{(l)}} J(W,b;x,y)</math>。 <br />
</ol><br />
<br />
<li>更新权重参数:<br />
:<math> \begin{align}<br />
W^{(l)} &= W^{(l)} - \alpha \left[ \left(\frac{1}{m} \Delta W^{(l)} \right) + \lambda W^{(l)}\right] \\<br />
b^{(l)} &= b^{(l)} - \alpha \left[\frac{1}{m} \Delta b^{(l)}\right]<br />
\end{align}</math> <br />
</ol><br />
<br />
现在,我们可以重复梯度下降法的迭代步骤来减小代价函数 <math>\textstyle J(W,b)</math> 的值,进而求解我们的神经网络。<br />
<br />
<br />
==中英文对照==<br />
<br />
:反向传播算法 Backpropagation Algorithm<br />
:(批量)梯度下降法 (batch) gradient descent<br />
:(整体)代价函数 (overall) cost function<br />
:方差 squared-error<br />
:均方差 average sum-of-squares error<br />
:规则化项 regularization term<br />
:权重衰减 weight decay<br />
:偏置项 bias terms<br />
:贝叶斯规则化方法 Bayesian regularization method<br />
:高斯先验概率 Gaussian prior<br />
:极大后验估计 MAP<br />
:极大似然估计 maximum likelihood estimation<br />
:激活函数 activation function<br />
:双曲正切函数 tanh function<br />
:非凸函数 non-convex function<br />
:隐藏层单元 hidden (layer) units<br />
:对称失效 symmetry breaking<br />
:学习速率 learning rate<br />
:前向传导 forward pass<br />
:假设值 hypothesis <br />
:残差 error term<br />
:加权平均值 weighted average <br />
:前馈传导 feedforward pass<br />
:阿达马乘积 Hadamard product<br />
:前向传播 forward propagation<br />
<br />
<br />
==中文译者==<br />
<br />
王方(fangkey@gmail.com),林锋(xlfg@yeah.net),许利杰(csxulijie@gmail.com)<br />
<br />
<br />
{{稀疏自编码器}}<br />
<br />
<br />
<br />
{{Languages|Backpropagation_Algorithm|English}}</div>
Kandeng
http://ufldl.stanford.edu/wiki/index.php/%E5%8F%8D%E5%90%91%E4%BC%A0%E5%AF%BC%E7%AE%97%E6%B3%95
反向传导算法
2013-04-15T02:35:44Z
<p>Kandeng: </p>
<hr />
<div>假设我们有一个固定样本集 <math>\textstyle \{ (x^{(1)}, y^{(1)}), \ldots, (x^{(m)}, y^{(m)}) \}</math>,它包含 <math>\textstyle m</math> 个样例。我们可以用批量梯度下降法来求解神经网络。具体来讲,对于单个样例 <math>\textstyle (x,y)</math>,其代价函数为:<br />
<br />
:<math><br />
\begin{align}<br />
J(W,b; x,y) = \frac{1}{2} \left\| h_{W,b}(x) - y \right\|^2.<br />
\end{align}<br />
</math><br />
<br />
这是一个(二分之一的)方差代价函数。给定一个包含 <math>\textstyle m</math> 个样例的数据集,我们可以定义整体代价函数为:<br />
<br />
:<math> <br />
\begin{align}<br />
J(W,b)<br />
&= \left[ \frac{1}{m} \sum_{i=1}^m J(W,b;x^{(i)},y^{(i)}) \right]<br />
+ \frac{\lambda}{2} \sum_{l=1}^{n_l-1} \; \sum_{i=1}^{s_l} \; \sum_{j=1}^{s_{l+1}} \left( W^{(l)}_{ji} \right)^2<br />
\\<br />
&= \left[ \frac{1}{m} \sum_{i=1}^m \left( \frac{1}{2} \left\| h_{W,b}(x^{(i)}) - y^{(i)} \right\|^2 \right) \right]<br />
+ \frac{\lambda}{2} \sum_{l=1}^{n_l-1} \; \sum_{i=1}^{s_l} \; \sum_{j=1}^{s_{l+1}} \left( W^{(l)}_{ji} \right)^2<br />
\end{align}<br />
</math><br />
<br />
以上公式中的第一项 <math>\textstyle J(W,b)</math> 是一个均方差项。第二项是一个规则化项(也叫'''权重衰减项'''),其目的是减小权重的幅度,防止过度拟合。<br />
<br />
<br />
[注:通常权重衰减的计算并不使用偏置项 <math>\textstyle b^{(l)}_i</math>,比如我们在 <math>\textstyle J(W, b)</math> 的定义中就没有使用。一般来说,将偏置项包含在权重衰减项中只会对最终的神经网络产生很小的影响。如果你在斯坦福选修过CS229(机器学习)课程,或者在YouTube上看过课程视频,你会发现这个权重衰减实际上是课上提到的贝叶斯规则化方法的变种。在贝叶斯规则化方法中,我们将高斯先验概率引入到参数中计算MAP(极大后验)估计(而不是极大似然估计)。]<br />
<br />
<br />
'''权重衰减参数''' <math>\textstyle \lambda</math> 用于控制公式中两项的相对重要性。在此重申一下这两个复杂函数的含义:<math>\textstyle J(W,b;x,y)</math> 是针对单个样例计算得到的方差代价函数;<math>\textstyle J(W,b)</math> 是整体样本代价函数,它包含权重衰减项。<br />
<br />
<br />
以上的代价函数经常被用于分类和回归问题。在分类问题中,我们用 <math>\textstyle y = 0</math> 或 <math>\textstyle 1</math>,来代表两种类型的标签(回想一下,这是因为 sigmoid激活函数的值域为 <math>\textstyle [0,1]</math>;如果我们使用双曲正切型激活函数,那么应该选用 <math>\textstyle -1</math> 和 <math>\textstyle +1</math> 作为标签)。对于回归问题,我们首先要变换输出值域(译者注:也就是 <math>\textstyle y</math>),以保证其范围为 <math>\textstyle [0,1]</math> (同样地,如果我们使用双曲正切型激活函数,要使输出值域为 <math>\textstyle [-1,1]</math>)。<br />
<br />
<br />
我们的目标是针对参数 <math>\textstyle W</math> 和 <math>\textstyle b</math> 来求其函数 <math>\textstyle J(W,b)</math> 的最小值。为了求解神经网络,我们需要将每一个参数 <math>\textstyle W^{(l)}_{ij}</math> 和 <math>\textstyle b^{(l)}_i</math> 初始化为一个很小的、接近零的随机值(比如说,使用正态分布 <math>\textstyle {Normal}(0,\epsilon^2)</math> 生成的随机值,其中 <math>\textstyle \epsilon</math> 设置为 <math>\textstyle 0.01</math> ),之后对目标函数使用诸如批量梯度下降法的最优化算法。因为 <math>\textstyle J(W, b)</math> 是一个非凸函数,梯度下降法很可能会收敛到局部最优解;但是在实际应用中,梯度下降法通常能得到令人满意的结果。最后,需要再次强调的是,要将参数进行随机初始化,而不是全部置为 <math>\textstyle 0</math>。如果所有参数都用相同的值作为初始值,那么所有隐藏层单元最终会得到与输入值有关的、相同的函数(也就是说,对于所有 <math>\textstyle i</math>,<math>\textstyle W^{(1)}_{ij}</math>都会取相同的值,那么对于任何输入 <math>\textstyle x</math> 都会有:<math>\textstyle a^{(2)}_1 = a^{(2)}_2 = a^{(2)}_3 = \ldots</math> )。随机初始化的目的是使'''对称失效'''。<br />
<br />
<br />
梯度下降法中每一次迭代都按照如下公式对参数 <math>\textstyle W</math> 和<math>\textstyle b</math> 进行更新:<br />
<br />
:<math><br />
\begin{align}<br />
W_{ij}^{(l)} &= W_{ij}^{(l)} - \alpha \frac{\partial}{\partial W_{ij}^{(l)}} J(W,b) \\<br />
b_{i}^{(l)} &= b_{i}^{(l)} - \alpha \frac{\partial}{\partial b_{i}^{(l)}} J(W,b)<br />
\end{align}<br />
</math> <br />
<br />
其中 <math>\textstyle \alpha</math> 是学习速率。其中关键步骤是计算偏导数。我们现在来讲一下'''反向传播'''算法,它是计算偏导数的一种有效方法。<br />
<br />
<br />
我们首先来讲一下如何使用反向传播算法来计算 <math>\textstyle \frac{\partial}{\partial W_{ij}^{(l)}} J(W,b; x, y)</math> 和 <math>\textstyle \frac{\partial}{\partial b_{i}^{(l)}} J(W,b; x, y)</math>,这两项是单个样例 <math>\textstyle (x,y)</math> 的代价函数 <math>\textstyle J(W,b;x,y)</math> 的偏导数。一旦我们求出该偏导数,就可以推导出整体代价函数 <math>\textstyle J(W,b)</math> 的偏导数:<br />
<br />
<br />
:<math><br />
\begin{align}<br />
\frac{\partial}{\partial W_{ij}^{(l)}} J(W,b) &=<br />
\left[ \frac{1}{m} \sum_{i=1}^m \frac{\partial}{\partial W_{ij}^{(l)}} J(W,b; x^{(i)}, y^{(i)}) \right] + \lambda W_{ij}^{(l)} \\<br />
\frac{\partial}{\partial b_{i}^{(l)}} J(W,b) &=<br />
\frac{1}{m}\sum_{i=1}^m \frac{\partial}{\partial b_{i}^{(l)}} J(W,b; x^{(i)}, y^{(i)})<br />
\end{align}<br />
</math> <br />
<br />
以上两行公式稍有不同,第一行比第二行多出一项,是因为权重衰减是作用于 <math>\textstyle W</math> 而不是 <math>\textstyle b</math>。<br />
<br />
<br />
反向传播算法的思路如下:给定一个样例 <math>\textstyle (x,y)</math>,我们首先进行“前向传导”运算,计算出网络中所有的激活值,包括 <math>\textstyle h_{W,b}(x)</math> 的输出值。之后,针对第 <math>\textstyle l</math> 层的每一个节点 <math>\textstyle i</math>,我们计算出其“残差” <math>\textstyle \delta^{(l)}_i</math>,该残差表明了该节点对最终输出值的残差产生了多少影响。对于最终的输出节点,我们可以直接算出网络产生的激活值与实际值之间的差距,我们将这个差距定义为 <math>\textstyle \delta^{(n_l)}_i</math> (第 <math>\textstyle n_l</math> 层表示输出层)。对于隐藏单元我们如何处理呢?我们将基于节点(译者注:第 <math>\textstyle l+1</math> 层节点)残差的加权平均值计算 <math>\textstyle \delta^{(l)}_i</math>,这些节点以 <math>\textstyle a^{(l)}_i</math> 作为输入。下面将给出反向传导算法的细节:<br />
<br />
<br />
<ol><br />
<li>进行前馈传导计算,利用前向传导公式,得到 <math>\textstyle L_2, L_3, \ldots </math> 直到输出层 <math>\textstyle L_{n_l}</math> 的激活值。<br />
<li>对于第 <math>\textstyle n_l</math> 层(输出层)的每个输出单元 <math>\textstyle i</math>,我们根据以下公式计算残差:<br />
<br />
<br />
:<math><br />
\begin{align}<br />
\delta^{(n_l)}_i<br />
= \frac{\partial}{\partial z^{(n_l)}_i} \;\;<br />
\frac{1}{2} \left\|y - h_{W,b}(x)\right\|^2 = - (y_i - a^{(n_l)}_i) \cdot f'(z^{(n_l)}_i)<br />
\end{align}<br />
</math><br />
<br />
[译者注:<br />
:<math> <br />
\begin{align}<br />
\delta^{(n_l)}_i &= \frac{\partial}{\partial z^{n_l}_i}J(W,b;x,y)<br />
= \frac{\partial}{\partial z^{n_l}_i}\frac{1}{2} \left\|y - h_{W,b}(x)\right\|^2 \\<br />
&= \frac{\partial}{\partial z^{n_l}_i}\frac{1}{2} \sum_{j=1}^{S_{n_l}} (y_j-a_j^{(n_l)})^2<br />
= \frac{\partial}{\partial z^{n_l}_i}\frac{1}{2} \sum_{j=1}^{S_{n_l}} (y_j-f(z_j^{(n_l)}))^2 \\<br />
&= - (y_i - f(z_j^{(n_l)})) \cdot f'(z^{(n_l)}_i)<br />
= - (y_i - a^{(n_l)}_i) \cdot f'(z^{(n_l)}_i)<br />
\end{align}<br />
</math> <br />
]<br />
<br />
<li>对 <math>\textstyle l = n_l-1, n_l-2, n_l-3, \ldots, 2</math> 的各个层,第 <math>\textstyle l</math> 层的第 <math>\textstyle i</math> 个节点的残差计算方法如下:<br />
: <math> <br />
\delta^{(l)}_i = \left( \sum_{j=1}^{s_{l+1}} W^{(l)}_{ji} \delta^{(l+1)}_j \right) f'(z^{(l)}_i)<br />
</math> <br />
<br />
{译者注:<br />
:<math> <br />
\begin{align}<br />
\delta^{(n_l-1)}_i &=\frac{\partial}{\partial z^{n_l-1}_i}J(W,b;x,y)<br />
= \frac{\partial}{\partial z^{n_l-1}_i}\frac{1}{2} \left\|y - h_{W,b}(x)\right\|^2 <br />
= \frac{\partial}{\partial z^{n_l-1}_i}\frac{1}{2} \sum_{j=1}^{S_{n_l}}(y_j-a_j^{(n_l)})^2 \\<br />
&= \frac{1}{2} \sum_{j=1}^{S_{n_l}}\frac{\partial}{\partial z^{n_l-1}_i}(y_j-a_j^{(n_l)})^2<br />
= \frac{1}{2} \sum_{j=1}^{S_{n_l}}\frac{\partial}{\partial z^{n_l-1}_i}(y_j-f(z_j^{(n_l)}))^2 \\<br />
&= \sum_{j=1}^{S_{n_l}}(y_j-f(z_j^{(n_l)}) \cdot \frac{\partial}{\partial z_i^{(n_l-1)}}f(z_j^{(n_l)})<br />
= \sum_{j=1}^{S_{n_l}}(y_j-f(z_j^{(n_l)}) \cdot f'(z_j^{(n_l)}) \cdot \frac{\partial z_j^{(n_l)}}{\partial z_i^{(n_l-1)}} \\<br />
&= \sum_{j=1}^{S_{n_l}} \delta_j^{(n_l)} \cdot \frac{\partial z_j^{(n_l)}}{z_i^{n_l-1}}<br />
= \sum_{j=1}^{S_{n_l}} \left(\delta_j^{(n_l)} \cdot \frac{\partial}{\partial z_i^{n_l-1}}\sum_{k=1}^{S_{n_l-1}}f(z_k^{n_l-1}) \cdot W_{jk}^{n_l-1}\right) \\<br />
&= \sum_{j=1}^{S_{n_l}} \delta_j^{(n_l)} \cdot W_{ji}^{n_l-1} \cdot f'(z_i^{n_l-1})<br />
= \left(\sum_{j=1}^{S_{n_l-1}}W_{ji}^{n_l-1}\delta_j^{(n_l)}\right)f'(z_i^{n_l-1})<br />
\end{align}<br />
</math> <br />
<br />
将上式中的<math>\textstyle n_l-1</math>与<math>\textstyle n_l</math>的关系替换为<math>\textstyle l</math>与<math>\textstyle l+1</math>的关系,就可以得到:<br />
: <math> <br />
\delta^{(l)}_i = \left( \sum_{j=1}^{s_{l+1}} W^{(l)}_{ji} \delta^{(l+1)}_j \right) f'(z^{(l)}_i)<br />
</math> <br />
以上逐次从后向前求导的过程即为“反向传导”的本意所在。<br />
<br />
]<br />
<br />
<br />
<br />
<li>计算我们需要的偏导数,计算方法如下:<br />
:<math> <br />
\begin{align}<br />
\frac{\partial}{\partial W_{ij}^{(l)}} J(W,b; x, y) &= a^{(l)}_j \delta_i^{(l+1)} \\<br />
\frac{\partial}{\partial b_{i}^{(l)}} J(W,b; x, y) &= \delta_i^{(l+1)}.<br />
\end{align}<br />
</math> <br />
</ol><br />
<br />
<br />
最后,我们用矩阵-向量表示法重写以上算法。我们使用“<math>\textstyle \bullet</math>” 表示向量乘积运算符(在Matlab或Octave里用“<tt>.*</tt>”表示,也称作阿达马乘积)。若 <math>\textstyle a = b \bullet c</math>,则 <math>\textstyle a_i = b_ic_i</math>。在上一个教程中我们扩展了 <math>\textstyle f(\cdot)</math> 的定义,使其包含向量运算,这里我们也对偏导数 <math>\textstyle f'(\cdot)</math> 也做了同样的处理(于是又有 <math> \textstyle f'([z_1, z_2, z_3]) = [f'(z_1), f'(z_2), f'(z_3)]</math> )。<br />
<br />
<br />
那么,反向传播算法可表示为以下几个步骤:<br />
<br />
<ol><br />
<li>进行前馈传导计算,利用前向传导公式,得到 <math>\textstyle L_2, L_3, \ldots</math>直到输出层 <math>\textstyle L_{n_l}</math> 的激活值。<br />
<br />
<li>对输出层(第 <math>\textstyle n_l</math> 层),计算:<br />
<br />
:<math> \begin{align}<br />
\delta^{(n_l)}<br />
= - (y - a^{(n_l)}) \bullet f'(z^{(n_l)})<br />
\end{align}</math> <br />
<br />
<li>对于 <math>\textstyle l = n_l-1, n_l-2, n_l-3, \ldots, 2</math> 的各层,计算:<br />
:<math> \begin{align}<br />
\delta^{(l)} = \left((W^{(l)})^T \delta^{(l+1)}\right) \bullet f'(z^{(l)})<br />
\end{align}</math> <br />
<br />
<li>计算最终需要的偏导数值:<br />
:<math> \begin{align}<br />
\nabla_{W^{(l)}} J(W,b;x,y) &= \delta^{(l+1)} (a^{(l)})^T, \\<br />
\nabla_{b^{(l)}} J(W,b;x,y) &= \delta^{(l+1)}.<br />
\end{align}</math> <br />
</ol><br />
<br />
<br />
'''实现中应注意:'''在以上的第2步和第3步中,我们需要为每一个 <math>\textstyle i</math> 值计算其 <math>\textstyle f'(z^{(l)}_i)</math>。假设 <math>\textstyle f(z)</math> 是sigmoid函数,并且我们已经在前向传导运算中得到了 <math>\textstyle a^{(l)}_i</math>。那么,使用我们早先推导出的 <math>\textstyle f'(z)</math>表达式,就可以计算得到 <math>\textstyle f'(z^{(l)}_i) = a^{(l)}_i (1- a^{(l)}_i)</math>。<br />
<br />
<br />
最后,我们将对梯度下降算法做个全面总结。在下面的伪代码中,<math>\textstyle \Delta W^{(l)}</math> 是一个与矩阵 <math>\textstyle W^{(l)}</math> 维度相同的矩阵,<math>\textstyle \Delta b^{(l)}</math> 是一个与 <math>\textstyle b^{(l)}</math> 维度相同的向量。注意这里“<math>\textstyle \Delta W^{(l)}</math>”是一个矩阵,而不是“<math>\textstyle \Delta</math> 与 <math>\textstyle W^{(l)}</math> 相乘”。下面,我们实现批量梯度下降法中的一次迭代:<br />
<br />
<br />
<ol><br />
<li>对于所有 <math>\textstyle l</math>,令 <math>\textstyle \Delta W^{(l)} := 0</math> , <math>\textstyle \Delta b^{(l)} := 0</math> (设置为全零矩阵或全零向量)<br />
<br />
<li>对于 <math>\textstyle i = 1</math> 到 <math>\textstyle m</math>,<br />
<br />
<ol type="a"><br />
<li>使用反向传播算法计算 <math>\textstyle \nabla_{W^{(l)}} J(W,b;x,y)</math> 和 <math>\textstyle \nabla_{b^{(l)}} J(W,b;x,y)</math>。<br />
<li>计算 <math>\textstyle \Delta W^{(l)} := \Delta W^{(l)} + \nabla_{W^{(l)}} J(W,b;x,y)</math>。<br />
<li>计算 <math>\textstyle \Delta b^{(l)} := \Delta b^{(l)} + \nabla_{b^{(l)}} J(W,b;x,y)</math>。 <br />
</ol><br />
<br />
<li>更新权重参数:<br />
:<math> \begin{align}<br />
W^{(l)} &= W^{(l)} - \alpha \left[ \left(\frac{1}{m} \Delta W^{(l)} \right) + \lambda W^{(l)}\right] \\<br />
b^{(l)} &= b^{(l)} - \alpha \left[\frac{1}{m} \Delta b^{(l)}\right]<br />
\end{align}</math> <br />
</ol><br />
<br />
现在,我们可以重复梯度下降法的迭代步骤来减小代价函数 <math>\textstyle J(W,b)</math> 的值,进而求解我们的神经网络。<br />
<br />
<br />
==中英文对照==<br />
<br />
:反向传播算法 Backpropagation Algorithm<br />
:(批量)梯度下降法 (batch) gradient descent<br />
:(整体)代价函数 (overall) cost function<br />
:方差 squared-error<br />
:均方差 average sum-of-squares error<br />
:规则化项 regularization term<br />
:权重衰减 weight decay<br />
:偏置项 bias terms<br />
:贝叶斯规则化方法 Bayesian regularization method<br />
:高斯先验概率 Gaussian prior<br />
:极大后验估计 MAP<br />
:极大似然估计 maximum likelihood estimation<br />
:激活函数 activation function<br />
:双曲正切函数 tanh function<br />
:非凸函数 non-convex function<br />
:隐藏层单元 hidden (layer) units<br />
:对称失效 symmetry breaking<br />
:学习速率 learning rate<br />
:前向传导 forward pass<br />
:假设值 hypothesis <br />
:残差 error term<br />
:加权平均值 weighted average <br />
:前馈传导 feedforward pass<br />
:阿达马乘积 Hadamard product<br />
:前向传播 forward propagation<br />
<br />
<br />
==中文译者==<br />
<br />
王方(fangkey@gmail.com),林锋(xlfg@yeah.net),许利杰(csxulijie@gmail.com)<br />
<br />
<br />
{{稀疏自编码器}}<br />
<br />
<br />
<br />
{{Languages|Backpropagation_Algorithm|English}}</div>
Kandeng
http://ufldl.stanford.edu/wiki/index.php/%E4%BB%8E%E8%87%AA%E6%88%91%E5%AD%A6%E4%B9%A0%E5%88%B0%E6%B7%B1%E5%B1%82%E7%BD%91%E7%BB%9C
从自我学习到深层网络
2013-04-10T13:38:43Z
<p>Kandeng: </p>
<hr />
<div>在前一节中,我们利用自编码器来学习输入至 softmax 或 logistic 回归分类器的特征。这些特征仅利用未标注数据学习获得。在本节中,我们描述如何利用已标注数据进行'''微调''',从而进一步优化这些特征。如果有大量已标注数据,通过微调就可以显著提升分类器的性能。<br />
<br />
<br />
在自我学习中,我们首先利用未标注数据训练一个稀疏自编码器。随后,给定一个新样本 <math>\textstyle x</math>,我们通过隐含层提取出特征 <math>\textstyle a</math>。上述过程图示如下:<br />
<br />
[[File:STL_SparseAE_Features.png|300px]]<br />
<br />
<br />
我们感兴趣的是分类问题,目标是预测样本的类别标号 <math>\textstyle y</math>。我们拥有标注数据集 <math>\textstyle \{ (x_l^{(1)}, y^{(1)}), (x_l^{(2)}, y^{(2)}), \ldots (x_l^{(m_l)},y^{(m_l)}) \}</math>,包含 <math>\textstyle m_l</math> 个标注样本。此前我们已经说明,可以利用稀疏自编码器获得的特征 <math>\textstyle a^{(l)}</math> 来替代原始特征。这样就可获得训练数据集 <math>\textstyle \{(a^{(1)},y^{(1)}), \ldots (a^{(m_l)}, y^{(m_l)}) \}</math>。最终,我们训练出一个从特征 <math>\textstyle a^{(i)}</math> 到类标号 <math>\textstyle y^{(i)}</math> 的 logistic 分类器。为说明这一过程,我们按照[[神经网络|神经网络]]一节中的方式,用下图描述 logistic 回归单元(橘黄色)。<br />
<br />
::::[[File:STL_Logistic_Classifier.png|380px]]<br />
<br />
<br />
考虑利用这个方法所学到的分类器(输入-输出映射)。它描述了一个把测试样本 <math>\textstyle x</math> 映射到预测值 <math>\textstyle p(y=1|x)</math> 的函数。将此前的两张图片结合起来,就得到该函数的图形表示。也即,最终的分类器可以表示为:<br />
<br />
[[File:STL_CombinedAE.png|500px]]<br />
<br />
<br />
该模型的参数通过两个步骤训练获得:在该网络的第一层,将输入 <math>\textstyle x</math> 映射至隐藏单元激活量 <math>\textstyle a</math> 的权值 <math>\textstyle W^{(1)}</math> 可以通过稀疏自编码器训练过程获得。在第二层,将隐藏单元 <math>\textstyle a</math> 映射至输出 <math>\textstyle y</math> 的权值 <math>\textstyle W^{(2)}</math> 可以通过 logistic 回归或 softmax 回归训练获得。<br />
<br />
<br />
<br />
这个最终分类器整体上显然是一个大的神经网络。因此,在训练获得模型最初参数(利用自动编码器训练第一层,利用 logistic/softmax 回归训练第二层)之后,我们可以进一步修正模型参数,进而降低训练误差。具体来说,我们可以对参数进行微调,在现有参数的基础上采用梯度下降或者 L-BFGS 来降低已标注样本集 <math>\textstyle \{ (x_l^{(1)}, y^{(1)}), (x_l^{(2)}, y^{(2)}), \ldots (x_l^{(m_l)}, y^{(m_l)}) \}</math> 上的训练误差。<br />
<br />
<br />
使用微调时,初始的非监督特征学习步骤(也就是自动编码器和logistic分类器训练)有时候被称为预训练。微调的作用在于,已标注数据集也可以用来修正权值 <math>\textstyle W^{(1)}</math>,这样可以对隐藏单元所提取的特征 <math>\textstyle a</math> 做进一步调整。<br />
<br />
<br />
到现在为止,我们描述上述过程时,都假设采用了“替代 (Replacement)”表示而不是“级联 (Concatenation)”表示。在替代表示中,logistic 分类器所看到的训练样本格式为 <math>\textstyle (a^{(i)}, y^{(i)})</math>;而在级联表示中,分类器所看到的训练样本格式为 <math>\textstyle ((x^{(i)}, a^{(i)}), y^{(i)})</math>。对级联表示同样可以进行微调(在级联表示神经网络中,输入值 <math>\textstyle x_i</math> 也直接被输入至 logistic 分类器。对此前的神经网络示意图稍加更改,即可获得其示意图。具体的说,第一层的输入节点除了与隐层联接之外,还将越过隐层,与第三层输出节点直接相连)。但是对于微调来说,级联表示相对于替代表示几乎没有优势。因此,如果需要开展微调,我们通常使用替代表示的网络(但是如果不开展微调,级联表示的效果有时候会好得多)。<br />
<br />
<br />
在什么时候应用微调?通常仅在有大量已标注训练数据的情况下使用。在这样的情况下,微调能显著提升分类器性能。然而,如果有大量未标注数据集(用于非监督特征学习/预训练),却只有相对较少的已标注训练集,微调的作用非常有限。<br />
<br />
<br />
==中英文对照==<br />
<br />
:自我学习 self-taught learning<br />
<br />
:深层网络 deep networks<br />
<br />
:微调 fine-tune<br />
<br />
:稀疏自编码器 sparse autoencoder<br />
<br />
:梯度下降 gradient descent<br />
<br />
:非监督特征学习 unsupervised feature learning<br />
<br />
:预训练 pre-training<br />
<br />
<br />
==中文译者==<br />
<br />
杨耀(iamyangyao@163.com),阎志涛(zhitao.yan@gmail.com),王文中(wangwenzhong@ymail.com)<br />
<br />
<br />
<br />
{{建立分类用深度网络}}<br />
<br />
<br />
{{Languages|Self-Taught_Learning_to_Deep_Networks|English}}</div>
Kandeng
http://ufldl.stanford.edu/wiki/index.php/UFLDL%E6%95%99%E7%A8%8B
UFLDL教程
2013-04-10T00:26:05Z
<p>Kandeng: </p>
<hr />
<div>'''说明:'''本教程将阐述无监督特征学习和深度学习的主要观点。通过学习,你也将实现多个功能学习/深度学习算法,能看到它们为你工作,并学习如何应用/适应这些想法到新问题上。<br />
<br />
本教程假定机器学习的基本知识(特别是熟悉的监督学习,逻辑回归,梯度下降的想法),如果你不熟悉这些想法,我们建议你去这里 <br />
<br />
[http://openclassroom.stanford.edu/MainFolder/CoursePage.php?course=MachineLearning 机器学习课程],并先完成第II,III,IV章(到逻辑回归)。<br />
<br />
<br />
'''稀疏自编码器'''<br />
* [[神经网络]]<br />
* [[反向传导算法]]<br />
* [[梯度检验与高级优化]]<br />
* [[自编码算法与稀疏性]]<br />
* [[可视化自编码器训练结果]]<br />
* [[稀疏自编码器符号一览表]] <br />
* [[Exercise:Sparse Autoencoder]]<br />
<br />
<br />
'''矢量化编程实现'''<br />
* [[矢量化编程]]<br />
* [[逻辑回归的向量化实现样例]]<br />
* [[神经网络向量化]]<br />
* [[Exercise:Vectorization]]<br />
<br />
<br />
'''预处理:主成分分析与白化'''<br />
* [[主成分分析]]<br />
* [[白化]]<br />
* [[实现主成分分析和白化]]<br />
* [[Exercise:PCA in 2D]]<br />
* [[Exercise:PCA and Whitening]]<br />
<br />
<br />
'''Softmax回归'''<br />
* [[Softmax回归]]<br />
* [[Exercise:Softmax Regression]]<br />
<br />
<br />
'''自我学习与无监督特征学习''' <br />
* [[自我学习]]<br />
* [[Exercise:Self-Taught Learning]]<br />
<br />
<br />
'''建立分类用深度网络'''<br />
* [[从自我学习到深层网络]]<br />
* [[深度网络概览]]<br />
* [[栈式自编码算法]]<br />
* [[微调多层自编码算法]]<br />
* [[Exercise: Implement deep networks for digit classification]]<br />
<br />
<br />
'''自编码线性解码器'''<br />
* [[线性解码器]]<br />
* [[Exercise:Learning color features with Sparse Autoencoders]]<br />
<br />
<br />
'''处理大型图像'''<br />
* [[卷积特征提取]]<br />
* [[池化]]<br />
* [[Exercise:Convolution and Pooling]]<br />
<br />
<br />
----<br />
'''注意''': 这条线以上的章节是稳定的。下面的章节仍在建设中,如有变更,恕不另行通知。请随意浏览周围并欢迎提交反馈/建议。<br />
<br />
<br />
'''混杂的'''<br />
* [[MATLAB Modules]]<br />
* [[Style Guide]]<br />
* [[Useful Links]]<br />
<br />
'''混杂的主题'''<br />
* [[数据预处理]]<br />
* [[用反向传导思想求导]]<br />
<br />
<br />
'''进阶主题''':<br />
<br />
'''稀疏编码'''<br />
* [[稀疏编码]]<br />
* [[稀疏编码自编码表达]]<br />
* [[Exercise:Sparse Coding]]<br />
<br />
'''独立成分分析样式建模'''<br />
* [[独立成分分析]]<br />
* [[Exercise:Independent Component Analysis]]<br />
<br />
'''其它'''<br />
* [[Convolutional training]] <br />
* [[Restricted Boltzmann Machines]]<br />
* [[Deep Belief Networks]]<br />
* [[Denoising Autoencoders]]<br />
* [[K-means]]<br />
* [[Spatial pyramids / Multiscale]]<br />
* [[Slow Feature Analysis]]<br />
* [[Tiled Convolution Networks]]<br />
<br />
<br />
----<br />
<br />
英文原文作者: Andrew Ng, Jiquan Ngiam, Chuan Yu Foo, Yifan Mai, Caroline Suen<br />
<br />
<br />
{{Languages|UFLDL_Tutorial|English}}</div>
Kandeng
http://ufldl.stanford.edu/wiki/index.php/%E5%8F%8D%E5%90%91%E4%BC%A0%E5%AF%BC%E7%AE%97%E6%B3%95
反向传导算法
2013-04-09T14:59:10Z
<p>Kandeng: </p>
<hr />
<div>假设我们有一个固定样本集 <math>\textstyle \{ (x^{(1)}, y^{(1)}), \ldots, (x^{(m)}, y^{(m)}) \}</math>,它包含 <math>\textstyle m</math> 个样例。我们可以用批量梯度下降法来求解神经网络。具体来讲,对于单个样例 <math>\textstyle (x,y)</math>,其代价函数为:<br />
<br />
:<math><br />
\begin{align}<br />
J(W,b; x,y) = \frac{1}{2} \left\| h_{W,b}(x) - y \right\|^2.<br />
\end{align}<br />
</math><br />
<br />
这是一个(二分之一的)方差代价函数。给定一个包含 <math>\textstyle m</math> 个样例的数据集,我们可以定义整体代价函数为:<br />
<br />
:<math> <br />
\begin{align}<br />
J(W,b)<br />
&= \left[ \frac{1}{m} \sum_{i=1}^m J(W,b;x^{(i)},y^{(i)}) \right]<br />
+ \frac{\lambda}{2} \sum_{l=1}^{n_l-1} \; \sum_{i=1}^{s_l} \; \sum_{j=1}^{s_{l+1}} \left( W^{(l)}_{ji} \right)^2<br />
\\<br />
&= \left[ \frac{1}{m} \sum_{i=1}^m \left( \frac{1}{2} \left\| h_{W,b}(x^{(i)}) - y^{(i)} \right\|^2 \right) \right]<br />
+ \frac{\lambda}{2} \sum_{l=1}^{n_l-1} \; \sum_{i=1}^{s_l} \; \sum_{j=1}^{s_{l+1}} \left( W^{(l)}_{ji} \right)^2<br />
\end{align}<br />
</math><br />
<br />
以上公式中的第一项 <math>\textstyle J(W,b)</math> 是一个均方差项。第二项是一个规则化项(也叫'''权重衰减项'''),其目的是减小权重的幅度,防止过度拟合。<br />
<br />
<br />
[注:通常权重衰减的计算并不使用偏置项 <math>\textstyle b^{(l)}_i</math>,比如我们在 <math>\textstyle J(W, b)</math> 的定义中就没有使用。一般来说,将偏置项包含在权重衰减项中只会对最终的神经网络产生很小的影响。如果你在斯坦福选修过CS229(机器学习)课程,或者在YouTube上看过课程视频,你会发现这个权重衰减实际上是课上提到的贝叶斯规则化方法的变种。在贝叶斯规则化方法中,我们将高斯先验概率引入到参数中计算MAP(极大后验)估计(而不是极大似然估计)。]<br />
<br />
<br />
'''权重衰减参数''' <math>\textstyle \lambda</math> 用于控制公式中两项的相对重要性。在此重申一下这两个复杂函数的含义:<math>\textstyle J(W,b;x,y)</math> 是针对单个样例计算得到的方差代价函数;<math>\textstyle J(W,b)</math> 是整体样本代价函数,它包含权重衰减项。<br />
<br />
<br />
以上的代价函数经常被用于分类和回归问题。在分类问题中,我们用 <math>\textstyle y = 0</math> 或 <math>\textstyle 1</math>,来代表两种类型的标签(回想一下,这是因为 sigmoid激活函数的值域为 <math>\textstyle [0,1]</math>;如果我们使用双曲正切型激活函数,那么应该选用 <math>\textstyle -1</math> 和 <math>\textstyle +1</math> 作为标签)。对于回归问题,我们首先要变换输出值域(译者注:也就是 <math>\textstyle y</math>),以保证其范围为 <math>\textstyle [0,1]</math> (同样地,如果我们使用双曲正切型激活函数,要使输出值域为 <math>\textstyle [-1,1]</math>)。<br />
<br />
<br />
我们的目标是针对参数 <math>\textstyle W</math> 和 <math>\textstyle b</math> 来求其函数 <math>\textstyle J(W,b)</math> 的最小值。为了求解神经网络,我们需要将每一个参数 <math>\textstyle W^{(l)}_{ij}</math> 和 <math>\textstyle b^{(l)}_i</math> 初始化为一个很小的、接近零的随机值(比如说,使用正态分布 <math>\textstyle {Normal}(0,\epsilon^2)</math> 生成的随机值,其中 <math>\textstyle \epsilon</math> 设置为 <math>\textstyle 0.01</math> ),之后对目标函数使用诸如批量梯度下降法的最优化算法。因为 <math>\textstyle J(W, b)</math> 是一个非凸函数,梯度下降法很可能会收敛到局部最优解;但是在实际应用中,梯度下降法通常能得到令人满意的结果。最后,需要再次强调的是,要将参数进行随机初始化,而不是全部置为 <math>\textstyle 0</math>。如果所有参数都用相同的值作为初始值,那么所有隐藏层单元最终会得到与输入值有关的、相同的函数(也就是说,对于所有 <math>\textstyle i</math>,<math>\textstyle W^{(1)}_{ij}</math>都会取相同的值,那么对于任何输入 <math>\textstyle x</math> 都会有:<math>\textstyle a^{(2)}_1 = a^{(2)}_2 = a^{(2)}_3 = \ldots</math> )。随机初始化的目的是使'''对称失效'''。<br />
<br />
<br />
梯度下降法中每一次迭代都按照如下公式对参数 <math>\textstyle W</math> 和<math>\textstyle b</math> 进行更新:<br />
<br />
:<math><br />
\begin{align}<br />
W_{ij}^{(l)} &= W_{ij}^{(l)} - \alpha \frac{\partial}{\partial W_{ij}^{(l)}} J(W,b) \\<br />
b_{i}^{(l)} &= b_{i}^{(l)} - \alpha \frac{\partial}{\partial b_{i}^{(l)}} J(W,b)<br />
\end{align}<br />
</math> <br />
<br />
其中 <math>\textstyle \alpha</math> 是学习速率。其中关键步骤是计算偏导数。我们现在来讲一下'''反向传播'''算法,它是计算偏导数的一种有效方法。<br />
<br />
<br />
我们首先来讲一下如何使用反向传播算法来计算 <math>\textstyle \frac{\partial}{\partial W_{ij}^{(l)}} J(W,b; x, y)</math> 和 <math>\textstyle \frac{\partial}{\partial b_{i}^{(l)}} J(W,b; x, y)</math>,这两项是单个样例 <math>\textstyle (x,y)</math> 的代价函数 <math>\textstyle J(W,b;x,y)</math> 的偏导数。一旦我们求出该偏导数,就可以推导出整体代价函数 <math>\textstyle J(W,b)</math> 的偏导数:<br />
<br />
<br />
:<math><br />
\begin{align}<br />
\frac{\partial}{\partial W_{ij}^{(l)}} J(W,b) &=<br />
\left[ \frac{1}{m} \sum_{i=1}^m \frac{\partial}{\partial W_{ij}^{(l)}} J(W,b; x^{(i)}, y^{(i)}) \right] + \lambda W_{ij}^{(l)} \\<br />
\frac{\partial}{\partial b_{i}^{(l)}} J(W,b) &=<br />
\frac{1}{m}\sum_{i=1}^m \frac{\partial}{\partial b_{i}^{(l)}} J(W,b; x^{(i)}, y^{(i)})<br />
\end{align}<br />
</math> <br />
<br />
以上两行公式稍有不同,第一行比第二行多出一项,是因为权重衰减是作用于 <math>\textstyle W</math> 而不是 <math>\textstyle b</math>。<br />
<br />
<br />
反向传播算法的思路如下:给定一个样例 <math>\textstyle (x,y)</math>,我们首先进行“前向传导”运算,计算出网络中所有的激活值,包括 <math>\textstyle h_{W,b}(x)</math> 的输出值。之后,针对第 <math>\textstyle l</math> 层的每一个节点 <math>\textstyle i</math>,我们计算出其“残差” <math>\textstyle \delta^{(l)}_i</math>,该残差表明了该节点对最终输出值的残差产生了多少影响。对于最终的输出节点,我们可以直接算出网络产生的激活值与实际值之间的差距,我们将这个差距定义为 <math>\textstyle \delta^{(n_l)}_i</math> (第 <math>\textstyle n_l</math> 层表示输出层)。对于隐藏单元我们如何处理呢?我们将基于节点(译者注:第 <math>\textstyle l+1</math> 层节点)残差的加权平均值计算 <math>\textstyle \delta^{(l)}_i</math>,这些节点以 <math>\textstyle a^{(l)}_i</math> 作为输入。下面将给出反向传导算法的细节:<br />
<br />
<br />
<ol><br />
<li>进行前馈传导计算,利用前向传导公式,得到 <math>\textstyle L_2, L_3, \ldots </math> 直到输出层 <math>\textstyle L_{n_l}</math> 的激活值。<br />
<li>对于第 <math>\textstyle n_l</math> 层(输出层)的每个输出单元 <math>\textstyle i</math>,我们根据以下公式计算残差:<br />
<br />
<br />
:<math><br />
\begin{align}<br />
\delta^{(n_l)}_i<br />
= \frac{\partial}{\partial z^{(n_l)}_i} \;\;<br />
\frac{1}{2} \left\|y - h_{W,b}(x)\right\|^2 = - (y_i - a^{(n_l)}_i) \cdot f'(z^{(n_l)}_i)<br />
\end{align}<br />
</math><br />
<br />
[译者注:<br />
:<math> <br />
\begin{align}<br />
\delta^{(n_l)}_i &= \frac{\partial}{\partial z^{n_l}_i}J(W,b;x,y)<br />
= \frac{\partial}{\partial z^{n_l}_i}\frac{1}{2} \left\|y - h_{W,b}(x)\right\|^2 \\<br />
&= \frac{\partial}{\partial z^{n_l}_i}\frac{1}{2} \sum_{j=1}^{S_{n_l}} (y_j-a_j^{(n_l)})^2<br />
= \frac{\partial}{\partial z^{n_l}_i}\frac{1}{2} \sum_{j=1}^{S_{n_l}} (y_j-f(z_j^{(n_l)}))^2 \\<br />
&= - (y_i - f(z_j^{(n_l)})) \cdot f'(z^{(n_l)}_i)<br />
= - (y_i - a^{(n_l)}_i) \cdot f'(z^{(n_l)}_i)<br />
\end{align}<br />
</math> <br />
]<br />
<br />
<li>对 <math>\textstyle l = n_l-1, n_l-2, n_l-3, \ldots, 2</math> 的各个层,第 <math>\textstyle l</math> 层的第 <math>\textstyle i</math> 个节点的残差计算方法如下:<br />
: <math> <br />
\delta^{(l)}_i = \left( \sum_{j=1}^{s_{l+1}} W^{(l)}_{ji} \delta^{(l+1)}_j \right) f'(z^{(l)}_i)<br />
</math> <br />
<br />
{译者注:<br />
:<math> <br />
\begin{align}<br />
\delta^{(n_l-1)}_i &=\frac{\partial}{\partial z^{n_l-1}_i}J(W,b;x,y)<br />
= \frac{\partial}{\partial z^{n_l-1}_i}\frac{1}{2} \left\|y - h_{W,b}(x)\right\|^2 <br />
= \frac{\partial}{\partial z^{n_l-1}_i}\frac{1}{2} \sum_{j=1}^{S_{n_l}}(y_j-a_j^{(n_l)})^2 \\<br />
&= \frac{1}{2} \sum_{j=1}^{S_{n_l}}\frac{\partial}{\partial z^{n_l-1}_i}(y_i-a_j^{(n_l)})^2<br />
= \frac{1}{2} \sum_{j=1}^{S_{n_l}}\frac{\partial}{\partial z^{n_l-1}_i}(y_i-f(z_j^{(n_l)})^2 \\<br />
&= \sum_{j=1}^{S_{n_l}}(y_j-f(z_j^{(n_l)}) \cdot \frac{\partial}{\partial z_i^{(n_l-1)}}f(z_j^{(n_l)})<br />
= \sum_{j=1}^{S_{n_l}}(y_j-f(z_j^{(n_l)}) \cdot f'(z_j^{(n_l)}) \cdot \frac{\partial z_j^{(n_l)}}{\partial z_i^{(n_l-1)}} \\<br />
&= \sum_{j=1}^{S_{n_l}} \delta_j^{(n_l)} \cdot \frac{\partial z_j^{(n_l)}}{z_i^{n_l-1}}<br />
= \sum_{j=1}^{S_{n_l}} \left(\delta_j^{(n_l)} \cdot \frac{\partial}{\partial z_i^{n_l-1}}\sum_{k=1}^{S_{n_l-1}}f(z_k^{n_l-1}) \cdot W_{jk}^{n_l-1}\right) \\<br />
&= \sum_{j=1}^{S_{n_l}} \delta_j^{(n_l)} \cdot W_{ji}^{n_l-1} \cdot f'(z_i^{n_l-1})<br />
= \left(\sum_{j=1}^{S_{n_l-1}}W_{ji}^{n_l-1}\delta_j^{(n_l)}\right)f'(z_i^{n_l-1})<br />
\end{align}<br />
</math> <br />
<br />
将上式中的<math>\textstyle n_l-1</math>与<math>\textstyle n_l</math>的关系替换为<math>\textstyle l</math>与<math>\textstyle l-1</math>的关系,就可以得到:<br />
: <math> <br />
\delta^{(l)}_i = \left( \sum_{j=1}^{s_{l+1}} W^{(l)}_{ji} \delta^{(l+1)}_j \right) f'(z^{(l)}_i)<br />
</math> <br />
以上逐次从后向前求导的过程即为“反向传导”的本意所在。<br />
<br />
]<br />
<br />
<br />
<br />
<li>计算我们需要的偏导数,计算方法如下:<br />
:<math> <br />
\begin{align}<br />
\frac{\partial}{\partial W_{ij}^{(l)}} J(W,b; x, y) &= a^{(l)}_j \delta_i^{(l+1)} \\<br />
\frac{\partial}{\partial b_{i}^{(l)}} J(W,b; x, y) &= \delta_i^{(l+1)}.<br />
\end{align}<br />
</math> <br />
</ol><br />
<br />
<br />
最后,我们用矩阵-向量表示法重写以上算法。我们使用“<math>\textstyle \bullet</math>” 表示向量乘积运算符(在Matlab或Octave里用“<tt>.*</tt>”表示,也称作阿达马乘积)。若 <math>\textstyle a = b \bullet c</math>,则 <math>\textstyle a_i = b_ic_i</math>。在上一个教程中我们扩展了 <math>\textstyle f(\cdot)</math> 的定义,使其包含向量运算,这里我们也对偏导数 <math>\textstyle f'(\cdot)</math> 也做了同样的处理(于是又有 <math> \textstyle f'([z_1, z_2, z_3]) = [f'(z_1), f'(z_2), f'(z_3)]</math> )。<br />
<br />
<br />
那么,反向传播算法可表示为以下几个步骤:<br />
<br />
<ol><br />
<li>进行前馈传导计算,利用前向传导公式,得到 <math>\textstyle L_2, L_3, \ldots</math>直到输出层 <math>\textstyle L_{n_l}</math> 的激活值。<br />
<br />
<li>对输出层(第 <math>\textstyle n_l</math> 层),计算:<br />
<br />
:<math> \begin{align}<br />
\delta^{(n_l)}<br />
= - (y - a^{(n_l)}) \bullet f'(z^{(n_l)})<br />
\end{align}</math> <br />
<br />
<li>对于 <math>\textstyle l = n_l-1, n_l-2, n_l-3, \ldots, 2</math> 的各层,计算:<br />
:<math> \begin{align}<br />
\delta^{(l)} = \left((W^{(l)})^T \delta^{(l+1)}\right) \bullet f'(z^{(l)})<br />
\end{align}</math> <br />
<br />
<li>计算最终需要的偏导数值:<br />
:<math> \begin{align}<br />
\nabla_{W^{(l)}} J(W,b;x,y) &= \delta^{(l+1)} (a^{(l)})^T, \\<br />
\nabla_{b^{(l)}} J(W,b;x,y) &= \delta^{(l+1)}.<br />
\end{align}</math> <br />
</ol><br />
<br />
<br />
'''实现中应注意:'''在以上的第2步和第3步中,我们需要为每一个 <math>\textstyle i</math> 值计算其 <math>\textstyle f'(z^{(l)}_i)</math>。假设 <math>\textstyle f(z)</math> 是sigmoid函数,并且我们已经在前向传导运算中得到了 <math>\textstyle a^{(l)}_i</math>。那么,使用我们早先推导出的 <math>\textstyle f'(z)</math>表达式,就可以计算得到 <math>\textstyle f'(z^{(l)}_i) = a^{(l)}_i (1- a^{(l)}_i)</math>。<br />
<br />
<br />
最后,我们将对梯度下降算法做个全面总结。在下面的伪代码中,<math>\textstyle \Delta W^{(l)}</math> 是一个与矩阵 <math>\textstyle W^{(l)}</math> 维度相同的矩阵,<math>\textstyle \Delta b^{(l)}</math> 是一个与 <math>\textstyle b^{(l)}</math> 维度相同的向量。注意这里“<math>\textstyle \Delta W^{(l)}</math>”是一个矩阵,而不是“<math>\textstyle \Delta</math> 与 <math>\textstyle W^{(l)}</math> 相乘”。下面,我们实现批量梯度下降法中的一次迭代:<br />
<br />
<br />
<ol><br />
<li>对于所有 <math>\textstyle l</math>,令 <math>\textstyle \Delta W^{(l)} := 0</math> , <math>\textstyle \Delta b^{(l)} := 0</math> (设置为全零矩阵或全零向量)<br />
<br />
<li>对于 <math>\textstyle i = 1</math> 到 <math>\textstyle m</math>,<br />
<br />
<ol type="a"><br />
<li>使用反向传播算法计算 <math>\textstyle \nabla_{W^{(l)}} J(W,b;x,y)</math> 和 <math>\textstyle \nabla_{b^{(l)}} J(W,b;x,y)</math>。<br />
<li>计算 <math>\textstyle \Delta W^{(l)} := \Delta W^{(l)} + \nabla_{W^{(l)}} J(W,b;x,y)</math>。<br />
<li>计算 <math>\textstyle \Delta b^{(l)} := \Delta b^{(l)} + \nabla_{b^{(l)}} J(W,b;x,y)</math>。 <br />
</ol><br />
<br />
<li>更新权重参数:<br />
:<math> \begin{align}<br />
W^{(l)} &= W^{(l)} - \alpha \left[ \left(\frac{1}{m} \Delta W^{(l)} \right) + \lambda W^{(l)}\right] \\<br />
b^{(l)} &= b^{(l)} - \alpha \left[\frac{1}{m} \Delta b^{(l)}\right]<br />
\end{align}</math> <br />
</ol><br />
<br />
现在,我们可以重复梯度下降法的迭代步骤来减小代价函数 <math>\textstyle J(W,b)</math> 的值,进而求解我们的神经网络。<br />
<br />
<br />
==中英文对照==<br />
<br />
:反向传播算法 Backpropagation Algorithm<br />
:(批量)梯度下降法 (batch) gradient descent<br />
:(整体)代价函数 (overall) cost function<br />
:方差 squared-error<br />
:均方差 average sum-of-squares error<br />
:规则化项 regularization term<br />
:权重衰减 weight decay<br />
:偏置项 bias terms<br />
:贝叶斯规则化方法 Bayesian regularization method<br />
:高斯先验概率 Gaussian prior<br />
:极大后验估计 MAP<br />
:极大似然估计 maximum likelihood estimation<br />
:激活函数 activation function<br />
:双曲正切函数 tanh function<br />
:非凸函数 non-convex function<br />
:隐藏层单元 hidden (layer) units<br />
:对称失效 symmetry breaking<br />
:学习速率 learning rate<br />
:前向传导 forward pass<br />
:假设值 hypothesis <br />
:残差 error term<br />
:加权平均值 weighted average <br />
:前馈传导 feedforward pass<br />
:阿达马乘积 Hadamard product<br />
:前向传播 forward propagation<br />
<br />
<br />
==中文译者==<br />
<br />
王方(fangkey@gmail.com),林锋(xlfg@yeah.net),许利杰(csxulijie@gmail.com)<br />
<br />
<br />
{{稀疏自编码器}}<br />
<br />
<br />
<br />
{{Languages|Backpropagation_Algorithm|English}}</div>
Kandeng
http://ufldl.stanford.edu/wiki/index.php/%E5%8F%8D%E5%90%91%E4%BC%A0%E5%AF%BC%E7%AE%97%E6%B3%95
反向传导算法
2013-04-09T14:57:56Z
<p>Kandeng: </p>
<hr />
<div>假设我们有一个固定样本集 <math>\textstyle \{ (x^{(1)}, y^{(1)}), \ldots, (x^{(m)}, y^{(m)}) \}</math>,它包含 <math>\textstyle m</math> 个样例。我们可以用批量梯度下降法来求解神经网络。具体来讲,对于单个样例 <math>\textstyle (x,y)</math>,其代价函数为:<br />
<br />
:<math><br />
\begin{align}<br />
J(W,b; x,y) = \frac{1}{2} \left\| h_{W,b}(x) - y \right\|^2.<br />
\end{align}<br />
</math><br />
<br />
这是一个(二分之一的)方差代价函数。给定一个包含 <math>\textstyle m</math> 个样例的数据集,我们可以定义整体代价函数为:<br />
<br />
:<math> <br />
\begin{align}<br />
J(W,b)<br />
&= \left[ \frac{1}{m} \sum_{i=1}^m J(W,b;x^{(i)},y^{(i)}) \right]<br />
+ \frac{\lambda}{2} \sum_{l=1}^{n_l-1} \; \sum_{i=1}^{s_l} \; \sum_{j=1}^{s_{l+1}} \left( W^{(l)}_{ji} \right)^2<br />
\\<br />
&= \left[ \frac{1}{m} \sum_{i=1}^m \left( \frac{1}{2} \left\| h_{W,b}(x^{(i)}) - y^{(i)} \right\|^2 \right) \right]<br />
+ \frac{\lambda}{2} \sum_{l=1}^{n_l-1} \; \sum_{i=1}^{s_l} \; \sum_{j=1}^{s_{l+1}} \left( W^{(l)}_{ji} \right)^2<br />
\end{align}<br />
</math><br />
<br />
以上公式中的第一项 <math>\textstyle J(W,b)</math> 是一个均方差项。第二项是一个规则化项(也叫'''权重衰减项'''),其目的是减小权重的幅度,防止过度拟合。<br />
<br />
<br />
[注:通常权重衰减的计算并不使用偏置项 <math>\textstyle b^{(l)}_i</math>,比如我们在 <math>\textstyle J(W, b)</math> 的定义中就没有使用。一般来说,将偏置项包含在权重衰减项中只会对最终的神经网络产生很小的影响。如果你在斯坦福选修过CS229(机器学习)课程,或者在YouTube上看过课程视频,你会发现这个权重衰减实际上是课上提到的贝叶斯规则化方法的变种。在贝叶斯规则化方法中,我们将高斯先验概率引入到参数中计算MAP(极大后验)估计(而不是极大似然估计)。]<br />
<br />
<br />
'''权重衰减参数''' <math>\textstyle \lambda</math> 用于控制公式中两项的相对重要性。在此重申一下这两个复杂函数的含义:<math>\textstyle J(W,b;x,y)</math> 是针对单个样例计算得到的方差代价函数;<math>\textstyle J(W,b)</math> 是整体样本代价函数,它包含权重衰减项。<br />
<br />
<br />
以上的代价函数经常被用于分类和回归问题。在分类问题中,我们用 <math>\textstyle y = 0</math> 或 <math>\textstyle 1</math>,来代表两种类型的标签(回想一下,这是因为 sigmoid激活函数的值域为 <math>\textstyle [0,1]</math>;如果我们使用双曲正切型激活函数,那么应该选用 <math>\textstyle -1</math> 和 <math>\textstyle +1</math> 作为标签)。对于回归问题,我们首先要变换输出值域(译者注:也就是 <math>\textstyle y</math>),以保证其范围为 <math>\textstyle [0,1]</math> (同样地,如果我们使用双曲正切型激活函数,要使输出值域为 <math>\textstyle [-1,1]</math>)。<br />
<br />
<br />
我们的目标是针对参数 <math>\textstyle W</math> 和 <math>\textstyle b</math> 来求其函数 <math>\textstyle J(W,b)</math> 的最小值。为了求解神经网络,我们需要将每一个参数 <math>\textstyle W^{(l)}_{ij}</math> 和 <math>\textstyle b^{(l)}_i</math> 初始化为一个很小的、接近零的随机值(比如说,使用正态分布 <math>\textstyle {Normal}(0,\epsilon^2)</math> 生成的随机值,其中 <math>\textstyle \epsilon</math> 设置为 <math>\textstyle 0.01</math> ),之后对目标函数使用诸如批量梯度下降法的最优化算法。因为 <math>\textstyle J(W, b)</math> 是一个非凸函数,梯度下降法很可能会收敛到局部最优解;但是在实际应用中,梯度下降法通常能得到令人满意的结果。最后,需要再次强调的是,要将参数进行随机初始化,而不是全部置为 <math>\textstyle 0</math>。如果所有参数都用相同的值作为初始值,那么所有隐藏层单元最终会得到与输入值有关的、相同的函数(也就是说,对于所有 <math>\textstyle i</math>,<math>\textstyle W^{(1)}_{ij}</math>都会取相同的值,那么对于任何输入 <math>\textstyle x</math> 都会有:<math>\textstyle a^{(2)}_1 = a^{(2)}_2 = a^{(2)}_3 = \ldots</math> )。随机初始化的目的是使'''对称失效'''。<br />
<br />
<br />
梯度下降法中每一次迭代都按照如下公式对参数 <math>\textstyle W</math> 和<math>\textstyle b</math> 进行更新:<br />
<br />
:<math><br />
\begin{align}<br />
W_{ij}^{(l)} &= W_{ij}^{(l)} - \alpha \frac{\partial}{\partial W_{ij}^{(l)}} J(W,b) \\<br />
b_{i}^{(l)} &= b_{i}^{(l)} - \alpha \frac{\partial}{\partial b_{i}^{(l)}} J(W,b)<br />
\end{align}<br />
</math> <br />
<br />
其中 <math>\textstyle \alpha</math> 是学习速率。其中关键步骤是计算偏导数。我们现在来讲一下'''反向传播'''算法,它是计算偏导数的一种有效方法。<br />
<br />
<br />
我们首先来讲一下如何使用反向传播算法来计算 <math>\textstyle \frac{\partial}{\partial W_{ij}^{(l)}} J(W,b; x, y)</math> 和 <math>\textstyle \frac{\partial}{\partial b_{i}^{(l)}} J(W,b; x, y)</math>,这两项是单个样例 <math>\textstyle (x,y)</math> 的代价函数 <math>\textstyle J(W,b;x,y)</math> 的偏导数。一旦我们求出该偏导数,就可以推导出整体代价函数 <math>\textstyle J(W,b)</math> 的偏导数:<br />
<br />
<br />
:<math><br />
\begin{align}<br />
\frac{\partial}{\partial W_{ij}^{(l)}} J(W,b) &=<br />
\left[ \frac{1}{m} \sum_{i=1}^m \frac{\partial}{\partial W_{ij}^{(l)}} J(W,b; x^{(i)}, y^{(i)}) \right] + \lambda W_{ij}^{(l)} \\<br />
\frac{\partial}{\partial b_{i}^{(l)}} J(W,b) &=<br />
\frac{1}{m}\sum_{i=1}^m \frac{\partial}{\partial b_{i}^{(l)}} J(W,b; x^{(i)}, y^{(i)})<br />
\end{align}<br />
</math> <br />
<br />
以上两行公式稍有不同,第一行比第二行多出一项,是因为权重衰减是作用于 <math>\textstyle W</math> 而不是 <math>\textstyle b</math>。<br />
<br />
<br />
反向传播算法的思路如下:给定一个样例 <math>\textstyle (x,y)</math>,我们首先进行“前向传导”运算,计算出网络中所有的激活值,包括 <math>\textstyle h_{W,b}(x)</math> 的输出值。之后,针对第 <math>\textstyle l</math> 层的每一个节点 <math>\textstyle i</math>,我们计算出其“残差” <math>\textstyle \delta^{(l)}_i</math>,该残差表明了该节点对最终输出值的残差产生了多少影响。对于最终的输出节点,我们可以直接算出网络产生的激活值与实际值之间的差距,我们将这个差距定义为 <math>\textstyle \delta^{(n_l)}_i</math> (第 <math>\textstyle n_l</math> 层表示输出层)。对于隐藏单元我们如何处理呢?我们将基于节点(译者注:第 <math>\textstyle l+1</math> 层节点)残差的加权平均值计算 <math>\textstyle \delta^{(l)}_i</math>,这些节点以 <math>\textstyle a^{(l)}_i</math> 作为输入。下面将给出反向传导算法的细节:<br />
<br />
<br />
<ol><br />
<li>进行前馈传导计算,利用前向传导公式,得到 <math>\textstyle L_2, L_3, \ldots </math> 直到输出层 <math>\textstyle L_{n_l}</math> 的激活值。<br />
<li>对于第 <math>\textstyle n_l</math> 层(输出层)的每个输出单元 <math>\textstyle i</math>,我们根据以下公式计算残差:<br />
<br />
<br />
:<math><br />
\begin{align}<br />
\delta^{(n_l)}_i<br />
= \frac{\partial}{\partial z^{(n_l)}_i} \;\;<br />
\frac{1}{2} \left\|y - h_{W,b}(x)\right\|^2 = - (y_i - a^{(n_l)}_i) \cdot f'(z^{(n_l)}_i)<br />
\end{align}<br />
</math><br />
<br />
[译者注:<br />
:<math> <br />
\begin{align}<br />
\delta^{(n_l)}_i &= \frac{\partial}{\partial z^{n_l}_i}J(W,b;x,y)<br />
= \frac{\partial}{\partial z^{n_l}_i}\frac{1}{2} \left\|y - h_{W,b}(x)\right\|^2 \\<br />
&= \frac{\partial}{\partial z^{n_l}_i}\frac{1}{2} \sum_{j=1}^{S_{n_l}} (y_j-a_j^{(n_l)})^2<br />
= \frac{\partial}{\partial z^{n_l}_i}\frac{1}{2} \sum_{j=1}^{S_{n_l}} (y_j-f(z_j^{(n_l)}))^2 \\<br />
&= - (y_i - f(z_j^{(n_l)})) \cdot f'(z^{(n_l)}_i)<br />
= - (y_i - a^{(n_l)}_i) \cdot f'(z^{(n_l)}_i)<br />
\end{align}<br />
</math> <br />
]<br />
<br />
<li>对 <math>\textstyle l = n_l-1, n_l-2, n_l-3, \ldots, 2</math> 的各个层,第 <math>\textstyle l</math> 层的第 <math>\textstyle i</math> 个节点的残差计算方法如下:<br />
: <math> <br />
\delta^{(l)}_i = \left( \sum_{j=1}^{s_{l+1}} W^{(l)}_{ji} \delta^{(l+1)}_j \right) f'(z^{(l)}_i)<br />
</math> <br />
<br />
{译者注:<br />
:<math> <br />
\begin{align}<br />
\delta^{(n_l-1)}_i &=\frac{\partial}{\partial z^{n_l-1}_i}J(W,b;x,y)<br />
= \frac{\partial}{\partial z^{n_l-1}_i}\frac{1}{2} \left\|y - h_{W,b}(x)\right\|^2 <br />
= \frac{\partial}{\partial z^{n_l-1}_i}\frac{1}{2} \sum_{j=1}^{S_{n_l}}(y_j-a_j^{(n_l)})^2 \\<br />
&= \frac{1}{2} \sum_{j=1}^{S_{n_l}}\frac{\partial}{\partial z^{n_l-1}_i}(y_i-a_j^{(n_l)})^2<br />
= \frac{1}{2} \sum_{j=1}^{S_{n_l}}\frac{\partial}{\partial z^{n_l-1}_i}(y_i-f(z_j^{(n_l)})^2 \\<br />
&= \sum_{j=1}^{S_{n_l}}(y_j-f(z_j^{(n_l)}) \cdot \frac{\partial}{\partial z_i^{(n_l-1)}}f(z_j^{(n_l)})<br />
= \sum_{j=1}^{S_{n_l}}(y_j-f(z_j^{(n_l)}) \cdot f'(z_j^{(n_l)}) \cdot \frac{\partial z_j^{(n_l)}}{\partial z_i^{(n_l-1)}} \\<br />
&= \sum_{j=1}^{S_{n_l}} \delta_j^{(n_l)} \cdot \frac{\partial z_j^{(n_l)}}{z_i^{n_l-1}}<br />
= \sum_{j=1}^{S_{n_l}} \left(\delta_j^{(n_l)} \cdot \frac{\partial}{\partial z_i^{n_l-1}}\sum_{k=1}^{S_{n_l-1}}f(z_k^{n_l-1}) \cdot W_{jk}^{n_l-1}\right) \\<br />
&= \sum_{j=1}^{S_{n_l}} \delta_j^{(n_l)} \cdot W_{ji}^{n_l-1} \cdot f'(z_i^{n_l-1})<br />
= \left(\sum_{j=1}^{S_{n_l-1}}W_{ji}^{n_l-1}\delta_j^{(n_l)}\right)f'(z_i^{n_l-1})<br />
\end{align}<br />
</math> <br />
<br />
将上式中的<math>n_l-1</math>与<math>n_l</math>的关系替换为<math>l</math>与<math>l-1</math>的关系,就可以得到:<br />
: <math> <br />
\delta^{(l)}_i = \left( \sum_{j=1}^{s_{l+1}} W^{(l)}_{ji} \delta^{(l+1)}_j \right) f'(z^{(l)}_i)<br />
</math> <br />
以上逐次从后向前求导的过程即为“反向传导”的本意所在。<br />
<br />
]<br />
<br />
<br />
<br />
<li>计算我们需要的偏导数,计算方法如下:<br />
:<math> <br />
\begin{align}<br />
\frac{\partial}{\partial W_{ij}^{(l)}} J(W,b; x, y) &= a^{(l)}_j \delta_i^{(l+1)} \\<br />
\frac{\partial}{\partial b_{i}^{(l)}} J(W,b; x, y) &= \delta_i^{(l+1)}.<br />
\end{align}<br />
</math> <br />
</ol><br />
<br />
<br />
最后,我们用矩阵-向量表示法重写以上算法。我们使用“<math>\textstyle \bullet</math>” 表示向量乘积运算符(在Matlab或Octave里用“<tt>.*</tt>”表示,也称作阿达马乘积)。若 <math>\textstyle a = b \bullet c</math>,则 <math>\textstyle a_i = b_ic_i</math>。在上一个教程中我们扩展了 <math>\textstyle f(\cdot)</math> 的定义,使其包含向量运算,这里我们也对偏导数 <math>\textstyle f'(\cdot)</math> 也做了同样的处理(于是又有 <math> \textstyle f'([z_1, z_2, z_3]) = [f'(z_1), f'(z_2), f'(z_3)]</math> )。<br />
<br />
<br />
那么,反向传播算法可表示为以下几个步骤:<br />
<br />
<ol><br />
<li>进行前馈传导计算,利用前向传导公式,得到 <math>\textstyle L_2, L_3, \ldots</math>直到输出层 <math>\textstyle L_{n_l}</math> 的激活值。<br />
<br />
<li>对输出层(第 <math>\textstyle n_l</math> 层),计算:<br />
<br />
:<math> \begin{align}<br />
\delta^{(n_l)}<br />
= - (y - a^{(n_l)}) \bullet f'(z^{(n_l)})<br />
\end{align}</math> <br />
<br />
<li>对于 <math>\textstyle l = n_l-1, n_l-2, n_l-3, \ldots, 2</math> 的各层,计算:<br />
:<math> \begin{align}<br />
\delta^{(l)} = \left((W^{(l)})^T \delta^{(l+1)}\right) \bullet f'(z^{(l)})<br />
\end{align}</math> <br />
<br />
<li>计算最终需要的偏导数值:<br />
:<math> \begin{align}<br />
\nabla_{W^{(l)}} J(W,b;x,y) &= \delta^{(l+1)} (a^{(l)})^T, \\<br />
\nabla_{b^{(l)}} J(W,b;x,y) &= \delta^{(l+1)}.<br />
\end{align}</math> <br />
</ol><br />
<br />
<br />
'''实现中应注意:'''在以上的第2步和第3步中,我们需要为每一个 <math>\textstyle i</math> 值计算其 <math>\textstyle f'(z^{(l)}_i)</math>。假设 <math>\textstyle f(z)</math> 是sigmoid函数,并且我们已经在前向传导运算中得到了 <math>\textstyle a^{(l)}_i</math>。那么,使用我们早先推导出的 <math>\textstyle f'(z)</math>表达式,就可以计算得到 <math>\textstyle f'(z^{(l)}_i) = a^{(l)}_i (1- a^{(l)}_i)</math>。<br />
<br />
<br />
最后,我们将对梯度下降算法做个全面总结。在下面的伪代码中,<math>\textstyle \Delta W^{(l)}</math> 是一个与矩阵 <math>\textstyle W^{(l)}</math> 维度相同的矩阵,<math>\textstyle \Delta b^{(l)}</math> 是一个与 <math>\textstyle b^{(l)}</math> 维度相同的向量。注意这里“<math>\textstyle \Delta W^{(l)}</math>”是一个矩阵,而不是“<math>\textstyle \Delta</math> 与 <math>\textstyle W^{(l)}</math> 相乘”。下面,我们实现批量梯度下降法中的一次迭代:<br />
<br />
<br />
<ol><br />
<li>对于所有 <math>\textstyle l</math>,令 <math>\textstyle \Delta W^{(l)} := 0</math> , <math>\textstyle \Delta b^{(l)} := 0</math> (设置为全零矩阵或全零向量)<br />
<br />
<li>对于 <math>\textstyle i = 1</math> 到 <math>\textstyle m</math>,<br />
<br />
<ol type="a"><br />
<li>使用反向传播算法计算 <math>\textstyle \nabla_{W^{(l)}} J(W,b;x,y)</math> 和 <math>\textstyle \nabla_{b^{(l)}} J(W,b;x,y)</math>。<br />
<li>计算 <math>\textstyle \Delta W^{(l)} := \Delta W^{(l)} + \nabla_{W^{(l)}} J(W,b;x,y)</math>。<br />
<li>计算 <math>\textstyle \Delta b^{(l)} := \Delta b^{(l)} + \nabla_{b^{(l)}} J(W,b;x,y)</math>。 <br />
</ol><br />
<br />
<li>更新权重参数:<br />
:<math> \begin{align}<br />
W^{(l)} &= W^{(l)} - \alpha \left[ \left(\frac{1}{m} \Delta W^{(l)} \right) + \lambda W^{(l)}\right] \\<br />
b^{(l)} &= b^{(l)} - \alpha \left[\frac{1}{m} \Delta b^{(l)}\right]<br />
\end{align}</math> <br />
</ol><br />
<br />
现在,我们可以重复梯度下降法的迭代步骤来减小代价函数 <math>\textstyle J(W,b)</math> 的值,进而求解我们的神经网络。<br />
<br />
<br />
==中英文对照==<br />
<br />
:反向传播算法 Backpropagation Algorithm<br />
:(批量)梯度下降法 (batch) gradient descent<br />
:(整体)代价函数 (overall) cost function<br />
:方差 squared-error<br />
:均方差 average sum-of-squares error<br />
:规则化项 regularization term<br />
:权重衰减 weight decay<br />
:偏置项 bias terms<br />
:贝叶斯规则化方法 Bayesian regularization method<br />
:高斯先验概率 Gaussian prior<br />
:极大后验估计 MAP<br />
:极大似然估计 maximum likelihood estimation<br />
:激活函数 activation function<br />
:双曲正切函数 tanh function<br />
:非凸函数 non-convex function<br />
:隐藏层单元 hidden (layer) units<br />
:对称失效 symmetry breaking<br />
:学习速率 learning rate<br />
:前向传导 forward pass<br />
:假设值 hypothesis <br />
:残差 error term<br />
:加权平均值 weighted average <br />
:前馈传导 feedforward pass<br />
:阿达马乘积 Hadamard product<br />
:前向传播 forward propagation<br />
<br />
<br />
==中文译者==<br />
<br />
王方(fangkey@gmail.com),林锋(xlfg@yeah.net),许利杰(csxulijie@gmail.com)<br />
<br />
<br />
{{稀疏自编码器}}<br />
<br />
<br />
<br />
{{Languages|Backpropagation_Algorithm|English}}</div>
Kandeng
http://ufldl.stanford.edu/wiki/index.php/%E5%8F%8D%E5%90%91%E4%BC%A0%E5%AF%BC%E7%AE%97%E6%B3%95
反向传导算法
2013-04-09T14:56:48Z
<p>Kandeng: </p>
<hr />
<div>假设我们有一个固定样本集 <math>\textstyle \{ (x^{(1)}, y^{(1)}), \ldots, (x^{(m)}, y^{(m)}) \}</math>,它包含 <math>\textstyle m</math> 个样例。我们可以用批量梯度下降法来求解神经网络。具体来讲,对于单个样例 <math>\textstyle (x,y)</math>,其代价函数为:<br />
<br />
:<math><br />
\begin{align}<br />
J(W,b; x,y) = \frac{1}{2} \left\| h_{W,b}(x) - y \right\|^2.<br />
\end{align}<br />
</math><br />
<br />
这是一个(二分之一的)方差代价函数。给定一个包含 <math>\textstyle m</math> 个样例的数据集,我们可以定义整体代价函数为:<br />
<br />
:<math> <br />
\begin{align}<br />
J(W,b)<br />
&= \left[ \frac{1}{m} \sum_{i=1}^m J(W,b;x^{(i)},y^{(i)}) \right]<br />
+ \frac{\lambda}{2} \sum_{l=1}^{n_l-1} \; \sum_{i=1}^{s_l} \; \sum_{j=1}^{s_{l+1}} \left( W^{(l)}_{ji} \right)^2<br />
\\<br />
&= \left[ \frac{1}{m} \sum_{i=1}^m \left( \frac{1}{2} \left\| h_{W,b}(x^{(i)}) - y^{(i)} \right\|^2 \right) \right]<br />
+ \frac{\lambda}{2} \sum_{l=1}^{n_l-1} \; \sum_{i=1}^{s_l} \; \sum_{j=1}^{s_{l+1}} \left( W^{(l)}_{ji} \right)^2<br />
\end{align}<br />
</math><br />
<br />
以上公式中的第一项 <math>\textstyle J(W,b)</math> 是一个均方差项。第二项是一个规则化项(也叫'''权重衰减项'''),其目的是减小权重的幅度,防止过度拟合。<br />
<br />
<br />
[注:通常权重衰减的计算并不使用偏置项 <math>\textstyle b^{(l)}_i</math>,比如我们在 <math>\textstyle J(W, b)</math> 的定义中就没有使用。一般来说,将偏置项包含在权重衰减项中只会对最终的神经网络产生很小的影响。如果你在斯坦福选修过CS229(机器学习)课程,或者在YouTube上看过课程视频,你会发现这个权重衰减实际上是课上提到的贝叶斯规则化方法的变种。在贝叶斯规则化方法中,我们将高斯先验概率引入到参数中计算MAP(极大后验)估计(而不是极大似然估计)。]<br />
<br />
<br />
'''权重衰减参数''' <math>\textstyle \lambda</math> 用于控制公式中两项的相对重要性。在此重申一下这两个复杂函数的含义:<math>\textstyle J(W,b;x,y)</math> 是针对单个样例计算得到的方差代价函数;<math>\textstyle J(W,b)</math> 是整体样本代价函数,它包含权重衰减项。<br />
<br />
<br />
以上的代价函数经常被用于分类和回归问题。在分类问题中,我们用 <math>\textstyle y = 0</math> 或 <math>\textstyle 1</math>,来代表两种类型的标签(回想一下,这是因为 sigmoid激活函数的值域为 <math>\textstyle [0,1]</math>;如果我们使用双曲正切型激活函数,那么应该选用 <math>\textstyle -1</math> 和 <math>\textstyle +1</math> 作为标签)。对于回归问题,我们首先要变换输出值域(译者注:也就是 <math>\textstyle y</math>),以保证其范围为 <math>\textstyle [0,1]</math> (同样地,如果我们使用双曲正切型激活函数,要使输出值域为 <math>\textstyle [-1,1]</math>)。<br />
<br />
<br />
我们的目标是针对参数 <math>\textstyle W</math> 和 <math>\textstyle b</math> 来求其函数 <math>\textstyle J(W,b)</math> 的最小值。为了求解神经网络,我们需要将每一个参数 <math>\textstyle W^{(l)}_{ij}</math> 和 <math>\textstyle b^{(l)}_i</math> 初始化为一个很小的、接近零的随机值(比如说,使用正态分布 <math>\textstyle {Normal}(0,\epsilon^2)</math> 生成的随机值,其中 <math>\textstyle \epsilon</math> 设置为 <math>\textstyle 0.01</math> ),之后对目标函数使用诸如批量梯度下降法的最优化算法。因为 <math>\textstyle J(W, b)</math> 是一个非凸函数,梯度下降法很可能会收敛到局部最优解;但是在实际应用中,梯度下降法通常能得到令人满意的结果。最后,需要再次强调的是,要将参数进行随机初始化,而不是全部置为 <math>\textstyle 0</math>。如果所有参数都用相同的值作为初始值,那么所有隐藏层单元最终会得到与输入值有关的、相同的函数(也就是说,对于所有 <math>\textstyle i</math>,<math>\textstyle W^{(1)}_{ij}</math>都会取相同的值,那么对于任何输入 <math>\textstyle x</math> 都会有:<math>\textstyle a^{(2)}_1 = a^{(2)}_2 = a^{(2)}_3 = \ldots</math> )。随机初始化的目的是使'''对称失效'''。<br />
<br />
<br />
梯度下降法中每一次迭代都按照如下公式对参数 <math>\textstyle W</math> 和<math>\textstyle b</math> 进行更新:<br />
<br />
:<math><br />
\begin{align}<br />
W_{ij}^{(l)} &= W_{ij}^{(l)} - \alpha \frac{\partial}{\partial W_{ij}^{(l)}} J(W,b) \\<br />
b_{i}^{(l)} &= b_{i}^{(l)} - \alpha \frac{\partial}{\partial b_{i}^{(l)}} J(W,b)<br />
\end{align}<br />
</math> <br />
<br />
其中 <math>\textstyle \alpha</math> 是学习速率。其中关键步骤是计算偏导数。我们现在来讲一下'''反向传播'''算法,它是计算偏导数的一种有效方法。<br />
<br />
<br />
我们首先来讲一下如何使用反向传播算法来计算 <math>\textstyle \frac{\partial}{\partial W_{ij}^{(l)}} J(W,b; x, y)</math> 和 <math>\textstyle \frac{\partial}{\partial b_{i}^{(l)}} J(W,b; x, y)</math>,这两项是单个样例 <math>\textstyle (x,y)</math> 的代价函数 <math>\textstyle J(W,b;x,y)</math> 的偏导数。一旦我们求出该偏导数,就可以推导出整体代价函数 <math>\textstyle J(W,b)</math> 的偏导数:<br />
<br />
<br />
:<math><br />
\begin{align}<br />
\frac{\partial}{\partial W_{ij}^{(l)}} J(W,b) &=<br />
\left[ \frac{1}{m} \sum_{i=1}^m \frac{\partial}{\partial W_{ij}^{(l)}} J(W,b; x^{(i)}, y^{(i)}) \right] + \lambda W_{ij}^{(l)} \\<br />
\frac{\partial}{\partial b_{i}^{(l)}} J(W,b) &=<br />
\frac{1}{m}\sum_{i=1}^m \frac{\partial}{\partial b_{i}^{(l)}} J(W,b; x^{(i)}, y^{(i)})<br />
\end{align}<br />
</math> <br />
<br />
以上两行公式稍有不同,第一行比第二行多出一项,是因为权重衰减是作用于 <math>\textstyle W</math> 而不是 <math>\textstyle b</math>。<br />
<br />
<br />
反向传播算法的思路如下:给定一个样例 <math>\textstyle (x,y)</math>,我们首先进行“前向传导”运算,计算出网络中所有的激活值,包括 <math>\textstyle h_{W,b}(x)</math> 的输出值。之后,针对第 <math>\textstyle l</math> 层的每一个节点 <math>\textstyle i</math>,我们计算出其“残差” <math>\textstyle \delta^{(l)}_i</math>,该残差表明了该节点对最终输出值的残差产生了多少影响。对于最终的输出节点,我们可以直接算出网络产生的激活值与实际值之间的差距,我们将这个差距定义为 <math>\textstyle \delta^{(n_l)}_i</math> (第 <math>\textstyle n_l</math> 层表示输出层)。对于隐藏单元我们如何处理呢?我们将基于节点(译者注:第 <math>\textstyle l+1</math> 层节点)残差的加权平均值计算 <math>\textstyle \delta^{(l)}_i</math>,这些节点以 <math>\textstyle a^{(l)}_i</math> 作为输入。下面将给出反向传导算法的细节:<br />
<br />
<br />
<ol><br />
<li>进行前馈传导计算,利用前向传导公式,得到 <math>\textstyle L_2, L_3, \ldots </math> 直到输出层 <math>\textstyle L_{n_l}</math> 的激活值。<br />
<li>对于第 <math>\textstyle n_l</math> 层(输出层)的每个输出单元 <math>\textstyle i</math>,我们根据以下公式计算残差:<br />
<br />
<br />
:<math><br />
\begin{align}<br />
\delta^{(n_l)}_i<br />
= \frac{\partial}{\partial z^{(n_l)}_i} \;\;<br />
\frac{1}{2} \left\|y - h_{W,b}(x)\right\|^2 = - (y_i - a^{(n_l)}_i) \cdot f'(z^{(n_l)}_i)<br />
\end{align}<br />
</math><br />
<br />
[译者注:<br />
:<math> <br />
\begin{align}<br />
\delta^{(n_l)}_i &= \frac{\partial}{\partial z^{n_l}_i}J(W,b;x,y)<br />
= \frac{\partial}{\partial z^{n_l}_i}\frac{1}{2} \left\|y - h_{W,b}(x)\right\|^2 \\<br />
&= \frac{\partial}{\partial z^{n_l}_i}\frac{1}{2} \sum_{j=1}^{S_{n_l}} (y_j-a_j^{(n_l)})^2<br />
= \frac{\partial}{\partial z^{n_l}_i}\frac{1}{2} \sum_{j=1}^{S_{n_l}} (y_j-f(z_j^{(n_l)}))^2 \\<br />
&= - (y_i - f(z_j^{(n_l)})) \cdot f'(z^{(n_l)}_i)<br />
= - (y_i - a^{(n_l)}_i) \cdot f'(z^{(n_l)}_i)<br />
\end{align}<br />
</math> <br />
]<br />
<br />
<li>对 <math>\textstyle l = n_l-1, n_l-2, n_l-3, \ldots, 2</math> 的各个层,第 <math>\textstyle l</math> 层的第 <math>\textstyle i</math> 个节点的残差计算方法如下:<br />
: <math> <br />
\delta^{(l)}_i = \left( \sum_{j=1}^{s_{l+1}} W^{(l)}_{ji} \delta^{(l+1)}_j \right) f'(z^{(l)}_i)<br />
</math> <br />
<br />
{译者注:<br />
:<math> <br />
\begin{align}<br />
\delta^{(n_l-1)}_i &=\frac{\partial}{\partial z^{n_l-1}_i}J(W,b;x,y)<br />
= \frac{\partial}{\partial z^{n_l-1}_i}\frac{1}{2} \left\|y - h_{W,b}(x)\right\|^2 <br />
= \frac{\partial}{\partial z^{n_l-1}_i}\frac{1}{2} \sum_{j=1}^{S_{n_l}}(y_j-a_j^{(n_l)})^2 \\<br />
&= \frac{1}{2} \sum_{j=1}^{S_{n_l}}\frac{\partial}{\partial z^{n_l-1}_i}(y_i-a_j^{(n_l)})^2<br />
= \frac{1}{2} \sum_{j=1}^{S_{n_l}}\frac{\partial}{\partial z^{n_l-1}_i}(y_i-f(z_j^{(n_l)})^2 \\<br />
&= \sum_{j=1}^{S_{n_l}}(y_j-f(z_j^{(n_l)}) \cdot \frac{\partial}{\partial z_i^{(n_l-1)}}f(z_j^{(n_l)})<br />
= \sum_{j=1}^{S_{n_l}}(y_j-f(z_j^{(n_l)}) \cdot f'(z_j^{(n_l)}) \cdot \frac{\partial z_j^{(n_l)}}{\partial z_i^{(n_l-1)}} \\<br />
&= \sum_{j=1}^{S_{n_l}} \delta_j^{(n_l)} \cdot \frac{\partial z_j^{(n_l)}}{z_i^{n_l-1}}<br />
= \sum_{j=1}^{S_{n_l}} \left(\delta_j^{(n_l)} \cdot \frac{\partial}{\partial z_i^{n_l-1}}\sum_{k=1}^{S_{n_l-1}}f(z_k^{n_l-1}) \cdot W_{jk}^{n_l-1}\right) \\<br />
&= \sum_{j=1}^{S_{n_l}} \delta_j^{(n_l)} \cdot W_{ji}^{n_l-1} \cdot f'(z_i^{n_l-1})<br />
= \left(\sum_{j=1}^{S_{n_l-1}}W_{ji}^{n_l-1}\delta_j^{(n_l)}\right)f'(z_i^{n_l-1})<br />
\end{align}<br />
</math> <br />
<br />
将上式中的<math>n_l-1</math>与<math>n_l</math>的关系替换为<math>l</math>与<math>l-1</math>的关系,就可以得到:<br />
: <math> <br />
\delta^{(l)}_i = \left( \sum_{j=1}^{s_{l+1}} W^{(l)}_{ji} \delta^{(l+1)}_j \right) f'(z^{(l)}_i)<br />
</math> <br />
以上逐次从后向前求导的过程即为“反向传导”的本意所在。<br />
]<br />
<br />
<li>计算我们需要的偏导数,计算方法如下:<br />
:<math> <br />
\begin{align}<br />
\frac{\partial}{\partial W_{ij}^{(l)}} J(W,b; x, y) &= a^{(l)}_j \delta_i^{(l+1)} \\<br />
\frac{\partial}{\partial b_{i}^{(l)}} J(W,b; x, y) &= \delta_i^{(l+1)}.<br />
\end{align}<br />
</math> <br />
</ol><br />
<br />
<br />
最后,我们用矩阵-向量表示法重写以上算法。我们使用“<math>\textstyle \bullet</math>” 表示向量乘积运算符(在Matlab或Octave里用“<tt>.*</tt>”表示,也称作阿达马乘积)。若 <math>\textstyle a = b \bullet c</math>,则 <math>\textstyle a_i = b_ic_i</math>。在上一个教程中我们扩展了 <math>\textstyle f(\cdot)</math> 的定义,使其包含向量运算,这里我们也对偏导数 <math>\textstyle f'(\cdot)</math> 也做了同样的处理(于是又有 <math> \textstyle f'([z_1, z_2, z_3]) = [f'(z_1), f'(z_2), f'(z_3)]</math> )。<br />
<br />
<br />
那么,反向传播算法可表示为以下几个步骤:<br />
<br />
<ol><br />
<li>进行前馈传导计算,利用前向传导公式,得到 <math>\textstyle L_2, L_3, \ldots</math>直到输出层 <math>\textstyle L_{n_l}</math> 的激活值。<br />
<br />
<li>对输出层(第 <math>\textstyle n_l</math> 层),计算:<br />
<br />
:<math> \begin{align}<br />
\delta^{(n_l)}<br />
= - (y - a^{(n_l)}) \bullet f'(z^{(n_l)})<br />
\end{align}</math> <br />
<br />
<li>对于 <math>\textstyle l = n_l-1, n_l-2, n_l-3, \ldots, 2</math> 的各层,计算:<br />
:<math> \begin{align}<br />
\delta^{(l)} = \left((W^{(l)})^T \delta^{(l+1)}\right) \bullet f'(z^{(l)})<br />
\end{align}</math> <br />
<br />
<li>计算最终需要的偏导数值:<br />
:<math> \begin{align}<br />
\nabla_{W^{(l)}} J(W,b;x,y) &= \delta^{(l+1)} (a^{(l)})^T, \\<br />
\nabla_{b^{(l)}} J(W,b;x,y) &= \delta^{(l+1)}.<br />
\end{align}</math> <br />
</ol><br />
<br />
<br />
'''实现中应注意:'''在以上的第2步和第3步中,我们需要为每一个 <math>\textstyle i</math> 值计算其 <math>\textstyle f'(z^{(l)}_i)</math>。假设 <math>\textstyle f(z)</math> 是sigmoid函数,并且我们已经在前向传导运算中得到了 <math>\textstyle a^{(l)}_i</math>。那么,使用我们早先推导出的 <math>\textstyle f'(z)</math>表达式,就可以计算得到 <math>\textstyle f'(z^{(l)}_i) = a^{(l)}_i (1- a^{(l)}_i)</math>。<br />
<br />
<br />
最后,我们将对梯度下降算法做个全面总结。在下面的伪代码中,<math>\textstyle \Delta W^{(l)}</math> 是一个与矩阵 <math>\textstyle W^{(l)}</math> 维度相同的矩阵,<math>\textstyle \Delta b^{(l)}</math> 是一个与 <math>\textstyle b^{(l)}</math> 维度相同的向量。注意这里“<math>\textstyle \Delta W^{(l)}</math>”是一个矩阵,而不是“<math>\textstyle \Delta</math> 与 <math>\textstyle W^{(l)}</math> 相乘”。下面,我们实现批量梯度下降法中的一次迭代:<br />
<br />
<br />
<ol><br />
<li>对于所有 <math>\textstyle l</math>,令 <math>\textstyle \Delta W^{(l)} := 0</math> , <math>\textstyle \Delta b^{(l)} := 0</math> (设置为全零矩阵或全零向量)<br />
<br />
<li>对于 <math>\textstyle i = 1</math> 到 <math>\textstyle m</math>,<br />
<br />
<ol type="a"><br />
<li>使用反向传播算法计算 <math>\textstyle \nabla_{W^{(l)}} J(W,b;x,y)</math> 和 <math>\textstyle \nabla_{b^{(l)}} J(W,b;x,y)</math>。<br />
<li>计算 <math>\textstyle \Delta W^{(l)} := \Delta W^{(l)} + \nabla_{W^{(l)}} J(W,b;x,y)</math>。<br />
<li>计算 <math>\textstyle \Delta b^{(l)} := \Delta b^{(l)} + \nabla_{b^{(l)}} J(W,b;x,y)</math>。 <br />
</ol><br />
<br />
<li>更新权重参数:<br />
:<math> \begin{align}<br />
W^{(l)} &= W^{(l)} - \alpha \left[ \left(\frac{1}{m} \Delta W^{(l)} \right) + \lambda W^{(l)}\right] \\<br />
b^{(l)} &= b^{(l)} - \alpha \left[\frac{1}{m} \Delta b^{(l)}\right]<br />
\end{align}</math> <br />
</ol><br />
<br />
现在,我们可以重复梯度下降法的迭代步骤来减小代价函数 <math>\textstyle J(W,b)</math> 的值,进而求解我们的神经网络。<br />
<br />
<br />
==中英文对照==<br />
<br />
:反向传播算法 Backpropagation Algorithm<br />
:(批量)梯度下降法 (batch) gradient descent<br />
:(整体)代价函数 (overall) cost function<br />
:方差 squared-error<br />
:均方差 average sum-of-squares error<br />
:规则化项 regularization term<br />
:权重衰减 weight decay<br />
:偏置项 bias terms<br />
:贝叶斯规则化方法 Bayesian regularization method<br />
:高斯先验概率 Gaussian prior<br />
:极大后验估计 MAP<br />
:极大似然估计 maximum likelihood estimation<br />
:激活函数 activation function<br />
:双曲正切函数 tanh function<br />
:非凸函数 non-convex function<br />
:隐藏层单元 hidden (layer) units<br />
:对称失效 symmetry breaking<br />
:学习速率 learning rate<br />
:前向传导 forward pass<br />
:假设值 hypothesis <br />
:残差 error term<br />
:加权平均值 weighted average <br />
:前馈传导 feedforward pass<br />
:阿达马乘积 Hadamard product<br />
:前向传播 forward propagation<br />
<br />
<br />
==中文译者==<br />
<br />
王方(fangkey@gmail.com),林锋(xlfg@yeah.net),许利杰(csxulijie@gmail.com)<br />
<br />
<br />
{{稀疏自编码器}}<br />
<br />
<br />
<br />
{{Languages|Backpropagation_Algorithm|English}}</div>
Kandeng
http://ufldl.stanford.edu/wiki/index.php/%E5%8F%8D%E5%90%91%E4%BC%A0%E5%AF%BC%E7%AE%97%E6%B3%95
反向传导算法
2013-04-09T14:46:03Z
<p>Kandeng: </p>
<hr />
<div>假设我们有一个固定样本集 <math>\textstyle \{ (x^{(1)}, y^{(1)}), \ldots, (x^{(m)}, y^{(m)}) \}</math>,它包含 <math>\textstyle m</math> 个样例。我们可以用批量梯度下降法来求解神经网络。具体来讲,对于单个样例 <math>\textstyle (x,y)</math>,其代价函数为:<br />
<br />
:<math><br />
\begin{align}<br />
J(W,b; x,y) = \frac{1}{2} \left\| h_{W,b}(x) - y \right\|^2.<br />
\end{align}<br />
</math><br />
<br />
这是一个(二分之一的)方差代价函数。给定一个包含 <math>\textstyle m</math> 个样例的数据集,我们可以定义整体代价函数为:<br />
<br />
:<math> <br />
\begin{align}<br />
J(W,b)<br />
&= \left[ \frac{1}{m} \sum_{i=1}^m J(W,b;x^{(i)},y^{(i)}) \right]<br />
+ \frac{\lambda}{2} \sum_{l=1}^{n_l-1} \; \sum_{i=1}^{s_l} \; \sum_{j=1}^{s_{l+1}} \left( W^{(l)}_{ji} \right)^2<br />
\\<br />
&= \left[ \frac{1}{m} \sum_{i=1}^m \left( \frac{1}{2} \left\| h_{W,b}(x^{(i)}) - y^{(i)} \right\|^2 \right) \right]<br />
+ \frac{\lambda}{2} \sum_{l=1}^{n_l-1} \; \sum_{i=1}^{s_l} \; \sum_{j=1}^{s_{l+1}} \left( W^{(l)}_{ji} \right)^2<br />
\end{align}<br />
</math><br />
<br />
以上公式中的第一项 <math>\textstyle J(W,b)</math> 是一个均方差项。第二项是一个规则化项(也叫'''权重衰减项'''),其目的是减小权重的幅度,防止过度拟合。<br />
<br />
<br />
[注:通常权重衰减的计算并不使用偏置项 <math>\textstyle b^{(l)}_i</math>,比如我们在 <math>\textstyle J(W, b)</math> 的定义中就没有使用。一般来说,将偏置项包含在权重衰减项中只会对最终的神经网络产生很小的影响。如果你在斯坦福选修过CS229(机器学习)课程,或者在YouTube上看过课程视频,你会发现这个权重衰减实际上是课上提到的贝叶斯规则化方法的变种。在贝叶斯规则化方法中,我们将高斯先验概率引入到参数中计算MAP(极大后验)估计(而不是极大似然估计)。]<br />
<br />
<br />
'''权重衰减参数''' <math>\textstyle \lambda</math> 用于控制公式中两项的相对重要性。在此重申一下这两个复杂函数的含义:<math>\textstyle J(W,b;x,y)</math> 是针对单个样例计算得到的方差代价函数;<math>\textstyle J(W,b)</math> 是整体样本代价函数,它包含权重衰减项。<br />
<br />
<br />
以上的代价函数经常被用于分类和回归问题。在分类问题中,我们用 <math>\textstyle y = 0</math> 或 <math>\textstyle 1</math>,来代表两种类型的标签(回想一下,这是因为 sigmoid激活函数的值域为 <math>\textstyle [0,1]</math>;如果我们使用双曲正切型激活函数,那么应该选用 <math>\textstyle -1</math> 和 <math>\textstyle +1</math> 作为标签)。对于回归问题,我们首先要变换输出值域(译者注:也就是 <math>\textstyle y</math>),以保证其范围为 <math>\textstyle [0,1]</math> (同样地,如果我们使用双曲正切型激活函数,要使输出值域为 <math>\textstyle [-1,1]</math>)。<br />
<br />
<br />
我们的目标是针对参数 <math>\textstyle W</math> 和 <math>\textstyle b</math> 来求其函数 <math>\textstyle J(W,b)</math> 的最小值。为了求解神经网络,我们需要将每一个参数 <math>\textstyle W^{(l)}_{ij}</math> 和 <math>\textstyle b^{(l)}_i</math> 初始化为一个很小的、接近零的随机值(比如说,使用正态分布 <math>\textstyle {Normal}(0,\epsilon^2)</math> 生成的随机值,其中 <math>\textstyle \epsilon</math> 设置为 <math>\textstyle 0.01</math> ),之后对目标函数使用诸如批量梯度下降法的最优化算法。因为 <math>\textstyle J(W, b)</math> 是一个非凸函数,梯度下降法很可能会收敛到局部最优解;但是在实际应用中,梯度下降法通常能得到令人满意的结果。最后,需要再次强调的是,要将参数进行随机初始化,而不是全部置为 <math>\textstyle 0</math>。如果所有参数都用相同的值作为初始值,那么所有隐藏层单元最终会得到与输入值有关的、相同的函数(也就是说,对于所有 <math>\textstyle i</math>,<math>\textstyle W^{(1)}_{ij}</math>都会取相同的值,那么对于任何输入 <math>\textstyle x</math> 都会有:<math>\textstyle a^{(2)}_1 = a^{(2)}_2 = a^{(2)}_3 = \ldots</math> )。随机初始化的目的是使'''对称失效'''。<br />
<br />
<br />
梯度下降法中每一次迭代都按照如下公式对参数 <math>\textstyle W</math> 和<math>\textstyle b</math> 进行更新:<br />
<br />
:<math><br />
\begin{align}<br />
W_{ij}^{(l)} &= W_{ij}^{(l)} - \alpha \frac{\partial}{\partial W_{ij}^{(l)}} J(W,b) \\<br />
b_{i}^{(l)} &= b_{i}^{(l)} - \alpha \frac{\partial}{\partial b_{i}^{(l)}} J(W,b)<br />
\end{align}<br />
</math> <br />
<br />
其中 <math>\textstyle \alpha</math> 是学习速率。其中关键步骤是计算偏导数。我们现在来讲一下'''反向传播'''算法,它是计算偏导数的一种有效方法。<br />
<br />
<br />
我们首先来讲一下如何使用反向传播算法来计算 <math>\textstyle \frac{\partial}{\partial W_{ij}^{(l)}} J(W,b; x, y)</math> 和 <math>\textstyle \frac{\partial}{\partial b_{i}^{(l)}} J(W,b; x, y)</math>,这两项是单个样例 <math>\textstyle (x,y)</math> 的代价函数 <math>\textstyle J(W,b;x,y)</math> 的偏导数。一旦我们求出该偏导数,就可以推导出整体代价函数 <math>\textstyle J(W,b)</math> 的偏导数:<br />
<br />
<br />
:<math><br />
\begin{align}<br />
\frac{\partial}{\partial W_{ij}^{(l)}} J(W,b) &=<br />
\left[ \frac{1}{m} \sum_{i=1}^m \frac{\partial}{\partial W_{ij}^{(l)}} J(W,b; x^{(i)}, y^{(i)}) \right] + \lambda W_{ij}^{(l)} \\<br />
\frac{\partial}{\partial b_{i}^{(l)}} J(W,b) &=<br />
\frac{1}{m}\sum_{i=1}^m \frac{\partial}{\partial b_{i}^{(l)}} J(W,b; x^{(i)}, y^{(i)})<br />
\end{align}<br />
</math> <br />
<br />
以上两行公式稍有不同,第一行比第二行多出一项,是因为权重衰减是作用于 <math>\textstyle W</math> 而不是 <math>\textstyle b</math>。<br />
<br />
<br />
反向传播算法的思路如下:给定一个样例 <math>\textstyle (x,y)</math>,我们首先进行“前向传导”运算,计算出网络中所有的激活值,包括 <math>\textstyle h_{W,b}(x)</math> 的输出值。之后,针对第 <math>\textstyle l</math> 层的每一个节点 <math>\textstyle i</math>,我们计算出其“残差” <math>\textstyle \delta^{(l)}_i</math>,该残差表明了该节点对最终输出值的残差产生了多少影响。对于最终的输出节点,我们可以直接算出网络产生的激活值与实际值之间的差距,我们将这个差距定义为 <math>\textstyle \delta^{(n_l)}_i</math> (第 <math>\textstyle n_l</math> 层表示输出层)。对于隐藏单元我们如何处理呢?我们将基于节点(译者注:第 <math>\textstyle l+1</math> 层节点)残差的加权平均值计算 <math>\textstyle \delta^{(l)}_i</math>,这些节点以 <math>\textstyle a^{(l)}_i</math> 作为输入。下面将给出反向传导算法的细节:<br />
<br />
<br />
<ol><br />
<li>进行前馈传导计算,利用前向传导公式,得到 <math>\textstyle L_2, L_3, \ldots </math> 直到输出层 <math>\textstyle L_{n_l}</math> 的激活值。<br />
<li>对于第 <math>\textstyle n_l</math> 层(输出层)的每个输出单元 <math>\textstyle i</math>,我们根据以下公式计算残差:<br />
<br />
<br />
:<math><br />
\begin{align}<br />
\delta^{(n_l)}_i<br />
= \frac{\partial}{\partial z^{(n_l)}_i} \;\;<br />
\frac{1}{2} \left\|y - h_{W,b}(x)\right\|^2 = - (y_i - a^{(n_l)}_i) \cdot f'(z^{(n_l)}_i)<br />
\end{align}<br />
</math><br />
<br />
[译者注:<br />
:<math> <br />
\begin{align}<br />
\delta^{(n_l)}_i &= \frac{\partial}{\partial z^{n_l}_i}J(W,b;x,y)<br />
= \frac{\partial}{\partial z^{n_l}_i}\frac{1}{2} \left\|y - h_{W,b}(x)\right\|^2 \\<br />
&= \frac{\partial}{\partial z^{n_l}_i}\frac{1}{2} \sum_{j=1}^{S_{n_l}} (y_j-a_j^{(n_l)})^2<br />
= \frac{\partial}{\partial z^{n_l}_i}\frac{1}{2} \sum_{j=1}^{S_{n_l}} (y_j-f(z_j^{(n_l)}))^2 \\<br />
&= - (y_i - f(z_j^{(n_l)})) \cdot f'(z^{(n_l)}_i)<br />
= - (y_i - a^{(n_l)}_i) \cdot f'(z^{(n_l)}_i)<br />
\end{align}<br />
</math> <br />
]<br />
<br />
<li>对 <math>\textstyle l = n_l-1, n_l-2, n_l-3, \ldots, 2</math> 的各个层,第 <math>\textstyle l</math> 层的第 <math>\textstyle i</math> 个节点的残差计算方法如下:<br />
: <math> <br />
\delta^{(l)}_i = \left( \sum_{j=1}^{s_{l+1}} W^{(l)}_{ji} \delta^{(l+1)}_j \right) f'(z^{(l)}_i)<br />
</math> <br />
<br />
{译者注:<br />
:<math> <br />
\begin{align}<br />
\delta^{(n_l-1)}_i &=\frac{\partial}{\partial z^{n_l-1}_i}J(W,b;x,y)<br />
= \frac{\partial}{\partial z^{n_l-1}_i}\frac{1}{2} \left\|y - h_{W,b}(x)\right\|^2 <br />
= \frac{\partial}{\partial z^{n_1-1}_i}\frac{1}{2} \sum_{j=1}^{S_{n_l}}(y_j-a_j^{(n_l)})^2 \\<br />
&= \frac{1}{2} \sum_{j=1}^{S_{n_l}}\frac{\partial}{\partial z^{n_l-1}_i}(y_i-a_j^{(n_l)})^2<br />
= \frac{1}{2} \sum_{j=1}^{S_{n_l}}\frac{\partial}{\partial z^{n_l-1}_i}(y_i-f(z_j^{(n_l)})^2 \\<br />
&= \sum_{j=1}^{S_{n_l}}(y_j-f(z_j^{(n_l)})\frac{\partial}{\partial z_i^{(n_l-1)}}f(z_j^{(n_l)})<br />
= \sum_{j=1}^{S_{n_l}}(y_j-f(z_j^{(n_l)}) f'(z_j^{(n_l)})\frac{\partial z_j^{(n_l)}}{\partial z_i^{(n_l-1)}} \\<br />
&= \sum_{j=1}^{S_{n_l}} \delta_j^{(n_l)}\frac{\partial z_j^{(n_l)}}{z_i^{n_l-1}}<br />
= \sum_{j=1}^{S_{n_l}} \left(\delta_j^{(n_l)}\frac{\partial}{\partial z_i^{n_l-1}}\sum_{k=1}^{S_{n_l-1}}f(z_k^{n_l-1})W_{jk}^{n_l-1}\right) \\<br />
&= \sum_{j=1}^{S_{n_l}} \delta_j^{(n_l)} W_{ji}^{n_l-1}f'(z_i^{n_l-1})<br />
= \left(\sum_{j=1}^{S_{n_l-1}}W_{ji}^{n_l-1}\delta_j^{(n_l)}\right)f'(z_i^{n_l-1})<br />
\end{align}<br />
</math> <br />
]<br />
<br />
<li>计算我们需要的偏导数,计算方法如下:<br />
:<math> <br />
\begin{align}<br />
\frac{\partial}{\partial W_{ij}^{(l)}} J(W,b; x, y) &= a^{(l)}_j \delta_i^{(l+1)} \\<br />
\frac{\partial}{\partial b_{i}^{(l)}} J(W,b; x, y) &= \delta_i^{(l+1)}.<br />
\end{align}<br />
</math> <br />
</ol><br />
<br />
<br />
最后,我们用矩阵-向量表示法重写以上算法。我们使用“<math>\textstyle \bullet</math>” 表示向量乘积运算符(在Matlab或Octave里用“<tt>.*</tt>”表示,也称作阿达马乘积)。若 <math>\textstyle a = b \bullet c</math>,则 <math>\textstyle a_i = b_ic_i</math>。在上一个教程中我们扩展了 <math>\textstyle f(\cdot)</math> 的定义,使其包含向量运算,这里我们也对偏导数 <math>\textstyle f'(\cdot)</math> 也做了同样的处理(于是又有 <math> \textstyle f'([z_1, z_2, z_3]) = [f'(z_1), f'(z_2), f'(z_3)]</math> )。<br />
<br />
<br />
那么,反向传播算法可表示为以下几个步骤:<br />
<br />
<ol><br />
<li>进行前馈传导计算,利用前向传导公式,得到 <math>\textstyle L_2, L_3, \ldots</math>直到输出层 <math>\textstyle L_{n_l}</math> 的激活值。<br />
<br />
<li>对输出层(第 <math>\textstyle n_l</math> 层),计算:<br />
<br />
:<math> \begin{align}<br />
\delta^{(n_l)}<br />
= - (y - a^{(n_l)}) \bullet f'(z^{(n_l)})<br />
\end{align}</math> <br />
<br />
<li>对于 <math>\textstyle l = n_l-1, n_l-2, n_l-3, \ldots, 2</math> 的各层,计算:<br />
:<math> \begin{align}<br />
\delta^{(l)} = \left((W^{(l)})^T \delta^{(l+1)}\right) \bullet f'(z^{(l)})<br />
\end{align}</math> <br />
<br />
<li>计算最终需要的偏导数值:<br />
:<math> \begin{align}<br />
\nabla_{W^{(l)}} J(W,b;x,y) &= \delta^{(l+1)} (a^{(l)})^T, \\<br />
\nabla_{b^{(l)}} J(W,b;x,y) &= \delta^{(l+1)}.<br />
\end{align}</math> <br />
</ol><br />
<br />
<br />
'''实现中应注意:'''在以上的第2步和第3步中,我们需要为每一个 <math>\textstyle i</math> 值计算其 <math>\textstyle f'(z^{(l)}_i)</math>。假设 <math>\textstyle f(z)</math> 是sigmoid函数,并且我们已经在前向传导运算中得到了 <math>\textstyle a^{(l)}_i</math>。那么,使用我们早先推导出的 <math>\textstyle f'(z)</math>表达式,就可以计算得到 <math>\textstyle f'(z^{(l)}_i) = a^{(l)}_i (1- a^{(l)}_i)</math>。<br />
<br />
<br />
最后,我们将对梯度下降算法做个全面总结。在下面的伪代码中,<math>\textstyle \Delta W^{(l)}</math> 是一个与矩阵 <math>\textstyle W^{(l)}</math> 维度相同的矩阵,<math>\textstyle \Delta b^{(l)}</math> 是一个与 <math>\textstyle b^{(l)}</math> 维度相同的向量。注意这里“<math>\textstyle \Delta W^{(l)}</math>”是一个矩阵,而不是“<math>\textstyle \Delta</math> 与 <math>\textstyle W^{(l)}</math> 相乘”。下面,我们实现批量梯度下降法中的一次迭代:<br />
<br />
<br />
<ol><br />
<li>对于所有 <math>\textstyle l</math>,令 <math>\textstyle \Delta W^{(l)} := 0</math> , <math>\textstyle \Delta b^{(l)} := 0</math> (设置为全零矩阵或全零向量)<br />
<br />
<li>对于 <math>\textstyle i = 1</math> 到 <math>\textstyle m</math>,<br />
<br />
<ol type="a"><br />
<li>使用反向传播算法计算 <math>\textstyle \nabla_{W^{(l)}} J(W,b;x,y)</math> 和 <math>\textstyle \nabla_{b^{(l)}} J(W,b;x,y)</math>。<br />
<li>计算 <math>\textstyle \Delta W^{(l)} := \Delta W^{(l)} + \nabla_{W^{(l)}} J(W,b;x,y)</math>。<br />
<li>计算 <math>\textstyle \Delta b^{(l)} := \Delta b^{(l)} + \nabla_{b^{(l)}} J(W,b;x,y)</math>。 <br />
</ol><br />
<br />
<li>更新权重参数:<br />
:<math> \begin{align}<br />
W^{(l)} &= W^{(l)} - \alpha \left[ \left(\frac{1}{m} \Delta W^{(l)} \right) + \lambda W^{(l)}\right] \\<br />
b^{(l)} &= b^{(l)} - \alpha \left[\frac{1}{m} \Delta b^{(l)}\right]<br />
\end{align}</math> <br />
</ol><br />
<br />
现在,我们可以重复梯度下降法的迭代步骤来减小代价函数 <math>\textstyle J(W,b)</math> 的值,进而求解我们的神经网络。<br />
<br />
<br />
==中英文对照==<br />
<br />
:反向传播算法 Backpropagation Algorithm<br />
:(批量)梯度下降法 (batch) gradient descent<br />
:(整体)代价函数 (overall) cost function<br />
:方差 squared-error<br />
:均方差 average sum-of-squares error<br />
:规则化项 regularization term<br />
:权重衰减 weight decay<br />
:偏置项 bias terms<br />
:贝叶斯规则化方法 Bayesian regularization method<br />
:高斯先验概率 Gaussian prior<br />
:极大后验估计 MAP<br />
:极大似然估计 maximum likelihood estimation<br />
:激活函数 activation function<br />
:双曲正切函数 tanh function<br />
:非凸函数 non-convex function<br />
:隐藏层单元 hidden (layer) units<br />
:对称失效 symmetry breaking<br />
:学习速率 learning rate<br />
:前向传导 forward pass<br />
:假设值 hypothesis <br />
:残差 error term<br />
:加权平均值 weighted average <br />
:前馈传导 feedforward pass<br />
:阿达马乘积 Hadamard product<br />
:前向传播 forward propagation<br />
<br />
<br />
==中文译者==<br />
<br />
王方(fangkey@gmail.com),林锋(xlfg@yeah.net),许利杰(csxulijie@gmail.com)<br />
<br />
<br />
{{稀疏自编码器}}<br />
<br />
<br />
<br />
{{Languages|Backpropagation_Algorithm|English}}</div>
Kandeng
http://ufldl.stanford.edu/wiki/index.php/%E5%8F%8D%E5%90%91%E4%BC%A0%E5%AF%BC%E7%AE%97%E6%B3%95
反向传导算法
2013-04-09T13:52:36Z
<p>Kandeng: </p>
<hr />
<div>假设我们有一个固定样本集 <math>\textstyle \{ (x^{(1)}, y^{(1)}), \ldots, (x^{(m)}, y^{(m)}) \}</math>,它包含 <math>\textstyle m</math> 个样例。我们可以用批量梯度下降法来求解神经网络。具体来讲,对于单个样例 <math>\textstyle (x,y)</math>,其代价函数为:<br />
<br />
:<math><br />
\begin{align}<br />
J(W,b; x,y) = \frac{1}{2} \left\| h_{W,b}(x) - y \right\|^2.<br />
\end{align}<br />
</math><br />
<br />
这是一个(二分之一的)方差代价函数。给定一个包含 <math>\textstyle m</math> 个样例的数据集,我们可以定义整体代价函数为:<br />
<br />
:<math> <br />
\begin{align}<br />
J(W,b)<br />
&= \left[ \frac{1}{m} \sum_{i=1}^m J(W,b;x^{(i)},y^{(i)}) \right]<br />
+ \frac{\lambda}{2} \sum_{l=1}^{n_l-1} \; \sum_{i=1}^{s_l} \; \sum_{j=1}^{s_{l+1}} \left( W^{(l)}_{ji} \right)^2<br />
\\<br />
&= \left[ \frac{1}{m} \sum_{i=1}^m \left( \frac{1}{2} \left\| h_{W,b}(x^{(i)}) - y^{(i)} \right\|^2 \right) \right]<br />
+ \frac{\lambda}{2} \sum_{l=1}^{n_l-1} \; \sum_{i=1}^{s_l} \; \sum_{j=1}^{s_{l+1}} \left( W^{(l)}_{ji} \right)^2<br />
\end{align}<br />
</math><br />
<br />
以上公式中的第一项 <math>\textstyle J(W,b)</math> 是一个均方差项。第二项是一个规则化项(也叫'''权重衰减项'''),其目的是减小权重的幅度,防止过度拟合。<br />
<br />
<br />
[注:通常权重衰减的计算并不使用偏置项 <math>\textstyle b^{(l)}_i</math>,比如我们在 <math>\textstyle J(W, b)</math> 的定义中就没有使用。一般来说,将偏置项包含在权重衰减项中只会对最终的神经网络产生很小的影响。如果你在斯坦福选修过CS229(机器学习)课程,或者在YouTube上看过课程视频,你会发现这个权重衰减实际上是课上提到的贝叶斯规则化方法的变种。在贝叶斯规则化方法中,我们将高斯先验概率引入到参数中计算MAP(极大后验)估计(而不是极大似然估计)。]<br />
<br />
<br />
'''权重衰减参数''' <math>\textstyle \lambda</math> 用于控制公式中两项的相对重要性。在此重申一下这两个复杂函数的含义:<math>\textstyle J(W,b;x,y)</math> 是针对单个样例计算得到的方差代价函数;<math>\textstyle J(W,b)</math> 是整体样本代价函数,它包含权重衰减项。<br />
<br />
<br />
以上的代价函数经常被用于分类和回归问题。在分类问题中,我们用 <math>\textstyle y = 0</math> 或 <math>\textstyle 1</math>,来代表两种类型的标签(回想一下,这是因为 sigmoid激活函数的值域为 <math>\textstyle [0,1]</math>;如果我们使用双曲正切型激活函数,那么应该选用 <math>\textstyle -1</math> 和 <math>\textstyle +1</math> 作为标签)。对于回归问题,我们首先要变换输出值域(译者注:也就是 <math>\textstyle y</math>),以保证其范围为 <math>\textstyle [0,1]</math> (同样地,如果我们使用双曲正切型激活函数,要使输出值域为 <math>\textstyle [-1,1]</math>)。<br />
<br />
<br />
我们的目标是针对参数 <math>\textstyle W</math> 和 <math>\textstyle b</math> 来求其函数 <math>\textstyle J(W,b)</math> 的最小值。为了求解神经网络,我们需要将每一个参数 <math>\textstyle W^{(l)}_{ij}</math> 和 <math>\textstyle b^{(l)}_i</math> 初始化为一个很小的、接近零的随机值(比如说,使用正态分布 <math>\textstyle {Normal}(0,\epsilon^2)</math> 生成的随机值,其中 <math>\textstyle \epsilon</math> 设置为 <math>\textstyle 0.01</math> ),之后对目标函数使用诸如批量梯度下降法的最优化算法。因为 <math>\textstyle J(W, b)</math> 是一个非凸函数,梯度下降法很可能会收敛到局部最优解;但是在实际应用中,梯度下降法通常能得到令人满意的结果。最后,需要再次强调的是,要将参数进行随机初始化,而不是全部置为 <math>\textstyle 0</math>。如果所有参数都用相同的值作为初始值,那么所有隐藏层单元最终会得到与输入值有关的、相同的函数(也就是说,对于所有 <math>\textstyle i</math>,<math>\textstyle W^{(1)}_{ij}</math>都会取相同的值,那么对于任何输入 <math>\textstyle x</math> 都会有:<math>\textstyle a^{(2)}_1 = a^{(2)}_2 = a^{(2)}_3 = \ldots</math> )。随机初始化的目的是使'''对称失效'''。<br />
<br />
<br />
梯度下降法中每一次迭代都按照如下公式对参数 <math>\textstyle W</math> 和<math>\textstyle b</math> 进行更新:<br />
<br />
:<math><br />
\begin{align}<br />
W_{ij}^{(l)} &= W_{ij}^{(l)} - \alpha \frac{\partial}{\partial W_{ij}^{(l)}} J(W,b) \\<br />
b_{i}^{(l)} &= b_{i}^{(l)} - \alpha \frac{\partial}{\partial b_{i}^{(l)}} J(W,b)<br />
\end{align}<br />
</math> <br />
<br />
其中 <math>\textstyle \alpha</math> 是学习速率。其中关键步骤是计算偏导数。我们现在来讲一下'''反向传播'''算法,它是计算偏导数的一种有效方法。<br />
<br />
<br />
我们首先来讲一下如何使用反向传播算法来计算 <math>\textstyle \frac{\partial}{\partial W_{ij}^{(l)}} J(W,b; x, y)</math> 和 <math>\textstyle \frac{\partial}{\partial b_{i}^{(l)}} J(W,b; x, y)</math>,这两项是单个样例 <math>\textstyle (x,y)</math> 的代价函数 <math>\textstyle J(W,b;x,y)</math> 的偏导数。一旦我们求出该偏导数,就可以推导出整体代价函数 <math>\textstyle J(W,b)</math> 的偏导数:<br />
<br />
<br />
:<math><br />
\begin{align}<br />
\frac{\partial}{\partial W_{ij}^{(l)}} J(W,b) &=<br />
\left[ \frac{1}{m} \sum_{i=1}^m \frac{\partial}{\partial W_{ij}^{(l)}} J(W,b; x^{(i)}, y^{(i)}) \right] + \lambda W_{ij}^{(l)} \\<br />
\frac{\partial}{\partial b_{i}^{(l)}} J(W,b) &=<br />
\frac{1}{m}\sum_{i=1}^m \frac{\partial}{\partial b_{i}^{(l)}} J(W,b; x^{(i)}, y^{(i)})<br />
\end{align}<br />
</math> <br />
<br />
以上两行公式稍有不同,第一行比第二行多出一项,是因为权重衰减是作用于 <math>\textstyle W</math> 而不是 <math>\textstyle b</math>。<br />
<br />
<br />
反向传播算法的思路如下:给定一个样例 <math>\textstyle (x,y)</math>,我们首先进行“前向传导”运算,计算出网络中所有的激活值,包括 <math>\textstyle h_{W,b}(x)</math> 的输出值。之后,针对第 <math>\textstyle l</math> 层的每一个节点 <math>\textstyle i</math>,我们计算出其“残差” <math>\textstyle \delta^{(l)}_i</math>,该残差表明了该节点对最终输出值的残差产生了多少影响。对于最终的输出节点,我们可以直接算出网络产生的激活值与实际值之间的差距,我们将这个差距定义为 <math>\textstyle \delta^{(n_l)}_i</math> (第 <math>\textstyle n_l</math> 层表示输出层)。对于隐藏单元我们如何处理呢?我们将基于节点(译者注:第 <math>\textstyle l+1</math> 层节点)残差的加权平均值计算 <math>\textstyle \delta^{(l)}_i</math>,这些节点以 <math>\textstyle a^{(l)}_i</math> 作为输入。下面将给出反向传导算法的细节:<br />
<br />
<br />
<ol><br />
<li>进行前馈传导计算,利用前向传导公式,得到 <math>\textstyle L_2, L_3, \ldots </math> 直到输出层 <math>\textstyle L_{n_l}</math> 的激活值。<br />
<li>对于第 <math>\textstyle n_l</math> 层(输出层)的每个输出单元 <math>\textstyle i</math>,我们根据以下公式计算残差:<br />
<br />
<br />
:<math><br />
\begin{align}<br />
\delta^{(n_l)}_i<br />
= \frac{\partial}{\partial z^{(n_l)}_i} \;\;<br />
\frac{1}{2} \left\|y - h_{W,b}(x)\right\|^2 = - (y_i - a^{(n_l)}_i) \cdot f'(z^{(n_l)}_i)<br />
\end{align}<br />
</math><br />
<br />
[译者注:<br />
:<math> <br />
\begin{align}<br />
\delta^{(n_l)}_i &= \frac{\partial}{\partial z^{n_l}_i}J(W,b;x,y)<br />
= \frac{\partial}{\partial z^{n_l}_i}\frac{1}{2} \left\|y - h_{W,b}(x)\right\|^2 \\<br />
&= \frac{\partial}{\partial z^{n_l}_i}\frac{1}{2} \sum_{j=1}^{S_{n_l}} (y_j-a_j^{(n_l)})^2<br />
= \frac{\partial}{\partial z^{n_l}_i}\frac{1}{2} \sum_{j=1}^{S_{n_l}} (y_j-f(z_j^{(n_l)}))^2 \\<br />
&= - (y_i - f(z_j^{(n_l)})) \cdot f'(z^{(n_l)}_i)<br />
= - (y_i - a^{(n_l)}_i) \cdot f'(z^{(n_l)}_i)<br />
\end{align}<br />
</math> <br />
]<br />
<br />
<li>对 <math>\textstyle l = n_l-1, n_l-2, n_l-3, \ldots, 2</math> 的各个层,第 <math>\textstyle l</math> 层的第 <math>\textstyle i</math> 个节点的残差计算方法如下:<br />
: <math> <br />
\delta^{(l)}_i = \left( \sum_{j=1}^{s_{l+1}} W^{(l)}_{ji} \delta^{(l+1)}_j \right) f'(z^{(l)}_i)<br />
</math> <br />
<br />
<br />
<li>计算我们需要的偏导数,计算方法如下:<br />
:<math> <br />
\begin{align}<br />
\frac{\partial}{\partial W_{ij}^{(l)}} J(W,b; x, y) &= a^{(l)}_j \delta_i^{(l+1)} \\<br />
\frac{\partial}{\partial b_{i}^{(l)}} J(W,b; x, y) &= \delta_i^{(l+1)}.<br />
\end{align}<br />
</math> <br />
</ol><br />
<br />
<br />
最后,我们用矩阵-向量表示法重写以上算法。我们使用“<math>\textstyle \bullet</math>” 表示向量乘积运算符(在Matlab或Octave里用“<tt>.*</tt>”表示,也称作阿达马乘积)。若 <math>\textstyle a = b \bullet c</math>,则 <math>\textstyle a_i = b_ic_i</math>。在上一个教程中我们扩展了 <math>\textstyle f(\cdot)</math> 的定义,使其包含向量运算,这里我们也对偏导数 <math>\textstyle f'(\cdot)</math> 也做了同样的处理(于是又有 <math> \textstyle f'([z_1, z_2, z_3]) = [f'(z_1), f'(z_2), f'(z_3)]</math> )。<br />
<br />
<br />
那么,反向传播算法可表示为以下几个步骤:<br />
<br />
<ol><br />
<li>进行前馈传导计算,利用前向传导公式,得到 <math>\textstyle L_2, L_3, \ldots</math>直到输出层 <math>\textstyle L_{n_l}</math> 的激活值。<br />
<br />
<li>对输出层(第 <math>\textstyle n_l</math> 层),计算:<br />
<br />
:<math> \begin{align}<br />
\delta^{(n_l)}<br />
= - (y - a^{(n_l)}) \bullet f'(z^{(n_l)})<br />
\end{align}</math> <br />
<br />
<li>对于 <math>\textstyle l = n_l-1, n_l-2, n_l-3, \ldots, 2</math> 的各层,计算:<br />
:<math> \begin{align}<br />
\delta^{(l)} = \left((W^{(l)})^T \delta^{(l+1)}\right) \bullet f'(z^{(l)})<br />
\end{align}</math> <br />
<br />
<li>计算最终需要的偏导数值:<br />
:<math> \begin{align}<br />
\nabla_{W^{(l)}} J(W,b;x,y) &= \delta^{(l+1)} (a^{(l)})^T, \\<br />
\nabla_{b^{(l)}} J(W,b;x,y) &= \delta^{(l+1)}.<br />
\end{align}</math> <br />
</ol><br />
<br />
<br />
'''实现中应注意:'''在以上的第2步和第3步中,我们需要为每一个 <math>\textstyle i</math> 值计算其 <math>\textstyle f'(z^{(l)}_i)</math>。假设 <math>\textstyle f(z)</math> 是sigmoid函数,并且我们已经在前向传导运算中得到了 <math>\textstyle a^{(l)}_i</math>。那么,使用我们早先推导出的 <math>\textstyle f'(z)</math>表达式,就可以计算得到 <math>\textstyle f'(z^{(l)}_i) = a^{(l)}_i (1- a^{(l)}_i)</math>。<br />
<br />
<br />
最后,我们将对梯度下降算法做个全面总结。在下面的伪代码中,<math>\textstyle \Delta W^{(l)}</math> 是一个与矩阵 <math>\textstyle W^{(l)}</math> 维度相同的矩阵,<math>\textstyle \Delta b^{(l)}</math> 是一个与 <math>\textstyle b^{(l)}</math> 维度相同的向量。注意这里“<math>\textstyle \Delta W^{(l)}</math>”是一个矩阵,而不是“<math>\textstyle \Delta</math> 与 <math>\textstyle W^{(l)}</math> 相乘”。下面,我们实现批量梯度下降法中的一次迭代:<br />
<br />
<br />
<ol><br />
<li>对于所有 <math>\textstyle l</math>,令 <math>\textstyle \Delta W^{(l)} := 0</math> , <math>\textstyle \Delta b^{(l)} := 0</math> (设置为全零矩阵或全零向量)<br />
<br />
<li>对于 <math>\textstyle i = 1</math> 到 <math>\textstyle m</math>,<br />
<br />
<ol type="a"><br />
<li>使用反向传播算法计算 <math>\textstyle \nabla_{W^{(l)}} J(W,b;x,y)</math> 和 <math>\textstyle \nabla_{b^{(l)}} J(W,b;x,y)</math>。<br />
<li>计算 <math>\textstyle \Delta W^{(l)} := \Delta W^{(l)} + \nabla_{W^{(l)}} J(W,b;x,y)</math>。<br />
<li>计算 <math>\textstyle \Delta b^{(l)} := \Delta b^{(l)} + \nabla_{b^{(l)}} J(W,b;x,y)</math>。 <br />
</ol><br />
<br />
<li>更新权重参数:<br />
:<math> \begin{align}<br />
W^{(l)} &= W^{(l)} - \alpha \left[ \left(\frac{1}{m} \Delta W^{(l)} \right) + \lambda W^{(l)}\right] \\<br />
b^{(l)} &= b^{(l)} - \alpha \left[\frac{1}{m} \Delta b^{(l)}\right]<br />
\end{align}</math> <br />
</ol><br />
<br />
现在,我们可以重复梯度下降法的迭代步骤来减小代价函数 <math>\textstyle J(W,b)</math> 的值,进而求解我们的神经网络。<br />
<br />
<br />
==中英文对照==<br />
<br />
:反向传播算法 Backpropagation Algorithm<br />
:(批量)梯度下降法 (batch) gradient descent<br />
:(整体)代价函数 (overall) cost function<br />
:方差 squared-error<br />
:均方差 average sum-of-squares error<br />
:规则化项 regularization term<br />
:权重衰减 weight decay<br />
:偏置项 bias terms<br />
:贝叶斯规则化方法 Bayesian regularization method<br />
:高斯先验概率 Gaussian prior<br />
:极大后验估计 MAP<br />
:极大似然估计 maximum likelihood estimation<br />
:激活函数 activation function<br />
:双曲正切函数 tanh function<br />
:非凸函数 non-convex function<br />
:隐藏层单元 hidden (layer) units<br />
:对称失效 symmetry breaking<br />
:学习速率 learning rate<br />
:前向传导 forward pass<br />
:假设值 hypothesis <br />
:残差 error term<br />
:加权平均值 weighted average <br />
:前馈传导 feedforward pass<br />
:阿达马乘积 Hadamard product<br />
:前向传播 forward propagation<br />
<br />
<br />
==中文译者==<br />
<br />
王方(fangkey@gmail.com),林锋(xlfg@yeah.net),许利杰(csxulijie@gmail.com)<br />
<br />
<br />
{{稀疏自编码器}}<br />
<br />
<br />
<br />
{{Languages|Backpropagation_Algorithm|English}}</div>
Kandeng
http://ufldl.stanford.edu/wiki/index.php/%E5%8F%8D%E5%90%91%E4%BC%A0%E5%AF%BC%E7%AE%97%E6%B3%95
反向传导算法
2013-04-09T13:36:02Z
<p>Kandeng: </p>
<hr />
<div>假设我们有一个固定样本集 <math>\textstyle \{ (x^{(1)}, y^{(1)}), \ldots, (x^{(m)}, y^{(m)}) \}</math>,它包含 <math>\textstyle m</math> 个样例。我们可以用批量梯度下降法来求解神经网络。具体来讲,对于单个样例 <math>\textstyle (x,y)</math>,其代价函数为:<br />
<br />
:<math><br />
\begin{align}<br />
J(W,b; x,y) = \frac{1}{2} \left\| h_{W,b}(x) - y \right\|^2.<br />
\end{align}<br />
</math><br />
<br />
这是一个(二分之一的)方差代价函数。给定一个包含 <math>\textstyle m</math> 个样例的数据集,我们可以定义整体代价函数为:<br />
<br />
:<math> <br />
\begin{align}<br />
J(W,b)<br />
&= \left[ \frac{1}{m} \sum_{i=1}^m J(W,b;x^{(i)},y^{(i)}) \right]<br />
+ \frac{\lambda}{2} \sum_{l=1}^{n_l-1} \; \sum_{i=1}^{s_l} \; \sum_{j=1}^{s_{l+1}} \left( W^{(l)}_{ji} \right)^2<br />
\\<br />
&= \left[ \frac{1}{m} \sum_{i=1}^m \left( \frac{1}{2} \left\| h_{W,b}(x^{(i)}) - y^{(i)} \right\|^2 \right) \right]<br />
+ \frac{\lambda}{2} \sum_{l=1}^{n_l-1} \; \sum_{i=1}^{s_l} \; \sum_{j=1}^{s_{l+1}} \left( W^{(l)}_{ji} \right)^2<br />
\end{align}<br />
</math><br />
<br />
以上公式中的第一项 <math>\textstyle J(W,b)</math> 是一个均方差项。第二项是一个规则化项(也叫'''权重衰减项'''),其目的是减小权重的幅度,防止过度拟合。<br />
<br />
<br />
[注:通常权重衰减的计算并不使用偏置项 <math>\textstyle b^{(l)}_i</math>,比如我们在 <math>\textstyle J(W, b)</math> 的定义中就没有使用。一般来说,将偏置项包含在权重衰减项中只会对最终的神经网络产生很小的影响。如果你在斯坦福选修过CS229(机器学习)课程,或者在YouTube上看过课程视频,你会发现这个权重衰减实际上是课上提到的贝叶斯规则化方法的变种。在贝叶斯规则化方法中,我们将高斯先验概率引入到参数中计算MAP(极大后验)估计(而不是极大似然估计)。]<br />
<br />
<br />
'''权重衰减参数''' <math>\textstyle \lambda</math> 用于控制公式中两项的相对重要性。在此重申一下这两个复杂函数的含义:<math>\textstyle J(W,b;x,y)</math> 是针对单个样例计算得到的方差代价函数;<math>\textstyle J(W,b)</math> 是整体样本代价函数,它包含权重衰减项。<br />
<br />
<br />
以上的代价函数经常被用于分类和回归问题。在分类问题中,我们用 <math>\textstyle y = 0</math> 或 <math>\textstyle 1</math>,来代表两种类型的标签(回想一下,这是因为 sigmoid激活函数的值域为 <math>\textstyle [0,1]</math>;如果我们使用双曲正切型激活函数,那么应该选用 <math>\textstyle -1</math> 和 <math>\textstyle +1</math> 作为标签)。对于回归问题,我们首先要变换输出值域(译者注:也就是 <math>\textstyle y</math>),以保证其范围为 <math>\textstyle [0,1]</math> (同样地,如果我们使用双曲正切型激活函数,要使输出值域为 <math>\textstyle [-1,1]</math>)。<br />
<br />
<br />
我们的目标是针对参数 <math>\textstyle W</math> 和 <math>\textstyle b</math> 来求其函数 <math>\textstyle J(W,b)</math> 的最小值。为了求解神经网络,我们需要将每一个参数 <math>\textstyle W^{(l)}_{ij}</math> 和 <math>\textstyle b^{(l)}_i</math> 初始化为一个很小的、接近零的随机值(比如说,使用正态分布 <math>\textstyle {Normal}(0,\epsilon^2)</math> 生成的随机值,其中 <math>\textstyle \epsilon</math> 设置为 <math>\textstyle 0.01</math> ),之后对目标函数使用诸如批量梯度下降法的最优化算法。因为 <math>\textstyle J(W, b)</math> 是一个非凸函数,梯度下降法很可能会收敛到局部最优解;但是在实际应用中,梯度下降法通常能得到令人满意的结果。最后,需要再次强调的是,要将参数进行随机初始化,而不是全部置为 <math>\textstyle 0</math>。如果所有参数都用相同的值作为初始值,那么所有隐藏层单元最终会得到与输入值有关的、相同的函数(也就是说,对于所有 <math>\textstyle i</math>,<math>\textstyle W^{(1)}_{ij}</math>都会取相同的值,那么对于任何输入 <math>\textstyle x</math> 都会有:<math>\textstyle a^{(2)}_1 = a^{(2)}_2 = a^{(2)}_3 = \ldots</math> )。随机初始化的目的是使'''对称失效'''。<br />
<br />
<br />
梯度下降法中每一次迭代都按照如下公式对参数 <math>\textstyle W</math> 和<math>\textstyle b</math> 进行更新:<br />
<br />
:<math><br />
\begin{align}<br />
W_{ij}^{(l)} &= W_{ij}^{(l)} - \alpha \frac{\partial}{\partial W_{ij}^{(l)}} J(W,b) \\<br />
b_{i}^{(l)} &= b_{i}^{(l)} - \alpha \frac{\partial}{\partial b_{i}^{(l)}} J(W,b)<br />
\end{align}<br />
</math> <br />
<br />
其中 <math>\textstyle \alpha</math> 是学习速率。其中关键步骤是计算偏导数。我们现在来讲一下'''反向传播'''算法,它是计算偏导数的一种有效方法。<br />
<br />
<br />
我们首先来讲一下如何使用反向传播算法来计算 <math>\textstyle \frac{\partial}{\partial W_{ij}^{(l)}} J(W,b; x, y)</math> 和 <math>\textstyle \frac{\partial}{\partial b_{i}^{(l)}} J(W,b; x, y)</math>,这两项是单个样例 <math>\textstyle (x,y)</math> 的代价函数 <math>\textstyle J(W,b;x,y)</math> 的偏导数。一旦我们求出该偏导数,就可以推导出整体代价函数 <math>\textstyle J(W,b)</math> 的偏导数:<br />
<br />
<br />
:<math><br />
\begin{align}<br />
\frac{\partial}{\partial W_{ij}^{(l)}} J(W,b) &=<br />
\left[ \frac{1}{m} \sum_{i=1}^m \frac{\partial}{\partial W_{ij}^{(l)}} J(W,b; x^{(i)}, y^{(i)}) \right] + \lambda W_{ij}^{(l)} \\<br />
\frac{\partial}{\partial b_{i}^{(l)}} J(W,b) &=<br />
\frac{1}{m}\sum_{i=1}^m \frac{\partial}{\partial b_{i}^{(l)}} J(W,b; x^{(i)}, y^{(i)})<br />
\end{align}<br />
</math> <br />
<br />
以上两行公式稍有不同,第一行比第二行多出一项,是因为权重衰减是作用于 <math>\textstyle W</math> 而不是 <math>\textstyle b</math>。<br />
<br />
<br />
反向传播算法的思路如下:给定一个样例 <math>\textstyle (x,y)</math>,我们首先进行“前向传导”运算,计算出网络中所有的激活值,包括 <math>\textstyle h_{W,b}(x)</math> 的输出值。之后,针对第 <math>\textstyle l</math> 层的每一个节点 <math>\textstyle i</math>,我们计算出其“残差” <math>\textstyle \delta^{(l)}_i</math>,该残差表明了该节点对最终输出值的残差产生了多少影响。对于最终的输出节点,我们可以直接算出网络产生的激活值与实际值之间的差距,我们将这个差距定义为 <math>\textstyle \delta^{(n_l)}_i</math> (第 <math>\textstyle n_l</math> 层表示输出层)。对于隐藏单元我们如何处理呢?我们将基于节点(译者注:第 <math>\textstyle l+1</math> 层节点)残差的加权平均值计算 <math>\textstyle \delta^{(l)}_i</math>,这些节点以 <math>\textstyle a^{(l)}_i</math> 作为输入。下面将给出反向传导算法的细节:<br />
<br />
<br />
<ol><br />
<li>进行前馈传导计算,利用前向传导公式,得到 <math>\textstyle L_2, L_3, \ldots </math> 直到输出层 <math>\textstyle L_{n_l}</math> 的激活值。<br />
<li>对于第 <math>\textstyle n_l</math> 层(输出层)的每个输出单元 <math>\textstyle i</math>,我们根据以下公式计算残差:<br />
<br />
<br />
:<math><br />
\begin{align}<br />
\delta^{(n_l)}_i<br />
= \frac{\partial}{\partial z^{(n_l)}_i} \;\;<br />
\frac{1}{2} \left\|y - h_{W,b}(x)\right\|^2 = - (y_i - a^{(n_l)}_i) \cdot f'(z^{(n_l)}_i)<br />
\end{align}<br />
</math><br />
<br />
[译者注:<br />
<br />
]<br />
<br />
<li>对 <math>\textstyle l = n_l-1, n_l-2, n_l-3, \ldots, 2</math> 的各个层,第 <math>\textstyle l</math> 层的第 <math>\textstyle i</math> 个节点的残差计算方法如下:<br />
: <math> <br />
\delta^{(l)}_i = \left( \sum_{j=1}^{s_{l+1}} W^{(l)}_{ji} \delta^{(l+1)}_j \right) f'(z^{(l)}_i)<br />
</math> <br />
<br />
<br />
<li>计算我们需要的偏导数,计算方法如下:<br />
:<math> <br />
\begin{align}<br />
\frac{\partial}{\partial W_{ij}^{(l)}} J(W,b; x, y) &= a^{(l)}_j \delta_i^{(l+1)} \\<br />
\frac{\partial}{\partial b_{i}^{(l)}} J(W,b; x, y) &= \delta_i^{(l+1)}.<br />
\end{align}<br />
</math> <br />
</ol><br />
<br />
<br />
最后,我们用矩阵-向量表示法重写以上算法。我们使用“<math>\textstyle \bullet</math>” 表示向量乘积运算符(在Matlab或Octave里用“<tt>.*</tt>”表示,也称作阿达马乘积)。若 <math>\textstyle a = b \bullet c</math>,则 <math>\textstyle a_i = b_ic_i</math>。在上一个教程中我们扩展了 <math>\textstyle f(\cdot)</math> 的定义,使其包含向量运算,这里我们也对偏导数 <math>\textstyle f'(\cdot)</math> 也做了同样的处理(于是又有 <math> \textstyle f'([z_1, z_2, z_3]) = [f'(z_1), f'(z_2), f'(z_3)]</math> )。<br />
<br />
<br />
那么,反向传播算法可表示为以下几个步骤:<br />
<br />
<ol><br />
<li>进行前馈传导计算,利用前向传导公式,得到 <math>\textstyle L_2, L_3, \ldots</math>直到输出层 <math>\textstyle L_{n_l}</math> 的激活值。<br />
<br />
<li>对输出层(第 <math>\textstyle n_l</math> 层),计算:<br />
<br />
:<math> \begin{align}<br />
\delta^{(n_l)}<br />
= - (y - a^{(n_l)}) \bullet f'(z^{(n_l)})<br />
\end{align}</math> <br />
<br />
<li>对于 <math>\textstyle l = n_l-1, n_l-2, n_l-3, \ldots, 2</math> 的各层,计算:<br />
:<math> \begin{align}<br />
\delta^{(l)} = \left((W^{(l)})^T \delta^{(l+1)}\right) \bullet f'(z^{(l)})<br />
\end{align}</math> <br />
<br />
<li>计算最终需要的偏导数值:<br />
:<math> \begin{align}<br />
\nabla_{W^{(l)}} J(W,b;x,y) &= \delta^{(l+1)} (a^{(l)})^T, \\<br />
\nabla_{b^{(l)}} J(W,b;x,y) &= \delta^{(l+1)}.<br />
\end{align}</math> <br />
</ol><br />
<br />
<br />
'''实现中应注意:'''在以上的第2步和第3步中,我们需要为每一个 <math>\textstyle i</math> 值计算其 <math>\textstyle f'(z^{(l)}_i)</math>。假设 <math>\textstyle f(z)</math> 是sigmoid函数,并且我们已经在前向传导运算中得到了 <math>\textstyle a^{(l)}_i</math>。那么,使用我们早先推导出的 <math>\textstyle f'(z)</math>表达式,就可以计算得到 <math>\textstyle f'(z^{(l)}_i) = a^{(l)}_i (1- a^{(l)}_i)</math>。<br />
<br />
<br />
最后,我们将对梯度下降算法做个全面总结。在下面的伪代码中,<math>\textstyle \Delta W^{(l)}</math> 是一个与矩阵 <math>\textstyle W^{(l)}</math> 维度相同的矩阵,<math>\textstyle \Delta b^{(l)}</math> 是一个与 <math>\textstyle b^{(l)}</math> 维度相同的向量。注意这里“<math>\textstyle \Delta W^{(l)}</math>”是一个矩阵,而不是“<math>\textstyle \Delta</math> 与 <math>\textstyle W^{(l)}</math> 相乘”。下面,我们实现批量梯度下降法中的一次迭代:<br />
<br />
<br />
<ol><br />
<li>对于所有 <math>\textstyle l</math>,令 <math>\textstyle \Delta W^{(l)} := 0</math> , <math>\textstyle \Delta b^{(l)} := 0</math> (设置为全零矩阵或全零向量)<br />
<br />
<li>对于 <math>\textstyle i = 1</math> 到 <math>\textstyle m</math>,<br />
<br />
<ol type="a"><br />
<li>使用反向传播算法计算 <math>\textstyle \nabla_{W^{(l)}} J(W,b;x,y)</math> 和 <math>\textstyle \nabla_{b^{(l)}} J(W,b;x,y)</math>。<br />
<li>计算 <math>\textstyle \Delta W^{(l)} := \Delta W^{(l)} + \nabla_{W^{(l)}} J(W,b;x,y)</math>。<br />
<li>计算 <math>\textstyle \Delta b^{(l)} := \Delta b^{(l)} + \nabla_{b^{(l)}} J(W,b;x,y)</math>。 <br />
</ol><br />
<br />
<li>更新权重参数:<br />
:<math> \begin{align}<br />
W^{(l)} &= W^{(l)} - \alpha \left[ \left(\frac{1}{m} \Delta W^{(l)} \right) + \lambda W^{(l)}\right] \\<br />
b^{(l)} &= b^{(l)} - \alpha \left[\frac{1}{m} \Delta b^{(l)}\right]<br />
\end{align}</math> <br />
</ol><br />
<br />
现在,我们可以重复梯度下降法的迭代步骤来减小代价函数 <math>\textstyle J(W,b)</math> 的值,进而求解我们的神经网络。<br />
<br />
<br />
==中英文对照==<br />
<br />
:反向传播算法 Backpropagation Algorithm<br />
:(批量)梯度下降法 (batch) gradient descent<br />
:(整体)代价函数 (overall) cost function<br />
:方差 squared-error<br />
:均方差 average sum-of-squares error<br />
:规则化项 regularization term<br />
:权重衰减 weight decay<br />
:偏置项 bias terms<br />
:贝叶斯规则化方法 Bayesian regularization method<br />
:高斯先验概率 Gaussian prior<br />
:极大后验估计 MAP<br />
:极大似然估计 maximum likelihood estimation<br />
:激活函数 activation function<br />
:双曲正切函数 tanh function<br />
:非凸函数 non-convex function<br />
:隐藏层单元 hidden (layer) units<br />
:对称失效 symmetry breaking<br />
:学习速率 learning rate<br />
:前向传导 forward pass<br />
:假设值 hypothesis <br />
:残差 error term<br />
:加权平均值 weighted average <br />
:前馈传导 feedforward pass<br />
:阿达马乘积 Hadamard product<br />
:前向传播 forward propagation<br />
<br />
<br />
==中文译者==<br />
<br />
王方(fangkey@gmail.com),林锋(xlfg@yeah.net),许利杰(csxulijie@gmail.com)<br />
<br />
<br />
{{稀疏自编码器}}<br />
<br />
<br />
<br />
{{Languages|Backpropagation_Algorithm|English}}</div>
Kandeng
http://ufldl.stanford.edu/wiki/index.php/%E5%8F%8D%E5%90%91%E4%BC%A0%E5%AF%BC%E7%AE%97%E6%B3%95
反向传导算法
2013-04-09T13:30:32Z
<p>Kandeng: </p>
<hr />
<div>假设我们有一个固定样本集 <math>\textstyle \{ (x^{(1)}, y^{(1)}), \ldots, (x^{(m)}, y^{(m)}) \}</math>,它包含 <math>\textstyle m</math> 个样例。我们可以用批量梯度下降法来求解神经网络。具体来讲,对于单个样例 <math>\textstyle (x,y)</math>,其代价函数为:<br />
<br />
:<math><br />
\begin{align}<br />
J(W,b; x,y) = \frac{1}{2} \left\| h_{W,b}(x) - y \right\|^2.<br />
\end{align}<br />
</math><br />
<br />
这是一个(二分之一的)方差代价函数。给定一个包含 <math>\textstyle m</math> 个样例的数据集,我们可以定义整体代价函数为:<br />
<br />
:<math> <br />
\begin{align}<br />
J(W,b)<br />
&= \left[ \frac{1}{m} \sum_{i=1}^m J(W,b;x^{(i)},y^{(i)}) \right]<br />
+ \frac{\lambda}{2} \sum_{l=1}^{n_l-1} \; \sum_{i=1}^{s_l} \; \sum_{j=1}^{s_{l+1}} \left( W^{(l)}_{ji} \right)^2<br />
\\<br />
&= \left[ \frac{1}{m} \sum_{i=1}^m \left( \frac{1}{2} \left\| h_{W,b}(x^{(i)}) - y^{(i)} \right\|^2 \right) \right]<br />
+ \frac{\lambda}{2} \sum_{l=1}^{n_l-1} \; \sum_{i=1}^{s_l} \; \sum_{j=1}^{s_{l+1}} \left( W^{(l)}_{ji} \right)^2<br />
\end{align}<br />
</math><br />
<br />
以上公式中的第一项 <math>\textstyle J(W,b)</math> 是一个均方差项。第二项是一个规则化项(也叫'''权重衰减项'''),其目的是减小权重的幅度,防止过度拟合。<br />
<br />
<br />
[注:通常权重衰减的计算并不使用偏置项 <math>\textstyle b^{(l)}_i</math>,比如我们在 <math>\textstyle J(W, b)</math> 的定义中就没有使用。一般来说,将偏置项包含在权重衰减项中只会对最终的神经网络产生很小的影响。如果你在斯坦福选修过CS229(机器学习)课程,或者在YouTube上看过课程视频,你会发现这个权重衰减实际上是课上提到的贝叶斯规则化方法的变种。在贝叶斯规则化方法中,我们将高斯先验概率引入到参数中计算MAP(极大后验)估计(而不是极大似然估计)。]<br />
<br />
<br />
'''权重衰减参数''' <math>\textstyle \lambda</math> 用于控制公式中两项的相对重要性。在此重申一下这两个复杂函数的含义:<math>\textstyle J(W,b;x,y)</math> 是针对单个样例计算得到的方差代价函数;<math>\textstyle J(W,b)</math> 是整体样本代价函数,它包含权重衰减项。<br />
<br />
<br />
以上的代价函数经常被用于分类和回归问题。在分类问题中,我们用 <math>\textstyle y = 0</math> 或 <math>\textstyle 1</math>,来代表两种类型的标签(回想一下,这是因为 sigmoid激活函数的值域为 <math>\textstyle [0,1]</math>;如果我们使用双曲正切型激活函数,那么应该选用 <math>\textstyle -1</math> 和 <math>\textstyle +1</math> 作为标签)。对于回归问题,我们首先要变换输出值域(译者注:也就是 <math>\textstyle y</math>),以保证其范围为 <math>\textstyle [0,1]</math> (同样地,如果我们使用双曲正切型激活函数,要使输出值域为 <math>\textstyle [-1,1]</math>)。<br />
<br />
<br />
我们的目标是针对参数 <math>\textstyle W</math> 和 <math>\textstyle b</math> 来求其函数 <math>\textstyle J(W,b)</math> 的最小值。为了求解神经网络,我们需要将每一个参数 <math>\textstyle W^{(l)}_{ij}</math> 和 <math>\textstyle b^{(l)}_i</math> 初始化为一个很小的、接近零的随机值(比如说,使用正态分布 <math>\textstyle {Normal}(0,\epsilon^2)</math> 生成的随机值,其中 <math>\textstyle \epsilon</math> 设置为 <math>\textstyle 0.01</math> ),之后对目标函数使用诸如批量梯度下降法的最优化算法。因为 <math>\textstyle J(W, b)</math> 是一个非凸函数,梯度下降法很可能会收敛到局部最优解;但是在实际应用中,梯度下降法通常能得到令人满意的结果。最后,需要再次强调的是,要将参数进行随机初始化,而不是全部置为 <math>\textstyle 0</math>。如果所有参数都用相同的值作为初始值,那么所有隐藏层单元最终会得到与输入值有关的、相同的函数(也就是说,对于所有 <math>\textstyle i</math>,<math>\textstyle W^{(1)}_{ij}</math>都会取相同的值,那么对于任何输入 <math>\textstyle x</math> 都会有:<math>\textstyle a^{(2)}_1 = a^{(2)}_2 = a^{(2)}_3 = \ldots</math> )。随机初始化的目的是使'''对称失效'''。<br />
<br />
<br />
梯度下降法中每一次迭代都按照如下公式对参数 <math>\textstyle W</math> 和<math>\textstyle b</math> 进行更新:<br />
<br />
:<math><br />
\begin{align}<br />
W_{ij}^{(l)} &= W_{ij}^{(l)} - \alpha \frac{\partial}{\partial W_{ij}^{(l)}} J(W,b) \\<br />
b_{i}^{(l)} &= b_{i}^{(l)} - \alpha \frac{\partial}{\partial b_{i}^{(l)}} J(W,b)<br />
\end{align}<br />
</math> <br />
<br />
其中 <math>\textstyle \alpha</math> 是学习速率。其中关键步骤是计算偏导数。我们现在来讲一下'''反向传播'''算法,它是计算偏导数的一种有效方法。<br />
<br />
<br />
我们首先来讲一下如何使用反向传播算法来计算 <math>\textstyle \frac{\partial}{\partial W_{ij}^{(l)}} J(W,b; x, y)</math> 和 <math>\textstyle \frac{\partial}{\partial b_{i}^{(l)}} J(W,b; x, y)</math>,这两项是单个样例 <math>\textstyle (x,y)</math> 的代价函数 <math>\textstyle J(W,b;x,y)</math> 的偏导数。一旦我们求出该偏导数,就可以推导出整体代价函数 <math>\textstyle J(W,b)</math> 的偏导数:<br />
<br />
<br />
:<math><br />
\begin{align}<br />
\frac{\partial}{\partial W_{ij}^{(l)}} J(W,b) &=<br />
\left[ \frac{1}{m} \sum_{i=1}^m \frac{\partial}{\partial W_{ij}^{(l)}} J(W,b; x^{(i)}, y^{(i)}) \right] + \lambda W_{ij}^{(l)} \\<br />
\frac{\partial}{\partial b_{i}^{(l)}} J(W,b) &=<br />
\frac{1}{m}\sum_{i=1}^m \frac{\partial}{\partial b_{i}^{(l)}} J(W,b; x^{(i)}, y^{(i)})<br />
\end{align}<br />
</math> <br />
<br />
以上两行公式稍有不同,第一行比第二行多出一项,是因为权重衰减是作用于 <math>\textstyle W</math> 而不是 <math>\textstyle b</math>。<br />
<br />
<br />
反向传播算法的思路如下:给定一个样例 <math>\textstyle (x,y)</math>,我们首先进行“前向传导”运算,计算出网络中所有的激活值,包括 <math>\textstyle h_{W,b}(x)</math> 的输出值。之后,针对第 <math>\textstyle l</math> 层的每一个节点 <math>\textstyle i</math>,我们计算出其“残差” <math>\textstyle \delta^{(l)}_i</math>,该残差表明了该节点对最终输出值的残差产生了多少影响。对于最终的输出节点,我们可以直接算出网络产生的激活值与实际值之间的差距,我们将这个差距定义为 <math>\textstyle \delta^{(n_l)}_i</math> (第 <math>\textstyle n_l</math> 层表示输出层)。对于隐藏单元我们如何处理呢?我们将基于节点(译者注:第 <math>\textstyle l+1</math> 层节点)残差的加权平均值计算 <math>\textstyle \delta^{(l)}_i</math>,这些节点以 <math>\textstyle a^{(l)}_i</math> 作为输入。下面将给出反向传导算法的细节:<br />
<br />
<br />
<ol><br />
<li>进行前馈传导计算,利用前向传导公式,得到 <math>\textstyle L_2, L_3, \ldots </math> 直到输出层 <math>\textstyle L_{n_l}</math> 的激活值。<br />
<li>对于第 <math>\textstyle n_l</math> 层(输出层)的每个输出单元 <math>\textstyle i</math>,我们根据以下公式计算残差:<br />
<br />
<br />
:<math><br />
\begin{align}<br />
\delta^{(n_l)}_i<br />
= \frac{\partial}{\partial z^{(n_l)}_i} \;\;<br />
\frac{1}{2} \left\|y - h_{W,b}(x)\right\|^2 = - (y_i - a^{(n_l)}_i) \cdot f'(z^{(n_l)}_i)<br />
\end{align}<br />
</math><br />
<br />
[译者注:<br />
:<math> <br />
\delta^{(n_l)}_i = \frac{\partial}{\partial z^{n_l}_i}J(W,b;x,y)<br />
= \frac{\partial}{\partial z^{n_l}_i}\frac{1}{2} \left\|y - h_{W,b}(x)\right\|^2<br />
= \frac{\partial}{\partial z^{n_l}_i}\frac{1}{2} \sum_{j=1}^S_n_l(y_j-a_j^(n_l))^2<br />
</math> <br />
]<br />
<br />
<li>对 <math>\textstyle l = n_l-1, n_l-2, n_l-3, \ldots, 2</math> 的各个层,第 <math>\textstyle l</math> 层的第 <math>\textstyle i</math> 个节点的残差计算方法如下:<br />
: <math> <br />
\delta^{(l)}_i = \left( \sum_{j=1}^{s_{l+1}} W^{(l)}_{ji} \delta^{(l+1)}_j \right) f'(z^{(l)}_i)<br />
</math> <br />
<br />
<br />
<li>计算我们需要的偏导数,计算方法如下:<br />
:<math> <br />
\begin{align}<br />
\frac{\partial}{\partial W_{ij}^{(l)}} J(W,b; x, y) &= a^{(l)}_j \delta_i^{(l+1)} \\<br />
\frac{\partial}{\partial b_{i}^{(l)}} J(W,b; x, y) &= \delta_i^{(l+1)}.<br />
\end{align}<br />
</math> <br />
</ol><br />
<br />
<br />
最后,我们用矩阵-向量表示法重写以上算法。我们使用“<math>\textstyle \bullet</math>” 表示向量乘积运算符(在Matlab或Octave里用“<tt>.*</tt>”表示,也称作阿达马乘积)。若 <math>\textstyle a = b \bullet c</math>,则 <math>\textstyle a_i = b_ic_i</math>。在上一个教程中我们扩展了 <math>\textstyle f(\cdot)</math> 的定义,使其包含向量运算,这里我们也对偏导数 <math>\textstyle f'(\cdot)</math> 也做了同样的处理(于是又有 <math> \textstyle f'([z_1, z_2, z_3]) = [f'(z_1), f'(z_2), f'(z_3)]</math> )。<br />
<br />
<br />
那么,反向传播算法可表示为以下几个步骤:<br />
<br />
<ol><br />
<li>进行前馈传导计算,利用前向传导公式,得到 <math>\textstyle L_2, L_3, \ldots</math>直到输出层 <math>\textstyle L_{n_l}</math> 的激活值。<br />
<br />
<li>对输出层(第 <math>\textstyle n_l</math> 层),计算:<br />
<br />
:<math> \begin{align}<br />
\delta^{(n_l)}<br />
= - (y - a^{(n_l)}) \bullet f'(z^{(n_l)})<br />
\end{align}</math> <br />
<br />
<li>对于 <math>\textstyle l = n_l-1, n_l-2, n_l-3, \ldots, 2</math> 的各层,计算:<br />
:<math> \begin{align}<br />
\delta^{(l)} = \left((W^{(l)})^T \delta^{(l+1)}\right) \bullet f'(z^{(l)})<br />
\end{align}</math> <br />
<br />
<li>计算最终需要的偏导数值:<br />
:<math> \begin{align}<br />
\nabla_{W^{(l)}} J(W,b;x,y) &= \delta^{(l+1)} (a^{(l)})^T, \\<br />
\nabla_{b^{(l)}} J(W,b;x,y) &= \delta^{(l+1)}.<br />
\end{align}</math> <br />
</ol><br />
<br />
<br />
'''实现中应注意:'''在以上的第2步和第3步中,我们需要为每一个 <math>\textstyle i</math> 值计算其 <math>\textstyle f'(z^{(l)}_i)</math>。假设 <math>\textstyle f(z)</math> 是sigmoid函数,并且我们已经在前向传导运算中得到了 <math>\textstyle a^{(l)}_i</math>。那么,使用我们早先推导出的 <math>\textstyle f'(z)</math>表达式,就可以计算得到 <math>\textstyle f'(z^{(l)}_i) = a^{(l)}_i (1- a^{(l)}_i)</math>。<br />
<br />
<br />
最后,我们将对梯度下降算法做个全面总结。在下面的伪代码中,<math>\textstyle \Delta W^{(l)}</math> 是一个与矩阵 <math>\textstyle W^{(l)}</math> 维度相同的矩阵,<math>\textstyle \Delta b^{(l)}</math> 是一个与 <math>\textstyle b^{(l)}</math> 维度相同的向量。注意这里“<math>\textstyle \Delta W^{(l)}</math>”是一个矩阵,而不是“<math>\textstyle \Delta</math> 与 <math>\textstyle W^{(l)}</math> 相乘”。下面,我们实现批量梯度下降法中的一次迭代:<br />
<br />
<br />
<ol><br />
<li>对于所有 <math>\textstyle l</math>,令 <math>\textstyle \Delta W^{(l)} := 0</math> , <math>\textstyle \Delta b^{(l)} := 0</math> (设置为全零矩阵或全零向量)<br />
<br />
<li>对于 <math>\textstyle i = 1</math> 到 <math>\textstyle m</math>,<br />
<br />
<ol type="a"><br />
<li>使用反向传播算法计算 <math>\textstyle \nabla_{W^{(l)}} J(W,b;x,y)</math> 和 <math>\textstyle \nabla_{b^{(l)}} J(W,b;x,y)</math>。<br />
<li>计算 <math>\textstyle \Delta W^{(l)} := \Delta W^{(l)} + \nabla_{W^{(l)}} J(W,b;x,y)</math>。<br />
<li>计算 <math>\textstyle \Delta b^{(l)} := \Delta b^{(l)} + \nabla_{b^{(l)}} J(W,b;x,y)</math>。 <br />
</ol><br />
<br />
<li>更新权重参数:<br />
:<math> \begin{align}<br />
W^{(l)} &= W^{(l)} - \alpha \left[ \left(\frac{1}{m} \Delta W^{(l)} \right) + \lambda W^{(l)}\right] \\<br />
b^{(l)} &= b^{(l)} - \alpha \left[\frac{1}{m} \Delta b^{(l)}\right]<br />
\end{align}</math> <br />
</ol><br />
<br />
现在,我们可以重复梯度下降法的迭代步骤来减小代价函数 <math>\textstyle J(W,b)</math> 的值,进而求解我们的神经网络。<br />
<br />
<br />
==中英文对照==<br />
<br />
:反向传播算法 Backpropagation Algorithm<br />
:(批量)梯度下降法 (batch) gradient descent<br />
:(整体)代价函数 (overall) cost function<br />
:方差 squared-error<br />
:均方差 average sum-of-squares error<br />
:规则化项 regularization term<br />
:权重衰减 weight decay<br />
:偏置项 bias terms<br />
:贝叶斯规则化方法 Bayesian regularization method<br />
:高斯先验概率 Gaussian prior<br />
:极大后验估计 MAP<br />
:极大似然估计 maximum likelihood estimation<br />
:激活函数 activation function<br />
:双曲正切函数 tanh function<br />
:非凸函数 non-convex function<br />
:隐藏层单元 hidden (layer) units<br />
:对称失效 symmetry breaking<br />
:学习速率 learning rate<br />
:前向传导 forward pass<br />
:假设值 hypothesis <br />
:残差 error term<br />
:加权平均值 weighted average <br />
:前馈传导 feedforward pass<br />
:阿达马乘积 Hadamard product<br />
:前向传播 forward propagation<br />
<br />
<br />
==中文译者==<br />
<br />
王方(fangkey@gmail.com),林锋(xlfg@yeah.net),许利杰(csxulijie@gmail.com)<br />
<br />
<br />
{{稀疏自编码器}}<br />
<br />
<br />
<br />
{{Languages|Backpropagation_Algorithm|English}}</div>
Kandeng
http://ufldl.stanford.edu/wiki/index.php/%E5%8F%8D%E5%90%91%E4%BC%A0%E5%AF%BC%E7%AE%97%E6%B3%95
反向传导算法
2013-04-09T13:29:42Z
<p>Kandeng: </p>
<hr />
<div>假设我们有一个固定样本集 <math>\textstyle \{ (x^{(1)}, y^{(1)}), \ldots, (x^{(m)}, y^{(m)}) \}</math>,它包含 <math>\textstyle m</math> 个样例。我们可以用批量梯度下降法来求解神经网络。具体来讲,对于单个样例 <math>\textstyle (x,y)</math>,其代价函数为:<br />
<br />
:<math><br />
\begin{align}<br />
J(W,b; x,y) = \frac{1}{2} \left\| h_{W,b}(x) - y \right\|^2.<br />
\end{align}<br />
</math><br />
<br />
这是一个(二分之一的)方差代价函数。给定一个包含 <math>\textstyle m</math> 个样例的数据集,我们可以定义整体代价函数为:<br />
<br />
:<math> <br />
\begin{align}<br />
J(W,b)<br />
&= \left[ \frac{1}{m} \sum_{i=1}^m J(W,b;x^{(i)},y^{(i)}) \right]<br />
+ \frac{\lambda}{2} \sum_{l=1}^{n_l-1} \; \sum_{i=1}^{s_l} \; \sum_{j=1}^{s_{l+1}} \left( W^{(l)}_{ji} \right)^2<br />
\\<br />
&= \left[ \frac{1}{m} \sum_{i=1}^m \left( \frac{1}{2} \left\| h_{W,b}(x^{(i)}) - y^{(i)} \right\|^2 \right) \right]<br />
+ \frac{\lambda}{2} \sum_{l=1}^{n_l-1} \; \sum_{i=1}^{s_l} \; \sum_{j=1}^{s_{l+1}} \left( W^{(l)}_{ji} \right)^2<br />
\end{align}<br />
</math><br />
<br />
以上公式中的第一项 <math>\textstyle J(W,b)</math> 是一个均方差项。第二项是一个规则化项(也叫'''权重衰减项'''),其目的是减小权重的幅度,防止过度拟合。<br />
<br />
<br />
[注:通常权重衰减的计算并不使用偏置项 <math>\textstyle b^{(l)}_i</math>,比如我们在 <math>\textstyle J(W, b)</math> 的定义中就没有使用。一般来说,将偏置项包含在权重衰减项中只会对最终的神经网络产生很小的影响。如果你在斯坦福选修过CS229(机器学习)课程,或者在YouTube上看过课程视频,你会发现这个权重衰减实际上是课上提到的贝叶斯规则化方法的变种。在贝叶斯规则化方法中,我们将高斯先验概率引入到参数中计算MAP(极大后验)估计(而不是极大似然估计)。]<br />
<br />
<br />
'''权重衰减参数''' <math>\textstyle \lambda</math> 用于控制公式中两项的相对重要性。在此重申一下这两个复杂函数的含义:<math>\textstyle J(W,b;x,y)</math> 是针对单个样例计算得到的方差代价函数;<math>\textstyle J(W,b)</math> 是整体样本代价函数,它包含权重衰减项。<br />
<br />
<br />
以上的代价函数经常被用于分类和回归问题。在分类问题中,我们用 <math>\textstyle y = 0</math> 或 <math>\textstyle 1</math>,来代表两种类型的标签(回想一下,这是因为 sigmoid激活函数的值域为 <math>\textstyle [0,1]</math>;如果我们使用双曲正切型激活函数,那么应该选用 <math>\textstyle -1</math> 和 <math>\textstyle +1</math> 作为标签)。对于回归问题,我们首先要变换输出值域(译者注:也就是 <math>\textstyle y</math>),以保证其范围为 <math>\textstyle [0,1]</math> (同样地,如果我们使用双曲正切型激活函数,要使输出值域为 <math>\textstyle [-1,1]</math>)。<br />
<br />
<br />
我们的目标是针对参数 <math>\textstyle W</math> 和 <math>\textstyle b</math> 来求其函数 <math>\textstyle J(W,b)</math> 的最小值。为了求解神经网络,我们需要将每一个参数 <math>\textstyle W^{(l)}_{ij}</math> 和 <math>\textstyle b^{(l)}_i</math> 初始化为一个很小的、接近零的随机值(比如说,使用正态分布 <math>\textstyle {Normal}(0,\epsilon^2)</math> 生成的随机值,其中 <math>\textstyle \epsilon</math> 设置为 <math>\textstyle 0.01</math> ),之后对目标函数使用诸如批量梯度下降法的最优化算法。因为 <math>\textstyle J(W, b)</math> 是一个非凸函数,梯度下降法很可能会收敛到局部最优解;但是在实际应用中,梯度下降法通常能得到令人满意的结果。最后,需要再次强调的是,要将参数进行随机初始化,而不是全部置为 <math>\textstyle 0</math>。如果所有参数都用相同的值作为初始值,那么所有隐藏层单元最终会得到与输入值有关的、相同的函数(也就是说,对于所有 <math>\textstyle i</math>,<math>\textstyle W^{(1)}_{ij}</math>都会取相同的值,那么对于任何输入 <math>\textstyle x</math> 都会有:<math>\textstyle a^{(2)}_1 = a^{(2)}_2 = a^{(2)}_3 = \ldots</math> )。随机初始化的目的是使'''对称失效'''。<br />
<br />
<br />
梯度下降法中每一次迭代都按照如下公式对参数 <math>\textstyle W</math> 和<math>\textstyle b</math> 进行更新:<br />
<br />
:<math><br />
\begin{align}<br />
W_{ij}^{(l)} &= W_{ij}^{(l)} - \alpha \frac{\partial}{\partial W_{ij}^{(l)}} J(W,b) \\<br />
b_{i}^{(l)} &= b_{i}^{(l)} - \alpha \frac{\partial}{\partial b_{i}^{(l)}} J(W,b)<br />
\end{align}<br />
</math> <br />
<br />
其中 <math>\textstyle \alpha</math> 是学习速率。其中关键步骤是计算偏导数。我们现在来讲一下'''反向传播'''算法,它是计算偏导数的一种有效方法。<br />
<br />
<br />
我们首先来讲一下如何使用反向传播算法来计算 <math>\textstyle \frac{\partial}{\partial W_{ij}^{(l)}} J(W,b; x, y)</math> 和 <math>\textstyle \frac{\partial}{\partial b_{i}^{(l)}} J(W,b; x, y)</math>,这两项是单个样例 <math>\textstyle (x,y)</math> 的代价函数 <math>\textstyle J(W,b;x,y)</math> 的偏导数。一旦我们求出该偏导数,就可以推导出整体代价函数 <math>\textstyle J(W,b)</math> 的偏导数:<br />
<br />
<br />
:<math><br />
\begin{align}<br />
\frac{\partial}{\partial W_{ij}^{(l)}} J(W,b) &=<br />
\left[ \frac{1}{m} \sum_{i=1}^m \frac{\partial}{\partial W_{ij}^{(l)}} J(W,b; x^{(i)}, y^{(i)}) \right] + \lambda W_{ij}^{(l)} \\<br />
\frac{\partial}{\partial b_{i}^{(l)}} J(W,b) &=<br />
\frac{1}{m}\sum_{i=1}^m \frac{\partial}{\partial b_{i}^{(l)}} J(W,b; x^{(i)}, y^{(i)})<br />
\end{align}<br />
</math> <br />
<br />
以上两行公式稍有不同,第一行比第二行多出一项,是因为权重衰减是作用于 <math>\textstyle W</math> 而不是 <math>\textstyle b</math>。<br />
<br />
<br />
反向传播算法的思路如下:给定一个样例 <math>\textstyle (x,y)</math>,我们首先进行“前向传导”运算,计算出网络中所有的激活值,包括 <math>\textstyle h_{W,b}(x)</math> 的输出值。之后,针对第 <math>\textstyle l</math> 层的每一个节点 <math>\textstyle i</math>,我们计算出其“残差” <math>\textstyle \delta^{(l)}_i</math>,该残差表明了该节点对最终输出值的残差产生了多少影响。对于最终的输出节点,我们可以直接算出网络产生的激活值与实际值之间的差距,我们将这个差距定义为 <math>\textstyle \delta^{(n_l)}_i</math> (第 <math>\textstyle n_l</math> 层表示输出层)。对于隐藏单元我们如何处理呢?我们将基于节点(译者注:第 <math>\textstyle l+1</math> 层节点)残差的加权平均值计算 <math>\textstyle \delta^{(l)}_i</math>,这些节点以 <math>\textstyle a^{(l)}_i</math> 作为输入。下面将给出反向传导算法的细节:<br />
<br />
<br />
<ol><br />
<li>进行前馈传导计算,利用前向传导公式,得到 <math>\textstyle L_2, L_3, \ldots </math> 直到输出层 <math>\textstyle L_{n_l}</math> 的激活值。<br />
<li>对于第 <math>\textstyle n_l</math> 层(输出层)的每个输出单元 <math>\textstyle i</math>,我们根据以下公式计算残差:<br />
<br />
<br />
:<math><br />
\begin{align}<br />
\delta^{(n_l)}_i<br />
= \frac{\partial}{\partial z^{(n_l)}_i} \;\;<br />
\frac{1}{2} \left\|y - h_{W,b}(x)\right\|^2 = - (y_i - a^{(n_l)}_i) \cdot f'(z^{(n_l)}_i)<br />
\end{align}<br />
</math><br />
<br />
[译者注:<br />
:<math> <br />
\delta^{(n_l)}_i = \frac{\partial}{\partial z^{n_l}_i}J(W,b;x,y)<br />
= \frac{\partial}{\partial z^{n_l}_i}\frac{1}{2} \left\|y - h_{W,b}(x)\right\|^2<br />
= \frac{\partial}{\partial z^{n_l}_i}\frac{1}{2} \sum_{j=1}^S_n_l(y_j-a_j^(n_l))^2<br />
= \frac{\partial}{\partial z^{n_l}_i}\frac{1}{2} \sum_{j=1}^S_n_l(y_j-f(z_j^(n_l)))^2<br />
= - (y_i - f(z_j^(n_l))) \cdot f'(z^{(n_l)}_i)<br />
= - (y_i - a^{(n_l)}_i) \cdot f'(z^{(n_l)}_i)<br />
</math> <br />
]<br />
<br />
<li>对 <math>\textstyle l = n_l-1, n_l-2, n_l-3, \ldots, 2</math> 的各个层,第 <math>\textstyle l</math> 层的第 <math>\textstyle i</math> 个节点的残差计算方法如下:<br />
: <math> <br />
\delta^{(l)}_i = \left( \sum_{j=1}^{s_{l+1}} W^{(l)}_{ji} \delta^{(l+1)}_j \right) f'(z^{(l)}_i)<br />
</math> <br />
<br />
<br />
<li>计算我们需要的偏导数,计算方法如下:<br />
:<math> <br />
\begin{align}<br />
\frac{\partial}{\partial W_{ij}^{(l)}} J(W,b; x, y) &= a^{(l)}_j \delta_i^{(l+1)} \\<br />
\frac{\partial}{\partial b_{i}^{(l)}} J(W,b; x, y) &= \delta_i^{(l+1)}.<br />
\end{align}<br />
</math> <br />
</ol><br />
<br />
<br />
最后,我们用矩阵-向量表示法重写以上算法。我们使用“<math>\textstyle \bullet</math>” 表示向量乘积运算符(在Matlab或Octave里用“<tt>.*</tt>”表示,也称作阿达马乘积)。若 <math>\textstyle a = b \bullet c</math>,则 <math>\textstyle a_i = b_ic_i</math>。在上一个教程中我们扩展了 <math>\textstyle f(\cdot)</math> 的定义,使其包含向量运算,这里我们也对偏导数 <math>\textstyle f'(\cdot)</math> 也做了同样的处理(于是又有 <math> \textstyle f'([z_1, z_2, z_3]) = [f'(z_1), f'(z_2), f'(z_3)]</math> )。<br />
<br />
<br />
那么,反向传播算法可表示为以下几个步骤:<br />
<br />
<ol><br />
<li>进行前馈传导计算,利用前向传导公式,得到 <math>\textstyle L_2, L_3, \ldots</math>直到输出层 <math>\textstyle L_{n_l}</math> 的激活值。<br />
<br />
<li>对输出层(第 <math>\textstyle n_l</math> 层),计算:<br />
<br />
:<math> \begin{align}<br />
\delta^{(n_l)}<br />
= - (y - a^{(n_l)}) \bullet f'(z^{(n_l)})<br />
\end{align}</math> <br />
<br />
<li>对于 <math>\textstyle l = n_l-1, n_l-2, n_l-3, \ldots, 2</math> 的各层,计算:<br />
:<math> \begin{align}<br />
\delta^{(l)} = \left((W^{(l)})^T \delta^{(l+1)}\right) \bullet f'(z^{(l)})<br />
\end{align}</math> <br />
<br />
<li>计算最终需要的偏导数值:<br />
:<math> \begin{align}<br />
\nabla_{W^{(l)}} J(W,b;x,y) &= \delta^{(l+1)} (a^{(l)})^T, \\<br />
\nabla_{b^{(l)}} J(W,b;x,y) &= \delta^{(l+1)}.<br />
\end{align}</math> <br />
</ol><br />
<br />
<br />
'''实现中应注意:'''在以上的第2步和第3步中,我们需要为每一个 <math>\textstyle i</math> 值计算其 <math>\textstyle f'(z^{(l)}_i)</math>。假设 <math>\textstyle f(z)</math> 是sigmoid函数,并且我们已经在前向传导运算中得到了 <math>\textstyle a^{(l)}_i</math>。那么,使用我们早先推导出的 <math>\textstyle f'(z)</math>表达式,就可以计算得到 <math>\textstyle f'(z^{(l)}_i) = a^{(l)}_i (1- a^{(l)}_i)</math>。<br />
<br />
<br />
最后,我们将对梯度下降算法做个全面总结。在下面的伪代码中,<math>\textstyle \Delta W^{(l)}</math> 是一个与矩阵 <math>\textstyle W^{(l)}</math> 维度相同的矩阵,<math>\textstyle \Delta b^{(l)}</math> 是一个与 <math>\textstyle b^{(l)}</math> 维度相同的向量。注意这里“<math>\textstyle \Delta W^{(l)}</math>”是一个矩阵,而不是“<math>\textstyle \Delta</math> 与 <math>\textstyle W^{(l)}</math> 相乘”。下面,我们实现批量梯度下降法中的一次迭代:<br />
<br />
<br />
<ol><br />
<li>对于所有 <math>\textstyle l</math>,令 <math>\textstyle \Delta W^{(l)} := 0</math> , <math>\textstyle \Delta b^{(l)} := 0</math> (设置为全零矩阵或全零向量)<br />
<br />
<li>对于 <math>\textstyle i = 1</math> 到 <math>\textstyle m</math>,<br />
<br />
<ol type="a"><br />
<li>使用反向传播算法计算 <math>\textstyle \nabla_{W^{(l)}} J(W,b;x,y)</math> 和 <math>\textstyle \nabla_{b^{(l)}} J(W,b;x,y)</math>。<br />
<li>计算 <math>\textstyle \Delta W^{(l)} := \Delta W^{(l)} + \nabla_{W^{(l)}} J(W,b;x,y)</math>。<br />
<li>计算 <math>\textstyle \Delta b^{(l)} := \Delta b^{(l)} + \nabla_{b^{(l)}} J(W,b;x,y)</math>。 <br />
</ol><br />
<br />
<li>更新权重参数:<br />
:<math> \begin{align}<br />
W^{(l)} &= W^{(l)} - \alpha \left[ \left(\frac{1}{m} \Delta W^{(l)} \right) + \lambda W^{(l)}\right] \\<br />
b^{(l)} &= b^{(l)} - \alpha \left[\frac{1}{m} \Delta b^{(l)}\right]<br />
\end{align}</math> <br />
</ol><br />
<br />
现在,我们可以重复梯度下降法的迭代步骤来减小代价函数 <math>\textstyle J(W,b)</math> 的值,进而求解我们的神经网络。<br />
<br />
<br />
==中英文对照==<br />
<br />
:反向传播算法 Backpropagation Algorithm<br />
:(批量)梯度下降法 (batch) gradient descent<br />
:(整体)代价函数 (overall) cost function<br />
:方差 squared-error<br />
:均方差 average sum-of-squares error<br />
:规则化项 regularization term<br />
:权重衰减 weight decay<br />
:偏置项 bias terms<br />
:贝叶斯规则化方法 Bayesian regularization method<br />
:高斯先验概率 Gaussian prior<br />
:极大后验估计 MAP<br />
:极大似然估计 maximum likelihood estimation<br />
:激活函数 activation function<br />
:双曲正切函数 tanh function<br />
:非凸函数 non-convex function<br />
:隐藏层单元 hidden (layer) units<br />
:对称失效 symmetry breaking<br />
:学习速率 learning rate<br />
:前向传导 forward pass<br />
:假设值 hypothesis <br />
:残差 error term<br />
:加权平均值 weighted average <br />
:前馈传导 feedforward pass<br />
:阿达马乘积 Hadamard product<br />
:前向传播 forward propagation<br />
<br />
<br />
==中文译者==<br />
<br />
王方(fangkey@gmail.com),林锋(xlfg@yeah.net),许利杰(csxulijie@gmail.com)<br />
<br />
<br />
{{稀疏自编码器}}<br />
<br />
<br />
<br />
{{Languages|Backpropagation_Algorithm|English}}</div>
Kandeng
http://ufldl.stanford.edu/wiki/index.php/%E5%8F%8D%E5%90%91%E4%BC%A0%E5%AF%BC%E7%AE%97%E6%B3%95
反向传导算法
2013-04-09T13:17:42Z
<p>Kandeng: </p>
<hr />
<div>假设我们有一个固定样本集 <math>\textstyle \{ (x^{(1)}, y^{(1)}), \ldots, (x^{(m)}, y^{(m)}) \}</math>,它包含 <math>\textstyle m</math> 个样例。我们可以用批量梯度下降法来求解神经网络。具体来讲,对于单个样例 <math>\textstyle (x,y)</math>,其代价函数为:<br />
<br />
:<math><br />
\begin{align}<br />
J(W,b; x,y) = \frac{1}{2} \left\| h_{W,b}(x) - y \right\|^2.<br />
\end{align}<br />
</math><br />
<br />
这是一个(二分之一的)方差代价函数。给定一个包含 <math>\textstyle m</math> 个样例的数据集,我们可以定义整体代价函数为:<br />
<br />
:<math> <br />
\begin{align}<br />
J(W,b)<br />
&= \left[ \frac{1}{m} \sum_{i=1}^m J(W,b;x^{(i)},y^{(i)}) \right]<br />
+ \frac{\lambda}{2} \sum_{l=1}^{n_l-1} \; \sum_{i=1}^{s_l} \; \sum_{j=1}^{s_{l+1}} \left( W^{(l)}_{ji} \right)^2<br />
\\<br />
&= \left[ \frac{1}{m} \sum_{i=1}^m \left( \frac{1}{2} \left\| h_{W,b}(x^{(i)}) - y^{(i)} \right\|^2 \right) \right]<br />
+ \frac{\lambda}{2} \sum_{l=1}^{n_l-1} \; \sum_{i=1}^{s_l} \; \sum_{j=1}^{s_{l+1}} \left( W^{(l)}_{ji} \right)^2<br />
\end{align}<br />
</math><br />
<br />
以上公式中的第一项 <math>\textstyle J(W,b)</math> 是一个均方差项。第二项是一个规则化项(也叫'''权重衰减项'''),其目的是减小权重的幅度,防止过度拟合。<br />
<br />
<br />
[注:通常权重衰减的计算并不使用偏置项 <math>\textstyle b^{(l)}_i</math>,比如我们在 <math>\textstyle J(W, b)</math> 的定义中就没有使用。一般来说,将偏置项包含在权重衰减项中只会对最终的神经网络产生很小的影响。如果你在斯坦福选修过CS229(机器学习)课程,或者在YouTube上看过课程视频,你会发现这个权重衰减实际上是课上提到的贝叶斯规则化方法的变种。在贝叶斯规则化方法中,我们将高斯先验概率引入到参数中计算MAP(极大后验)估计(而不是极大似然估计)。]<br />
<br />
<br />
'''权重衰减参数''' <math>\textstyle \lambda</math> 用于控制公式中两项的相对重要性。在此重申一下这两个复杂函数的含义:<math>\textstyle J(W,b;x,y)</math> 是针对单个样例计算得到的方差代价函数;<math>\textstyle J(W,b)</math> 是整体样本代价函数,它包含权重衰减项。<br />
<br />
<br />
以上的代价函数经常被用于分类和回归问题。在分类问题中,我们用 <math>\textstyle y = 0</math> 或 <math>\textstyle 1</math>,来代表两种类型的标签(回想一下,这是因为 sigmoid激活函数的值域为 <math>\textstyle [0,1]</math>;如果我们使用双曲正切型激活函数,那么应该选用 <math>\textstyle -1</math> 和 <math>\textstyle +1</math> 作为标签)。对于回归问题,我们首先要变换输出值域(译者注:也就是 <math>\textstyle y</math>),以保证其范围为 <math>\textstyle [0,1]</math> (同样地,如果我们使用双曲正切型激活函数,要使输出值域为 <math>\textstyle [-1,1]</math>)。<br />
<br />
<br />
我们的目标是针对参数 <math>\textstyle W</math> 和 <math>\textstyle b</math> 来求其函数 <math>\textstyle J(W,b)</math> 的最小值。为了求解神经网络,我们需要将每一个参数 <math>\textstyle W^{(l)}_{ij}</math> 和 <math>\textstyle b^{(l)}_i</math> 初始化为一个很小的、接近零的随机值(比如说,使用正态分布 <math>\textstyle {Normal}(0,\epsilon^2)</math> 生成的随机值,其中 <math>\textstyle \epsilon</math> 设置为 <math>\textstyle 0.01</math> ),之后对目标函数使用诸如批量梯度下降法的最优化算法。因为 <math>\textstyle J(W, b)</math> 是一个非凸函数,梯度下降法很可能会收敛到局部最优解;但是在实际应用中,梯度下降法通常能得到令人满意的结果。最后,需要再次强调的是,要将参数进行随机初始化,而不是全部置为 <math>\textstyle 0</math>。如果所有参数都用相同的值作为初始值,那么所有隐藏层单元最终会得到与输入值有关的、相同的函数(也就是说,对于所有 <math>\textstyle i</math>,<math>\textstyle W^{(1)}_{ij}</math>都会取相同的值,那么对于任何输入 <math>\textstyle x</math> 都会有:<math>\textstyle a^{(2)}_1 = a^{(2)}_2 = a^{(2)}_3 = \ldots</math> )。随机初始化的目的是使'''对称失效'''。<br />
<br />
<br />
梯度下降法中每一次迭代都按照如下公式对参数 <math>\textstyle W</math> 和<math>\textstyle b</math> 进行更新:<br />
<br />
:<math><br />
\begin{align}<br />
W_{ij}^{(l)} &= W_{ij}^{(l)} - \alpha \frac{\partial}{\partial W_{ij}^{(l)}} J(W,b) \\<br />
b_{i}^{(l)} &= b_{i}^{(l)} - \alpha \frac{\partial}{\partial b_{i}^{(l)}} J(W,b)<br />
\end{align}<br />
</math> <br />
<br />
其中 <math>\textstyle \alpha</math> 是学习速率。其中关键步骤是计算偏导数。我们现在来讲一下'''反向传播'''算法,它是计算偏导数的一种有效方法。<br />
<br />
<br />
我们首先来讲一下如何使用反向传播算法来计算 <math>\textstyle \frac{\partial}{\partial W_{ij}^{(l)}} J(W,b; x, y)</math> 和 <math>\textstyle \frac{\partial}{\partial b_{i}^{(l)}} J(W,b; x, y)</math>,这两项是单个样例 <math>\textstyle (x,y)</math> 的代价函数 <math>\textstyle J(W,b;x,y)</math> 的偏导数。一旦我们求出该偏导数,就可以推导出整体代价函数 <math>\textstyle J(W,b)</math> 的偏导数:<br />
<br />
<br />
:<math><br />
\begin{align}<br />
\frac{\partial}{\partial W_{ij}^{(l)}} J(W,b) &=<br />
\left[ \frac{1}{m} \sum_{i=1}^m \frac{\partial}{\partial W_{ij}^{(l)}} J(W,b; x^{(i)}, y^{(i)}) \right] + \lambda W_{ij}^{(l)} \\<br />
\frac{\partial}{\partial b_{i}^{(l)}} J(W,b) &=<br />
\frac{1}{m}\sum_{i=1}^m \frac{\partial}{\partial b_{i}^{(l)}} J(W,b; x^{(i)}, y^{(i)})<br />
\end{align}<br />
</math> <br />
<br />
以上两行公式稍有不同,第一行比第二行多出一项,是因为权重衰减是作用于 <math>\textstyle W</math> 而不是 <math>\textstyle b</math>。<br />
<br />
<br />
反向传播算法的思路如下:给定一个样例 <math>\textstyle (x,y)</math>,我们首先进行“前向传导”运算,计算出网络中所有的激活值,包括 <math>\textstyle h_{W,b}(x)</math> 的输出值。之后,针对第 <math>\textstyle l</math> 层的每一个节点 <math>\textstyle i</math>,我们计算出其“残差” <math>\textstyle \delta^{(l)}_i</math>,该残差表明了该节点对最终输出值的残差产生了多少影响。对于最终的输出节点,我们可以直接算出网络产生的激活值与实际值之间的差距,我们将这个差距定义为 <math>\textstyle \delta^{(n_l)}_i</math> (第 <math>\textstyle n_l</math> 层表示输出层)。对于隐藏单元我们如何处理呢?我们将基于节点(译者注:第 <math>\textstyle l+1</math> 层节点)残差的加权平均值计算 <math>\textstyle \delta^{(l)}_i</math>,这些节点以 <math>\textstyle a^{(l)}_i</math> 作为输入。下面将给出反向传导算法的细节:<br />
<br />
<br />
<ol><br />
<li>进行前馈传导计算,利用前向传导公式,得到 <math>\textstyle L_2, L_3, \ldots </math> 直到输出层 <math>\textstyle L_{n_l}</math> 的激活值。<br />
<li>对于第 <math>\textstyle n_l</math> 层(输出层)的每个输出单元 <math>\textstyle i</math>,我们根据以下公式计算残差:<br />
<br />
<br />
:<math><br />
\begin{align}<br />
\delta^{(n_l)}_i<br />
= \frac{\partial}{\partial z^{(n_l)}_i} \;\;<br />
\frac{1}{2} \left\|y - h_{W,b}(x)\right\|^2 = - (y_i - a^{(n_l)}_i) \cdot f'(z^{(n_l)}_i)<br />
\end{align}<br />
</math><br />
<br />
<br />
<li>对 <math>\textstyle l = n_l-1, n_l-2, n_l-3, \ldots, 2</math> 的各个层,第 <math>\textstyle l</math> 层的第 <math>\textstyle i</math> 个节点的残差计算方法如下:<br />
: <math> <br />
\delta^{(l)}_i = \left( \sum_{j=1}^{s_{l+1}} W^{(l)}_{ji} \delta^{(l+1)}_j \right) f'(z^{(l)}_i)<br />
</math> <br />
<br />
<br />
<li>计算我们需要的偏导数,计算方法如下:<br />
:<math> <br />
\begin{align}<br />
\frac{\partial}{\partial W_{ij}^{(l)}} J(W,b; x, y) &= a^{(l)}_j \delta_i^{(l+1)} \\<br />
\frac{\partial}{\partial b_{i}^{(l)}} J(W,b; x, y) &= \delta_i^{(l+1)}.<br />
\end{align}<br />
</math> <br />
</ol><br />
<br />
<br />
最后,我们用矩阵-向量表示法重写以上算法。我们使用“<math>\textstyle \bullet</math>” 表示向量乘积运算符(在Matlab或Octave里用“<tt>.*</tt>”表示,也称作阿达马乘积)。若 <math>\textstyle a = b \bullet c</math>,则 <math>\textstyle a_i = b_ic_i</math>。在上一个教程中我们扩展了 <math>\textstyle f(\cdot)</math> 的定义,使其包含向量运算,这里我们也对偏导数 <math>\textstyle f'(\cdot)</math> 也做了同样的处理(于是又有 <math> \textstyle f'([z_1, z_2, z_3]) = [f'(z_1), f'(z_2), f'(z_3)]</math> )。<br />
<br />
<br />
那么,反向传播算法可表示为以下几个步骤:<br />
<br />
<ol><br />
<li>进行前馈传导计算,利用前向传导公式,得到 <math>\textstyle L_2, L_3, \ldots</math>直到输出层 <math>\textstyle L_{n_l}</math> 的激活值。<br />
<br />
<li>对输出层(第 <math>\textstyle n_l</math> 层),计算:<br />
<br />
:<math> \begin{align}<br />
\delta^{(n_l)}<br />
= - (y - a^{(n_l)}) \bullet f'(z^{(n_l)})<br />
\end{align}</math> <br />
<br />
<li>对于 <math>\textstyle l = n_l-1, n_l-2, n_l-3, \ldots, 2</math> 的各层,计算:<br />
:<math> \begin{align}<br />
\delta^{(l)} = \left((W^{(l)})^T \delta^{(l+1)}\right) \bullet f'(z^{(l)})<br />
\end{align}</math> <br />
<br />
<li>计算最终需要的偏导数值:<br />
:<math> \begin{align}<br />
\nabla_{W^{(l)}} J(W,b;x,y) &= \delta^{(l+1)} (a^{(l)})^T, \\<br />
\nabla_{b^{(l)}} J(W,b;x,y) &= \delta^{(l+1)}.<br />
\end{align}</math> <br />
</ol><br />
<br />
<br />
'''实现中应注意:'''在以上的第2步和第3步中,我们需要为每一个 <math>\textstyle i</math> 值计算其 <math>\textstyle f'(z^{(l)}_i)</math>。假设 <math>\textstyle f(z)</math> 是sigmoid函数,并且我们已经在前向传导运算中得到了 <math>\textstyle a^{(l)}_i</math>。那么,使用我们早先推导出的 <math>\textstyle f'(z)</math>表达式,就可以计算得到 <math>\textstyle f'(z^{(l)}_i) = a^{(l)}_i (1- a^{(l)}_i)</math>。<br />
<br />
<br />
最后,我们将对梯度下降算法做个全面总结。在下面的伪代码中,<math>\textstyle \Delta W^{(l)}</math> 是一个与矩阵 <math>\textstyle W^{(l)}</math> 维度相同的矩阵,<math>\textstyle \Delta b^{(l)}</math> 是一个与 <math>\textstyle b^{(l)}</math> 维度相同的向量。注意这里“<math>\textstyle \Delta W^{(l)}</math>”是一个矩阵,而不是“<math>\textstyle \Delta</math> 与 <math>\textstyle W^{(l)}</math> 相乘”。下面,我们实现批量梯度下降法中的一次迭代:<br />
<br />
<br />
<ol><br />
<li>对于所有 <math>\textstyle l</math>,令 <math>\textstyle \Delta W^{(l)} := 0</math> , <math>\textstyle \Delta b^{(l)} := 0</math> (设置为全零矩阵或全零向量)<br />
<br />
<li>对于 <math>\textstyle i = 1</math> 到 <math>\textstyle m</math>,<br />
<br />
<ol type="a"><br />
<li>使用反向传播算法计算 <math>\textstyle \nabla_{W^{(l)}} J(W,b;x,y)</math> 和 <math>\textstyle \nabla_{b^{(l)}} J(W,b;x,y)</math>。<br />
<li>计算 <math>\textstyle \Delta W^{(l)} := \Delta W^{(l)} + \nabla_{W^{(l)}} J(W,b;x,y)</math>。<br />
<li>计算 <math>\textstyle \Delta b^{(l)} := \Delta b^{(l)} + \nabla_{b^{(l)}} J(W,b;x,y)</math>。 <br />
</ol><br />
<br />
<li>更新权重参数:<br />
:<math> \begin{align}<br />
W^{(l)} &= W^{(l)} - \alpha \left[ \left(\frac{1}{m} \Delta W^{(l)} \right) + \lambda W^{(l)}\right] \\<br />
b^{(l)} &= b^{(l)} - \alpha \left[\frac{1}{m} \Delta b^{(l)}\right]<br />
\end{align}</math> <br />
</ol><br />
<br />
现在,我们可以重复梯度下降法的迭代步骤来减小代价函数 <math>\textstyle J(W,b)</math> 的值,进而求解我们的神经网络。<br />
<br />
<br />
==中英文对照==<br />
<br />
:反向传播算法 Backpropagation Algorithm<br />
:(批量)梯度下降法 (batch) gradient descent<br />
:(整体)代价函数 (overall) cost function<br />
:方差 squared-error<br />
:均方差 average sum-of-squares error<br />
:规则化项 regularization term<br />
:权重衰减 weight decay<br />
:偏置项 bias terms<br />
:贝叶斯规则化方法 Bayesian regularization method<br />
:高斯先验概率 Gaussian prior<br />
:极大后验估计 MAP<br />
:极大似然估计 maximum likelihood estimation<br />
:激活函数 activation function<br />
:双曲正切函数 tanh function<br />
:非凸函数 non-convex function<br />
:隐藏层单元 hidden (layer) units<br />
:对称失效 symmetry breaking<br />
:学习速率 learning rate<br />
:前向传导 forward pass<br />
:假设值 hypothesis <br />
:残差 error term<br />
:加权平均值 weighted average <br />
:前馈传导 feedforward pass<br />
:阿达马乘积 Hadamard product<br />
:前向传播 forward propagation<br />
<br />
<br />
==中文译者==<br />
<br />
王方(fangkey@gmail.com),林锋(xlfg@yeah.net),许利杰(csxulijie@gmail.com)<br />
<br />
<br />
{{稀疏自编码器}}<br />
<br />
<br />
<br />
{{Languages|Backpropagation_Algorithm|English}}</div>
Kandeng
http://ufldl.stanford.edu/wiki/index.php/%E5%8F%8D%E5%90%91%E4%BC%A0%E5%AF%BC%E7%AE%97%E6%B3%95
反向传导算法
2013-04-09T03:54:21Z
<p>Kandeng: </p>
<hr />
<div>假设我们有一个固定样本集 <math>\textstyle \{ (x^{(1)}, y^{(1)}), \ldots, (x^{(m)}, y^{(m)}) \}</math>,它包含 <math>\textstyle m</math> 个样例。我们可以用批量梯度下降法来求解神经网络。具体来讲,对于单个样例 <math>\textstyle (x,y)</math>,其代价函数为:<br />
<br />
:<math><br />
\begin{align}<br />
J(W,b; x,y) = \frac{1}{2} \left\| h_{W,b}(x) - y \right\|^2.<br />
\end{align}<br />
</math><br />
<br />
这是一个(二分之一的)方差代价函数。给定一个包含 <math>\textstyle m</math> 个样例的数据集,我们可以定义整体代价函数为:<br />
<br />
:<math> <br />
\begin{align}<br />
J(W,b)<br />
&= \left[ \frac{1}{m} \sum_{i=1}^m J(W,b;x^{(i)},y^{(i)}) \right]<br />
+ \frac{\lambda}{2} \sum_{l=1}^{n_l-1} \; \sum_{i=1}^{s_l} \; \sum_{j=1}^{s_{l+1}} \left( W^{(l)}_{ji} \right)^2<br />
\\<br />
&= \left[ \frac{1}{m} \sum_{i=1}^m \left( \frac{1}{2} \left\| h_{W,b}(x^{(i)}) - y^{(i)} \right\|^2 \right) \right]<br />
+ \frac{\lambda}{2} \sum_{l=1}^{n_l-1} \; \sum_{i=1}^{s_l} \; \sum_{j=1}^{s_{l+1}} \left( W^{(l)}_{ji} \right)^2<br />
\end{align}<br />
</math><br />
<br />
以上公式中的第一项 <math>\textstyle J(W,b)</math> 是一个均方差项。第二项是一个规则化项(也叫'''权重衰减项'''),其目的是减小权重的幅度,防止过度拟合。<br />
<br />
<br />
[注:通常权重衰减的计算并不使用偏置项 <math>\textstyle b^{(l)}_i</math>,比如我们在 <math>\textstyle J(W, b)</math> 的定义中就没有使用。一般来说,将偏置项包含在权重衰减项中只会对最终的神经网络产生很小的影响。如果你在斯坦福选修过CS229(机器学习)课程,或者在YouTube上看过课程视频,你会发现这个权重衰减实际上是课上提到的贝叶斯规则化方法的变种。在贝叶斯规则化方法中,我们将高斯先验概率引入到参数中计算MAP(极大后验)估计(而不是极大似然估计)。]<br />
<br />
<br />
'''权重衰减参数''' <math>\textstyle \lambda</math> 用于控制公式中两项的相对重要性。在此重申一下这两个复杂函数的含义:<math>\textstyle J(W,b;x,y)</math> 是针对单个样例计算得到的方差代价函数;<math>\textstyle J(W,b)</math> 是整体样本代价函数,它包含权重衰减项。<br />
<br />
<br />
以上的代价函数经常被用于分类和回归问题。在分类问题中,我们用 <math>\textstyle y = 0</math> 或 <math>\textstyle 1</math>,来代表两种类型的标签(回想一下,这是因为 sigmoid激活函数的值域为 <math>\textstyle [0,1]</math>;如果我们使用双曲正切型激活函数,那么应该选用 <math>\textstyle -1</math> 和 <math>\textstyle +1</math> 作为标签)。对于回归问题,我们首先要变换输出值域(译者注:也就是 <math>\textstyle y</math>),以保证其范围为 <math>\textstyle [0,1]</math> (同样地,如果我们使用双曲正切型激活函数,要使输出值域为 <math>\textstyle [-1,1]</math>)。<br />
<br />
<br />
我们的目标是针对参数 <math>\textstyle W</math> 和 <math>\textstyle b</math> 来求其函数 <math>\textstyle J(W,b)</math> 的最小值。为了求解神经网络,我们需要将每一个参数 <math>\textstyle W^{(l)}_{ij}</math> 和 <math>\textstyle b^{(l)}_i</math> 初始化为一个很小的、接近零的随机值(比如说,使用正态分布 <math>\textstyle {Normal}(0,\epsilon^2)</math> 生成的随机值,其中 <math>\textstyle \epsilon</math> 设置为 <math>\textstyle 0.01</math> ),之后对目标函数使用诸如批量梯度下降法的最优化算法。因为 <math>\textstyle J(W, b)</math> 是一个非凸函数,梯度下降法很可能会收敛到局部最优解;但是在实际应用中,梯度下降法通常能得到令人满意的结果。最后,需要再次强调的是,要将参数进行随机初始化,而不是全部置为 <math>\textstyle 0</math>。如果所有参数都用相同的值作为初始值,那么所有隐藏层单元最终会得到与输入值有关的、相同的函数(也就是说,对于所有 <math>\textstyle i</math>,<math>\textstyle W^{(1)}_{ij}</math>都会取相同的值,那么对于任何输入 <math>\textstyle x</math> 都会有:<math>\textstyle a^{(2)}_1 = a^{(2)}_2 = a^{(2)}_3 = \ldots</math> )。随机初始化的目的是使'''对称失效'''。<br />
<br />
<br />
梯度下降法中每一次迭代都按照如下公式对参数 <math>\textstyle W</math> 和<math>\textstyle b</math> 进行更新:<br />
<br />
:<math><br />
\begin{align}<br />
W_{ij}^{(l)} &= W_{ij}^{(l)} - \alpha \frac{\partial}{\partial W_{ij}^{(l)}} J(W,b) \\<br />
b_{i}^{(l)} &= b_{i}^{(l)} - \alpha \frac{\partial}{\partial b_{i}^{(l)}} J(W,b)<br />
\end{align}<br />
</math> <br />
<br />
其中 <math>\textstyle \alpha</math> 是学习速率。其中关键步骤是计算偏导数。我们现在来讲一下'''反向传播'''算法,它是计算偏导数的一种有效方法。<br />
<br />
<br />
我们首先来讲一下如何使用反向传播算法来计算 <math>\textstyle \frac{\partial}{\partial W_{ij}^{(l)}} J(W,b; x, y)</math> 和 <math>\textstyle \frac{\partial}{\partial b_{i}^{(l)}} J(W,b; x, y)</math>,这两项是单个样例 <math>\textstyle (x,y)</math> 的代价函数 <math>\textstyle J(W,b;x,y)</math> 的偏导数。一旦我们求出该偏导数,就可以推导出整体代价函数 <math>\textstyle J(W,b)</math> 的偏导数:<br />
<br />
<br />
:<math><br />
\begin{align}<br />
\frac{\partial}{\partial W_{ij}^{(l)}} J(W,b) &=<br />
\left[ \frac{1}{m} \sum_{i=1}^m \frac{\partial}{\partial W_{ij}^{(l)}} J(W,b; x^{(i)}, y^{(i)}) \right] + \lambda W_{ij}^{(l)} \\<br />
\frac{\partial}{\partial b_{i}^{(l)}} J(W,b) &=<br />
\frac{1}{m}\sum_{i=1}^m \frac{\partial}{\partial b_{i}^{(l)}} J(W,b; x^{(i)}, y^{(i)})<br />
\end{align}<br />
</math> <br />
<br />
以上两行公式稍有不同,第一行比第二行多出一项,是因为权重衰减是作用于 <math>\textstyle W</math> 而不是 <math>\textstyle b</math>。<br />
<br />
<br />
反向传播算法的思路如下:给定一个样例 <math>\textstyle (x,y)</math>,我们首先进行“前向传导”运算,计算出网络中所有的激活值,包括 <math>\textstyle h_{W,b}(x)</math> 的输出值。之后,针对第 <math>\textstyle l</math> 层的每一个节点 <math>\textstyle i</math>,我们计算出其“残差” <math>\textstyle \delta^{(l)}_i</math>,该残差表明了该节点对最终输出值的残差产生了多少影响。对于最终的输出节点,我们可以直接算出网络产生的激活值与实际值之间的差距,我们将这个差距定义为 <math>\textstyle \delta^{(n_l)}_i</math> (第 <math>\textstyle n_l</math> 层表示输出层)。对于隐藏单元我们如何处理呢?我们将基于节点(译者注:第 <math>\textstyle l+1</math> 层节点)残差的加权平均值计算 <math>\textstyle \delta^{(l)}_i</math>,这些节点以 <math>\textstyle a^{(l)}_i</math> 作为输入。下面将给出反向传导算法的细节:<br />
<br />
<br />
<ol><br />
<li>进行前馈传导计算,利用前向传导公式,得到 <math>\textstyle L_2, L_3, \ldots </math> 直到输出层 <math>\textstyle L_{n_l}</math> 的激活值。<br />
<li>对于第 <math>\textstyle n_l</math> 层(输出层)的每个输出单元 <math>\textstyle i</math>,我们根据以下公式计算残差:<br />
<br />
:<math> <br />
\delta^{(n_l)}_i = \frac{\partial}{\partial z^{n_l}_i}J(W,b;x,y)<br />
= \frac{\partial}{\partial z^{n_l}_i}\frac{1}{2} \left\|y - h_{W,b}(x)\right\|^2<br />
= - (y_i - a^{(n_l)}_i) \cdot f'(z^{(n_l)}_i)<br />
</math> <br />
<br />
<br />
<li>对 <math>\textstyle l = n_l-1, n_l-2, n_l-3, \ldots, 2</math> 的各个层,第 <math>\textstyle l</math> 层的第 <math>\textstyle i</math> 个节点的残差计算方法如下:<br />
: <math> <br />
\delta^{(l)}_i = \left( \sum_{j=1}^{s_{l+1}} W^{(l)}_{ji} \delta^{(l+1)}_j \right) f'(z^{(l)}_i)<br />
</math> <br />
<br />
<br />
<li>计算我们需要的偏导数,计算方法如下:<br />
:<math> <br />
\begin{align}<br />
\frac{\partial}{\partial W_{ij}^{(l)}} J(W,b; x, y) &= a^{(l)}_j \delta_i^{(l+1)} \\<br />
\frac{\partial}{\partial b_{i}^{(l)}} J(W,b; x, y) &= \delta_i^{(l+1)}.<br />
\end{align}<br />
</math> <br />
</ol><br />
<br />
<br />
最后,我们用矩阵-向量表示法重写以上算法。我们使用“<math>\textstyle \bullet</math>” 表示向量乘积运算符(在Matlab或Octave里用“<tt>.*</tt>”表示,也称作阿达马乘积)。若 <math>\textstyle a = b \bullet c</math>,则 <math>\textstyle a_i = b_ic_i</math>。在上一个教程中我们扩展了 <math>\textstyle f(\cdot)</math> 的定义,使其包含向量运算,这里我们也对偏导数 <math>\textstyle f'(\cdot)</math> 也做了同样的处理(于是又有 <math> \textstyle f'([z_1, z_2, z_3]) = [f'(z_1), f'(z_2), f'(z_3)]</math> )。<br />
<br />
<br />
那么,反向传播算法可表示为以下几个步骤:<br />
<br />
<ol><br />
<li>进行前馈传导计算,利用前向传导公式,得到 <math>\textstyle L_2, L_3, \ldots</math>直到输出层 <math>\textstyle L_{n_l}</math> 的激活值。<br />
<br />
<li>对输出层(第 <math>\textstyle n_l</math> 层),计算:<br />
<br />
:<math> \begin{align}<br />
\delta^{(n_l)}<br />
= - (y - a^{(n_l)}) \bullet f'(z^{(n_l)})<br />
\end{align}</math> <br />
<br />
<li>对于 <math>\textstyle l = n_l-1, n_l-2, n_l-3, \ldots, 2</math> 的各层,计算:<br />
:<math> \begin{align}<br />
\delta^{(l)} = \left((W^{(l)})^T \delta^{(l+1)}\right) \bullet f'(z^{(l)})<br />
\end{align}</math> <br />
<br />
<li>计算最终需要的偏导数值:<br />
:<math> \begin{align}<br />
\nabla_{W^{(l)}} J(W,b;x,y) &= \delta^{(l+1)} (a^{(l)})^T, \\<br />
\nabla_{b^{(l)}} J(W,b;x,y) &= \delta^{(l+1)}.<br />
\end{align}</math> <br />
</ol><br />
<br />
<br />
'''实现中应注意:'''在以上的第2步和第3步中,我们需要为每一个 <math>\textstyle i</math> 值计算其 <math>\textstyle f'(z^{(l)}_i)</math>。假设 <math>\textstyle f(z)</math> 是sigmoid函数,并且我们已经在前向传导运算中得到了 <math>\textstyle a^{(l)}_i</math>。那么,使用我们早先推导出的 <math>\textstyle f'(z)</math>表达式,就可以计算得到 <math>\textstyle f'(z^{(l)}_i) = a^{(l)}_i (1- a^{(l)}_i)</math>。<br />
<br />
<br />
最后,我们将对梯度下降算法做个全面总结。在下面的伪代码中,<math>\textstyle \Delta W^{(l)}</math> 是一个与矩阵 <math>\textstyle W^{(l)}</math> 维度相同的矩阵,<math>\textstyle \Delta b^{(l)}</math> 是一个与 <math>\textstyle b^{(l)}</math> 维度相同的向量。注意这里“<math>\textstyle \Delta W^{(l)}</math>”是一个矩阵,而不是“<math>\textstyle \Delta</math> 与 <math>\textstyle W^{(l)}</math> 相乘”。下面,我们实现批量梯度下降法中的一次迭代:<br />
<br />
<br />
<ol><br />
<li>对于所有 <math>\textstyle l</math>,令 <math>\textstyle \Delta W^{(l)} := 0</math> , <math>\textstyle \Delta b^{(l)} := 0</math> (设置为全零矩阵或全零向量)<br />
<br />
<li>对于 <math>\textstyle i = 1</math> 到 <math>\textstyle m</math>,<br />
<br />
<ol type="a"><br />
<li>使用反向传播算法计算 <math>\textstyle \nabla_{W^{(l)}} J(W,b;x,y)</math> 和 <math>\textstyle \nabla_{b^{(l)}} J(W,b;x,y)</math>。<br />
<li>计算 <math>\textstyle \Delta W^{(l)} := \Delta W^{(l)} + \nabla_{W^{(l)}} J(W,b;x,y)</math>。<br />
<li>计算 <math>\textstyle \Delta b^{(l)} := \Delta b^{(l)} + \nabla_{b^{(l)}} J(W,b;x,y)</math>。 <br />
</ol><br />
<br />
<li>更新权重参数:<br />
:<math> \begin{align}<br />
W^{(l)} &= W^{(l)} - \alpha \left[ \left(\frac{1}{m} \Delta W^{(l)} \right) + \lambda W^{(l)}\right] \\<br />
b^{(l)} &= b^{(l)} - \alpha \left[\frac{1}{m} \Delta b^{(l)}\right]<br />
\end{align}</math> <br />
</ol><br />
<br />
现在,我们可以重复梯度下降法的迭代步骤来减小代价函数 <math>\textstyle J(W,b)</math> 的值,进而求解我们的神经网络。<br />
<br />
<br />
==中英文对照==<br />
<br />
:反向传播算法 Backpropagation Algorithm<br />
:(批量)梯度下降法 (batch) gradient descent<br />
:(整体)代价函数 (overall) cost function<br />
:方差 squared-error<br />
:均方差 average sum-of-squares error<br />
:规则化项 regularization term<br />
:权重衰减 weight decay<br />
:偏置项 bias terms<br />
:贝叶斯规则化方法 Bayesian regularization method<br />
:高斯先验概率 Gaussian prior<br />
:极大后验估计 MAP<br />
:极大似然估计 maximum likelihood estimation<br />
:激活函数 activation function<br />
:双曲正切函数 tanh function<br />
:非凸函数 non-convex function<br />
:隐藏层单元 hidden (layer) units<br />
:对称失效 symmetry breaking<br />
:学习速率 learning rate<br />
:前向传导 forward pass<br />
:假设值 hypothesis <br />
:残差 error term<br />
:加权平均值 weighted average <br />
:前馈传导 feedforward pass<br />
:阿达马乘积 Hadamard product<br />
:前向传播 forward propagation<br />
<br />
<br />
==中文译者==<br />
<br />
王方(fangkey@gmail.com),林锋(xlfg@yeah.net),许利杰(csxulijie@gmail.com)<br />
<br />
<br />
{{稀疏自编码器}}<br />
<br />
<br />
<br />
{{Languages|Backpropagation_Algorithm|English}}</div>
Kandeng
http://ufldl.stanford.edu/wiki/index.php/%E7%94%A8%E5%8F%8D%E5%90%91%E4%BC%A0%E5%AF%BC%E6%80%9D%E6%83%B3%E6%B1%82%E5%AF%BC
用反向传导思想求导
2013-04-08T09:53:03Z
<p>Kandeng: </p>
<hr />
<div>== 简介 ==<br />
<br />
在[[ 反向传导算法 | 反向传导算法 ]]一节中,我们介绍了在稀疏自编码器中用反向传导算法来求梯度的方法。事实证明,反向传导算法与矩阵运算相结合的方法,对于计算复杂矩阵函数(从矩阵到实数的函数,或用符号表示为:从 <math>\mathbb{R}^{r \times c} \rightarrow \mathbb{R}</math> )的梯度是十分强大和直观的。<br />
<br />
<br />
首先,我们回顾一下反向传导的思想,为了更适合我们的目的,将其稍作修改呈现于下:<br />
<ol><br />
<li>对第 <math>n_l</math> 层(最后一层)中的每一个输出单元 <math>i</math> ,令<br />
:<math><br />
\delta^{(n_l)}_i<br />
= \frac{\partial}{\partial z^{(n_l)}_i} \;\;<br />
J(z^{(n_l)})<br />
</math><br />
其中 <math>J(z)</math> 是我们的“目标函数”(稍后解释)。<br />
<li>对 <math>l = n_l-1, n_l-2, n_l-3, \ldots, 2</math> , <br />
:对第 <math>l</math> 层中的每个节点 <math>i</math> , 令 <br />
::<math><br />
\delta^{(l)}_i = \left( \sum_{j=1}^{s_{l+1}} W^{(l)}_{ji} \delta^{(l+1)}_j \right) \bullet \frac{\partial}{\partial z^{(l)}_i} f^{(l)} (z^{(l)}_i)<br />
</math> <br />
<li>计算我们要的偏导数<br />
:<math><br />
\begin{align}<br />
\nabla_{W^{(l)}} J(W,b;x,y) &= \delta^{(l+1)} (a^{(l)})^T, \\<br />
\end{align}<br />
</math><br />
</ol><br />
<br />
<br />
符号扼要重述:<br />
<ul><br />
<li><math>l</math> 是神经网络的层数<br />
<li><math>n_l</math> 第l层神经元的个数<br />
<li><math>W^{(l)}_{ji}</math> 是 <math>l</math> 层第 <math>i</math> 个节点到第 <math>(l+1)</math> 层第 <math>j</math> 个节点的权重<br />
<li><math>z^{(l)}_i</math> 是第 <math>l</math> 层第 <math>i</math> 个单元的输入<br />
<li><math>a^{(l)}_i</math> 是第 <math>l</math> 层第 <math>i</math> 个节点的激励<br />
<li><math>A \bullet B</math> 是矩阵的Hadamard积或逐个元素乘积,对 <math>r \times c</math> 矩阵 <math>A</math> 和 <math>B</math> ,它们的乘积是 <math>r \times c</math> 矩阵 <math>C = A \bullet B</math> ,即 <math>C_{r, c} = A_{r, c} \cdot B_{r, c}</math> <br />
<li><math>f^{(l)}</math> 是第 <math>l</math> 层中各单元的激励函数<br />
</ul><br />
<br />
假设我们有一个函数 <math>F</math> , <math>F</math> 以矩阵 <math>X</math> 为参数生成一个实数。我们希望用反向传导思想计算 <math>F</math> 关于 <math>X</math> 的梯度,即 <math>\nabla_X F</math> 。大致思路是将函数 <math>F</math> 看成一个多层神经网络,并使用反向传导思想求梯度。<br />
<br />
为了实现这个想法,我们取目标函数为 <math>J(z)</math> ,当计算最后一层神经元的输出时,会产生值 <math>F(X)</math> 。对于中间层,我们将选择激励函数 <math>f^{(l)}</math> 。<br />
<br />
稍后我们会看到,使用这种方法,我们可以很容易计算出对于输入 <math>X</math> 以及网络中任意一个权重的导数。<br />
<br />
<br />
== 示例 ==<br />
<br />
为了阐述如何使用反向传导思想计算关于输入的导数,我们要在示例1,示例2中用 [[ 稀疏编码自编码表达 | 稀疏编码 ]] 章节中的两个函数。在示例3中,我们使用[[ 独立成分分析 | 独立成分分析 ]]一节中的一个函数来说明使用此思想计算关于权重的偏导的方法,以及在这种特殊情况下,如何处理相互捆绑或重复的权重。<br />
<br />
<br />
=== 示例1:稀疏编码中权重矩阵的目标函数 ===<br />
<br />
回顾一下[[ 稀疏编码自编码表达 | 稀疏编码 ]],当给定特征矩阵 <math>s</math> 时,权重矩阵 <math>A</math> 的目标函数为:<br />
<br />
:<math>F(A; s) = \lVert As - x \rVert_2^2 + \gamma \lVert A \rVert_2^2</math><br />
<br />
<br />
我们希望求 <math>F</math> 对于 <math>A</math> 的梯度,即 <math>\nabla_A F(A)</math> 。因为目标函数是两个含 <math>A</math> 的式子之和,所以它的梯度是每个式子的梯度之和。第二项的梯度很容易求,因此我们只考虑第一项的梯度。<br />
<br />
<br />
第一项, <math>\lVert As - x \rVert_2^2</math> ,可以看成一个用 <math>s</math> 做输入的神经网络的实例,通过四步进行计算,文字以及图形描述如下:<br />
<ol><br />
<li>把 <math>A</math> 作为第一层到第二层的权重。<br />
<li>将第二层的激励减 <math>x</math> ,第二层使用了单位激励函数。<br />
<li>通过单位权重将结果不变地传到第三层。在第三层使用平方函数作为激励函数。<br />
<li>将第三层的所有激励相加。<br />
</ol><br />
<br />
[[File:Backpropagation Method Example 1.png | 400px]]<br />
<br />
<br />
该网络的权重和激励函数如下表所示:<br />
<br />
<table align="center"><br />
<tr><th width="50px">层</th><th width="200px">权重</th><th width="200px">激励函数 <math>f</math></th></tr><br />
<tr><br />
<td>1</td><br />
<td><math>A</math></td><br />
<td><math>f(z_i) = z_i</math> (单位函数)</td><br />
</tr><br />
<tr><br />
<td>2</td><br />
<td><math>I</math> (单位向量)</td><br />
<td><math>f(z_i) = z_i - x_i</math></td><br />
</tr><br />
<tr><br />
<td>3</td><br />
<td>N/A</td><br />
<td><math>f(z_i) = z_i^2</math></td><br />
</tr><br />
</table><br />
<br />
为了使 <math>J(z^{(3)}) = F(x)</math> ,我们可令 <math>J(z^{(3)}) = \sum_k J(z^{(3)}_k)</math> 。<br />
<br />
一旦我们将 <math>F</math> 看成神经网络,梯度 <math>\nabla_X F</math> 就很容易求了——使用反向传导得到:<br />
<br />
<table align="center"><br />
<tr><th width="50px">层</th><th width="200px">激励函数的导数<math>f'</math></th><th width="200px">Delta</th><th>该层输入<math>z</math></th></tr><br />
<tr><br />
<td>3</td><br />
<td><math>f'(z_i) = 2z_i</math></td><br />
<td><math>f'(z_i) = 2z_i</math></td><br />
<td><math>As - x</math></td><br />
</tr><br />
<tr><br />
<td>2</td><br />
<td><math>f'(z_i) = 1</math></td><br />
<td><math>\left( I^T \delta^{(3)} \right) \bullet 1</math></td><br />
<td><math>As</math></td><br />
</tr><br />
<tr><br />
<td>1</td><br />
<td><math>f'(z_i) = 1</math></td><br />
<td><math>\left( A^T \delta^{(2)} \right) \bullet 1</math></td><br />
<td><math>s</math></td><br />
</tr><br />
</table><br />
<br />
<br />
因此<br />
<br />
:<math><br />
\begin{align}<br />
\nabla_X F & = A^T I^T 2(As - x) \\<br />
& = A^T 2(As - x)<br />
\end{align}<br />
</math><br />
<br />
<br />
=== 示例2:稀疏编码中的平滑地形L1稀疏罚函数 ===<br />
<br />
回顾[[ 稀疏编码自编码表达 | 稀疏编码 ]]一节中对 <math>s</math> 的平滑地形L1稀疏罚函数:<br />
<br />
:<math>\sum{ \sqrt{Vss^T + \epsilon} }</math><br />
<br />
其中 <math>V</math> 是分组矩阵, <math>s</math> 是特征矩阵, <math>\epsilon</math> 是一个常数。<br />
<br />
我们希望求得 <math>\nabla_s \sum{ \sqrt{Vss^T + \epsilon} }</math> 。像上面那样,我们把这一项看做一个神经网络的实例:<br />
<br />
[[File:Backpropagation Method Example 2.png | 600px]]<br />
<br />
<br />
该网络的权重和激励函数如下表所示:<br />
<br />
<table align="center"><br />
<tr><th width="50px">层</th><th width="200px">权重</th><th width="200px">激励函数 <math>f</math></th></tr><br />
<tr><br />
<td>1</td><br />
<td><math>I</math></td><br />
<td><math>f(z_i) = z_i^2</math></td><br />
</tr><br />
<tr><br />
<td>2</td><br />
<td><math>V</math></td><br />
<td><math>f(z_i) = z_i</math></td><br />
</tr><br />
<tr><br />
<td>3</td><br />
<td><math>I</math></td><br />
<td><math>f(z_i) = z_i + \epsilon</math></td><br />
</tr><br />
<tr><br />
<td>4</td><br />
<td>N/A</td><br />
<td><math>f(z_i) = z_i^{\frac{1}{2}}</math></td><br />
</tr><br />
</table><br />
<br />
<br />
为使 <math>J(z^{(4)}) = F(x)</math> ,我们可令 <math>J(z^{(4)}) = \sum_k J(z^{(4)}_k)</math> 。<br />
<br />
一旦我们把 <math>F</math> 看做一个神经网络,梯度 <math>\nabla_X F</math> 变得很容易计算——使用反向传导得到:<br />
<br />
<table align="center"><br />
<tr><th width="50px">层</th><th width="200px">激励函数的导数 <math>f'</math><br />
</th><th width="200px">Delta</th><th>该层输入<math>z</math></th></tr><br />
<tr><br />
<td>4</td><br />
<td><math>f'(z_i) = \frac{1}{2} z_i^{-\frac{1}{2}}</math></td><br />
<td><math>f'(z_i) = \frac{1}{2} z_i^{-\frac{1}{2}}</math></td><br />
<td><math>(Vss^T + \epsilon)</math></td><br />
</tr><br />
<tr><br />
<td>3</td><br />
<td><math>f'(z_i) = 1</math></td><br />
<td><math>\left( I^T \delta^{(4)} \right) \bullet 1</math></td><br />
<td><math>Vss^T</math></td><br />
</tr><br />
<tr><br />
<td>2</td><br />
<td><math>f'(z_i) = 1</math></td><br />
<td><math>\left( V^T \delta^{(3)} \right) \bullet 1</math></td><br />
<td><math>ss^T</math></td><br />
</tr><br />
<tr><br />
<td>1</td><br />
<td><math>f'(z_i) = 2z_i</math></td><br />
<td><math>\left( I^T \delta^{(2)} \right) \bullet 2s</math></td><br />
<td><math>s</math></td><br />
</tr><br />
</table><br />
<br />
<br />
因此<br />
<br />
:<math><br />
\begin{align}<br />
\nabla_X F & = I^T V^T I^T \frac{1}{2}(Vss^T + \epsilon)^{-\frac{1}{2}} \bullet 2s \\<br />
& = V^T \frac{1}{2}(Vss^T + \epsilon)^{-\frac{1}{2}} \bullet 2s \\<br />
& = V^T (Vss^T + \epsilon)^{-\frac{1}{2}} \bullet s<br />
\end{align}<br />
</math><br />
<br />
<br />
=== 示例3:ICA重建代价 ===<br />
<br />
回顾 [[ 独立成分分析 | 独立成分分析(ICA) ]]一节重建代价一项: <math>\lVert W^TWx - x \rVert_2^2</math> ,其中 <math>W</math> 是权重矩阵, <math>x</math> 是输入。<br />
<br />
我们希望计算 <math>\nabla_W \lVert W^TWx - x \rVert_2^2</math> ——对于'''权重矩阵'''的导数,而不是像前两例中对于'''输入'''的导数。不过我们仍然用类似的方法处理,把该项看做一个神经网络的实例:<br />
<br />
[[File:Backpropagation Method Example 3.png | 400px]]<br />
<br />
<br />
该网络的权重和激励函数如下表所示:<br />
<br />
<table align="center"><br />
<tr><th width="50px">层</th><th width="200px">权重</th><th width="200px">激励函数 <math>f</math></th></tr><br />
<tr><br />
<td>1</td><br />
<td><math>W</math></td><br />
<td><math>f(z_i) = z_i</math></td><br />
</tr><br />
<tr><br />
<td>2</td><br />
<td><math>W^T</math></td><br />
<td><math>f(z_i) = z_i</math></td><br />
</tr><br />
<tr><br />
<td>3</td><br />
<td><math>I</math></td><br />
<td><math>f(z_i) = z_i - x_i</math></td><br />
</tr><br />
<tr><br />
<td>4</td><br />
<td>N/A</td><br />
<td><math>f(z_i) = z_i^2</math></td><br />
</tr><br />
</table><br />
<br />
为使 <math>J(z^{(4)}) = F(x)</math> ,我们可令 <math>J(z^{(4)}) = \sum_k J(z^{(4)}_k)</math> 。<br />
<br />
既然我们可将 <math>F</math> 看做神经网络,我们就能计算出梯度 <math>\nabla_W F</math> 。然而,我们现在面临的难题是 <math>W</math> 在网络中出现了两次。幸运的是,可以证明如果 <math>W</math> 在网络中出现多次,那么对于 <math>W</math> 的梯度是对网络中每个 <math>W</math> 实例的梯度的简单相加(你需要自己给出对这一事实的严格证明来说服自己)。知道这一点后,我们将首先计算delta:<br />
<br />
<table align="center"><br />
<tr><th width="50px">层</th><th width="200px">激励函数的导数 <math>f'</math><br />
</th><th width="200px">Delta</th><th>该层输入<math>z</math></th></tr><br />
<tr><br />
<td>4</td><br />
<td><math>f'(z_i) = 2z_i</math></td><br />
<td><math>f'(z_i) = 2z_i</math></td><br />
<td><math>(W^TWx - x)</math></td><br />
</tr><br />
<tr><br />
<td>3</td><br />
<td><math>f'(z_i) = 1</math></td><br />
<td><math>\left( I^T \delta^{(4)} \right) \bullet 1</math></td><br />
<td><math>W^TWx</math></td><br />
</tr><br />
<tr><br />
<td>2</td><br />
<td><math>f'(z_i) = 1</math></td><br />
<td><math>\left( (W^T)^T \delta^{(3)} \right) \bullet 1</math></td><br />
<td><math>Wx</math></td><br />
</tr><br />
<tr><br />
<td>1</td><br />
<td><math>f'(z_i) = 1</math></td><br />
<td><math>\left( W^T \delta^{(2)} \right) \bullet 1</math></td><br />
<td><math>x</math></td><br />
</tr><br />
</table><br />
<br />
为计算对于 <math>W</math> 的梯度,首先计算对网络中每个 <math>W</math> 实例的梯度。<br />
<br />
对于 <math>W^T</math> :<br />
<br />
:<math><br />
\begin{align}<br />
\nabla_{W^T} F & = \delta^{(3)} a^{(2)T} \\<br />
& = 2(W^TWx - x) (Wx)^T<br />
\end{align}<br />
</math><br />
<br />
对于 <math>W</math> :<br />
<br />
:<math><br />
\begin{align}<br />
\nabla_{W} F & = \delta^{(2)} a^{(1)T} \\<br />
& = (W^T)(2(W^TWx -x)) x^T<br />
\end{align}<br />
</math><br />
<br />
最后进行求和,得到对于 <math>W</math> 的最终梯度,注意我们需要对 <math>W^T</math> 梯度进行转置,来得到关于 <math>W</math> 的梯度(原谅我在这里稍稍滥用了符号):<br />
<br />
:<math><br />
\begin{align}<br />
\nabla_{W} F & = \nabla_{W} F + (\nabla_{W^T} F)^T \\<br />
& = (W^T)(2(W^TWx -x)) x^T + 2(Wx)(W^TWx - x)^T<br />
\end{align}<br />
</math><br />
<br />
<br />
<br />
==中英文对照==<br />
<br />
:反向传导 backpropagation<br />
:稀疏编码 sparse coding <br />
:权重矩阵 weight matrix<br />
:目标函数 objective<br />
:平滑地形L1稀疏罚函数 Smoothed topographic L1 sparsity penalty<br />
:重建代价 reconstruction cost<br />
:稀疏自编码器 sparse autoencoder<br />
:梯度 gradient<br />
:神经网络 neural network<br />
:神经元 neuron<br />
:激励 activation<br />
:激励函数 activation function<br />
:独立成分分析 independent component analysis<br />
:单位激励函数 identity activation function<br />
:平方函数 square function<br />
:分组矩阵 grouping matrix<br />
:特征矩阵 feature matrix<br />
<br />
<br />
<br />
==中文译者==<br />
<br />
葛燕儒(yrgehi@gmail.com), 顾祺龙(ggnle@hotmail.com), 李良玥(jackiey99@gmail.com), 王方(fangkey@gmail.com)<br />
<br />
<br />
<br />
{{Languages|Deriving_gradients_using_the_backpropagation_idea|English}}</div>
Kandeng
http://ufldl.stanford.edu/wiki/index.php/%E7%94%A8%E5%8F%8D%E5%90%91%E4%BC%A0%E5%AF%BC%E6%80%9D%E6%83%B3%E6%B1%82%E5%AF%BC
用反向传导思想求导
2013-04-08T09:04:40Z
<p>Kandeng: /* 中英文对照 */</p>
<hr />
<div>== 简介 ==<br />
<br />
在[[ 反向传导算法 | 反向传导算法 ]]一节中,我们介绍了在稀疏自编码器中用反向传导算法来求梯度的方法。事实证明,反向传导算法与矩阵运算相结合的方法,对于计算复杂矩阵函数(从矩阵到实数的函数,或用符号表示为:从 <math>\mathbb{R}^{r \times c} \rightarrow \mathbb{R}</math> )的梯度是十分强大和直观的。<br />
<br />
<br />
首先,我们回顾一下反向传导的思想,为了更适合我们的目的,将其稍作修改呈现于下:<br />
<ol><br />
<li>对第 <math>n_l</math> 层(最后一层)中的每一个输出单元 <math>i</math> ,令<br />
:<math><br />
\delta^{(n_l)}_i<br />
= \frac{\partial}{\partial z^{(n_l)}_i} \;\;<br />
J(z^{(n_l)})<br />
</math><br />
其中 <math>J(z)</math> 是我们的“目标函数”(稍后解释)。<br />
<li>对 <math>l = n_l-1, n_l-2, n_l-3, \ldots, 2</math> , <br />
:对第 <math>l</math> 层中的每个节点 <math>i</math> , 令 <br />
::<math><br />
\delta^{(l)}_i = \left( \sum_{j=1}^{s_{l+1}} W^{(l)}_{ji} \delta^{(l+1)}_j \right) \bullet \frac{\partial}{\partial z^{(l)}_i} f^{(l)} (z^{(l)}_i)<br />
</math> <br />
<li>计算我们要的偏导数<br />
:<math><br />
\begin{align}<br />
\nabla_{W^{(l)}} J(W,b;x,y) &= \delta^{(l+1)} (a^{(l)})^T, \\<br />
\end{align}<br />
</math><br />
</ol><br />
<br />
<br />
符号扼要重述:<br />
<ul><br />
<li><math>l</math> 是神经网络的层数<br />
<li><math>n_l</math> 第l层神经元的个数<br />
<li><math>W^{(l)}_{ji}</math> 是 <math>l</math> 层第 <math>i</math> 个节点到第 <math>(l+1)</math> 层第 <math>j</math> 个节点的权重<br />
<li><math>z^{(l)}_i</math> 是第 <math>l</math> 层第 <math>i</math> 个单元的输入<br />
<li><math>a^{(l)}_i</math> 是第 <math>l</math> 层第 <math>i</math> 个节点的激励<br />
<li><math>A \bullet B</math> 是矩阵的Hadamard积或逐个元素乘积,对 <math>r \times c</math> 矩阵 <math>A</math> 和 <math>B</math> ,它们的乘积是 <math>r \times c</math> 矩阵 <math>C = A \bullet B</math> ,即 <math>C_{r, c} = A_{r, c} \cdot B_{r, c}</math> <br />
<li><math>f^{(l)}</math> 是第 <math>l</math> 层中各单元的激励函数<br />
</ul><br />
<br />
假设我们有一个函数 <math>F</math> , <math>F</math> 以矩阵 <math>X</math> 为参数生成一个实数。我们希望用反向传导思想计算 <math>F</math> 关于 <math>X</math> 的梯度,即 <math>\nabla_X F</math> 。大致思路是将函数 <math>F</math> 看成一个多层神经网络,并使用反向传导思想求梯度。<br />
<br />
为了实现这个想法,我们取目标函数为 <math>J(z)</math> ,当计算最后一层神经元的输出时,会产生值 <math>F(X)</math> 。对于中间层,我们将选择激励函数 <math>f^{(l)}</math> 。<br />
<br />
稍后我们会看到,使用这种方法,我们可以很容易计算出对于输入 <math>X</math> 以及网络中任意一个权重的导数。<br />
<br />
<br />
== 示例 ==<br />
<br />
为了阐述如何使用反向传导思想计算关于输入的导数,我们要在示例1,示例2中用 [[ 稀疏编码自编码表达 | 稀疏编码 ]] 章节中的两个函数。在示例3中,我们使用[[ 独立成分分析 | 独立成分分析 ]]一节中的一个函数来说明使用此思想计算关于权重的偏导的方法,以及在这种特殊情况下,如何处理相互捆绑或重复的权重。<br />
<br />
<br />
=== 示例1:稀疏编码中权重矩阵的目标函数 ===<br />
<br />
回顾一下[[ 稀疏编码自编码表达 | 稀疏编码 ]],当给定特征矩阵 <math>s</math> 时,权重矩阵 <math>A</math> 的目标函数为:<br />
<br />
:<math>F(A; s) = \lVert As - x \rVert_2^2 + \gamma \lVert A \rVert_2^2</math><br />
<br />
<br />
我们希望求 <math>F</math> 对于 <math>A</math> 的梯度,即 <math>\nabla_A F(A)</math> 。因为目标函数是两个含 <math>A</math> 的式子之和,所以它的梯度是每个式子的梯度之和。第二项的梯度很容易求,因此我们只考虑第一项的梯度。<br />
<br />
<br />
第一项, <math>\lVert As - x \rVert_2^2</math> ,可以看成一个用 <math>s</math> 做输入的神经网络的实例,通过四步进行计算,文字以及图形描述如下:<br />
<ol><br />
<li>把 <math>A</math> 作为第一层到第二层的权重。<br />
<li>将第二层的激励减 <math>x</math> ,第二层使用了单位激励函数。<br />
<li>通过单位权重将结果不变地传到第三层。在第三层使用平方函数作为激励函数。<br />
<li>将第三层的所有激励相加。<br />
</ol><br />
<br />
[[File:Backpropagation Method Example 1.png | 400px]]<br />
<br />
<br />
该网络的权重和激励函数如下表所示:<br />
<br />
<table align="center"><br />
<tr><th width="50px">层</th><th width="200px">权重</th><th width="200px">激励函数 <math>f</math></th></tr><br />
<tr><br />
<td>1</td><br />
<td><math>A</math></td><br />
<td><math>f(z_i) = z_i</math> (单位函数)</td><br />
</tr><br />
<tr><br />
<td>2</td><br />
<td><math>I</math> (单位向量)</td><br />
<td><math>f(z_i) = z_i - x_i</math></td><br />
</tr><br />
<tr><br />
<td>3</td><br />
<td>N/A</td><br />
<td><math>f(z_i) = z_i^2</math></td><br />
</tr><br />
</table><br />
<br />
为了使 <math>J(z^{(3)}) = F(x)</math> ,我们可令 <math>J(z^{(3)}) = \sum_k J(z^{(3)}_k)</math> 。<br />
<br />
一旦我们将 <math>F</math> 看成神经网络,梯度 <math>\nabla_X F</math> 就很容易求了——使用反向传导得到:<br />
<br />
<table align="center"><br />
<tr><th width="50px">层</th><th width="200px">激励函数的导数<math>f'</math></th><th width="200px">Delta</th><th>该层输入<math>z</math></th></tr><br />
<tr><br />
<td>3</td><br />
<td><math>f'(z_i) = 2z_i</math></td><br />
<td><math>f'(z_i) = 2z_i</math></td><br />
<td><math>As - x</math></td><br />
</tr><br />
<tr><br />
<td>2</td><br />
<td><math>f'(z_i) = 1</math></td><br />
<td><math>\left( I^T \delta^{(3)} \right) \bullet 1</math></td><br />
<td><math>As</math></td><br />
</tr><br />
<tr><br />
<td>1</td><br />
<td><math>f'(z_i) = 1</math></td><br />
<td><math>\left( A^T \delta^{(2)} \right) \bullet 1</math></td><br />
<td><math>s</math></td><br />
</tr><br />
</table><br />
<br />
<br />
因此<br />
<br />
:<math><br />
\begin{align}<br />
\nabla_X F & = A^T I^T 2(As - x) \\<br />
& = A^T 2(As - x)<br />
\end{align}<br />
</math><br />
<br />
<br />
=== 示例2:稀疏编码中的平滑地形L1稀疏罚函数 ===<br />
<br />
回顾[[ 稀疏编码自编码表达 | 稀疏编码 ]]一节中对 <math>s</math> 的平滑地形L1稀疏罚函数:<br />
<br />
:<math>\sum{ \sqrt{Vss^T + \epsilon} }</math><br />
<br />
其中 <math>V</math> 是分组矩阵, <math>s</math> 是特征矩阵, <math>\epsilon</math> 是一个常数。<br />
<br />
我们希望求得 <math>\nabla_s \sum{ \sqrt{Vss^T + \epsilon} }</math> 。像上面那样,我们把这一项看做一个神经网络的实例:<br />
<br />
[[File:Backpropagation Method Example 2.png | 600px]]<br />
<br />
<br />
该网络的权重和激励函数如下表所示:<br />
<br />
<table align="center"><br />
<tr><th width="50px">层</th><th width="200px">权重</th><th width="200px">激励函数 <math>f</math></th></tr><br />
<tr><br />
<td>1</td><br />
<td><math>I</math></td><br />
<td><math>f(z_i) = z_i^2</math></td><br />
</tr><br />
<tr><br />
<td>2</td><br />
<td><math>V</math></td><br />
<td><math>f(z_i) = z_i</math></td><br />
</tr><br />
<tr><br />
<td>3</td><br />
<td><math>I</math></td><br />
<td><math>f(z_i) = z_i + \epsilon</math></td><br />
</tr><br />
<tr><br />
<td>4</td><br />
<td>N/A</td><br />
<td><math>f(z_i) = z_i^{\frac{1}{2}}</math></td><br />
</tr><br />
</table><br />
<br />
<br />
为使 <math>J(z^{(4)}) = F(x)</math> ,我们可令 <math>J(z^{(4)}) = \sum_k J(z^{(4)}_k)</math> 。<br />
<br />
一旦我们把 <math>F</math> 看做一个神经网络,梯度 <math>\nabla_X F</math> 变得很容易计算——使用反向传导得到:<br />
<br />
<table align="center"><br />
<tr><th width="50px">层</th><th width="200px">激励函数的导数 <math>f'</math><br />
</th><th width="200px">Delta</th><th>该层输入<math>z</math></th></tr><br />
<tr><br />
<td>4</td><br />
<td><math>f'(z_i) = \frac{1}{2} z_i^{-\frac{1}{2}}</math></td><br />
<td><math>f'(z_i) = \frac{1}{2} z_i^{-\frac{1}{2}}</math></td><br />
<td><math>(Vss^T + \epsilon)</math></td><br />
</tr><br />
<tr><br />
<td>3</td><br />
<td><math>f'(z_i) = 1</math></td><br />
<td><math>\left( I^T \delta^{(4)} \right) \bullet 1</math></td><br />
<td><math>Vss^T</math></td><br />
</tr><br />
<tr><br />
<td>2</td><br />
<td><math>f'(z_i) = 1</math></td><br />
<td><math>\left( V^T \delta^{(3)} \right) \bullet 1</math></td><br />
<td><math>ss^T</math></td><br />
</tr><br />
<tr><br />
<td>1</td><br />
<td><math>f'(z_i) = 2z_i</math></td><br />
<td><math>\left( I^T \delta^{(2)} \right) \bullet 2s</math></td><br />
<td><math>s</math></td><br />
</tr><br />
</table><br />
<br />
<br />
因此<br />
<br />
:<math><br />
\begin{align}<br />
\nabla_X F & = I^T V^T I^T \frac{1}{2}(Vss^T + \epsilon)^{-\frac{1}{2}} \bullet 2s \\<br />
& = V^T \frac{1}{2}(Vss^T + \epsilon)^{-\frac{1}{2}} \bullet 2s \\<br />
& = V^T (Vss^T + \epsilon)^{-\frac{1}{2}} \bullet s<br />
\end{align}<br />
</math><br />
<br />
<br />
=== 示例3:ICA重建代价 ===<br />
<br />
回顾 [[ 独立成分分析 | 独立成分分析(ICA) ]]一节重建代价一项: <math>\lVert W^TWx - x \rVert_2^2</math> ,其中 <math>W</math> 是权重矩阵, <math>x</math> 是输入。<br />
<br />
我们希望计算 <math>\nabla_W \lVert W^TWx - x \rVert_2^2</math> ——对于'''权重矩阵'''的导数,而不是像前两例中对于'''输入'''的导数。不过我们仍然用类似的方法处理,把该项看做一个神经网络的实例:<br />
<br />
[[File:Backpropagation Method Example 3.png | 400px]]<br />
<br />
<br />
该网络的权重和激励函数如下表所示:<br />
<br />
<table align="center"><br />
<tr><th width="50px">层</th><th width="200px">权重</th><th width="200px">激励函数 <math>f</math></th></tr><br />
<tr><br />
<td>1</td><br />
<td><math>W</math></td><br />
<td><math>f(z_i) = z_i</math></td><br />
</tr><br />
<tr><br />
<td>2</td><br />
<td><math>W^T</math></td><br />
<td><math>f(z_i) = z_i</math></td><br />
</tr><br />
<tr><br />
<td>3</td><br />
<td><math>I</math></td><br />
<td><math>f(z_i) = z_i - x_i</math></td><br />
</tr><br />
<tr><br />
<td>4</td><br />
<td>N/A</td><br />
<td><math>f(z_i) = z_i^2</math></td><br />
</tr><br />
</table><br />
<br />
为使 <math>J(z^{(4)}) = F(x)</math> ,我们可令 <math>J(z^{(4)}) = \sum_k J(z^{(4)}_k)</math> 。<br />
<br />
既然我们可将 <math>F</math> 看做神经网络,我们就能计算出梯度 <math>\nabla_W F</math> 。然而,我们现在面临的难题是 <math>W</math> 在网络中出现了两次。幸运的是,可以证明如果 <math>W</math> 在网络中出现多次,那么对于 <math>W</math> 的梯度是对网络中每个 <math>W</math> 实例的梯度的简单相加(你需要自己给出对这一事实的严格证明来说服自己)。知道这一点后,我们将首先计算delta:<br />
<br />
<table align="center"><br />
<tr><th width="50px">层</th><th width="200px">激励函数的导数 <math>f'</math><br />
</th><th width="200px">Delta</th><th>该层输入<math>z</math></th></tr><br />
<tr><br />
<td>4</td><br />
<td><math>f'(z_i) = 2z_i</math></td><br />
<td><math>f'(z_i) = 2z_i</math></td><br />
<td><math>(W^TWx - x)</math></td><br />
</tr><br />
<tr><br />
<td>3</td><br />
<td><math>f'(z_i) = 1</math></td><br />
<td><math>\left( I^T \delta^{(4)} \right) \bullet 1</math></td><br />
<td><math>W^TWx</math></td><br />
</tr><br />
<tr><br />
<td>2</td><br />
<td><math>f'(z_i) = 1</math></td><br />
<td><math>\left( (W^T)^T \delta^{(3)} \right) \bullet 1</math></td><br />
<td><math>Wx</math></td><br />
</tr><br />
<tr><br />
<td>1</td><br />
<td><math>f'(z_i) = 1</math></td><br />
<td><math>\left( W^T \delta^{(2)} \right) \bullet 1</math></td><br />
<td><math>x</math></td><br />
</tr><br />
</table><br />
<br />
为计算对于 <math>W</math> 的梯度,首先计算对网络中每个 <math>W</math> 实例的梯度。<br />
<br />
对于 <math>W^T</math> :<br />
<br />
:<math><br />
\begin{align}<br />
\nabla_{W^T} F & = \delta^{(3)} a^{(2)T} \\<br />
& = 2(W^TWx - x) (Wx)^T<br />
\end{align}<br />
</math><br />
<br />
对于 <math>W</math> :<br />
<br />
:<math><br />
\begin{align}<br />
\nabla_{W} F & = \delta^{(2)} a^{(1)T} \\<br />
& = (W^T)(2(W^TWx -x)) x^T<br />
\end{align}<br />
</math><br />
<br />
最后进行求和,得到对于 <math>W</math> 的最终梯度,注意我们需要对 <math>W^T</math> 梯度进行转置,来得到关于 <math>W</math> 的梯度(原谅我在这里稍稍滥用了符号):<br />
<br />
:<math><br />
\begin{align}<br />
\nabla_{W} F & = \nabla_{W} F + (\nabla_{W^T} F)^T \\<br />
& = (W^T)(2(W^TWx -x)) x^T + 2(Wx)(W^TWx - x)^T<br />
\end{align}<br />
</math><br />
<br />
<br />
<br />
==中英文对照==<br />
<br />
:反向传导 backpropagation<br />
:稀疏编码 sparse coding <br />
:权重矩阵 weight matrix<br />
:目标函数 objective<br />
:平滑地形L1稀疏罚函数 Smoothed topographic L1 sparsity penalty<br />
:重建代价 reconstruction cost<br />
:稀疏自编码器 sparse autoencoder<br />
:梯度 gradient<br />
:神经网络 neural network<br />
:神经元 neuron<br />
:激励 activation<br />
:激励函数 activation function<br />
:独立成分分析 independent component analysis<br />
:单位激励函数 identity activation function<br />
:平方函数 square function<br />
:分组矩阵 grouping matrix<br />
:特征矩阵 feature matrix<br />
<br />
==中文译者==<br />
<br />
葛燕儒(yrgehi@gmail.com), 顾祺龙(ggnle@hotmail.com), 李良玥(jackiey99@gmail.com), 王方(fangkey@gmail.com)<br />
<br />
<br />
<br />
{{Languages|Deriving_gradients_using_the_backpropagation_idea|English}}</div>
Kandeng
http://ufldl.stanford.edu/wiki/index.php/%E5%8F%AF%E8%A7%86%E5%8C%96%E8%87%AA%E7%BC%96%E7%A0%81%E5%99%A8%E8%AE%AD%E7%BB%83%E7%BB%93%E6%9E%9C
可视化自编码器训练结果
2013-04-08T08:52:15Z
<p>Kandeng: /* 中英文对照 */</p>
<hr />
<div>训练完(稀疏)自编码器,我们还想把这自编码器学到的函数可视化出来,好弄明白它到底学到了什么。我们以在10×10图像(即n=100)上训练自编码器为例。在该自编码器中,每个隐藏单元i对如下关于输入的函数进行计算:<br />
:<math>\begin{align}<br />
a^{(2)}_i = f\left(\sum_{j=1}^{100} W^{(1)}_{ij} x_j + b^{(1)}_i \right).<br />
\end{align}</math><br />
<!-- This is the activation function <math>\textstyle g(\cdot)</math> applied to an affine function of the input.!--><br />
<br />
我们将要可视化的函数,就是上面这个以2D图像为输入、并由隐藏单元i计算出来的函数。它是依赖于参数<math>\textstyle W^{(1)}_{ij}</math>的(暂时忽略偏置项<math>b_i</math>)。需要注意的是,<math>\textstyle a^{(2)}_i</math>可看作输入<math>\textstyle x</math>的非线性特征。不过还有个问题:什么样的输入图像<math>\textstyle x</math>可让<math>\textstyle a^{(2)}_i</math>得到最大程度的激励?(通俗一点说,隐藏单元<math>\textstyle i</math>要找个什么样的特征?)。这里我们必须给<math>\textstyle x</math>加约束,否则会得到平凡解。若假设输入有范数约束<math>\textstyle ||x||^2 = \sum_{i=1}^{100} x_i^2 \leq 1</math>,则可证(请读者自行推导)令隐藏单元<math>\textstyle i</math>得到最大激励的输入应由下面公式计算的像素<math>\textstyle x_j</math>给出(共需计算100个像素,j=1,…,100):<br />
:<math>\begin{align}<br />
x_j = \frac{W^{(1)}_{ij}}{\sqrt{\sum_{j=1}^{100} (W^{(1)}_{ij})^2}}.<br />
\end{align}</math><br />
<br />
当我们用上式算出各像素的值、把它们组成一幅图像、并将图像呈现在我们面前之时,隐藏单元<math>\textstyle i</math>所追寻特征的真正含义也渐渐明朗起来。<br />
<br />
假如我们训练的自编码器有100个隐藏单元,可视化结果就会包含100幅这样的图像——每个隐藏单元都对应一幅图像。审视这100幅图像,我们可以试着体会这些隐藏单元学出来的整体效果是什么样的。<br />
<br />
<br />
当我们对稀疏自编码器(100个隐藏单元,在10X10像素的输入上训练 )进行上述可视化处理之后,结果如下所示:<br />
<br />
[[Image:ExampleSparseAutoencoderWeights.png|thumb|400px|center]]<br />
<br />
上图的每个小方块都给出了一个(带有有界范数 的)输入图像<math>\textstyle x</math>,它可使这100个隐藏单元中的某一个获得最大激励。我们可以看到,不同的隐藏单元学会了在图像的不同位置和方向进行边缘检测。<br />
<br />
显而易见,这些特征对物体识别等计算机视觉任务是十分有用的。若将其用于其他输入域(如音频),该算法也可学到对这些输入域有用的表示或特征。<br />
<br />
<br />
==中英文对照==<br />
<br />
:可视化 Visualizing<br />
:自编码器 Autoencoder<br />
:隐藏单元 hidden unit<br />
:非线性特征 non-linear feature<br />
:激励 activate<br />
:平凡解 non-trivial answer<br />
:范数约束 norm constrained<br />
:稀疏自编码器 sparse autoencoder<br />
:有界范数 norm bounded<br />
:输入域 input domains<br />
<br />
==中文译者==<br />
<br />
王方(fangkey@gmail.com),胡伦(hulun499@gmail.com),谢宇(msforbus@sina.com),@小琳爱肉肉(新浪微博账号), 余凯(kai.yu.cool@gmail.com)<br />
<br />
<br />
{{稀疏自编码器}}<br />
<br />
<br />
<br />
{{Languages|Visualizing_a_Trained_Autoencoder|English}}</div>
Kandeng
http://ufldl.stanford.edu/wiki/index.php/%E7%A8%80%E7%96%8F%E7%BC%96%E7%A0%81
稀疏编码
2013-04-08T08:32:53Z
<p>Kandeng: </p>
<hr />
<div>== 稀疏编码 ==<br />
<br />
稀疏编码算法是一种无监督学习方法,它用来寻找一组“超完备”基向量来更高效地表示样本数据。稀疏编码算法的目的就是找到一组基向量 <math>\mathbf{\phi}_i</math> ,使得我们能将输入向量 <math>\mathbf{x}</math> 表示为这些基向量的线性组合:<br />
<br />
:<math>\begin{align}<br />
\mathbf{x} = \sum_{i=1}^k a_i \mathbf{\phi}_{i} <br />
\end{align}</math><br />
<br />
<br />
虽然形如主成分分析技术(PCA)能使我们方便地找到一组“完备”基向量,但是这里我们想要做的是找到一组'''“超完备”'''基向量来表示输入向量 <math>\mathbf{x}\in\mathbb{R}^n</math> (也就是说,<math>k > n</math>)。超完备基的好处是它们能更有效地找出隐含在输入数据内部的结构与模式。然而,对于超完备基来说,系数 <math>a_i</math> 不再由输入向量 <math>\mathbf{x}</math> 唯一确定。因此,在稀疏编码算法中,我们另加了一个评判标准'''“稀疏性”'''来解决因超完备而导致的退化(degeneracy)问题。<br />
<br />
<br />
这里,我们把“稀疏性”定义为:只有很少的几个非零元素或只有很少的几个远大于零的元素。要求系数 <math>a_i</math> 是稀疏的意思就是说:对于一组输入向量,我们只想有尽可能少的几个系数远大于零。选择使用具有稀疏性的分量来表示我们的输入数据是有原因的,因为绝大多数的感官数据,比如自然图像,可以被表示成少量基本元素的叠加,在图像中这些基本元素可以是面或者线。同时,比如与初级视觉皮层的类比过程也因此得到了提升。<br />
<br />
<br />
我们把有 <math>m</math> 个输入向量的稀疏编码代价函数定义为:<br />
<br />
:<math>\begin{align}<br />
\text{minimize}_{a^{(j)}_i,\mathbf{\phi}_{i}} \sum_{j=1}^{m} \left|\left| \mathbf{x}^{(j)} - \sum_{i=1}^k a^{(j)}_i \mathbf{\phi}_{i}\right|\right|^{2} + \lambda \sum_{i=1}^{k}S(a^{(j)}_i)<br />
\end{align}</math><br />
<br />
<br />
此处 <math>S(.)</math> 是一个稀疏代价函数,由它来对远大于零的 <math>a_i</math> 进行“惩罚”。我们可以把稀疏编码目标函式的第一项解释为一个重构项,这一项迫使稀疏编码算法能为输入向量 <math>\mathbf{x}</math> 提供一个高拟合度的线性表达式,而公式第二项即“稀疏惩罚”项,它使 <math>\mathbf{x}</math> 的表达式变得“稀疏”。常量 <math>\lambda</math> 是一个变换量,由它来控制这两项式子的相对重要性。 <br />
<br />
<br />
虽然“稀疏性”的最直接测度标准是 "<math>L_0</math>" 范式(<math>S(a_i) = \mathbf{1}(|a_i|>0)</math>),但这是不可微的,而且通常很难进行优化。在实际中,稀疏代价函数 <math>S(.)</math> 的普遍选择是<math>L_1</math> 范式代价函数 <math>S(a_i)=\left|a_i\right|_1 </math> 及对数代价函数 <math>S(a_i)=\log(1+a_i^2)</math> 。<br />
<br />
<br />
此外,很有可能因为减小 <math>a_i</math> 或增加 <math>\mathbf{\phi}_i</math> 至很大的常量,使得稀疏惩罚变得非常小。为防止此类事件发生,我们将限制 <math>\left|\left|\mathbf{\phi}\right|\right|^2</math> 要小于某常量 <math>C</math> 。包含了限制条件的稀疏编码代价函数的完整形式如下:<br />
<br />
:<math>\begin{array}{rc}<br />
\text{minimize}_{a^{(j)}_i,\mathbf{\phi}_{i}} & \sum_{j=1}^{m} \left|\left| \mathbf{x}^{(j)} - \sum_{i=1}^k a^{(j)}_i \mathbf{\phi}_{i}\right|\right|^{2} + \lambda \sum_{i=1}^{k}S(a^{(j)}_i) <br />
\\<br />
\text{subject to} & \left|\left|\mathbf{\phi}_i\right|\right|^2 \leq C, \forall i = 1,...,k <br />
\\<br />
\end{array}</math><br />
<br />
<br />
<br />
== 概率解释 [基于1996年Olshausen与Field的理论] ==<br />
<br />
到目前为止,我们所考虑的稀疏编码,是为了寻找到一个稀疏的、超完备基向量集,来覆盖我们的输入数据空间。现在换一种方式,我们可以从概率的角度出发,将稀疏编码算法当作一种“生成模型”。<br />
<br />
<br />
我们将自然图像建模问题看成是一种线性叠加,叠加元素包括 <math>k</math> 个独立的源特征 <math>\mathbf{\phi}_i</math> 以及加性噪声 <math>\nu</math> :<br />
<br />
:<math>\begin{align}<br />
\mathbf{x} = \sum_{i=1}^k a_i \mathbf{\phi}_{i} + \nu(\mathbf{x})<br />
\end{align}</math><br />
<br />
<br />
我们的目标是找到一组特征基向量 <math>\mathbf{\phi}</math> ,它使得图像的分布函数 <math>P(\mathbf{x}\mid\mathbf{\phi})</math> 尽可能地近似于输入数据的经验分布函数 <math>P^*(\mathbf{x})</math> 。一种实现方式是,最小化 <math>P^*(\mathbf{x})</math> 与 <math>P(\mathbf{x}\mid\mathbf{\phi})</math> 之间的 KL 散度,此 KL 散度表示如下:<br />
<br />
:<math>\begin{align}<br />
D(P^*(\mathbf{x})||P(\mathbf{x}\mid\mathbf{\phi})) = \int P^*(\mathbf{x}) \log \left(\frac{P^*(\mathbf{x})}{P(\mathbf{x}\mid\mathbf{\phi})}\right)d\mathbf{x}<br />
\end{align}</math> <br />
<br />
<br />
因为无论我们如何选择 <math>\mathbf{\phi}</math> ,经验分布函数 <math>P^*(\mathbf{x})</math> 都是常量,也就是说我们只需要最大化对数似然函数 <math>P(\mathbf{x}\mid\mathbf{\phi})</math> 。<br />
假设 <math>\nu</math> 是具有方差 <math>\sigma^2</math> 的高斯白噪音,则有下式:<br />
<br />
:<math>\begin{align}<br />
P(\mathbf{x} \mid \mathbf{a}, \mathbf{\phi}) = \frac{1}{Z} \exp\left(- \frac{(\mathbf{x}-\sum^{k}_{i=1} a_i \mathbf{\phi}_{i})^2}{2\sigma^2}\right)<br />
\end{align}</math><br />
<br />
<br />
为了确定分布 <math>P(\mathbf{x}\mid\mathbf{\phi})</math> ,我们需要指定先验分布 <math>P(\mathbf{a})</math> 。假定我们的特征变量是独立的,我们就可以将先验概率分解为:<br />
<br />
:<math>\begin{align}<br />
P(\mathbf{a}) = \prod_{i=1}^{k} P(a_i)<br />
\end{align}</math><br />
<br />
<br />
此时,我们将“稀疏”假设加入进来——假设任何一幅图像都是由相对较少的一些源特征组合起来的。因此,我们希望 <math>a_i</math> 的概率分布在零值附近是凸起的,而且峰值很高。一个方便的参数化先验分布就是:<br />
<br />
:<math>\begin{align}<br />
P(a_i) = \frac{1}{Z}\exp(-\beta S(a_i))<br />
\end{align}</math><br />
<br />
<br />
这里 <math>S(a_i)</math> 是决定先验分布的形状的函数。<br />
<br />
<br />
当定义了 <math>P(\mathbf{x} \mid \mathbf{a} , \mathbf{\phi})</math> 和 <math> P(\mathbf{a})</math> 后,我们就可以写出在由 <math>\mathbf{\phi}</math> 定义的模型之下的数据 <math>\mathbf{x}</math> 的概率分布:<br />
<br />
:<math>\begin{align}<br />
P(\mathbf{x} \mid \mathbf{\phi}) = \int P(\mathbf{x} \mid \mathbf{a}, \mathbf{\phi}) P(\mathbf{a}) d\mathbf{a}<br />
\end{align}</math><br />
<br />
<br />
那么,我们的问题就简化为寻找:<br />
<br />
:<math>\begin{align}<br />
\mathbf{\phi}^*=\text{argmax}_{\mathbf{\phi}} < \log(P(\mathbf{x} \mid \mathbf{\phi})) ><br />
\end{align}</math><br />
<br />
<br />
这里 <math><.></math> 表示的是输入数据的期望值。<br />
<br />
<br />
不幸的是,通过对 <math>\mathbf{a}</math> 的积分计算 <math>P(\mathbf{x} \mid \mathbf{\phi})</math> 通常是难以实现的。虽然如此,我们注意到如果 <math>P(\mathbf{x} \mid \mathbf{\phi})</math> 的分布(对于相应的 <math>\mathbf{a}</math> )足够陡峭的话,我们就可以用 <math>P(\mathbf{x} \mid \mathbf{\phi})</math> 的最大值来估算以上积分。估算方法如下:<br />
<br />
:<math>\begin{align}<br />
\mathbf{\phi}^{*'}=\text{argmax}_{\mathbf{\phi}} < \max_{\mathbf{a}} \log(P(\mathbf{x} \mid \mathbf{\phi})) ><br />
\end{align}</math><br />
<br />
<br />
跟之前一样,我们可以通过减小 <math>a_i</math> 或增大 <math>\mathbf{\phi}</math> 来增加概率的估算值(因为 <math>P(a_i)</math> 在零值附近陡升)。因此我们要对特征向量 <math>\mathbf{\phi}</math> 加一个限制以防止这种情况发生。<br />
<br />
最后,我们可以定义一种线性生成模型的能量函数,从而将原先的代价函数重新表述为:<br />
<br />
:<math>\begin{array}{rl}<br />
E\left( \mathbf{x} , \mathbf{a} \mid \mathbf{\phi} \right) & := -\log \left( P(\mathbf{x}\mid \mathbf{\phi},\mathbf{a}\right)P(\mathbf{a})) \\<br />
&= \sum_{j=1}^{m} \left|\left| \mathbf{x}^{(j)} - \sum_{i=1}^k a^{(j)}_i \mathbf{\phi}_{i}\right|\right|^{2} + \lambda \sum_{i=1}^{k}S(a^{(j)}_i) <br />
\end{array}</math><br />
<br />
<br />
其中 <math>\lambda = 2\sigma^2\beta</math> ,并且关系不大的常量已被隐藏起来。因为最大化对数似然函数等同于最小化能量函数,我们就可以将原先的优化问题重新表述为:<br />
<br />
:<math>\begin{align}<br />
\mathbf{\phi}^{*},\mathbf{a}^{*}=\text{argmin}_{\mathbf{\phi},\mathbf{a}} \sum_{j=1}^{m} \left|\left| \mathbf{x}^{(j)} - \sum_{i=1}^k a^{(j)}_i \mathbf{\phi}_{i}\right|\right|^{2} + \lambda \sum_{i=1}^{k}S(a^{(j)}_i) <br />
\end{align}</math><br />
<br />
<br />
使用概率理论来分析,我们可以发现,选择 <math>L_1</math> 惩罚和 <math>\log(1+a_i^2)</math> 惩罚作为函数 <math>S(.)</math> ,分别对应于使用了拉普拉斯概率 <math>P(a_i) \propto \exp\left(-\beta|a_i|\right)</math> 和柯西先验概率 <math>P(a_i) \propto \frac{\beta}{1+a_i^2}</math> 。<br />
<br />
<br />
== 学习算法 ==<br />
<br />
使用稀疏编码算法学习基向量集的方法,是由两个独立的优化过程组合起来的。第一个是逐个使用训练样本 <math>\mathbf{x}</math> 来优化系数 <math>a_i</math> ,第二个是一次性处理多个样本对基向量 <math>\mathbf{\phi}</math> 进行优化。<br />
<br />
<br />
如果使用 <math>L_1</math> 范式作为稀疏惩罚函数,对 <math>a^{(j)}_i</math> 的学习过程就简化为求解 由 <math>L_1</math> 范式正则化的最小二乘法问题,这个问题函数在域 <math>a^{(j)}_i</math> 内为凸,已经有很多技术方法来解决这个问题(诸如CVX之类的凸优化软件可以用来解决L1正则化的最小二乘法问题)。如果 <math>S(.)</math> 是可微的,比如是对数惩罚函数,则可以采用基于梯度算法的方法,如共轭梯度法。<br />
<br />
<br />
用 <math>L_2</math> 范式约束来学习基向量,同样可以简化为一个带有二次约束的最小二乘问题,其问题函数在域 <math>\mathbf{\phi}</math> 内也为凸。标准的凸优化软件(如CVX)或其它迭代方法就可以用来求解 <math>\mathbf{\phi}</math>,虽然已经有了更有效的方法,比如求解拉格朗日对偶函数(Lagrange dual)。<br />
<br />
<br />
根据前面的的描述,稀疏编码是有一个明显的局限性的,这就是即使已经学习得到一组基向量,如果为了对新的数据样本进行“编码”,我们必须再次执行优化过程来得到所需的系数。这个显著的“实时”消耗意味着,即使是在测试中,实现稀疏编码也需要高昂的计算成本,尤其是与典型的前馈结构算法相比。<br />
<br />
<br />
<br />
==中英文对照==<br />
<br />
:稀疏编码 Sparse Coding <br />
:无监督学习 unsupervised method<br />
:超完备基 over-complete bases<br />
:主成分分析 PCA<br />
:稀疏性 sparsity<br />
:退化 degeneracy<br />
:代价函数 cost function<br />
:重构项 reconstruction term<br />
:稀疏惩罚项 sparsity penalty<br />
:范式 norm<br />
:生成模型 generative model<br />
:线性叠加 linear superposition<br />
:加性噪声 additive noise<br />
:特征基向量 basis feature vectors<br />
:经验分布函数 the empirical distribution<br />
:KL 散度 KL divergence<br />
:对数似然函数 the log-likelihood<br />
:高斯白噪音 Gaussian white noise<br />
:先验分布 the prior distribution<br />
:先验概率 prior probability<br />
:源特征 source features<br />
:能量函数 the energy function<br />
:正则化 regularized<br />
:最小二乘法 least squares<br />
:凸优化软件convex optimization software<br />
:共轭梯度法 conjugate gradient methods<br />
:二次约束 quadratic constraints<br />
:拉格朗日对偶函数 the Lagrange dual<br />
:前馈结构算法 feedforward architectures<br />
<br />
<br />
==中文译者==<br />
<br />
柳翠寅(liucuiyin@163.com),林锋(xlfg@yeah.net),王方(fangkey@gmail.com)<br />
<br />
<br />
<br />
{{Languages|Sparse_Coding|English}}</div>
Kandeng
http://ufldl.stanford.edu/wiki/index.php/%E9%80%BB%E8%BE%91%E5%9B%9E%E5%BD%92%E7%9A%84%E5%90%91%E9%87%8F%E5%8C%96%E5%AE%9E%E7%8E%B0%E6%A0%B7%E4%BE%8B
逻辑回归的向量化实现样例
2013-04-08T08:31:49Z
<p>Kandeng: </p>
<hr />
<div>我们想用批量梯度上升法对logistic回归分析模型进行训练,其模型如下:<br />
<br />
:<math>\begin{align}<br />
h_\theta(x) = \frac{1}{1+\exp(-\theta^Tx)},<br />
\end{align}</math><br />
<br />
让我们遵从公开课程视频与CS229教学讲义的符号规范,设 <math>\textstyle x_0=1</math>,于是<math>x\in R^{n+1}</math> ,<math>\theta \in R^{n+1}</math>, <math>\textstyle \theta_0</math> 为截距。假设我们有m个训练样本{(<math>x^\left( 1\right) </math>,<math>y^\left( 1\right)</math> ) ,...,(<math>x^\left( m\right)</math> ,<math>y^\left( m\right)</math> )},而批量梯度上升法的更新法则是:<math>\theta :=\theta +\alpha \nabla _{\theta }l\left( \theta \right) </math> ,这里的 <math>l\left( \theta \right) </math> 是对数似然函数,<math>\nabla _{\theta }l\left( \theta \right) </math> 是其导函数。<br />
<br />
[注:下文的符号规范与<公开课程视频>或<教学讲义CS229:机器学习>中的相同,详细内容可以参见公开课程视频或教学讲义#1 http://cs229.stanford.edu/]<br />
<br />
于是,我们需要如下计算梯度:<br />
<br />
:<math>\begin{align}<br />
\nabla_\theta \ell(\theta) = \sum_{i=1}^m \left(y^{(i)} - h_\theta(x^{(i)}) \right) x^{(i)}_j.<br />
\end{align}</math><br />
<br />
我们用Matlab/Octave风格变量x表示输入数据构成的样本矩阵,x(:,i)代表第 i个训练样本<math>x^{\left( i\right) }</math>,x(j,i)就代表<math>x_{j}^{\left( i\right) }</math>(译者注:第i个训练样本向量的第j个元素)。同样,用Matlab/Octave风格变量y表示由训练样本集合的全体类别标号所构成的行向量,则该向量的第i个元素y(i)就代表上式中的<math>y^{\left(i\right) }\in \left\{ 0,1\right\} </math>。(注意这里跟公开课程视频及CS229的符号规范不同,矩阵x按列而不是按行存放输入训练样本,同样,<math>y\in R^{1\times m}</math>是行向量而不是列向量。)<br />
<br />
<br />
以下是梯度运算代码的一种实现,非常恐怖,速度极慢:<br />
<br />
<syntaxhighlight lang="matlab"><br />
% 代码1<br />
grad = zeros(n+1,1);<br />
for i=1:m,<br />
h = sigmoid(theta'*x(:,i));<br />
temp = y(i) - h; <br />
for j=1:n+1,<br />
grad(j) = grad(j) + temp * x(j,i); <br />
end;<br />
end;<br />
</syntaxhighlight><br />
<br />
<br />
嵌套的for循环语句使这段代码的运行非常缓慢。以下是更典型的实现方式,它对算法进行部分向量化,带来更优的执行效率:<br />
<br />
<syntaxhighlight lang="matlab"><br />
% 代码2<br />
grad = zeros(n+1,1);<br />
for i=1:m,<br />
grad = grad + (y(i) - sigmoid(theta'*x(:,i)))* x(:,i);<br />
end;<br />
</syntaxhighlight><br />
<br />
<br />
但是,或许可以向量化得更彻底些。如果去除for循环,我们就可以显著地改善代码执行效率。特别的,假定b是一个列向量,A是一个矩阵,我们用以下两种方式来计算A*b:<br />
<br />
<syntaxhighlight lang="matlab"><br />
% 矩阵-向量乘法运算的低效代码<br />
grad = zeros(n+1,1);<br />
for i=1:m,<br />
grad = grad + b(i) * A(:,i); % 通常写法为A(:,i)*b(i)<br />
end;<br />
<br />
% 矩阵-向量乘法运算的高效代码<br />
grad = A*b;<br />
</syntaxhighlight><br />
<br />
<br />
我们看到,代码2是用了低效的for循环语句执行梯度上升(译者注:原文是下降)运算,将b(i)看成(y(i) - sigmoid(theta'*x(:,i))),A看成x,我们就可以使用以下高效率的代码:<br />
<br />
<syntaxhighlight lang="matlab"><br />
% 代码3<br />
grad = x * (y- sigmoid(theta'*x));<br />
</syntaxhighlight><br />
<br />
<br />
这里我们假定Matlab/Octave的sigmoid(z)函数接受一个向量形式的输入z,依次对输入向量的每个元素施行sigmoid函数,最后返回运算结果,因此sigmoid(z)的输出结果是一个与z有相同维度的向量。<br />
<br />
当训练数据集很大时,最终的实现(译者注:代码3)充分发挥了Matlab/Octave高度优化的数值线性代数库的优势来进行矩阵-向量操作,因此,比起之前代码要高效得多。<br />
<br />
想采用向量化实现并非易事,通常需要周密的思考。但当你熟练掌握向量化操作后,你会发现,这里面有固定的设计模式(对应少量的向量化技巧),可以灵活运用到很多不同的代码片段中。<br />
<br />
<br />
==中英文对照==<br />
<br />
:逻辑回归 Logistic Regression<br />
:批量梯度上升法 batch gradient ascent<br />
:截距 intercept term<br />
:对数似然函数 the log likelihood<br />
:导函数 derivative<br />
:梯度 gradient<br />
<br />
<br />
==中文译者==<br />
<br />
林锋(xlfg@yeah.net),谭晓阳(x.tan@nuaa.edu.cn),邓亚峰(dengyafeng@gmail.com)<br />
<br />
<br />
{{矢量化编程实现}}<br />
<br />
<br />
{{Languages|Logistic_Regression_Vectorization_Example|English}}</div>
Kandeng
http://ufldl.stanford.edu/wiki/index.php/%E7%A8%80%E7%96%8F%E7%BC%96%E7%A0%81
稀疏编码
2013-04-08T08:16:44Z
<p>Kandeng: /* 中英文对照 */</p>
<hr />
<div>== 稀疏编码 ==<br />
<br />
稀疏编码算法是一种无监督学习方法,它用来寻找一组“超完备”基向量来更高效地表示样本数据。稀疏编码算法的目的就是找到一组基向量 <math>\mathbf{\phi}_i</math> ,使得我们能将输入向量 <math>\mathbf{x}</math> 表示为这些基向量的线性组合:<br />
<br />
:<math>\begin{align}<br />
\mathbf{x} = \sum_{i=1}^k a_i \mathbf{\phi}_{i} <br />
\end{align}</math><br />
<br />
<br />
虽然形如主成分分析技术(PCA)能使我们方便地找到一组“完备”基向量,但是这里我们想要做的是找到一组'''“超完备”'''基向量来表示输入向量 <math>\mathbf{x}\in\mathbb{R}^n</math> (也就是说,<math>k > n</math>)。超完备基的好处是它们能更有效地找出隐含在输入数据内部的结构与模式。然而,对于超完备基来说,系数 <math>a_i</math> 不再由输入向量 <math>\mathbf{x}</math> 唯一确定。因此,在稀疏编码算法中,我们另加了一个评判标准'''“稀疏性”'''来解决因超完备而导致的退化(degeneracy)问题。<br />
<br />
<br />
这里,我们把“稀疏性”定义为:只有很少的几个非零元素或只有很少的几个远大于零的元素。要求系数 <math>a_i</math> 是稀疏的意思就是说:对于一组输入向量,我们只想有尽可能少的几个系数远大于零。选择使用具有稀疏性的分量来表示我们的输入数据是有原因的,因为绝大多数的感官数据,比如自然图像,可以被表示成少量基本元素的叠加,在图像中这些基本元素可以是面或者线。同时,比如与初级视觉皮层的类比过程也因此得到了提升。<br />
<br />
<br />
我们把有 <math>m</math> 个输入向量的稀疏编码代价函数定义为:<br />
<br />
:<math>\begin{align}<br />
\text{minimize}_{a^{(j)}_i,\mathbf{\phi}_{i}} \sum_{j=1}^{m} \left|\left| \mathbf{x}^{(j)} - \sum_{i=1}^k a^{(j)}_i \mathbf{\phi}_{i}\right|\right|^{2} + \lambda \sum_{i=1}^{k}S(a^{(j)}_i)<br />
\end{align}</math><br />
<br />
<br />
此处 <math>S(.)</math> 是一个稀疏代价函数,由它来对远大于零的 <math>a_i</math> 进行“惩罚”。我们可以把稀疏编码目标函式的第一项解释为一个重构项,这一项迫使稀疏编码算法能为输入向量 <math>\mathbf{x}</math> 提供一个高拟合度的线性表达式,而公式第二项即“稀疏惩罚”项,它使 <math>\mathbf{x}</math> 的表达式变得“稀疏”。常量 <math>\lambda</math> 是一个变换量,由它来控制这两项式子的相对重要性。 <br />
<br />
<br />
虽然“稀疏性”的最直接测度标准是 "<math>L_0</math>" 范式(<math>S(a_i) = \mathbf{1}(|a_i|>0)</math>),但这是不可微的,而且通常很难进行优化。在实际中,稀疏代价函数 <math>S(.)</math> 的普遍选择是<math>L_1</math> 范式代价函数 <math>S(a_i)=\left|a_i\right|_1 </math> 及对数代价函数 <math>S(a_i)=\log(1+a_i^2)</math> 。<br />
<br />
<br />
此外,很有可能因为减小 <math>a_i</math> 或增加 <math>\mathbf{\phi}_i</math> 至很大的常量,使得稀疏惩罚变得非常小。为防止此类事件发生,我们将限制 <math>\left|\left|\mathbf{\phi}\right|\right|^2</math> 要小于某常量 <math>C</math> 。包含了限制条件的稀疏编码代价函数的完整形式如下:<br />
<br />
:<math>\begin{array}{rc}<br />
\text{minimize}_{a^{(j)}_i,\mathbf{\phi}_{i}} & \sum_{j=1}^{m} \left|\left| \mathbf{x}^{(j)} - \sum_{i=1}^k a^{(j)}_i \mathbf{\phi}_{i}\right|\right|^{2} + \lambda \sum_{i=1}^{k}S(a^{(j)}_i) <br />
\\<br />
\text{subject to} & \left|\left|\mathbf{\phi}_i\right|\right|^2 \leq C, \forall i = 1,...,k <br />
\\<br />
\end{array}</math><br />
<br />
<br />
<br />
== 概率解释 [基于1996年Olshausen与Field的理论] ==<br />
<br />
到目前为止,我们所考虑的稀疏编码,是为了寻找到一个稀疏的、超完备基向量集,来覆盖我们的输入数据空间。现在换一种方式,我们可以从概率的角度出发,将稀疏编码算法当作一种“生成模型”。<br />
<br />
<br />
我们将自然图像建模问题看成是一种线性叠加,叠加元素包括 <math>k</math> 个独立的源特征 <math>\mathbf{\phi}_i</math> 以及加性噪声 <math>\nu</math> :<br />
<br />
:<math>\begin{align}<br />
\mathbf{x} = \sum_{i=1}^k a_i \mathbf{\phi}_{i} + \nu(\mathbf{x})<br />
\end{align}</math><br />
<br />
<br />
我们的目标是找到一组特征基向量 <math>\mathbf{\phi}</math> ,它使得图像的分布函数 <math>P(\mathbf{x}\mid\mathbf{\phi})</math> 尽可能地近似于输入数据的经验分布函数 <math>P^*(\mathbf{x})</math> 。一种实现方式是,最小化 <math>P^*(\mathbf{x})</math> 与 <math>P(\mathbf{x}\mid\mathbf{\phi})</math> 之间的 KL 散度,此 KL 散度表示如下:<br />
<br />
:<math>\begin{align}<br />
D(P^*(\mathbf{x})||P(\mathbf{x}\mid\mathbf{\phi})) = \int P^*(\mathbf{x}) \log \left(\frac{P^*(\mathbf{x})}{P(\mathbf{x}\mid\mathbf{\phi})}\right)d\mathbf{x}<br />
\end{align}</math> <br />
<br />
<br />
因为无论我们如何选择 <math>\mathbf{\phi}</math> ,经验分布函数 <math>P^*(\mathbf{x})</math> 都是常量,也就是说我们只需要最大化对数似然函数 <math>P(\mathbf{x}\mid\mathbf{\phi})</math> 。<br />
假设 <math>\nu</math> 是具有方差 <math>\sigma^2</math> 的高斯白噪音,则有下式:<br />
<br />
:<math>\begin{align}<br />
P(\mathbf{x} \mid \mathbf{a}, \mathbf{\phi}) = \frac{1}{Z} \exp\left(- \frac{(\mathbf{x}-\sum^{k}_{i=1} a_i \mathbf{\phi}_{i})^2}{2\sigma^2}\right)<br />
\end{align}</math><br />
<br />
<br />
为了确定分布 <math>P(\mathbf{x}\mid\mathbf{\phi})</math> ,我们需要指定先验分布 <math>P(\mathbf{a})</math> 。假定我们的特征变量是独立的,我们就可以将先验概率分解为:<br />
<br />
:<math>\begin{align}<br />
P(\mathbf{a}) = \prod_{i=1}^{k} P(a_i)<br />
\end{align}</math><br />
<br />
<br />
此时,我们将“稀疏”假设加入进来——假设任何一幅图像都是由相对较少的一些源特征组合起来的。因此,我们希望 <math>a_i</math> 的概率分布在零值附近是凸起的,而且峰值很高。一个方便的参数化先验分布就是:<br />
<br />
:<math>\begin{align}<br />
P(a_i) = \frac{1}{Z}\exp(-\beta S(a_i))<br />
\end{align}</math><br />
<br />
<br />
这里 <math>S(a_i)</math> 是决定先验分布的形状的函数。<br />
<br />
<br />
当定义了 <math>P(\mathbf{x} \mid \mathbf{a} , \mathbf{\phi})</math> 和 <math> P(\mathbf{a})</math> 后,我们就可以写出在由 <math>\mathbf{\phi}</math> 定义的模型之下的数据 <math>\mathbf{x}</math> 的概率分布:<br />
<br />
:<math>\begin{align}<br />
P(\mathbf{x} \mid \mathbf{\phi}) = \int P(\mathbf{x} \mid \mathbf{a}, \mathbf{\phi}) P(\mathbf{a}) d\mathbf{a}<br />
\end{align}</math><br />
<br />
<br />
那么,我们的问题就简化为寻找:<br />
<br />
:<math>\begin{align}<br />
\mathbf{\phi}^*=\text{argmax}_{\mathbf{\phi}} < \log(P(\mathbf{x} \mid \mathbf{\phi})) ><br />
\end{align}</math><br />
<br />
<br />
这里 <math><.></math> 表示的是输入数据的期望值。<br />
<br />
<br />
不幸的是,通过对 <math>\mathbf{a}</math> 的积分计算 <math>P(\mathbf{x} \mid \mathbf{\phi})</math> 通常是难以实现的。虽然如此,我们注意到如果 <math>P(\mathbf{x} \mid \mathbf{\phi})</math> 的分布(对于相应的 <math>\mathbf{a}</math> )足够陡峭的话,我们就可以用 <math>P(\mathbf{x} \mid \mathbf{\phi})</math> 的最大值来估算以上积分。估算方法如下:<br />
<br />
:<math>\begin{align}<br />
\mathbf{\phi}^{*'}=\text{argmax}_{\mathbf{\phi}} < \max_{\mathbf{a}} \log(P(\mathbf{x} \mid \mathbf{\phi})) ><br />
\end{align}</math><br />
<br />
<br />
跟之前一样,我们可以通过减小 <math>a_i</math> 或增大 <math>\mathbf{\phi}</math> 来增加概率的估算值(因为 <math>P(a_i)</math> 在零值附近陡升)。因此我们要对特征向量 <math>\mathbf{\phi}</math> 加一个限制以防止这种情况发生。<br />
<br />
最后,我们可以定义一种线性生成模型的能量函数,从而将原先的代价函数重新表述为:<br />
<br />
:<math>\begin{array}{rl}<br />
E\left( \mathbf{x} , \mathbf{a} \mid \mathbf{\phi} \right) & := -\log \left( P(\mathbf{x}\mid \mathbf{\phi},\mathbf{a}\right)P(\mathbf{a})) \\<br />
&= \sum_{j=1}^{m} \left|\left| \mathbf{x}^{(j)} - \sum_{i=1}^k a^{(j)}_i \mathbf{\phi}_{i}\right|\right|^{2} + \lambda \sum_{i=1}^{k}S(a^{(j)}_i) <br />
\end{array}</math><br />
<br />
<br />
其中 <math>\lambda = 2\sigma^2\beta</math> ,并且关系不大的常量已被隐藏起来。因为最大化对数似然函数等同于最小化能量函数,我们就可以将原先的优化问题重新表述为:<br />
<br />
:<math>\begin{align}<br />
\mathbf{\phi}^{*},\mathbf{a}^{*}=\text{argmin}_{\mathbf{\phi},\mathbf{a}} \sum_{j=1}^{m} \left|\left| \mathbf{x}^{(j)} - \sum_{i=1}^k a^{(j)}_i \mathbf{\phi}_{i}\right|\right|^{2} + \lambda \sum_{i=1}^{k}S(a^{(j)}_i) <br />
\end{align}</math><br />
<br />
<br />
使用概率理论来分析,我们可以发现,选择 <math>L_1</math> 惩罚和 <math>\log(1+a_i^2)</math> 惩罚作为函数 <math>S(.)</math> ,分别对应于使用了拉普拉斯概率 <math>P(a_i) \propto \exp\left(-\beta|a_i|\right)</math> 和柯西先验概率 <math>P(a_i) \propto \frac{\beta}{1+a_i^2}</math> 。<br />
<br />
<br />
== 学习算法 ==<br />
<br />
使用稀疏编码算法学习基向量集的方法,是由两个独立的优化过程组合起来的。第一个是逐个使用训练样本 <math>\mathbf{x}</math> 来优化系数 <math>a_i</math> ,第二个是一次性处理多个样本对基向量 <math>\mathbf{\phi}</math> 进行优化。<br />
<br />
<br />
如果使用 <math>L_1</math> 范式作为稀疏惩罚函数,对 <math>a^{(j)}_i</math> 的学习过程就简化为求解 由 <math>L_1</math> 范式正则化的最小二乘法问题,这个问题函数在域 <math>a^{(j)}_i</math> 内为凸,已经有很多技术方法来解决这个问题(诸如CVX之类的凸优化软件可以用来解决L1正则化的最小二乘法问题)。如果 <math>S(.)</math> 是可微的,比如是对数惩罚函数,则可以采用基于梯度算法的方法,如共轭梯度法。<br />
<br />
<br />
用 <math>L_2</math> 范式约束来学习基向量,同样可以简化为一个带有二次约束的最小二乘问题,其问题函数在域 <math>\mathbf{\phi}</math> 内也为凸。标准的凸优化软件(如CVX)或其它迭代方法就可以用来求解 <math>\mathbf{\phi}</math>,虽然已经有了更有效的方法,比如求解拉格朗日对偶函数(Lagrange dual)。<br />
<br />
<br />
根据前面的的描述,稀疏编码是有一个明显的局限性的,这就是即使已经学习得到一组基向量,如果为了对新的数据样本进行“编码”,我们必须再次执行优化过程来得到所需的系数。这个显著的“实时”消耗意味着,即使是在测试中,实现稀疏编码也需要高昂的计算成本,尤其是与典型的前馈结构算法相比。<br />
<br />
<br />
<br />
==中英文对照==<br />
<br />
:稀疏编码 Sparse Coding <br />
:无监督学习 unsupervised method<br />
:超完备基 over-complete bases<br />
:主成分分析 PCA<br />
:稀疏性 sparsity<br />
:退化 degeneracy<br />
:代价函数 cost function<br />
:重构项 reconstruction term<br />
:稀疏惩罚项 sparsity penalty<br />
:范式 norm<br />
:生成模型 generative model<br />
:线性叠加 linear superposition<br />
:加性噪声 additive noise<br />
:特征基向量 basis feature vectors<br />
:经验分布函数 the empirical distribution<br />
:KL 散度 KL divergence<br />
:对数似然函数 the log-likelihood<br />
:高斯白噪音 Gaussian white noise<br />
:先验分布 the prior distribution<br />
:先验概率 prior probability<br />
:源特征 source features<br />
:能量函数 the energy function<br />
:正则化 regularized<br />
:最小二乘法 least squares<br />
:凸优化软件convex optimization software<br />
:共轭梯度法 conjugate gradient methods<br />
:二次约束 quadratic constraints<br />
:拉格朗日对偶函数 the Lagrange dual<br />
:前馈结构算法 feedforward architectures<br />
<br />
==中文译者==<br />
<br />
柳翠寅(liucuiyin@163.com),林锋(xlfg@yeah.net),王方(fangkey@gmail.com)<br />
<br />
<br />
<br />
{{Languages|Sparse_Coding|English}}</div>
Kandeng
http://ufldl.stanford.edu/wiki/index.php/%E9%80%BB%E8%BE%91%E5%9B%9E%E5%BD%92%E7%9A%84%E5%90%91%E9%87%8F%E5%8C%96%E5%AE%9E%E7%8E%B0%E6%A0%B7%E4%BE%8B
逻辑回归的向量化实现样例
2013-04-08T07:55:10Z
<p>Kandeng: /* 中英文对照 */</p>
<hr />
<div>我们想用批量梯度上升法对logistic回归分析模型进行训练,其模型如下:<br />
<br />
:<math>\begin{align}<br />
h_\theta(x) = \frac{1}{1+\exp(-\theta^Tx)},<br />
\end{align}</math><br />
<br />
让我们遵从公开课程视频与CS229教学讲义的符号规范,设 <math>\textstyle x_0=1</math>,于是<math>x\in R^{n+1}</math> ,<math>\theta \in R^{n+1}</math>, <math>\textstyle \theta_0</math> 为截距。假设我们有m个训练样本{(<math>x^\left( 1\right) </math>,<math>y^\left( 1\right)</math> ) ,...,(<math>x^\left( m\right)</math> ,<math>y^\left( m\right)</math> )},而批量梯度上升法的更新法则是:<math>\theta :=\theta +\alpha \nabla _{\theta }l\left( \theta \right) </math> ,这里的 <math>l\left( \theta \right) </math> 是对数似然函数,<math>\nabla _{\theta }l\left( \theta \right) </math> 是其导函数。<br />
<br />
[注:下文的符号规范与<公开课程视频>或<教学讲义CS229:机器学习>中的相同,详细内容可以参见公开课程视频或教学讲义#1 http://cs229.stanford.edu/]<br />
<br />
于是,我们需要如下计算梯度:<br />
<br />
:<math>\begin{align}<br />
\nabla_\theta \ell(\theta) = \sum_{i=1}^m \left(y^{(i)} - h_\theta(x^{(i)}) \right) x^{(i)}_j.<br />
\end{align}</math><br />
<br />
我们用Matlab/Octave风格变量x表示输入数据构成的样本矩阵,x(:,i)代表第 i个训练样本<math>x^{\left( i\right) }</math>,x(j,i)就代表<math>x_{j}^{\left( i\right) }</math>(译者注:第i个训练样本向量的第j个元素)。同样,用Matlab/Octave风格变量y表示由训练样本集合的全体类别标号所构成的行向量,则该向量的第i个元素y(i)就代表上式中的<math>y^{\left(i\right) }\in \left\{ 0,1\right\} </math>。(注意这里跟公开课程视频及CS229的符号规范不同,矩阵x按列而不是按行存放输入训练样本,同样,<math>y\in R^{1\times m}</math>是行向量而不是列向量。)<br />
<br />
<br />
以下是梯度运算代码的一种实现,非常恐怖,速度极慢:<br />
<br />
<syntaxhighlight lang="matlab"><br />
% 代码1<br />
grad = zeros(n+1,1);<br />
for i=1:m,<br />
h = sigmoid(theta'*x(:,i));<br />
temp = y(i) - h; <br />
for j=1:n+1,<br />
grad(j) = grad(j) + temp * x(j,i); <br />
end;<br />
end;<br />
</syntaxhighlight><br />
<br />
<br />
嵌套的for循环语句使这段代码的运行非常缓慢。以下是更典型的实现方式,它对算法进行部分向量化,带来更优的执行效率:<br />
<br />
<syntaxhighlight lang="matlab"><br />
% 代码2<br />
grad = zeros(n+1,1);<br />
for i=1:m,<br />
grad = grad + (y(i) - sigmoid(theta'*x(:,i)))* x(:,i);<br />
end;<br />
</syntaxhighlight><br />
<br />
<br />
但是,或许可以向量化得更彻底些。如果去除for循环,我们就可以显著地改善代码执行效率。特别的,假定b是一个列向量,A是一个矩阵,我们用以下两种方式来计算A*b:<br />
<br />
<syntaxhighlight lang="matlab"><br />
% 矩阵-向量乘法运算的低效代码<br />
grad = zeros(n+1,1);<br />
for i=1:m,<br />
grad = grad + b(i) * A(:,i); % 通常写法为A(:,i)*b(i)<br />
end;<br />
<br />
% 矩阵-向量乘法运算的高效代码<br />
grad = A*b;<br />
</syntaxhighlight><br />
<br />
<br />
我们看到,代码2是用了低效的for循环语句执行梯度上升(译者注:原文是下降)运算,将b(i)看成(y(i) - sigmoid(theta'*x(:,i))),A看成x,我们就可以使用以下高效率的代码:<br />
<br />
<syntaxhighlight lang="matlab"><br />
% 代码3<br />
grad = x * (y- sigmoid(theta'*x));<br />
</syntaxhighlight><br />
<br />
<br />
这里我们假定Matlab/Octave的sigmoid(z)函数接受一个向量形式的输入z,依次对输入向量的每个元素施行sigmoid函数,最后返回运算结果,因此sigmoid(z)的输出结果是一个与z有相同维度的向量。<br />
<br />
当训练数据集很大时,最终的实现(译者注:代码3)充分发挥了Matlab/Octave高度优化的数值线性代数库的优势来进行矩阵-向量操作,因此,比起之前代码要高效得多。<br />
<br />
想采用向量化实现并非易事,通常需要周密的思考。但当你熟练掌握向量化操作后,你会发现,这里面有固定的设计模式(对应少量的向量化技巧),可以灵活运用到很多不同的代码片段中。<br />
<br />
<br />
==中英文对照==<br />
<br />
:逻辑回归 Logistic Regression<br />
:批量梯度上升法 batch gradient ascent<br />
:截距 intercept term<br />
:对数似然函数 the log likelihood<br />
:导函数 derivative<br />
:梯度 gradient<br />
<br />
==中文译者==<br />
<br />
林锋(xlfg@yeah.net),谭晓阳(x.tan@nuaa.edu.cn),邓亚峰(dengyafeng@gmail.com)<br />
<br />
<br />
{{矢量化编程实现}}<br />
<br />
<br />
{{Languages|Logistic_Regression_Vectorization_Example|English}}</div>
Kandeng
http://ufldl.stanford.edu/wiki/index.php/%E9%80%BB%E8%BE%91%E5%9B%9E%E5%BD%92%E7%9A%84%E5%90%91%E9%87%8F%E5%8C%96%E5%AE%9E%E7%8E%B0%E6%A0%B7%E4%BE%8B
逻辑回归的向量化实现样例
2013-04-08T07:54:09Z
<p>Kandeng: /* 中英文对照 */</p>
<hr />
<div>我们想用批量梯度上升法对logistic回归分析模型进行训练,其模型如下:<br />
<br />
:<math>\begin{align}<br />
h_\theta(x) = \frac{1}{1+\exp(-\theta^Tx)},<br />
\end{align}</math><br />
<br />
让我们遵从公开课程视频与CS229教学讲义的符号规范,设 <math>\textstyle x_0=1</math>,于是<math>x\in R^{n+1}</math> ,<math>\theta \in R^{n+1}</math>, <math>\textstyle \theta_0</math> 为截距。假设我们有m个训练样本{(<math>x^\left( 1\right) </math>,<math>y^\left( 1\right)</math> ) ,...,(<math>x^\left( m\right)</math> ,<math>y^\left( m\right)</math> )},而批量梯度上升法的更新法则是:<math>\theta :=\theta +\alpha \nabla _{\theta }l\left( \theta \right) </math> ,这里的 <math>l\left( \theta \right) </math> 是对数似然函数,<math>\nabla _{\theta }l\left( \theta \right) </math> 是其导函数。<br />
<br />
[注:下文的符号规范与<公开课程视频>或<教学讲义CS229:机器学习>中的相同,详细内容可以参见公开课程视频或教学讲义#1 http://cs229.stanford.edu/]<br />
<br />
于是,我们需要如下计算梯度:<br />
<br />
:<math>\begin{align}<br />
\nabla_\theta \ell(\theta) = \sum_{i=1}^m \left(y^{(i)} - h_\theta(x^{(i)}) \right) x^{(i)}_j.<br />
\end{align}</math><br />
<br />
我们用Matlab/Octave风格变量x表示输入数据构成的样本矩阵,x(:,i)代表第 i个训练样本<math>x^{\left( i\right) }</math>,x(j,i)就代表<math>x_{j}^{\left( i\right) }</math>(译者注:第i个训练样本向量的第j个元素)。同样,用Matlab/Octave风格变量y表示由训练样本集合的全体类别标号所构成的行向量,则该向量的第i个元素y(i)就代表上式中的<math>y^{\left(i\right) }\in \left\{ 0,1\right\} </math>。(注意这里跟公开课程视频及CS229的符号规范不同,矩阵x按列而不是按行存放输入训练样本,同样,<math>y\in R^{1\times m}</math>是行向量而不是列向量。)<br />
<br />
<br />
以下是梯度运算代码的一种实现,非常恐怖,速度极慢:<br />
<br />
<syntaxhighlight lang="matlab"><br />
% 代码1<br />
grad = zeros(n+1,1);<br />
for i=1:m,<br />
h = sigmoid(theta'*x(:,i));<br />
temp = y(i) - h; <br />
for j=1:n+1,<br />
grad(j) = grad(j) + temp * x(j,i); <br />
end;<br />
end;<br />
</syntaxhighlight><br />
<br />
<br />
嵌套的for循环语句使这段代码的运行非常缓慢。以下是更典型的实现方式,它对算法进行部分向量化,带来更优的执行效率:<br />
<br />
<syntaxhighlight lang="matlab"><br />
% 代码2<br />
grad = zeros(n+1,1);<br />
for i=1:m,<br />
grad = grad + (y(i) - sigmoid(theta'*x(:,i)))* x(:,i);<br />
end;<br />
</syntaxhighlight><br />
<br />
<br />
但是,或许可以向量化得更彻底些。如果去除for循环,我们就可以显著地改善代码执行效率。特别的,假定b是一个列向量,A是一个矩阵,我们用以下两种方式来计算A*b:<br />
<br />
<syntaxhighlight lang="matlab"><br />
% 矩阵-向量乘法运算的低效代码<br />
grad = zeros(n+1,1);<br />
for i=1:m,<br />
grad = grad + b(i) * A(:,i); % 通常写法为A(:,i)*b(i)<br />
end;<br />
<br />
% 矩阵-向量乘法运算的高效代码<br />
grad = A*b;<br />
</syntaxhighlight><br />
<br />
<br />
我们看到,代码2是用了低效的for循环语句执行梯度上升(译者注:原文是下降)运算,将b(i)看成(y(i) - sigmoid(theta'*x(:,i))),A看成x,我们就可以使用以下高效率的代码:<br />
<br />
<syntaxhighlight lang="matlab"><br />
% 代码3<br />
grad = x * (y- sigmoid(theta'*x));<br />
</syntaxhighlight><br />
<br />
<br />
这里我们假定Matlab/Octave的sigmoid(z)函数接受一个向量形式的输入z,依次对输入向量的每个元素施行sigmoid函数,最后返回运算结果,因此sigmoid(z)的输出结果是一个与z有相同维度的向量。<br />
<br />
当训练数据集很大时,最终的实现(译者注:代码3)充分发挥了Matlab/Octave高度优化的数值线性代数库的优势来进行矩阵-向量操作,因此,比起之前代码要高效得多。<br />
<br />
想采用向量化实现并非易事,通常需要周密的思考。但当你熟练掌握向量化操作后,你会发现,这里面有固定的设计模式(对应少量的向量化技巧),可以灵活运用到很多不同的代码片段中。<br />
<br />
<br />
==中英文对照==<br />
<br />
:批量梯度上升法 batch gradient ascent<br />
:截距 intercept term<br />
:对数似然函数 the log likelihood<br />
:导函数 derivative<br />
:梯度 gradient<br />
<br />
==中文译者==<br />
<br />
林锋(xlfg@yeah.net),谭晓阳(x.tan@nuaa.edu.cn),邓亚峰(dengyafeng@gmail.com)<br />
<br />
<br />
{{矢量化编程实现}}<br />
<br />
<br />
{{Languages|Logistic_Regression_Vectorization_Example|English}}</div>
Kandeng
http://ufldl.stanford.edu/wiki/index.php/%E8%87%AA%E7%BC%96%E7%A0%81%E7%AE%97%E6%B3%95%E4%B8%8E%E7%A8%80%E7%96%8F%E6%80%A7
自编码算法与稀疏性
2013-04-08T07:46:37Z
<p>Kandeng: /* 中文译者 */</p>
<hr />
<div>目前为止,我们已经讨论了神经网络在有监督学习中的应用。在有监督学习中,训练样本是有类别标签的。现在假设我们只有一个没有带类别标签的训练样本集合 <math>\textstyle \{x^{(1)}, x^{(2)}, x^{(3)}, \ldots\}</math> ,其中 <math>\textstyle x^{(i)} \in \Re^{n}</math> 。自编码神经网络是一种无监督学习算法,它使用了反向传播算法,并让目标值等于输入值,比如 <math>\textstyle y^{(i)} = x^{(i)}</math> 。下图是一个自编码神经网络的示例。<br />
<br />
[[Image:Autoencoder636.png|400px|center]]<br />
<br />
<br />
<br />
自编码神经网络尝试学习一个 <math>\textstyle h_{W,b}(x) \approx x</math> 的函数。换句话说,它尝试逼近一个恒等函数,从而使得输出 <math>\textstyle \hat{x}</math> 接近于输入 <math>\textstyle x</math> 。恒等函数虽然看上去不太有学习的意义,但是当我们为自编码神经网络加入某些限制,比如限定隐藏神经元的数量,我们就可以从输入数据中发现一些有趣的结构。举例来说,假设某个自编码神经网络的输入 <math>\textstyle x</math> 是一张 <math>\textstyle 10 \times 10</math> 图像(共100个像素)的像素灰度值,于是 <math>\textstyle n=100</math> ,其隐藏层 <math>\textstyle L_2</math> 中有50个隐藏神经元。注意,输出也是100维的 <math>\textstyle y \in \Re^{100}</math> 。由于只有50个隐藏神经元,我们迫使自编码神经网络去学习输入数据的'''压缩'''表示,也就是说,它必须从50维的隐藏神经元激活度向量 <math>\textstyle a^{(2)} \in \Re^{50}</math> 中'''重构'''出100维的像素灰度值输入 <math>\textstyle x</math> 。如果网络的输入数据是完全随机的,比如每一个输入 <math>\textstyle x_i</math> 都是一个跟其它特征完全无关的独立同分布高斯随机变量,那么这一压缩表示将会非常难学习。但是如果输入数据中隐含着一些特定的结构,比如某些输入特征是彼此相关的,那么这一算法就可以发现输入数据中的这些相关性。事实上,这一简单的自编码神经网络通常可以学习出一个跟主元分析(PCA)结果非常相似的输入数据的低维表示。<br />
<br />
<br />
我们刚才的论述是基于隐藏神经元数量较小的假设。但是即使隐藏神经元的数量较大(可能比输入像素的个数还要多),我们仍然通过给自编码神经网络施加一些其他的限制条件来发现输入数据中的结构。具体来说,如果我们给隐藏神经元加入稀疏性限制,那么自编码神经网络即使在隐藏神经元数量较多的情况下仍然可以发现输入数据中一些有趣的结构。<br />
<br />
稀疏性可以被简单地解释如下。如果当神经元的输出接近于1的时候我们认为它被激活,而输出接近于0的时候认为它被抑制,那么使得神经元大部分的时间都是被抑制的限制则被称作稀疏性限制。这里我们假设的神经元的激活函数是sigmoid函数。如果你使用tanh作为激活函数的话,当神经元输出为-1的时候,我们认为神经元是被抑制的。<br />
<br />
注意到 <math>\textstyle a^{(2)}_j</math> 表示隐藏神经元 <math>\textstyle j</math> 的激活度,但是这一表示方法中并未明确指出哪一个输入 <math>\textstyle x</math> 带来了这一激活度。所以我们将使用 <math>\textstyle a^{(2)}_j(x)</math> 来表示在给定输入为 <math>\textstyle x</math> 情况下,自编码神经网络隐藏神经元 <math>\textstyle j</math> 的激活度。<br />
进一步,让<br />
:<math>\begin{align}<br />
\hat\rho_j = \frac{1}{m} \sum_{i=1}^m \left[ a^{(2)}_j(x^{(i)}) \right]<br />
\end{align}</math><br />
表示隐藏神经元 <math>\textstyle j</math> 的平均活跃度(在训练集上取平均)。我们可以近似的加入一条限制<br />
:<math>\begin{align}<br />
\hat\rho_j = \rho,<br />
\end{align}</math><br />
其中, <math>\textstyle \rho</math> 是'''稀疏性参数''',通常是一个接近于0的较小的值(比如 <math>\textstyle \rho = 0.05</math> )。换句话说,我们想要让隐藏神经元 <math>\textstyle j</math> 的平均活跃度接近0.05。为了满足这一条件,隐藏神经元的活跃度必须接近于0。<br />
<br />
为了实现这一限制,我们将会在我们的优化目标函数中加入一个额外的惩罚因子,而这一惩罚因子将惩罚那些 <math>\textstyle \hat\rho_j</math> 和 <math>\textstyle \rho</math> 有显著不同的情况从而使得隐藏神经元的平均活跃度保持在较小范围内。惩罚因子的具体形式有很多种合理的选择,我们将会选择以下这一种:<br />
:<math>\begin{align}<br />
\sum_{j=1}^{s_2} \rho \log \frac{\rho}{\hat\rho_j} + (1-\rho) \log \frac{1-\rho}{1-\hat\rho_j}.<br />
\end{align}</math><br />
这里, <math>\textstyle s_2</math> 是隐藏层中隐藏神经元的数量,而索引 <math>\textstyle j</math> 依次代表隐藏层中的每一个神经元。如果你对相对熵(KL divergence)比较熟悉,这一惩罚因子实际上是基于它的。于是惩罚因子也可以被表示为<br />
:<math>\begin{align}<br />
\sum_{j=1}^{s_2} {\rm KL}(\rho || \hat\rho_j),<br />
\end{align}</math><br />
其中 <math>\textstyle {\rm KL}(\rho || \hat\rho_j)<br />
= \rho \log \frac{\rho}{\hat\rho_j} + (1-\rho) \log \frac{1-\rho}{1-\hat\rho_j}</math> 是一个以 <math>\textstyle \rho</math> 为均值和一个以 <math>\textstyle \hat\rho_j</math> 为均值的两个伯努利随机变量之间的相对熵。相对熵是一种标准的用来测量两个分布之间差异的方法。(如果你没有见过相对熵,不用担心,所有你需要知道的内容都会被包含在这份笔记之中。)<br />
<br />
<br />
这一惩罚因子有如下性质,当 <math>\textstyle \hat\rho_j = \rho</math> 时 <math>\textstyle {\rm KL}(\rho || \hat\rho_j) = 0</math> ,并且随着 <math>\textstyle \hat\rho_j</math> 与 <math>\textstyle \rho</math> 之间的差异增大而单调递增。举例来说,在下图中,我们设定 <math>\textstyle \rho = 0.2</math> 并且画出了相对熵值 <math>\textstyle {\rm KL}(\rho || \hat\rho_j)</math> 随着 <math>\textstyle \hat\rho_j</math> 变化的变化。<br />
<br />
[[Image:KLPenaltyExample.png|400px|center]]<br />
<br />
<br />
我们可以看出,相对熵在 <math>\textstyle \hat\rho_j = \rho</math> 时达到它的最小值0,而当 <math>\textstyle \hat\rho_j</math> 靠近0或者1的时候,相对熵则变得非常大(其实是趋向于<math>\textstyle \infty</math>)。所以,最小化这一惩罚因子具有使得 <math>\textstyle \hat\rho_j</math> 靠近 <math>\textstyle \rho</math> 的效果。<br />
现在,我们的总体代价函数可以表示为<br />
:<math>\begin{align}<br />
J_{\rm sparse}(W,b) = J(W,b) + \beta \sum_{j=1}^{s_2} {\rm KL}(\rho || \hat\rho_j),<br />
\end{align}</math><br />
其中 <math>\textstyle J(W,b)</math> 如之前所定义,而 <math>\textstyle \beta</math> 控制稀疏性惩罚因子的权重。 <math>\textstyle \hat\rho_j</math> 项则也(间接地)取决于 <math>\textstyle W,b</math> ,因为它是隐藏神经元 <math>\textstyle j</math> 的平均激活度,而隐藏层神经元的激活度取决于 <math>\textstyle W,b</math> 。<br />
<br />
<br />
为了对相对熵进行导数计算,我们可以使用一个易于实现的技巧,这只需要在你的程序中稍作改动即可。具体来说,前面在后向传播算法中计算第二层( <math>\textstyle l=2</math> )更新的时候我们已经计算了<br />
:<math>\begin{align}<br />
\delta^{(2)}_i = \left( \sum_{j=1}^{s_{2}} W^{(2)}_{ji} \delta^{(3)}_j \right) f'(z^{(2)}_i),<br />
\end{align}</math><br />
现在我们将其换成<br />
:<math>\begin{align}<br />
\delta^{(2)}_i =<br />
\left( \left( \sum_{j=1}^{s_{2}} W^{(2)}_{ji} \delta^{(3)}_j \right)<br />
+ \beta \left( - \frac{\rho}{\hat\rho_i} + \frac{1-\rho}{1-\hat\rho_i} \right) \right) f'(z^{(2)}_i) .<br />
\end{align}</math><br />
就可以了。<br />
<br />
<br />
有一个需要注意的地方就是我们需要知道 <math>\textstyle \hat\rho_i</math> 来计算这一项更新。所以在计算任何神经元的后向传播之前,你需要对所有的训练样本计算一遍前向传播,从而获取平均激活度。如果你的训练样本可以小到被整个存到内存之中(对于编程作业来说,通常如此),你可以方便地在你所有的样本上计算前向传播并将得到的激活度存入内存并且计算平均激活度 。然后你就可以使用事先计算好的激活度来对所有的训练样本进行后向传播的计算。如果你的数据量太大,无法全部存入内存,你就可以扫过你的训练样本并计算一次前向传播,然后将获得的结果累积起来并计算平均激活度 <math>\textstyle \hat\rho_i</math> (当某一个前向传播的结果中的激活度 <math>\textstyle a^{(2)}_i</math> 被用于计算平均激活度 <math>\textstyle \hat\rho_i</math> 之后就可以将此结果删除)。然后当你完成平均激活度 <math>\textstyle \hat\rho_i</math> 的计算之后,你需要重新对每一个训练样本做一次前向传播从而可以对其进行后向传播的计算。对于后一种情况,你对每一个训练样本需要计算两次前向传播,所以在计算上的效率会稍低一些。<br />
<br />
证明上面算法能达到梯度下降效果的完整推导过程不再本教程的范围之内。不过如果你想要使用经过以上修改的后向传播来实现自编码神经网络,那么你就会对目标函数 <math>\textstyle J_{\rm sparse}(W,b)</math> 做梯度下降。使用梯度验证方法,你可以自己来验证梯度下降算法是否正确。。<br />
<br />
<br />
==中英文对照==<br />
<br />
:自编码算法 Autoencoders<br />
:稀疏性 Sparsity<br />
:神经网络 neural networks<br />
:监督学习 supervised learning<br />
:无监督学习 unsupervised learning<br />
:反向传播算法 backpropagation<br />
:隐藏神经元 hidden units<br />
:像素灰度值 the pixel intensity value<br />
:独立同分布 IID<br />
:主元分析 PCA<br />
:激活 active<br />
:抑制 inactive<br />
:激活函数 activation function<br />
:激活度 activation<br />
:平均活跃度 the average activation<br />
:稀疏性参数 sparsity parameter<br />
:惩罚因子 penalty term<br />
:相对熵 KL divergence<br />
:伯努利随机变量 Bernoulli random variable<br />
:总体代价函数 overall cost function<br />
:后向传播 backpropagation<br />
:前向传播 forward pass<br />
:梯度下降 gradient descent<br />
:目标函数 the objective<br />
:梯度验证方法 the derivative checking method<br />
<br />
==中文译者==<br />
<br />
周韬(ztsailing@gmail.com),葛燕儒(yrgehi@gmail.com),林锋(xlfg@yeah.net),余凯(kai.yu.cool@gmail.com)<br />
<br />
<br />
{{稀疏自编码器}}<br />
<br />
<br />
{{Languages|Autoencoders_and_Sparsity|English}}</div>
Kandeng
http://ufldl.stanford.edu/wiki/index.php/%E9%80%BB%E8%BE%91%E5%9B%9E%E5%BD%92%E7%9A%84%E5%90%91%E9%87%8F%E5%8C%96%E5%AE%9E%E7%8E%B0%E6%A0%B7%E4%BE%8B
逻辑回归的向量化实现样例
2013-04-08T05:25:37Z
<p>Kandeng: </p>
<hr />
<div>我们想用批量梯度上升法对logistic回归分析模型进行训练,其模型如下:<br />
<br />
:<math>\begin{align}<br />
h_\theta(x) = \frac{1}{1+\exp(-\theta^Tx)},<br />
\end{align}</math><br />
<br />
让我们遵从公开课程视频与CS229教学讲义的符号规范,设 <math>\textstyle x_0=1</math>,于是<math>x\in R^{n+1}</math> ,<math>\theta \in R^{n+1}</math>, <math>\textstyle \theta_0</math> 为截距。假设我们有m个训练样本{(<math>x^\left( 1\right) </math>,<math>y^\left( 1\right)</math> ) ,...,(<math>x^\left( m\right)</math> ,<math>y^\left( m\right)</math> )},而批量梯度上升法的更新法则是:<math>\theta :=\theta +\alpha \nabla _{\theta }l\left( \theta \right) </math> ,这里的 <math>l\left( \theta \right) </math> 是对数似然函数,<math>\nabla _{\theta }l\left( \theta \right) </math> 是其导函数。<br />
<br />
[注:下文的符号规范与<公开课程视频>或<教学讲义CS229:机器学习>中的相同,详细内容可以参见公开课程视频或教学讲义#1 http://cs229.stanford.edu/]<br />
<br />
于是,我们需要如下计算梯度:<br />
<br />
:<math>\begin{align}<br />
\nabla_\theta \ell(\theta) = \sum_{i=1}^m \left(y^{(i)} - h_\theta(x^{(i)}) \right) x^{(i)}_j.<br />
\end{align}</math><br />
<br />
我们用Matlab/Octave风格变量x表示输入数据构成的样本矩阵,x(:,i)代表第 i个训练样本<math>x^{\left( i\right) }</math>,x(j,i)就代表<math>x_{j}^{\left( i\right) }</math>(译者注:第i个训练样本向量的第j个元素)。同样,用Matlab/Octave风格变量y表示由训练样本集合的全体类别标号所构成的行向量,则该向量的第i个元素y(i)就代表上式中的<math>y^{\left(i\right) }\in \left\{ 0,1\right\} </math>。(注意这里跟公开课程视频及CS229的符号规范不同,矩阵x按列而不是按行存放输入训练样本,同样,<math>y\in R^{1\times m}</math>是行向量而不是列向量。)<br />
<br />
<br />
以下是梯度运算代码的一种实现,非常恐怖,速度极慢:<br />
<br />
<syntaxhighlight lang="matlab"><br />
% 代码1<br />
grad = zeros(n+1,1);<br />
for i=1:m,<br />
h = sigmoid(theta'*x(:,i));<br />
temp = y(i) - h; <br />
for j=1:n+1,<br />
grad(j) = grad(j) + temp * x(j,i); <br />
end;<br />
end;<br />
</syntaxhighlight><br />
<br />
<br />
嵌套的for循环语句使这段代码的运行非常缓慢。以下是更典型的实现方式,它对算法进行部分向量化,带来更优的执行效率:<br />
<br />
<syntaxhighlight lang="matlab"><br />
% 代码2<br />
grad = zeros(n+1,1);<br />
for i=1:m,<br />
grad = grad + (y(i) - sigmoid(theta'*x(:,i)))* x(:,i);<br />
end;<br />
</syntaxhighlight><br />
<br />
<br />
但是,或许可以向量化得更彻底些。如果去除for循环,我们就可以显著地改善代码执行效率。特别的,假定b是一个列向量,A是一个矩阵,我们用以下两种方式来计算A*b:<br />
<br />
<syntaxhighlight lang="matlab"><br />
% 矩阵-向量乘法运算的低效代码<br />
grad = zeros(n+1,1);<br />
for i=1:m,<br />
grad = grad + b(i) * A(:,i); % 通常写法为A(:,i)*b(i)<br />
end;<br />
<br />
% 矩阵-向量乘法运算的高效代码<br />
grad = A*b;<br />
</syntaxhighlight><br />
<br />
<br />
我们看到,代码2是用了低效的for循环语句执行梯度上升(译者注:原文是下降)运算,将b(i)看成(y(i) - sigmoid(theta'*x(:,i))),A看成x,我们就可以使用以下高效率的代码:<br />
<br />
<syntaxhighlight lang="matlab"><br />
% 代码3<br />
grad = x * (y- sigmoid(theta'*x));<br />
</syntaxhighlight><br />
<br />
<br />
这里我们假定Matlab/Octave的sigmoid(z)函数接受一个向量形式的输入z,依次对输入向量的每个元素施行sigmoid函数,最后返回运算结果,因此sigmoid(z)的输出结果是一个与z有相同维度的向量。<br />
<br />
当训练数据集很大时,最终的实现(译者注:代码3)充分发挥了Matlab/Octave高度优化的数值线性代数库的优势来进行矩阵-向量操作,因此,比起之前代码要高效得多。<br />
<br />
想采用向量化实现并非易事,通常需要周密的思考。但当你熟练掌握向量化操作后,你会发现,这里面有固定的设计模式(对应少量的向量化技巧),可以灵活运用到很多不同的代码片段中。<br />
<br />
<br />
==中英文对照==<br />
<br />
<br />
<br />
==中文译者==<br />
<br />
林锋(xlfg@yeah.net),谭晓阳(x.tan@nuaa.edu.cn),邓亚峰(dengyafeng@gmail.com)<br />
<br />
<br />
{{矢量化编程实现}}<br />
<br />
<br />
{{Languages|Logistic_Regression_Vectorization_Example|English}}</div>
Kandeng
http://ufldl.stanford.edu/wiki/index.php/%E5%8F%AF%E8%A7%86%E5%8C%96%E8%87%AA%E7%BC%96%E7%A0%81%E5%99%A8%E8%AE%AD%E7%BB%83%E7%BB%93%E6%9E%9C
可视化自编码器训练结果
2013-04-08T05:24:07Z
<p>Kandeng: </p>
<hr />
<div>训练完(稀疏)自编码器,我们还想把这自编码器学到的函数可视化出来,好弄明白它到底学到了什么。我们以在10×10图像(即n=100)上训练自编码器为例。在该自编码器中,每个隐藏单元i对如下关于输入的函数进行计算:<br />
:<math>\begin{align}<br />
a^{(2)}_i = f\left(\sum_{j=1}^{100} W^{(1)}_{ij} x_j + b^{(1)}_i \right).<br />
\end{align}</math><br />
<!-- This is the activation function <math>\textstyle g(\cdot)</math> applied to an affine function of the input.!--><br />
<br />
我们将要可视化的函数,就是上面这个以2D图像为输入、并由隐藏单元i计算出来的函数。它是依赖于参数<math>\textstyle W^{(1)}_{ij}</math>的(暂时忽略偏置项<math>b_i</math>)。需要注意的是,<math>\textstyle a^{(2)}_i</math>可看作输入<math>\textstyle x</math>的非线性特征。不过还有个问题:什么样的输入图像<math>\textstyle x</math>可让<math>\textstyle a^{(2)}_i</math>得到最大程度的激励?(通俗一点说,隐藏单元<math>\textstyle i</math>要找个什么样的特征?)。这里我们必须给<math>\textstyle x</math>加约束,否则会得到平凡解。若假设输入有范数约束<math>\textstyle ||x||^2 = \sum_{i=1}^{100} x_i^2 \leq 1</math>,则可证(请读者自行推导)令隐藏单元<math>\textstyle i</math>得到最大激励的输入应由下面公式计算的像素<math>\textstyle x_j</math>给出(共需计算100个像素,j=1,…,100):<br />
:<math>\begin{align}<br />
x_j = \frac{W^{(1)}_{ij}}{\sqrt{\sum_{j=1}^{100} (W^{(1)}_{ij})^2}}.<br />
\end{align}</math><br />
<br />
当我们用上式算出各像素的值、把它们组成一幅图像、并将图像呈现在我们面前之时,隐藏单元<math>\textstyle i</math>所追寻特征的真正含义也渐渐明朗起来。<br />
<br />
假如我们训练的自编码器有100个隐藏单元,可视化结果就会包含100幅这样的图像——每个隐藏单元都对应一幅图像。审视这100幅图像,我们可以试着体会这些隐藏单元学出来的整体效果是什么样的。<br />
<br />
<br />
当我们对稀疏自编码器(100个隐藏单元,在10X10像素的输入上训练 )进行上述可视化处理之后,结果如下所示:<br />
<br />
[[Image:ExampleSparseAutoencoderWeights.png|thumb|400px|center]]<br />
<br />
上图的每个小方块都给出了一个(带有有界范数 的)输入图像<math>\textstyle x</math>,它可使这100个隐藏单元中的某一个获得最大激励。我们可以看到,不同的隐藏单元学会了在图像的不同位置和方向进行边缘检测。<br />
<br />
显而易见,这些特征对物体识别等计算机视觉任务是十分有用的。若将其用于其他输入域(如音频),该算法也可学到对这些输入域有用的表示或特征。<br />
<br />
<br />
==中英文对照==<br />
<br />
<br />
<br />
==中文译者==<br />
<br />
王方(fangkey@gmail.com),胡伦(hulun499@gmail.com),谢宇(msforbus@sina.com),@小琳爱肉肉(新浪微博账号), 余凯(kai.yu.cool@gmail.com)<br />
<br />
<br />
<br />
{{Languages|Visualizing_a_Trained_Autoencoder|English}}</div>
Kandeng
http://ufldl.stanford.edu/wiki/index.php/%E7%8B%AC%E7%AB%8B%E6%88%90%E5%88%86%E5%88%86%E6%9E%90
独立成分分析
2013-04-08T04:37:34Z
<p>Kandeng: </p>
<hr />
<div>== 概述 ==<br />
<br />
试着回想一下,在介绍[[Sparse Coding | 稀疏编码算法]]中我们想为样本数据学习得到一个超完备基(over-complete basis)。具体来说,这意味着用稀疏编码学习得到的基向量之间不一定线性独立。尽管在某些情况下这已经满足需要,但有时我们仍然希望得到的是一组线性独立基。独立成分分析算法(ICA)正实现了这一点。而且,在 ICA 中,我们希望学习到的基不仅要线性独立,而且还是一组标准正交基。(一组标准正交基 <math>(\phi_1, \ldots \phi_n)</math> 需要满足条件:<math>\phi_i \cdot \phi_j = 0</math>(如果 <math>i \ne j</math>)或者 <math>\phi_i \cdot \phi_j = 1</math>(如果 <math>i = j</math>))<br />
<br />
<br />
与稀疏编码算法类似,独立成分分析也有一个简单的数学形式。给定数据 x,我们希望学习得到一组基向量――以列向量形式构成的矩阵 <math>W</math>,其满足以下特点:首先,与稀疏编码一样,特征是稀疏的;其次,基是标准正交的(注意,在稀疏编码中,矩阵 <math>A</math> 用于将特征 <math>s</math> 映射到原始数据,而在独立成分分析中,矩阵 <math>W</math> 工作的方向相反,是将原始数据 <math>x</math> 映射到特征)。这样我们得到以下目标函数:<br />
<br />
:<math><br />
J(W) = \lVert Wx \rVert_1 <br />
</math><br />
<br />
<br />
由于 <math>Wx</math> 实际上是描述样本数据的特征,这个目标函数等价于在稀疏编码中特征 <math>s</math> 的稀疏惩罚项。加入标准正交性约束后,独立成分分析相当于求解如下优化问题:<br />
<br />
:<math><br />
\begin{array}{rcl}<br />
{\rm minimize} & \lVert Wx \rVert_1 \\<br />
{\rm s.t.} & WW^T = I \\<br />
\end{array} <br />
</math><br />
<br />
<br />
与深度学习中的通常情况一样,这个问题没有简单的解析解,而且更糟糕的是,由于标准正交性约束,使得用梯度下降方法来求解该问题变得更加困难――每次梯度下降迭代之后,必须将新的基映射回正交基空间中(以此保证正交性约束)。<br />
<br />
<br />
实践中,在最优化目标函数的同时施加正交性约束(如下一节[[Independent Component Analysis#Orthonormal ICA | 正交ICA]]中讲到的)是可行的,但是速度慢。在标准正交基是不可或缺的情况下,标准正交ICA的使用会受到一些限制。(哪些情况见:[[TODO]] )<br />
<br />
<br />
== 标准正交ICA ==<br />
<br />
标准正交ICA的目标函数是:<br />
<br />
:<math><br />
\begin{array}{rcl}<br />
{\rm minimize} & \lVert Wx \rVert_1 \\<br />
{\rm s.t.} & WW^T = I \\<br />
\end{array} <br />
</math><br />
<br />
<br />
通过观察可知,约束<math>WW^T = I</math>隐含着另外两个约束:<br />
<br />
<br />
第一,因为要学习到一组标准正交基,所以基向量的个数必须小于输入数据的维度。具体来说,这意味着不能像通常在[[Sparse Coding: Autoencoder Interpretation | 稀疏编码]]中所做的那样来学习得到超完备基(over-complete bases)。<br />
<br />
第二,数据必须经过无正则[[Whitening | ZCA白化]](也即,<math>\epsilon</math>设为0)。(为什么必须这样做?见[[TODO]])<br />
<br />
<br />
因此,在优化标准正交ICA目标函数之前,必须确保数据被白化过,并且学习的是一组不完备基(under-complete basis)。<br />
<br />
<br />
然后,为了优化目标函数,我们可以使用梯度下降法,在梯度下降的每一步中增加投影步骤,以满足标准正交约束。过程如下:<br />
<br />
<br />
重复以下步骤直到完成:<br />
<ol><br />
<li><math>W \leftarrow W - \alpha \nabla_W \lVert Wx \rVert_1</math><br />
<li><math>W \leftarrow \operatorname{proj}_U W</math>, 其中<math>U</math>是满足<math>WW^T = I</math>的矩阵空间<br />
</ol><br />
<br />
<br />
在实际中,学习速率<math>\alpha</math>是可变的,使用一个线搜索算法来加速梯度.投影步骤通过设置<math>W \leftarrow (WW^T)^{-\frac{1}{2}} W</math>来完成,这实际上可以看成就是ZCA白化([[TODO]]:解释为什么这就象ZCA白化).<br />
<br />
<br />
<br />
== 拓扑ICA ==<br />
<br />
<br />
与[[Sparse Coding: Autoencoder Interpretation | 稀疏编码算法]]类似,加上一个拓扑代价项,独立成分分析法可以修改成具有拓扑性质的算法。<br />
<br />
<br />
<br />
==中英文对照==<br />
<br />
:独立成分分析 Independent Component Analysis <br />
:稀疏编码算法 Sparse coding <br />
:超完备基 Over-complete basis <br />
:标准正交基 Orthonormal basis <br />
:稀疏惩罚项 Sparsity penalty <br />
:梯度下降法 Gradient descent <br />
:白化 Whitened <br />
:不完备基 Under-complete basis <br />
:线搜索算法 Line-search algorithm <br />
:拓扑代价项 Topographic cost term <br />
<br />
<br />
<br />
==中文译者==<br />
<br />
袁贞明(zmyuan@hznu.edu.cn),晓风(xiaofeng.zhb@alibaba-inc.com), 林锋(xlfg@yeah.net)<br />
<br />
<br />
{{Languages|Independent_Component_Analysis|English}}</div>
Kandeng
http://ufldl.stanford.edu/wiki/index.php/%E7%8B%AC%E7%AB%8B%E6%88%90%E5%88%86%E5%88%86%E6%9E%90
独立成分分析
2013-04-08T04:36:54Z
<p>Kandeng: </p>
<hr />
<div>== 概述 ==<br />
<br />
试着回想一下,在介绍[[Sparse Coding | 稀疏编码算法]]中我们想为样本数据学习得到一个超完备基(over-complete basis)。具体来说,这意味着用稀疏编码学习得到的基向量之间不一定线性独立。尽管在某些情况下这已经满足需要,但有时我们仍然希望得到的是一组线性独立基。独立成分分析算法(ICA)正实现了这一点。而且,在 ICA 中,我们希望学习到的基不仅要线性独立,而且还是一组标准正交基。(一组标准正交基 <math>(\phi_1, \ldots \phi_n)</math> 需要满足条件:<math>\phi_i \cdot \phi_j = 0</math>(如果 <math>i \ne j</math>)或者 <math>\phi_i \cdot \phi_j = 1</math>(如果 <math>i = j</math>))<br />
<br />
<br />
与稀疏编码算法类似,独立成分分析也有一个简单的数学形式。给定数据 x,我们希望学习得到一组基向量――以列向量形式构成的矩阵 <math>W</math>,其满足以下特点:首先,与稀疏编码一样,特征是稀疏的;其次,基是标准正交的(注意,在稀疏编码中,矩阵 <math>A</math> 用于将特征 <math>s</math> 映射到原始数据,而在独立成分分析中,矩阵 <math>W</math> 工作的方向相反,是将原始数据 <math>x</math> 映射到特征)。这样我们得到以下目标函数:<br />
<br />
:<math><br />
J(W) = \lVert Wx \rVert_1 <br />
</math><br />
<br />
<br />
由于 <math>Wx</math> 实际上是描述样本数据的特征,这个目标函数等价于在稀疏编码中特征 <math>s</math> 的稀疏惩罚项。加入标准正交性约束后,独立成分分析相当于求解如下优化问题:<br />
<br />
:<math><br />
\begin{array}{rcl}<br />
{\rm minimize} & \lVert Wx \rVert_1 \\<br />
{\rm s.t.} & WW^T = I \\<br />
\end{array} <br />
</math><br />
<br />
<br />
与深度学习中的通常情况一样,这个问题没有简单的解析解,而且更糟糕的是,由于标准正交性约束,使得用梯度下降方法来求解该问题变得更加困难――每次梯度下降迭代之后,必须将新的基映射回正交基空间中(以此保证正交性约束)。<br />
<br />
<br />
实践中,在最优化目标函数的同时施加正交性约束(如下一节[[Independent Component Analysis#Orthonormal ICA | 正交ICA]]中讲到的)是可行的,但是速度慢。在标准正交基是不可或缺的情况下,标准正交ICA的使用会受到一些限制。(哪些情况见:[[TODO]] )<br />
<br />
<br />
== 标准正交ICA ==<br />
<br />
标准正交ICA的目标函数是:<br />
<br />
:<math><br />
\begin{array}{rcl}<br />
{\rm minimize} & \lVert Wx \rVert_1 \\<br />
{\rm s.t.} & WW^T = I \\<br />
\end{array} <br />
</math><br />
<br />
<br />
通过观察可知,约束<math>WW^T = I</math>隐含着另外两个约束:<br />
<br />
<br />
第一,因为要学习到一组标准正交基,所以基向量的个数必须小于输入数据的维度。具体来说,这意味着不能像通常在[[Sparse Coding: Autoencoder Interpretation | 稀疏编码]]中所做的那样来学习得到超完备基(over-complete bases)。<br />
<br />
第二,数据必须经过无正则[[Whitening | ZCA白化]](也即,<math>\epsilon</math>设为0)。(为什么必须这样做?见[[TODO]])<br />
<br />
<br />
因此,在优化标准正交ICA目标函数之前,必须确保数据被白化过,并且学习的是一组不完备基(under-complete basis)。<br />
<br />
<br />
然后,为了优化目标函数,我们可以使用梯度下降法,在梯度下降的每一步中增加投影步骤,以满足标准正交约束。过程如下:<br />
<br />
<br />
重复以下步骤直到完成:<br />
<ol><br />
<li><math>W \leftarrow W - \alpha \nabla_W \lVert Wx \rVert_1</math><br />
<li><math>W \leftarrow \operatorname{proj}_U W</math>, 其中<math>U</math>是满足<math>WW^T = I</math>的矩阵空间<br />
</ol><br />
<br />
<br />
在实际中,学习速率<math>\alpha</math>是可变的,使用一个线搜索算法来加速梯度.投影步骤通过设置<math>W \leftarrow (WW^T)^{-\frac{1}{2}} W</math>来完成,这实际上可以看成就是ZCA白化([[TODO]]:解释为什么这就象ZCA白化).<br />
<br />
<br />
<br />
== 拓扑ICA ==<br />
<br />
<br />
与[[Sparse Coding: Autoencoder Interpretation | 稀疏编码算法]]类似,加上一个拓扑代价项,独立成分分析法可以修改成具有拓扑性质的算法。<br />
<br />
<br />
<br />
==中英文对照==<br />
<br />
:独立成分分析 Independent Component Analysis <br />
:稀疏编码算法 Sparse coding <br />
:超完备基 Over-complete basis <br />
:标准正交基 Orthonormal basis <br />
:稀疏惩罚项 Sparsity penalty <br />
:梯度下降法 Gradient descent <br />
:白化 Whitened <br />
:不完备基 Under-complete basis <br />
:线搜索算法 Line-search algorithm <br />
:拓扑代价项 Topographic cost term <br />
<br />
<br />
<br />
==中文译者==<br />
<br />
袁贞明(zmyuan@hznu.edu.cn),晓风(xiaofeng.zhb@alibaba-inc.com), 林锋(xlfg@yeah.net)<br />
<br />
<br />
{{Languages|Independent_Component_Analysis|English}}</div>
Kandeng
http://ufldl.stanford.edu/wiki/index.php/Independent_Component_Analysis
Independent Component Analysis
2013-04-08T04:35:10Z
<p>Kandeng: </p>
<hr />
<div>== Introduction ==<br />
<br />
If you recall, in [[Sparse Coding | sparse coding]], we wanted to learn an '''over-complete''' basis for the data. In particular, this implies that the basis vectors that we learn in sparse coding will not be linearly independent. While this may be desirable in certain situations, sometimes we want to learn a linearly independent basis for the data. In independent component analysis (ICA), this is exactly what we want to do. Further, in ICA, we want to learn not just any linearly independent basis, but an '''orthonormal''' basis for the data. (An orthonormal basis is a basis <math>(\phi_1, \ldots \phi_n)</math> such that <math>\phi_i \cdot \phi_j = 0</math> if <math>i \ne j</math> and <math>1</math> if <math>i = j</math>).<br />
<br />
Like sparse coding, independent component analysis has a simple mathematical formulation. Given some data <math>x</math>, we would like to learn a set of basis vectors which we represent in the columns of a matrix <math>W</math>, such that, firstly, as in sparse coding, our features are '''sparse'''; and secondly, our basis is an '''orthonormal''' basis. (Note that while in sparse coding, our matrix <math>A</math> was for mapping '''features''' <math>s</math> to '''raw data''', in independent component analysis, our matrix <math>W</math> works in the opposite direction, mapping '''raw data''' <math>x</math> to '''features''' instead). This gives us the following objective function:<br />
<br />
:<math><br />
J(W) = \lVert Wx \rVert_1 <br />
</math><br />
<br />
This objective function is equivalent to the sparsity penalty on the features <math>s</math> in sparse coding, since <math>Wx</math> is precisely the features that represent the data. Adding in the orthonormality constraint gives us the full optimization problem for independent component analysis:<br />
<br />
:<math><br />
\begin{array}{rcl}<br />
{\rm minimize} & \lVert Wx \rVert_1 \\<br />
{\rm s.t.} & WW^T = I \\<br />
\end{array} <br />
</math><br />
<br />
As is usually the case in deep learning, this problem has no simple analytic solution, and to make matters worse, the orthonormality constraint makes it slightly more difficult to optimize for the objective using gradient descent - every iteration of gradient descent must be followed by a step that maps the new basis back to the space of orthonormal bases (hence enforcing the constraint). <br />
<br />
In practice, optimizing for the objective function while enforcing the orthonormality constraint (as described in [[Independent Component Analysis#Orthonormal ICA | Orthonormal ICA]] section below) is feasible but slow. Hence, the use of orthonormal ICA is limited to situations where it is important to obtain an orthonormal basis ([[TODO]]: what situations) .<br />
<br />
== Orthonormal ICA ==<br />
<br />
The orthonormal ICA objective is:<br />
:<math><br />
\begin{array}{rcl}<br />
{\rm minimize} & \lVert Wx \rVert_1 \\<br />
{\rm s.t.} & WW^T = I \\<br />
\end{array} <br />
</math><br />
<br />
Observe that the constraint <math>WW^T = I</math> implies two other constraints. <br />
<br />
Firstly, since we are learning an orthonormal basis, the number of basis vectors we learn must be less than the dimension of the input. In particular, this means that we cannot learn over-complete bases as we usually do in [[Sparse Coding: Autoencoder Interpretation | sparse coding]]. <br />
<br />
Secondly, the data must be [[Whitening | ZCA whitened]] with no regularization (that is, with <math>\epsilon</math> set to 0). ([[TODO]] Why must this be so?)<br />
<br />
Hence, before we even begin to optimize for the orthonormal ICA objective, we must ensure that our data has been '''whitened''', and that we are learning an '''under-complete''' basis. <br />
<br />
Following that, to optimize for the objective, we can use gradient descent, interspersing gradient descent steps with projection steps to enforce the orthonormality constraint. Hence, the procedure will be as follows:<br />
<br />
Repeat until done:<br />
<ol><br />
<li><math>W \leftarrow W - \alpha \nabla_W \lVert Wx \rVert_1</math><br />
<li><math>W \leftarrow \operatorname{proj}_U W</math> where <math>U</math> is the space of matrices satisfying <math>WW^T = I</math><br />
</ol><br />
<br />
In practice, the learning rate <math>\alpha</math> is varied using a line-search algorithm to speed up the descent, and the projection step is achieved by setting <math>W \leftarrow (WW^T)^{-\frac{1}{2}} W</math>, which can actually be seen as ZCA whitening ([[TODO]] explain how it is like ZCA whitening).<br />
<br />
== Topographic ICA ==<br />
<br />
Just like [[Sparse Coding: Autoencoder Interpretation | sparse coding]], independent component analysis can be modified to give a topographic variant by adding a topographic cost term.<br />
<br />
<br />
{{Languages|独立成分分析|中文}}</div>
Kandeng
http://ufldl.stanford.edu/wiki/index.php/%E7%8B%AC%E7%AB%8B%E6%88%90%E5%88%86%E5%88%86%E6%9E%90
独立成分分析
2013-04-08T04:34:33Z
<p>Kandeng: </p>
<hr />
<div>== 概述 ==<br />
<br />
试着回想一下,在介绍[[Sparse Coding | 稀疏编码算法]]中我们想为样本数据学习得到一个超完备基(over-complete basis)。具体来说,这意味着用稀疏编码学习得到的基向量之间不一定线性独立。尽管在某些情况下这已经满足需要,但有时我们仍然希望得到的是一组线性独立基。独立成分分析算法(ICA)正实现了这一点。而且,在 ICA 中,我们希望学习到的基不仅要线性独立,而且还是一组标准正交基。(一组标准正交基 <math>(\phi_1, \ldots \phi_n)</math> 需要满足条件:<math>\phi_i \cdot \phi_j = 0</math>(如果 <math>i \ne j</math>)或者 <math>\phi_i \cdot \phi_j = 1</math>(如果 <math>i = j</math>))<br />
<br />
<br />
与稀疏编码算法类似,独立成分分析也有一个简单的数学形式。给定数据 x,我们希望学习得到一组基向量――以列向量形式构成的矩阵 <math>W</math>,其满足以下特点:首先,与稀疏编码一样,特征是稀疏的;其次,基是标准正交的(注意,在稀疏编码中,矩阵 <math>A</math> 用于将特征 <math>s</math> 映射到原始数据,而在独立成分分析中,矩阵 <math>W</math> 工作的方向相反,是将原始数据 <math>x</math> 映射到特征)。这样我们得到以下目标函数:<br />
<br />
:<math><br />
J(W) = \lVert Wx \rVert_1 <br />
</math><br />
<br />
<br />
由于 <math>Wx</math> 实际上是描述样本数据的特征,这个目标函数等价于在稀疏编码中特征 <math>s</math> 的稀疏惩罚项。加入标准正交性约束后,独立成分分析相当于求解如下优化问题:<br />
<br />
:<math><br />
\begin{array}{rcl}<br />
{\rm minimize} & \lVert Wx \rVert_1 \\<br />
{\rm s.t.} & WW^T = I \\<br />
\end{array} <br />
</math><br />
<br />
<br />
与深度学习中的通常情况一样,这个问题没有简单的解析解,而且更糟糕的是,由于标准正交性约束,使得用梯度下降方法来求解该问题变得更加困难――每次梯度下降迭代之后,必须将新的基映射回正交基空间中(以此保证正交性约束)。<br />
<br />
<br />
实践中,在最优化目标函数的同时施加正交性约束(如下一节[[Independent Component Analysis#Orthonormal ICA | 正交ICA]]中讲到的)是可行的,但是速度慢。在标准正交基是不可或缺的情况下,标准正交ICA的使用会受到一些限制。(哪些情况见:[[TODO]] )<br />
<br />
<br />
== 标准正交ICA ==<br />
<br />
标准正交ICA的目标函数是:<br />
<br />
:<math><br />
\begin{array}{rcl}<br />
{\rm minimize} & \lVert Wx \rVert_1 \\<br />
{\rm s.t.} & WW^T = I \\<br />
\end{array} <br />
</math><br />
<br />
<br />
通过观察可知,约束<math>WW^T = I</math>隐含着另外两个约束:<br />
<br />
<br />
第一,因为要学习到一组标准正交基,所以基向量的个数必须小于输入数据的维度。具体来说,这意味着不能像通常在[[Sparse Coding: Autoencoder Interpretation | 稀疏编码]]中所做的那样来学习得到超完备基(over-complete bases)。<br />
<br />
第二,数据必须经过无正则[[Whitening | ZCA白化]](也即,<math>\epsilon</math>设为0)。(为什么必须这样做?见[[TODO]])<br />
<br />
<br />
因此,在优化标准正交ICA目标函数之前,必须确保数据被白化过,并且学习的是一组不完备基(under-complete basis)。<br />
<br />
<br />
然后,为了优化目标函数,我们可以使用梯度下降法,在梯度下降的每一步中增加投影步骤,以满足标准正交约束。过程如下:<br />
<br />
<br />
重复以下步骤直到完成:<br />
<ol><br />
<li><math>W \leftarrow W - \alpha \nabla_W \lVert Wx \rVert_1</math><br />
<li><math>W \leftarrow \operatorname{proj}_U W</math>, 其中<math>U</math>是满足<math>WW^T = I</math>的矩阵空间<br />
</ol><br />
<br />
<br />
在实际中,学习速率<math>\alpha</math>是可变的,使用一个线搜索算法来加速梯度.投影步骤通过设置<math>W \leftarrow (WW^T)^{-\frac{1}{2}} W</math>来完成,这实际上可以看成就是ZCA白化([[TODO]]:解释为什么这就象ZCA白化).<br />
<br />
<br />
<br />
== 拓扑ICA ==<br />
<br />
<br />
与[[Sparse Coding: Autoencoder Interpretation | 稀疏编码算法]]类似,加上一个拓扑代价项,独立成分分析法可以修改成具有拓扑性质的算法。<br />
<br />
<br />
<br />
==中英文对照==<br />
<br />
:Independent Component Analysis 独立成分分析<br />
:sparse coding 稀疏编码算法<br />
:over-complete basis 超完备基<br />
:orthonormal basis 标准正交基<br />
:sparsity penalty 稀疏惩罚项<br />
:gradient descent 梯度下降法<br />
:whitened 白化<br />
:under-complete basis 不完备基<br />
:line-search algorithm 线搜索算法<br />
:topographic cost term 拓扑代价项<br />
<br />
<br />
<br />
==中文译者==<br />
<br />
袁贞明(zmyuan@hznu.edu.cn),晓风(xiaofeng.zhb@alibaba-inc.com), 林锋(xlfg@yeah.net)<br />
<br />
<br />
{{Languages|Independent_Component_Analysis|English}}</div>
Kandeng
http://ufldl.stanford.edu/wiki/index.php/Sparse_Coding:_Autoencoder_Interpretation
Sparse Coding: Autoencoder Interpretation
2013-04-08T04:33:12Z
<p>Kandeng: </p>
<hr />
<div>== Sparse coding ==<br />
<br />
In the sparse autoencoder, we tried to learn a set of weights <math>W</math> (and associated biases <math>b</math>) that would give us sparse features <math>\sigma(Wx + b)</math> useful in reconstructing the input <math>x</math>. <br />
<br />
[[File:STL_SparseAE.png | 240px]]<br />
<br />
Sparse coding can be seen as a modification of the sparse autoencoder method in which we try to learn the set of features for some data "directly". Together with an associated basis for transforming the learned features from the feature space to the data space, we can then reconstruct the data from the learned features.<br />
<br />
Formally, in sparse coding, we have some data <math>x</math> we would like to learn features on. In particular, we would like to learn <math>s</math>, a set of sparse features useful for representing the data, and <math>A</math>, a basis for transforming the features from the feature space to the data space. Our objective function is hence:<br />
<br />
:<math><br />
J(A, s) = \lVert As - x \rVert_2^2 + \lambda \lVert s \rVert_1<br />
</math><br />
<br />
(If you are unfamiliar with the notation, <math>\lVert x \rVert_k</math> refers to the L<math>k</math> norm of the <math>x</math> which is equal to <math>\left( \sum{ \left| x_i^k \right| } \right) ^{\frac{1}{k}}</math>. The L2 norm is the familiar Euclidean norm, while the L1 norm is the sum of absolute values of the elements of the vector)<br />
<br />
The first term is the error in reconstructing the data from the features using the basis, and the second term is a sparsity penalty term to encourage the learned features to be sparse. <br />
<br />
However, the objective function as it stands is not properly constrained - it is possible to reduce the sparsity cost (the second term) by scaling <math>A</math> by some constant and scaling <math>s</math> by the inverse of the same constant, without changing the error. Hence, we include the additional constraint that that for every column <math>A_j</math> of <math>A</math>, <br />
<math>A_j^TA_j \le 1</math>. Our problem is thus:<br />
<br />
:<math><br />
\begin{array}{rcl}<br />
{\rm minimize} & \lVert As - x \rVert_2^2 + \lambda \lVert s \rVert_1 \\<br />
{\rm s.t.} & A_j^TA_j \le 1 \; \forall j \\<br />
\end{array} <br />
</math><br />
<br />
Unfortunately, the objective function is non-convex, and hence impossible to optimize well using gradient-based methods. However, given <math>A</math>, the problem of finding <math>s</math> that minimizes <math>J(A, s)</math> is convex. Similarly, given <math>s</math>, the problem of finding <math>A</math> that minimizes <math>J(A, s)</math> is also convex. This suggests that we might try alternately optimizing for <math>A</math> for a fixed <math>s</math>, and then optimizing for <math>s</math> given a fixed <math>A</math>. It turns out that this works quite well in practice.<br />
<br />
However, the form of our problem presents another difficulty - the constraint that <math>A_j^TA_j \le 1 \; \forall j</math> cannot be enforced using simple gradient-based methods. Hence, in practice, this constraint is weakened to a "weight decay" term designed to keep the entries of <math>A</math> small. This gives us a new objective function:<br />
<br />
:<math><br />
J(A, s) = \lVert As - x \rVert_2^2 + \lambda \lVert s \rVert_1 + \gamma \lVert A \rVert_2^2<br />
</math><br />
<br />
(note that the third term, <math>\lVert A \rVert_2^2</math> is simply the sum of squares of the entries of A, or <math>\sum_r{\sum_c{A_{rc}^2}}</math>)<br />
<br />
This objective function presents one last problem - the L1 norm is not differentiable at 0, and hence poses a problem for gradient-based methods. While the problem can be solved using other non-gradient descent-based methods, we will "smooth out" the L1 norm using an approximation which will allow us to use gradient descent. To "smooth out" the L1 norm, we use <math>\sqrt{x + \epsilon}</math> in place of <math>\left| x \right|</math>, where <math>\epsilon</math> is a "smoothing parameter" which can also be interpreted as a sort of "sparsity parameter" (to see this, observe that when <math>\epsilon</math> is large compared to <math>x</math>, the <math>x + \epsilon</math> is dominated by <math>\epsilon</math>, and taking the square root yields approximately <math>\sqrt{\epsilon}</math>). This "smoothing" will come in handy later when considering topographic sparse coding below. <br />
<br />
Our final objective function is hence:<br />
<br />
:<math><br />
J(A, s) = \lVert As - x \rVert_2^2 + \lambda \sqrt{s^2 + \epsilon} + \gamma \lVert A \rVert_2^2<br />
</math><br />
<br />
(where <math>\sqrt{s^2 + \epsilon}</math> is shorthand for <math>\sum_k{\sqrt{s_k^2 + \epsilon}}</math>)<br />
<br />
This objective function can then be optimized iteratively, using the following procedure:<br />
<ol><br />
<li>Initialize <math>A</math> randomly<br />
<li>Repeat until convergence<br />
<ol><br />
<li>Find the <math>s</math> that minimizes <math>J(A, s)</math> for the <math>A</math> found in the previous step<br />
<li>Solve for the <math>A</math> that minimizes <math>J(A, s)</math> for the <math>s</math> found in the previous step <br />
</ol><br />
</ol><br />
<br />
Observe that with our modified objective function, the objective function <math>J(A, s)</math> given <math>s</math>, that is <math>J(A; s) = \lVert As - x \rVert_2^2 + \gamma \lVert A \rVert_2^2</math> (the L1 term in <math>s</math> can be omitted since it is not a function of <math>A</math>) is simply a quadratic term in <math>A</math>, and hence has an easily derivable analytic solution in <math>A</math>. A quick way to derive this solution would be to use matrix calculus - some pages about matrix calculus can be found in the [[Useful Links | useful links]] section. Unfortunately, the objective function given <math>A</math> does not have a similarly nice analytic solution, so that minimization step will have to be carried out using gradient descent or similar optimization methods.<br />
<br />
In theory, optimizing for this objective function using the iterative method as above should (eventually) yield features (the basis vectors of <math>A</math>) similar to those learned using the sparse autoencoder. However, in practice, there are quite a few tricks required for better convergence of the algorithm, and these tricks are described in greater detail in the later section on [[ Sparse Coding: Autoencoder Interpretation#Sparse coding in practice | sparse coding in practice]]. Deriving the gradients for the objective function may be slightly tricky as well, and using matrix calculus or [[Deriving gradients using the backpropagation idea | using the backpropagation intuition]] can be helpful.<br />
<br />
== Topographic sparse coding ==<br />
<br />
With sparse coding, we can learn a set of features useful for representing the data. However, drawing inspiration from the brain, we would like to learn a set of features that are "orderly" in some manner. For instance, consider visual features. As suggested earlier, the V1 cortex of the brain contains neurons which detect edges at particular orientations. However, these neurons are also organized into hypercolumns in which adjacent neurons detect edges at similar orientations. One neuron could detect a horizontal edge, its neighbors edges oriented slightly off the horizontal, and moving further along the hypercolumn, the neurons detect edges oriented further off the horizontal. <br />
<br />
Inspired by this example, we would like to learn features which are similarly "topographically ordered". What does this imply for our learned features? Intuitively, if "adjacent" features are "similar", we would expect that if one feature is activated, its neighbors will also be activated to a lesser extent. <br />
<br />
Concretely, suppose we (arbitrarily) organized our features into a square matrix. We would then like adjacent features in the matrix to be similar. The way this is accomplished is to group these adjacent features together in the smoothed L1 penalty, so that instead of say <math>\sqrt{s_{1,1}^2 + \epsilon}</math>, we use say <math>\sqrt{s_{1,1}^2 + s_{1,2}^2 + s_{1,3}^2 + s_{2,1}^2 + s_{2,2}^2 + s_{3,2}^2 + s_{3,1}^2 + s_{3,2}^2 + s_{3,3}^2 + \epsilon}</math> instead, if we group in 3x3 regions. The grouping is usually overlapping, so that the 3x3 region starting at the 1st row and 1st column is one group, the 3x3 region starting at the 1st row and 2nd column is another group, and so on. Further, the grouping is also usually done wrapping around, as if the matrix were a torus, so that every feature is counted an equal number of times.<br />
<br />
Hence, in place of the smoothed L1 penalty, we use the sum of smoothed L1 penalties over all the groups, so our new objective function is:<br />
<br />
:<math><br />
J(A, s) = \lVert As - x \rVert_2^2 + \lambda \sum_{\text{all groups } g}{\sqrt{ \left( \sum_{\text{all } s \in g}{s^2} \right) + \epsilon} } + \gamma \lVert A \rVert_2^2<br />
</math><br />
<br />
In practice, the "grouping" can be accomplished using a "grouping matrix" <math>V</math>, such that the <math>r</math>th row of <math>V</math> indicates which features are grouped in the <math>r</math>th group, so <math>V_{r, c} = 1</math> if group <math>r</math> contains feature <math>c</math>. Thinking of the grouping as being achieved by a grouping matrix makes the computation of the gradients more intuitive. Using this grouping matrix, the objective function can be rewritten as:<br />
<br />
:<math><br />
J(A, s) = \lVert As - x \rVert_2^2 + \lambda \sum{ \sqrt{Vss^T + \epsilon} } + \gamma \lVert A \rVert_2^2<br />
</math><br />
<br />
(where <math>\sum{ \sqrt{Vss^T + \epsilon} }</math> is <math>\sum_r{ \sum_c { D_{r, c} } } </math> if we let <math>D = \sqrt{Vss^T + \epsilon}</math>)<br />
<br />
This objective function can be optimized using the iterated method described in the earlier section. Topographic sparse coding will learn features similar to those learned by sparse coding, except that the features will now be "ordered" in some way.<br />
<br />
== Sparse coding in practice ==<br />
<br />
As suggested in the earlier sections, while the theory behind sparse coding is quite simple, writing a good implementation that actually works and converges reasonably quickly to good optima requires a bit of finesse.<br />
<br />
Recall the simple iterative algorithm proposed earlier:<br />
<ol><br />
<li>Initialize <math>A</math> randomly<br />
<li>Repeat until convergence<br />
<ol><br />
<li>Find the <math>s</math> that minimizes <math>J(A, s)</math> for the <math>A</math> found in the previous step<br />
<li>Solve for the <math>A</math> that minimizes <math>J(A, s)</math> for the <math>s</math> found in the previous step <br />
</ol><br />
</ol><br />
<br />
It turns out that running this algorithm out of the box will not produce very good results, if any results are produced at all. There are two main tricks to achieve faster and better convergence: <br />
<ol><br />
<li>Batching examples into "mini-batches"<br />
<li>Good initialization of <math>s</math><br />
</ol><br />
<br />
=== Batching examples into mini-batches ===<br />
<br />
If you try running the simple iterative algorithm on a large dataset of say 10 000 patches at one go, you will find that each iteration takes a long time, and the algorithm may hence take a long time to converge. To increase the rate of convergence, you can instead run the algorithm on mini-batches instead. To do this, instead of running the algorithm on all 10 000 patches, in each iteration, select a mini-batch - a (different) random subset of say 2000 patches from the 10 000 patches - and run the algorithm on that mini-batch for the iteration instead. This accomplishes two things - firstly, it speeds up each iteration, since now each iteration is operating on 2000 rather than 10 000 patches; secondly, and more importantly, it increases the rate of convergence [[(TODO]]: explain why).<br />
<br />
=== Good initialization of <math>s</math> ===<br />
<br />
Another important trick in obtaining faster and better convergence is good initialization of the feature matrix <math>s</math> before using gradient descent (or other methods) to optimize for the objective function for <math>s</math> given <math>A</math>. In practice, initializing <math>s</math> randomly at each iteration can result in poor convergence unless a good optima is found for <math>s</math> before moving on to optimize for <math>A</math>. A better way to initialize <math>s</math> is the following:<br />
<ol><br />
<li>Set <math>s \leftarrow W^Tx</math> (where <math>x</math> is the matrix of patches in the mini-batch)<br />
<li>For each feature in <math>s</math> (i.e. each column of <math>s</math>), divide the feature by the norm of the corresponding basis vector in <math>A</math>. That is, if <math>s_{r, c}</math> is the <math>r</math>th feature for the <math>c</math>th example, and <math>A_c</math> is the <math>c</math>th basis vector in <math>A</math>, then set <math>s_{r, c} \leftarrow \frac{ s_{r, c} } { \lVert A_c \rVert }.</math><br />
</ol><br />
<br />
Very roughly and informally speaking, this initialization helps because the first step is an attempt to find a good <math>s</math> such that <math>Ws \approx x</math>, and the second step "normalizes" <math>s</math> in an attempt to keep the sparsity penalty small. It turns out that initializing <math>s</math> using only one but not both steps results in poor performance in practice. ([[TODO]]: a better explanation for why this initialization helps?)<br />
<br />
=== The practical algorithm ===<br />
<br />
With the above two tricks, the algorithm for sparse coding then becomes:<br />
<ol><br />
<li>Initialize <math>A</math> randomly<br />
<li>Repeat until convergence<br />
<ol><br />
<li>Select a random mini-batch of 2000 patches<br />
<li>Initialize <math>s</math> as described above<br />
<li>Find the <math>s</math> that minimizes <math>J(A, s)</math> for the <math>A</math> found in the previous step<br />
<li>Solve for the <math>A</math> that minimizes <math>J(A, s)</math> for the <math>s</math> found in the previous step <br />
</ol><br />
</ol><br />
<br />
With this method, you should be able to reach a good local optima relatively quickly.<br />
<br />
<br />
<br />
{{Languages|稀疏编码自编码表达|中文}}</div>
Kandeng
http://ufldl.stanford.edu/wiki/index.php/%E7%A8%80%E7%96%8F%E7%BC%96%E7%A0%81%E8%87%AA%E7%BC%96%E7%A0%81%E8%A1%A8%E8%BE%BE
稀疏编码自编码表达
2013-04-08T04:32:26Z
<p>Kandeng: </p>
<hr />
<div>== 稀疏编码 ==<br />
<br />
<br />
在稀疏自编码算法中,我们试着学习得到一组权重参数 <math>W</math>(以及相应的截距 <math>b</math>),通过这些参数可以使我们得到稀疏特征向量 <math>\sigma(Wx + b)</math> ,这些特征向量对于重构输入样本非常有用。<br />
<br />
[[File:STL_SparseAE.png | 240px]]<br />
<br />
<br />
稀疏编码可以看作是稀疏自编码方法的一个变形,该方法试图直接学习数据的特征集。利用与此特征集相应的基向量,将学习得到的特征集从特征空间转换到样本数据空间,这样我们就可以用学习得到的特征集重构样本数据。 <br />
<br />
<br />
确切地说,在稀疏编码算法中,有样本数据 <math>x</math> 供我们进行特征学习。特别是,学习一个用于表示样本数据的稀疏特征集 <math>s</math>, 和一个将特征集从特征空间转换到样本数据空间的基向量 <math>A</math>, 我们可以构建如下目标函数:<br />
<br />
:<math><br />
J(A, s) = \lVert As - x \rVert_2^2 + \lambda \lVert s \rVert_1<br />
</math><br />
<br />
(<math>\lVert x \rVert_k</math>是x的Lk范数,等价于 <math>\left( \sum{ \left| x_i^k \right| } \right) ^{\frac{1}{k}}</math>。L2 范数即大家熟知的欧几里得范数,L1 范数是向量元素的绝对值之和)<br />
<br />
<br />
上式前第一部分是利用基向量将特征集重构为样本数据所产生的误差,第二部分为稀疏性惩罚项(sparsity penalty term),用于保证特征集的稀疏性。 <br />
<br />
<br />
但是,如目标函数所示,它的约束性并不强――按常数比例缩放<math>A</math>的同时再按这个常数的倒数缩放 <math>s</math>,结果不会改变误差大小,却会减少稀疏代价(表达式第二项)的值。因此,需要为 <math>A</math> 中每项 <math>A_j</math> 增加额外约束 <math>A_j^TA_j \le 1</math>。问题变为:<br />
<br />
:<math><br />
\begin{array}{rcl}<br />
{\rm minimize} & \lVert As - x \rVert_2^2 + \lambda \lVert s \rVert_1 \\<br />
{\rm s.t.} & A_j^TA_j \le 1 \; \forall j \\<br />
\end{array} <br />
</math><br />
<br />
<br />
遗憾的是,因为目标函数并不是一个凸函数,所以不能用梯度方法解决这个优化问题。但是,在给定 <math>A</math> 的情况下,最小化 <math>J(A, s)</math> 求解 <math>s</math> 是凸的。同理,给定 <math>s</math> 最小化 <math>J(A, s)</math> 求解 <math>A</math> 也是凸的。这表明,可以通过交替固定 <math>s</math >和 A 分别求解 <math>A</math>和<math>s</math>。实践表明,这一策略取得的效果非常好。 <br />
<br />
<br />
但是,以上表达式带来了另一个难题:不能用简单的梯度方法来实现约束条件 <math>A_j^TA_j \le 1 \; \forall j</math>。因此在实际问题中,此约束条件还不足以成为“权重衰变”("weight decay")项以保证 A 的每一项值够小。这样我们就得到一个新的目标函数: <br />
<br />
:<math><br />
J(A, s) = \lVert As - x \rVert_2^2 + \lambda \lVert s \rVert_1 + \gamma \lVert A \rVert_2^2<br />
</math><br />
<br />
(注意上式中第三项, <math>\lVert A \rVert_2^2</math>等价于<math>\sum_r{\sum_c{A_{rc}^2}}</math>,是A各项的平方和)<br />
<br />
<br />
这一目标函数带来了最后一个问题,即 L1 范数在 0 点处不可微影响了梯度方法的应用。尽管可以通过其他非梯度下降方法避开这一问题,但是本文通过使用近似值“平滑” L1 范数的方法解决此难题。使用 <math>\sqrt{x + \epsilon}</math> 代替 <math>\left| x \right|</math>, 对 L1 范数进行平滑,其中 <math>\epsilon</math> 是“平滑参数”("smoothing parameter")或者“稀疏参数”("sparsity parameter") (如果 <math>\epsilon</math>远大于<math>x</math>, 则 <math>x + \epsilon</math> 的值由 <math>\epsilon</math> 主导,其平方根近似于 )。在下文提及拓扑稀疏编码时,“平滑”会派上用场。 <br />
<br />
<br />
因此,最终的目标函数是:<br />
<br />
:<math><br />
J(A, s) = \lVert As - x \rVert_2^2 + \lambda \sqrt{s^2 + \epsilon} + \gamma \lVert A \rVert_2^2<br />
</math><br />
<br />
( <math>\sqrt{s^2 + \epsilon}</math> 是 <math>\sum_k{\sqrt{s_k^2 + \epsilon}}</math> 的简写)<br />
<br />
<br />
该目标函数可以通过以下过程迭代优化: <br />
<br />
<ol><br />
<li>随机初始化<math>A</math><br />
<li>重复以下步骤直至收敛:<br />
<ol><br />
<li>根据上一步给定的<math>A</math>,求解能够最小化<math>J(A, s)</math>的<math>s</math><br />
<li>根据上一步得到的<math>s</math>,,求解能够最小化<math>J(A, s)</math>的<math>A</math> </ol><br />
</ol><br />
<br />
<br />
观察修改后的目标函数 <math>J(A, s)</math>,给定 <math>s</math> 的条件下,目标函数可以简化为 <math>J(A; s) = \lVert As - x \rVert_2^2 + \gamma \lVert A \rVert_2^2</math>(因为 <math>s</math> 的 L1 范式不是 <math>A</math> 的函数,所以可以忽略)。简化后的目标函数是一个关于 <math>A</math> 的简单二次项式,因此对 <math>A</math> 求导是很容易的。这种求导的一种快捷方法是矩阵微积分([[Useful Links | 相关链接]]部分列出了跟矩阵演算有关的内容)。遗憾的是,在给定 <math>A</math> 的条件下,目标函数却不具备这样的求导方法,因此目标函数的最小化步骤只能用梯度下降或其他类似的最优化方法。 <br />
<br />
<br />
理论上,通过上述迭代方法求解目标函数的最优化问题最终得到的特征集(A 的基向量)与通过稀疏自编码学习得到的特征集是差不多的。但是实际上,为了获得更好的算法收敛性需要使用一些小技巧,后面的[[ Sparse Coding: Autoencoder Interpretation#Sparse coding in practice | 稀疏编码实践]] 稀疏编码实践章节会详细介绍这些技巧。用梯度下降方法求解目标函数也略需技巧,另外使用矩阵演算或[[Deriving gradients using the backpropagation idea | 反向传播算法]]则有助于解决此类问题。<br />
<br />
<br />
== 拓扑稀疏编码 ==<br />
<br />
<br />
通过稀疏编码,我们能够得到一组用于表示样本数据的特征集。不过,让我们来找些灵感,我们希望学习得到一组有某种“秩序”的特征集。举个例子,视觉特征,如前面所提到的,大脑皮层 V1 区神经元能够按特定的方向对边缘进行检测,同时,这些神经元(在生理上)被组织成超柱(hypercolumns),在超柱中,相邻神经元以相似的方向对边缘进行检测,一个神经元检测水平边缘,其相邻神经元检测到的边缘就稍微偏离水平方向,沿着超柱,神经元就可以检测到与水平方向相差更大的边缘了。 <br />
<br />
<br />
受该例子的启发,我们希望学习到的特征也具有这样“拓扑秩序”的性质。这对于我们要学习的特征意味着什么呢?直观的讲,如果“相邻”的特征是“相似”的,就意味着如果某个特征被激活,那么与之相邻的特征也将随之被激活。 <br />
<br />
<br />
具体而言,假设我们(随意地)将特征组织成一个方阵。我们就希望矩阵中相邻的特征是相似的。实现这一点的方法是将相邻特征按经过平滑的L1范式惩罚进行分组,如果按 3x3 方阵分组,则用 <math>\sqrt{s_{1,1}^2 + s_{1,2}^2 + s_{1,3}^2 + s_{2,1}^2 + s_{2,2}^2 + s_{3,2}^2 + s_{3,1}^2 + s_{3,2}^2 + s_{3,3}^2 + \epsilon}</math> 代替 <math>\sqrt{s_{1,1}^2 + \epsilon}</math>, 其分组通常是重合的,因此从第 1 行第 1 列开始的 3x3 区域是一个分组,从第 1 行第 2 列开始的 3x3 区域是另一个分组,以此类推。最终,这样的分组会形成环绕,就好像这个矩阵是个环形曲面,所以每个特征都以同样的次数进行了分组。<br />
于是,将经过平滑的所有分组的 L1 惩罚值之和代替经过平滑的 L1 惩罚值,得到新的目标函数如下:<br />
<br />
:<math><br />
J(A, s) = \lVert As - x \rVert_2^2 + \lambda \sum_{\text{all groups } g}{\sqrt{ \left( \sum_{\text{all } s \in g}{s^2} \right) + \epsilon} } + \gamma \lVert A \rVert_2^2<br />
</math><br />
<br />
<br />
实际上,“分组”可以通过“分组矩阵”<math>V</math> 完成,于是矩阵 <math>V</math> 的第 <math>r</math> 行标识了哪些特征被分到第 <math>r</math> 组中,即如果第 <math>r</math> 组包含特征 <math>c</math> 则 <math>V_{r, c} = 1</math>。通过分组矩阵实现分组使得梯度的计算更加直观,使用此分组矩阵,目标函数被重写为: <br />
<br />
:<math><br />
J(A, s) = \lVert As - x \rVert_2^2 + \lambda \sum{ \sqrt{Vss^T + \epsilon} } + \gamma \lVert A \rVert_2^2<br />
</math><br />
<br />
(令 <math>D = \sqrt{Vss^T + \epsilon}</math>,<math>\sum{ \sqrt{Vss^T + \epsilon} }</math> 等价于 <math>\sum_r{ \sum_c { D_{r, c} } } </math>)<br />
<br />
<br />
该目标函数能够使用之前部分提到的迭代方法进行求解。拓扑稀疏编码得到的特征与稀疏编码得到的类似,只是拓扑稀疏编码得到的特征是以某种方式有“秩序”排列的。 <br />
<br />
<br />
== 稀疏编码实践 ==<br />
<br />
<br />
如上所述,虽然稀疏编码背后的理论十分简单,但是要写出准确无误的实现代码并能快速又恰到好处地收敛到最优值,则需要一定的技巧。 <br />
<br />
<br />
回顾一下之前提到的简单迭代算法:<br />
<br />
<ol><br />
<li>随机初始化<math>A</math><br />
<li>重复以下步骤直至收敛到最优值:<br />
<ol><br />
<li>根据上一步给定的<math>A</math>,求解能够最小化<math>J(A, s)</math>的<math>s</math> <br />
<li>根据上一步得到的<math>s</math>,求解能够最小化<math>J(A, s)</math>的<math>A</math> <br />
</ol><br />
</ol><br />
<br />
<br />
这样信手拈来地执行这个算法,结果并不会令人满意,即使确实得到了某些结果。以下是两种更快更优化的收敛技巧:<br />
<br />
<ol><br />
<li>将样本分批为“迷你块”<br />
<li>良好的<math>s</math>初始值<br />
</ol><br />
<br />
<br />
=== 将样本分批为“迷你块” ===<br />
<br />
<br />
如果你一次性在大规模数据集(比如,有10000 个patch)上执行简单的迭代算法,你会发现每次迭代都要花很长时间,也因此这算法要花好长时间才能达到收敛结果。为了提高收敛速度,可以选择在迷你块上运行该算法。每次迭代的时候,不是在所有的 10000 个 patchs 上执行该算法,而是使用迷你块,即从 10000 个 patch 中随机选出 2000 个 patch,再在这个迷你块上执行这个算法。这样就可以做到一石二鸟――第一,提高了每次迭代的速度,因为现在每次迭代只在 2000 个 patch 上执行而不是 10000个;第二,也是更重要的,它提高了收敛的速度(原因见[[TODO]])。<br />
<br />
<br />
=== 良好的<math>s</math>初始值 ===<br />
<br />
另一个能获得更快速更优化收敛的重要技巧是:在给定 <math>A</math> 的条件下,根据目标函数使用梯度下降(或其他方法)求解 <math>s</math> 之前找到良好的特征矩阵 <math>s</math> 的初始值。实际上,除非在优化 <math>A</math> 的最优值前已找到一个最佳矩阵 <math>s</math>,不然每次迭代过程中随机初始化 <math>s</math> 值会导致很差的收敛效果。下面给出一个初始化 <math>s</math> 的较好方法: <br />
<br />
<ol><br />
<li>令<math>s \leftarrow W^Tx</math> (<math>x</math> 是迷你块中patches的矩阵表示)<br />
<li><math>s</math>中的每个特征(<math>s</math>的每一列),除以其在<math>A</math>中对应基向量的范数。即,如果<math>s_{r, c}</math>表示第<math>c</math>个样本的第<math>r</math>个特征,则<math>A_c</math>表示<math>A</math>中的第<math>c</math>个基向量,则令<br />
<math>s_{r, c} \leftarrow \frac{ s_{r, c} } { \lVert A_c \rVert }.</math><br />
</ol><br />
<br />
<br />
无疑,这样的初始化有助于算法的改进,因为上述的第一步希望找到满足 <math>Ws \approx x</math> 的矩阵 <math>s</math>;第二步对 <math>s</math> 作规范化处理是为了保持较小的稀疏惩罚值。这也表明,只采用上述步骤的某一步而不是两步对 <math>s</math> 做初始化处理将严重影响算法性能。([[TODO]]: 此链接将会对为什么这样的初始化能改进算法作出更详细的解释)<br />
<br />
<br />
=== 可运行算法 ===<br />
<br />
有了以上两种技巧,稀疏编码算法修改如下: <br />
<br />
<ol><br />
<li>随机初始化<math>A</math><br />
<li>重复以下步骤直至收敛<br />
<ol><br />
<li>随机选取一个有2000个patches的迷你块 <br />
<li>如上所述,初始化<math>s</math><br />
<li>根据上一步给定的<math>A</math>,求解能够最小化<math>J(A, s)</math>的<math>s</math><br />
<li>根据上一步得到的<math>s</math>,求解能够最小化<math>J(A, s)</math>的<math>A</math> <br />
</ol><br />
</ol><br />
<br />
通过上述方法,可以相对快速的得到局部最优解。<br />
<br />
<br />
<br />
==中英文对照==<br />
<br />
:稀疏编码 sparse coding<br />
:自编码 autoencoder<br />
:目标函数 objective function<br />
:稀疏代价 sparsity cost<br />
:反向传播 backpropagation <br />
:基于梯度的 gradient-based<br />
:非凸的 non-convex<br />
:权重衰变 weight decay<br />
:拓扑稀疏编码 topographic sparse coding<br />
:拓扑秩序 topographically ordered<br />
:平滑的一范数惩罚 smoothed L1 penalty<br />
:迷你块 mini-batches<br />
:收敛速度 the rate of convergence<br />
:梯度下降 gradient descent<br />
:局部最优解 local optima<br />
<br />
<br />
<br />
==中文译者==<br />
<br />
许超(xuchaowill@gmail.com), 张睿卿(zrqjennifer@gmail.com), 林锋(xlfg@yeah.net)<br />
<br />
<br />
{{Sparse_Autoencoder}}<br />
<br />
<br />
{{Languages|Sparse_Coding:_Autoencoder_Interpretation|English}}</div>
Kandeng
http://ufldl.stanford.edu/wiki/index.php/%E7%A8%80%E7%96%8F%E7%BC%96%E7%A0%81
稀疏编码
2013-04-08T04:30:52Z
<p>Kandeng: </p>
<hr />
<div>== 稀疏编码 ==<br />
<br />
稀疏编码算法是一种无监督学习方法,它用来寻找一组“超完备”基向量来更高效地表示样本数据。稀疏编码算法的目的就是找到一组基向量 <math>\mathbf{\phi}_i</math> ,使得我们能将输入向量 <math>\mathbf{x}</math> 表示为这些基向量的线性组合:<br />
<br />
:<math>\begin{align}<br />
\mathbf{x} = \sum_{i=1}^k a_i \mathbf{\phi}_{i} <br />
\end{align}</math><br />
<br />
<br />
虽然形如主成分分析技术(PCA)能使我们方便地找到一组“完备”基向量,但是这里我们想要做的是找到一组'''“超完备”'''基向量来表示输入向量 <math>\mathbf{x}\in\mathbb{R}^n</math> (也就是说,<math>k > n</math>)。超完备基的好处是它们能更有效地找出隐含在输入数据内部的结构与模式。然而,对于超完备基来说,系数 <math>a_i</math> 不再由输入向量 <math>\mathbf{x}</math> 唯一确定。因此,在稀疏编码算法中,我们另加了一个评判标准'''“稀疏性”'''来解决因超完备而导致的退化(degeneracy)问题。<br />
<br />
<br />
这里,我们把“稀疏性”定义为:只有很少的几个非零元素或只有很少的几个远大于零的元素。要求系数 <math>a_i</math> 是稀疏的意思就是说:对于一组输入向量,我们只想有尽可能少的几个系数远大于零。选择使用具有稀疏性的分量来表示我们的输入数据是有原因的,因为绝大多数的感官数据,比如自然图像,可以被表示成少量基本元素的叠加,在图像中这些基本元素可以是面或者线。同时,比如与初级视觉皮层的类比过程也因此得到了提升。<br />
<br />
<br />
我们把有 <math>m</math> 个输入向量的稀疏编码代价函数定义为:<br />
<br />
:<math>\begin{align}<br />
\text{minimize}_{a^{(j)}_i,\mathbf{\phi}_{i}} \sum_{j=1}^{m} \left|\left| \mathbf{x}^{(j)} - \sum_{i=1}^k a^{(j)}_i \mathbf{\phi}_{i}\right|\right|^{2} + \lambda \sum_{i=1}^{k}S(a^{(j)}_i)<br />
\end{align}</math><br />
<br />
<br />
此处 <math>S(.)</math> 是一个稀疏代价函数,由它来对远大于零的 <math>a_i</math> 进行“惩罚”。我们可以把稀疏编码目标函式的第一项解释为一个重构项,这一项迫使稀疏编码算法能为输入向量 <math>\mathbf{x}</math> 提供一个高拟合度的线性表达式,而公式第二项即“稀疏惩罚”项,它使 <math>\mathbf{x}</math> 的表达式变得“稀疏”。常量 <math>\lambda</math> 是一个变换量,由它来控制这两项式子的相对重要性。 <br />
<br />
<br />
虽然“稀疏性”的最直接测度标准是 "<math>L_0</math>" 范式(<math>S(a_i) = \mathbf{1}(|a_i|>0)</math>),但这是不可微的,而且通常很难进行优化。在实际中,稀疏代价函数 <math>S(.)</math> 的普遍选择是<math>L_1</math> 范式代价函数 <math>S(a_i)=\left|a_i\right|_1 </math> 及对数代价函数 <math>S(a_i)=\log(1+a_i^2)</math> 。<br />
<br />
<br />
此外,很有可能因为减小 <math>a_i</math> 或增加 <math>\mathbf{\phi}_i</math> 至很大的常量,使得稀疏惩罚变得非常小。为防止此类事件发生,我们将限制 <math>\left|\left|\mathbf{\phi}\right|\right|^2</math> 要小于某常量 <math>C</math> 。包含了限制条件的稀疏编码代价函数的完整形式如下:<br />
<br />
:<math>\begin{array}{rc}<br />
\text{minimize}_{a^{(j)}_i,\mathbf{\phi}_{i}} & \sum_{j=1}^{m} \left|\left| \mathbf{x}^{(j)} - \sum_{i=1}^k a^{(j)}_i \mathbf{\phi}_{i}\right|\right|^{2} + \lambda \sum_{i=1}^{k}S(a^{(j)}_i) <br />
\\<br />
\text{subject to} & \left|\left|\mathbf{\phi}_i\right|\right|^2 \leq C, \forall i = 1,...,k <br />
\\<br />
\end{array}</math><br />
<br />
<br />
<br />
== 概率解释 [基于1996年Olshausen与Field的理论] ==<br />
<br />
到目前为止,我们所考虑的稀疏编码,是为了寻找到一个稀疏的、超完备基向量集,来覆盖我们的输入数据空间。现在换一种方式,我们可以从概率的角度出发,将稀疏编码算法当作一种“生成模型”。<br />
<br />
<br />
我们将自然图像建模问题看成是一种线性叠加,叠加元素包括 <math>k</math> 个独立的源特征 <math>\mathbf{\phi}_i</math> 以及加性噪声 <math>\nu</math> :<br />
<br />
:<math>\begin{align}<br />
\mathbf{x} = \sum_{i=1}^k a_i \mathbf{\phi}_{i} + \nu(\mathbf{x})<br />
\end{align}</math><br />
<br />
<br />
我们的目标是找到一组特征基向量 <math>\mathbf{\phi}</math> ,它使得图像的分布函数 <math>P(\mathbf{x}\mid\mathbf{\phi})</math> 尽可能地近似于输入数据的经验分布函数 <math>P^*(\mathbf{x})</math> 。一种实现方式是,最小化 <math>P^*(\mathbf{x})</math> 与 <math>P(\mathbf{x}\mid\mathbf{\phi})</math> 之间的 KL 散度,此 KL 散度表示如下:<br />
<br />
:<math>\begin{align}<br />
D(P^*(\mathbf{x})||P(\mathbf{x}\mid\mathbf{\phi})) = \int P^*(\mathbf{x}) \log \left(\frac{P^*(\mathbf{x})}{P(\mathbf{x}\mid\mathbf{\phi})}\right)d\mathbf{x}<br />
\end{align}</math> <br />
<br />
<br />
因为无论我们如何选择 <math>\mathbf{\phi}</math> ,经验分布函数 <math>P^*(\mathbf{x})</math> 都是常量,也就是说我们只需要最大化对数似然函数 <math>P(\mathbf{x}\mid\mathbf{\phi})</math> 。<br />
假设 <math>\nu</math> 是具有方差 <math>\sigma^2</math> 的高斯白噪音,则有下式:<br />
<br />
:<math>\begin{align}<br />
P(\mathbf{x} \mid \mathbf{a}, \mathbf{\phi}) = \frac{1}{Z} \exp\left(- \frac{(\mathbf{x}-\sum^{k}_{i=1} a_i \mathbf{\phi}_{i})^2}{2\sigma^2}\right)<br />
\end{align}</math><br />
<br />
<br />
为了确定分布 <math>P(\mathbf{x}\mid\mathbf{\phi})</math> ,我们需要指定先验分布 <math>P(\mathbf{a})</math> 。假定我们的特征变量是独立的,我们就可以将先验概率分解为:<br />
<br />
:<math>\begin{align}<br />
P(\mathbf{a}) = \prod_{i=1}^{k} P(a_i)<br />
\end{align}</math><br />
<br />
<br />
此时,我们将“稀疏”假设加入进来——假设任何一幅图像都是由相对较少的一些源特征组合起来的。因此,我们希望 <math>a_i</math> 的概率分布在零值附近是凸起的,而且峰值很高。一个方便的参数化先验分布就是:<br />
<br />
:<math>\begin{align}<br />
P(a_i) = \frac{1}{Z}\exp(-\beta S(a_i))<br />
\end{align}</math><br />
<br />
<br />
这里 <math>S(a_i)</math> 是决定先验分布的形状的函数。<br />
<br />
<br />
当定义了 <math>P(\mathbf{x} \mid \mathbf{a} , \mathbf{\phi})</math> 和 <math> P(\mathbf{a})</math> 后,我们就可以写出在由 <math>\mathbf{\phi}</math> 定义的模型之下的数据 <math>\mathbf{x}</math> 的概率分布:<br />
<br />
:<math>\begin{align}<br />
P(\mathbf{x} \mid \mathbf{\phi}) = \int P(\mathbf{x} \mid \mathbf{a}, \mathbf{\phi}) P(\mathbf{a}) d\mathbf{a}<br />
\end{align}</math><br />
<br />
<br />
那么,我们的问题就简化为寻找:<br />
<br />
:<math>\begin{align}<br />
\mathbf{\phi}^*=\text{argmax}_{\mathbf{\phi}} < \log(P(\mathbf{x} \mid \mathbf{\phi})) ><br />
\end{align}</math><br />
<br />
<br />
这里 <math><.></math> 表示的是输入数据的期望值。<br />
<br />
<br />
不幸的是,通过对 <math>\mathbf{a}</math> 的积分计算 <math>P(\mathbf{x} \mid \mathbf{\phi})</math> 通常是难以实现的。虽然如此,我们注意到如果 <math>P(\mathbf{x} \mid \mathbf{\phi})</math> 的分布(对于相应的 <math>\mathbf{a}</math> )足够陡峭的话,我们就可以用 <math>P(\mathbf{x} \mid \mathbf{\phi})</math> 的最大值来估算以上积分。估算方法如下:<br />
<br />
:<math>\begin{align}<br />
\mathbf{\phi}^{*'}=\text{argmax}_{\mathbf{\phi}} < \max_{\mathbf{a}} \log(P(\mathbf{x} \mid \mathbf{\phi})) ><br />
\end{align}</math><br />
<br />
<br />
跟之前一样,我们可以通过减小 <math>a_i</math> 或增大 <math>\mathbf{\phi}</math> 来增加概率的估算值(因为 <math>P(a_i)</math> 在零值附近陡升)。因此我们要对特征向量 <math>\mathbf{\phi}</math> 加一个限制以防止这种情况发生。<br />
<br />
最后,我们可以定义一种线性生成模型的能量函数,从而将原先的代价函数重新表述为:<br />
<br />
:<math>\begin{array}{rl}<br />
E\left( \mathbf{x} , \mathbf{a} \mid \mathbf{\phi} \right) & := -\log \left( P(\mathbf{x}\mid \mathbf{\phi},\mathbf{a}\right)P(\mathbf{a})) \\<br />
&= \sum_{j=1}^{m} \left|\left| \mathbf{x}^{(j)} - \sum_{i=1}^k a^{(j)}_i \mathbf{\phi}_{i}\right|\right|^{2} + \lambda \sum_{i=1}^{k}S(a^{(j)}_i) <br />
\end{array}</math><br />
<br />
<br />
其中 <math>\lambda = 2\sigma^2\beta</math> ,并且关系不大的常量已被隐藏起来。因为最大化对数似然函数等同于最小化能量函数,我们就可以将原先的优化问题重新表述为:<br />
<br />
:<math>\begin{align}<br />
\mathbf{\phi}^{*},\mathbf{a}^{*}=\text{argmin}_{\mathbf{\phi},\mathbf{a}} \sum_{j=1}^{m} \left|\left| \mathbf{x}^{(j)} - \sum_{i=1}^k a^{(j)}_i \mathbf{\phi}_{i}\right|\right|^{2} + \lambda \sum_{i=1}^{k}S(a^{(j)}_i) <br />
\end{align}</math><br />
<br />
<br />
使用概率理论来分析,我们可以发现,选择 <math>L_1</math> 惩罚和 <math>\log(1+a_i^2)</math> 惩罚作为函数 <math>S(.)</math> ,分别对应于使用了拉普拉斯概率 <math>P(a_i) \propto \exp\left(-\beta|a_i|\right)</math> 和柯西先验概率 <math>P(a_i) \propto \frac{\beta}{1+a_i^2}</math> 。<br />
<br />
<br />
== 学习算法 ==<br />
<br />
使用稀疏编码算法学习基向量集的方法,是由两个独立的优化过程组合起来的。第一个是逐个使用训练样本 <math>\mathbf{x}</math> 来优化系数 <math>a_i</math> ,第二个是一次性处理多个样本对基向量 <math>\mathbf{\phi}</math> 进行优化。<br />
<br />
<br />
如果使用 <math>L_1</math> 范式作为稀疏惩罚函数,对 <math>a^{(j)}_i</math> 的学习过程就简化为求解 由 <math>L_1</math> 范式正则化的最小二乘法问题,这个问题函数在域 <math>a^{(j)}_i</math> 内为凸,已经有很多技术方法来解决这个问题(诸如CVX之类的凸优化软件可以用来解决L1正则化的最小二乘法问题)。如果 <math>S(.)</math> 是可微的,比如是对数惩罚函数,则可以采用基于梯度算法的方法,如共轭梯度法。<br />
<br />
<br />
用 <math>L_2</math> 范式约束来学习基向量,同样可以简化为一个带有二次约束的最小二乘问题,其问题函数在域 <math>\mathbf{\phi}</math> 内也为凸。标准的凸优化软件(如CVX)或其它迭代方法就可以用来求解 <math>\mathbf{\phi}</math>,虽然已经有了更有效的方法,比如求解拉格朗日对偶函数(Lagrange dual)。<br />
<br />
<br />
根据前面的的描述,稀疏编码是有一个明显的局限性的,这就是即使已经学习得到一组基向量,如果为了对新的数据样本进行“编码”,我们必须再次执行优化过程来得到所需的系数。这个显著的“实时”消耗意味着,即使是在测试中,实现稀疏编码也需要高昂的计算成本,尤其是与典型的前馈结构算法相比。<br />
<br />
<br />
<br />
==中英文对照==<br />
<br />
<br />
<br />
==中文译者==<br />
<br />
柳翠寅(liucuiyin@163.com),林锋(xlfg@yeah.net),王方(fangkey@gmail.com)<br />
<br />
<br />
<br />
{{Languages|Sparse_Coding|English}}</div>
Kandeng
http://ufldl.stanford.edu/wiki/index.php/%E7%A8%80%E7%96%8F%E7%BC%96%E7%A0%81
稀疏编码
2013-04-08T04:30:06Z
<p>Kandeng: </p>
<hr />
<div>== 稀疏编码 ==<br />
<br />
稀疏编码算法是一种无监督学习方法,它用来寻找一组“超完备”基向量来更高效地表示样本数据。稀疏编码算法的目的就是找到一组基向量 <math>\mathbf{\phi}_i</math> ,使得我们能将输入向量 <math>\mathbf{x}</math> 表示为这些基向量的线性组合:<br />
<br />
:<math>\begin{align}<br />
\mathbf{x} = \sum_{i=1}^k a_i \mathbf{\phi}_{i} <br />
\end{align}</math><br />
<br />
<br />
虽然形如主成分分析技术(PCA)能使我们方便地找到一组“完备”基向量,但是这里我们想要做的是找到一组'''“超完备”'''基向量来表示输入向量 <math>\mathbf{x}\in\mathbb{R}^n</math> (也就是说,<math>k > n</math>)。超完备基的好处是它们能更有效地找出隐含在输入数据内部的结构与模式。然而,对于超完备基来说,系数 <math>a_i</math> 不再由输入向量 <math>\mathbf{x}</math> 唯一确定。因此,在稀疏编码算法中,我们另加了一个评判标准'''“稀疏性”'''来解决因超完备而导致的退化(degeneracy)问题。<br />
<br />
<br />
这里,我们把“稀疏性”定义为:只有很少的几个非零元素或只有很少的几个远大于零的元素。要求系数 <math>a_i</math> 是稀疏的意思就是说:对于一组输入向量,我们只想有尽可能少的几个系数远大于零。选择使用具有稀疏性的分量来表示我们的输入数据是有原因的,因为绝大多数的感官数据,比如自然图像,可以被表示成少量基本元素的叠加,在图像中这些基本元素可以是面或者线。同时,比如与初级视觉皮层的类比过程也因此得到了提升。<br />
<br />
<br />
我们把有 <math>m</math> 个输入向量的稀疏编码代价函数定义为:<br />
<br />
:<math>\begin{align}<br />
\text{minimize}_{a^{(j)}_i,\mathbf{\phi}_{i}} \sum_{j=1}^{m} \left|\left| \mathbf{x}^{(j)} - \sum_{i=1}^k a^{(j)}_i \mathbf{\phi}_{i}\right|\right|^{2} + \lambda \sum_{i=1}^{k}S(a^{(j)}_i)<br />
\end{align}</math><br />
<br />
<br />
此处 <math>S(.)</math> 是一个稀疏代价函数,由它来对远大于零的 <math>a_i</math> 进行“惩罚”。我们可以把稀疏编码目标函式的第一项解释为一个重构项,这一项迫使稀疏编码算法能为输入向量 <math>\mathbf{x}</math> 提供一个高拟合度的线性表达式,而公式第二项即“稀疏惩罚”项,它使 <math>\mathbf{x}</math> 的表达式变得“稀疏”。常量 <math>\lambda</math> 是一个变换量,由它来控制这两项式子的相对重要性。 <br />
<br />
<br />
虽然“稀疏性”的最直接测度标准是 "<math>L_0</math>" 范式(<math>S(a_i) = \mathbf{1}(|a_i|>0)</math>),但这是不可微的,而且通常很难进行优化。在实际中,稀疏代价函数 <math>S(.)</math> 的普遍选择是<math>L_1</math> 范式代价函数 <math>S(a_i)=\left|a_i\right|_1 </math> 及对数代价函数 <math>S(a_i)=\log(1+a_i^2)</math> 。<br />
<br />
<br />
此外,很有可能因为减小 <math>a_i</math> 或增加 <math>\mathbf{\phi}_i</math> 至很大的常量,使得稀疏惩罚变得非常小。为防止此类事件发生,我们将限制 <math>\left|\left|\mathbf{\phi}\right|\right|^2</math> 要小于某常量 <math>C</math> 。包含了限制条件的稀疏编码代价函数的完整形式如下:<br />
<br />
:<math>\begin{array}{rc}<br />
\text{minimize}_{a^{(j)}_i,\mathbf{\phi}_{i}} & \sum_{j=1}^{m} \left|\left| \mathbf{x}^{(j)} - \sum_{i=1}^k a^{(j)}_i \mathbf{\phi}_{i}\right|\right|^{2} + \lambda \sum_{i=1}^{k}S(a^{(j)}_i) <br />
\\<br />
\text{subject to} & \left|\left|\mathbf{\phi}_i\right|\right|^2 \leq C, \forall i = 1,...,k <br />
\\<br />
\end{array}</math><br />
<br />
<br />
<br />
== 概率解释 [基于1996年Olshausen与Field的理论] ==<br />
<br />
到目前为止,我们所考虑的稀疏编码,是为了寻找到一个稀疏的、超完备基向量集,来覆盖我们的输入数据空间。现在换一种方式,我们可以从概率的角度出发,将稀疏编码算法当作一种“生成模型”。<br />
<br />
<br />
我们将自然图像建模问题看成是一种线性叠加,叠加元素包括 <math>k</math> 个独立的源特征 <math>\mathbf{\phi}_i</math> 以及加性噪声 <math>\nu</math> :<br />
<br />
:<math>\begin{align}<br />
\mathbf{x} = \sum_{i=1}^k a_i \mathbf{\phi}_{i} + \nu(\mathbf{x})<br />
\end{align}</math><br />
<br />
<br />
我们的目标是找到一组特征基向量 <math>\mathbf{\phi}</math> ,它使得图像的分布函数 <math>P(\mathbf{x}\mid\mathbf{\phi})</math> 尽可能地近似于输入数据的经验分布函数 <math>P^*(\mathbf{x})</math> 。一种实现方式是,最小化 <math>P^*(\mathbf{x})</math> 与 <math>P(\mathbf{x}\mid\mathbf{\phi})</math> 之间的 KL 散度,此 KL 散度表示如下:<br />
<br />
:<math>\begin{align}<br />
D(P^*(\mathbf{x})||P(\mathbf{x}\mid\mathbf{\phi})) = \int P^*(\mathbf{x}) \log \left(\frac{P^*(\mathbf{x})}{P(\mathbf{x}\mid\mathbf{\phi})}\right)d\mathbf{x}<br />
\end{align}</math> <br />
<br />
<br />
因为无论我们如何选择 <math>\mathbf{\phi}</math> ,经验分布函数 <math>P^*(\mathbf{x})</math> 都是常量,也就是说我们只需要最大化对数似然函数 <math>P(\mathbf{x}\mid\mathbf{\phi})</math> 。<br />
假设 <math>\nu</math> 是具有方差 <math>\sigma^2</math> 的高斯白噪音,则有下式:<br />
<br />
:<math>\begin{align}<br />
P(\mathbf{x} \mid \mathbf{a}, \mathbf{\phi}) = \frac{1}{Z} \exp\left(- \frac{(\mathbf{x}-\sum^{k}_{i=1} a_i \mathbf{\phi}_{i})^2}{2\sigma^2}\right)<br />
\end{align}</math><br />
<br />
<br />
为了确定分布 <math>P(\mathbf{x}\mid\mathbf{\phi})</math> ,我们需要指定先验分布 <math>P(\mathbf{a})</math> 。假定我们的特征变量是独立的,我们就可以将先验概率分解为:<br />
<br />
:<math>\begin{align}<br />
P(\mathbf{a}) = \prod_{i=1}^{k} P(a_i)<br />
\end{align}</math><br />
<br />
<br />
此时,我们将“稀疏”假设加入进来——假设任何一幅图像都是由相对较少的一些源特征组合起来的。因此,我们希望 <math>a_i</math> 的概率分布在零值附近是凸起的,而且峰值很高。一个方便的参数化先验分布就是:<br />
<br />
:<math>\begin{align}<br />
P(a_i) = \frac{1}{Z}\exp(-\beta S(a_i))<br />
\end{align}</math><br />
<br />
<br />
这里 <math>S(a_i)</math> 是决定先验分布的形状的函数。<br />
<br />
<br />
当定义了 <math>P(\mathbf{x} \mid \mathbf{a} , \mathbf{\phi})</math> 和 <math> P(\mathbf{a})</math> 后,我们就可以写出在由 <math>\mathbf{\phi}</math> 定义的模型之下的数据 <math>\mathbf{x}</math> 的概率分布:<br />
<br />
:<math>\begin{align}<br />
P(\mathbf{x} \mid \mathbf{\phi}) = \int P(\mathbf{x} \mid \mathbf{a}, \mathbf{\phi}) P(\mathbf{a}) d\mathbf{a}<br />
\end{align}</math><br />
<br />
<br />
那么,我们的问题就简化为寻找:<br />
<br />
:<math>\begin{align}<br />
\mathbf{\phi}^*=\text{argmax}_{\mathbf{\phi}} < \log(P(\mathbf{x} \mid \mathbf{\phi})) ><br />
\end{align}</math><br />
<br />
<br />
这里 <math><.></math> 表示的是输入数据的期望值。<br />
<br />
<br />
不幸的是,通过对 <math>\mathbf{a}</math> 的积分计算 <math>P(\mathbf{x} \mid \mathbf{\phi})</math> 通常是难以实现的。虽然如此,我们注意到如果 <math>P(\mathbf{x} \mid \mathbf{\phi})</math> 的分布(对于相应的 <math>\mathbf{a}</math> )足够陡峭的话,我们就可以用 <math>P(\mathbf{x} \mid \mathbf{\phi})</math> 的最大值来估算以上积分。估算方法如下:<br />
<br />
:<math>\begin{align}<br />
\mathbf{\phi}^{*'}=\text{argmax}_{\mathbf{\phi}} < \max_{\mathbf{a}} \log(P(\mathbf{x} \mid \mathbf{\phi})) ><br />
\end{align}</math><br />
<br />
<br />
跟之前一样,我们可以通过减小 <math>a_i</math> 或增大 <math>\mathbf{\phi}</math> 来增加概率的估算值(因为 <math>P(a_i)</math> 在零值附近陡升)。因此我们要对特征向量 <math>\mathbf{\phi}</math> 加一个限制以防止这种情况发生。<br />
<br />
最后,我们可以定义一种线性生成模型的能量函数,从而将原先的代价函数重新表述为:<br />
<br />
:<math>\begin{array}{rl}<br />
E\left( \mathbf{x} , \mathbf{a} \mid \mathbf{\phi} \right) & := -\log \left( P(\mathbf{x}\mid \mathbf{\phi},\mathbf{a}\right)P(\mathbf{a})) \\<br />
&= \sum_{j=1}^{m} \left|\left| \mathbf{x}^{(j)} - \sum_{i=1}^k a^{(j)}_i \mathbf{\phi}_{i}\right|\right|^{2} + \lambda \sum_{i=1}^{k}S(a^{(j)}_i) <br />
\end{array}</math><br />
<br />
<br />
其中 <math>\lambda = 2\sigma^2\beta</math> ,并且关系不大的常量已被隐藏起来。因为最大化对数似然函数等同于最小化能量函数,我们就可以将原先的优化问题重新表述为:<br />
<br />
:<math>\begin{align}<br />
\mathbf{\phi}^{*},\mathbf{a}^{*}=\text{argmin}_{\mathbf{\phi},\mathbf{a}} \sum_{j=1}^{m} \left|\left| \mathbf{x}^{(j)} - \sum_{i=1}^k a^{(j)}_i \mathbf{\phi}_{i}\right|\right|^{2} + \lambda \sum_{i=1}^{k}S(a^{(j)}_i) <br />
\end{align}</math><br />
<br />
<br />
使用概率理论来分析,我们可以发现,选择 <math>L_1</math> 惩罚和 <math>\log(1+a_i^2)</math> 惩罚作为函数 <math>S(.)</math> ,分别对应于使用了拉普拉斯概率 <math>P(a_i) \propto \exp\left(-\beta|a_i|\right)</math> 和柯西先验概率 <math>P(a_i) \propto \frac{\beta}{1+a_i^2}</math> 。<br />
<br />
<br />
== 学习算法 ==<br />
<br />
使用稀疏编码算法学习基向量集的方法,是由两个独立的优化过程组合起来的。第一个是逐个使用训练样本 <math>\mathbf{x}</math> 来优化系数 <math>a_i</math> ,第二个是一次性处理多个样本对基向量 <math>\mathbf{\phi}</math> 进行优化。<br />
<br />
<br />
如果使用 <math>L_1</math> 范式作为稀疏惩罚函数,对 <math>a^{(j)}_i</math> 的学习过程就简化为求解 由 <math>L_1</math> 范式正则化的最小二乘法问题,这个问题函数在域 <math>a^{(j)}_i</math> 内为凸,已经有很多技术方法来解决这个问题(诸如CVX之类的凸优化软件可以用来解决L1正则化的最小二乘法问题)。如果 <math>S(.)</math> 是可微的,比如是对数惩罚函数,则可以采用基于梯度算法的方法,如共轭梯度法。<br />
<br />
<br />
用 <math>L_2</math> 范式约束来学习基向量,同样可以简化为一个带有二次约束的最小二乘问题,其问题函数在域 <math>\mathbf{\phi}</math> 内也为凸。标准的凸优化软件(如CVX)或其它迭代方法就可以用来求解 <math>\mathbf{\phi}</math>,虽然已经有了更有效的方法,比如求解拉格朗日对偶函数(Lagrange dual)。<br />
<br />
<br />
根据前面的的描述,稀疏编码是有一个明显的局限性的,这就是即使已经学习得到一组基向量,如果为了对新的数据样本进行“编码”,我们必须再次执行优化过程来得到所需的系数。这个显著的“实时”消耗意味着,即使是在测试中,实现稀疏编码也需要高昂的计算成本,尤其是与典型的前馈结构算法相比。<br />
<br />
<br />
==中英文对照==<br />
<br />
<br />
==中文译者==<br />
<br />
柳翠寅(liucuiyin@163.com),林锋(xlfg@yeah.net),王方(fangkey@gmail.com)<br />
<br />
<br />
<br />
{{Languages|Sparse_Coding|English}}</div>
Kandeng
http://ufldl.stanford.edu/wiki/index.php/Sparse_Coding
Sparse Coding
2013-04-08T04:28:55Z
<p>Kandeng: </p>
<hr />
<div>== Sparse Coding ==<br />
Sparse coding is a class of unsupervised methods for learning sets of over-complete bases to represent data efficiently. The aim of sparse coding is to find a set of basis vectors <math>\mathbf{\phi}_i</math> such that we can represent an input vector <math>\mathbf{x}</math> as a linear combination of these basis vectors:<br />
<br />
:<math>\begin{align}<br />
\mathbf{x} = \sum_{i=1}^k a_i \mathbf{\phi}_{i} <br />
\end{align}</math><br />
<br />
While techniques such as Principal Component Analysis (PCA) allow us to learn a complete set of basis vectors efficiently, we wish to learn an '''over-complete''' set of basis vectors to represent input vectors <math>\mathbf{x}\in\mathbb{R}^n</math> (i.e. such that <math>k > n</math>). The advantage of having an over-complete basis is that our basis vectors are better able to capture structures and patterns inherent in the input data. However, with an over-complete basis, the coefficients <math>a_i</math> are no longer uniquely determined by the input vector <math>\mathbf{x}</math>. Therefore, in sparse coding, we introduce the additional criterion of '''sparsity''' to resolve the degeneracy introduced by over-completeness. <br />
<br />
Here, we define sparsity as having few non-zero components or having few components not close to zero. The requirement that our coefficients <math>a_i</math> be sparse means that given a input vector, we would like as few of our coefficients to be far from zero as possible. The choice of sparsity as a desired characteristic of our representation of the input data can be motivated by the observation that most sensory data such as natural images may be described as the superposition of a small number of atomic elements such as surfaces or edges. Other justifications such as comparisons to the properties of the primary visual cortex have also been advanced. <br />
<br />
We define the sparse coding cost function on a set of <math>m</math> input vectors as<br />
<br />
:<math>\begin{align}<br />
\text{minimize}_{a^{(j)}_i,\mathbf{\phi}_{i}} \sum_{j=1}^{m} \left|\left| \mathbf{x}^{(j)} - \sum_{i=1}^k a^{(j)}_i \mathbf{\phi}_{i}\right|\right|^{2} + \lambda \sum_{i=1}^{k}S(a^{(j)}_i)<br />
\end{align}</math><br />
<br />
where <math>S(.)</math> is a sparsity cost function which penalizes <math>a_i</math> for being far from zero. We can interpret the first term of the sparse coding objective as a reconstruction term which tries to force the algorithm to provide a good representation of <math>\mathbf{x}</math> and the second term as a sparsity penalty which forces our representation of <math>\mathbf{x}</math> to be sparse. The constant <math>\lambda</math> is a scaling constant to determine the relative importance of these two contributions. <br />
<br />
Although the most direct measure of sparsity is the "<math>L_0</math>" norm (<math>S(a_i) = \mathbf{1}(|a_i|>0)</math>), it is non-differentiable and difficult to optimize in general. In practice, common choices for the sparsity cost <math>S(.)</math> are the <math>L_1</math> penalty <math>S(a_i)=\left|a_i\right|_1 </math> and the log penalty <math>S(a_i)=\log(1+a_i^2)</math>.<br />
<br />
In addition, it is also possible to make the sparsity penalty arbitrarily small by scaling down <math>a_i</math> and scaling <math>\mathbf{\phi}_i</math> up by some large constant. To prevent this from happening, we will constrain <math>\left|\left|\mathbf{\phi}\right|\right|^2</math> to be less than some constant <math>C</math>. The full sparse coding cost function including our constraint on <math>\mathbf{\phi}</math> is<br />
<br />
:<math>\begin{array}{rc}<br />
\text{minimize}_{a^{(j)}_i,\mathbf{\phi}_{i}} & \sum_{j=1}^{m} \left|\left| \mathbf{x}^{(j)} - \sum_{i=1}^k a^{(j)}_i \mathbf{\phi}_{i}\right|\right|^{2} + \lambda \sum_{i=1}^{k}S(a^{(j)}_i) <br />
\\<br />
\text{subject to} & \left|\left|\mathbf{\phi}_i\right|\right|^2 \leq C, \forall i = 1,...,k <br />
\\<br />
\end{array}</math><br />
<br />
== Probabilistic Interpretation [Based on Olshausen and Field 1996] ==<br />
So far, we have considered sparse coding in the context of finding a sparse, over-complete set of basis vectors to span our input space. Alternatively, we may also approach sparse coding from a probabilistic perspective as a generative model. <br />
<br />
Consider the problem of modelling natural images as the linear superposition of <math>k</math> independent source features <math>\mathbf{\phi}_i</math> with some additive noise <math>\nu</math>:<br />
:<math>\begin{align}<br />
\mathbf{x} = \sum_{i=1}^k a_i \mathbf{\phi}_{i} + \nu(\mathbf{x})<br />
\end{align}</math><br />
Our goal is to find a set of basis feature vectors <math>\mathbf{\phi}</math> such that the distribution of images <math>P(\mathbf{x}\mid\mathbf{\phi})</math> is as close as possible to the empirical distribution of our input data <math>P^*(\mathbf{x})</math>. One method of doing so is to minimize the KL divergence between <math>P^*(\mathbf{x})</math> and <math>P(\mathbf{x}\mid\mathbf{\phi})</math> where the KL divergence is defined as:<br />
<br />
:<math>\begin{align}<br />
D(P^*(\mathbf{x})||P(\mathbf{x}\mid\mathbf{\phi})) = \int P^*(\mathbf{x}) \log \left(\frac{P^*(\mathbf{x})}{P(\mathbf{x}\mid\mathbf{\phi})}\right)d\mathbf{x}<br />
\end{align}</math> <br />
<br />
Since the empirical distribution <math>P^*(\mathbf{x})</math> is constant across our choice of <math>\mathbf{\phi}</math>, this is equivalent to maximizing the log-likelihood of <math>P(\mathbf{x}\mid\mathbf{\phi})</math>.<br />
<br />
Assuming <math>\nu</math> is Gaussian white noise with variance <math>\sigma^2</math>, we have that <br />
:<math>\begin{align}<br />
P(\mathbf{x} \mid \mathbf{a}, \mathbf{\phi}) = \frac{1}{Z} \exp\left(- \frac{(\mathbf{x}-\sum^{k}_{i=1} a_i \mathbf{\phi}_{i})^2}{2\sigma^2}\right)<br />
\end{align}</math><br />
In order to determine the distribution <math>P(\mathbf{x}\mid\mathbf{\phi})</math>, we also need to specify the prior distribution <math>P(\mathbf{a})</math>. Assuming the independence of our source features, we can factorize our prior probability as <br />
<br />
:<math>\begin{align}<br />
P(\mathbf{a}) = \prod_{i=1}^{k} P(a_i)<br />
\end{align}</math><br />
<br />
At this point, we would like to incorporate our sparsity assumption -- the assumption that any single image is likely to be the product of relatively few source features. Therefore, we would like the probability distribution of <math>a_i</math> to be peaked at zero and have high kurtosis. A convenient parameterization of the prior distribution is <br />
<br />
:<math>\begin{align}<br />
P(a_i) = \frac{1}{Z}\exp(-\beta S(a_i))<br />
\end{align}</math><br />
<br />
Where <math>S(a_i)</math> is a function determining the shape of the prior distribution.<br />
<br />
Having defined <math>P(\mathbf{x} \mid \mathbf{a}, \mathbf{\phi})</math> and <math> P(\mathbf{a})</math>, we can write the probability of the data <math>\mathbf{x}</math> under the model defined by <math>\mathbf{\phi}</math> as <br />
<br />
:<math>\begin{align}<br />
P(\mathbf{x} \mid \mathbf{\phi}) = \int P(\mathbf{x} \mid \mathbf{a}, \mathbf{\phi}) P(\mathbf{a}) d\mathbf{a}<br />
\end{align}</math><br />
<br />
and our problem reduces to finding<br />
<br />
:<math>\begin{align}<br />
\mathbf{\phi}^*=\text{argmax}_{\mathbf{\phi}} < \log(P(\mathbf{x} \mid \mathbf{\phi})) ><br />
\end{align}</math><br />
<br />
Where <math><.></math> denotes expectation over our input data. <br />
<br />
Unfortunately, the integral over <math>\mathbf{a}</math> to obtain <math>P(\mathbf{x} \mid \mathbf{\phi})</math> is generally intractable. We note though that if the distribution of <math>P(\mathbf{x} \mid \mathbf{\phi})</math> is sufficiently peaked (w.r.t. <math>\mathbf{a}</math>), we can approximate its integral with the maximum value of <math>P(\mathbf{x} \mid \mathbf{\phi})</math> and obtain a approximate solution <br />
:<math>\begin{align}<br />
\mathbf{\phi}^{*'}=\text{argmax}_{\mathbf{\phi}} < \max_{\mathbf{a}} \log(P(\mathbf{x} \mid \mathbf{\phi})) ><br />
\end{align}</math><br />
<br />
As before, we may increase the estimated probability by scaling down <math>a_i</math> and scaling up <math>\mathbf{\phi}</math> (since <math>P(a_i)</math> peaks about zero) , we therefore impose a norm constraint on our features <math>\mathbf{\phi}</math> to prevent this.<br />
<br />
Finally, we can recover our original cost function by defining the energy function of this linear generative model<br />
:<math>\begin{array}{rl}<br />
E\left( \mathbf{x} , \mathbf{a} \mid \mathbf{\phi} \right) & := -\log \left( P(\mathbf{x}\mid \mathbf{\phi},\mathbf{a}\right)P(\mathbf{a})) \\<br />
&= \sum_{j=1}^{m} \left|\left| \mathbf{x}^{(j)} - \sum_{i=1}^k a^{(j)}_i \mathbf{\phi}_{i}\right|\right|^{2} + \lambda \sum_{i=1}^{k}S(a^{(j)}_i) <br />
\end{array}</math><br />
where <math>\lambda = 2\sigma^2\beta</math> and irrelevant constants have been hidden. Since maximizing the log-likelihood is equivalent to minimizing the energy function, we recover the original optimization problem:<br />
:<math>\begin{align}<br />
\mathbf{\phi}^{*},\mathbf{a}^{*}=\text{argmin}_{\mathbf{\phi},\mathbf{a}} \sum_{j=1}^{m} \left|\left| \mathbf{x}^{(j)} - \sum_{i=1}^k a^{(j)}_i \mathbf{\phi}_{i}\right|\right|^{2} + \lambda \sum_{i=1}^{k}S(a^{(j)}_i) <br />
\end{align}</math><br />
<br />
Using a probabilistic approach, it can also be seen that the choices of the <math>L_1</math> penalty <math>\left|a_i\right|_1 </math> and the log penalty <math>\log(1+a_i^2)</math> for <math>S(.)</math> correspond to the use of the Laplacian <math>P(a_i) \propto \exp\left(-\beta|a_i|\right)</math> and the Cauchy prior <math>P(a_i) \propto \frac{\beta}{1+a_i^2}</math> respectively.<br />
<br />
== Learning ==<br />
Learning a set of basis vectors <math>\mathbf{\phi}</math> using sparse coding consists of performing two separate optimizations, the first being an optimization over coefficients <math>a_i</math> for each training example <math>\mathbf{x}</math> and the second an optimization over basis vectors <math>\mathbf{\phi}</math> across many training examples at once.<br />
<br />
Assuming an <math>L_1</math> sparsity penalty, learning <math>a^{(j)}_i</math> reduces to solving a <math>L_1</math> regularized least squares problem which is convex in <math>a^{(j)}_i</math> for which several techniques have been developed (convex optimization software such as CVX can also be used to perform L1 regularized least squares). Assuming a differentiable <math>S(.)</math> such as the log penalty, gradient-based methods such as conjugate gradient methods can also be used.<br />
<br />
Learning a set of basis vectors with a <math>L_2</math> norm constraint also reduces to a least squares problem with quadratic constraints which is convex in <math>\mathbf{\phi}</math>. Standard convex optimization software (e.g. CVX) or other iterative methods can be used to solve for <math>\mathbf{\phi}</math> although significantly more efficient methods such as solving the Lagrange dual have also been developed.<br />
<br />
As described above, a significant limitation of sparse coding is that even after a set of basis vectors have been learnt, in order to "encode" a new data example, optimization must be performed to obtain the required coefficients. This significant "runtime" cost means that sparse coding is computationally expensive to implement even at test time especially compared to typical feedforward architectures.<br />
<br />
<br />
<br />
{{Languages|稀疏编码|中文}}</div>
Kandeng
http://ufldl.stanford.edu/wiki/index.php/%E7%A8%80%E7%96%8F%E7%BC%96%E7%A0%81
稀疏编码
2013-04-08T04:28:13Z
<p>Kandeng: </p>
<hr />
<div>== 稀疏编码 ==<br />
<br />
稀疏编码算法是一种无监督学习方法,它用来寻找一组“超完备”基向量来更高效地表示样本数据。稀疏编码算法的目的就是找到一组基向量 <math>\mathbf{\phi}_i</math> ,使得我们能将输入向量 <math>\mathbf{x}</math> 表示为这些基向量的线性组合:<br />
<br />
:<math>\begin{align}<br />
\mathbf{x} = \sum_{i=1}^k a_i \mathbf{\phi}_{i} <br />
\end{align}</math><br />
<br />
<br />
虽然形如主成分分析技术(PCA)能使我们方便地找到一组“完备”基向量,但是这里我们想要做的是找到一组'''“超完备”'''基向量来表示输入向量 <math>\mathbf{x}\in\mathbb{R}^n</math> (也就是说,<math>k > n</math>)。超完备基的好处是它们能更有效地找出隐含在输入数据内部的结构与模式。然而,对于超完备基来说,系数 <math>a_i</math> 不再由输入向量 <math>\mathbf{x}</math> 唯一确定。因此,在稀疏编码算法中,我们另加了一个评判标准'''“稀疏性”'''来解决因超完备而导致的退化(degeneracy)问题。<br />
<br />
<br />
这里,我们把“稀疏性”定义为:只有很少的几个非零元素或只有很少的几个远大于零的元素。要求系数 <math>a_i</math> 是稀疏的意思就是说:对于一组输入向量,我们只想有尽可能少的几个系数远大于零。选择使用具有稀疏性的分量来表示我们的输入数据是有原因的,因为绝大多数的感官数据,比如自然图像,可以被表示成少量基本元素的叠加,在图像中这些基本元素可以是面或者线。同时,比如与初级视觉皮层的类比过程也因此得到了提升。<br />
<br />
<br />
我们把有 <math>m</math> 个输入向量的稀疏编码代价函数定义为:<br />
<br />
:<math>\begin{align}<br />
\text{minimize}_{a^{(j)}_i,\mathbf{\phi}_{i}} \sum_{j=1}^{m} \left|\left| \mathbf{x}^{(j)} - \sum_{i=1}^k a^{(j)}_i \mathbf{\phi}_{i}\right|\right|^{2} + \lambda \sum_{i=1}^{k}S(a^{(j)}_i)<br />
\end{align}</math><br />
<br />
<br />
此处 <math>S(.)</math> 是一个稀疏代价函数,由它来对远大于零的 <math>a_i</math> 进行“惩罚”。我们可以把稀疏编码目标函式的第一项解释为一个重构项,这一项迫使稀疏编码算法能为输入向量 <math>\mathbf{x}</math> 提供一个高拟合度的线性表达式,而公式第二项即“稀疏惩罚”项,它使 <math>\mathbf{x}</math> 的表达式变得“稀疏”。常量 <math>\lambda</math> 是一个变换量,由它来控制这两项式子的相对重要性。 <br />
<br />
<br />
虽然“稀疏性”的最直接测度标准是 "<math>L_0</math>" 范式(<math>S(a_i) = \mathbf{1}(|a_i|>0)</math>),但这是不可微的,而且通常很难进行优化。在实际中,稀疏代价函数 <math>S(.)</math> 的普遍选择是<math>L_1</math> 范式代价函数 <math>S(a_i)=\left|a_i\right|_1 </math> 及对数代价函数 <math>S(a_i)=\log(1+a_i^2)</math> 。<br />
<br />
<br />
此外,很有可能因为减小 <math>a_i</math> 或增加 <math>\mathbf{\phi}_i</math> 至很大的常量,使得稀疏惩罚变得非常小。为防止此类事件发生,我们将限制 <math>\left|\left|\mathbf{\phi}\right|\right|^2</math> 要小于某常量 <math>C</math> 。包含了限制条件的稀疏编码代价函数的完整形式如下:<br />
<br />
:<math>\begin{array}{rc}<br />
\text{minimize}_{a^{(j)}_i,\mathbf{\phi}_{i}} & \sum_{j=1}^{m} \left|\left| \mathbf{x}^{(j)} - \sum_{i=1}^k a^{(j)}_i \mathbf{\phi}_{i}\right|\right|^{2} + \lambda \sum_{i=1}^{k}S(a^{(j)}_i) <br />
\\<br />
\text{subject to} & \left|\left|\mathbf{\phi}_i\right|\right|^2 \leq C, \forall i = 1,...,k <br />
\\<br />
\end{array}</math><br />
<br />
<br />
<br />
== 概率解释 [基于1996年Olshausen与Field的理论] ==<br />
<br />
到目前为止,我们所考虑的稀疏编码,是为了寻找到一个稀疏的、超完备基向量集,来覆盖我们的输入数据空间。现在换一种方式,我们可以从概率的角度出发,将稀疏编码算法当作一种“生成模型”。<br />
<br />
<br />
我们将自然图像建模问题看成是一种线性叠加,叠加元素包括 <math>k</math> 个独立的源特征 <math>\mathbf{\phi}_i</math> 以及加性噪声 <math>\nu</math> :<br />
<br />
:<math>\begin{align}<br />
\mathbf{x} = \sum_{i=1}^k a_i \mathbf{\phi}_{i} + \nu(\mathbf{x})<br />
\end{align}</math><br />
<br />
<br />
我们的目标是找到一组特征基向量 <math>\mathbf{\phi}</math> ,它使得图像的分布函数 <math>P(\mathbf{x}\mid\mathbf{\phi})</math> 尽可能地近似于输入数据的经验分布函数 <math>P^*(\mathbf{x})</math> 。一种实现方式是,最小化 <math>P^*(\mathbf{x})</math> 与 <math>P(\mathbf{x}\mid\mathbf{\phi})</math> 之间的 KL 散度,此 KL 散度表示如下:<br />
<br />
:<math>\begin{align}<br />
D(P^*(\mathbf{x})||P(\mathbf{x}\mid\mathbf{\phi})) = \int P^*(\mathbf{x}) \log \left(\frac{P^*(\mathbf{x})}{P(\mathbf{x}\mid\mathbf{\phi})}\right)d\mathbf{x}<br />
\end{align}</math> <br />
<br />
<br />
因为无论我们如何选择 <math>\mathbf{\phi}</math> ,经验分布函数 <math>P^*(\mathbf{x})</math> 都是常量,也就是说我们只需要最大化对数似然函数 <math>P(\mathbf{x}\mid\mathbf{\phi})</math> 。<br />
假设 <math>\nu</math> 是具有方差 <math>\sigma^2</math> 的高斯白噪音,则有下式:<br />
<br />
:<math>\begin{align}<br />
P(\mathbf{x} \mid \mathbf{a}, \mathbf{\phi}) = \frac{1}{Z} \exp\left(- \frac{(\mathbf{x}-\sum^{k}_{i=1} a_i \mathbf{\phi}_{i})^2}{2\sigma^2}\right)<br />
\end{align}</math><br />
<br />
<br />
为了确定分布 <math>P(\mathbf{x}\mid\mathbf{\phi})</math> ,我们需要指定先验分布 <math>P(\mathbf{a})</math> 。假定我们的特征变量是独立的,我们就可以将先验概率分解为:<br />
<br />
:<math>\begin{align}<br />
P(\mathbf{a}) = \prod_{i=1}^{k} P(a_i)<br />
\end{align}</math><br />
<br />
<br />
此时,我们将“稀疏”假设加入进来——假设任何一幅图像都是由相对较少的一些源特征组合起来的。因此,我们希望 <math>a_i</math> 的概率分布在零值附近是凸起的,而且峰值很高。一个方便的参数化先验分布就是:<br />
<br />
:<math>\begin{align}<br />
P(a_i) = \frac{1}{Z}\exp(-\beta S(a_i))<br />
\end{align}</math><br />
<br />
<br />
这里 <math>S(a_i)</math> 是决定先验分布的形状的函数。<br />
<br />
<br />
当定义了 <math>P(\mathbf{x} \mid \mathbf{a} , \mathbf{\phi})</math> 和 <math> P(\mathbf{a})</math> 后,我们就可以写出在由 <math>\mathbf{\phi}</math> 定义的模型之下的数据 <math>\mathbf{x}</math> 的概率分布:<br />
<br />
:<math>\begin{align}<br />
P(\mathbf{x} \mid \mathbf{\phi}) = \int P(\mathbf{x} \mid \mathbf{a}, \mathbf{\phi}) P(\mathbf{a}) d\mathbf{a}<br />
\end{align}</math><br />
<br />
<br />
那么,我们的问题就简化为寻找:<br />
<br />
:<math>\begin{align}<br />
\mathbf{\phi}^*=\text{argmax}_{\mathbf{\phi}} < \log(P(\mathbf{x} \mid \mathbf{\phi})) ><br />
\end{align}</math><br />
<br />
<br />
这里 <math><.></math> 表示的是输入数据的期望值。<br />
<br />
<br />
不幸的是,通过对 <math>\mathbf{a}</math> 的积分计算 <math>P(\mathbf{x} \mid \mathbf{\phi})</math> 通常是难以实现的。虽然如此,我们注意到如果 <math>P(\mathbf{x} \mid \mathbf{\phi})</math> 的分布(对于相应的 <math>\mathbf{a}</math> )足够陡峭的话,我们就可以用 <math>P(\mathbf{x} \mid \mathbf{\phi})</math> 的最大值来估算以上积分。估算方法如下:<br />
<br />
:<math>\begin{align}<br />
\mathbf{\phi}^{*'}=\text{argmax}_{\mathbf{\phi}} < \max_{\mathbf{a}} \log(P(\mathbf{x} \mid \mathbf{\phi})) ><br />
\end{align}</math><br />
<br />
<br />
跟之前一样,我们可以通过减小 <math>a_i</math> 或增大 <math>\mathbf{\phi}</math> 来增加概率的估算值(因为 <math>P(a_i)</math> 在零值附近陡升)。因此我们要对特征向量 <math>\mathbf{\phi}</math> 加一个限制以防止这种情况发生。<br />
<br />
最后,我们可以定义一种线性生成模型的能量函数,从而将原先的代价函数重新表述为:<br />
<br />
:<math>\begin{array}{rl}<br />
E\left( \mathbf{x} , \mathbf{a} \mid \mathbf{\phi} \right) & := -\log \left( P(\mathbf{x}\mid \mathbf{\phi},\mathbf{a}\right)P(\mathbf{a})) \\<br />
&= \sum_{j=1}^{m} \left|\left| \mathbf{x}^{(j)} - \sum_{i=1}^k a^{(j)}_i \mathbf{\phi}_{i}\right|\right|^{2} + \lambda \sum_{i=1}^{k}S(a^{(j)}_i) <br />
\end{array}</math><br />
<br />
<br />
其中 <math>\lambda = 2\sigma^2\beta</math> ,并且关系不大的常量已被隐藏起来。因为最大化对数似然函数等同于最小化能量函数,我们就可以将原先的优化问题重新表述为:<br />
<br />
:<math>\begin{align}<br />
\mathbf{\phi}^{*},\mathbf{a}^{*}=\text{argmin}_{\mathbf{\phi},\mathbf{a}} \sum_{j=1}^{m} \left|\left| \mathbf{x}^{(j)} - \sum_{i=1}^k a^{(j)}_i \mathbf{\phi}_{i}\right|\right|^{2} + \lambda \sum_{i=1}^{k}S(a^{(j)}_i) <br />
\end{align}</math><br />
<br />
<br />
使用概率理论来分析,我们可以发现,选择 <math>L_1</math> 惩罚和 <math>\log(1+a_i^2)</math> 惩罚作为函数 <math>S(.)</math> ,分别对应于使用了拉普拉斯概率 <math>P(a_i) \propto \exp\left(-\beta|a_i|\right)</math> 和柯西先验概率 <math>P(a_i) \propto \frac{\beta}{1+a_i^2}</math> 。<br />
<br />
<br />
== 学习算法 ==<br />
<br />
使用稀疏编码算法学习基向量集的方法,是由两个独立的优化过程组合起来的。第一个是逐个使用训练样本 <math>\mathbf{x}</math> 来优化系数 <math>a_i</math> ,第二个是一次性处理多个样本对基向量 <math>\mathbf{\phi}</math> 进行优化。<br />
<br />
<br />
如果使用 <math>L_1</math> 范式作为稀疏惩罚函数,对 <math>a^{(j)}_i</math> 的学习过程就简化为求解 由 <math>L_1</math> 范式正则化的最小二乘法问题,这个问题函数在域 <math>a^{(j)}_i</math> 内为凸,已经有很多技术方法来解决这个问题(诸如CVX之类的凸优化软件可以用来解决L1正则化的最小二乘法问题)。如果 <math>S(.)</math> 是可微的,比如是对数惩罚函数,则可以采用基于梯度算法的方法,如共轭梯度法。<br />
<br />
<br />
用 <math>L_2</math> 范式约束来学习基向量,同样可以简化为一个带有二次约束的最小二乘问题,其问题函数在域 <math>\mathbf{\phi}</math> 内也为凸。标准的凸优化软件(如CVX)或其它迭代方法就可以用来求解 <math>\mathbf{\phi}</math>,虽然已经有了更有效的方法,比如求解拉格朗日对偶函数(Lagrange dual)。<br />
<br />
<br />
根据前面的的描述,稀疏编码是有一个明显的局限性的,这就是即使已经学习得到一组基向量,如果为了对新的数据样本进行“编码”,我们必须再次执行优化过程来得到所需的系数。这个显著的“实时”消耗意味着,即使是在测试中,实现稀疏编码也需要高昂的计算成本,尤其是与典型的前馈结构算法相比。<br />
<br />
<br />
==中文译者==<br />
<br />
柳翠寅(liucuiyin@163.com),林锋(xlfg@yeah.net),王方(fangkey@gmail.com)<br />
<br />
<br />
<br />
{{Languages|Sparse_Coding|English}}</div>
Kandeng
http://ufldl.stanford.edu/wiki/index.php/Deriving_gradients_using_the_backpropagation_idea
Deriving gradients using the backpropagation idea
2013-04-08T04:26:46Z
<p>Kandeng: </p>
<hr />
<div>== Introduction ==<br />
<br />
In the section on the [[Backpropagation Algorithm | backpropagation algorithm]], you were briefly introduced to backpropagation as a means of deriving gradients for learning in the sparse autoencoder. It turns out that together with matrix calculus, this provides a powerful method and intuition for deriving gradients for more complex matrix functions (functions from matrices to the reals, or symbolically, from <math>\mathbb{R}^{r \times c} \rightarrow \mathbb{R}</math>).<br />
<br />
First, recall the backpropagation idea, which we present in a modified form appropriate for our purposes below:<br />
<ol><br />
<li>For each output unit <math>i</math> in layer <math>n_l</math> (the final layer), set<br />
:<math><br />
\delta^{(n_l)}_i<br />
= \frac{\partial}{\partial z^{(n_l)}_i} \;\;<br />
J(z^{(n_l)})<br />
</math><br />
where <math>J(z)</math> is our "objective function" (explained below).<br />
<li>For <math>l = n_l-1, n_l-2, n_l-3, \ldots, 2</math> <br />
:For each node <math>i</math> in layer <math>l</math>, set<br />
::<math><br />
\delta^{(l)}_i = \left( \sum_{j=1}^{s_{l+1}} W^{(l)}_{ji} \delta^{(l+1)}_j \right) \bullet \frac{\partial}{\partial z^{(l)}_i} f^{(l)} (z^{(l)}_i)<br />
</math><br />
<li>Compute the desired partial derivatives,<br />
:<math><br />
\begin{align}<br />
\nabla_{W^{(l)}} J(W,b;x,y) &= \delta^{(l+1)} (a^{(l)})^T, \\<br />
\end{align}<br />
</math><br />
</ol><br />
<br />
Quick notation recap: <br />
<ul><br />
<li><math>l</math> is the number of layers in the neural network<br />
<li><math>n_l</math> is the number of neurons in the <math>l</math>th layer<br />
<li><math>W^{(l)}_{ji}</math> is the weight from the <math>i</math>th unit in the <math>l</math>th layer to the <math>j</math>th unit in the <math>(l + 1)</math>th layer<br />
<li><math>z^{(l)}_i</math> is the input to the <math>i</math>th unit in the <math>l</math>th layer<br />
<li><math>a^{(l)}_i</math> is the activation of the <math>i</math>th unit in the <math>l</math>th layer<br />
<li><math>A \bullet B</math> is the Hadamard or element-wise product, which for <math>r \times c</math> matrices <math>A</math> and <math>B</math> yields the <math>r \times c</math> matrix <math>C = A \bullet B</math> such that <math>C_{r, c} = A_{r, c} \cdot B_{r, c}</math><br />
<li><math>f^{(l)}</math> is the activation function for units in the <math>l</math>th layer<br />
</ul><br />
<br />
Let's say we have a function <math>F</math> that takes a matrix <math>X</math> and yields a real number. We would like to use the backpropagation idea to compute the gradient with respect to <math>X</math> of <math>F</math>, that is <math>\nabla_X F</math>. The general idea is to see the function <math>F</math> as a multi-layer neural network, and to derive the gradients using the backpropagation idea. <br />
<br />
To do this, we will set our "objective function" to be the function <math>J(z)</math> that when applied to the outputs of the neurons in the last layer yields the value <math>F(X)</math>. For the intermediate layers, we will also choose our activation functions <math>f^{(l)}</math> to this end.<br />
<br />
Using this method, we can easily compute derivatives with respect to the inputs <math>X</math>, as well as derivatives with respect to any of the weights in the network, as we shall see later.<br />
<br />
== Examples ==<br />
<br />
To illustrate the use of the backpropagation idea to compute derivatives with respect to the inputs, we will use two functions from the section on [[Sparse Coding: Autoencoder Interpretation | sparse coding]], in examples 1 and 2. In example 3, we use a function from [[Independent Component Analysis | independent component analysis]] to illustrate the use of this idea to compute derivates with respect to weights, and in this specific case, what to do in the case of tied or repeated weights.<br />
<br />
=== Example 1: Objective for weight matrix in sparse coding ===<br />
<br />
Recall for [[Sparse Coding: Autoencoder Interpretation | sparse coding]], the objective function for the weight matrix <math>A</math>, given the feature matrix <math>s</math>:<br />
:<math>F(A; s) = \lVert As - x \rVert_2^2 + \gamma \lVert A \rVert_2^2</math><br />
<br />
We would like to find the gradient of <math>F</math> with respect to <math>A</math>, or in symbols, <math>\nabla_A F(A)</math>. Since the objective function is a sum of two terms in <math>A</math>, the gradient is the sum of gradients of each of the individual terms. The gradient of the second term is trivial, so we will consider the gradient of the first term instead. <br />
<br />
The first term, <math>\lVert As - x \rVert_2^2</math>, can be seen as an instantiation of neural network taking <math>s</math> as an input, and proceeding in four steps, as described and illustrated in the paragraph and diagram below:<br />
<br />
<ol><br />
<li>Apply <math>A</math> as the weights from the first layer to the second layer.<br />
<li>Subtract <math>x</math> from the activation of the second layer, which uses the identity activation function.<br />
<li>Pass this unchanged to the third layer, via identity weights. Use the square function as the activation function for the third layer.<br />
<li>Sum all the activations of the third layer.<br />
</ol><br />
<br />
[[File:Backpropagation Method Example 1.png | 400px]]<br />
<br />
The weights and activation functions of this network are as follows:<br />
<table align="center"><br />
<tr><th width="50px">Layer</th><th width="200px">Weight</th><th width="200px">Activation function <math>f</math></th></tr><br />
<tr><br />
<td>1</td><br />
<td><math>A</math></td><br />
<td><math>f(z_i) = z_i</math> (identity)</td><br />
</tr><br />
<tr><br />
<td>2</td><br />
<td><math>I</math> (identity)</td><br />
<td><math>f(z_i) = z_i - x_i</math></td><br />
</tr><br />
<tr><br />
<td>3</td><br />
<td>N/A</td><br />
<td><math>f(z_i) = z_i^2</math></td><br />
</tr><br />
</table><br />
To have <math>J(z^{(3)}) = F(x)</math>, we can set <math>J(z^{(3)}) = \sum_k J(z^{(3)}_k)</math>.<br />
<br />
Once we see <math>F</math> as a neural network, the gradient <math>\nabla_X F</math> becomes easy to compute - applying backpropagation yields:<br />
<table align="center"><br />
<tr><th width="50px">Layer</th><th width="200px">Derivative of activation function <math>f'</math></th><th width="200px">Delta</th><th>Input <math>z</math> to this layer</th></tr><br />
<tr><br />
<td>3</td><br />
<td><math>f'(z_i) = 2z_i</math></td><br />
<td><math>f'(z_i) = 2z_i</math></td><br />
<td><math>As - x</math></td><br />
</tr><br />
<tr><br />
<td>2</td><br />
<td><math>f'(z_i) = 1</math></td><br />
<td><math>\left( I^T \delta^{(3)} \right) \bullet 1</math></td><br />
<td><math>As</math></td><br />
</tr><br />
<tr><br />
<td>1</td><br />
<td><math>f'(z_i) = 1</math></td><br />
<td><math>\left( A^T \delta^{(2)} \right) \bullet 1</math></td><br />
<td><math>s</math></td><br />
</tr><br />
</table><br />
<br />
Hence, <br />
:<math><br />
\begin{align}<br />
\nabla_X F & = A^T I^T 2(As - x) \\<br />
& = A^T 2(As - x)<br />
\end{align}<br />
</math> <br />
<br />
=== Example 2: Smoothed topographic L1 sparsity penalty in sparse coding ===<br />
<br />
Recall the smoothed topographic L1 sparsity penalty on <math>s</math> in [[Sparse Coding: Autoencoder Interpretation | sparse coding]]:<br />
:<math>\sum{ \sqrt{Vss^T + \epsilon} }</math><br />
where <math>V</math> is the grouping matrix, <math>s</math> is the feature matrix and <math>\epsilon</math> is a constant.<br />
<br />
We would like to find <math>\nabla_s \sum{ \sqrt{Vss^T + \epsilon} }</math>. As above, let's see this term as an instantiation of a neural network:<br />
<br />
[[File:Backpropagation Method Example 2.png | 600px]]<br />
<br />
The weights and activation functions of this network are as follows:<br />
<table align="center"><br />
<tr><th width="50px">Layer</th><th width="200px">Weight</th><th width="200px">Activation function <math>f</math></th></tr><br />
<tr><br />
<td>1</td><br />
<td><math>I</math></td><br />
<td><math>f(z_i) = z_i^2</math></td><br />
</tr><br />
<tr><br />
<td>2</td><br />
<td><math>V</math></td><br />
<td><math>f(z_i) = z_i</math></td><br />
</tr><br />
<tr><br />
<td>3</td><br />
<td><math>I</math></td><br />
<td><math>f(z_i) = z_i + \epsilon</math></td><br />
</tr><br />
<tr><br />
<td>4</td><br />
<td>N/A</td><br />
<td><math>f(z_i) = z_i^{\frac{1}{2}}</math></td><br />
</tr><br />
</table><br />
To have <math>J(z^{(4)}) = F(x)</math>, we can set <math>J(z^{(4)}) = \sum_k J(z^{(4)}_k)</math>.<br />
<br />
Once we see <math>F</math> as a neural network, the gradient <math>\nabla_X F</math> becomes easy to compute - applying backpropagation yields:<br />
<table align="center"><br />
<tr><th width="50px">Layer</th><th width="200px">Derivative of activation function <math>f'</math><br />
</th><th width="200px">Delta</th><th>Input <math>z</math> to this layer</th></tr><br />
<tr><br />
<td>4</td><br />
<td><math>f'(z_i) = \frac{1}{2} z_i^{-\frac{1}{2}}</math></td><br />
<td><math>f'(z_i) = \frac{1}{2} z_i^{-\frac{1}{2}}</math></td><br />
<td><math>(Vss^T + \epsilon)</math></td><br />
</tr><br />
<tr><br />
<td>3</td><br />
<td><math>f'(z_i) = 1</math></td><br />
<td><math>\left( I^T \delta^{(4)} \right) \bullet 1</math></td><br />
<td><math>Vss^T</math></td><br />
</tr><br />
<tr><br />
<td>2</td><br />
<td><math>f'(z_i) = 1</math></td><br />
<td><math>\left( V^T \delta^{(3)} \right) \bullet 1</math></td><br />
<td><math>ss^T</math></td><br />
</tr><br />
<tr><br />
<td>1</td><br />
<td><math>f'(z_i) = 2z_i</math></td><br />
<td><math>\left( I^T \delta^{(2)} \right) \bullet 2s</math></td><br />
<td><math>s</math></td><br />
</tr><br />
</table><br />
<br />
Hence, <br />
:<math><br />
\begin{align}<br />
\nabla_X F & = I^T V^T I^T \frac{1}{2}(Vss^T + \epsilon)^{-\frac{1}{2}} \bullet 2s \\<br />
& = V^T \frac{1}{2}(Vss^T + \epsilon)^{-\frac{1}{2}} \bullet 2s \\<br />
& = V^T (Vss^T + \epsilon)^{-\frac{1}{2}} \bullet s<br />
\end{align}<br />
</math><br />
<br />
=== Example 3: ICA reconstruction cost ===<br />
<br />
Recall the [[Independent Component Analysis | independent component analysis (ICA)]] reconstruction cost term:<br />
<math>\lVert W^TWx - x \rVert_2^2</math><br />
where <math>W</math> is the weight matrix and <math>x</math> is the input.<br />
<br />
We would like to find <math>\nabla_W \lVert W^TWx - x \rVert_2^2</math> - the derivative of the term with respect to the '''weight matrix''', rather than the '''input''' as in the earlier two examples. We will still proceed similarly though, seeing this term as an instantiation of a neural network:<br />
<br />
[[File:Backpropagation Method Example 3.png | 400px]]<br />
<br />
The weights and activation functions of this network are as follows:<br />
<table align="center"><br />
<tr><th width="50px">Layer</th><th width="200px">Weight</th><th width="200px">Activation function <math>f</math></th></tr><br />
<tr><br />
<td>1</td><br />
<td><math>W</math></td><br />
<td><math>f(z_i) = z_i</math></td><br />
</tr><br />
<tr><br />
<td>2</td><br />
<td><math>W^T</math></td><br />
<td><math>f(z_i) = z_i</math></td><br />
</tr><br />
<tr><br />
<td>3</td><br />
<td><math>I</math></td><br />
<td><math>f(z_i) = z_i - x_i</math></td><br />
</tr><br />
<tr><br />
<td>4</td><br />
<td>N/A</td><br />
<td><math>f(z_i) = z_i^2</math></td><br />
</tr><br />
</table><br />
To have <math>J(z^{(4)}) = F(x)</math>, we can set <math>J(z^{(4)}) = \sum_k J(z^{(4)}_k)</math>.<br />
<br />
Now that we can see <math>F</math> as a neural network, we can try to compute the gradient <math>\nabla_W F</math>. However, we now face the difficulty that <math>W</math> appears twice in the network. Fortunately, it turns out that if <math>W</math> appears multiple times in the network, the gradient with respect to <math>W</math> is simply the sum of gradients for each instance of <math>W</math> in the network (you may wish to work out a formal proof of this fact to convince yourself). With this in mind, we will proceed to work out the deltas first:<br />
<br />
<table align="center"><br />
<tr><th width="50px">Layer</th><th width="200px">Derivative of activation function <math>f'</math><br />
</th><th width="200px">Delta</th><th>Input <math>z</math> to this layer</th></tr><br />
<tr><br />
<td>4</td><br />
<td><math>f'(z_i) = 2z_i</math></td><br />
<td><math>f'(z_i) = 2z_i</math></td><br />
<td><math>(W^TWx - x)</math></td><br />
</tr><br />
<tr><br />
<td>3</td><br />
<td><math>f'(z_i) = 1</math></td><br />
<td><math>\left( I^T \delta^{(4)} \right) \bullet 1</math></td><br />
<td><math>W^TWx</math></td><br />
</tr><br />
<tr><br />
<td>2</td><br />
<td><math>f'(z_i) = 1</math></td><br />
<td><math>\left( (W^T)^T \delta^{(3)} \right) \bullet 1</math></td><br />
<td><math>Wx</math></td><br />
</tr><br />
<tr><br />
<td>1</td><br />
<td><math>f'(z_i) = 1</math></td><br />
<td><math>\left( W^T \delta^{(2)} \right) \bullet 1</math></td><br />
<td><math>x</math></td><br />
</tr><br />
</table><br />
<br />
To find the gradients with respect to <math>W</math>, first we find the gradients with respect to each instance of <math>W</math> in the network.<br />
<br />
With respect to <math>W^T</math>:<br />
:<math><br />
\begin{align}<br />
\nabla_{W^T} F & = \delta^{(3)} a^{(2)T} \\<br />
& = 2(W^TWx - x) (Wx)^T<br />
\end{align}<br />
</math><br />
<br />
With respect to <math>W</math>:<br />
:<math><br />
\begin{align}<br />
\nabla_{W} F & = \delta^{(2)} a^{(1)T} \\<br />
& = (W^T)(2(W^TWx -x)) x^T<br />
\end{align}<br />
</math><br />
<br />
Taking sums, noting that we need to transpose the gradient with respect to <math>W^T</math> to get the gradient with respect to <math>W</math>, yields the final gradient with respect to <math>W</math> (pardon the slight abuse of notation here):<br />
<br />
:<math><br />
\begin{align}<br />
\nabla_{W} F & = \nabla_{W} F + (\nabla_{W^T} F)^T \\<br />
& = (W^T)(2(W^TWx -x)) x^T + 2(Wx)(W^TWx - x)^T<br />
\end{align}<br />
</math><br />
<br />
<br />
<br />
{{Languages|用反向传导思想求导|中文}}</div>
Kandeng
http://ufldl.stanford.edu/wiki/index.php/%E7%94%A8%E5%8F%8D%E5%90%91%E4%BC%A0%E5%AF%BC%E6%80%9D%E6%83%B3%E6%B1%82%E5%AF%BC
用反向传导思想求导
2013-04-08T04:25:09Z
<p>Kandeng: </p>
<hr />
<div>== 简介 ==<br />
<br />
在[[ 反向传导算法 | 反向传导算法 ]]一节中,我们介绍了在稀疏自编码器中用反向传导算法来求梯度的方法。事实证明,反向传导算法与矩阵运算相结合的方法,对于计算复杂矩阵函数(从矩阵到实数的函数,或用符号表示为:从 <math>\mathbb{R}^{r \times c} \rightarrow \mathbb{R}</math> )的梯度是十分强大和直观的。<br />
<br />
<br />
首先,我们回顾一下反向传导的思想,为了更适合我们的目的,将其稍作修改呈现于下:<br />
<ol><br />
<li>对第 <math>n_l</math> 层(最后一层)中的每一个输出单元 <math>i</math> ,令<br />
:<math><br />
\delta^{(n_l)}_i<br />
= \frac{\partial}{\partial z^{(n_l)}_i} \;\;<br />
J(z^{(n_l)})<br />
</math><br />
其中 <math>J(z)</math> 是我们的“目标函数”(稍后解释)。<br />
<li>对 <math>l = n_l-1, n_l-2, n_l-3, \ldots, 2</math> , <br />
:对第 <math>l</math> 层中的每个节点 <math>i</math> , 令 <br />
::<math><br />
\delta^{(l)}_i = \left( \sum_{j=1}^{s_{l+1}} W^{(l)}_{ji} \delta^{(l+1)}_j \right) \bullet \frac{\partial}{\partial z^{(l)}_i} f^{(l)} (z^{(l)}_i)<br />
</math> <br />
<li>计算我们要的偏导数<br />
:<math><br />
\begin{align}<br />
\nabla_{W^{(l)}} J(W,b;x,y) &= \delta^{(l+1)} (a^{(l)})^T, \\<br />
\end{align}<br />
</math><br />
</ol><br />
<br />
<br />
符号扼要重述:<br />
<ul><br />
<li><math>l</math> 是神经网络的层数<br />
<li><math>n_l</math> 第l层神经元的个数<br />
<li><math>W^{(l)}_{ji}</math> 是 <math>l</math> 层第 <math>i</math> 个节点到第 <math>(l+1)</math> 层第 <math>j</math> 个节点的权重<br />
<li><math>z^{(l)}_i</math> 是第 <math>l</math> 层第 <math>i</math> 个单元的输入<br />
<li><math>a^{(l)}_i</math> 是第 <math>l</math> 层第 <math>i</math> 个节点的激励<br />
<li><math>A \bullet B</math> 是矩阵的Hadamard积或逐个元素乘积,对 <math>r \times c</math> 矩阵 <math>A</math> 和 <math>B</math> ,它们的乘积是 <math>r \times c</math> 矩阵 <math>C = A \bullet B</math> ,即 <math>C_{r, c} = A_{r, c} \cdot B_{r, c}</math> <br />
<li><math>f^{(l)}</math> 是第 <math>l</math> 层中各单元的激励函数<br />
</ul><br />
<br />
假设我们有一个函数 <math>F</math> , <math>F</math> 以矩阵 <math>X</math> 为参数生成一个实数。我们希望用反向传导思想计算 <math>F</math> 关于 <math>X</math> 的梯度,即 <math>\nabla_X F</math> 。大致思路是将函数 <math>F</math> 看成一个多层神经网络,并使用反向传导思想求梯度。<br />
<br />
为了实现这个想法,我们取目标函数为 <math>J(z)</math> ,当计算最后一层神经元的输出时,会产生值 <math>F(X)</math> 。对于中间层,我们将选择激励函数 <math>f^{(l)}</math> 。<br />
<br />
稍后我们会看到,使用这种方法,我们可以很容易计算出对于输入 <math>X</math> 以及网络中任意一个权重的导数。<br />
<br />
<br />
== 示例 ==<br />
<br />
为了阐述如何使用反向传导思想计算关于输入的导数,我们要在示例1,示例2中用 [[ 稀疏编码自编码表达 | 稀疏编码 ]] 章节中的两个函数。在示例3中,我们使用[[ 独立成分分析 | 独立成分分析 ]]一节中的一个函数来说明使用此思想计算关于权重的偏导的方法,以及在这种特殊情况下,如何处理相互捆绑或重复的权重。<br />
<br />
<br />
=== 示例1:稀疏编码中权重矩阵的目标函数 ===<br />
<br />
回顾一下[[ 稀疏编码自编码表达 | 稀疏编码 ]],当给定特征矩阵 <math>s</math> 时,权重矩阵 <math>A</math> 的目标函数为:<br />
<br />
:<math>F(A; s) = \lVert As - x \rVert_2^2 + \gamma \lVert A \rVert_2^2</math><br />
<br />
<br />
我们希望求 <math>F</math> 对于 <math>A</math> 的梯度,即 <math>\nabla_A F(A)</math> 。因为目标函数是两个含 <math>A</math> 的式子之和,所以它的梯度是每个式子的梯度之和。第二项的梯度很容易求,因此我们只考虑第一项的梯度。<br />
<br />
<br />
第一项, <math>\lVert As - x \rVert_2^2</math> ,可以看成一个用 <math>s</math> 做输入的神经网络的实例,通过四步进行计算,文字以及图形描述如下:<br />
<ol><br />
<li>把 <math>A</math> 作为第一层到第二层的权重。<br />
<li>将第二层的激励减 <math>x</math> ,第二层使用了单位激励函数。<br />
<li>通过单位权重将结果不变地传到第三层。在第三层使用平方函数作为激励函数。<br />
<li>将第三层的所有激励相加。<br />
</ol><br />
<br />
[[File:Backpropagation Method Example 1.png | 400px]]<br />
<br />
<br />
该网络的权重和激励函数如下表所示:<br />
<br />
<table align="center"><br />
<tr><th width="50px">层</th><th width="200px">权重</th><th width="200px">激励函数 <math>f</math></th></tr><br />
<tr><br />
<td>1</td><br />
<td><math>A</math></td><br />
<td><math>f(z_i) = z_i</math> (单位函数)</td><br />
</tr><br />
<tr><br />
<td>2</td><br />
<td><math>I</math> (单位向量)</td><br />
<td><math>f(z_i) = z_i - x_i</math></td><br />
</tr><br />
<tr><br />
<td>3</td><br />
<td>N/A</td><br />
<td><math>f(z_i) = z_i^2</math></td><br />
</tr><br />
</table><br />
<br />
为了使 <math>J(z^{(3)}) = F(x)</math> ,我们可令 <math>J(z^{(3)}) = \sum_k J(z^{(3)}_k)</math> 。<br />
<br />
一旦我们将 <math>F</math> 看成神经网络,梯度 <math>\nabla_X F</math> 就很容易求了——使用反向传导得到:<br />
<br />
<table align="center"><br />
<tr><th width="50px">层</th><th width="200px">激励函数的导数<math>f'</math></th><th width="200px">Delta</th><th>该层输入<math>z</math></th></tr><br />
<tr><br />
<td>3</td><br />
<td><math>f'(z_i) = 2z_i</math></td><br />
<td><math>f'(z_i) = 2z_i</math></td><br />
<td><math>As - x</math></td><br />
</tr><br />
<tr><br />
<td>2</td><br />
<td><math>f'(z_i) = 1</math></td><br />
<td><math>\left( I^T \delta^{(3)} \right) \bullet 1</math></td><br />
<td><math>As</math></td><br />
</tr><br />
<tr><br />
<td>1</td><br />
<td><math>f'(z_i) = 1</math></td><br />
<td><math>\left( A^T \delta^{(2)} \right) \bullet 1</math></td><br />
<td><math>s</math></td><br />
</tr><br />
</table><br />
<br />
<br />
因此<br />
<br />
:<math><br />
\begin{align}<br />
\nabla_X F & = A^T I^T 2(As - x) \\<br />
& = A^T 2(As - x)<br />
\end{align}<br />
</math><br />
<br />
<br />
=== 示例2:稀疏编码中的平滑地形L1稀疏罚函数 ===<br />
<br />
回顾[[ 稀疏编码自编码表达 | 稀疏编码 ]]一节中对 <math>s</math> 的平滑地形L1稀疏罚函数:<br />
<br />
:<math>\sum{ \sqrt{Vss^T + \epsilon} }</math><br />
<br />
其中 <math>V</math> 是分组矩阵, <math>s</math> 是特征矩阵, <math>\epsilon</math> 是一个常数。<br />
<br />
我们希望求得 <math>\nabla_s \sum{ \sqrt{Vss^T + \epsilon} }</math> 。像上面那样,我们把这一项看做一个神经网络的实例:<br />
<br />
[[File:Backpropagation Method Example 2.png | 600px]]<br />
<br />
<br />
该网络的权重和激励函数如下表所示:<br />
<br />
<table align="center"><br />
<tr><th width="50px">层</th><th width="200px">权重</th><th width="200px">激励函数 <math>f</math></th></tr><br />
<tr><br />
<td>1</td><br />
<td><math>I</math></td><br />
<td><math>f(z_i) = z_i^2</math></td><br />
</tr><br />
<tr><br />
<td>2</td><br />
<td><math>V</math></td><br />
<td><math>f(z_i) = z_i</math></td><br />
</tr><br />
<tr><br />
<td>3</td><br />
<td><math>I</math></td><br />
<td><math>f(z_i) = z_i + \epsilon</math></td><br />
</tr><br />
<tr><br />
<td>4</td><br />
<td>N/A</td><br />
<td><math>f(z_i) = z_i^{\frac{1}{2}}</math></td><br />
</tr><br />
</table><br />
<br />
<br />
为使 <math>J(z^{(4)}) = F(x)</math> ,我们可令 <math>J(z^{(4)}) = \sum_k J(z^{(4)}_k)</math> 。<br />
<br />
一旦我们把 <math>F</math> 看做一个神经网络,梯度 <math>\nabla_X F</math> 变得很容易计算——使用反向传导得到:<br />
<br />
<table align="center"><br />
<tr><th width="50px">层</th><th width="200px">激励函数的导数 <math>f'</math><br />
</th><th width="200px">Delta</th><th>该层输入<math>z</math></th></tr><br />
<tr><br />
<td>4</td><br />
<td><math>f'(z_i) = \frac{1}{2} z_i^{-\frac{1}{2}}</math></td><br />
<td><math>f'(z_i) = \frac{1}{2} z_i^{-\frac{1}{2}}</math></td><br />
<td><math>(Vss^T + \epsilon)</math></td><br />
</tr><br />
<tr><br />
<td>3</td><br />
<td><math>f'(z_i) = 1</math></td><br />
<td><math>\left( I^T \delta^{(4)} \right) \bullet 1</math></td><br />
<td><math>Vss^T</math></td><br />
</tr><br />
<tr><br />
<td>2</td><br />
<td><math>f'(z_i) = 1</math></td><br />
<td><math>\left( V^T \delta^{(3)} \right) \bullet 1</math></td><br />
<td><math>ss^T</math></td><br />
</tr><br />
<tr><br />
<td>1</td><br />
<td><math>f'(z_i) = 2z_i</math></td><br />
<td><math>\left( I^T \delta^{(2)} \right) \bullet 2s</math></td><br />
<td><math>s</math></td><br />
</tr><br />
</table><br />
<br />
<br />
因此<br />
<br />
:<math><br />
\begin{align}<br />
\nabla_X F & = I^T V^T I^T \frac{1}{2}(Vss^T + \epsilon)^{-\frac{1}{2}} \bullet 2s \\<br />
& = V^T \frac{1}{2}(Vss^T + \epsilon)^{-\frac{1}{2}} \bullet 2s \\<br />
& = V^T (Vss^T + \epsilon)^{-\frac{1}{2}} \bullet s<br />
\end{align}<br />
</math><br />
<br />
<br />
=== 示例3:ICA重建代价 ===<br />
<br />
回顾 [[ 独立成分分析 | 独立成分分析(ICA) ]]一节重建代价一项: <math>\lVert W^TWx - x \rVert_2^2</math> ,其中 <math>W</math> 是权重矩阵, <math>x</math> 是输入。<br />
<br />
我们希望计算 <math>\nabla_W \lVert W^TWx - x \rVert_2^2</math> ——对于'''权重矩阵'''的导数,而不是像前两例中对于'''输入'''的导数。不过我们仍然用类似的方法处理,把该项看做一个神经网络的实例:<br />
<br />
[[File:Backpropagation Method Example 3.png | 400px]]<br />
<br />
<br />
该网络的权重和激励函数如下表所示:<br />
<br />
<table align="center"><br />
<tr><th width="50px">层</th><th width="200px">权重</th><th width="200px">激励函数 <math>f</math></th></tr><br />
<tr><br />
<td>1</td><br />
<td><math>W</math></td><br />
<td><math>f(z_i) = z_i</math></td><br />
</tr><br />
<tr><br />
<td>2</td><br />
<td><math>W^T</math></td><br />
<td><math>f(z_i) = z_i</math></td><br />
</tr><br />
<tr><br />
<td>3</td><br />
<td><math>I</math></td><br />
<td><math>f(z_i) = z_i - x_i</math></td><br />
</tr><br />
<tr><br />
<td>4</td><br />
<td>N/A</td><br />
<td><math>f(z_i) = z_i^2</math></td><br />
</tr><br />
</table><br />
<br />
为使 <math>J(z^{(4)}) = F(x)</math> ,我们可令 <math>J(z^{(4)}) = \sum_k J(z^{(4)}_k)</math> 。<br />
<br />
既然我们可将 <math>F</math> 看做神经网络,我们就能计算出梯度 <math>\nabla_W F</math> 。然而,我们现在面临的难题是 <math>W</math> 在网络中出现了两次。幸运的是,可以证明如果 <math>W</math> 在网络中出现多次,那么对于 <math>W</math> 的梯度是对网络中每个 <math>W</math> 实例的梯度的简单相加(你需要自己给出对这一事实的严格证明来说服自己)。知道这一点后,我们将首先计算delta:<br />
<br />
<table align="center"><br />
<tr><th width="50px">层</th><th width="200px">激励函数的导数 <math>f'</math><br />
</th><th width="200px">Delta</th><th>该层输入<math>z</math></th></tr><br />
<tr><br />
<td>4</td><br />
<td><math>f'(z_i) = 2z_i</math></td><br />
<td><math>f'(z_i) = 2z_i</math></td><br />
<td><math>(W^TWx - x)</math></td><br />
</tr><br />
<tr><br />
<td>3</td><br />
<td><math>f'(z_i) = 1</math></td><br />
<td><math>\left( I^T \delta^{(4)} \right) \bullet 1</math></td><br />
<td><math>W^TWx</math></td><br />
</tr><br />
<tr><br />
<td>2</td><br />
<td><math>f'(z_i) = 1</math></td><br />
<td><math>\left( (W^T)^T \delta^{(3)} \right) \bullet 1</math></td><br />
<td><math>Wx</math></td><br />
</tr><br />
<tr><br />
<td>1</td><br />
<td><math>f'(z_i) = 1</math></td><br />
<td><math>\left( W^T \delta^{(2)} \right) \bullet 1</math></td><br />
<td><math>x</math></td><br />
</tr><br />
</table><br />
<br />
为计算对于 <math>W</math> 的梯度,首先计算对网络中每个 <math>W</math> 实例的梯度。<br />
<br />
对于 <math>W^T</math> :<br />
<br />
:<math><br />
\begin{align}<br />
\nabla_{W^T} F & = \delta^{(3)} a^{(2)T} \\<br />
& = 2(W^TWx - x) (Wx)^T<br />
\end{align}<br />
</math><br />
<br />
对于 <math>W</math> :<br />
<br />
:<math><br />
\begin{align}<br />
\nabla_{W} F & = \delta^{(2)} a^{(1)T} \\<br />
& = (W^T)(2(W^TWx -x)) x^T<br />
\end{align}<br />
</math><br />
<br />
最后进行求和,得到对于 <math>W</math> 的最终梯度,注意我们需要对 <math>W^T</math> 梯度进行转置,来得到关于 <math>W</math> 的梯度(原谅我在这里稍稍滥用了符号):<br />
<br />
:<math><br />
\begin{align}<br />
\nabla_{W} F & = \nabla_{W} F + (\nabla_{W^T} F)^T \\<br />
& = (W^T)(2(W^TWx -x)) x^T + 2(Wx)(W^TWx - x)^T<br />
\end{align}<br />
</math><br />
<br />
<br />
<br />
==中英文对照==<br />
<br />
<br />
<br />
==中文译者==<br />
<br />
葛燕儒(yrgehi@gmail.com), 顾祺龙(ggnle@hotmail.com), 李良玥(jackiey99@gmail.com), 王方(fangkey@gmail.com)<br />
<br />
<br />
<br />
{{Languages|Deriving_gradients_using_the_backpropagation_idea|English}}</div>
Kandeng
http://ufldl.stanford.edu/wiki/index.php/Data_Preprocessing
Data Preprocessing
2013-04-08T04:22:55Z
<p>Kandeng: </p>
<hr />
<div>== Overview ==<br />
<br />
Data preprocessing plays a very important in many deep learning algorithms. In practice, many methods work best after the data has been normalized and whitened. However, the exact parameters for data preprocessing are usually not immediately apparent unless one has much experience working with the algorithms. In this page, we hope to demystify some of the preprocessing methods and also provide tips (and a "standard pipeline") for preprocessing data.<br />
<br />
{{quote |<br />
Tip: When approaching a dataset, the first thing to do is to look at the data itself and observe its properties. While the techniques here apply generally, you might want to opt to do certain things differently given your dataset. For example, one standard preprocessing trick is to subtract the mean of each data point from itself (also known as remove DC, local mean subtraction, subtractive normalization). While this makes sense for data such as natural images, it is less obvious for data where stationarity does not hold. <br />
}}<br />
<br />
<br />
== Data Normalization ==<br />
<br />
A standard first step to data preprocessing is data normalization. While there are a few possible approaches, this step is usually clear depending on the data. The common methods for feature normalization are:<br />
<br />
* Simple Rescaling<br />
* Per-example mean subtraction (a.k.a. remove DC)<br />
* Feature Standardization (zero-mean and unit variance for each feature across the dataset)<br />
<br />
<br />
=== Simple Rescaling ===<br />
<br />
In simple rescaling, our goal is to rescale the data along each data dimension (possibly independently) so that the final data vectors lie in the range <math>[0, 1]</math> or <math>[-1, 1]</math> (depending on your dataset). This is useful for later processing as many ''default'' parameters (e.g., epsilon in PCA-whitening) treat the data as if it has been scaled to a reasonable range. <br />
<br />
'''Example: ''' When processing natural images, we often obtain pixel values in the range <math>[0, 255]</math>. It is a common operation to rescale these values to <math>[0, 1]</math> by dividing the data by 255.<br />
<br />
=== Per-example mean subtraction ===<br />
<br />
If your data is ''stationary'' (i.e., the statistics for each data dimension follow the same distribution), then you might want to consider subtracting the mean-value for each example (computed per-example). <br />
<br />
'''Example:''' In images, this normalization has the property of removing the average brightness (intensity) of the data point. In many cases, we are not interested in the illumination conditions of the image, but more so in the content; removing the average pixel value per data point makes sense here. '''Note:''' While this method is generally used for images, one might want to take more care when applying this to color images. In particular, the stationarity property does not generally apply across pixels in different color channels.<br />
<br />
=== Feature Standardization ===<br />
<br />
Feature standardization refers to (independently) setting each dimension of the data to have zero-mean and unit-variance. This is the most common method for normalization and is generally used widely (e.g., when working with SVMs, feature standardization is often recommended as a preprocessing step). In practice, one achieves this by first computing the mean of each dimension (across the dataset) and subtracts this from each dimension. Next, each dimension is divided by its standard deviation. <br />
<br />
'''Example: ''' When working with audio data, it is common to use [http://en.wikipedia.org/wiki/Mel-frequency_cepstrum MFCCs] as the data representation. However, the first component (representing the DC) of the MFCC features often overshadow the other components. Thus, one method to restore balance to the components is to standardize the values in each component independently.<br />
<br />
<br />
== PCA/ZCA Whitening ==<br />
<br />
After doing the simple normalizations, whitening is often the next preprocessing step employed that helps make our algorithms work better. In practice, many deep learning algorithms rely on whitening to learn good features.<br />
<br />
In performing PCA/ZCA whitening, it is pertinent to first zero-mean the features (across the dataset) to ensure that <math> \frac{1}{m} \sum_i x^{(i)} = 0 </math>. Specifically, this should be done before computing the covariance matrix. (The only exception is when per-example mean subtraction is performed and the data is stationary across dimensions/pixels.)<br />
<br />
Next, one needs to select the value of <tt>epsilon</tt> to use when performing [[Whitening | PCA/ZCA whitening]] (recall that this was the regularization term that has an effect of ''low-pass filtering'' the data). It turns out that selecting this value can also play an important role for feature learning, we discuss two cases for selecting <tt>epsilon</tt>:<br />
<br />
=== Reconstruction Based Models ===<br />
<br />
In models based on reconstruction (including Autoencoders, Sparse Coding, RBMs, k-Means), it is often preferable to set <tt>epsilon</tt> to a value such that low-pass filtering is achieved. One way to check this is to set a value for <tt>epsilon</tt>, run ZCA whitening, and thereafter visualize the data before and after whitening. If the value of epsilon is set too low, the data will look very noisy; conversely, if <tt>epsilon</tt> is set too high, you will see a "blurred" version of the original data. A good way to get a feel for the magnitude of <tt>epsilon</tt> to try is to plot the eigenvalues on a graph. As visible in the example graph below, you may get a "long tail" corresponding to the high frequency noise components. You will want to choose <tt>epsilon</tt> such that most of the "long tail" is filtered out, i.e. choose <tt>epsilon</tt> such that it is greater than most of the small eigenvalues corresponding to the noise.<br />
<br />
[[File:ZCA_Eigenvalues_Plot.png]]<br />
<br />
In reconstruction based models, the loss function includes a term that penalizes reconstructions that are far from the original inputs. Then, if <tt>epsilon</tt> is set too ''low'', the data will contain a lot of noise which the model will need to reconstruct well. As a result, it is very important for reconstruction based models to have data that has been low-pass filtered.<br />
<br />
{{Quote|<br />
Tip: If your data has been scaled reasonably (e.g., to <math>[0, 1]</math>), start with <math>epsilon = 0.01</math> or <math>epsilon = 0.1</math>.<br />
}}<br />
<br />
=== ICA-based Models (with orthogonalization) ===<br />
<br />
For ICA-based models with orthogonalization, it is ''very'' important for the data to be as close to white (identity covariance) as possible. This is a side-effect of using orthogonalization to decorrelate the features learned (more details in [[Independent Component Analysis | ICA]]). Hence, in this case, you will want to use an <tt>epsilon</tt> that is as small as possible (e.g., <math>epsilon = 1e-6</math>).<br />
<br />
<br />
{{Quote|<br />
Tip: In PCA whitening, one also has the option of performing dimension reduction while whitening the data. This is usually an excellent idea since it can greatly speed up the algorithms (less computation and less parameters). A simple rule of thumb to choose how many principle components to retain is to keep enough components to have 99% of the variance retained (more details at [[PCA#Number_of_components_to_retain | PCA]])<br />
}}<br />
<br />
<br />
{{quote|<br />
Note: When working in a classification framework, one should compute the PCA/ZCA whitening matrices based only on the training set. The following parameters used be saved for use with the test set: (a) average vector that was used to zero-mean the data, (b) whitening matrices. The test set should undergo the same preprocessing steps using these saved values. }}<br />
<br />
== Large Images ==<br />
<br />
For large images, PCA/ZCA based whitening methods are impractical as the covariance matrix is too large. For these cases, we defer to 1/f-whitening methods. (more details to come)<br />
<br />
<br />
== Standard Pipelines ==<br />
<br />
In this section, we describe several "standard pipelines" that have worked well for some datasets:<br />
<br />
=== Natural Grey-scale Images ===<br />
<br />
Since grey-scale images have the stationarity property, we usually first remove the mean-component from each data example separately (remove DC). After this step, PCA/ZCA whitening is often employed with a value of <tt>epsilon</tt> set large enough to low-pass filter the data.<br />
<br />
=== Color Images ===<br />
<br />
For color images, the stationarity property does not hold across color channels. Hence, we usually start by rescaling the data (making sure it is in <math>[0, 1]</math>) ad then applying PCA/ZCA with a sufficiently large <tt>epsilon</tt>. Note that it is important to perform feature mean-normalization before computing the PCA transformation.<br />
<br />
=== Audio (MFCC/Spectrograms) ===<br />
<br />
For audio data (MFCC and Spectrograms), each dimension usually have different scales (variances); the first component of MFCCs, for example, is the DC component and usually has a larger magnitude than the other components. This is especially so when one includes the temporal derivatives (a common practice in audio processing). As a result, the preprocessing usually starts with simple data standardization (zero-mean, unit-variance per data dimension), followed by PCA/ZCA whitening (with an appropriate <tt>epsilon</tt>).<br />
<br />
=== MNIST Handwritten Digits ===<br />
<br />
The MNIST dataset has pixel values in the range <math>[0, 255]</math>. We thus start with simple rescaling to shift the data into the range <math>[0, 1]</math>. In practice, removing the mean-value per example can also help feature learning. ''Note: While one could also elect to use PCA/ZCA whitening on MNIST if desired, this is not often done in practice.''<br />
<br />
<br />
<br />
{{Languages|数据预处理|中文}}</div>
Kandeng
http://ufldl.stanford.edu/wiki/index.php/%E6%95%B0%E6%8D%AE%E9%A2%84%E5%A4%84%E7%90%86
数据预处理
2013-04-08T04:22:09Z
<p>Kandeng: </p>
<hr />
<div>== 概要 ==<br />
<br />
数据预处理在众多深度学习算法中都起着重要作用,实际情况中,将数据做归一化和白化处理后,很多算法能够发挥最佳效果。然而除非对这些算法有丰富的使用经验,否则预处理的精确参数并非显而易见。在本页中,我们希望能够揭开预处理方法的神秘面纱,同时为预处理数据提供技巧(和标准流程)。<br />
<br />
{{quote |<br />
提示:当我们开始处理数据时,首先要做的事是观察数据并获知其特性。本部分将介绍一些通用的技术,在实际中应该针对具体数据选择合适的预处理技术。例如一种标准的预处理方法是对每一个数据点都减去它的均值(也被称为移除直流分量,局部均值消减,消减归一化),这一方法对诸如自然图像这类数据是有效的,但对非平稳的数据则不然。<br />
}}<br />
<br />
<br />
== 数据归一化 ==<br />
<br />
数据预处理中,标准的第一步是数据归一化。虽然这里有一系列可行的方法,但是这一步通常是根据数据的具体情况而明确选择的。特征归一化常用的方法包含如下几种:<br />
<br />
* 简单缩放<br />
* 逐样本均值消减(也称为移除直流分量)<br />
* 特征标准化(使数据集中所有特征都具有零均值和单位方差)<br />
<br />
<br />
=== 简单缩放 ===<br />
<br />
在简单缩放中,我们的目的是通过对数据的每一个维度的值进行重新调节(这些维度可能是相互独立的),使得最终的数据向量落在 <math>[0, 1]</math>或<math>[-1, 1]</math> 的区间内(根据数据情况而定)。这对后续的处理十分重要,因为很多''默认''参数(如 PCA-白化中的 epsilon)都假定数据已被缩放到合理区间。<br />
<br />
'''例子:'''在处理自然图像时,我们获得的像素值在 <math>[0, 255]</math> 区间中,常用的处理是将这些像素值除以 255,使它们缩放到 <math>[0, 1]</math> 中.<br />
<br />
<br />
=== 逐样本均值消减 ===<br />
<br />
如果你的数据是''平稳''的(即数据每一个维度的统计都服从相同分布),那么你可以考虑在每个样本上减去数据的统计平均值(逐样本计算)。<br />
<br />
'''例子:'''对于图像,这种归一化可以移除图像的平均亮度值 (intensity)。很多情况下我们对图像的照度并不感兴趣,而更多地关注其内容,这时对每个数据点移除像素的均值是有意义的。'''注意:'''虽然该方法广泛地应用于图像,但在处理彩色图像时需要格外小心,具体来说,是因为不同色彩通道中的像素并不都存在平稳特性。<br />
<br />
<br />
=== 特征标准化 ===<br />
<br />
特征标准化指的是(独立地)使得数据的每一个维度具有零均值和单位方差。这是归一化中最常见的方法并被广泛地使用(例如,在使用支持向量机(SVM)时,特征标准化常被建议用作预处理的一部分)。在实际应用中,特征标准化的具体做法是:首先计算每一个维度上数据的均值(使用全体数据计算),之后在每一个维度上都减去该均值。下一步便是在数据的每一维度上除以该维度上数据的标准差。<br />
<br />
'''例子''':处理音频数据时,常用 Mel 倒频系数 [http://en.wikipedia.org/wiki/Mel-frequency_cepstrum MFCCs] 来表征数据。然而MFCC特征的第一个分量(表示直流分量)数值太大,常常会掩盖其他分量。这种情况下,为了平衡各个分量的影响,通常对特征的每个分量独立地使用标准化处理。<br />
<br />
<br />
== PCA/ZCA白化 ==<br />
<br />
在做完简单的归一化后,白化通常会被用来作为接下来的预处理步骤,它会使我们的算法工作得更好。实际上许多深度学习算法都依赖于白化来获得好的特征。<br />
<br />
在进行 PCA/ZCA 白化时,首先使特征零均值化是很有必要的,这保证了 <math> \frac{1}{m} \sum_i x^{(i)} = 0 </math>。特别地,这一步需要在计算协方差矩阵前完成。(唯一例外的情况是已经进行了逐样本均值消减,并且数据在各维度上或像素上是平稳的。)<br />
<br />
接下来在 PCA/ZCA 白化中我们需要选择合适的 <tt>epsilon</tt>(回忆一下,这是规则化项,对数据有低通滤波作用)。 选取合适的 <tt>epsilon</tt> 值对特征学习起着很大作用,下面讨论在两种不同场合下如何选取 <tt>epsilon</tt>:<br />
<br />
<br />
=== 基于重构的模型 ===<br />
<br />
在基于重构的模型中(包括自编码器,稀疏编码,受限 Boltzman 机(RBM),k-均值(K-Means)),经常倾向于选取合适的 <tt>epsilon</tt> 以使得白化达到低通滤波的效果。(译注:通常认为数据中的高频分量是噪声,低通滤波的作用就是尽可能抑制这些噪声,同时保留有用的信息。在 PCA 等方法中,假设数据的信息主要分布在方差较高的方向,方差较低的方向是噪声(即高频分量),因此后文中 <tt>epsilon</tt> 的选择与特征值有关)。一种检验 <tt>epsilon</tt> 是否合适的方法是用该值对数据进行 ZCA 白化,然后对白化前后的数据进行可视化。如果 <tt>epsilon</tt> 值过低,白化后的数据会显得噪声很大;相反,如果 <tt>epsilon</tt> 值过高,白化后的数据与原始数据相比就过于模糊。一种直观上得到 <tt>epsilon</tt> 大小的方法是以图形方式画出数据的特征值,如下图的例子所示,你可以看到一条"长尾",它对应于数据中的高频噪声部分。你需要选取合适的 <tt>epsilon</tt>,使其能够在很大程度上过滤掉这条"长尾",也就是说,选取的 <tt>epsilon</tt> 应大于大多数较小的、反映数据中噪声的特征值。<br />
<br />
[[File:ZCA_Eigenvalues_Plot.png]]<br />
<br />
在基于重构的模型中,损失函数有一项是用于惩罚那些与原始输入数据差异较大的重构结果(译注:以自动编码机为例,要求输入数据经过编码和解码之后还能尽可能的还原输入数据)。如果 <tt>epsilon</tt> 太小,白化后的数据中就会包含很多噪声,而模型要拟合这些噪声,以达到很好的重构结果。因此,对于基于重构的模型来说,对原始数据进行低通滤波就显得非常重要。<br />
<br />
{{Quote|<br />
提示:如果数据已被缩放到合理范围(如<math>[0, 1]</math>),可以从<math>epsilon = 0.01</math>或<math>epsilon = 0.1</math>开始调节<tt>epsilon</tt>。<br />
}}<br />
<br />
<br />
=== 基于正交化ICA的模型 ===<br />
<br />
对基于正交化ICA的模型来说,保证输入数据尽可能地白化(即协方差矩阵为单位矩阵)非常重要。这是因为:这类模型需要对学习到的特征做正交化,以解除不同维度之间的相关性(详细内容请参考 [[Independent Component Analysis | ICA ]] 一节)。因此在这种情况下,<tt>epsilon</tt> 要足够小(比如 <math>epsilon = 1e-6</math>)。<br />
<br />
{{Quote|<br />
提示:我们也可以在PCA白化过程中同时降低数据的维度。这是一个很好的主意,因为这样可以大大提升算法的速度(减少了运算量和参数数目)。确定要保留的主成分数目有一个经验法则:即所保留的成分的总方差达到总样本方差的 99% 以上。(详细内容请参考[[PCA#Number_of_components_to_retain | PCA ]])<br />
}}<br />
<br />
<br />
{{Quote|<br />
注意: 在使用分类框架时,我们应该只基于练集上的数据计算PCA/ZCA白化矩阵。需要保存以下两个参数留待测试集合使用:(a)用于零均值化数据的平均值向量;(b)白化矩阵。测试集需要采用这两组保存的参数来进行相同的预处理。}}<br />
<br />
<br />
== 大图像 ==<br />
<br />
对于大图像,采用基于 PCA/ZCA 的白化方法是不切实际的,因为协方差矩阵太大。在这些情况下我们退而使用 1/f 白化方法(更多内容后续再讲)。<br />
<br />
<br />
== 标准流程 ==<br />
<br />
在这一部分中,我们将介绍几种在一些数据集上有良好表现的预处理标准流程.<br />
<br />
<br />
=== 自然灰度图像 ===<br />
<br />
灰度图像具有平稳特性,我们通常在第一步对每个数据样本分别做均值消减(即减去直流分量),然后采用 PCA/ZCA 白化处理,其中的 <tt>epsilon</tt> 要足够大以达到低通滤波的效果。<br />
<br />
<br />
=== 彩色图像 ===<br />
<br />
对于彩色图像,色彩通道间并不存在平稳特性。因此我们通常首先对数据进行特征缩放(使像素值位于 <math>[0, 1]</math> 区间),然后使用足够大的 <tt>epsilon</tt> 来做 PCA/ZCA。注意在进行 PCA 变换前需要对特征进行分量均值归零化。<br />
<br />
<br />
=== 音频 (MFCC/频谱图) ===<br />
<br />
对于音频数据 (MFCC 和频谱图),每一维度的取值范围(方差)不同。例如 MFCC 的第一分量是直流分量,通常其幅度远大于其他分量,尤其当特征中包含时域导数 (temporal derivatives) 时(这是音频处理中的常用方法)更是如此。因此,对这类数据的预处理通常从简单的数据标准化开始(即使得数据的每一维度均值为零、方差为 1),然后进行 PCA/ZCA 白化(使用合适的 <tt>epsilon</tt>)。<br />
<br />
<br />
=== MNIST 手写数字 ===<br />
<br />
MNIST 数据集的像素值在 <math>[0, 255]</math> 区间中。我们首先将其缩放到 <math>[0, 1]</math> 区间。实际上,进行逐样本均值消去也有助于特征学习。''注:也可选择以对 MNIST 进行 PCA/ZCA 白化,但这在实践中不常用。''<br />
<br />
<br />
==中英文对照==<br />
<br />
:归一化 normalization<br />
<br />
:白化 whitening<br />
<br />
:直流分量 DC component<br />
<br />
:局部均值消减 local mean subtraction<br />
<br />
:消减归一化 sparse autoencoder<br />
<br />
:缩放 rescaling<br />
<br />
:逐样本均值消减 per-example mean subtraction<br />
<br />
:特征标准化 feature standardization<br />
<br />
:平稳 stationary<br />
<br />
:Mel倒频系数 MFCC<br />
<br />
:零均值化 zero-mean<br />
<br />
:低通滤波 low-pass filtering<br />
<br />
:基于重构的模型 reconstruction based models<br />
<br />
:自编码器 autoencoders<br />
<br />
:稀疏编码 sparse coding<br />
<br />
:受限Boltzman机 RBMs<br />
<br />
:k-均值 k-Means<br />
<br />
:长尾 long tail<br />
<br />
:损失函数 loss function<br />
<br />
:正交化 orthogonalization<br />
<br />
<br />
==中文译者==<br />
<br />
陈磊(lei.chen@operasolutions.com), 王文中(wangwenzhong@ymail.com), 王方(fangkey@gmail.com)<br />
<br />
<br />
{{Languages|Data_Preprocessing|English}}</div>
Kandeng
http://ufldl.stanford.edu/wiki/index.php/Pooling
Pooling
2013-04-08T04:17:21Z
<p>Kandeng: </p>
<hr />
<div>== Pooling: Overview ==<br />
<br />
After obtaining features using convolution, we would next like to use them for classification. In theory, one could use all the extracted features with a classifier such as a softmax classifier, but this can be computationally challenging. Consider for instance images of size 96x96 pixels, and suppose we have learned 400 features over 8x8 inputs. Each convolution results in an output of size <math>(96-8+1)*(96-8+1)=7921</math>, and since we have 400 features, this results in a vector of <math>89^2 * 400 = 3,168,400</math> features per example. Learning a classifier with inputs having 3+ million features can be unwieldy, and can also be prone to over-fitting. <br />
<br />
To address this, first recall that we decided to obtain convolved features because images have the "stationarity" property, which implies that features that are useful in one region are also likely to be useful for other regions. Thus, to describe a large image, one natural approach is to aggregate statistics of these features at various locations. For example, one could compute the mean (or max) value of a particular feature over a region of the image. These summary statistics are much lower in dimension (compared to using all of the extracted features) and can also improve results (less over-fitting). We aggregation operation is called this operation '''pooling''', or sometimes '''mean pooling''' or '''max pooling''' (depending on the pooling operation applied). <br />
<br />
The following image shows how pooling is done over 4 non-overlapping regions of the image.<br />
<br />
[[File:Pooling_schematic.gif]]<br />
<br />
== Pooling for Invariance ==<br />
<br />
If one chooses the pooling regions to be contiguous areas in the image and only pools features generated from the same (replicated) hidden units. Then, these pooling units will then be '''translation invariant'''. This means that the same (pooled) feature will be active even when the image undergoes (small) translations. Translation-invariant features are often desirable; in many tasks (e.g., object detection, audio recognition), the label of the example (image) is the same even when the image is translated. For example, if you were to take an MNIST digit and translate it left or right, you would want your classifier to still accurately classify it as the same digit regardless of its final position.<br />
<br />
== Formal description ==<br />
<br />
Formally, after obtaining our convolved features as described earlier, we decide the size of the region, say <math>m \times n</math> to pool our convolved features over. Then, we divide our convolved features into disjoint <math>m \times n</math> regions, and take the mean (or maximum) feature activation over these regions to obtain the pooled convolved features. These pooled features can then be used for classification.<br />
<br />
<br />
<br />
{{Languages|池化|中文}}</div>
Kandeng
http://ufldl.stanford.edu/wiki/index.php/%E6%B1%A0%E5%8C%96
池化
2013-04-08T04:16:12Z
<p>Kandeng: </p>
<hr />
<div>== 池化: 概述 ==<br />
<br />
在通过卷积获得了特征 (features) 之后,下一步我们希望利用这些特征去做分类。理论上讲,人们可以用所有提取得到的特征去训练分类器,例如 softmax 分类器,但这样做面临计算量的挑战。例如:对于一个 96X96 像素的图像,假设我们已经学习得到了400个定义在8X8输入上的特征,每一个特征和图像卷积都会得到一个 <math>(96-8+1)*(96-8+1)=7921</math> 维的卷积特征,由于有 400 个特征,所以每个样例 (example) 都会得到一个 <math>89^2 * 400 = 3,168,400</math> 维的卷积特征向量。学习一个拥有超过 3 百万特征输入的分类器十分不便,并且容易出现过拟合 (over-fitting)。<br />
<br />
<br />
为了解决这个问题,首先回忆一下,我们之所以决定使用卷积后的特征是因为图像具有一种“静态性”的属性,这也就意味着在一个图像区域有用的特征极有可能在另一个区域同样适用。因此,为了描述大的图像,一个很自然的想法就是对不同位置的特征进行聚合统计,例如,人们可以计算图像一个区域上的某个特定特征的平均值 (或最大值)。这些概要统计特征不仅具有低得多的维度 (相比使用所有提取得到的特征),同时还会改善结果(不容易过拟合)。这种聚合的操作就叫做池化 (pooling),有时也称为平均池化或者最大池化 (取决于计算池化的方法)。<br />
<br />
<br />
下图显示池化如何应用于一个图像的四块不重合区域。<br />
<br />
[[File:Pooling_schematic.gif]]<br />
<br />
<br />
== 池化的不变性 ==<br />
<br />
如果人们选择图像中的连续范围作为池化区域,并且只是池化相同(重复)的隐藏单元产生的特征,那么,这些池化单元就具有平移不变性 (translation invariant)。这就意味着即使图像经历了一个小的平移之后,依然会产生相同的 (池化的) 特征。在很多任务中 (例如物体检测、声音识别),我们都更希望得到具有平移不变性的特征,因为即使图像经过了平移,样例(图像)的标记仍然保持不变。例如,如果你处理一个MNIST数据集的数字,把它向左侧或右侧平移,那么不论最终的位置在哪里,你都会期望你的分类器仍然能够精确地将其分类为相同的数字。<br />
<br />
(*MNIST 是一个手写数字库识别库: http://yann.lecun.com/exdb/mnist/)<br />
<br />
<br />
== 形式化描述 ==<br />
<br />
形式上,在获取到我们前面讨论过的卷积特征后,我们要确定池化区域的大小(假定为<math>m \times n</math>),来池化我们的卷积特征。那么,我们把卷积特征划分到数个大小为 <math>m \times n</math>的不相交区域上,然后用这些区域的平均(或最大)特征来获取池化后的卷积特征。这些池化后的特征便可以用来做分类。<br />
<br />
<br />
==中英文对照==<br />
<br />
:特征 features<br />
<br />
:样例 example<br />
<br />
:过拟合 over-fitting<br />
<br />
:平移不变性 translation invariant<br />
<br />
:池化 pooling<br />
<br />
:提取 extract<br />
<br />
:物体检测 object detection<br />
<br />
<br />
==中文译者==<br />
<br />
陈玉栓 (chris_chen_cys@hotmail.com) , 刘鸿鹏飞(just.dark@foxmail.com), 邓亚峰(dengyafeng@gmail.com), 晓风(xiaofeng.zhb@alibaba-inc.com)<br />
<br />
<br />
{{Languages|Pooling|English}}</div>
Kandeng
http://ufldl.stanford.edu/wiki/index.php/Feature_extraction_using_convolution
Feature extraction using convolution
2013-04-08T04:11:41Z
<p>Kandeng: </p>
<hr />
<div>== Overview ==<br />
<br />
In the previous exercises, you worked through problems which involved images that were relatively low in resolution, such as small image patches and small images of hand-written digits. In this section, we will develop methods which will allow us to scale up these methods to more realistic datasets that have larger images.<br />
<br />
== Fully Connected Networks ==<br />
<br />
In the sparse autoencoder, one design choice that we had made was to "fully connect" all the hidden units to all the input units. On the relatively small images that we were working with (e.g., 8x8 patches for the sparse autoencoder assignment, 28x28 images for the MNIST dataset), it was computationally feasible to learn features on the entire image. However, with larger images (e.g., 96x96 images) learning features that span the entire image (fully connected networks) is very computationally expensive--you would have about <math>10^4</math> input units, and assuming you want to learn 100 features, you would have on the order of <math>10^6</math> parameters to learn. The feedforward and backpropagation computations would also be about <math>10^2</math> times slower, compared to 28x28 images.<br />
<br />
== Locally Connected Networks ==<br />
<br />
One simple solution to this problem is to restrict the connections between the hidden units and the input units, allowing each hidden unit to connect to only a small subset of the input units. Specifically, each hidden unit will connect to only a small contiguous region of pixels in the input. (For input modalities different than images, there is often also a natural way to select "contiguous groups" of input units to connect to a single hidden unit as well; for example, for audio, a hidden unit might be connected to only the input units corresponding to a certain time span of the input audio clip.) <br />
<br />
This idea of having locally connected networks also draws inspiration from how the early visual system is wired up in biology. Specifically, neurons in the visual cortex have localized receptive fields (i.e., they respond only to stimuli in a certain location).<br />
<br />
== Convolutions ==<br />
<br />
Natural images have the property of being '''stationary''', meaning that the statistics of one part of the image are the same as any other part. This suggests that the features that we learn at one part of the image can also be applied to other parts of the image, and we can use the same features at all locations. <br />
<!--<br />
To capture this idea of learning the same features "everywhere in the image," one option is to add an additional added as an additional constraint known as weight sharing (tying) between the hidden units at different locations. If one chooses to have the same hidden unit replicated at every possible location, this turns out to be equivalent to a convolution of the feature (as a filter) on the image.<br />
<br />
== Fast Feature Learning and Extraction ==<br />
<br />
While in principle one can learn feature convolutionally over the entire image, the learning procedure becomes more complicated to implement and often takes longer to execute. <br />
!--><br />
<br />
<br />
More precisely, having learned features over small (say 8x8) patches sampled randomly from the larger image, we can then apply this learned 8x8 feature detector anywhere in the image. Specifically, we can take the learned 8x8 features and <br />
'''convolve''' them with the larger image, thus obtaining a different feature activation value at each location in the image. <br />
<br />
<br />
To give a concrete example, suppose you have learned features on 8x8 patches sampled from a 96x96 image. Suppose further this was done with an autoencoder that has 100 hidden units. To get the convolved features, for every 8x8 region of the 96x96 image, that is, the 8x8 regions starting at <math>(1, 1), (1, 2), \ldots (89, 89)</math>, you would extract the 8x8 patch, and run it through your trained sparse autoencoder to get the feature activations. This would result in 100 sets 89x89 convolved features. <br />
<br />
<br />
<!--<br />
These convolved features can later be '''[[#pooling | pooled]]''' together to produce a smaller set of pooled features, which can then be used for classification. <br />
!--><br />
<br />
[[File:Convolution_schematic.gif]]<br />
<br />
Formally, given some large <math>r \times c</math> images <math>x_{large}</math>, we first train a sparse autoencoder on small <math>a \times b</math> patches <math>x_{small}</math> sampled from these images, learning <math>k</math> features <math>f = \sigma(W^{(1)}x_{small} + b^{(1)})</math> (where <math>\sigma</math> is the sigmoid function), given by the weights <math>W^{(1)}</math> and biases <math>b^{(1)}</math> from the visible units to the hidden units. For every <math>a \times b</math> patch <math>x_s</math> in the large image, we compute <math>f_s = \sigma(W^{(1)}x_s + b^{(1)})</math>, giving us <math>f_{convolved}</math>, a <math>k \times (r - a + 1) \times (c - b + 1)</math> array of convolved features. <br />
<br />
<br />
<br />
In the next section, we further describe how to "pool" these features together to get even better features for classification.<br />
<br />
<br />
{{Languages|卷积特征提取|中文}}</div>
Kandeng