为什么要有神经网络
我们已经学会了线性回归和逻辑回归,它们在拟合曲线与划分类别方面的表现都还不错,为什么我们还需要神经网络呢?因为在许多应用场景中,特征值的数量远超之前练习中的规模,一张灰度图就包含成千上万的像素点信息,对于这样的问题,光是一次项就有成千上万个,若再考虑高次项,矩阵的大小将超出算法的承受范围。因此,我们需要可以更有效表示复杂多项式的工具——神经网络。
神经网络的基本结构
输入数据的一层为输入层,输出结果的一层为输出层,中间都是隐藏层(可以没有,也可以有不只一层)。
除了输入节点和由输入运算得到的节点
x
1
−
3
,
a
1
−
3
x_{1-3},a_{1-3}
x1−3,a1−3一般还会在网络中加入偏置,即
x
0
,
a
0
x_0,a_0
x0,a0。
我们定义 L L L为网络层数, s l s_l sl为第 l l l层的节点个数。 a i ( j ) a_i^{(j)} ai(j)为第 j j j层第 i i i个单元的值,而 Θ ( j ) \Theta^{(j)} Θ(j)表示从第 j j j层向第 j + 1 j+1 j+1层的转移矩阵,其中 Θ p q ( j ) \Theta_{pq}^{(j)} Θpq(j)表示从 a q ( j ) a_q^{(j)} aq(j)向 a p ( j + 1 ) a_p^{(j+1)} ap(j+1)转移的权值,因此 Θ ( j ) \Theta^{(j)} Θ(j)的大小为 s j + 1 × ( s j + 1 ) s_{j+1}\times (s_j+1) sj+1×(sj+1)
神经网络中的运算
正向传播
单个列向量传播
在输入层后续的节点中,我们都引入了逻辑函数
g
(
z
)
=
1
1
+
e
−
z
g(z)=\frac{1}{1+e^{-z}}
g(z)=1+e−z1,转移的代数形式为
a
i
(
j
+
1
)
=
g
(
∑
k
=
0
s
j
Θ
i
k
(
j
)
a
k
(
j
)
)
a_i^{(j+1)}=g\left(\sum_{k=0}^{s_j}\Theta_{ik}^{(j)}a_k^{(j)} \right)
ai(j+1)=g(k=0∑sjΘik(j)ak(j))
在改进后的神经网络中,我们不再使用逻辑函数,因为其在远大于0的区域非常平缓,梯度很小所以收敛速度也很慢。一种改进是使用类似SVM中的曲线,叫做ReLU函数,大概长下面这样:
在
<
0
<0
<0时ReLU函数恒为0;而
>
0
>0
>0时,ReLU函数斜率恒为1,使得梯度下降能一直保持一个不慢的下降速率。不过这已经涉及到后面深度学习的内容了,本文还是按吴恩达讲的来,用逻辑函数。
很显然,层与层之间的转移可以写成矩阵运算形式,令
Θ
(
j
)
=
[
Θ
10
(
j
)
Θ
11
(
j
)
⋯
Θ
1
s
j
(
j
)
Θ
20
(
j
)
Θ
21
(
j
)
⋯
Θ
2
s
j
(
j
)
⋮
⋮
⋱
⋮
Θ
s
j
+
1
0
(
j
)
Θ
s
j
+
1
1
(
j
)
⋯
Θ
s
j
+
1
s
j
(
j
)
]
,
a
(
j
)
=
[
a
1
(
j
)
a
2
(
j
)
⋮
a
s
j
(
j
)
]
\Theta^{(j)}= \left[\begin{matrix} \Theta_{10}^{(j)}&\Theta_{11}^{(j)}&\cdots&\Theta_{1s_j}^{(j)}\\ \Theta_{20}^{(j)}&\Theta_{21}^{(j)}&\cdots&\Theta_{2s_j}^{(j)}\\ \vdots&\vdots&\ddots&\vdots\\ \Theta_{s_{j+1}0}^{(j)}&\Theta_{s_{j+1}1}^{(j)}&\cdots&\Theta_{s_{j+1}s_j}^{(j)}\\ \end{matrix}\right], a^{(j)}= \left[\begin{matrix} a_1^{(j)}\\ a_2^{(j)}\\ \vdots\\ a_{s_{j}}^{(j)}\\ \end{matrix}\right]
Θ(j)=⎣⎢⎢⎢⎢⎡Θ10(j)Θ20(j)⋮Θsj+10(j)Θ11(j)Θ21(j)⋮Θsj+11(j)⋯⋯⋱⋯Θ1sj(j)Θ2sj(j)⋮Θsj+1sj(j)⎦⎥⎥⎥⎥⎤,a(j)=⎣⎢⎢⎢⎢⎡a1(j)a2(j)⋮asj(j)⎦⎥⎥⎥⎥⎤
s
j
+
1
×
(
s
j
+
1
)
s_{j+1}\times (s_j+1)
sj+1×(sj+1)的
Θ
(
j
)
\Theta^{(j)}
Θ(j)乘上
(
s
j
+
1
)
×
1
(s_j+1)\times1
(sj+1)×1的
a
(
j
)
a^{(j)}
a(j)在套用逻辑函数就可以得到
a
(
j
+
1
)
a^{(j+1)}
a(j+1)完成一次从
j
j
j层到
j
+
1
j+1
j+1层的转移。注意这里
a
(
j
)
a^{(j)}
a(j)在运算之前要在加上偏置单位
a
0
a_0
a0,一般
a
0
=
1
a_0=1
a0=1。
矩阵传播
输入数据也有可能不止一个列向量,而是包含了多组数据的矩阵,令
x
i
(
j
)
x_i^{(j)}
xi(j)表示第
j
j
j组数据中第
i
i
i个特征值,输入矩阵
X
X
X为
m
×
s
1
m\times s_1
m×s1矩阵
X
=
[
x
1
(
1
)
x
2
(
1
)
⋯
x
s
1
(
1
)
x
1
(
2
)
x
2
(
2
)
⋯
x
s
1
(
2
)
⋮
⋮
⋱
⋮
x
1
(
m
)
x
2
(
m
)
⋯
x
s
1
(
m
)
]
X= \left[\begin{matrix} x_{1}^{(1)}&x_{2}^{(1)}&\cdots&x_{s_1}^{(1)}\\ x_{1}^{(2)}&x_{2}^{(2)}&\cdots&x_{s_1}^{(2)}\\ \vdots&\vdots&\ddots&\vdots\\ x_{1}^{(m)}&x_{2}^{(m)}&\cdots&x_{s_1}^{(m)}\\ \end{matrix}\right]
X=⎣⎢⎢⎢⎢⎡x1(1)x1(2)⋮x1(m)x2(1)x2(2)⋮x2(m)⋯⋯⋱⋯xs1(1)xs1(2)⋮xs1(m)⎦⎥⎥⎥⎥⎤
此时,要进行向前传播运算,则先在
X
X
X矩阵左侧增加一列
x
0
=
1
x_0=1
x0=1,再乘以参数矩阵的转置,通过逻辑函数得到下一层,通用的矩阵算式为
a
(
j
+
1
)
=
g
(
[
1
a
(
j
)
]
Θ
(
j
)
T
)
a^{(j+1)}=g([1\quad a^{(j)}]\Theta^{(j)T})
a(j+1)=g([1a(j)]Θ(j)T)
这样做的好处是,
a
(
j
)
a^{(j)}
a(j)矩阵始终是
m
m
m行的,对应
m
m
m个样本,添加偏置只需要在左侧加一列
m
×
1
m\times1
m×1的
1
1
1向量就可以了,不过每次参数矩阵都要专职一下。
如此一直到输出层,找到每行最大值所在索引,就能知道每个样本被分到哪一类了。
反向传播
代价函数
正向传播是利用已有参数进行预测,要优化参数则需要反向传播,这时也要用到代价函数的概念。令
K
=
s
L
K=s_L
K=sL为输出层的单元个数,一般为分类问题中种类的个数,则代价函数为
J
(
Θ
)
=
−
1
m
∑
i
=
1
m
∑
k
=
1
K
[
y
k
(
i
)
log
(
(
h
Θ
(
x
(
i
)
)
)
k
)
+
(
1
−
y
k
(
i
)
)
log
(
1
−
(
h
Θ
(
x
(
i
)
)
)
k
)
]
+
λ
2
m
∑
l
=
1
L
−
1
∑
i
=
1
s
l
∑
j
=
1
s
l
+
1
(
Θ
j
i
(
l
)
)
2
J(\Theta)=-\frac{1}{m}\sum_{i=1}^m\sum_{k=1}^K[y_k^{(i)}\log((h_\Theta(x^{(i)}))_k)+(1-y_k^{(i)})\log(1-(h_\Theta(x^{(i)}))_k)]+\frac{\lambda}{2m}\sum_{l=1}^{L-1}\sum_{i=1}^{s_l}\sum_{j=1}^{s_{l+1}}(\Theta_{ji}^{(l)})^2
J(Θ)=−m1i=1∑mk=1∑K[yk(i)log((hΘ(x(i)))k)+(1−yk(i))log(1−(hΘ(x(i)))k)]+2mλl=1∑L−1i=1∑slj=1∑sl+1(Θji(l))2
看起来很复杂,实际上只是把正则化逻辑回归代价函数的拟合程度部分扩展到了
K
K
K类,把正则项扩展到了
L
L
L层的所有矩阵。可以与正则化逻辑回归代价函数比对起来观察:
J
(
θ
)
=
−
1
m
∑
i
=
1
m
[
y
log
(
h
θ
(
x
⃗
)
)
+
(
1
−
y
)
log
(
1
−
h
θ
(
x
⃗
)
)
]
+
λ
2
m
∑
j
=
1
n
θ
j
2
J(\theta)=-\frac{1}{m}\sum_{i=1}^m\left[y\log(h_\theta(\vec{x}))+(1-y)\log(1-h_\theta(\vec{x}))\right] +\frac{\lambda}{2m}\sum_{j=1}^n\theta_j^2
J(θ)=−m1i=1∑m[ylog(hθ(x))+(1−y)log(1−hθ(x))]+2mλj=1∑nθj2
计算误差
既然要修正,首先就要定义误差, δ j ( l ) \delta_j^{(l)} δj(l)表示第 l l l层第 j j j个单元的误差。显然,对于输出层,就有 δ j ( L ) = a j ( L ) − y j \delta_j^{(L)}=a_j^{(L)}-y_j δj(L)=aj(L)−yj,向量化之后就是 δ ( L ) = a ( L ) − y \delta^{(L)}=a^{(L)}-y δ(L)=a(L)−y。
得到了输出层的误差,接下来就要反推之前所有隐藏层的误差了(输入层无误差)。大致的思路是误差乘以参数矩阵传递一下再乘以逻辑函数的倒数,即
δ
(
l
)
=
(
(
Θ
(
l
)
)
T
δ
(
l
+
1
)
)
.
∗
g
′
(
z
(
l
)
)
\delta^{(l)}=((\Theta^{(l)})^T\delta^{(l+1)}).*g'(z^{(l)})
δ(l)=((Θ(l))Tδ(l+1)).∗g′(z(l))
其中,
a
(
l
)
=
g
(
z
(
l
)
)
a^{(l)}=g(z^{(l)})
a(l)=g(z(l)),故
g
′
(
z
(
l
)
)
=
e
−
z
(
l
)
(
1
+
e
−
z
(
l
)
)
2
=
1
1
+
e
−
z
(
l
)
.
∗
(
1
−
1
1
+
e
−
z
(
l
)
)
=
a
(
l
)
.
∗
(
1
−
a
(
l
)
)
g'(z^{(l)})=\frac{e^{-z^{(l)}}}{(1+e^{-z^{(l)}})^2}=\frac{1}{1+e^{-z^{(l)}}}.*(1-\frac{1}{1+e^{-z^{(l)}}})=a^{(l)}.*(1-a^{(l)})
g′(z(l))=(1+e−z(l))2e−z(l)=1+e−z(l)1.∗(1−1+e−z(l)1)=a(l).∗(1−a(l))
最终得到的误差传播公式为
δ
(
l
)
=
(
(
Θ
(
l
)
)
T
δ
(
l
+
1
)
)
.
∗
a
(
l
)
.
∗
(
1
−
a
(
l
)
)
\delta^{(l)}=((\Theta^{(l)})^T\delta^{(l+1)}).*a^{(l)}.*(1-a^{(l)})
δ(l)=((Θ(l))Tδ(l+1)).∗a(l).∗(1−a(l))
计算梯度
定义
Δ
i
j
(
l
)
:
=
Δ
i
j
(
l
)
+
a
j
(
l
)
δ
i
(
l
+
1
)
\Delta_{ij}^{(l)}:=\Delta_{ij}^{(l)}+a_j^{(l)}\delta_i^{(l+1)}
Δij(l):=Δij(l)+aj(l)δi(l+1),矩阵运算形式为
Δ
(
l
)
:
=
Δ
(
l
)
+
δ
(
l
+
1
)
(
a
(
l
)
)
T
\Delta^{(l)}:=\Delta^{(l)}+\delta^{(l+1)}(a^{(l)})^T
Δ(l):=Δ(l)+δ(l+1)(a(l))T
将误差与单元激励值相乘并累加后,经过一系列很复杂以至于吴恩达没讲的推导以后,我们就得到了梯度的表达式:
∂
∂
Θ
i
j
(
l
)
J
(
Θ
)
=
D
i
j
(
l
)
=
{
1
m
(
Δ
i
j
(
l
)
+
λ
Θ
i
j
(
l
)
)
j
≠
0
1
m
Δ
i
j
(
l
)
j
=
0
\frac{\partial}{\partial\Theta_{ij}^{(l)}}J(\Theta)=D_{ij}^{(l)}=\left\{ \begin{aligned} &\frac{1}{m}(\Delta_{ij}^{(l)}+\lambda\Theta_{ij}^{(l)})&&j\not=0\\ &\frac{1}{m}\Delta_{ij}^{(l)}&&j=0\\ \end{aligned}\right.
∂Θij(l)∂J(Θ)=Dij(l)=⎩⎪⎨⎪⎧m1(Δij(l)+λΘij(l))m1Δij(l)j=0j=0
注意
j
=
0
j=0
j=0为偏置,不参与正则化,故没有正则项。
综上,每次我们用已有参数进行一次向前传播,再进行一次向后传播修改参数,如此迭代多次就可以得到一个较准确的模型了。