理解神经网络

神经网络为何如此成功?
这已经是一个困扰我们快三十年的问题了. 深度学习的广泛应用，反而加深了这种困惑. 为什么只需要稍微调整一下参数，就能将它应用到任何分类和预测的问题上，还总能得到不错的结果？对于好奇心旺盛的人而言，使用这样强大却难以解释的工具会带来强烈的不安感：还会有更好的选择吗？

这种不安感会随着神经网络的应用持续发酵. 神经网络中有大量的参数往往需要使用试错的方式来选择，包括隐藏层的数量、神经元的数量、激活函数的类型等. 训练神经网络的反向传播算法可能是神经网络其中最神秘的部分. 在理解这些过程之前，很难想象要怎样提高神经网络的效率.

所有这些困难本质上都指向了同一个问题：神经网络到底在做什么？什么使得它看起来无所不能？

答案在这里！准备好了吗？
简单地说，神经网络从数据中提取出了描述特征和标签性关联性的关键信息. 换句话说，神经网络的具体形式决定了我们可存储和计算的数据结构，而神经网络训练的结果给出的是使用该数据结构对特征与标签的统计关联的最佳刻画.

现在你一定有两个问题要问：真的么？为什么？

要回答“为什么”可能得花些功夫，我们为此写了一篇论文对此进行讨论. 用一句话总结的话，首先我们度量了信息对特定推断任务的价值，并发现了神经网络实际上是在提取数据中最有价值的信息. 同样的分析方法可以用在理解或比较其他学习算法，或者主成分分析和 压缩感知等方法中.

我们尝试用这个页面回答“真的么”这个问题. 要回答这个问题，我可以列出论文里的数学证明. 不过这里，我们尝试从数值上解释相关的结果，可能还带一点点数学以及直观的解释. 在一系列的实验之后，我们会介绍一个新的度量用来评价神经网络的“效率”. 在设计复杂的网络时，这个度量对于选择网络结构和超参数是尤其有用的.

我们希望这个页面可以：


 * 1) 为神经网络的初学者提供可参考的案例. 希望这些基础的案例在你开始编程时能有帮助.
 * 2) 为有丰富神经网络实践经验的工程师解释我们的研究. 我们将使用代码解释研究的核心想法，希望它可以使你更灵活高效地开展下一个项目.
 * 3) 为对理论感兴趣的统计学家提供附加材料. 本页面无法取代论文中的数学证明，但可以有效地解释我们论文里的核心想法.

为了理解这些实验：
你可以阅读这些代码和注释，并且接受运行结果；或者选择自己运行代码. 运行代码将需要一个标准的Python环境, 还会用到Numpy, Matplotlib等工具包. 当然，神经网络neural network的工具包也是需要的，这里我使用的是基于TensorFlow后台的Keras，安装过程可以参照这个链接. 我推荐使用Anaconda来安装和管理所有这些环境，应该只需要几分钟的时间. 当然，我会把实验现象都展示出来，悠闲地欣赏也会是不错的体验.

你会需要一些代码来初始化：

如果程序没有报错，那么恭喜你，至少环境配置没有问题. 现在，我们的旅途正式开始了！

一些实验
我们将会开展三个难度依次递进的实验. 在每个实验里，我们都会生成一系列的样本$$ (x_i, y_i), i=1, \ldots, N $$. 我们使用$$ x $$和$$ y $$分别作为神经网络的输入和对应的标签，并进行训练. 我们的目标是理解神经网络训练过程中到底发生了什么：神经网络从训练数据中“学习”到了什么，以及如何存储学习的结果. 为了解答这些问题，我们将在训练结束时提取出网络参数，并和参数的理论值进行对比；在某些情况下我们会跳过训练过程，直接将使用理论的参数值，并检查此时网络的性能.

这三个实验的大体内容如下：
 * 1) 我们从结构最简单的神经网络入手，即只有SoftMax输出层的单层神经网络. 这回帮助我们建立关于神经网络中权重计算的第一个数学公式；
 * 2) 接下来，我们考虑有一个隐藏层的网络，但我们限定数据集中的$$ x $$ 和 $$ y $$的只能取有限的离散值. 这实际上对应于有足够表达/拟合能力的神经网络，进而我们可以得到这个网络提取出的“理想”特征，并与理论最优的特征进行比较；
 * 3) 最后我们对多层神经网络进行研究，以理解表达能力不足的网络如何逼近“理想”的特征. 基于此，我们可以自然地定义对逼近效果的度量，从而可衡量不同网络结构表达特征的有效性.

数据样本生成
我们将生成一系列的数据样本$$(\underline{x}, y )$$，其中$$\underline{x}$$为数据的特征，$$y $$为数据所对应的标签. 有了这些样本之后，我们可以训练一个简单的 神经网络完成对特征的分类任务.

具体操作时，我们生成服从Dirichlet分布的一系列$$ \underline{x} $$. 分布的参数是随机选取的，但会与$$ y $$的值有关. 为什么要使用Dirichlet分布呢？当然，我们也可以使用更熟悉的混合高斯模型，但这样容易造成错误的印象：实验结果与数据分布密切相关，或者只在高斯条件下成立. 从这个意义上来说，Dirichlet分布显然是足够“非高斯”的. 这不是一个严谨的说法，欢迎你尝试其他更奇怪的概率分布，越多越好.

这是我用来生成数据的代码：

生成的数据大概长成这样. 我必须把数据对应的标签用不同颜色表明，否则几乎无法区分. 这个分类问题看起来不那么容易，是吧？图里面有点古怪的三角形，是由于Dirichlet分布的支撑集在一个单纯形上. 这里我们是在一个3维空间中的单纯形上生成了数据，然后将它们投影到二维空间，看起来就是三角形的样子.



用于分类问题的神经网络
现在，我们搭建一个神经网络来处理这些数据. 这里用到的网络只有一层，还不能称为深度学习；不过简单的结构会有助于我们的理解，也能够说明神经网络的SoftMax单元的一些特性. 这个网络的结构是这样：



神经网络所做的就是训练其中的参数$$(\underline{v}_j, b_j )$$，从而对特征进行相应的线性变换，可表示为$$Z_j = \underline{v}_j^{\mathrm{T}} \cdot \underline{x} + b_j$$，每个$$j$$对应不同的输出层神经元. 接下来，输出层通过SoftMax函数将这些$$Z_j$$转化为概率分布的形式

$$Q^{(v,b)}_{Y|\underline{X}}(j | \underline{x}) = \frac{e^{Z_l}}{\sum_i e^{Z_l}}$$

并且尝试最大化样本对应的似然函数值：

$$\max_{v, b} \sum_{i=1}^N \log Q_{Y|\underline{X}}^{(v,b)}(y_i| \underline{x}_i) $$

输出层节点的数量$$ K $$应该和标签所有可能取值的数量一样，对应于代码里的$$\text{Cy} = |{\mathcal Y}| $$. 使用Keras实现该网络的代码很简单：

