本章编程作业及代码实现部分见:多类分类和神经网络 神经网络中的反向传播
无论是线性回归还是逻辑回归都有这样一个缺点,即:当特征太多时,计算的负荷会非常大。
下面是一个例子:
当我们使用 x 1 x_1 x1, x 2 x_2 x2 的多次项式进行预测时,我们可以应用的很好。
之前我们已经看到过,使用非线性的多项式项,能够帮助我们建立更好的分类模型。假设我们有非常多的特征,例如大于100个变量,我们希望用这100个特征来构建一个非线性的多项式模型,结果将是数量非常惊人的特征组合,即便我们只采用两两特征的组合 ( x 1 x 2 + x 1 x 3 + x 1 x 4 + . . . + x 2 x 3 + x 2 x 4 + . . . + x 99 x 100 ) (x_1x_2+x_1x_3+x_1x_4+...+x_2x_3+x_2x_4+...+x_{99}x_{100}) (x1x2+x1x3+x1x4+...+x2x3+x2x4+...+x99x100),我们也会有接近5000个组合而成的特征。这对于一般的逻辑回归来说需要计算的特征太多了。
假设我们希望训练一个模型来识别视觉对象(例如识别一张图片上是否是一辆汽车),我们怎样才能这么做呢?一种方法是我们利用很多汽车的图片和很多非汽车的图片,然后利用这些图片上一个个像素的值(饱和度或亮度)来作为特征。
假如我们只选用灰度图片,每个像素则只有一个值(而非 RGB值),我们可以选取图片上的两个不同位置上的两个像素,然后训练一个逻辑回归算法利用这两个像素的值来判断图片上是否是汽车:
假使我们采用的都是50x50像素的小图片,并且我们将所有的像素视为特征,则会有 2500个特征,如果我们要进一步将两两特征组合构成一个多项式模型,则会有约 2500 2 / 2 {{2500}^{2}}/2 25002/2个(接近3百万个)特征。普通的逻辑回归模型,不能有效地处理这么多的特征,这时候我们需要神经网络。
为了构建神经网络模型,我们需要首先思考大脑中的神经网络是怎样的?每一个神经元都可以被认为是一个处理单元/神经核(processing unit/Nucleus),它含有许多输入/树突(input/Dendrite),并且有一个输出/轴突(output/Axon)。神经网络是大量神经元相互链接并通过电脉冲来交流的一个网络。
神经网络模型建立在很多神经元之上,每一个神经元又是一个个学习模型。这些神经元(也叫激活单元,activation unit)采纳一些特征作为输出,并且根据本身的模型提供一个输出。下图是一个以逻辑回归模型作为自身学习模型的神经元示例,在神经网络中,参数又可被成为权重(weight)。
其中 x 1 x_1 x1, x 2 x_2 x2, x 3 x_3 x3是输入单元(input units),我们将原始数据输入给它们。
a 1 a_1 a1, a 2 a_2 a2, a 3 a_3 a3是中间单元,它们负责将数据进行处理,然后呈递到下一层。
最后是输出单元,它负责计算 h θ ( x ) {h_\theta}\left( x \right) hθ(x)。
神经网络模型是许多逻辑单元按照不同层级组织起来的网络,每一层的输出变量都是下一层的输入变量。下图为一个3层的神经网络,第一层成为输入层(Input Layer),最后一层称为输出层(Output Layer),中间一层成为隐藏层(Hidden Layers)。我们为每一层都增加一个偏差单位(bias unit):
下面引入一些标记法来帮助描述模型:
a i ( j ) a_{i}^{\left( j \right)} ai(j) 代表第 j j j 层的第 i i i 个激活单元。 θ ( j ) {{\theta }^{\left( j \right)}} θ(j)代表从第 j j j 层映射到第$ j+1$ 层时的权重的矩阵,例如 θ ( 1 ) {{\theta }^{\left( 1 \right)}} θ(1)代表从第一层映射到第二层的权重的矩阵。其尺寸为:以第 j + 1 j+1 j+1层的激活单元数量为行数,以第 j j j 层的激活单元数加一为列数的矩阵。例如:上图所示的神经网络中 θ ( 1 ) {{\theta }^{\left( 1 \right)}} θ(1)的尺寸为 3*4。
对于上图所示的模型,激活单元和输出分别表达为:
a 1 ( 2 ) = g ( Θ 10 ( 1 ) x 0 + Θ 11 ( 1 ) x 1 + Θ 12 ( 1 ) x 2 + Θ 13 ( 1 ) x 3 ) a_{1}^{(2)}=g(\Theta _{10}^{(1)}{{x}_{0}}+\Theta _{11}^{(1)}{{x}_{1}}+\Theta _{12}^{(1)}{{x}_{2}}+\Theta _{13}^{(1)}{{x}_{3}}) a1(2)=g(Θ10(1)x0+Θ11(1)x1+Θ12(1)x2+Θ13(1)x3)
a 2 ( 2 ) = g ( Θ 20 ( 1 ) x 0 + Θ 21 ( 1 ) x 1 + Θ 22 ( 1 ) x 2 + Θ 23 ( 1 ) x 3 ) a_{2}^{(2)}=g(\Theta _{20}^{(1)}{{x}_{0}}+\Theta _{21}^{(1)}{{x}_{1}}+\Theta _{22}^{(1)}{{x}_{2}}+\Theta _{23}^{(1)}{{x}_{3}}) a2(2)=g(Θ20(1)x0+Θ21(1)x1+Θ22(1)x2+Θ23(1)x3)
a 3 ( 2 ) = g ( Θ 30 ( 1 ) x 0 + Θ 31 ( 1 ) x 1 + Θ 32 ( 1 ) x 2 + Θ 33 ( 1 ) x 3 ) a_{3}^{(2)}=g(\Theta _{30}^{(1)}{{x}_{0}}+\Theta _{31}^{(1)}{{x}_{1}}+\Theta _{32}^{(1)}{{x}_{2}}+\Theta _{33}^{(1)}{{x}_{3}}) a3(2)=g(Θ30(1)x0+Θ31(1)x1+Θ32(1)x2+Θ33(1)x3)
h Θ ( x ) = g ( Θ 10 ( 2 ) a 0 ( 2 ) + Θ 11 ( 2 ) a 1 ( 2 ) + Θ 12 ( 2 ) a 2 ( 2 ) + Θ 13 ( 2 ) a 3 ( 2 ) ) {{h}_{\Theta }}(x)=g(\Theta _{10}^{(2)}a_{0}^{(2)}+\Theta _{11}^{(2)}a_{1}^{(2)}+\Theta _{12}^{(2)}a_{2}^{(2)}+\Theta _{13}^{(2)}a_{3}^{(2)}) hΘ(x)=g(Θ10(2)a0(2)+Θ11(2)a1(2)+Θ12(2)a2(2)+Θ13(2)a3(2))
上面进行的讨论中只是将特征矩阵中的一行(一个训练实例)喂给了神经网络,我们需要将整个训练集都喂给我们的神经网络算法来学习模型。
我们可以知道:每一个 a a a都是由上一层所有的 x x x和每一个 x x x所对应的决定的。
(我们把这样从左到右的算法称为前向传播算法( FORWARD PROPAGATION ))
把 x x x, θ \theta θ, a a a 分别用矩阵表示:
我们可以得到 θ ⋅ X = a \theta \cdot X=a θ⋅X=a 。
( FORWARD PROPAGATION )
相对于使用循环来编码,利用向量化的方法会使得计算更为简便。以上面的神经网络为例,试着计算第二层的值:
我们令 z ( 2 ) = θ ( 1 ) x {{z}^{\left( 2 \right)}}={{\theta }^{\left( 1 \right)}}x z(2)=θ(1)x,则 a ( 2 ) = g ( z ( 2 ) ) {{a}^{\left( 2 \right)}}=g({{z}^{\left( 2 \right)}}) a(2)=g(z(2)) ,计算后添加 a 0 ( 2 ) = 1 a_{0}^{\left( 2 \right)}=1 a0(2)=1。 计算输出的值为:
我们令 z ( 3 ) = θ ( 2 ) a ( 2 ) {{z}^{\left( 3 \right)}}={{\theta }^{\left( 2 \right)}}{{a}^{\left( 2 \right)}} z(3)=θ(2)a(2),则 h θ ( x ) = a ( 3 ) = g ( z ( 3 ) ) h_\theta(x)={{a}^{\left( 3 \right)}}=g({{z}^{\left( 3 \right)}}) hθ(x)=a(3)=g(z(3))。
这只是针对训练集中一个训练实例所进行的计算。如果我们要对整个训练集进行计算,我们需要将训练集特征矩阵进行转置,使得同一个实例的特征都在同一列里。即:
z ( 2 ) = Θ ( 1 ) × X T {{z}^{\left( 2 \right)}}={{\Theta }^{\left( 1 \right)}}\times {{X}^{T}} z(2)=Θ(1)×XT
a ( 2 ) = g ( z ( 2 ) ) {{a}^{\left( 2 \right)}}=g({{z}^{\left( 2 \right)}}) a(2)=g(z(2))
为了更好了了解Neuron Networks的工作原理,我们先把左半部分遮住:
右半部分其实就是以 a 0 , a 1 , a 2 , a 3 a_0, a_1, a_2, a_3 a0,a1,a2,a3, 按照Logistic Regression的方式输出 h θ ( x ) h_\theta(x) hθ(x):
h θ ( x ) = g ( Θ 0 ( 2 ) a 0 ( 2 ) + Θ 1 ( 2 ) a 1 ( 2 ) + Θ 2 ( 2 ) a 2 ( 2 ) + Θ 3 ( 2 ) a 3 ( 2 ) ) h_\theta(x)=g\left( \Theta_0^{\left( 2 \right)}a_0^{\left( 2 \right)}+\Theta_1^{\left( 2 \right)}a_1^{\left( 2 \right)}+\Theta_{2}^{\left( 2 \right)}a_{2}^{\left( 2 \right)}+\Theta_{3}^{\left( 2 \right)}a_{3}^{\left( 2 \right)} \right) hθ(x)=g(Θ0(2)a0(2)+Θ1(2)a1(2)+Θ2(2)a2(2)+Θ3(2)a3(2))
其实神经网络就像是logistic regression,只不过我们把logistic regression中的输入向量 [ x 1 ∼ x 3 ] \left[ x_1\sim {x_3} \right] [x1∼x3] 变成了中间层的 [ a 1 ( 2 ) ∼ a 3 ( 2 ) ] \left[ a_1^{(2)}\sim a_3^{(2)} \right] [a1(2)∼a3(2)], 即: h θ ( x ) = g ( Θ 0 ( 2 ) a 0 ( 2 ) + Θ 1 ( 2 ) a 1 ( 2 ) + Θ 2 ( 2 ) a 2 ( 2 ) + Θ 3 ( 2 ) a 3 ( 2 ) ) h_\theta(x)=g\left( \Theta_0^{\left( 2 \right)}a_0^{\left( 2 \right)}+\Theta_1^{\left( 2 \right)}a_1^{\left( 2 \right)}+\Theta_{2}^{\left( 2 \right)}a_{2}^{\left( 2 \right)}+\Theta_{3}^{\left( 2 \right)}a_{3}^{\left( 2 \right)} \right) hθ(x)=g(Θ0(2)a0(2)+Θ1(2)a1(2)+Θ2(2)a2(2)+Θ3(2)a3(2))
我们可以把 a 0 , a 1 , a 2 , a 3 a_0, a_1, a_2, a_3 a0,a1,a2,a3看成更为高级的特征值,也就是 x 0 , x 1 , x 2 , x 3 x_0, x_1, x_2, x_3 x0,x1,x2,x3的进化体,并且它们是由 x x x与 θ \theta θ决定的,因为是梯度下降的,所以 a a a是变化的,并且变得越来越厉害,所以这些更高级的特征值远比仅仅将 x x x次方厉害,也能更好的预测新数据。
这就是神经网络相比于逻辑回归和线性回归的优势。
从本质上讲,神经网络能够通过学习得出其自身的一系列特征。在普通的逻辑回归中,我们被限制为使用数据中的原始特征 x 1 , x 2 , . . . , x n x_1,x_2,...,{{x}_{n}} x1,x2,...,xn,我们虽然可以使用一些二项式项来组合这些特征,但是我们仍然受到这些原始特征的限制。在神经网络中,原始特征只是输入层,在我们上面三层的神经网络例子中,第三层也就是输出层做出的预测利用的是第二层的特征,而非输入层中的原始特征,我们可以认为第二层中的特征是神经网络通过学习后自己得出的一系列用于预测输出变量的新特征。
神经网络中,单层神经元(无中间层)的计算可用来表示逻辑运算,比如逻辑与(AND)、逻辑或(OR)。
举例说明:逻辑与(AND);下图中左半部分是神经网络的设计与output层表达式,右边上部分是sigmod函数,下半部分是真值表。
其中 θ 0 = − 30 , θ 1 = 20 , θ 2 = 20 \theta_0 = -30, \theta_1 = 20, \theta_2 = 20 θ0=−30,θ1=20,θ2=20
我们的输出函数 h θ ( x ) h_\theta(x) hθ(x)即为: h Θ ( x ) = g ( − 30 + 20 x 1 + 20 x 2 ) h_\Theta(x)=g\left( -30+20x_1+20x_2 \right) hΘ(x)=g(−30+20x1+20x2)
所以我们有: h Θ ( x ) ≈ x 1 AND   x 2 h_\Theta(x) \approx \text{x}_1 \text{AND} \, \text{x}_2 hΘ(x)≈x1ANDx2
所以我们的:$h_\Theta(x) $
这就是AND函数。
接下来再介绍一个OR函数:
OR与AND整体一样,区别只在于的取值不同。
二元逻辑运算符(BINARY LOGICAL OPERATORS)当输入特征为布尔值(0或1)时,我们可以用一个单一的激活层可以作为二元逻辑运算符,为了表示不同的运算符,我们只需要选择不同的权重即可。
下图的神经元(三个权重分别为-30,20,20)可以被视为作用同于逻辑与(AND):
下图的神经元(三个权重分别为-10,20,20)可以被视为作用等同于逻辑或(OR):
下图的神经元(两个权重分别为 10,-20)可以被视为作用等同于逻辑非(NOT):
我们可以利用神经元来组合成更为复杂的神经网络以实现更复杂的运算。例如我们要实现XNOR 功能(输入的两个值必须一样,均为1或均为0),即 XNOR = ( x 1   AND   x 2 )   OR ( ( NOT   x 1 ) AND ( NOT   x 2 ) ) \text{XNOR}=( \text{x}_1\, \text{AND}\, \text{x}_2 )\, \text{OR} \left( \left( \text{NOT}\, \text{x}_1 \right) \text{AND} \left( \text{NOT}\, \text{x}_2 \right) \right) XNOR=(x1ANDx2)OR((NOTx1)AND(NOTx2))
首先构造一个能表达 ( NOT   x 1 ) AND ( NOT   x 2 ) \left( \text{NOT}\, \text{x}_1 \right) \text{AND} \left( \text{NOT}\, \text{x}_2 \right) (NOTx1)AND(NOTx2)部分的神经元:
然后将表示 AND 的神经元和表示 ( NOT   x 1 ) AND ( NOT   x 2 ) \left( \text{NOT}\, \text{x}_1 \right) \text{AND} \left( \text{NOT}\, \text{x}_2 \right) (NOTx1)AND(NOTx2)的神经元以及表示 OR 的神经元进行组合:
我们就得到了一个能实现 XNOR \text{XNOR} XNOR 运算符功能的神经网络。
按这种方法我们可以逐渐构造出越来越复杂的函数,也能得到更加厉害的特征值。;这就是神经网络的厉害之处。
当我们有不止两种分类时(也就是 y = 1 , 2 , 3 … . y=1,2,3…. y=1,2,3….),比如以下这种情况,该怎么办?如果我们要训练一个神经网络算法来识别路人、汽车、摩托车和卡车,在输出层我们应该有4个值。例如,第一个值为1或0用于预测是否是行人,第二个值用于判断是否为汽车。
输入向量 x x x有三个维度,两个中间层,输出层4个神经元分别用来表示4类,也就是每一个数据在输出层都会出现 [ a b c d ] T {{\left[ a\text{ }b\text{ }c\text{ }d \right]}^{T}} [a b c d]T,且 a , b , c , d a,b,c,d a,b,c,d中仅有一个为1,表示当前类。下面是该神经网络的可能结构示例: