原文: sparseAutoencoder_2011new by Andrew Ng from http://web.stanford.edu/class/cs294a/sparseAutoencoder_2011new.pdf
稀疏自动编码器
吴恩达
绪论
监督学习是人工智能最强大的工具之一,它已经导致了自动邮政编码识别、语音识别、自动驾驶汽车以及对人类基因组的不断加深的理解。尽管监督学习取得了巨大的成功,但今天它仍然受到严重的限制。具体来说,它的大多数应用仍然需要我们手动指定给算法的输入特征x。一旦给出了一个好的特征表示,监督学习算法就可以做得很好。但是在计算机视觉、音频处理和自然语言处理等领域,现在有成百上千的研究人员花费数年时间缓慢而费力地手工设计视觉、音频或文本特征。 虽然这种特性工程工作非常聪明,但人们不得不怀疑我们是否能做得更好。当然,这种劳动密集型的手工工程方法不能很好地适应新的问题;此外,理想情况下,我们希望算法能够自动学习比手工设计的更好的特征表示。
这篇笔记描述了稀疏自动编码器学习算法,这是一种从未标记数据中自动学习特征的方法。在某些领域,例如计算机视觉,这种方法本身并不能与最好的手工设计的特征相竞争,但是它所能学习的特征确实证明对一系列问题(包括音频、文本等)是有用的。 此外,还有更复杂版本的稀疏自动编码器(在这些笔记中没有描述,但您将在后面的课程中听到更多内容),它们表现得出奇的好,并且在许多情况下甚至可以与最好的手工制作的表示相媲美或更胜一筹。
这些笔记组织如下。我们将首先描述用于监督学习的前馈神经网络和反向传播算法。 然后,我们展示如何使用它来构造自动编码器,这是一种无监督的学习算法。最后,我们在此基础上构建一个稀疏自动编码器。因为这些笔记非常多,最后一页还包含了所用符号的摘要。
2神经网络
考虑一个有监督的学习问题,在这个问题中,我们可以访问带标签的训练样本
(
x
(
i
)
,
y
(
i
)
)
({x^{(i)}},{y^{(i)}})
(x(i),y(i))。神经网络提供了一种定义复杂的、非线性形式
h
W
,
b
(
x
)
{h_{W,b}}(x)
hW,b(x)方法,我们可以用参数W、b来拟合我们的数据。
为了描述神经网络,我们将从描述最简单的可能的神经网络开始,一个由单个“神经元”组成的网络我们将使用下图来表示单个神经元:
这个“神经元”是一个计算单元,它将
x
1
{x_1}
x1、
x
2
{x_2}
x2、
x
3
{x_3}
x3(和一个+1截距项)作为输入,并输出
h
W
,
b
(
x
)
=
f
(
W
T
x
)
=
f
(
∑
i
=
1
3
W
i
x
i
+
b
)
{h_{W,b}}(x) = f({W^T}x) = f(\sum\nolimits_{i = 1}^3 {W{}_i{x_i} + b} )
hW,b(x)=f(WTx)=f(∑i=13Wixi+b),其中
f
:
R
↦
R
f:\R \mapsto\R
f:R↦R称为激活函数。在这些笔记中,我们将选择sigmoid函数作为
f
(
)
f()
f():
f ( z ) = 1 1 + exp ( − z ) f(z) = {1 \over {1 + \exp ( - z)}} f(z)=1+exp(−z)1
因此,我们的单个神经元恰好对应于逻辑回归定义的输入输出映射。
尽管这些笔记将使用sigmoid函数,但值得注意的是,
f
f
f的另一个常见选择是双曲正切函数:
f ( z ) = tanh ( z ) = e z − e − z e z + e − z (1) f(z) = \tanh (z) = {{{e^z} - {e^{ - z}}} \over {{e^z} + {e^{ - z}}}}\tag{1} f(z)=tanh(z)=ez+e−zez−e−z(1)
以下是sigmoid和tanh函数的曲线图:
tanh
(
z
)
\tanh (z)
tanh(z)函数是sigmoid的重缩放版本,其输出范围是[-1,1]而不是[0,1]。
请注意,与CS221和(部分)CS229不同,我们这里不使用
x
0
=
1
{x_0} = 1
x0=1的约定。相反,截距项由参数b单独处理。
最后,一个稍后有用的恒等式是:如果是sigmoid函数
f
(
z
)
=
1
/
(
1
+
exp
(
−
z
)
)
f(z) = 1/(1 + \exp ( - z))
f(z)=1/(1+exp(−z)),那么它的导数由
f
′
(
z
)
=
f
(
z
)
(
1
−
f
(
z
)
)
f'(z) = f(z)(1 - f(z))
f′(z)=f(z)(1−f(z))给出。(如果f是正切函数,那么它的导数由
f
′
(
z
)
=
1
−
(
f
(
z
)
)
2
f'(z) = 1 - {(f(z))^2}
f′(z)=1−(f(z))2给出。)您可以使用sigmoid(或tanh)函数的定义自己推导出来。
2.1神经网络公式
一个神经网络是通过将我们的许多简单“神经元”连接在一起而组成的,这样一个神经元的输出就可以成为另一个神经元的输入。例如,这里有一个小型神经网络:
在这个图中,我们用圆圈来表示网络的输入。标有“+1”的圆圈称为偏置单位,对应于截距项。网络最左边的层称为输入层,最右边的层称为输出层(在本例中,输出层只有一个节点)。节点的中间层称为隐藏层,因为它的值在训练集中没有观察到。我们还说,我们的示例神经网络有3个输入单元(不包括偏置单元)、3个隐藏单元和1个输出单元。
我们将让
n
l
{n_l}
nl表示网络中的层数;因此,在我们的例子中
n
l
=
3
{n_l=3}
nl=3。我们将
l
l
l层标记为
L
l
L_l
Ll,第一层标记为
L
1
{L_1}
L1,输出层记为
L
n
l
{L_{{n_l}}}
Lnl。我们的神经网络具有参数
(
W
,
b
)
=
(
W
(
1
)
,
b
(
1
)
,
W
(
2
)
,
b
(
2
)
)
(W,b) = ({W^{(1)}},{b^{(1)}},{W^{(2)}},{b^{(2)}})
(W,b)=(W(1),b(1),W(2),b(2)),其中我们用
W
i
j
(
l
)
W_{ij}^{(l)}
Wij(l)来表示与层
l
l
l中的单元
j
j
j和层
l
+
1
l+1
l+1中的单元
i
i
i之间的连接参数(或权重)。(注意索引的顺序。)此外,
b
i
(
l
)
b_i^{(l)}
bi(l)是与层
l
+
1
l+1
l+1中的单元
i
i
i相连接的偏置值。因此,在我们的例子中,我们有
W
(
1
)
∈
3
×
3
{W^{(1)}} \in {^{3 \times 3}}
W(1)∈3×3,和
W
(
2
)
∈
1
×
3
{W^{(2)}} \in {^{1 \times 3}}
W(2)∈1×3。请注意,偏置单元没有输入或连接,因为它们总是输出值+1。我们还让
s
l
s_l
sl表示层
l
l
l中的节点数(不包括偏置单元)。
我们将写
a
i
(
l
)
a_i^{(l)}
ai(l)来表示层
l
l
l中单元
i
i
i的激活(意味着输出值)。对于
l
=
1
l=1
l=1,我们也使用
a
i
(
1
)
=
x
i
a_i^{(1)}=x_i
ai(1)=xi以表示第
i
i
i个输入。 给定固定参数
W
W
W,
b
b
b,我们的神经网络定义输出实数的表示
h
W
,
b
(
x
)
{h_{W,b}}(x)
hW,b(x)。具体而言,该神经网络表示的计算由下式给出:
a
1
(
2
)
=
f
(
W
11
(
1
)
x
1
+
W
12
(
1
)
x
2
+
W
13
(
1
)
x
3
+
b
1
(
1
)
)
(2)
a_1^{(2)} = f(W_{11}^{(1)}{x_1} + W_{12}^{(1)}{x_2} + W_{13}^{(1)}{x_3} + b_1^{(1)})\tag{2}
a1(2)=f(W11(1)x1+W12(1)x2+W13(1)x3+b1(1))(2)
a 2 ( 2 ) = f ( W 21 ( 1 ) x 1 + W 22 ( 1 ) x 2 + W 23 ( 1 ) x 3 + b 2 ( 1 ) ) (3) a_2^{(2)} = f(W_{21}^{(1)}{x_1} + W_{22}^{(1)}{x_2} + W_{23}^{(1)}{x_3} + b_2^{(1)})\tag{3} a2(2)=f(W21(1)x1+W22(1)x2+W23(1)x3+b2(1))(3)
a 3 ( 2 ) = f ( W 31 ( 1 ) x 1 + W 32 ( 1 ) x 2 + W 33 ( 1 ) x 3 + b 3 ( 1 ) ) (4) a_3^{(2)} = f(W_{31}^{(1)}{x_1} + W_{32}^{(1)}{x_2} + W_{33}^{(1)}{x_3} + b_3^{(1)})\tag{4} a3(2)=f(W31(1)x1+W32(1)x2+W33(1)x3+b3(1))(4)
h W , b ( x ) = a 1 ( 3 ) = f ( W 11 ( 2 ) a 1 ( 2 ) + W 12 ( 2 ) a 2 ( 2 ) + W 13 ( 2 ) a 3 ( 2 ) + b 1 ( 2 ) ) (5) {h_{W,b}}(x) = a_1^{(3)} = f(W_{11}^{(2)}a_1^{(2)} + W_{12}^{(2)}a_2^{(2)} + W_{13}^{(2)}a_3^{(2)} + b_1^{(2)})\tag{5} hW,b(x)=a1(3)=f(W11(2)a1(2)+W12(2)a2(2)+W13(2)a3(2)+b1(2))(5)
接下来,我们还让
z
i
(
l
)
z_i^{(l)}
zi(l)表示层
l
l
l中神经原
i
i
i输入的总加权和,包括偏置项(例如,
z
i
(
2
)
=
∑
j
=
1
n
W
i
j
(
1
)
x
j
+
b
i
(
1
)
z_i^{(2)} = \sum\nolimits_{j = 1}^n {W_{ij}^{(1)}{x_j}} + b_i^{(1)}
zi(2)=∑j=1nWij(1)xj+bi(1)),因此
a
i
(
l
)
=
f
(
z
i
(
l
)
)
a_i^{(l)} = f(z_i^{(l)})
ai(l)=f(zi(l))。
请注意,这很容易使自己成为一个更紧凑的符号。具体来说,如果我们扩展激活函数f(.)以元素方式应用于向量(即,
f
(
[
z
1
,
z
2
,
z
3
)
)
=
[
f
(
z
1
)
,
f
(
z
2
)
,
f
(
z
3
)
]
f([z_1,z_2,z_3))=[f(z_1),f(z_2),f(z_3)]
f([z1,z2,z3))=[f(z1),f(z2),f(z3)]),然后式(2-5)我们可以写成:
z
(
2
)
=
W
(
1
)
x
+
b
(
1
)
{z^{(2)}} = {W^{(1)}}x + {b^{(1)}}
z(2)=W(1)x+b(1)
a ( 2 ) = f ( z ( 2 ) ) {a^{(2)}} = f({z^{(2)}}) a(2)=f(z(2))
z ( 3 ) = W ( 2 ) a ( 2 ) + b ( 2 ) {z^{(3)}} = {W^{(2)}}{a^{(2)}} + {b^{(2)}} z(3)=W(2)a(2)+b(2)
h W , b ( x ) = a ( 3 ) = f ( z ( 3 ) ) {h_{W,b}}(x) = {a^{(3)}} = f({z^{(3)}}) hW,b(x)=a(3)=f(z(3))
更一般地说,回想一下我们也使用
a
(
1
)
=
x
{a^{(1)}} = x
a(1)=x来表示来自输入层的值,那么给定层
l
l
l的激活
a
(
l
)
{a^{(l)}}
a(l),我们可以计算层
l
+
1
l+1
l+1的激活
a
(
l
+
1
)
{a^{(l+1)}}
a(l+1)为:
z
(
l
+
1
)
=
W
(
l
)
a
(
l
)
+
b
(
l
)
(6)
{z^{(l + 1)}} = {W^{(l)}}{a^{(l)}} + {b^{(l)}}\tag{6}
z(l+1)=W(l)a(l)+b(l)(6)
a
(
l
+
1
)
=
f
(
z
(
l
+
1
)
)
(7)
{a^{(l + 1)}} = f({z^{(l + 1)}})\tag{7}
a(l+1)=f(z(l+1))(7)
通过在矩阵中组织我们的参数和使用矩阵向量运算, 我们可以利用快速线性代数例程在我们的网络中快速执行计算。
到目前为止,我们只关注了一个神经网络的例子,但是我们也可以用其他的结构来构建神经网络(也就是神经元之间的连接模式),包括具有多个隐藏层的结构。 最常见的选择是
n
l
{n_l}
nl层网络,其中第1层是输入层,第
n
l
{n_l}
nl层是输出层,每一层
l
l
l都密集地连接到第
l
+
1
l+1
l+1层。在此设置中,为了计算网络的输出,我们需要使用等式(6-7)依次计算层
L
2
{L_2}
L2、层
L
3
{L_3}
L3等直至层
L
n
l
{L_{{n_l}}}
Lnl的所有激活。这是前馈神经网络的一个例子,因为连接图没有任何有向回路或循环。
神经网络也可以有多个输出单元。例如,这里有一个网络,它有两个隐藏层层
L
2
{L_2}
L2和层
L
3
{L_3}
L3,以及
L
4
{L_4}
L4层的两个输出单元:
为了训练这个网络,我们需要训练样本
(
x
(
i
)
,
y
(
i
)
)
({x^{(i)}},{y^{(i)}})
(x(i),y(i)),其中
y
(
i
)
∈
R
2
{y^{(i)}} \in {\R^2}
y(i)∈R2。如果您有兴趣预测多个输出,这种网络非常有用(例如,在医学诊断应用中,向量
x
x
x可以给出患者的输入特征,不同的输出
y
i
{y_i}
yi可以指示不同疾病的存在或不存在。)
2.2反向传播算法
假设我们有一个固定的训练集 { ( x ( 1 ) , y ( 1 ) ) , . . . , ( x ( m ) , y ( m ) ) } \{ ({x^{(1)}},{y^{(1)}}),...,({x^{(m)}},{y^{(m)}})\} {(x(1),y(1)),...,(x(m),y(m))} 共 m m m个训练样本。我们可以使用梯度下降法(batch gradient descent)来训练我们的神经网络。 具体来说,对于单个训练样本 ( x , y ) (x,y) (x,y),我们将该单个样本的代价函数定义为:
J
(
W
,
b
;
x
,
y
)
=
1
2
∥
h
W
,
b
(
x
)
−
y
∥
2
J(W,b;x,y) = {1 \over 2}{\left\| {{h_{W,b}}(x) - y} \right\|^2}
J(W,b;x,y)=21∥hW,b(x)−y∥2
这是一个(二分之一)平方误差代价函数。给定一个由m个样本组成的训练集,然后我们将总代价函数定义为:
J ( W , b ) = [ 1 m ∑ i = 1 m J ( W , b ; x ( i ) , y ( i ) ) ] + λ 2 ∑ l = 1 n l − 1 ∑ i = 1 s l ∑ j = 1 s l + 1 ( W j i ( l ) ) 2 (8) J(W,b) = [{1 \over m}\sum\limits_{i = 1}^m {J(W,b;{x^{(i)}},{y^{(i)}})]} + {\lambda \over 2}\sum\limits_{l = 1}^{{n_l} - 1} {\sum\limits_{i = 1}^{{s_l}} {\sum\limits_{j = 1}^{{s_{l+ 1}} } {(W_{ji}^{(l)}} {)^2}} }\tag{8} J(W,b)=[m1i=1∑mJ(W,b;x(i),y(i))]+2λl=1∑nl−1i=1∑slj=1∑sl+1(Wji(l))2(8)
=
[
1
m
∑
i
=
1
m
(
1
2
∥
h
W
,
b
(
x
(
i
)
)
−
y
(
i
)
∥
2
)
]
+
λ
2
∑
l
=
1
n
l
−
1
∑
i
=
1
s
l
∑
j
=
1
s
l
+
1
(
W
j
i
(
l
)
)
2
\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ = [{1 \over m}\sum\limits_{i = 1}^m {({1 \over 2}{{\left\| {h{}_{W,b}({x^{(i)}}) - {y^{(i)}}} \right\|}^2})]} + {\lambda \over 2}\sum\limits_{l = 1}^{{n_l} - 1} {\sum\limits_{i = 1}^{{s_l}} {\sum\limits_{j = 1}^{{s_{l+ 1}}} {(W_{ji}^{(l)}} {)^2}} }
=[m1i=1∑m(21∥∥∥hW,b(x(i))−y(i)∥∥∥2)]+2λl=1∑nl−1i=1∑slj=1∑sl+1(Wji(l))2
J
(
W
,
b
)
J(W,b)
J(W,b)定义中的第一项是平均平方和误差项。第二项是一个正则项(也称为权重去伪项),用于减小权重的大小,并有助于防止过拟合(通常权重衰减不适用于偏置项
b
i
(
l
)
b_i^{(l)}
bi(l),如我们对
J
(
W
,
b
)
J(W,b)
J(W,b)的定义所示。然而,将权重衰减应用于偏置单元通常只对最终网络产生很小的不同。如果你选择了CS229,你可能还会认识到权重衰减这是你在那里看到的贝叶斯正则化方法的一个变种,我们在参数上放置了一个高斯先验,并做了最大似然估计(而不是最大似然估计) )。权重衰减参数
λ
\lambda
λ控制这两个项的相对重要性。还要注意稍微重载的符号:
J
(
W
,
b
;
x
,
y
)
J(W,b;x,y)
J(W,b;x,y)是关于单样本的平方误差代价;J(W,b)是总代价函数,其中包括权重衰减项。
上述代价函数通常用于分类和回归问题。对于分类,我们让
y
=
0
y=0
y=0或1代表两个类别标签(回想一下,sigmoid激活函数输出[0,1]中的值;如果我们使用tanh激活函数,我们将使用-1和+1来表示标签)。对于回归问题,我们首先调整我们的输出,以确保它们位于[0,1]范围内(或者如果我们使用的是tanh激活函数,那么是[-1,1]范围)。
我们的目标是将关于W和b的函数J(W,b)最小化。为了训练我们的神经网络,我们将初始化每个参数
W
i
j
(
l
)
{W_{ij}^{(l)}}
Wij(l)和每个
b
i
(
l
)
b_i^{(l)}
bi(l)到接近于零的小随机值(例如根据一些小
ε
\varepsilon
ε的
ℵ
(
0
,
ε
2
)
\aleph (0,{\varepsilon ^2})
ℵ(0,ε2)分布,例如0.01),然后应用优化算法,例如批梯度下降法。由于
J
(
W
,
b
)
J(W,b)
J(W,b)是一个非凸函数,梯度下降法易受局部最优的影响;然而,在实践中,梯度下降法通常相当有效。最后,注意随机初始化参数是很重要的,而不是所有的0。如果所有的参数从相同的值开始,那么所有的隐藏层单元将最终学习相同的输入函数(更正式地说,对于所有的
i
i
i其
W
i
j
(
1
)
{W_{ij}^{(1)}}
Wij(1)值都是相同的,因此对于任何输入
x
x
x都有
a
1
(
2
)
=
a
2
(
2
)
=
a
3
(
2
)
=
.
.
.
a_1^{(2)} = a_2^{(2)} = a_3^{(2)} = ...
a1(2)=a2(2)=a3(2)=...)。随机初始化的目的是打破对称。
梯度下降法的一次迭代,参数W、b更新如下:
W i j ( l ) : = W i j ( l ) − α ∂ ∂ W i j ( l ) J ( W , b ) \ \ \ W_{ij}^{(l)}: = W_{ij}^{(l)} - \alpha {\partial \over {\partial W_{ij}^{(l)}}}J(W,b) Wij(l):=Wij(l)−α∂Wij(l)∂J(W,b)
b i ( l ) : = b i ( l ) − α ∂ ∂ b i ( l ) J ( W , b ) b_i^{(l)}: = b_i^{(l)} - \alpha {\partial \over {\partial b_i^{(l)}}}J(W,b) bi(l):=bi(l)−α∂bi(l)∂J(W,b)
其中
α
\alpha
α是学习率。关键步骤是计算上面的偏导数。现在我们将描述反向传播算法,它给出了一种计算这些偏导数的有效方法。
我们将首先描述如何使用反向传播来计算
∂
∂
W
i
j
(
l
)
J
(
W
,
b
;
x
,
y
)
{\partial \over {\partial W_{ij}^{(l)}}}J(W,b;x,y)
∂Wij(l)∂J(W,b;x,y)和
∂
∂
b
i
(
l
)
J
(
W
,
b
;
x
,
y
)
{\partial \over {\partial b_i^{(l)}}}J(W,b;x,y)
∂bi(l)∂J(W,b;x,y),代价函数的偏导数函数
J
(
W
,
b
;
x
,
y
)
J(W,b;x,y)
J(W,b;x,y)是相对于单个样本
(
x
,
y
)
(x,y)
(x,y)定义的。一旦我们能够计算出这些偏导数,那么通过参考等式(8),我们看到总代价函数
J
(
W
,
b
)
J(W,b)
J(W,b)的导数可以计算为:
∂ ∂ W i j ( l ) J ( W , b ) = [ 1 m ∑ i = 1 m ∂ ∂ W i j ( l ) J ( W , b ; x ( i ) , y ( i ) ) ] + λ W i j ( l ) , {\partial \over {\partial W_{ij}^{(l)}}}J(W,b) = [{1 \over m}\sum\limits_{i = 1}^m {{\partial \over {\partial W_{ij}^{(l)}}}} J(W,b;{x^{(i)}},{y^{(i)}})] + \lambda W_{ij}^{(l)}, ∂Wij(l)∂J(W,b)=[m1i=1∑m∂Wij(l)∂J(W,b;x(i),y(i))]+λWij(l),
∂
∂
b
i
(
l
)
J
(
W
,
b
)
=
1
m
∑
i
=
1
m
∂
∂
b
i
(
l
)
J
(
W
,
b
;
x
(
i
)
,
y
(
i
)
)
{\partial \over {\partial b_i^{(l)}}}J(W,b) = {1 \over m}\sum\limits_{i = 1}^m {{\partial \over {\partial b_i^{(l)}}}} J(W,b;{x^{(i)}},{y^{(i)}})
∂bi(l)∂J(W,b)=m1i=1∑m∂bi(l)∂J(W,b;x(i),y(i))
上面的两条公式略有不同,因为权重衰减适用于
W
W
W,而不适用于
b
b
b.
反向传播算法背后的直观理解如下。给定一个训练样本
(
x
,
y
)
(x,y)
(x,y),我们将首先运行一个“向前传递”来计算整个网络中的所有激活值,包括假设
h
W
,
b
(
x
)
h_{W,b}(x)
hW,b(x)的输出值。然后,对于第
l
l
l层中的每个节点
i
i
i,我们想要计算一个“误差项”
δ
i
(
l
)
\delta _i^{(l)}
δi(l),来衡量该节点对我们输出中的所有误差的“负责”程度。对于输出节点,我们可以直接测量网络激活和真实目标值之间的差异,并使用它来定义
δ
i
(
n
l
)
\delta _i^{({n_l})}
δi(nl)(其中
n
l
n_l
nl层是输出层)。隐藏层怎么计算?对于这些,我们将使用
a
i
(
l
)
a_i^{(l)}
ai(l)作为输入的节点的误差项的加权平均来计算
δ
i
(
l
)
\delta _i^{({l})}
δi(l)。详细来说,这是反向传播算法:
-
.执行前馈传递,计算 L 2 L_2 L2层、 L 3 L_3 L3层等直到输出层 L n l L_{n_l} Lnl的激活。
-
对于层 n l {n_l} nl(输出层)中的每个输出单元 i i i,设置为:
δ i ( n l ) = ∂ ∂ z i ( n l ) 1 2 ∥ y − h W , b ( x ) ∥ 2 = − ( y i − a i ( n l ) ) ∙ f ′ ( z i ( n l ) ) \delta _i^{({n_l})} = {\partial \over {\partial z_i^{({n_l})}}}{1 \over 2}{\left\| {y - {h_{W,b}}(x)} \right\|^2} = - ({y_i} - a_i^{({n_l})}) \bullet f'(z_i^{({n_l})}) δi(nl)=∂zi(nl)∂21∥y−hW,b(x)∥2=−(yi−ai(nl))∙f′(zi(nl)) -
对于 l = n l − 1 , n l − 2 , n l − 3 , . . . , 2 l=n_l-1,n_l-2,n_l-3,...,2 l=nl−1,nl−2,nl−3,...,2
对于层 l l l中的每个节点 i i i,设置
δ i ( l ) = ( ∑ j = 1 s l + 1 W j i ( l ) δ j ( l + 1 ) ) f ′ ( z i ( l ) ) \ \ \ \ \ \delta _i^{(l)} = (\sum\limits_{j = 1}^{{s_{l+ 1}} } {W_{ji}^{(l)}} \delta _j^{(l + 1)})f'(z_i^{(l)}) δi(l)=(j=1∑sl+1Wji(l)δj(l+1))f′(zi(l))
4.计算所需的偏导数,如下所示:
∂ ∂ W i j ( l ) J ( W , b ; x , y ) = a j ( l ) δ i ( l + 1 ) {\partial \over {\partial W_{ij}^{(l)}}}J(W,b;x,y) = a_j^{(l)}\delta _i^{(l + 1)} ∂Wij(l)∂J(W,b;x,y)=aj(l)δi(l+1)
∂ ∂ b i ( l ) J ( W , b ; x , y ) = δ i ( l + 1 ) {\partial \over {\partial b_i^{(l)}}}J(W,b;x,y) = \delta _i^{(l + 1)} ∂bi(l)∂J(W,b;x,y)=δi(l+1)
最后,我们也可以用矩阵矢量来重写算法。我们将使用" ∙ \bullet ∙“来表示元素式乘积运算符(在Matlab或Octave中表示为” . ∗ .* .∗",也称为哈达玛乘积),所以如果 a = b ∙ c a=b{\bullet}c a=b∙c,那么 a i = b i c i a_i=b_ic_i ai=bici。类似于我们如何扩展 f ( ∙ ) f({\bullet}) f(∙)为了将元素方式应用于向量,我们也对 f ′ ( ∙ ) f'( \bullet ) f′(∙)进行同样的操作。(因此 f ′ ( [ z 1 , z 2 , z 3 ] ) = [ ∂ ∂ z 1 f ( z 1 ) , ∂ ∂ z 2 f ( z 2 ) , ∂ ∂ z 3 f ( z 3 ) ] f'([{z_1},{z_2},{z_3}]) = [{\partial \over {\partial {z_1}}}f({z_1}),{\partial \over {\partial {z_2}}}f({z_2}),{\partial \over {\partial {z_3}}}f({z_3})] f′([z1,z2,z3])=[∂z1∂f(z1),∂z2∂f(z2),∂z3∂f(z3)])。然后可以编写算法:
-
执行前馈传递,使用公式(6-7)来计算 L 2 L_2 L2层、 L 3 L_3 L3层等直到输出层 L n l L_{n_l} Lnl的激活。
-
对于输出层(层 n l {n_l} nl),设置为:
δ ( n l ) = − ( y − a ( n l ) ) ∙ f ′ ( z ( n l ) ) \delta ^{({n_l})} = - ({y} - a^{({n_l})}) \bullet f'(z^{({n_l})}) δ(nl)=−(y−a(nl))∙f′(z(nl)) -
对于 l = n l − 1 , n l − 2 , n l − 3 , . . . , 2 l=n_l-1,n_l-2,n_l-3,...,2 l=nl−1,nl−2,nl−3,...,2
设置
δ ( l ) = ( ( W ( l ) ) T δ ( l + 1 ) ) f ′ ( z ( l ) ) \ \ \ \ \ \delta ^{(l)} = (({W^{(l)}} )^T\delta ^{(l + 1)})f'(z^{(l)}) δ(l)=((W(l))Tδ(l+1))f′(z(l))
4.计算所需的偏导数:
∇ W ( l ) J ( W , b ; x , y ) = δ ( l + 1 ) ( a ( l ) ) T {\nabla _{{W^{(l)}}}}J(W,b;x,y) = {\delta ^{(l + 1)}}({a^{(l)}})^T ∇W(l)J(W,b;x,y)=δ(l+1)(a(l))T
∇ b ( l ) J ( W , b ; x , y ) = δ ( l + 1 ) {\nabla _{{b^{(l)}}}}J(W,b;x,y) = {\delta ^{(l + 1)}} ∇b(l)J(W,b;x,y)=δ(l+1)
注意:在上面的步骤2和3中,我们需要为每个
i
i
i值计算
f
′
(
z
i
(
l
)
)
f'(z_i^{(l)})
f′(zi(l))。假设
f
(
z
)
f(z)
f(z)是sigmoid激活函数,通过网络的前向传递我们已经将
a
i
(
l
)
a_i^{(l)}
ai(l)存储起来了。因此,使用先前计算的表达式
f
′
(
z
)
f'(z)
f′(z),我们可以将其计算为
f
′
(
z
i
(
l
)
)
=
a
i
(
l
)
(
1
−
a
i
(
l
)
)
f'(z_i^{(l)})=a_i^{(l)}(1-a_i^{(l)})
f′(zi(l))=ai(l)(1−ai(l))(sigmoid:
f
′
(
z
)
=
f
(
z
)
(
1
−
f
(
z
)
)
f'(z) = f(z)(1 - f(z))
f′(z)=f(z)(1−f(z)) )。
最后,我们描述梯度下降法。在下面的伪代码中,
Δ
W
(
l
)
\Delta {W^{(l)}}
ΔW(l)是一个矩阵(与
W
(
l
)
W^{(l)}
W(l)维数相同),而
Δ
b
(
l
)
\Delta {b^{(l)}}
Δb(l)是一个向量(与
b
(
l
)
b^{(l)}
b(l)维数相同)。请注意,在这个符号中,“
Δ
W
(
l
)
\Delta {W^{(l)}}
ΔW(l)”是一个矩阵,特别是它不是“
Δ
\Delta
Δ乘以
W
(
l
)
{W^{(l)}}
W(l)”我们按如下方式实现批量梯度下降的一次迭代:
- 对所有 l l l设置 Δ W ( l ) : = 0 \Delta {W^{(l)}}:=0 ΔW(l):=0, Δ b ( l ) : = 0 \Delta {b^{(l)}}:=0 Δb(l):=0(矩阵零/矢量零)
- 从
i
=
1
i=1
i=1到
m
m
m
2a.使用反向传播算法计算 ∇ W ( l ) J ( W , b ; x , y ) {\nabla _{{W^{(l)}}}}J(W,b;x,y) ∇W(l)J(W,b;x,y)和 ∇ b ( l ) J ( W , b ; x , y ) {\nabla _{{b^{(l)}}}}J(W,b;x,y) ∇b(l)J(W,b;x,y)
2b.设置 Δ W ( l ) : = Δ W ( l ) + ∇ W ( l ) J ( W , b ; x , y ) \Delta {W^{(l)}}:=\Delta {W^{(l)}}+\nabla _{{W^{(l)}}}J(W,b;x,y) ΔW(l):=ΔW(l)+∇W(l)J(W,b;x,y)
2c.设置 Δ b ( l ) : = Δ b ( l ) + ∇ b ( l ) J ( W , b ; x , y ) \Delta {b^{(l)}}:=\Delta {b^{(l)}}+\nabla _{{b^{(l)}}}J(W,b;x,y) Δb(l):=Δb(l)+∇b(l)J(W,b;x,y) - 更新参数:
W ( l ) : = W ( l ) − α [ ( 1 m Δ W ( l ) ) + λ W ( l ) ] {W^{(l)}}: = {W^{(l)}} - \alpha [({1 \over m}\Delta {W^{(l)}}) + \lambda {W^{(l)}}] W(l):=W(l)−α[(m1ΔW(l))+λW(l)]
b
(
l
)
:
=
b
(
l
)
−
α
[
1
m
Δ
b
(
l
)
]
{b^{(l)}}: = {b^{(l)}} - \alpha [{1 \over m}\Delta {b^{(l)}}]
b(l):=b(l)−α[m1Δb(l)]
为了训练我们的神经网络,我们现在可以重复使用梯度下降法来降低我们的代价函数
J
(
W
,
b
)
J(W,b)
J(W,b)。
2.3梯度检查和高级优化
众所周知,反向传播是一个难以调试和获得正确结果的算法,尤其是因为许多微妙的错误实现——例如,在索引中有一个接一个错误,因此只训练一些层的权重,或者一个省略了偏置项的实现——将设法学习一些看起来令人惊讶的合理的东西(尽管执行得不如正确的实现好)。因此,即使有一个错误的实现,也可能根本看不出有什么问题。在这一节中,我们将描述一种用数字检查由您的代码计算的导数的方法,以确保您的实现是正确的。 执行这里描述的派生检查过程将会大大增加您对代码正确性的信心。
假设我们想把
θ
\theta
θ的函数
J
(
θ
)
J(\theta )
J(θ)最小化。对于这个例子,假设
J
:
R
↦
R
J:\R \mapsto\R
J:R↦R,所以
θ
∈
R
\theta \in\R
θ∈R。在这个一维的例子中,梯度下降法的一次迭代由下式给出:
θ
:
=
θ
−
α
d
d
θ
J
(
θ
)
\theta : = \theta - \alpha {d \over {d\theta }}J(\theta )
θ:=θ−αdθdJ(θ)
还假设我们已经实现了一些计算
d
d
θ
J
(
θ
)
{d \over {d\theta }}J(\theta )
dθdJ(θ)的函数
g
(
θ
)
g(\theta)
g(θ),因此我们实现梯度下降法的更新为
θ
:
=
θ
−
α
g
(
θ
)
\theta : = \theta - \alpha g(\theta)
θ:=θ−αg(θ)。我们如何检查
g
g
g的实现是否正确?
回忆一下导数的数学定义
d
d
θ
J
(
θ
)
=
lim
ε
→
0
J
(
θ
+
ε
)
−
J
(
θ
−
ε
)
2
ε
{d \over {d\theta }}J(\theta ) = \mathop {\lim }\limits_{\varepsilon \to 0} {{J(\theta + \varepsilon ) - J(\theta - \varepsilon )} \over {2\varepsilon }}
dθdJ(θ)=ε→0lim2εJ(θ+ε)−J(θ−ε)
因此,在任何给定的
θ
\theta
θ,我们都可以用数字来近似导数,如下所示:
J
(
θ
+
E
P
S
I
L
O
N
)
−
J
(
θ
−
E
P
S
I
L
O
N
)
2
×
E
P
S
I
L
O
N
{{J(\theta +EPSILON ) - J(\theta -EPSILON )} \over {2{\times}EPSILON }}
2×EPSILONJ(θ+EPSILON)−J(θ−EPSILON)
实际上,我们将EPSILON设置为一个小常数,比如说
1
0
−
4
10^{-4}
10−4左右。(EPSILON在有很大的范围内取值,都可以很好地工作,但我们不会将EPSILON设置为“非常”小,比如
1
0
−
20
10^{-20}
10−20,因为这会导致数值舍入误差。)
因此,给定一个计算
d
d
θ
J
(
θ
)
{d \over {d\theta }}J(\theta )
dθdJ(θ)的函数
g
(
θ
)
g(\theta)
g(θ),我们现在可以通过计算数值来验证它的正确性:
g ( θ ) ≈ J ( θ + E P S I L O N ) − J ( θ − E P S I L O N ) 2 × E P S I L O N g( \theta) \approx {{J(\theta +EPSILON ) - J(\theta -EPSILON )} \over {2{\times}EPSILON }} g(θ)≈2×EPSILONJ(θ+EPSILON)−J(θ−EPSILON)
这两个值彼此近似的程度将取决于
J
J
J的细节。但是假设
E
P
S
I
L
O
N
=
1
0
−
4
EPSILON=10^{-4}
EPSILON=10−4,你通常会发现上面的左边和右边将会至少4个有效数字(通常更多)相同。
现在,考虑这样的情况,其中
θ
∈
R
n
\theta\in\R^n
θ∈Rn是一个向量,而不是一个简单的实数(所以我们需要学习的参数有n个),并且
J
:
R
↦
R
J:\R \mapsto\R
J:R↦R。在我们的神经网络的例子中,我们使用“
J
(
W
,
b
)
J(W,b)
J(W,b)”,但人们可以想象“展开”参数
W
,
b
W,b
W,b成一个长向量
θ
\theta
θ。现在我们将导数检验过程推广到
θ
\theta
θ可能是向量的情况。
假设我们有一个计算
d
d
θ
i
J
(
θ
)
{d \over {d\theta_i }}J(\theta )
dθidJ(θ)的函数
g
i
(
θ
)
g_i(\theta)
gi(θ);我们想检查
g
i
g_i
gi是否输出正确的导数值。设
θ
(
i
+
)
=
θ
+
E
P
S
I
L
O
N
×
e
i
→
\theta^{(i+)}= \theta+EPSILON\times\mathop {{e_i}}\limits^ \to
θ(i+)=θ+EPSILON×ei→,其中
e
i
→
=
[
0
0
⋮
1
⋮
0
]
\mathop {{e_i}}\limits^ \to = \left[\begin{matrix} 0 \\ 0 \\ \vdots \\ 1\\\vdots \\0\end{matrix} \right]
ei→=⎣⎢⎢⎢⎢⎢⎢⎢⎢⎡00⋮1⋮0⎦⎥⎥⎥⎥⎥⎥⎥⎥⎤
是第
i
i
i个基向量(与
θ
\theta
θ维数相同的向量,在第
i
i
i个位置是1,其他地方都是0)。因此,
θ
(
i
+
)
\theta^{(i+)}
θ(i+)与
θ
\theta
θ相类是,只是它的第
i
i
i个元素增加了EPSILON。类似地,让
θ
(
i
−
)
=
θ
−
E
P
S
I
L
O
N
×
e
i
→
\theta^{(i-)}=\theta-EPSILON\times\mathop{{e_i}}\limits^ \to
θ(i−)=θ−EPSILON×ei→是第
i
i
i个元素减去EPSILON的对应向量。我们现在可以用数值方法来验证
g
i
(
θ
)
g_i(\theta)
gi(θ)的正确性,方法是检查每个
i
i
i:
g
i
(
θ
)
≈
J
(
θ
(
i
+
)
)
−
J
(
θ
(
i
−
)
)
2
×
E
P
S
I
L
O
N
g_i( \theta) \approx {{J(\theta^{(i+)} ) - J(\theta^{(i-)} )} \over {2{\times}EPSILON }}
gi(θ)≈2×EPSILONJ(θ(i+))−J(θ(i−))
当用反向传播来训练神经网络时,在正确的实现中,我们将得到:
∇
W
(
l
)
J
(
W
,
b
)
=
(
1
m
Δ
W
(
l
)
)
+
λ
W
(
l
)
\nabla _{W^{(l)}}J(W,b) = ({1 \over m}\Delta {W^{(l)}}) + \lambda {W^{(l)}}
∇W(l)J(W,b)=(m1ΔW(l))+λW(l)
∇
b
(
l
)
J
(
W
,
b
)
=
1
m
Δ
b
(
l
)
\nabla_ {b^{(l)}}J(W,b) = {1 \over m}\Delta {b^{(l)}}
∇b(l)J(W,b)=m1Δb(l)
这个结果表明,第2.2节中的最后一个伪代码块实际上是在实现梯度下降算法。为了确保梯度下降法的实现是正确的,使用上述方法计算
J
(
W
,
b
)
J(W,b)
J(W,b)的导数值通常是很有用的,从而验证
(
1
m
Δ
W
(
l
)
)
+
λ
W
(
l
)
({1 \over m}\Delta {W^{(l)}}) + \lambda {W^{(l)}}
(m1ΔW(l))+λW(l)和
1
m
Δ
b
(
l
)
{1 \over m}\Delta {b^{(l)}}
m1Δb(l)确实给出了你想要的导数。
最后,到目前为止,我们的集中讨论使用梯度下降法求
J
(
θ
)
J(\theta)
J(θ)的最小值。如果您已经实现了一个计算
J
(
θ
)
J(\theta)
J(θ)和
Δ
θ
J
(
θ
)
\Delta_{\theta}J(\theta)
ΔθJ(θ)的的函数。事实证明,有比梯度下降法更复杂的算法来求
J
(
θ
)
J(\theta)
J(θ)的最小值。例如,可以设想一种使用梯度下降算法,但是自动调整学习速率
α
\alpha
α,以便尝试使用步长,使
θ
\theta
θ尽可能快地接近局部最优。还有比这更复杂的算法;例如,有一些算法试图找到一个Hessian矩阵的近似值,这样它就可以更快地找到局部最优解(类似于牛顿法)。对这些算法的全面讨论超出了这些笔记的范围,但L-BFGS算法就是一个例子。(另一个例子是共轭梯度。)您将在编程练习中使用这些算法之一。这些高级优化算法需要您工作的主要内容是,对于任何
θ
\theta
θ,计算
J
(
θ
)
J(\theta)
J(θ)和
Δ
θ
J
(
θ
)
\Delta_{\theta}J(\theta)
ΔθJ(θ)。然后,这些优化算法将对学习速率/步长
α
\alpha
α进行内部调整(并计算其对Hessian的近似值,等等)。)来自动搜索最小化
J
(
θ
)
J(\theta)
J(θ)的值
θ
\theta
θ。诸如L-BFGS和共轭梯度等算法通常比梯度下降法快得多。
3自动编码器和稀疏性
到目前为止,我们已经描述了神经网络在监督学习中的应用,其中我们有标记的训练样本。现在假设我们只有未标记的训练样本集
{
x
(
1
)
,
x
(
2
)
,
x
(
3
)
,
.
.
.
}
\{ x^{(1)},x^{(2)},x^{(3)},...\}
{x(1),x(2),x(3),...},其中
x
(
i
)
∈
R
n
x^{(i)}\in\R^n
x(i)∈Rn。自动编码器神经网络是一种无监督的学习算法,它应用反向传播算法,将目标值设置为等于输入,即
y
(
i
)
=
x
(
i
)
y^{(i)}=x^{(i)}
y(i)=x(i)。
这是一个自动编码器:
自动编码器试图学习函数
h
W
,
b
(
x
)
≈
x
h_{W,b}(x) \approx x
hW,b(x)≈x。换句话说,它试图学习恒等式函数的近似值,以便输出类似于
x
x
x的结果
x
^
\hat x
x^。恒等函数似乎是一个特别容易学习的函数;但是通过对网络进行限制,比如限制隐藏单元的数量,我们可以发现数据的有趣结构。作为具体示例,假设输入
x
x
x是来自10×10图像(100个像素)的像素强度值,因此
n
=
100
n=100
n=100,并且在层
L
2
L_2
L2中有
s
2
=
50
s_2=50
s2=50个隐藏单元。请注意,我们也有
y
∈
R
100
y\in\R^{100}
y∈R100。由于只有50个隐藏单元,网络被迫学习输入的压缩表示,即仅给定隐藏单元激活向量
a
(
2
)
∈
R
50
a^{(2)}\in\R^{50}
a(2)∈R50,它必须尝试对输入
x
x
x的100像素进行重建。如果输入完全随机,也就是说每个
x
i
x_i
xi来自独立于其他特征的
I
I
D
IID
IID高斯,则这个压缩任务中会非常困难。但是,如果数据中有结构,例如,如果一些输入特征是相关的,那么这个算法将能够发现一些相关性(事实上,这种简单的自动编码器经常以学习一种与主成分分析PCA非常相似的低维表示而告终)。
我们上面的论点依赖于隐藏单元
s
2
s_2
s2的数量很小。 但是即使隐藏单元的数量很大(甚至可能大于输入像素的数量),我们仍然可以通过对网络施加其他约束来发现有趣的结构。特别是,如果我们对隐藏单元施加稀疏性约束,那么即使隐藏单元的数量很大,自动编码器仍然会发现数据中有趣的结构。
非正式地说,如果一个神经元输出值接近1,我们会认为该神经元是“活跃的”(或“正在放电的”),或者如果输出值接近0,则为“非活动”。我们想限制神经元在大部分时间处于非活动状态。(本讨论假定使用sigmoid激活函数。如果你正在使用一个tanh激活函数,那么当一个神经元输出的值接近-1)
a
j
(
2
)
a_j^{(2)}
aj(2)表示自动编码器中隐藏单元
j
j
j的激活。但是,这个符号并没有明确说明是什么输入
x
x
x导致了激活。因此,我们将写
a
j
(
2
)
(
x
)
a_j^{(2)}(x)
aj(2)(x)来表示当给网络一个特定的输入
x
x
x时这个隐藏单元的激活值。进一步,让
ρ ^ j = 1 m ∑ i = 1 m [ a j ( 2 ) ( x ( i ) ) ] \hat \rho _j = {1 \over m}\sum\limits_{i = 1}^m {[a_j^{(2)}(x^{(i)})]} ρ^j=m1i=1∑m[aj(2)(x(i))]
是隐藏神经元 j j j的平均激活(在训练集中平均)我们想要(近似地)强制约束
ρ
^
j
=
ρ
,
\hat \rho _j =\rho,
ρ^j=ρ,
其中
ρ
\rho
ρ是稀疏性参数,通常是接近于零的小值(假设
ρ
=
0.05
\rho =0.05
ρ=0.05,自己取值)。换句话说,我们希望每个隐藏神经元
j
j
j的平均激活接近0.05。为了满足这个约束,隐藏神经元的激活值必须接近0。
为此,我们将在优化目标中增加一个额外的惩罚项,惩罚明显偏离
ρ
\rho
ρ的
ρ
^
j
\hat \rho _j
ρ^j。惩罚项的许多选择将给出合理的结果。我们将选择以下选项:
∑
j
=
1
s
2
[
ρ
log
ρ
ρ
^
j
+
(
1
−
ρ
)
log
1
−
ρ
1
−
ρ
^
j
]
\sum\limits_{j = 1}^{s_2} {[\rho \log {\rho \over {{{\hat \rho }_j}}}} + (1 - \rho )\log {{1 - \rho } \over {1 - {{\hat \rho }_j}}}]
j=1∑s2[ρlogρ^jρ+(1−ρ)log1−ρ^j1−ρ]
这里,
s
2
s_2
s2是隐藏层中神经元的数量,索引
j
j
j是我们网络中隐藏单元的总和。如果你熟悉KL散度的概念,这个罚项就是以它为基础的,也可以写成
∑ j = 1 s 2 K L ( ρ ∥ ρ ^ j ) \sum\limits_{j = 1}^{s_2} {KL(\left. \rho \right\|} \hat \rho_j) j=1∑s2KL(ρ∥ρ^j)
其中
K
L
(
ρ
∥
ρ
^
j
)
=
ρ
log
ρ
ρ
^
j
+
(
1
−
ρ
)
log
1
−
ρ
1
−
ρ
^
j
{KL(\left. \rho \right\|} \hat \rho_j)= {\rho \log {\rho \over {{{\hat \rho }_j}}}} + (1 - \rho )\log {{1 - \rho } \over {1 - {{\hat \rho }_j}}}
KL(ρ∥ρ^j)=ρlogρ^jρ+(1−ρ)log1−ρ^j1−ρ是具有平均值
ρ
\rho
ρ的伯努利随机变量和具有平均值
ρ
^
j
{\hat \rho }_j
ρ^j的伯努利随机变量之间的库尔巴克-莱布勒(KL)散度。KL散度是一个标准函数,用于测量两种不同分布的差异。(如果你以前没有见过KL散度,不用担心;你需要知道的一切都包含在这些笔记中。)
该惩罚函数具有当
ρ
^
j
=
ρ
{\hat \rho }_j=\rho
ρ^j=ρ时,
∑
j
=
1
s
2
K
L
(
ρ
∥
ρ
^
j
)
=
0
\sum\limits_{j = 1}^{s_2} {KL(\left. \rho \right\|} \hat \rho_j)=0
j=1∑s2KL(ρ∥ρ^j)=0性质,否则当
ρ
^
j
{\hat \rho }_j
ρ^j偏离
ρ
\rho
ρ时,该惩罚函数单调增加。例如,在下图中,我们设置
ρ
=
0.2
\rho = 0.2
ρ=0.2,并绘制了
ρ
^
j
\hat \rho_j
ρ^j-
K
L
(
ρ
∥
ρ
^
j
)
{KL(\left. \rho \right\|} \hat \rho_j)
KL(ρ∥ρ^j)图:
我们看到,在
ρ
^
j
=
ρ
{\hat \rho }_j=\rho
ρ^j=ρ时,KL散度达到最小值0,当
ρ
^
j
{\hat \rho }_j
ρ^j接近0或1时,KL散度增大(实际上接近
∞
\infty
∞)。因此,最小化该惩罚项具有使
ρ
^
j
{\hat \rho }_j
ρ^j接近
ρ
\rho
ρ的效果。
我们的总代价函数现在
J s p a r s e ( W , b ) = J ( W , b ) + β ∑ j = 1 s 2 K L ( ρ ∥ ρ ^ j ) J_{sparse}(W,b) = J(W,b) + \beta \sum\limits_{j = 1}^{s_2} {KL(\left. \rho \right\|} \hat \rho_j) Jsparse(W,b)=J(W,b)+βj=1∑s2KL(ρ∥ρ^j)
其中
J
(
W
,
b
)
J(W,b)
J(W,b)如前所述,
β
\beta
β控制稀疏性惩罚项的权重。术语
ρ
^
j
{\hat \rho }_j
ρ^j(隐含地)也依赖于
W
,
b
W,b
W,b,因为它是隐藏神经元
j
j
j的平均激活,并且隐藏神经元的激活依赖于参数
W
,
b
.
W,b.
W,b.
为了将KL散度项加入到你的导数计算中,有一个简单易行的技巧,只需要对你的代码做一点小小的修改。具体来说,在第二层(
l
2
l_2
l2)之前,在反向传播过程中,您应该已经计算:
δ i ( 2 ) = ( ∑ j = 1 s 2 W j i ( 2 ) δ j ( 3 ) ) f ′ ( z i ( 2 ) ) , \delta _i^{(2)} = (\sum\limits_{j = 1}^{s_2} {W_{ji}^{(2)}} \delta_ j^{(3)})f'(z_i^{(2)}), δi(2)=(j=1∑s2Wji(2)δj(3))f′(zi(2)),
现在改为计算:
δ
i
(
2
)
=
(
(
∑
j
=
1
s
2
W
j
i
(
2
)
δ
j
(
3
)
)
+
β
(
−
ρ
ρ
^
i
+
1
−
ρ
1
−
ρ
^
i
)
)
f
′
(
z
i
(
2
)
)
.
\delta_ i^{(2)} = ((\sum\limits_{j = 1}^{s_2} {W_{ji}^{(2)}} \delta _j^{(3)}) + \beta ( - {\rho \over {\hat \rho_ i}} + {{1 - \rho } \over {1 - \hat \rho _i}}))f'(z_i^{(2)}).
δi(2)=((j=1∑s2Wji(2)δj(3))+β(−ρ^iρ+1−ρ^i1−ρ))f′(zi(2)).
一个微妙之处是你需要知道
ρ
^
i
\hat\rho_i
ρ^i来计算这个项。因此,在计算任何样本的反向传播之前,您需要首先计算所有训练示例的正向传递,以计算训练集中的平均激活。如果您的训练集足够小,可以轻松地放在计算机内存中(这将是编程作业的情况),您可以计算所有示例的向前传递,并将结果激活值保存在内存中,并计算
ρ
^
i
s
\hat\rho_is
ρ^is。然后,您可以使用预计算的激活值来对所有样本执行反向传播。如果您的数据太大,无法存储,您可能需要扫描您的样本,计算每个数据的前向传递,以累积(汇总)激活值并计算
ρ
^
i
\hat\rho_i
ρ^i(在您将每个前向传递的激活
a
i
(
2
)
a_i^{(2)}
ai(2)计算完
ρ
^
i
\hat\rho_i
ρ^i后,丢弃
a
i
(
2
)
a_i^{(2)}
ai(2))。 然后在计算了
ρ
^
i
\hat\rho_i
ρ^i之后,你必须为每个样本重做前向传递,这样你就可以在那个样本上做反向传递。在后一种情况下,您将在您的训练集中的每个示例上计算两次向前传递(一次求均值,一次训练),从而降低了计算效率。
显示上述算法导致梯度下降的完整推导超出了这些注释的范围。但是如果你用这种方式修改的反向传播来实现自动编码器,你将在目标
J
s
p
a
r
s
e
(
W
,
b
)
J_{sparse}(W,b)
Jsparse(W,b)上精确地执行梯度下降。使用导数检查方法,您也可以自己验证这一点。
4可视化
在训练了一个(稀疏的)自动编码器之后,我们现在想要可视化通过算法学习的函数,以尝试理解它已经学习了什么。 考虑在10×10图像上训练自动编码器的情况,因此 n = 100 n =100 n=100。每个隐藏单元 i i i计算输入的函数:
a
i
(
2
)
=
f
(
∑
j
=
1
100
W
i
j
(
1
)
x
j
+
b
i
(
1
)
)
.
a_i^{(2)} = f(\sum\limits_{j = 1}^{100} {W_{ij}^{(1)}} x_j + b_i^{(1)}).
ai(2)=f(j=1∑100Wij(1)xj+bi(1)).
我们将使用2D图像可视化由隐藏神经元
i
i
i计算的函数,隐藏神经元依赖于参数
W
i
j
(
1
)
W_{ij}^{(1)}
Wij(1)(暂时忽略偏置项)。特别是,我们想到一个
a
i
(
1
)
a_i^{(1)}
ai(1)作为输入
x
x
x的一些非线性特征。我们问:什么样的输入图像
x
x
x会导致
a
i
(
1
)
a_i^{(1)}
ai(1)被最大程度地激活?这个问题要有一个不平凡的答案,我们必须对
x
x
x施加一些约束。如果我们假设输入由
∥
x
∥
2
=
∑
i
=
1
100
x
i
2
≤
1
\left\| x \right\|^2 = \sum\nolimits_{i = 1}^{100} {x_i^2 \le 1}
∥x∥2=∑i=1100xi2≤1的范数约束,那么我们就可以证明(你自己试试看)最大限度地激活隐藏神经元
i
i
i的输入是通过设置像素
x
j
x_j
xj(对于所有100个像素,j= 1,…,100)给出
x j = W i j ( 1 ) ∑ j = 1 100 ( W i j ( 1 ) ) 2 x_j = {{W_{ij}^{(1)}} \over {\sqrt {\sum\nolimits_{j = 1}^{100} {(W_{ij}^{(1)})2} } }} xj=∑j=1100(Wij(1))2Wij(1)
通过显示由这些像素强度值形成的图像,我们可以开始理解隐藏神经元在寻找什么特征。
如果我们有一个有100个隐藏神经元的自动编码器,那么我们的可视化将有100个这样的图像,每个隐藏神经元一个。通过检查这100张图片,我们可以试着理解隐藏神经元的集合在学习什么。
当我们对一个稀疏的自动编码器(在10×10像素输入上用100个隐藏神经元训练(
4
^4
4下面的结果是通过对白化的自然图像进行训练获得的。白化是一个预处理步骤,通过降低相邻像素的相关性来消除输入中的冗余。))这样做时,我们得到以下结果:
上图中的每个方块显示了(范数有界的)能够最大程度地激活了100个隐藏神经元中的一个的输入图像
x
x
x。我们看到不同的隐藏单元已经学会了检测图像中不同位置和方向的边缘。
毫不奇怪,这些特征对于物体识别和其他视觉任务是有用的。当应用于其他输入域(如音频)时,该算法也学习这些域的有用表示/特征。
5符号摘要
符号 | 描述 |
---|---|
x x x | 训练样本的输入特征, x ∈ R n x\in\R^n x∈Rn |
y y y | 输出/目标值。这里y可以是向量值。在自动编码器的情况 y = x y=x y=x |
( x ( i ) , y ( i ) ) (x^{(i)},y^{(i)}) (x(i),y(i)) | 第 i i i个训练样本 |
h W , b ( x ) h_{W,b}(x) hW,b(x) | 输入 x x x、使用参数W,b的输出。这应该是与目标值 y y y相同维数的向量。 |
W i j ( l ) W_{ij}^{(l)} Wij(l) | 层 l l l中的神经元 j j j和层 l + 1 l+1 l+1中的神经元 i i i之间的连接系数。 |
b i ( l ) b_i^{(l)} bi(l) | 与层 l + 1 l+1 l+1中的神经元 i i i相关的偏置项。也可以认为是层 l l l和层 l + 1 l+1 l+1中的之间的连接偏置 参数。 |
θ \theta θ | 参数向量。将此视为将参数 W 、 b W、b W、b“展开”成一个长列向量。 |
a i ( l ) a_i^{(l)} ai(l) | l l l层第 i i i个神经元的激活(输出)。另外,因为层 L 1 L_1 L1是输入层,所以我们有 a i ( 1 ) = x i a_i^{(1)}=x_i ai(1)=xi。 |
f ( ∙ ) f( \bullet ) f(∙) | 激活函数。在这些笔记中,我们使用了 f ( z ) = t a n h ( z ) f(z)=tanh(z) f(z)=tanh(z)。 |
z i ( l ) z_i^{(l)} zi(l) | 层 l l l中神经元 i i i的总输入加权和。因此 a i ( l ) = f ( z i ( l ) ) a_i^{(l)}=f(z_i^{(l)}) ai(l)=f(zi(l)) |
α \alpha α | 学习率 |
s l s_l sl | 层 l l l的神经元个数(不包括偏置神经元) |
n l n_l nl | 网络层数。层 L 1 L_1 L1通常是输入层,层 L n l L_{n_l} Lnl是输出层 |
λ \lambda λ | 权重衰减参数 |
x ^ \hat x x^ | 对于自动编码器,它是输出;即它对输入 x x x的重构,与 h W , b ( x ) h_{W,b}(x) hW,b(x)的意思相同。 |
ρ \rho ρ | 稀疏度参数,它指定了我们期望的稀疏度级别。 |
ρ ^ i \hat \rho_i ρ^i | 隐藏神经元 i i i的平均激活(在稀疏自动编码器中)。 |
β \beta β | 稀疏惩罚项的权重(在稀疏自动编码器目标中)。 |