从变量和函数名称里可以清楚地看出我们在做什么：model.add指定了网络的结构，接下来model.fit开始训练权重. 训练好的权重值可以通过调用model.get_weights获得，于是我们得到：

一个困扰我们几十年的问题是：这些权重到底代表什么？

这些权重是什么?
现在我们来计算$$ Y $$的经验分布以及每一类数据的经验平均值$$ {\mathbb E} [\underline{X}|Y=y] $$：

所得到的M是一个Cy行Dx列的矩阵. 对于range(C_y=8)中的每一个j， M[j,:]是一个Dx=2维的向量. M的每一列M[:, i]可以被看作是$$ y $$的一个函数. 可以注意到，神经网络计算的权重，即我们在图里画的$$ v_j $$们，也是一个Cy乘Dx的矩阵，它的每个元素对应从一条从输入层神经元到输出层神经元的连线. 我们希望对这两组取值进行比较. 在比较之前，我们需要使用以下的程序将所有$$ y $$的函数归一化，保证它们在经验分布PPy下是零均值和单位方差的.

现在我们可以准备画图了：

得到的结果类似这样：

是不是有点意思？所以神经网络的训练过程实际上在算的东西很简单：不同$$y$$对应的条件期望$${\mathbb E} [\underline{X}|Y=y] $$的经验值.

那么，为什么神经网络要费这么大劲去算条件期望呢？这个可以追溯到Alfréd Rényi以及HGR相关的的记号. 在论文里，我们证明了条件期望实际上是$$y$$的所有函数中，与分类问题最相关的函数.

好吧，如果HGR这些东西听起来过于抽象，你可以简单地认为有一个统计学家们希望计算的“好”的函数. 这个函数可能和经典概念中所说的描述$$(\underline{X}, Y)$$的充分统计量有些不一样. 在这里，由于输入特征维度过高且具有复杂的结构，很难通过学习得到像充分统计量这样完整的信息. 神经网络则限定了我们能够学习到包含多少个自由参数的函数，而这个数量远小于描述$$(\underline{X}, Y)$$完整的统计模型所需要的参数个数. 因此，我们希望通过比较少的参数有效地对完整的统计模型进行逼近. HGR相关的概念以及我们的论文说的就是，我们可以从理论上分析什么样的函数可以给出最佳的逼近；我们的结果表明，神经网络所给出的参数正是理论上逼近效果最好的，而且这些参数正是以权重的方式存储在网络中！

无需训练的神经网络
到这里，我想我们可以来点更大胆的想法. 我们可以构造一个神经网络但并不训练，而是直接把权重的理论值填进去，看看结果会怎样！

我们用到的代码应该长这样：

本质的变化是，这里没有出现model.fit函数. 这里，我们用函数makeup_1layer计算所有这些权重，并用model.set_weights直接设置了权重值. 这种做法相当于只是把神经网络作为一个特定的数据结构，并使用我们自己造的函数替代了反向传播/训练过程. 之后，我们可以用model.predict_classes检查这个新网络的性能.

我们计算权重的函数如下:

更明确地说，这段程序实际在计算

$$ \underline{v}_j = \frac{{\mathbb E}[\underline{X} | Y=j]}{\sigma^2}; \qquad b_j= \log P_Y(j) - \frac{\|{\mathbb E}[\underline{X} | Y=j]\|^2}{2\sigma^2} $$

其中$$ {\mathbb E}[\cdot] $$是经验平均，$$ \sigma^2 $$是$$ \underline{x}$$中元素经验方差的平均值.

毋庸讳言，计算的这些权重表现不错，可以和Keras训练出来的结果相比拟. 换句话说，神经网络的所有秘密都藏在这两个等式里！

实验2: 离散数据输入
上一个实验远远不能满足我们对深度学习的好奇心，尽管它已经说明了SoftMax输出层的作用. 对实际的深度神经网络而言，似乎中间上百个隐藏层对网络性能的影响更大. 那么这些隐藏层都起了什么作用呢？

为了研究这个问题，我们把之前的单层神经网络稍作修改，得到如下的网络.



暂且将红色的虚线看作是神经网络中的许多层，它们构造了特征$$ S(x) $$，即输入$$ x $$的一个函数，并将它送到SoftMax输出层中. 神经网络会选择什么样的函数$$ S(\cdot) $$呢？直觉告诉我们，$$ S(x) $$应该会是一个“有信息量”的特征以帮助我们完成对$$ y $$的推断过程. 但什么样的特征会是“有信息量”的？

为了回答这个问题，我们先看一个简单的情形. 当$$ x $$只从有限集合$$ \{ 1, \ldots, m\} $$取值时，若神经网络输入为指示函数，或者说one-hot编码的形式，设此时经过一个隐藏层后我们将得到$$ S(x) $$. 这个简单例子的精妙之处在于，任何形式的$$ S(x) $$ 都可以通过选择合适的权重$$ w_1, \ldots, w_m $$生成：

$$ S(x) = \sigma\left( \sum_{i=j}^m w_j \cdot \mathbb{I}_{x=j}\right) $$

其中$$ \sigma(\cdot) $$为激活函数，这里我们选用sigmoid函数. 换句话说，这个单隐藏层的神经网络具有足够的表达能力. 我们的问题是，当我们给神经网络选择特征的自由时，它会选择什么样的$$ S(x) $$？为什么？

生成数据样本
我们通过随机的方式产生联合分布$$ p_{XY} $$. 这不是必要的，你也可以选择任何其它想要的联合分布. 这里的随机，只是为了避免产生精心选择实验条件的印象. 好吧，如同所有非数学的表述，这样也说不清楚到底生成了什么. 尽管如此，我们是这样生成的：

值得一提的是，这个函数在生成数据之后返回的是分布$$ p_{XY}, p_X, p_Y $$. 这可能有作弊的嫌疑，因为更严格的方法应该仅仅返回生成的数据样本，再调用另一个函数根据样本计算联合分布及边缘分布的经验值. 基于对大数定理的信心，这里我们省去了这一步骤.

这时候我们已经可以计算两个函数，作为理论结果：

正如变量的名字所暗示的，计算得到的S_theory和v_theory将作为理论结果并与神经网络训练的结果进行比较. 别急，我很快会说明它们的计算过程. 如果不留一点点悬念，这个wiki页面会是多么的无趣！

在使用我们的数据样本之前，需要把它们转化成one-hot编码的形式. 这可以通过sklearn中标准的函数完成：

运行神经网络
现在我们准备构造一个神经网络用来学习这些数据. 这是Keras中相当标准的流程：

代码最后一行所得到的weights是一个列表，列表中有两个元素与我们图中的权重$$ w, v $$相对应. 我们把它们拿出来并进行如下的处理，其中regulate函数用于对结果归一化. 在这之后，我们就可以将结果画出来并与理论值进行比较了.

