自编码算法与稀疏性
From Ufldl
for
自编码算法与稀疏性
Jump to:
navigation
,
search
初译: 新浪微博,@上篮高手要抓紧时间少上微博 http://www.weibo.com/gapbridger 一审: 新浪微博,@达博西 http://www.weibo.com/mercivi 二审: 新浪微博,@大黄蜂的思索 http://weibo.com/u/1733291480 wiki上传: 新浪微博,@上篮高手要抓紧时间少上微博 http://www.weibo.com/gapbridger 【原文】 So far, we have described the application of neural networks to supervised learning, in which we have labeled training examples. Now suppose we have only a set of unlabeled training examples <math>\textstyle \{x^{(1)}, x^{(2)}, x^{(3)}, \ldots\}</math>, where <math>\textstyle x^{(i)} \in \Re^{n}</math>. An '''autoencoder''' neural network is an unsupervised learning algorithm that applies backpropagation, setting the target values to be equal to the inputs. I.e., it uses <math>\textstyle y^{(i)} = x^{(i)}</math>. Here is an autoencoder: 【初译】 目前为止,我们已经讨论了神经网络在监督学习中的应用。在监督学习中,训练样本是有类别标签的。现在假设我们只有一个没有类别标签的训练样本集合 <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> 。下图是一个自编码神经网络的示例。 【一审】 目前为止,我们已经讨论了神经网络在监督学习中的应用。在监督学习中,训练样本是有类别标签的。现在假设我们只有一个没有类别标签的训练样本集合 <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> 。下图是一个自编码神经网络的示例。 【二审】 目前为止,我们已经讨论了神经网络在有监督学习中的应用。在有监督学习中,训练样本是有类别标签的。现在假设我们只有一个没有带类别标签的训练样本集合 <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> 。下图是一个自编码神经网络的示例。 [[Image:Autoencoder636.png|400px|center]] 【原文】 The autoencoder tries to learn a function <math>\textstyle h_{W,b}(x) \approx x</math>. In other words, it is trying to learn an approximation to the identity function, so as to output <math>\textstyle \hat{x}</math> that is similar to <math>\textstyle x</math>. The identity function seems a particularly trivial function to be trying to learn; but by placing constraints on the network, such as by limiting the number of hidden units, we can discover interesting structure about the data. As a concrete example, suppose the inputs <math>\textstyle x</math> are the pixel intensity values from a <math>\textstyle 10 \times 10</math> image (100 pixels) so <math>\textstyle n=100</math>, and there are <math>\textstyle s_2=50</math> hidden units in layer <math>\textstyle L_2</math>. Note that we also have <math>\textstyle y \in \Re^{100}</math>. Since there are only 50 hidden units, the network is forced to learn a ''compressed'' representation of the input. I.e., given only the vector of hidden unit activations <math>\textstyle a^{(2)} \in \Re^{50}</math>, it must try to '''reconstruct''' the 100-pixel input <math>\textstyle x</math>. If the input were completely random---say, each <math>\textstyle x_i</math> comes from an IID Gaussian independent of the other features---then this compression task would be very difficult. But if there is structure in the data, for example, if some of the input features are correlated, then this algorithm will be able to discover some of those correlations. In fact, this simple autoencoder often ends up learning a low-dimensional representation very similar to PCAs. 【初译】 自编码神经网络尝试学习一个 <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> 图像的像素值,于是 <math>\textstyle n=100</math> ,其隐层 <math>\textstyle L_2</math> 中有 <math>\textstyle s_2=50</math> 个隐藏神经元 。注意,输出是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)结果非常相似的输入数据的低维表示。 【一审】 自编码算法要做的是学习得到一个函数 <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个隐藏神经元 ,注意 。由于只有50个隐藏神经元,就迫使神经网络要为输入值学习获取一个'''经过压缩的'''表示方式。也就是说,给定一个隐藏层的激活向量 <math>\textstyle a^{(2)} \in \Re^{50}</math> ,必须对有100个像素值的输入 <math>\textstyle x</math> 进行'''重构'''。如果输入是随机的――即,每个 <math>\textstyle x_i</math> 都彼此独立,并服从独立同高斯分布――那么这种压缩工作就会变得异常困难。但是,如果样本数据内部存在某种相关结构,比如,如果输入数据中某些特征变量是相关的,那么这种算法就可以找出这些相关关系。事实上,这种基本的自编码算法通常就能学习得到一个低维度的数据表现方式,它跟主成分分析方法很像。 【二审】 自编码神经网络尝试学习一个 <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)结果非常相似的输入数据的低维表示。 【原文】 Our argument above relied on the number of hidden units <math>\textstyle s_2</math> being small. But even when the number of hidden units is large (perhaps even greater than the number of input pixels), we can still discover interesting structure, by imposing other constraints on the network. In particular, if we impose a '''sparsity''' constraint on the hidden units, then the autoencoder will still discover interesting structure in the data, even if the number of hidden units is large. Informally, we will think of a neuron as being "active" (or as "firing") if its output value is close to 1, or as being "inactive" if its output value is close to 0. We would like to constrain the neurons to be inactive most of the time. This discussion assumes a sigmoid activation function. If you are using a tanh activation function, then we think of a neuron as being inactive when it outputs values close to -1. 【初译】 我们刚才的论述需要基于隐藏神经元数量较小的假设,但是即使隐藏神经元的数量较大(可能比输入像素的个数还要多),我们仍然通过给自编码神经网络施加一些其他的限制条件来发现输入数据中的结构。具体来说,如果我们给隐藏神经元加入'''稀疏性'''限制,那么自编码神经网络即使在隐藏神经元数量较多的情况下仍然可以发现输入数据中一些有趣的结构。 稀疏性可以被简单地解释如下。如果当神经元的输出接近于1的时候我们认为它被激活,而输出接近于0的时候认为它被抑制,那么使得神经元大部分的时间都是被抑制的限制则被称作稀疏性限制。这里我们假设神经元的激活函数是sigmoid函数。如果你使用tanh作为激活函数,那么当输出为-1的时候,我们认为神经元是被抑制的。 【一审】 以上我们所讨论的都有基于隐藏层单元数量是很小的情况。但是即使隐藏层单元数量很大(甚至可能比输入像素的数量还大),只要给这个神经网络加入其他限制条件,我们还是可以发现某种有意思的相关结构。打个比方,如果我们给隐藏层单元加上“稀疏性”限制,那么即使隐藏层单元数量很大,自编码算法仍然可以在输入数据中找到这种有意思的结构。 如果某个神经元的输出值接近于1,我们就给此神经元一个非专业的说法“活性”(或“易燃”),而如果输出值接近于0,就称之为“惰性”。大多数情况下,我们都想把这些神经元限制为惰性。这里我们假设激活函数是sigmoid函数。如果你使用tanh激活函数,那么当一个神经元的输出值接近于-1时,它才是惰性的。 【二审】 我们刚才的论述是基于隐藏神经元数量较小的假设。但是即使隐藏神经元的数量较大(可能比输入像素的个数还要多),我们仍然通过给自编码神经网络施加一些其他的限制条件来发现输入数据中的结构。具体来说,如果我们给隐藏神经元加入稀疏性限制,那么自编码神经网络即使在隐藏神经元数量较多的情况下仍然可以发现输入数据中一些有趣的结构。 稀疏性可以被简单地解释如下。如果当神经元的输出接近于1的时候我们认为它被激活,而输出接近于0的时候认为它被抑制,那么使得神经元大部分的时间都是被抑制的限制则被称作稀疏性限制。这里我们假设的神经元的激活函数是sigmoid函数。如果你使用tanh作为激活函数的话,当神经元输出为-1的时候,我们认为神经元是被抑制的。 【原文】 Recall that <math>\textstyle a^{(2)}_j</math> denotes the activation of hidden unit <math>\textstyle j</math> in the autoencoder. However, this notation doesn't make explicit what was the input <math>\textstyle x</math> that led to that activation. Thus, we will write <math>\textstyle a^{(2)}_j(x)</math> to denote the activation of this hidden unit when the network is given a specific input <math>\textstyle x</math>. Further, let :<math>\begin{align} \hat\rho_j = \frac{1}{m} \sum_{i=1}^m \left[ a^{(2)}_j(x^{(i)}) \right] \end{align}</math> be the average activation of hidden unit <math>\textstyle j</math> (averaged over the training set). We would like to (approximately) enforce the constraint :<math>\begin{align} \hat\rho_j = \rho, \end{align}</math> where <math>\textstyle \rho</math> is a '''sparsity parameter''', typically a small value close to zero (say <math>\textstyle \rho = 0.05</math>). In other words, we would like the average activation of each hidden neuron <math>\textstyle j</math> to be close to 0.05 (say). To satisfy this constraint, the hidden unit's activations must mostly be near 0. 【初译】 注意到 <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> 的激活度。 进一步,让 :<math>\begin{align} \hat\rho_j = \frac{1}{m} \sum_{i=1}^m \left[ a^{(2)}_j(x^{(i)}) \right] \end{align}</math> 表示隐藏神经元 <math>\textstyle j</math> 的平均活跃度(在训练集上取平均)。我们可以近似的加入一条限制 :<math>\begin{align} \hat\rho_j = \rho, \end{align}</math> 其中, <math>\textstyle \rho</math> 是'''稀疏性参数''',通常是一个接近于0的较小的值(比如 <math>\textstyle \rho = 0.05</math> )。换句话说,我们想要让隐藏神经元 <math>\textstyle j</math> 的平均活跃度接近0.05。为了满足这一条件,隐藏神经元的活跃度必须接近于0。 【一审】 回想一下,标识符 <math>\textstyle a^{(2)}_j</math> 代表自编码神经网络中隐藏单元 <math>\textstyle j</math> 的激活值。但是,这种标识符并没有清楚地指出产生这个激活值的输入向量 <math>\textstyle x</math> 是哪个。因此,当给定神经网络一个确定的输入向量 <math>\textstyle x</math> 时,我们就用 <math>\textstyle a^{(2)}_j(x)</math> 来表示这个隐藏单元的激活值。 更进一步,我们令 :<math>\begin{align} \hat\rho_j = \frac{1}{m} \sum_{i=1}^m \left[ a^{(2)}_j(x^{(i)}) \right] \end{align}</math> 表示隐藏单元 <math>\textstyle j</math> 的平均激活值(通过所有样本数据计算平均值),于是我们就要加入(近似的)约束条件: :<math>\begin{align} \hat\rho_j = \rho, \end{align}</math> 其中, <math>\textstyle \rho</math> 为'''稀疏参数''',通常是接近于零的值(比如, <math>\textstyle \rho = 0.05</math> )。换句话说,我们希望每个隐藏单元 <math>\textstyle j</math> 的平均激活值接近于0.05(打个比方)。为了满足这种约束条件,绝大多数隐藏单元的激活值必须非常接近于0. 【二审】 注意到 <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> 的激活度。 进一步,让 :<math>\begin{align} \hat\rho_j = \frac{1}{m} \sum_{i=1}^m \left[ a^{(2)}_j(x^{(i)}) \right] \end{align}</math> 表示隐藏神经元 <math>\textstyle j</math> 的平均活跃度(在训练集上取平均)。我们可以近似的加入一条限制 :<math>\begin{align} \hat\rho_j = \rho, \end{align}</math> 其中, <math>\textstyle \rho</math> 是'''稀疏性参数''',通常是一个接近于0的较小的值(比如 <math>\textstyle \rho = 0.05</math> )。换句话说,我们想要让隐藏神经元 <math>\textstyle j</math> 的平均活跃度接近0.05。为了满足这一条件,隐藏神经元的活跃度必须接近于0。 【原文】 To achieve this, we will add an extra penalty term to our optimization objective that penalizes <math>\textstyle \hat\rho_j</math> deviating significantly from <math>\textstyle \rho</math>. Many choices of the penalty term will give reasonable results. We will choose the following: :<math>\begin{align} \sum_{j=1}^{s_2} \rho \log \frac{\rho}{\hat\rho_j} + (1-\rho) \log \frac{1-\rho}{1-\hat\rho_j}. \end{align}</math> Here, <math>\textstyle s_2</math> is the number of neurons in the hidden layer, and the index <math>\textstyle j</math> is summing over the hidden units in our network. If you are familiar with the concept of KL divergence, this penalty term is based on it, and can also be written :<math>\begin{align} \sum_{j=1}^{s_2} {\rm KL}(\rho || \hat\rho_j), \end{align}</math> where <math>\textstyle {\rm KL}(\rho || \hat\rho_j) = \rho \log \frac{\rho}{\hat\rho_j} + (1-\rho) \log \frac{1-\rho}{1-\hat\rho_j}</math> is the Kullback-Leibler (KL) divergence between a Bernoulli random variable with mean <math>\textstyle \rho</math> and a Bernoulli random variable with mean <math>\textstyle \hat\rho_j</math>. KL-divergence is a standard function for measuring how different two different distributions are. (If you've not seen KL-divergence before, don't worry about it; everything you need to know about it is contained in these notes.) 【初译】 为了实现这一限制,我们将会在我们的优化目标函数中加入另外一个惩罚因子,而这一惩罚因子将惩罚那些 <math>\textstyle \hat\rho_j</math> 和 <math>\textstyle \rho</math> 有显著不同的情况从而使得隐藏神经元的平均活跃度保持在较小范围内。惩罚因子的具体形式有很多种合理的选择,我们将会选择以下这一种: :<math>\begin{align} \sum_{j=1}^{s_2} \rho \log \frac{\rho}{\hat\rho_j} + (1-\rho) \log \frac{1-\rho}{1-\hat\rho_j}. \end{align}</math> 这里, <math>\textstyle s_2</math> 是隐层中隐藏神经元的数量,而索引 <math>\textstyle j</math> 则代表隐层中的某一个神经元。如果你对相对熵(KL divergence)比较熟悉,这一惩罚因子实际上是基于它的。于是惩罚因子也可以被表示为 :<math>\begin{align} \sum_{j=1}^{s_2} {\rm KL}(\rho || \hat\rho_j), \end{align}</math> 其中 <math>\textstyle {\rm KL}(\rho || \hat\rho_j) = \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> 为均值的两个伯努利随机变量之间的相对熵。相对熵是一种标准的用来测量两个分布之间差异的方法。(如果你没有见过相对熵,不用担心,所有你需要知道的内容都会被包含在这份笔记之中。) 【一审】 为了达到这样的目的,我们将为我们的优化目标另外加入一个惩罚项,也即对与 <math>\textstyle \rho</math> 差别很大的 <math>\textstyle \hat\rho_j</math> 进行惩罚。惩罚项的选择有很多种,它们都可以得到很不错的效果。这里我们选择以下方式: :<math>\begin{align} \sum_{j=1}^{s_2} \rho \log \frac{\rho}{\hat\rho_j} + (1-\rho) \log \frac{1-\rho}{1-\hat\rho_j}. \end{align}</math> 这里, <math>\textstyle s_2</math> 是隐藏层神经元的数量,通过索引 <math>\textstyle j</math> 将对整个神经网络的隐藏单元加总。如果你了解KL距离的话,这个惩罚项就是以它为基础的,上式还可写成以下方式: :<math>\begin{align} \sum_{j=1}^{s_2} {\rm KL}(\rho || \hat\rho_j), \end{align}</math> 这里 <math>\textstyle {\rm KL}(\rho || \hat\rho_j) = \rho \log \frac{\rho}{\hat\rho_j} + (1-\rho) \log \frac{1-\rho}{1-\hat\rho_j}</math> 就叫作Kullback-Leibler(KL)距离,它表示的是分别具有平均值 <math>\textstyle \rho</math> 和 <math>\textstyle \hat\rho_j</math> ,服从贝努利分布的两个随机变量之间的差距。KL距离是度量两种分布差异度的项函数。(如果你之前没接触过KL距离,也不要紧,所有你需要知道的东西都包含在本教程中。) 【二审】 为了实现这一限制,我们将会在我们的优化目标函数中加入一个额外的惩罚因子,而这一惩罚因子将惩罚那些 <math>\textstyle \hat\rho_j</math> 和 <math>\textstyle \rho</math> 有显著不同的情况从而使得隐藏神经元的平均活跃度保持在较小范围内。惩罚因子的具体形式有很多种合理的选择,我们将会选择以下这一种: :<math>\begin{align} \sum_{j=1}^{s_2} \rho \log \frac{\rho}{\hat\rho_j} + (1-\rho) \log \frac{1-\rho}{1-\hat\rho_j}. \end{align}</math> 这里, <math>\textstyle s_2</math> 是隐藏层中隐藏神经元的数量,而索引 <math>\textstyle j</math> 依次代表隐藏层中的每一个神经元。如果你对相对熵(KL divergence)比较熟悉,这一惩罚因子实际上是基于它的。于是惩罚因子也可以被表示为 :<math>\begin{align} \sum_{j=1}^{s_2} {\rm KL}(\rho || \hat\rho_j), \end{align}</math> 其中 <math>\textstyle {\rm KL}(\rho || \hat\rho_j) = \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> 为均值的两个伯努利随机变量之间的相对熵。相对熵是一种标准的用来测量两个分布之间差异的方法。(如果你没有见过相对熵,不用担心,所有你需要知道的内容都会被包含在这份笔记之中。) 【原文】 This penalty function has the property that <math>\textstyle {\rm KL}(\rho || \hat\rho_j) = 0</math> if <math>\textstyle \hat\rho_j = \rho</math>, and otherwise it increases monotonically as <math>\textstyle \hat\rho_j</math> diverges from <math>\textstyle \rho</math>. For example, in the figure below, we have set <math>\textstyle \rho = 0.2</math>, and plotted <math>\textstyle {\rm KL}(\rho || \hat\rho_j)</math> for a range of values of <math>\textstyle \hat\rho_j</math>: 【初译】 这一惩罚因子有如下性质,当 <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 \hat\rho_j</math> 变化,相对熵值 <math>\textstyle {\rm KL}(\rho || \hat\rho_j)</math> 的变化。 【一审】 这个惩罚函数具有一种属性:即,如果 <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 \hat\rho_j</math> 的取值范围内,作出了函数 <math>\textstyle {\rm KL}(\rho || \hat\rho_j)</math> 曲线图: 【二审】 这一惩罚因子有如下性质,当 <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> 变化的变化。 [[Image:KLPenaltyExample.png|400px|center]] 【原文】 We see that the KL-divergence reaches its minimum of 0 at <math>\textstyle \hat\rho_j = \rho</math>, and blows up (it actually approaches <math>\textstyle \infty</math>) as <math>\textstyle \hat\rho_j</math> approaches 0 or 1. Thus, minimizing this penalty term has the effect of causing <math>\textstyle \hat\rho_j</math> to be close to <math>\textstyle \rho</math>. Our overall cost function is now :<math>\begin{align} J_{\rm sparse}(W,b) = J(W,b) + \beta \sum_{j=1}^{s_2} {\rm KL}(\rho || \hat\rho_j), \end{align}</math> where <math>\textstyle J(W,b)</math> is as defined previously, and <math>\textstyle \beta</math> controls the weight of the sparsity penalty term. The term <math>\textstyle \hat\rho_j</math> (implicitly) depends on <math>\textstyle W,b</math> also, because it is the average activation of hidden unit <math>\textstyle j</math>, and the activation of a hidden unit depends on the parameters <math>\textstyle W,b</math>. 【初译】 我们可以看出,相对熵在 <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> 的效果。 总体来说,我们的代价函数可以表示为 :<math>\begin{align} J_{\rm sparse}(W,b) = J(W,b) + \beta \sum_{j=1}^{s_2} {\rm KL}(\rho || \hat\rho_j), \end{align}</math> 其中 <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> 。 【一审】 我们看到,KL距离在 <math>\textstyle \hat\rho_j = \rho</math> 处达到了最小值0,而当 <math>\textstyle \hat\rho_j</math> 接近于0或1时,KL距离逐渐增大(最终达到 <math>\textstyle \infty</math> )。因此,要最小化这个惩罚项就等同于让 <math>\textstyle \hat\rho_j</math> 接近于 <math>\textstyle \rho</math> 。 最后,整体代价函数如下: :<math>\begin{align} J_{\rm sparse}(W,b) = J(W,b) + \beta \sum_{j=1}^{s_2} {\rm KL}(\rho || \hat\rho_j), \end{align}</math> 其中, <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> 。 【二审】 我们可以看出,相对熵在 <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> 的效果。 现在,我们的总体代价函数可以表示为 :<math>\begin{align} J_{\rm sparse}(W,b) = J(W,b) + \beta \sum_{j=1}^{s_2} {\rm KL}(\rho || \hat\rho_j), \end{align}</math> 其中 <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> 。 【原文】 To incorporate the KL-divergence term into your derivative calculation, there is a simple-to-implement trick involving only a small change to your code. Specifically, where previously for the second layer (<math>\textstyle l=2</math>), during backpropagation you would have computed :<math>\begin{align} \delta^{(2)}_i = \left( \sum_{j=1}^{s_{2}} W^{(2)}_{ji} \delta^{(3)}_j \right) f'(z^{(2)}_i), \end{align}</math> now instead compute :<math>\begin{align} \delta^{(2)}_i = \left( \left( \sum_{j=1}^{s_{2}} W^{(2)}_{ji} \delta^{(3)}_j \right) + \beta \left( - \frac{\rho}{\hat\rho_i} + \frac{1-\rho}{1-\hat\rho_i} \right) \right) f'(z^{(2)}_i) . \end{align}</math> 【初译】 为了将相对熵引入导数的计算,我们可以使用一个易于实现的技巧,这只需要在你的程序中稍作改动。具体来说,前面在后向传播算法中计算第二层( <math>\textstyle l=2</math> )更新的时候我们已经计算了 :<math>\begin{align} \delta^{(2)}_i = \left( \sum_{j=1}^{s_{2}} W^{(2)}_{ji} \delta^{(3)}_j \right) f'(z^{(2)}_i), \end{align}</math> 现在我们将其换成 :<math>\begin{align} \delta^{(2)}_i = \left( \left( \sum_{j=1}^{s_{2}} W^{(2)}_{ji} \delta^{(3)}_j \right) + \beta \left( - \frac{\rho}{\hat\rho_i} + \frac{1-\rho}{1-\hat\rho_i} \right) \right) f'(z^{(2)}_i) . \end{align}</math> 就可以了。 【一审】 为了将KL距离项整合进导数的计算中,这里有个易于实现的小技巧,只需对你的代码稍作改动。就比如说,在之前介绍反向传播算法的课程中,对于第二层( <math>\textstyle l=2</math> ),你应该计算得到: :<math>\begin{align} \delta^{(2)}_i = \left( \sum_{j=1}^{s_{2}} W^{(2)}_{ji} \delta^{(3)}_j \right) f'(z^{(2)}_i), \end{align}</math> 现在我们将其换成 : :<math>\begin{align} \delta^{(2)}_i = \left( \left( \sum_{j=1}^{s_{2}} W^{(2)}_{ji} \delta^{(3)}_j \right) + \beta \left( - \frac{\rho}{\hat\rho_i} + \frac{1-\rho}{1-\hat\rho_i} \right) \right) f'(z^{(2)}_i) . \end{align}</math> 【二审】 为了对相对熵进行导数计算,我们可以使用一个易于实现的技巧,这只需要在你的程序中稍作改动即可。具体来说,前面在后向传播算法中计算第二层( <math>\textstyle l=2</math> )更新的时候我们已经计算了 :<math>\begin{align} \delta^{(2)}_i = \left( \sum_{j=1}^{s_{2}} W^{(2)}_{ji} \delta^{(3)}_j \right) f'(z^{(2)}_i), \end{align}</math> 现在我们将其换成 :<math>\begin{align} \delta^{(2)}_i = \left( \left( \sum_{j=1}^{s_{2}} W^{(2)}_{ji} \delta^{(3)}_j \right) + \beta \left( - \frac{\rho}{\hat\rho_i} + \frac{1-\rho}{1-\hat\rho_i} \right) \right) f'(z^{(2)}_i) . \end{align}</math> 就可以了。 【原文】 One subtlety is that you'll need to know <math>\textstyle \hat\rho_i</math> to compute this term. Thus, you'll need to compute a forward pass on all the training examples first to compute the average activations on the training set, before computing backpropagation on any example. If your training set is small enough to fit comfortably in computer memory (this will be the case for the programming assignment), you can compute forward passes on all your examples and keep the resulting activations in memory and compute the <math>\textstyle \hat\rho_i</math>s. Then you can use your precomputed activations to perform backpropagation on all your examples. If your data is too large to fit in memory, you may have to scan through your examples computing a forward pass on each to accumulate (sum up) the activations and compute <math>\textstyle \hat\rho_i</math> (discarding the result of each forward pass after you have taken its activations <math>\textstyle a^{(2)}_i</math> into account for computing <math>\textstyle \hat\rho_i</math>). Then after having computed <math>\textstyle \hat\rho_i</math>, you'd have to redo the forward pass for each example so that you can do backpropagation on that example. In this latter case, you would end up computing a forward pass twice on each example in your training set, making it computationally less efficient. The full derivation showing that the algorithm above results in gradient descent is beyond the scope of these notes. But if you implement the autoencoder using backpropagation modified this way, you will be performing gradient descent exactly on the objective <math>\textstyle J_{\rm sparse}(W,b)</math>. Using the derivative checking method, you will be able to verify this for yourself as well. 【初译】 有一个需要注意的地方就是我们需要知道 <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> 的计算之后,你需要重新对每一个训练样本做一次前向传播从而可以对其进行后向传播的计算。对于后一种情况,你对每一个训练样本需要计算两次前向传播,所以在计算上的效率会稍低一些。 如何从上面算法得出梯度下降表达式的具体推导过程不再本教程的范围之内。不过如果你想要使用经过以上修改的后向传播来实现自编码神经网络,那么你就需要做以 <math>\textstyle J_{\rm sparse}(W,b)</math> 为目标函数的梯度下降。使用梯度验证方法,你可以自己确认自己的推导是否正确。 【一审】 其中细微的变化就是你要先知道 <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> 之后,你必须对每个样本再次进行前向运算,这样你才可以对这个样本作反向传播运算。对于后一种情况,你对每一个样本需要计算两次前向传播,所以在计算上的效率会稍低一些。 以上整个求导等式可以看出,本算法的梯度下降算法超出了本教程的范围,但是,如果你使用按以上方式调整过的反向传播算法运算自编码算法,你就需要以 <math>\textstyle J_{\rm sparse}(W,b)</math> 为目标函数执行梯度下降算法。使用梯度检验法,你可以自己来验证梯度下降算法是否正确。 【二审】 有一个需要注意的地方就是我们需要知道 <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> 的计算之后,你需要重新对每一个训练样本做一次前向传播从而可以对其进行后向传播的计算。对于后一种情况,你对每一个训练样本需要计算两次前向传播,所以在计算上的效率会稍低一些。 证明上面算法能达到梯度下降效果的完整推导过程不再本教程的范围之内。不过如果你想要使用经过以上修改的后向传播来实现自编码神经网络,那么你就会对目标函数 <math>\textstyle J_{\rm sparse}(W,b)</math> 做梯度下降。使用导数验证方法,你可以自己确认此说法。 {{Sparse_Autoencoder}}
Template:Languages
(
view source
)
Template:稀疏自编码器
(
view source
)
Return to
自编码算法与稀疏性
.
Views
Page
Discussion
View source
History
Personal tools
Log in
ufldl resources
UFLDL Tutorial
Recommended Readings
wiki
Main page
Recent changes
Random page
Help
Search
Toolbox
What links here
Related changes
Special pages