假设神经网络的训练样本有m个,每个包含一组输入x和一组输出信号y,L表示神经网络层数,SI表示每层的neuron个数(Sl表示输出层神经元个数),SL代表最后一层中处理单元的个数。
将神经网络的分类定义为两种情况:二类分类和多类分类,
二类分类:SL=0,y=0/1表示哪一类;
类分类:SL=k,yi=1表示分到第i类(k>2);
我们回顾逻辑回归问题中我们的代价函数为:
hθ = − 1 m [ ∑ i = 1 m y i ⋅ 1 log h 0 ( x ( i ) + ( 1 − y ( i ) ) ) log ( 1 − h a ( x ( i ) ) ] + x 2 m ∑ j = 1 n Θ j 2 -\dfrac{1}{m}[ \sum ^{m}_{i=1}y^{i\cdot 1}\log h_{0}\left( x^{\left( i\right) }+\left( 1-y^{\left( i\right) }\right) \right) \log ( 1-h_{a}\left( x^{(i)}\right)] +\dfrac{x}{2m}\sum ^{n}_{j=1}\Theta _{j}^{2} −m1[∑i=1myi⋅1logh0(x(i)+(1−y(i)))log(1−ha(x(i))]+2mx∑j=1nΘj2
在逻辑回归中,我们只有一个输出变量,又称标量(scalar),也只有一个因变量y,但是在神经网络中,我们可以有很多输出变量,我们的hθ(x)是一个维度为K的向量,并且我们训练集中的因变量也是同样维度的一个向量,因此我们的代价函数会比逻辑回归更加复杂一些,为: h θ ( x ) ∈ R k ( h 0 ( x ) ) i = i t h o u t p u t h_{\theta }\left( x\right) \in R^{k}\left( h_{0}\left( x\right) \right) _{i}=i^{th}output hθ(x)∈Rk(h0(x))i=ithoutput
这个看起来复杂很多的代价函数背后的思想还是一样的,我们希望通过代价函数来观察算法预测的结果与真实情况的误差有多大,唯一不同的是,对于每一行特征,我们都会给出个K预测,基本上我们可以利用循环,对每一行特征都预测K个不同结果,然后在利用循环在K个预测中选择可能性最高的一个,将其与y中的实际数据进行比较。
正则化的那一项只是排除了每一层θ0后,每一层的θ 矩阵的和。最里层的j循环循环所有的行(由 Sl+1 层的激活单元数决定),循环则循环所有的列,由该层(Sl层)的激活单元数所决定。即:hθ(x)与真实值之间的距离为每个样本-每个类输出的加和,对参数进行regularization的bias项处理所有参数的平方和。
采用了一种正向传播方法,我们从第一层开始正向一层一层进行计算,直到最后一层的 h θ ( x ) h_{\theta}\left(x\right) hθ(x)。
现在,为了计算代价函数的偏导数 ∂ ∂ Θ i j ( l ) J ( Θ ) \frac{\partial}{\partial\Theta^{(l)}_{ij}}J\left(\Theta\right) ∂Θij(l)∂J(Θ),我们需要采用一种反向传播算法,也就是首先计算最后一层的误差,然后再一层一层反向求出各层的误差,直到倒数第二层。 以一个例子来说明反向传播算法。
假设我们的训练集只有一个样本 ( x ( 1 ) , y ( 1 ) ) \left({x}^{(1)},{y}^{(1)}\right) (x(1),y(1)),我们的神经网络是一个四层的神经网络,其中 K = 4 , S L = 4 , L = 4 K=4,S_{L}=4,L=4 K=4,SL=4,L=4:
前向传播算法:
从最后一层的误差开始计算,误差是激活单元的预测( a ( 4 ) {a^{(4)}} a(4))与实际值( y k y^k yk)之间的误差,( k = 1 : k k=1:k k=1:k)。 我们用 δ \delta δ来表示误差,则: δ ( 4 ) = a ( 4 ) − y \delta^{(4)}=a^{(4)}-y δ(4)=a(4)−y 我们利用这个误差值来计算前一层的误差: δ ( 3 ) = ( Θ ( 3 ) ) T δ ( 4 ) ∗ g ′ ( z ( 3 ) ) \delta^{(3)}=\left({\Theta^{(3)}}\right)^{T}\delta^{(4)}\ast g'\left(z^{(3)}\right) δ(3)=(Θ(3))Tδ(4)∗g′(z(3)) 其中 g ′ ( z ( 3 ) ) g'(z^{(3)}) g′(z(3))是 S S S 形函数的导数, g ′ ( z ( 3 ) ) = a ( 3 ) ∗ ( 1 − a ( 3 ) ) g'(z^{(3)})=a^{(3)}\ast(1-a^{(3)}) g′(z(3))=a(3)∗(1−a(3))。而 ( θ ( 3 ) ) T δ ( 4 ) (θ^{(3)})^{T}\delta^{(4)} (θ(3))Tδ(4)则是权重导致的误差的和。下一步是继续计算第二层的误差: $ \delta{(2)}=(\Theta{(2)}){T}\delta{(3)}\ast g’(z^{(2)})$ 因为第一层是输入变量,不存在误差。我们有了所有的误差的表达式后,便可以计算代价函数的偏导数了,假设 λ = 0 λ=0 λ=0,即我们不做任何正则化处理时有: ∂ ∂ Θ i j ( l ) J ( Θ ) = a j ( l ) δ i l + 1 \frac{\partial}{\partial\Theta_{ij}^{(l)}}J(\Theta)=a_{j}^{(l)} \delta_{i}^{l+1} ∂Θij(l)∂J(Θ)=aj(l)δil+1
重要的是清楚地知道上面式子中上下标的含义:
l l l 代表目前所计算的是第几层。
j j j 代表目前计算层中的激活单元的下标,也将是下一层的第 j j j个输入变量的下标。
i i i 代表下一层中误差单元的下标,是受到权重矩阵中第 i i i行影响的下一层中的误差单元的下标。
如果我们考虑正则化处理,并且我们的训练集是一个特征矩阵而非向量。在上面的特殊情况中,我们需要计算每一层的误差单元来计算代价函数的偏导数。在更为一般的情况中,我们同样需要计算每一层的误差单元,但是我们需要为整个训练集计算误差单元,此时的误差单元也是一个矩阵,我们用 Δ i j ( l ) \Delta^{(l)}_{ij} Δij(l)来表示这个误差矩阵。第 l l l 层的第 i i i 个激活单元受到第 j j j 个参数影响而导致的误差。
我们的算法表示为:
即首先用正向传播方法计算出每一层的激活单元,利用训练集的结果与神经网络预测的结果求出最后一层的误差,然后利用该误差运用反向传播法计算出直至第二层的所有误差。
在求出了 Δ i j ( l ) \Delta_{ij}^{(l)} Δij(l)之后,我们便可以计算代价函数的偏导数了,计算方法如下: $ D_{ij}^{(l)} :=\frac{1}{m}\Delta_{ij}{(l)}+\lambda\Theta_{ij}{(l)}$ i f ; j ≠ 0 {if}; j \neq 0 if;j=0
$ D_{ij}^{(l)} :=\frac{1}{m}\Delta_{ij}^{(l)}$ i f ; j = 0 {if}; j = 0 if;j=0
在Octave 中,如果我们要使用 fminuc这样的优化算法来求解求出权重矩阵,我们需要将矩阵首先展开成为向量,在利用算法求出最优解后再重新转换回矩阵。
假设我们有三个权重矩阵,Theta1,Theta2 和 Theta3,尺寸分别为 1011,1011 和1*11, 下面的代码可以实现这样的转换:
thetaVec = [Theta1(:) ; Theta2(:) ; Theta3(:)]
...optimization using functions like fminuc...
Theta1 = reshape(thetaVec(1:110, 10, 11);
Theta2 = reshape(thetaVec(111:220, 10, 11);
Theta1 = reshape(thetaVec(221:231, 1, 11);
前向传播算法:
感悟:上图中的 δ ( l ) j = " e r r o r " o f c o s t f o r a ( l ) j ( u n i t j i n l a y e r l ) \delta^{(l)}{j}="error" \ of cost \ for \ a^{(l)}{j} \ (unit \ j \ in \ layer \ l) δ(l)j="error" ofcost for a(l)j (unit j in layer l) 理解如下:
δ ( l ) j \delta^{(l)}{j} δ(l)j 相当于是第 l l l 层的第 j j j 单元中得到的激活项的“误差”,即”正确“的 a ( l ) j a^{(l)}{j} a(l)j 与计算得到的 a j ( l ) a^{(l)}_{j} aj(l) 的差。
而 a ( l ) j = g ( z ( l ) ) a^{(l)}{j}=g(z^{(l)}) a(l)j=g(z(l)) ,(g为sigmoid函数)。我们可以想象 δ ( l ) j \delta^{(l)}{j} δ(l)j 为函数求导时迈出的那一丁点微分,所以更准确的说 δ ( l ) j = ∂ ∂ z ( l ) j c o s t ( i ) \delta^{(l)}{j}=\frac{\partial}{\partial z^{(l)}{j}}cost(i) δ(l)j=∂z(l)j∂cost(i)
怎样把你的参数从矩阵展开成向量,以便我们在高级最优化步骤中的使用需要。
当我们对一个较为复杂的模型(例如神经网络)使用梯度下降算法时,可能会存在一些不容易察觉的错误,意味着,虽然代价看上去在不断减小,但最终的结果可能并不是最优解。
为了避免这样的问题,我们采取一种叫做梯度的数值检验(Numerical Gradient Checking)方法。这种方法的思想是通过估计梯度值来检验我们计算的导数值是否真的是我们要求的。
对梯度的估计采用的方法是在代价函数上沿着切线的方向选择离两个非常近的点然后计算两个点的平均值用以估计梯度。即对于某个特定的 θ \theta θ,我们计算出在 θ \theta θ-$\varepsilon $ 处和 θ \theta θ+$\varepsilon $ 的代价值($\varepsilon $是一个非常小的值,通常选取 0.001),然后求两个代价的平均,用以估计在 θ \theta θ 处的代价值。
Octave 中代码如下:
gradApprox = (J(theta + eps) – J(theta - eps)) / (2*eps)
当 θ \theta θ是一个向量时,我们则需要对偏导数进行检验。因为代价函数的偏导数检验只针对一个参数的改变进行检验,下面是一个只针对 θ 1 \theta_1 θ1进行检验的示例: ∂ ∂ θ 1 = J ( θ 1 + ε 1 , θ 2 , θ 3 . . . θ n ) − J ( θ 1 − ε 1 , θ 2 , θ 3 . . . θ n ) 2 ε \frac{\partial}{\partial\theta_1}=\frac{J\left(\theta_1+\varepsilon_1,\theta_2,\theta_3...\theta_n \right)-J \left( \theta_1-\varepsilon_1,\theta_2,\theta_3...\theta_n \right)}{2\varepsilon} ∂θ1∂=2εJ(θ1+ε1,θ2,θ3...θn)−J(θ1−ε1,θ2,θ3...θn)
最后我们还需要对通过反向传播方法计算出的偏导数进行检验。
根据上面的算法,计算出的偏导数存储在矩阵 D i j ( l ) D_{ij}^{(l)} Dij(l) 中。检验时,我们要将该矩阵展开成为向量,同时我们也将 θ \theta θ 矩阵展开为向量,我们针对每一个 θ \theta θ 都计算一个近似的梯度值,将这些值存储于一个近似梯度矩阵中,最终将得出的这个矩阵同 D i j ( l ) D_{ij}^{(l)} Dij(l) 进行比较。
任何优化算法都需要一些初始的参数。到目前为止我们都是初始所有参数为0,这样的初始方法对于逻辑回归来说是可行的,但是对于神经网络来说是不可行的。如果我们令所有的初始参数都为0,这将意味着我们第二层的所有激活单元都会有相同的值。同理,如果我们初始所有的参数都为一个非0的数,结果也是一样的。
我们通常初始参数为正负ε之间的随机值,假设我们要随机初始一个尺寸为10×11的参数矩阵,代码如下:
Theta1 = rand(10, 11) * (2*eps) – eps
神经网络时的步骤:
网络结构:第一件要做的事是选择网络结构,即决定选择多少层以及决定每层分别有多少个单元。
第一层的单元数即我们训练集的特征数量。
最后一层的单元数是我们训练集的结果的类的数量。
如果隐藏层数大于1,确保每个隐藏层的单元个数相同,通常情况下隐藏层单元的个数越多越好。
我们真正要决定的是隐藏层的层数和每个中间层的单元数。
训练神经网络:
参数的随机初始化
利用正向传播方法计算所有的 h θ ( x ) h_{\theta}(x) hθ(x)
编写计算代价函数 J J J 的代码
利用反向传播方法计算所有偏导数
利用数值检验方法检验这些偏导数
使用优化算法来最小化代价函数
了解就好了