需要指出的是，这里我们使用了'expit'函数来计算$$ S $$，因为我们使用了sigmoid作为激活函数. 这样计算得到的$$ S(x) $$就对应于我们图中隐藏层的输出，也就是神经网络所提取的特征.

这里给出一个典型的结果：意外不意外？训练值和理论值看起来是一样的！现在是不是有点好奇理论值的计算方式，或者说WhatTheorySays函数的内容了？



What Theory Says?
首先，我们使用真实分布 $$ p_{XY} $$ 作为了WhatTheorySays的输入参数，这其实是在作弊. 原则上，我们应该输入的是所有的训练样本，以保证WhatTheorySays获取的信息和神经网络完全一样. 你当然可以计算经验的联合分布来替代 $$ p_{XY} $$ ，因为大数定理的作用，结果应该是一样的. 这里的情形更为微妙：我们提供的样本数量可能还不足以精确地学习出 $$ p_{XY} $$，因为 $$ {\mathcal X} $$ 和 $$ {\mathcal Y} $$ 可能是很大的字母集. 但是为了使得神经网络能够正常工作，我们只需要保证联合分布中与任务相关的部分有比较准确的估计. 这是一个重要的有关控制算法样本复杂度的事实. 在我们的例子里，两个字母集都很小，避免了有关样本复杂度的讨论. 有兴趣的读者可以试着增大字母集，即程序中的xCard, yCard，看看神经网络和我们的方法哪一个会先失效.

聊完这些后，我们来看一下代码：

比你想象的简单多了，不是么？是的，这就是神经网络所计算的！以数学形式表达，这段代码所做的是：首先构造一个大小为 $$ |{\mathcal Y} | \times |{\mathcal X}| $$ 的矩阵 $$ B $$，矩阵各元素与特定的$$ (x, y) $$取值相对应:

$$ B(y, x) = \frac{p_{XY}(x, y)}{\sqrt{p_X(x)} \sqrt{p_Y(y)}} $$

在这之后我们对 $$ B $$ 矩阵进行奇异值分解(SVD)，并选出第二大奇异值对应的左右奇异向量 $$\underline{r}_1 \in {\mathbb R}^{|{\mathcal Y}|} $$ 和 $$ \underline{u}_1 \in {\mathbb R}^{|{\mathcal X}|}$$. 将 $$ \underline{u}_1, \underline{r}_1 $$ 分别视为 $$ {\mathcal X, Y} $$ 的实值函数，并作归一化

$$ S(x) = \frac{u_1(x)}{\sqrt{p_X(x)}}, \quad v(y) = \frac{r_1(y)}{\sqrt{p_Y(y)}} $$

这样得到的 $$S, v $$ 就是我们的理论结果. SVD的性质保证了它们是零均值和单位方差的因此我们这里不需要regulate函数了. 这就给出了你看到的图中的结果.

被这些公式绕晕了？别慌，让我们走近再瞧一瞧.

B 矩阵
首先，你可能会觉得我们引入的归一化方式有一点奇怪. 这个归一化建立了数据的函数及可以操作的向量之间的对应关系. 在 $$ X $$ 空间中，我们将函数 $$ S : {\mathcal X} \mapsto {\mathbb R} $$ 以向量形式表达为 $$ \underline{u} \in {\mathbb R}^{|{\mathcal X}|} $$. 在 $$ Y $$空间中，归一化方式是 $$ v(y) = r(y) /\sqrt{p_Y(y)} $$. 这样建立了函数与向量之间的对应关系 $$ \underline{u} \leftrightarrow S, \underline{r} \leftrightarrow v $$. 在我们进一步解释之前，暂且认为这个奇怪的归一化方式是给定的.

你可能会问，我们之前不是已经计算过 $$ v(y) $$ 的表达式了，它不就应该等于 $$ v(y) = {\mathbb E} [ S(X)|Y=y] $$ 吗？

是的，这正是我希望你问的问题.

结果表明，这里的和之前问题的答案确实完全一样. 我们从刚才定义的 $$ B $$ 矩阵入手，寻找些线索. $$ B $$ 矩阵有许多漂亮的性质，其中一个出现在 $$ B $$ 矩阵与向量做乘法时.

考虑 $$ \underline{r} = B \cdot \underline{u} $$ ，其中 $$ \underline{u}, \underline{r} $$ 分别和函数 $$ S(x) $$ 及 $$ v(y) $$ 相对应. 把这个乘法的计算过程写出来：

$$ \begin{align} v(y) &= \frac{1}{\sqrt{p_Y(y)}} r(y) = \frac{1}{\sqrt{p_Y(y)}} \sum_x B(x, y) u(x) \\ & = \frac{1}{\sqrt{p_Y(y)}} \sum_x B(x, y) \sqrt{p_X(x)} \cdot S(x) \\ &= \frac{1}{\sqrt{p_Y(y)}} \sum_x \left( \frac{p_{XY}(x,y) } {\sqrt{p_X(x)} \sqrt{p_Y(y)}} \right) \sqrt{p_X(x)} \cdot S(x)\\ &= {\mathbb E} [S(X)|Y=y] \end{align} $$

换句话说，矩阵乘法 $$ \underline{r} = B \cdot \underline{u} $$ 定义了一个映射关系，将定义在 $$ {\mathcal X} $$ 空间上的特征 $$ S(\cdot) $$ 映射为 $$ {\mathcal Y} $$ 上对应的特征 $$ v(\cdot) $$ ，而且 $$ v(y)={\mathbb E} [S(X)|Y=y] $$. 正如我们已经看到的那样，这个映射关系和神经网络的运行机制密切相关.

不难验证，与之共轭的操作 $$ \underline{u} = B^{\mathrm{T}} \cdot \underline{r} $$ 定义了反方向的映射，将 $$ y $$ 的函数 $$ v(y) $$ 映射为 $$ x $$ 的函数 $$ S(x) = {\mathbb E}[v(Y)|X=x] $$.

特征投影
现在我们可以大致描述神经网络的运行机制了. 最开始，网络中的所有系数都是随机选择的，因此相应的特征 $$ S(x) $$ 和输出层权重 $$ v(y) $$ 也是随机的. 在反向传播算法的执行过程中，我们首先固定了 $$ S(x) $$ 来更新 $$ v(y) $$ ，这可以看作是在找和 $$ S(x) $$ 最“吻合”的 $$ y $$ 的特征 $$ v(y) $$ ，而这个 $$ v(y) $$ 就是 $$ v(y) = {\mathbb E} [S(X)|Y=y] $$. 下一步，我们固定 $$ v(y) $$ 找与之相吻合的 $$ x $$ 的特征，也就是 $$ S(x) = {\mathbb E}[v(Y)|X=x] $$. 这样多次迭代之后， $$ S(x) $$ 与 $$ v(y) $$ 最终将完美地吻合.

在刚才的描述里，我们在重复地回答一个问题：一个变量什么样的特征与另一个变量的特征是最吻合的. 我们将这个问题的结果称为“特征投影”：如果我们要在所有 $$ y $$ 的特征的空间中寻找 $$ S(x) $$ 的投影，那这个投影的结果正是条件期望 $$ v(y) = {\mathbb E} [S(X)|Y=y] $$.

特征投影的故事将自然引出的理论结果中的SVD. 设 $$ \underline{u}, \underline{r} $$ 是 $$ B $$与奇异值 $$ \sigma $$ 对应的一组奇异向量，我们有 $$ \sigma \cdot \underline{r} = B \cdot \underline{u} $$ 以及 $$ \sigma \cdot \underline{u} = B^{\mathrm{T}} \cdot \underline{v} $$. 暂时不用关心这里的比例因子 $$ \sigma $$ ，毕竟它已经程序里的regulate处理了. 当我们需要计算SVD时，可以考虑使用幂法. 也就是说，我们随机选择一个 $$ \underline{u} $$ 的初始值，然后重复地左乘上 $$ B^{\mathrm{T}} B $$. 你可以发现这实际上就是在做特征投影.

在论文里，我们表明最终的 $$ \underline{u}, \underline{r} $$ 对就是 $$ B $$ 的第二大奇异值所对应的奇异向量. 这样的 $$ \underline{u}, \underline{r} $$ 提炼出了 $$ X $$ 和 $$ Y $$ 最强的相关模式. 这正是这样的特征被用于神经网络预测的原因. 这个故事可以很容易地推广到有 $$ k $$ 对奇异向量的情形，此时提炼出的是最强的 $$ k $$ 个相关模式，对应神经网络在输出层的前一层有 $$ k $$ 个神经元的情形.

还漏了一件事情：这里为什么选择第二大奇异值对应的奇异向量，而不是最大的. 事实上，第一对奇异向量的值是固定的：

$$ \underline{u}_0 = [\sqrt{P_X(x)}, x \in {\mathcal X}], \underline{r}_0 = [\sqrt{P_Y(y)}, y \in {\mathcal Y}] $$,

它们对应的奇异值是 $$\sigma_0= 1 $$. 这可通过简单的计算验证： $$ \begin{align} B \underline{u}_0 = \sum_x B(y,x) \sqrt{P_X(x)} = \sum_x\left( \frac{P_{XY}(x, y)}{\sqrt{P_X(x)}\sqrt{P_Y(y)}}\right)\cdot \sqrt{P_X(x)} = \sqrt{P_Y(y)} \end{align} $$

所有其他的奇异向量都必须和第一对奇异向量正交，即

$$ \begin{align} 0 = \langle \underline{u}_0, \underline{u} \rangle = \sum_x \sqrt{P_X(x)} \cdot \sqrt{P_X(x)} S(x) = {\mathbb E}[S(X)] \end{align} $$

这意味着对应于 $$ \underline{u} $$ 的特征 $$ S(x) $$ 必须关于分布 $$ P_X $$ 是零均值的. 不失一般性，我们假设选取的特征都是零均值的. 可以发现，$$ B $$ 的其它奇异值都不大于1，这是数据处理不等式的一个简单推论. 因此，第二对奇异向量其实是第一对非平凡的奇异向量.

在我们的论文里，我们实际上使用了如下的 $$ \tilde{B} $$ 作为 $$ B $$ 的定义. $$ \tilde{B} $$ 中除去了平凡的那对奇异向量的影响，更清晰地反映了 $$ X $$ 和 $$ Y $$ 之间的相关性.

$$ \begin{align} \tilde{B} (y,x)= \frac{P_{XY}(x, y)}{\sqrt{P_X(x)}\sqrt{P_Y(y)}} - \sqrt{P_X(x)}\sqrt{P_Y(y)} = \frac{P_{XY}(x, y) - P_X(x) P_Y(y)}{\sqrt{P_X(x)}\sqrt{P_Y(y)}} \end{align} $$

实验3: 受限的表达能力
目前，我们已经知道神经网络在基于输入样本 $$ X $$预测 $$ Y $$ 时，网络使用训练样本所“学习”到的是两个特征$$ S(x) $$ 及 $$ v(y) $$ ，并以权重的形式存储在神经网络中. 这两个特征可表示为以下问题的解：

$$ \begin{cases} S(x) = {\mathbb E}[v(Y)|X=x]\\ v(y) = {\mathbb E}[S(X) |Y=y] \end{cases} $$

而且，它们对应于一个矩阵 $$ \tilde{B} $$ 的奇异向量，因此可以解释为 $$ X $$ 和 $$ Y $$ 最强的相关“模式”.

换句话说，神经网络有清晰的计算目标，并且我们解释了这样计算的优点.

但这个目标要求这个网络有足够强的表达能力，即可以表达任何形式的特征. 为此，我们在上一个实验里限制了输入的 $$ x $$ 只取离散值. 但在这里，我们更进一步地讨论神经网络表达能力不足的情况. 这是我们将神经网络用于自然语言处理、计算机视觉等应用时都将面临的问题. 直观地看，这时候网络应该寻找次优解，即在所有能够生成的特征中找到与SVD所得出理想特征最接近的一个. 我们希望能够验证并更好地理解这个直观的想法.

这是我们准备研究的网络：



离散数据，连续数据
这个网络和之前的主要区别在于，这里的输入数据 $$ T_1, \ldots, T_m $$ 取的是连续值，而之前我们假设输入是离散随机变量 $$ X $$ 的one-hot编码.

这个改动为什么值得一提呢？如果你仔细检查刚才的解法，我们指出神经网络是在计算联合分布 $$ P_{XY} $$ 的一个函数. 当输入 $$ T $$ 取连续值的时候，并不是我们不能类似地做联合分布 $$ P_{TY} $$ 的假设，而是像 $$ {\mathbb E}[v(Y)|T=t] $$ 的记号不再有意义. 仔细考虑一下，这个条件期望是 $$ t $$ 的函数. 我们可能指望对接近的 $$ t $$ 和 $$ t+ \delta $$ ，对应条件期望的值也很接近，但是数据似乎并不能保证这一点. 当然，一个自然的考虑是对数据进行平滑操作，但这样很难给出漂亮的解析结果.

所以我们计划这样：不直接将一组随意的连续值的数据送到神经网络中，而是假设在 $$ T $$ 的背后存在一个离散取值的 $$ X $$. 也就是说，在获取数据的过程中，我们不能直接观测到离散取值的 $$ X $$ ，而是 $$ X $$ 经过“预处理”（pre-processing）后的结果，也就是连续取值的 $$ T $$. 预处理的方式是给定的. 现在问题是：神经网络会怎样处理这些预处理后的数据样本呢？

这样的视角可以帮助我们理解深度神经网络：从多层神经网络中的每一层看，前一层都是在做特定方式的预处理；在给定预处理方式后，神经网络会通过反向传播算法来分配相应的权重；而我们这里要解决的，正是解读这个权重的问题.

这会引出有点哲学意味的问题：我们是不是总可以将连续取值的数据看作是，某个离散取值的数据源预处理后的结果？我们给出的答案是：几乎总是如此！尤其是，当我们允许 $$ X $$ 的字母集很大的时候. 这不是严格的数学陈述，我们先把它作为假设.

这样的假设会使神经网络“表达能力”的概念发生变化. 一般地，我们认为表达能力解决的问题是，给定的网络能否能够产生输入 $$ T $$ 的任意函数. 为此，我们希望网络可以尽量复杂，或者说需要更多神经元和更多层，以产生更复杂的 $$ T $$ 的函数. 现在如果假设 $$ T $$ 是被离散数据源 $$ X $$ 所驱动的，那我们只需要有限的网络. 以图中网络为例，如果 $$ m \geq L $$ ，也就是预处理结果的维度大于输入 $$ X $$ 字母集的大小，那么只要让 $$ w $$ 取合适的值，网络就可以完成预处理的逆过程. 这样，我们就回到了输入取离散值的情况. 在现实中，一方面 $$ X $$ 的字母集会非常的大，另一方面预处理过程中不可避免地包含噪声，因此即便是这样“有限的网络”也会非常的大. 我们不能因此就放弃让老板给换GPU的想法.

好！聊了这么多，我们来做些实验吧.

运行神经网络
这是我们生成数据的方式：

函数Generate2DSamples和之前的实验一样，首先随机选择联合分布 $$ P_{XY} $$ 并依次生成数据样本. MakeLabels和之前一样用于one-hot编码. 这里只是增加了一个随机生成的“预处理”矩阵，用于产生对应于每个 $$ x_i $$ 的 $$ T(x_i) $$. 注意我们保证了xCard > tDim，用图里的记号表示就是 $$ L > m $$ ，否则问题就会成为平凡的.

现在我们把数据 $$ (T(x_i), y_i) $$ 送到神经网络里：

训练这个网络，我们就可以得到权重. 现在就剩检验权重了？

检验权重
我们已经证实了，将离散数据源 $$ X $$ 输入神经网络，训练的结果应该满足

$$ \begin{cases} v^*(y) = {\mathbb E} [S^*(X)|Y=y]\\ S^*(x) = {\mathbb E} [v^*(Y)|X=x] \end{cases} $$

还可以非常漂亮地被解释为矩阵 $$ \tilde{B} $$ 的奇异向量.

现在我们将 $$ X $$ 换为预处理的结果 $$ T(x) $$. 第一个等式应该是一样的：

$$ v(y) = {\mathbb E} [S(T(X)) | Y=y ] $$

第二个等式不再成立，因为我们可能得不到函数 $$ S^*(x) $$. 神经网络的结构限制了特征 $$ S(x) $$ 只能取特定的形式

$$ S(x) = \sigma\left( \sum_{j=1}^m w_j \cdot T_j(x) + d\right) $$

其中 $$ \sigma(\cdot) $$ 是sigmoid函数，各 $$ T_j(\cdot) $$ 的形式是给定的. 直观上，我们可以做的是选择合适的权重 $$ (w_1, \ldots, w_m, d) $$ 是的所生成的 $$ S(x) $$ 在某种意义上尽量“接近”我们想要的 $$ S^*(x) $$.

回顾之前的内容，条件期望可以解释为特征投影. 对于给定的特征 $$ v(y) $$，我们希望找到 $$ x $$ 的特征使其与 $$ v(y) $$ 最吻合. 对应结果就是条件期望 $$ S(x) = {\mathbb E} [v(Y) |X=x] $$. 现在，我们的问题做了一个小的改动. 对于给定特征 $$ v(y) $$，我们希望找到可以由诸 $$ T_j(x) $$ 以特定形式生成的特征，并使得它与 $$ v(y) $$ 最吻合. 这在概念上只是做了一点推广，因此我们称之为“有约束的特征投影”.

要在数值计算层面验证刚才的直觉并不容易，因为这里对 $$ S(x) $$ 的约束是非线性的. 另一个更不明显的困难来自神经网络的偏置项. 这些困难，让我们逐一来处理.

讨厌的偏置
偏置项，即图中的 $$ b_1, \ldots, b_k $$ ，在这里是一个枯燥又碍事的存在.

从特征投影角度来看，神经网络做的是一个特征到另一个特征的线性映射，加减常数显然对结果而言是无关紧要的. 因此我们应该将注意力集中在零均值的特征上. 这里的零均值是相对于边缘分布而言，即 $$ S(x) $$ 在分布 $$ P_X $$ 下、 $$ v(y) $$ 在分布 $$ P_Y $$ 下是零均值的.

为得到零均值的特征，我们引入相应的记号

$$ \begin{align} \tilde{S}(x) &= S(x) - {\mathbb E}[S(X)], \\ \tilde{v}(y) &= v(y) - {\mathbb E}[v(Y)] \end{align} $$

于是特征投影可表达为

$$ \begin{cases} \tilde{S}(x) = {\mathbb E}[\tilde{v}(Y)|X=x]\\ \tilde{v}(y) = {\mathbb E}[\tilde{S}(X)|Y=y] \end{cases} $$

遗憾的是，神经网络并不喜欢这样简单而优雅的形式. （而你还在操心人类会不会被AI取代. ）神经网络的做法是控制这些函数的均值，使得神经元在激活函数特定的工作点附近起作用，以利用激活函数的非线性特性. 因此，神经网络的输出几乎都不是零均值的. 例如，sigmoid函数的输出就总为正，因此不会是零均值的.

这就是在对比网络训练结果与理论结果时，总需要用regulate函数先作归一化的原因. 在神经网络里，偏置节点实际上会对非零均值的特征做补偿. 如果将偏置项 $$ b_1, \ldots, b_k $$ 看作一个函数 $$ b(y) $$ ，它实际上满足

$$ b(y) = \log P_Y(y) - v(y) \cdot {\mathbb E} [S(X)] $$

其中第二项就是用于补偿 $$ S(x) $$ 均值的作用. 在偏置项的作用下，神经元实际输出为 $$ v(y) \cdot S(x) + b(y) = v(y) \cdot \tilde{S}(x) + \log P_Y(y) $$

也就是说，在输出层看来，特征 $$ S(x) $$ 总是零均值的.

这个事实可以很容易通过下面的代码来验证，其中weights是通过model.get_weights函数得到的神经网络权重.



得到的运行结果长这样.

你会发现我们在计算b和b_theory的时候，我们也减去了均值. 这个均值是相对于分布 $$ P_Y $$ 而言的. 因为输出层的Softmax函数也是非线性的，偏置项又出来捣乱了. 是挺讨人厌的！

细心的读者可能发现在第一个实验里，我们构造的偏置项使用了另一个公式

$$ b(y) = \log P_Y(y) - \frac{({\mathbb E}[S|Y=y])^2}{2 \cdot {\rm var}[S]} $$

论述这两个公式的等价性会显得相当乏味，不过道理很简单：表达式形式不同是因为我们用了不同的归一化方式.

本质特性
现在，讨厌的偏置已经被扔到一边，我们来看一下神经网络是怎么做特征投影的. 回顾一下，隐藏层神经元理想的输出为

$$ S^*(x) = {\mathbb E} [ \tilde{v}(Y)| X=x] = {\mathbb E}[v(Y)|X=x] - {\mathbb E}[v(Y)] $$

我们的假设是，神经网络会生成 $$ \tilde{S}(x) = S(x) - {\mathbb E}[S(X)] $$ 来逼近理论解 $$ S^* $$. 神经网络通过选择权重 $$ w_1, \ldots, w_m, d $$ 实际生成的是非零均值的

$$ S^{(w, d)}(x) = \sigma\left( \sum_j w_j T_j(x) + d \right) $$

不过，我们知道均值在下一层会被偏置项补偿，因此并不影响.

我们做个大胆的假设，假设逼近是在均方误差意义下的. 现在，逼近问题可以写成

$$ \min_{w, d} \sum_x P_X(x) \cdot ( S^{(w, d)}(x) - {\mathbb E}[S^{(w, d)}(X)] - S^*(x))^2 $$

或者使用 $$ \tilde{S} $$ 的记号，写成

$$ \min_{w, d} \sum_x P_X(x) \cdot (\tilde{S}^{(w, d)} (x) - S^*(x))^2 $$

现在，我们可以对目标求导了：

$$ \begin{align} 0 &= \frac{\partial}{\partial w_j } \sum_x P_X(x) \cdot (\tilde{S}^{(w, d)} (x) - S^*(x))^2\\ &= \sum_x P_X(x) \cdot (\tilde{S}^{(w, d)} (x) - S^*(x)) \cdot\left( \frac{\partial}{\partial w_j} \tilde{S}^{(w, d)}(x)\right) \end{align} $$

这可以看做是函数 $$ (\tilde{S}^{(w, d)} (x) - S^*(x)) $$ 与函数 $$ \left( \frac{\partial}{\partial w_j} \tilde{S}^{(w, d)}(x)\right)$$ 的正交性，其中内积定义为 $$ P_X $$ 加权后的标准内积. 因为两个函数都可以按比例缩放，我们很难在数值上判断内积是否足够接近0. 因此，我们转而检查这两个函数的夹角是否接近 $$ \pi/2 $$ ，或者说 $$ 90 ^\circ $$.

唯一需要小心的是第二个带导数的函数表达式. 我知道许多人，包括我自己，都还记得 sigmoid函数的导数表达式： $$ \sigma'(z) = \sigma(z) \cdot (1- \sigma(z)) $$. 然而，这里我们需要将导数的均值减去：

$$ \begin{align} \frac{\partial}{\partial w_j} \tilde{S}^{(w, d)}(x) &= \frac{\partial}{\partial w_j} \left[ S^{(w, d)} (x) - \sum_{x'} P_X(x') S^{(w, d)}(x') \right] \end{align} $$

用我们的记号就可以简单地写成 $$ \widetilde{\frac{\partial }{\partial w_j} S^{(w, d)}}(x) $$，也就是零均值版本的导数. 最后，我们将以下结果代入：

$$ \frac{\partial}{\partial w_j} S^{(w, d)} (x) = S^{(w, d)}(x) (1-S^{(w, d)}(x)) \cdot T_j(x) $$

现在我们可以再次准备编程了：

结果如何？这是一组典型的结果：

服不服气?

深度学习的理论
如果你在Google搜索栏中输入“神经网络”，那么“解释”很可能是下一个候选词. 实际上，有很多工作都试图对神经网络的工作机制进行解释，但我还没看到能够对网络学习结果进行定量描述并验证的. 这个意义上，我相信我们已经取得了一些进步.

这里我们没有在理论方面深入，也不指望用这些简单的实例证明什么. 我只希望用这些实验解释关键的想法，以及展示我们的理论在若干特定场景下的应用. 以上可能足够让一些读者有兴趣阅读我们的论文. 在论文里，我们给出了一个更完整的图景. 首先，我们论述了需要一个新的衡量信息的方式. 在设计了这样的度量后，我们可以用它来描述任何数据处理过程中的信息流动情况，包括信息的保留和丢弃过程，并对每个处理过程给出评价. 接着我们表明，之前说的求 $$ \tilde{B} $$ 奇异向量的过程是一个好的信息处理方式——它提取了 $$ X $$ 和 $$ Y $$ 关联中最强的模式，或者说提取了 $$ X $$ 和 $$ Y $$ 的“共同信息”中最为重要的部分. 可能更重要的是，这样选出的特征在我们称为“通用特征选择”的问题中是最优的.

在经典统计学中，当我们需要从数据中选取某些特征以进行推断时，应该选择的是充分统计量. 在大多数学习问题中，当我们面临高维数据样本时，很难精确得知数据的哪些属性对之后的推断有帮助. 例如，单看顾客的消费行为，我们并不清楚哪些消费行为会对之后为顾客推荐产品的过程有影响. 从而，对于尚未明确的新任务，我们无法针对特定任务构建充分统计量. 取而代之的是，我们需要选取一系列的特征，无论新任务依赖于哪个特征，要保证基于这些特征的决策在“通用”意义下是好的. 对这个问题，我们表明奇异向量的选择确实是通用意义下最优的. 也就是说，对任何特征选取问题，只要特征不是用来解决某一个统计模型已知的任务，最明智的选择是选取这样的通用特征. 而神经网络作为解决这类问题的一个工具，正是给出了通用特征的解决方案. 这个结果是前面三个实验的基础.

尤其在深度学习这个领域，我希望能够避免过度强调我们结果的重要性，比如做“打开深度学习黑箱”这样的论述. 陈述结论最好的方式，是给出相应的数学结果. 既然我们没有在这里做这件事，我认为至少要澄清这个理论能做与不能做的事情. 下面就开始吧.

神经网络的一个性能度量
基于理论，我们可以得到一个神经网络的性能度量. 如果我们沿用记号 $$ \underline{S}(x) = [S_1(x), \ldots, S_k(x)] $$ 作为最后一个隐藏层的 $$ k $$ 个神经元的输出，并用 $$ \underline{v}(y) = [v_1(y), \ldots, v_k(y)] $$ 表示输出层的权重，我们的理论表明神经网络的目的是让这两者的相关——$$ {\mathbb E}[ \langle\underline{S}(x), \underline{v}(y)\rangle] $$ ——尽可能地大. 这个问题的最优解就是从SVD的奇异向量中得到的诸 $$ S(x) $$ 和 $$ v(y) $$. 然而由于网络结构限制了其表达能力，我们通常达不到这样的最优值. 用实际解和最优解之间的间隙可以很好地度量神经网络的有效性.

H-Score
为此，可以定义我们称之为"H-score"的性能度量. 对于给定网络，设其所训练得到的特征和权重分别为 $$ S(x) $$ 和 $$ v(y) $$. 需要注意的是，神经网络并不使用我们习惯的坐标系统表达结果，而是引入了一系列平移、放缩和旋转的操作. 因此，我们首先需要将 $$ \tilde{S}(x), \tilde{v}(y) \in {\mathbb R}^k $$ 减去均值，得到中心化的特征和权重，并定义 $$ \Phi = [\phi_1, \ldots, \phi_k], \Psi= [\psi_1, \ldots, \psi_k] $$，其中

$$ \begin{align} \phi_i (x) &= \sqrt{P_X(x)} \cdot \tilde{S}(x) \\ \psi_i (y) &= \sqrt{P_Y(y)} \cdot \tilde{v}(y) \end{align} $$

那么"H-score"定义为

$$ \begin{align} H(S, v) &:= \|\tilde{B}\|^2 - \| \tilde{B} - \Psi \Phi^{\mathrm{T}} \|^2\\ &= 2 {\mathbb E}[ \underline{S}^{\mathrm{T}}(X) \underline{v}(Y) ] - {\rm trace} ({\rm cov}(\underline{S}(X)) {\rm cov}(\underline{v}(Y))) \end{align} $$

如果仅对特征 $$ S(x) $$ 的评价感兴趣，我们可以将权重 $$ v(y) $$ 的理论解代入，得到单边的H-score

$$ \begin{align} H(S) := H(S, v^*) &= \| \tilde{B} \Phi (\Phi^{\mathrm{T}} \Phi) ^{-\frac{1}{2}}\|^2 \\ &= {\mathbb E}_{P_Y} [ \ {\mathbb E} [\underline{S}(X) |Y=y]^{T} \cdot {\rm cov}(\underline{S}(x))^{-1} \cdot {\mathbb E} [\underline{S}(X) |Y=y]\ ] \end{align} $$

在实际应用中，上式中所有的期望和协方差都可以用它们的经验平均替代. 于是我们可以计算神经网络各层提取特征对应的H-score，以此评价这些特征的好坏.



为了演示如何使用H-score，我们设计了以下的分类实验，所用的数据如图所示. 这些杂乱的数据由混合高斯模型产生，图中显示的是所用六维数据中的前两维，用不同颜色表示不同的类别. 我们使用一个多层感知器来对数据分类，并观察训练过程中每层特征的H-score，结果显示在下一张图.



从图中我们可以看到，随着训练的进行，H-score在不断增长；而且靠后面的层对应特征的H-score也比前面的层要高. 这意味着随着训练进行及网络层数的增加，神经网络选出的特征也越来越好. 最后，图例里显示的分类准确度与H-scroe也有很好的对应关系：与我们的预期一致，性能好的分类器对应高的H-score.

细心的读者可能会从H-score的结果中发现，这个网络的第三层没有太大用处，有进一步优化的空间. 整个实验的代码可以在这里下载.

为了在更实际的问题上测试H-score的用处，我们对不同算法在ImageNet数据集中提取的特征进行了评价，得到的H-score和对应的准确度如下表所示.



为什么不是对数损失？
当然，在神经网络里更常用的度量是对数损失函数，也被称为交叉熵，与K-L散度紧密相关. 我们来看一下H-score和这些度量的关系，以及为什么H-score可能是一个更好的选择.

对数损失函数，或者说交叉熵计算的是 $$ {\rm LL}(S, v)= -{\mathbb E}_{P_{XY}} \left[ \log Q_{Y|X}^{(S, v)}(Y|X) \right] $$，其中 $$ P $$ 为数据的经验分布. $$ Q^{(S, v)} $$ 是 SoftMax 单元的输出，可以看做是一个条件分布. 整个神经网络通过选择 $$ S $$ 和 $$ v $$ 使得损失最小. 作为整个优化问题的目标函数，我们当然可以使用对数损失函数的值作为结果的性能度量. 事实上，目前工程师在设计神经网络时最重要的工作之一，就是观察对数损失函数的减小过程，以此判断算法是否收敛.

对数损失的问题在于，很难找到一个预期值作为我们的参考. 我们不清楚损失值应该取几十，还是10的6次方，以及哪个值是更可接受的. 实际上，这个预期值将与具体的数据集及任务有关. 因此，对数损失的绝对数值不能用来衡量神经网络自身的好坏.

另一个选择是使用K-L散度，或者说相对熵. 神经网络会间接地计算K-L散度 $$ D(P_{XY} || P_X \cdot Q_{Y|X}^{(S, v)}) = {\mathbb E}_{P_{XY}} \left[ \log \frac{P_{Y|X}(Y|X)}{Q_{Y|X}^{(S, v)}(Y|X)}\right] $$

并试图最小化它. 从优化的角度看，这个问题等价于最小化对数损失函数：目标函数只是多了 $$ {\mathbb E} [\log P_{Y|X}] $$ 这一项，而它与 $$ (S, v) $$ 无关.

K-L散度的优点是它具有操作意义：实际数据经验分布 $$ P $$和神经网络生成的分布 $$ Q $$ 之间的“距离”. 这赋予了整个网络一个漂亮的解释：神经网络视图找到对联合经验分布 $$ P_{XY} $$ 的最佳逼近. 在操作层面，K-L散度至少是有界的：$$ 0 \leq D(P||Q) \leq \log |{\mathcal Y}|$$. 这是件好事. 例如，对于某个 $$ |{\mathcal Y}| =8 $$ 的数据集，如果你得到的K-L散度为0.02，那说明你的网络逼近得不错；而K-L散度是1.2时，你的网络多少有点瞎猜的成分.

K-L散度的一个致命问题在于难以计算，因为我们不能从实际数据中获知 $$ P_{Y|X} $$. 实际上，神经网络正是在想方设法逼近 $$ P_{Y|X} $$. 因此，计算 $$ P_{Y|X} $$ 的难度不亚于设计并训练神经网络的难度.

将K-L散度用我们所定义的向量表达，会发现另一个问题：

$$ D(P_{XY} || P_X \cdot Q_{Y|X}^{(S, v)}) \approx \frac{1}{2} \| \tilde{B} - \Psi \Phi^{\mathrm{T}} \|^2 = \frac{1}{2} \| \tilde{B} - \sum_{i=1}^k \psi_i \cdot \phi_i^{\mathrm{T}} \|^2 $$

这里我们是在尝试用秩为 $$ k $$ 的矩阵来逼近 $$ \tilde{B} $$，并直接计算了这两个矩阵之间的距离. 因此，即便我们用SVD给出的最优的秩 $$ k $$ 矩阵，剩下的奇异值 $$ \sigma_{k+1}, \sigma_{k+2}, \ldots $$ 仍然体现在结果中. 一般情况下，K-L散度可以看成是两部分组成：一部分是我们的解与最优的秩为 $$ k $$ 的解之间的距离，另一部分源于在 $$ k $$ 之后的这些奇异值的贡献，且这两部分贡献不能分离开. 这使得K-L散度的意义变得模糊，尤其是在 $$ |{\mathcal Y}| $$ 比较大的情形.

相比之下，可以看出H-score好在哪里：

$$ H(S, v) := \|\tilde{B}\|^2 - \| \tilde{B} - \Psi \Phi^{\mathrm{T}} \|^2 $$

可以看出，我们让K-L散度被 $$ \|\tilde{B}\|^2 $$ 减，这样就把K-L散度中的第二部分贡献除去了. 换句话说，我们除去了前 $$ k $$ 个之外的奇异值的贡献. 为了更清楚地看到这一点，设 $$ \Psi \Phi^T $$ 为 $$ \tilde{B} $$ 的秩 $$ k $$ 逼近，此时H-score就等于前 $$ k $$ 个奇异值的平方和，从而消除了后面奇异值的影响.

下列不等式可能会很有用：

$$

H(S, v) \leq H(S) \leq \sum_{i=1}^k \sigma_i^2 \leq k

$$

其中 $$ k $$ 为所选择的特征 $$ S(x) $$ 的维数.

根据定义，第一个不等号两边 $$ H(S, v) $$ 和 $$ H(S) $$ 的间隙表示的是权重 $$ v(y) $$ 离最优值 $$ v^*(y) $$ 有多远. 对于深度神经网络的中间层，我们可以想象直接将它的输出送到全连接的 SoftMax 输出层，并使用 $$ v^*(y) $$ 作为权重. 因此，这个间隙可以度量网络训练是否收敛到最优值.

第二个间隙度量了所选特征 $$ S(x) $$ 离最优的SVD解有多远. 对于已经收敛的网络，所选特征达不到最优解的唯一可能就是网络结构的表达能力受限. 因此，这个间隙可以作为网络结构好坏的度量.

第三个间隙度量了数据集的好坏. 或者说，对$$ X $$ 与 $$ Y $$相关性的 $$ k $$ 维逼近所包含的信息量. 而信息量的上界正好是 $$ k $$. 举例来说，在MNIST手写体识别问题较好的解决方案中， $$ H(S) $$ 可以达到8.1，而这里 $$ k = 9 $$ 对应于需要识别的10个数字的9个自由维度. 由此可以得知，MNIST的数据集很好，而且选出的特征也很接近最优值，因此可以预期分类的结果也很准确.

局限性
以上是H-score能做的事情，现在我们聊聊它不能做的事情. 本质上，在一些情况下H-score并不是精确的性能度量，较低的H-score可能对应更优的性能. 这可能是因为如下几个原因：

首先，我们提到了H-score是通用意义下度量所选择特征的好坏，即特征在所有可能的任务中的性能. 对于特定任务，这样的通用性能往往不如针对任务定制的方法好. 在任务未知的情形下，通用方案是唯一明智的选择. 然而在实践中，确实存在只对某个特定问题感兴趣，或者问题变化范围非常小的情况. 这种情况下，如果以试错的方式进行一系列实验，我们总可以使得求出的特征有比较好的性能. 但实际上，试错是在根据特定任务调整选出的特征，即便我们并没有显式地这样做. 尽管通用特征显得更高雅，我们不能否认，基于试错的方法在实践中也有它的价值.

第二个问题可以从我们ImageNet实验结果的表中看出. 某些情况下，具有较高H-score的算法反而有更低的准确度，例如VGG16和VGG19. 其中一个原因是，这两个网络具有比其他算法更复杂的结构及更多的参数. 而且，我们假设统计模型是精确的且可以真实地被数据反映. 此外，我们也没有考虑过拟合带来的泛化误差.

H-Score的第三个，也可能是最重要的问题，在于它的计算利用了局部近似. 关于这个近似，我们的论文里有详细的讨论. 简而言之，这个近似使得我们可以只关注特定的局部最优解. 如果我们一定要在没有这个近似的情况下分析，那我们的解将十分复杂，难以推广，在数值上也可能是不稳定的. 缺乏稳定性是深度神经网络一个致命的问题，也是这个领域里工程师的噩梦. 遗憾的是，我们的理论对解决这个问题并没有帮助：局部性的假设使得我们一开始就避免了它. 这是一个慎重的选择，可能也是我们得到的结果形式能够如此优美的主要原因. 在优化领域里，确实有勇士在尝试求非凸问题的全局最优解，但很难想象结果会像局部最优解一样简单及具有一般性，而这却是我们在神经网络中需要求解的.

可解释性
可解释性对神经网络而言是一个重要的问题. 这么些复杂的结构究竟学习了什么？神经网络选出的那些特征是什么？期待我们的结果可以在某种程度上阐明这些问题：我们给出了每个神经元及权重值的数学表达式，也明白了神经网络计算的目标，以及存储计算结果的方式. 这肯定是一件好事情.

我们方法一个明显的好处是，可以帮助我们有指导性地做迁移学习和多任务学习. 不同于构建巨大的深度神经网络作为黑箱模型，现在我们可以对分析算法的中间结果，并了解哪些结果可能对其他任务有帮助. 在这方面我们已经有了一些实践，相应结果会在另一个页面展示.

现在是否意味着我们可以解释选出的这些特征的意义了呢？不完全是这样. 可能比这更悲观的是，我们现在有了对可解释性不抱有希望的理由. 我们的理论表明，一般情况下神经网络所选出的特征是一系列优化问题的解：它们带有最多的信息，是最可区分的特征，在推断任务未知时是通用意义下最优的……等等. 但这些特性不意味着它们可以被解释，换句话说，可能它们不对应于人类思维中任何一个简单且凝练的概念.

现在来想想你的某位好朋友. 你的第一反应一定是这个人的给你的整体印象，而不是像年龄、性别、身份证号这些能在海关表格上找到的东西. 人们发明了一系列的标签用于区分世界上的东西，而为什么选择这些标签的问题已经远远超过了工程的范畴. 我们唯一可以明确的是，这些标签和我们从数据中选出的特征很可能是不吻合的. 通常来说，我们选出的这些帮助我们分类的特征，往往是这一系列标签的某个特定组合. 原则上，对于包含这些标签的数据集，我们总可以通过学习得知这些标签组合成为特征的具体方式，从而就将特征翻译成了人类可理解的标签. 这样的翻译过程，可以看作是从特征选择问题中分离出的一个学习问题.

小明终于找到了他的soulmate因为她的&xi;值非常高，其中 &xi; = 0.0122 &times; 发色 + 0.0031 &times; 喜欢运动 + 0.0041 &times; 烹饪技能 + 0.0201 &times; 特别的笑点 + 0.0311 &times; 喜欢Python超过Matlab + ...

嘿! 你猜对了，小明是个程序员.

下载链接
本页面中提到的实验源代码可以从以下链接下载：

Experiment 1: The SoftMax Output Units

Experiment 2: Discrete Valued Inputs

Experiment 3: Limited Expressive Power

Experiment 4: H-Scores

本页面在徐祥祥帮助下完成，他长这样.

其他语言: English