0


手把手教你用numpy搭建一个单隐层神经网络

在阅读本文之前,请确保你已经有了一定的神经网络基础(可先看一遍西瓜书)。

本文采用的是标准BP算法,即每次仅针对一个样例更新权重和阈值。
本文将搭建用于分类的单隐层BP神经网络。

目录

一、理论部分

1.1 正向计算

     符
    
    
     号
    
    
     说
    
    
     明
    
   
  
  
   \textcolor{red}{符号说明}
  
 
符号说明

设我们的单隐层BP神经网络有

    m
   
  
  
   m
  
 
m 个**输入神经元**,

 
  
   
    n
   
  
  
   n
  
 
n 个**输出神经元**,

 
  
   
    h
   
  
  
   h
  
 
h 个**隐层神经元**。
  • 权重: 第 i i i 个输入神经元到第 j j j 个隐层神经元的权重记为 v i j v_{ij} vij​,第 i i i 个隐层神经元到第 j j j 个输出神经元的权重记为 w i j w_{ij} wij​;
  • 阈值: 第 i i i 个隐层神经元的阈值记为 γ i \gamma_i γi​,第 i i i 个输出神经元的阈值记为 θ i \theta_i θi​;
  • 输入: 第 k k k 个输入神经元接收到的输入记为 x k x_k xk​,第 k k k 个隐层神经元接收到的输入记为 α k \alpha_k αk​,第 k k k 个输出神经元接收到的输入记为 β k \beta_k βk​;
  • 输出: 第 j j j 个隐层神经元的输出记为 b j b_j bj​,第 j j j 个输出神经元的输出记为 y ^ j \hat{y}_j y^​j​。

    x
   
   
    =
   
   
    (
   
   
    
     x
    
    
     1
    
   
   
    ,
   
   
    
     x
    
    
     2
    
   
   
    ,
   
   
    ⋯
    
   
    ,
   
   
    
     x
    
    
     n
    
   
   
    
     )
    
    
     T
    
   
  
  
   \boldsymbol{x}=(x_1,x_2,\cdots,x_n)^{\mathrm T}
  
 
x=(x1​,x2​,⋯,xn​)T,激活函数为 

 
  
   
    σ
   
   
    (
   
   
    x
   
   
    )
   
  
  
   \sigma(x)
  
 
σ(x),我们定义:

 
  
   
    
     σ
    
    
     (
    
    
     x
    
    
     )
    
    
     =
    
    
     (
    
    
     σ
    
    
     (
    
    
     
      x
     
     
      1
     
    
    
     )
    
    
     ,
    
    
     σ
    
    
     (
    
    
     
      x
     
     
      2
     
    
    
     )
    
    
     ,
    
    
     ⋯
     
    
     ,
    
    
     σ
    
    
     (
    
    
     
      x
     
     
      n
     
    
    
     )
    
    
     
      )
     
     
      T
     
    
   
   
     \sigma(\boldsymbol{x})=(\sigma(x_1),\sigma(x_2),\cdots,\sigma(x_n))^{\mathrm T} 
   
  
 σ(x)=(σ(x1​),σ(x2​),⋯,σ(xn​))T


 
  
   
    
     公
    
    
     式
    
    
     推
    
    
     导
    
   
  
  
   \textcolor{red}{公式推导}
  
 
公式推导

注意到

     α
    
    
     k
    
   
   
    =
   
   
    
     ∑
    
    
     
      i
     
     
      =
     
     
      1
     
    
    
     m
    
   
   
    
     v
    
    
     
      i
     
     
      k
     
    
   
   
    
     x
    
    
     i
    
   
  
  
   \alpha_k=\sum_{i=1}^m v_{ik}x_i
  
 
αk​=∑i=1m​vik​xi​,如果我们记

 
  
   
    
     α
    
    
     =
    
    
     
      
       [
      
      
       
        
         
          
           
            α
           
           
            1
           
          
         
        
       
       
        
         
          
           
            α
           
           
            2
           
          
         
        
       
       
        
         
          
           ⋮
          
          
           
          
         
        
       
       
        
         
          
           
            α
           
           
            h
           
          
         
        
       
      
      
       ]
      
     
     
      
       h
      
      
       ×
      
      
       1
      
     
    
    
     ,
    
    
    
     V
    
    
     =
    
    
     
      
       [
      
      
       
        
         
          
           
            v
           
           
            11
           
          
         
        
        
         
          
           
            v
           
           
            21
           
          
         
        
        
         
          
           ⋯
          
         
        
        
         
          
           
            v
           
           
            
             m
            
            
             1
            
           
          
         
        
       
       
        
         
          
           
            v
           
           
            12
           
          
         
        
        
         
          
           
            v
           
           
            22
           
          
         
        
        
         
          
           ⋯
          
         
        
        
         
          
           
            v
           
           
            
             m
            
            
             2
            
           
          
         
        
       
       
        
         
          
           ⋮
          
          
           
          
         
        
        
         
          
           ⋮
          
          
           
          
         
        
        
         
          
         
        
        
         
          
           ⋮
          
          
           
          
         
        
       
       
        
         
          
           
            v
           
           
            
             1
            
            
             h
            
           
          
         
        
        
         
          
           
            v
           
           
            
             2
            
            
             h
            
           
          
         
        
        
         
          
           ⋯
          
         
        
        
         
          
           
            v
           
           
            
             m
            
            
             h
            
           
          
         
        
       
      
      
       ]
      
     
     
      
       h
      
      
       ×
      
      
       m
      
     
    
    
     ,
    
    
    
     x
    
    
     =
    
    
     
      
       [
      
      
       
        
         
          
           
            x
           
           
            1
           
          
         
        
       
       
        
         
          
           
            x
           
           
            2
           
          
         
        
       
       
        
         
          
           ⋮
          
          
           
          
         
        
       
       
        
         
          
           
            x
           
           
            m
           
          
         
        
       
      
      
       ]
      
     
     
      
       m
      
      
       ×
      
      
       1
      
     
    
   
   
     \boldsymbol{\alpha}= \begin{bmatrix} \alpha_1 \\ \alpha_2 \\ \vdots \\ \alpha_h \end{bmatrix}_{h\times 1}, \quad \boldsymbol{V}= \begin{bmatrix} v_{11} & v_{21} & \cdots & v_{m1} \\ v_{12} & v_{22} & \cdots & v_{m2} \\ \vdots & \vdots & & \vdots \\ v_{1h} & v_{2h} & \cdots & v_{mh} \\ \end{bmatrix}_{h\times m},\quad \boldsymbol{x}= \begin{bmatrix} x_1 \\ x_2 \\ \vdots \\ x_m \end{bmatrix}_{m\times 1} 
   
  
 α=⎣⎢⎢⎢⎡​α1​α2​⋮αh​​⎦⎥⎥⎥⎤​h×1​,V=⎣⎢⎢⎢⎡​v11​v12​⋮v1h​​v21​v22​⋮v2h​​⋯⋯⋯​vm1​vm2​⋮vmh​​⎦⎥⎥⎥⎤​h×m​,x=⎣⎢⎢⎢⎡​x1​x2​⋮xm​​⎦⎥⎥⎥⎤​m×1​

则有

     α
    
    
     =
    
    
     
      V
     
     
      x
     
    
   
   
     \boldsymbol{\alpha}=\boldsymbol{Vx} 
   
  
 α=Vx

再令

    b
   
   
    =
   
   
    (
   
   
    
     b
    
    
     1
    
   
   
    ,
   
   
    
     b
    
    
     2
    
   
   
    ,
   
   
    ⋯
    
   
    ,
   
   
    
     b
    
    
     h
    
   
   
    
     )
    
    
     T
    
   
   
    ,
    
   
    γ
   
   
    =
   
   
    (
   
   
    
     γ
    
    
     1
    
   
   
    ,
   
   
    
     γ
    
    
     2
    
   
   
    ,
   
   
    ⋯
    
   
    ,
   
   
    
     γ
    
    
     h
    
   
   
    
     )
    
    
     T
    
   
  
  
   \boldsymbol{b}=(b_1,b_2,\cdots,b_h)^{\mathrm T},\,\boldsymbol{\gamma}=(\gamma_1,\gamma_2,\cdots,\gamma_h)^{\mathrm T}
  
 
b=(b1​,b2​,⋯,bh​)T,γ=(γ1​,γ2​,⋯,γh​)T,从而 

 
  
   
    b
   
   
    =
   
   
    σ
   
   
    (
   
   
    α
   
   
    −
   
   
    γ
   
   
    )
   
   
    =
   
   
    σ
   
   
    (
   
   
    
     V
    
    
     x
    
   
   
    −
   
   
    γ
   
   
    )
   
  
  
   \boldsymbol{b}=\sigma(\boldsymbol \alpha-\boldsymbol{\gamma})=\sigma(\boldsymbol{Vx}-\boldsymbol{\gamma})
  
 
b=σ(α−γ)=σ(Vx−γ)。

同理可得,

     W
    
    
     
      n
     
     
      ×
     
     
      h
     
    
   
  
  
   \boldsymbol{W}_{n\times h}
  
 
Wn×h​ 为隐层和输出层之间的**权重矩阵**,且有

 
  
   
    
     β
    
    
     =
    
    
     W
    
    
     b
    
    
     ,
    
    
    
     
      y
     
     
      ^
     
    
    
     =
    
    
     σ
    
    
     (
    
    
     β
    
    
     −
    
    
     θ
    
    
     )
    
    
     =
    
    
     σ
    
    
     (
    
    
     W
    
    
     b
    
    
     −
    
    
     θ
    
    
     )
    
   
   
     \boldsymbol{\beta}=\boldsymbol{W}\boldsymbol{b},\quad \boldsymbol{\hat{y}}=\sigma(\boldsymbol{\beta}-\boldsymbol{\theta})=\sigma(\boldsymbol{W}\boldsymbol{b}-\boldsymbol{\theta}) 
   
  
 β=Wb,y^​=σ(β−θ)=σ(Wb−θ)

进一步有

     y
    
    
     ^
    
   
   
    =
   
   
    σ
   
   
    (
   
   
    W
   
   
    σ
   
   
    (
   
   
    
     V
    
    
     x
    
   
   
    −
   
   
    γ
   
   
    )
   
   
    −
   
   
    θ
   
   
    )
   
  
  
   \boldsymbol{\hat{y}}=\sigma(\boldsymbol{W}\sigma(\boldsymbol{Vx}-\boldsymbol{\gamma})-\boldsymbol{\theta})
  
 
y^​=σ(Wσ(Vx−γ)−θ)。

于是我们就得到了神经网络的输出。

1.2 反向传播

对于给定的训练样例

    (
   
   
    x
   
   
    ,
   
   
    y
   
   
    )
   
  
  
   (\boldsymbol{x},\boldsymbol{y})
  
 
(x,y),神经网络的输出为 

 
  
   
    
     y
    
    
     ^
    
   
   
    =
   
   
    σ
   
   
    (
   
   
    β
   
   
    −
   
   
    θ
   
   
    )
   
  
  
   \boldsymbol{\hat{y}}=\sigma(\boldsymbol{\beta}-\boldsymbol{\theta})
  
 
y^​=σ(β−θ),从而误差为

 
  
   
    
     E
    
    
     =
    
    
     ∥
    
    
     
      y
     
     
      ^
     
    
    
     −
    
    
     y
    
    
     
      ∥
     
     
      2
     
    
    
     =
    
    
     
      ∑
     
     
      
       j
      
      
       =
      
      
       1
      
     
     
      n
     
    
    
     (
    
    
     
      
       y
      
      
       ^
      
     
     
      j
     
    
    
     −
    
    
     
      y
     
     
      j
     
    
    
     
      )
     
     
      2
     
    
   
   
     E=\Vert \boldsymbol{\hat{y}}-\boldsymbol{y} \Vert^2=\sum_{j=1}^n(\hat{y}_j-y_j)^2 
   
  
 E=∥y^​−y∥2=j=1∑n​(y^​j​−yj​)2

为消掉求导后多出来的系数

    2
   
  
  
   2
  
 
2,我们做一个处理,即令

 
  
   
    
     E
    
    
     =
    
    
     
      1
     
     
      2
     
    
    
     
      ∑
     
     
      
       j
      
      
       =
      
      
       1
      
     
     
      n
     
    
    
     (
    
    
     
      
       y
      
      
       ^
      
     
     
      j
     
    
    
     −
    
    
     
      y
     
     
      j
     
    
    
     
      )
     
     
      2
     
    
   
   
     E=\frac12\sum_{j=1}^n(\hat{y}_j-y_j)^2 
   
  
 E=21​j=1∑n​(y^​j​−yj​)2

我们采用梯度下降策略来最小化误差,即

      w
     
     
      
       i
      
      
       j
      
     
    
    
     :
    
    
     =
    
    
     
      w
     
     
      
       i
      
      
       j
      
     
    
    
     −
    
    
     η
    
    
     
      
       ∂
      
      
       E
      
     
     
      
       ∂
      
      
       
        w
       
       
        
         i
        
        
         j
        
       
      
     
    
    
     ,
    
    
    
     
      θ
     
     
      j
     
    
    
     :
    
    
     =
    
    
     
      θ
     
     
      j
     
    
    
     −
    
    
     η
    
    
     
      
       ∂
      
      
       E
      
     
     
      
       ∂
      
      
       
        θ
       
       
        j
       
      
     
    
   
   
     w_{ij}:=w_{ij}-\eta\frac{\partial E}{\partial w_{ij}},\quad \theta_j:=\theta_j-\eta\frac{\partial E}{\partial \theta_j} 
   
  
 wij​:=wij​−η∂wij​∂E​,θj​:=θj​−η∂θj​∂E​

其中

          ∂
         
         
          E
         
        
        
         
          ∂
         
         
          
           w
          
          
           
            i
           
           
            j
           
          
         
        
       
      
     
     
      
       
        
        
         =
        
        
         
          
           
            ∂
           
           
            E
           
          
          
           
            ∂
           
           
            
             
              y
             
             
              ^
             
            
            
             j
            
           
          
         
        
        
         ⋅
        
        
         
          
           
            ∂
           
           
            
             
              y
             
             
              ^
             
            
            
             j
            
           
          
          
           
            ∂
           
           
            
             β
            
            
             j
            
           
          
         
        
        
         ⋅
        
        
         
          
           
            ∂
           
           
            
             β
            
            
             j
            
           
          
          
           
            ∂
           
           
            
             w
            
            
             
              i
             
             
              j
             
            
           
          
         
        
       
      
     
    
    
     
      
       
      
     
     
      
       
        
        
         =
        
        
         
          (
         
         
          
           
            y
           
           
            ^
           
          
          
           j
          
         
         
          −
         
         
          
           y
          
          
           j
          
         
         
          )
         
        
        
         ⋅
        
        
         
          
           σ
          
          
           ′
          
         
         
          (
         
         
          
           β
          
          
           j
          
         
         
          −
         
         
          
           θ
          
          
           j
          
         
         
          )
         
        
        
         ⋅
        
        
         
          
           b
          
          
           i
          
         
        
       
      
     
    
   
   
     \begin{aligned} \frac{\partial E}{\partial w_{ij}}&=\textcolor{red}{\frac{\partial E}{\partial \hat{y}_j}} \cdot \textcolor{blue}{\frac{\partial \hat{y}_j}{\partial \beta_j}} \cdot \textcolor{green}{\frac{\partial \beta_j}{\partial w_{ij}}}\\ &=\textcolor{red}{(\hat{y}_j-y_j)} \cdot \textcolor{blue}{\sigma'(\beta_j-\theta_j)}\cdot \textcolor{green}{b_i} \\ \end{aligned} 
   
  
 ∂wij​∂E​​=∂y^​j​∂E​⋅∂βj​∂y^​j​​⋅∂wij​∂βj​​=(y^​j​−yj​)⋅σ′(βj​−θj​)⋅bi​​

     g
    
    
     j
    
   
   
    =
   
   
    −
   
   
    
     (
    
    
     
      
       y
      
      
       ^
      
     
     
      j
     
    
    
     −
    
    
     
      y
     
     
      j
     
    
    
     )
    
   
   
    ⋅
   
   
    
     
      σ
     
     
      ′
     
    
    
     (
    
    
     
      β
     
     
      j
     
    
    
     −
    
    
     
      θ
     
     
      j
     
    
    
     )
    
   
  
  
   g_j =- \textcolor{red}{(\hat{y}_j-y_j)} \cdot \textcolor{blue}{\sigma'(\beta_j-\theta_j)}
  
 
gj​=−(y^​j​−yj​)⋅σ′(βj​−θj​),则可得知 

 
  
   
    Δ
   
   
    
     w
    
    
     
      i
     
     
      j
     
    
   
   
    =
   
   
    η
   
   
    
     g
    
    
     j
    
   
   
    
     b
    
    
     i
    
   
  
  
   \Delta w_{ij}=\eta g_jb_i
  
 
Δwij​=ηgj​bi​。另一方面

 
  
   
    
     
      
       
        
         
          ∂
         
         
          E
         
        
        
         
          ∂
         
         
          
           θ
          
          
           j
          
         
        
       
      
     
     
      
       
        
        
         =
        
        
         
          
           
            ∂
           
           
            E
           
          
          
           
            ∂
           
           
            
             
              y
             
             
              ^
             
            
            
             j
            
           
          
         
        
        
         ⋅
        
        
         
          
           
            ∂
           
           
            
             
              y
             
             
              ^
             
            
            
             j
            
           
          
          
           
            ∂
           
           
            
             θ
            
            
             j
            
           
          
         
        
       
      
     
    
    
     
      
       
      
     
     
      
       
        
        
         =
        
        
         
          (
         
         
          
           
            y
           
           
            ^
           
          
          
           j
          
         
         
          −
         
         
          
           y
          
          
           j
          
         
         
          )
         
        
        
         ⋅
        
        
         
          (
         
         
          −
         
         
          
           σ
          
          
           ′
          
         
         
          (
         
         
          
           β
          
          
           j
          
         
         
          −
         
         
          
           θ
          
          
           j
          
         
         
          )
         
         
          )
         
        
        
         =
        
        
         
          g
         
         
          j
         
        
       
      
     
    
   
   
     \begin{aligned} \frac{\partial E}{\partial \theta_j}&= \textcolor{red}{\frac{\partial E}{\partial \hat{y}_j}} \cdot \textcolor{blue}{\frac{\partial \hat{y}_j}{\partial \theta_j}} \\ &=\textcolor{red}{(\hat{y}_j-y_j)} \cdot \textcolor{blue}{(-\sigma'(\beta_j-\theta_j))}=g_j \end{aligned} 
   
  
 ∂θj​∂E​​=∂y^​j​∂E​⋅∂θj​∂y^​j​​=(y^​j​−yj​)⋅(−σ′(βj​−θj​))=gj​​

因此

    Δ
   
   
    
     θ
    
    
     j
    
   
   
    =
   
   
    −
   
   
    η
   
   
    
     g
    
    
     j
    
   
  
  
   \Delta \theta_j=-\eta g_j
  
 
Δθj​=−ηgj​。

    Δ
   
   
    W
   
   
    =
   
   
    η
   
   
    g
   
   
    
     b
    
    
     T
    
   
  
  
   \Delta\boldsymbol{W}=\eta \boldsymbol{g}\boldsymbol{b}^{\mathrm{T}}
  
 
ΔW=ηgbT,

 
  
   
    Δ
   
   
    θ
   
   
    =
   
   
    −
   
   
    η
   
   
    g
   
  
  
   \Delta \boldsymbol{\theta}=-\eta\boldsymbol{g}
  
 
Δθ=−ηg,于是得到权重与阈值的更新公式:

 
  
   
    
     W
    
    
     :
    
    
     =
    
    
     W
    
    
     +
    
    
     Δ
    
    
     W
    
    
     ,
    
    
    
     θ
    
    
     :
    
    
     =
    
    
     θ
    
    
     +
    
    
     Δ
    
    
     θ
    
   
   
     \boldsymbol{W}:=\boldsymbol{W}+\Delta\boldsymbol{W},\quad \boldsymbol{\theta}:= \boldsymbol{\theta}+ \Delta\boldsymbol{\theta} 
   
  
 W:=W+ΔW,θ:=θ+Δθ

此外,还有

      v
     
     
      
       i
      
      
       j
      
     
    
    
     :
    
    
     =
    
    
     
      v
     
     
      
       i
      
      
       j
      
     
    
    
     −
    
    
     η
    
    
     
      
       ∂
      
      
       E
      
     
     
      
       ∂
      
      
       
        v
       
       
        
         i
        
        
         j
        
       
      
     
    
    
     ,
    
    
    
     
      γ
     
     
      j
     
    
    
     :
    
    
     =
    
    
     
      γ
     
     
      j
     
    
    
     −
    
    
     η
    
    
     
      
       ∂
      
      
       E
      
     
     
      
       ∂
      
      
       
        γ
       
       
        j
       
      
     
    
   
   
     v_{ij}:=v_{ij}-\eta\frac{\partial E}{\partial v_{ij}},\quad \gamma_j:=\gamma_j-\eta\frac{\partial E}{\partial \gamma_j} 
   
  
 vij​:=vij​−η∂vij​∂E​,γj​:=γj​−η∂γj​∂E​

其中

          ∂
         
         
          E
         
        
        
         
          ∂
         
         
          
           v
          
          
           
            i
           
           
            j
           
          
         
        
       
      
     
     
      
       
        
        
         =
        
        
         
          ∑
         
         
          
           k
          
          
           =
          
          
           1
          
         
         
          n
         
        
        
         
          
           
            ∂
           
           
            E
           
          
          
           
            ∂
           
           
            
             
              y
             
             
              ^
             
            
            
             k
            
           
          
         
        
        
         ⋅
        
        
         
          
           
            ∂
           
           
            
             
              y
             
             
              ^
             
            
            
             k
            
           
          
          
           
            ∂
           
           
            
             β
            
            
             k
            
           
          
         
        
        
         ⋅
        
        
         
          
           
            ∂
           
           
            
             β
            
            
             k
            
           
          
          
           
            ∂
           
           
            
             b
            
            
             j
            
           
          
         
        
        
         ⋅
        
        
         
          
           
            ∂
           
           
            
             b
            
            
             j
            
           
          
          
           
            ∂
           
           
            
             α
            
            
             j
            
           
          
         
        
        
         ⋅
        
        
         
          
           
            ∂
           
           
            
             α
            
            
             j
            
           
          
          
           
            ∂
           
           
            
             v
            
            
             
              i
             
             
              j
             
            
           
          
         
        
       
      
     
    
    
     
      
       
      
     
     
      
       
        
        
         =
        
        
         
          ∑
         
         
          
           k
          
          
           =
          
          
           1
          
         
         
          n
         
        
        
         (
        
        
         −
        
        
         
          g
         
         
          k
         
        
        
         )
        
        
         ⋅
        
        
         
          
           w
          
          
           
            j
           
           
            k
           
          
         
        
        
         ⋅
        
        
         
          
           σ
          
          
           ′
          
         
         
          (
         
         
          
           α
          
          
           j
          
         
         
          −
         
         
          
           γ
          
          
           j
          
         
         
          )
         
        
        
         ⋅
        
        
         
          
           x
          
          
           i
          
         
        
       
      
     
    
   
   
     \begin{aligned} \frac{\partial E}{\partial v_{ij}}&=\sum_{k=1}^n \textcolor{red}{\frac{\partial E}{\partial \hat{y}_k}}\cdot \textcolor{blue}{\frac{\partial \hat{y}_k}{\partial \beta_k}}\cdot \textcolor{green}{\frac{\partial \beta_k}{\partial b_j}}\cdot \textcolor{magenta}{\frac{\partial b_j}{\partial\alpha_j}}\cdot \textcolor{orange}{\frac{\partial \alpha_j}{\partial v_{ij}}}\\ &=\sum_{k=1}^n (-g_k)\cdot \textcolor{green}{w_{jk}}\cdot \textcolor{magenta}{\sigma'(\alpha_j-\gamma_j)}\cdot \textcolor{orange}{x_i}\\ \end{aligned} 
   
  
 ∂vij​∂E​​=k=1∑n​∂y^​k​∂E​⋅∂βk​∂y^​k​​⋅∂bj​∂βk​​⋅∂αj​∂bj​​⋅∂vij​∂αj​​=k=1∑n​(−gk​)⋅wjk​⋅σ′(αj​−γj​)⋅xi​​

     e
    
    
     j
    
   
   
    =
   
   
    −
   
   
    
     ∑
    
    
     
      k
     
     
      =
     
     
      1
     
    
    
     n
    
   
   
    (
   
   
    −
   
   
    
     g
    
    
     k
    
   
   
    )
   
   
    ⋅
   
   
    
     
      w
     
     
      
       j
      
      
       k
      
     
    
   
   
    ⋅
   
   
    
     
      σ
     
     
      ′
     
    
    
     (
    
    
     
      α
     
     
      j
     
    
    
     −
    
    
     
      γ
     
     
      j
     
    
    
     )
    
   
  
  
   e_j=-\sum_{k=1}^n (-g_k)\cdot \textcolor{green}{w_{jk}}\cdot \textcolor{magenta}{\sigma'(\alpha_j-\gamma_j)}
  
 
ej​=−∑k=1n​(−gk​)⋅wjk​⋅σ′(αj​−γj​),则得到 

 
  
   
    Δ
   
   
    
     v
    
    
     
      i
     
     
      j
     
    
   
   
    =
   
   
    η
   
   
    
     e
    
    
     j
    
   
   
    
     x
    
    
     i
    
   
  
  
   \Delta v_{ij}=\eta e_jx_i
  
 
Δvij​=ηej​xi​。另一方面

 
  
   
    
     
      
       
        
         
          ∂
         
         
          E
         
        
        
         
          ∂
         
         
          
           γ
          
          
           j
          
         
        
       
      
     
     
      
       
        
        
         =
        
        
         
          ∑
         
         
          
           k
          
          
           =
          
          
           1
          
         
         
          n
         
        
        
         
          
           
            ∂
           
           
            E
           
          
          
           
            ∂
           
           
            
             
              y
             
             
              ^
             
            
            
             k
            
           
          
         
        
        
         ⋅
        
        
         
          
           
            ∂
           
           
            
             
              y
             
             
              ^
             
            
            
             k
            
           
          
          
           
            ∂
           
           
            
             β
            
            
             k
            
           
          
         
        
        
         ⋅
        
        
         
          
           
            ∂
           
           
            
             β
            
            
             k
            
           
          
          
           
            ∂
           
           
            
             b
            
            
             j
            
           
          
         
        
        
         ⋅
        
        
         
          
           
            ∂
           
           
            
             b
            
            
             j
            
           
          
          
           
            ∂
           
           
            
             γ
            
            
             j
            
           
          
         
        
       
      
     
    
    
     
      
       
      
     
     
      
       
        
        
         =
        
        
         
          ∑
         
         
          
           k
          
          
           =
          
          
           1
          
         
         
          n
         
        
        
         (
        
        
         −
        
        
         
          g
         
         
          k
         
        
        
         )
        
        
         ⋅
        
        
         
          
           w
          
          
           
            j
           
           
            k
           
          
         
        
        
         ⋅
        
        
         
          (
         
         
          −
         
         
          
           σ
          
          
           ′
          
         
         
          (
         
         
          
           α
          
          
           j
          
         
         
          −
         
         
          
           γ
          
          
           j
          
         
         
          )
         
         
          )
         
        
        
         =
        
        
         
          e
         
         
          j
         
        
       
      
     
    
   
   
     \begin{aligned} \frac{\partial E}{\partial \gamma_j}&=\sum_{k=1}^n \textcolor{red}{\frac{\partial E}{\partial \hat{y}_k}}\cdot \textcolor{blue}{\frac{\partial \hat{y}_k}{\partial \beta_k}}\cdot \textcolor{green}{\frac{\partial \beta_k}{\partial b_j}}\cdot \textcolor{magenta}{\frac{\partial b_j}{\partial\gamma_j}}\\ &=\sum_{k=1}^n (-g_k)\cdot \textcolor{green}{w_{jk}}\cdot \textcolor{magenta}{(-\sigma'(\alpha_j-\gamma_j))}=e_j \\ \end{aligned} 
   
  
 ∂γj​∂E​​=k=1∑n​∂y^​k​∂E​⋅∂βk​∂y^​k​​⋅∂bj​∂βk​​⋅∂γj​∂bj​​=k=1∑n​(−gk​)⋅wjk​⋅(−σ′(αj​−γj​))=ej​​

因此

    Δ
   
   
    
     γ
    
    
     j
    
   
   
    =
   
   
    −
   
   
    η
   
   
    
     e
    
    
     j
    
   
  
  
   \Delta \gamma_j=-\eta e_j
  
 
Δγj​=−ηej​。

    Δ
   
   
    V
   
   
    =
   
   
    η
   
   
    e
   
   
    
     x
    
    
     T
    
   
  
  
   \Delta\boldsymbol{V}=\eta \boldsymbol{e}\boldsymbol{x}^{\mathrm{T}}
  
 
ΔV=ηexT,

 
  
   
    Δ
   
   
    γ
   
   
    =
   
   
    −
   
   
    η
   
   
    e
   
  
  
   \Delta \boldsymbol{\gamma}=-\eta\boldsymbol{e}
  
 
Δγ=−ηe,于是得到权重与阈值的更新公式:

 
  
   
    
     V
    
    
     :
    
    
     =
    
    
     V
    
    
     +
    
    
     Δ
    
    
     V
    
    
     ,
    
    
    
     γ
    
    
     :
    
    
     =
    
    
     γ
    
    
     +
    
    
     Δ
    
    
     γ
    
   
   
     \boldsymbol{V}:=\boldsymbol{V}+\Delta\boldsymbol{V},\quad \boldsymbol{\gamma}:= \boldsymbol{\gamma}+ \Delta\boldsymbol{\gamma} 
   
  
 V:=V+ΔV,γ:=γ+Δγ

二、实现部分

2.1 算法伪码

两个梯度项可以表示成:

        g
       
      
     
     
      
       
        
        
         =
        
        
         (
        
        
         y
        
        
         −
        
        
         
          y
         
         
          ^
         
        
        
         )
          
        
         ∗
          
        
         
          σ
         
         
          ′
         
        
        
         (
        
        
         β
        
        
         −
        
        
         θ
        
        
         )
        
       
      
     
    
    
     
      
       
        e
       
      
     
     
      
       
        
        
         =
        
        
         
          W
         
         
          T
         
        
        
         g
          
        
         ∗
          
        
         
          σ
         
         
          ′
         
        
        
         (
        
        
         α
        
        
         −
        
        
         γ
        
        
         )
        
       
      
     
    
   
   
     \begin{aligned} \boldsymbol{g}&=(\boldsymbol{y}-\boldsymbol{\hat{y}}) \;*\; \sigma'(\boldsymbol{\beta}-\boldsymbol{\theta}) \\ \boldsymbol{e}&=\boldsymbol{W}^{\mathrm T}\boldsymbol{g}\;*\;\sigma'(\boldsymbol{\alpha}-\boldsymbol{\gamma})\\ \end{aligned} 
   
  
 ge​=(y−y^​)∗σ′(β−θ)=WTg∗σ′(α−γ)​

其中

    ∗
   
  
  
   *
  
 
∗ 代表**按元素**运算。基于此,我们可以写出算法伪码:

          输入
         
         
          :训练集 
         
         
          
           D
          
         
         
          ,学习率 
         
         
          
           η
          
         
        
       
      
     
    
    
     
      
       
      
     
     
      
       
        
        
         过程:
        
       
      
     
    
    
     
      
       
      
     
     
      
       
        
        
         
          1. 随机初始化 
         
         
          
           
            V
           
           
            ,
           
           
            W
           
           
            ,
           
           
            γ
           
           
            ,
           
           
            θ
           
          
         
        
       
      
     
    
    
     
      
       
      
     
     
      
       
        
        
         
          2. 
         
         
          
           
            r
           
           
            e
           
           
            p
           
           
            e
           
           
            a
           
           
            t
           
          
         
        
       
      
     
    
    
     
      
       
      
     
     
      
       
        
        
         
          3. 
         
         
            
         
         
           
         
         
          
           
            f
           
           
            o
           
           
            r
             
           
            a
           
           
            l
           
           
            l
             
          
         
         
           
         
         
           ⁣
          
           (
          
          
           x
          
          
           ,
          
          
           y
          
          
           )
          
          
           ∈
          
          
           D
          
         
         
           
         
         
          
            
           
            d
           
           
            o
           
          
         
        
       
      
     
    
    
     
      
       
      
     
     
      
       
        
        
         
          4. 
         
         
          
                
         
         
           计算输入和输出 
         
         
          
           
            α
           
           
            ,
           
           
            b
           
           
            ,
           
           
            β
           
           
            ,
           
           
            
             y
            
            
             ^
            
           
          
         
         
          ; 
         
        
       
      
     
    
    
     
      
       
      
     
     
      
       
        
        
         
          5. 
         
         
          
                
         
         
           计算梯度项 
         
         
          
           
            g
           
           
            ,
           
           
            e
           
          
         
         
          ; 
         
        
       
      
     
    
    
     
      
       
      
     
     
      
       
        
        
         
          6. 
         
         
          
                
         
         
           计算改变量 
         
         
          
           
            Δ
           
           
            W
           
           
            ,
           
           
            Δ
           
           
            θ
           
           
            ,
           
           
            Δ
           
           
            V
           
           
            ,
           
           
            Δ
           
           
            γ
           
          
         
         
          ; 
         
        
       
      
     
    
    
     
      
       
      
     
     
      
       
        
        
         
          7. 
         
         
          
                
         
         
           更新 
         
         
          
           
            W
           
           
            ,
           
           
            θ
           
           
            ,
           
           
            V
           
           
            ,
           
           
            γ
           
          
         
         
          ; 
         
        
       
      
     
    
    
     
      
       
      
     
     
      
       
        
        
         
          8. 
         
         
            
         
         
           
         
         
          
           
            e
           
           
            n
           
           
            d
             
           
            f
           
           
            o
           
           
            r
           
          
         
        
       
      
     
    
    
     
      
       
      
     
     
      
       
        
        
         
          9. 
         
         
          
           
            u
           
           
            n
           
           
            t
           
           
            i
           
           
            l
           
           
         
         
           
         
         
          
           E
          
          
           <
          
          
           ϵ
           
         
         
           或迭代次数达到某个值
         
        
       
      
     
    
    
     
      
       
      
     
     
      
       
        
        
         
          输出
         
         
          :训练好的神经网络
         
        
       
      
     
    
   
   
     \begin{aligned} &\text{{\bf 输入}:训练集 $D$,学习率 $\eta$} \\ &\text{\bf 过程:} \\ &\text{1. 随机初始化 $\boldsymbol{V, W, \gamma, \theta}$} \\ &\text{2. $\mathrm{\bf repeat}$} \\ &\text{3. $\quad\;$ $\mathrm{\bf for\; all\;}$ $\!(\boldsymbol{x},\boldsymbol{y})\in D$ $\mathrm{\bf \,do}$} \\ &\text{4. $\quad\quad\;\;\;$ 计算输入和输出 $\boldsymbol{\alpha, b, \beta, \hat{y}}$; } \\ &\text{5. $\quad\quad\;\;\;$ 计算梯度项 $\boldsymbol{g, e}$; } \\ &\text{6. $\quad\quad\;\;\;$ 计算改变量 $\boldsymbol{\Delta W,\Delta \theta, \Delta V,\Delta \gamma}$; } \\ &\text{7. $\quad\quad\;\;\;$ 更新 $\boldsymbol{W, \theta, V,\gamma}$; } \\ &\text{8. $\quad\;$ $\mathrm{\bf end\;for}$} \\ &\text{9. $\mathrm{\bf until}\,$ $E<\epsilon\,$ 或迭代次数达到某个值} \\ &\text{{\bf 输出}:训练好的神经网络} \\ \end{aligned} 
   
  
 ​输入:训练集 D,学习率 η过程:1. 随机初始化 V,W,γ,θ2. repeat3.  forall (x,y)∈D do4.  计算输入和输出 α,b,β,y^​; 5.  计算梯度项 g,e; 6.  计算改变量 ΔW,Δθ,ΔV,Δγ; 7.  更新 W,θ,V,γ; 8.  endfor9. until E<ϵ 或迭代次数达到某个值输出:训练好的神经网络​

有了矩阵和向量化的表述,我们的单隐层神经网络可以简洁地表示成如下形式,这种形式也方便我们后续的编程。

在这里插入图片描述

假设我们的激活函数采用 Sigmoid 函数,利用它的性质:

     σ
    
    
     ′
    
   
   
    (
   
   
    x
   
   
    )
   
   
    =
   
   
    σ
   
   
    (
   
   
    x
   
   
    )
     
   
    ∗
     
   
    (
   
   
    1
   
   
    −
   
   
    σ
   
   
    (
   
   
    x
   
   
    )
   
   
    )
   
  
  
   \sigma'(\boldsymbol{x})=\sigma(\boldsymbol{x})\;*\;(\boldsymbol{1}-\sigma(\boldsymbol{x}))
  
 
σ′(x)=σ(x)∗(1−σ(x)),我们的两个梯度项变为:

 
  
   
    
     
      
       
        g
       
      
     
     
      
       
        
        
         =
        
        
         (
        
        
         y
        
        
         −
        
        
         
          y
         
         
          ^
         
        
        
         )
          
        
         ∗
          
        
         
          y
         
         
          ^
         
          
        
         ∗
          
        
         (
        
        
         1
        
        
         −
        
        
         
          y
         
         
          ^
         
        
        
         )
        
       
      
     
    
    
     
      
       
        e
       
      
     
     
      
       
        
        
         =
        
        
         
          W
         
         
          T
         
        
        
         g
          
        
         ∗
          
        
         b
          
        
         ∗
          
        
         (
        
        
         1
        
        
         −
        
        
         b
        
        
         )
        
       
      
     
    
   
   
     \begin{aligned} \boldsymbol{g}&=(\boldsymbol{y}-\boldsymbol{\hat{y}}) \;*\; \boldsymbol{\hat{y}}\;*\;(\boldsymbol{1}-\boldsymbol{\hat{y}}) \\ \boldsymbol{e}&=\boldsymbol{W}^{\mathrm T}\boldsymbol{g}\;*\;\boldsymbol{b}\;*\;(\boldsymbol{1}-\boldsymbol{b})\\ \end{aligned} 
   
  
 ge​=(y−y^​)∗y^​∗(1−y^​)=WTg∗b∗(1−b)​

2.2 算法实现

2.2.1 初始化

首先我们需要创建一个神经网络类:

import numpy as np

classNeuralNetwork:def__init__(self):pass

那我们应该初始化哪些参数呢?输入层结点数

    m
   
  
  
   m
  
 
m,隐层结点数 

 
  
   
    h
   
  
  
   h
  
 
h 和输出层结点数 

 
  
   
    n
   
  
  
   n
  
 
n 都是必须初始化的,它们决定了神经网络的结构。此外,根据算法伪码,我们还应该初始化 

 
  
   
    η
   
   
    ,
   
   
    W
   
   
    ,
   
   
    V
   
   
    ,
   
   
    θ
   
   
    ,
   
   
    γ
   
  
  
   \eta, \boldsymbol{W},\boldsymbol{V},\boldsymbol{\theta},\boldsymbol{\gamma}
  
 
η,W,V,θ,γ。

注意到

    η
   
   
    ,
   
   
    m
   
   
    ,
   
   
    n
   
   
    ,
   
   
    h
   
  
  
   \eta,m,n,h
  
 
η,m,n,h 是必须人工输入的,而权重矩阵和阈值向量则由后面三个参数决定。

当然,容忍度

tol

和 最大迭代次数

max_iter

也需要人工输入,这两个参数决定了我们的神经网络何时停止训练。

def__init__(
        self,
        learningrate,
        inputnodes,
        hiddennodes,
        outputnodes,
        tol,
        max_iter
    ):# 学习率
        self.lr = learningrate
        # 输入层结点数
        self.ins = inputnodes
        # 隐层结点数
        self.hns = hiddennodes
        # 输出层结点数
        self.ons = outputnodes
        # 容忍度
        self.tol = tol
        # 最大迭代次数
        self.max_iter = max_iter

权重矩阵和阈值向量在

    (
   
   
    0
   
   
    ,
   
   
    1
   
   
    )
   
  
  
   (0,1)
  
 
(0,1) 范围内初始化:
# 权重矩阵和阈值向量
self.V = np.random.rand(self.hns, self.ins)
self.W = np.random.rand(self.ons, self.hns)
self.gamma = np.random.rand(self.hns)
self.theta = np.random.rand(self.ons)

当然别忘了还有激活函数,我们采用匿名函数的形式:

# Sigmoid
self.sigmoid =lambda x:1/(1+ np.power(np.e,-x))

到此为止,我们的

__init__

函数算是完成了:

def__init__(
        self, 
        learningrate, 
        inputnodes,
        hiddennodes, 
        outputnodes, 
        tol, 
        max_iter
    ):
    self.lr = learningrate
    self.ins, self.hns, self.ons = inputnodes, hiddennodes, outputnodes
    self.tol = tol
    self.max_iter = max_iter

    self.V = np.random.rand(self.hns, self.ins)
    self.W = np.random.rand(self.ons, self.hns)
    self.gamma = np.random.rand(self.hns)
    self.theta = np.random.rand(self.ons)

    self.sigmoid =lambda x:1/(1+ np.power(np.e,-x))

2.2.2 正向传播

我们需要定义一个正向传播函数用来计算

    α
   
   
    ,
   
   
    b
   
   
    ,
   
   
    β
   
   
    ,
   
   
    
     y
    
    
     ^
    
   
  
  
   \boldsymbol{\alpha},\boldsymbol{b},\boldsymbol{\beta},\boldsymbol{\hat{y}}
  
 
α,b,β,y^​,该函数需要一个样本 

 
  
   
    (
   
   
    x
   
   
    ,
   
   
    y
   
   
    )
   
  
  
   (\boldsymbol{x},\boldsymbol{y})
  
 
(x,y) 作为输入,我们用 
(inputs, targets)

来表示,输出

     y
    
    
     ^
    
   
  
  
   \boldsymbol{\hat{y}}
  
 
y^​ 用 
outputs

来表示。

当然,我们还需要计算误差

    E
   
  
  
   E
  
 
E,用 
error

来表示。

defpropagate(self, inputs, targets):# 计算输入和输出
    alpha = np.dot(self.V, inputs)
    b = self.sigmoid(alpha - self.gamma)
    beta = np.dot(self.W, b)
    outputs = self.sigmoid(beta - self.theta)# 计算误差
    error = np.linalg.norm(targets - outputs,ord=2)**2/2return alpha, b, beta, outputs, error

2.2.3 反向传播

反向传播需要先计算两个梯度项

    g
   
   
    ,
   
   
    e
   
  
  
   \boldsymbol{g},\boldsymbol{e}
  
 
g,e,然后再进行参数更新:

 
  
   
    
     W
    
    
     :
    
    
     =
    
    
     W
    
    
     +
    
    
     η
    
    
     g
    
    
     
      b
     
     
      T
     
    
    
     ,
    
    
    
     θ
    
    
     :
    
    
     =
    
    
     θ
    
    
     +
    
    
     −
    
    
     η
    
    
     g
    
    
    
     V
    
    
     :
    
    
     =
    
    
     V
    
    
     +
    
    
     η
    
    
     e
    
    
     
      x
     
     
      T
     
    
    
     ,
    
    
    
     γ
    
    
     :
    
    
     =
    
    
     γ
    
    
     +
    
    
     −
    
    
     η
    
    
     e
    
    
   
   
     \boldsymbol{W}:=\boldsymbol{W}+\eta \boldsymbol{g}\boldsymbol{b}^{\mathrm{T}},\quad \boldsymbol{\theta}:= \boldsymbol{\theta}+ -\eta \boldsymbol{g}\\ \boldsymbol{V}:=\boldsymbol{V}+\eta \boldsymbol{e}\boldsymbol{x}^{\mathrm{T}},\quad \boldsymbol{\gamma}:= \boldsymbol{\gamma}+ -\eta\boldsymbol{e} \\ 
   
  
 W:=W+ηgbT,θ:=θ+−ηgV:=V+ηexT,γ:=γ+−ηe

可以看出我们的函数需要用到这些参数:

    x
   
   
    ,
   
   
    y
   
   
    ,
   
   
    α
   
   
    ,
   
   
    b
   
   
    ,
   
   
    β
   
   
    ,
   
   
    
     y
    
    
     ^
    
   
  
  
   \boldsymbol{x},\boldsymbol{y},\boldsymbol{\alpha},\boldsymbol{b},\boldsymbol{\beta},\boldsymbol{\hat{y}}
  
 
x,y,α,b,β,y^​。
defback_propagate(self, inputs, targets, alpha, b, beta, outputs):# 计算两个梯度项
    g =(targets - outputs)* outputs *(np.ones(len(outputs))- outputs)
    e = np.dot(self.W.T, g)* b *(np.ones(len(b))- b)# 更新参数
    self.W += self.lr * np.outer(g, b)
    self.theta +=-self.lr * g
    self.V += self.lr * np.outer(e, inputs)
    self.gamma +=-self.lr * e

2.2.3 训练

训练需要传入数据集,假设数据集的表示形式为

    X
   
   
    ,
   
   
    y
   
  
  
   X,y
  
 
X,y(不知道该记号的读者可参考我的这一篇文章)。

我们需要对传入的数据集做一些处理。在遍历数据集时,

X[i]

是向量,即

inputs

y[i]

是向量对应的标签,它仅仅是一个数,而非像

targets

这样的向量。

那么如何将

y[i]

处理成

targets

呢?

考虑像手写数字识别这样的十分类任务,对应的神经网络的输出层有十个神经元,每个神经元对应着一个数字。例如,当我们输入一张

    5
   
  
  
   5
  
 
5 的图片时,

 
  
   
    5
   
  
  
   5
  
 
5 对应的神经元的输出值应该是最高的,其他神经元的输出值应该是最低的。

因为激活函数是Sigmoid函数,它的输出区间为

    (
   
   
    0
   
   
    ,
   
   
    1
   
   
    )
   
  
  
   (0,1)
  
 
(0,1)。我们将输出层神经元按照其对应的数字从小到大进行排列,从而输出层的情况应当**十分接近**下面这个样子:

 
  
   
    
     [
    
    
     0
    
    
     ,
    
    
     0
    
    
     ,
    
    
     0
    
    
     ,
    
    
     0
    
    
     ,
    
    
     0
    
    
     ,
    
    
     1
    
    
     ,
    
    
     0
    
    
     ,
    
    
     0
    
    
     ,
    
    
     0
    
    
     ,
    
    
     0
    
    
     ]
    
   
   
     [0,0,0,0,0,1,0,0,0,0] 
   
  
 [0,0,0,0,0,1,0,0,0,0]
y

中包含了所有向量的标签,若要判断我们面临的问题是一个几分类问题,我们需要对

y

进行去重,再将结果从小到大进行排序:

self.classes = np.unique(y)

例如,

y = [2, 0, 0, 1, 0, 1, 0, 2, 2]

,则

self.classes = [0, 1, 2]

。即

self.classes

按序存储了所有的标签种类

获得

targets

的步骤如下:

首先创建全为

    0
   
  
  
   0
  
 
0 的数组,即
targets = np.zeros(len(self.classes))

然后我们要获取

inputs

的标签在

self.classes

中的索引,即

index =list(self.classes).index(y[i])

然后再赋值

targets[index]=1

上述过程可以统一为两步:

targets = np.zeros(len(self.classes))
targets[list(self.classes).index(y[i])]=1

我们前面提到,训练停止当且仅当下面两个条件满足其中一个:

  • 迭代收敛,即 E < ϵ E<\epsilon E<ϵ;
  • 迭代次数达到最大值,即训练了 max_iter 次。

如果第一个条件先达到,则我们立刻停止训练;如果第二个条件先达到,说明我们训练了

max_iter

次也没有收敛,此时应当抛出一个错误。

deftrain(self, X, y):# 初始时未收敛
    convergence =False
    self.classes = np.unique(y)# 开始迭代 max_iter 次for _ inrange(self.max_iter):# 遍历数据集for idx inrange(len(X)):
            inputs, targets = X[idx], np.zeros(len(self.classes))
            targets[list(self.classes).index(y[idx])]=1# 正向计算
            alpha, b, beta, outputs, error = self.propagate(inputs, targets)# 若误差不超过容忍度,则判定收敛if error <= self.tol:
                convergence =Truebreakelse:# 反向传播
                self.back_propagate(inputs, targets, alpha, b, beta, outputs)if convergence:breakifnot convergence:raise RuntimeError('神经网络的训练未收敛,请调大max_iter的值')

2.2.4 预测

训练好的神经网络理应能对单个样本完成分类,我们选择

outputs

输出最高的神经元对应的类别标签作为我们对样本的预测标签:

defpredict(self, sample):

    alpha = np.dot(self.V, sample)
    b = self.sigmoid(alpha - self.gamma)
    beta = np.dot(self.W, b)
    outputs = self.sigmoid(beta - self.theta)# 计算输出最高的神经元在outputs中的索引
    idx =list(outputs).index(max(outputs))
    label = self.classes[idx]return label

2.2.5 完善网络

到此为止,我们的神经网络就已经完成

    99
   
   
    %
   
  
  
   99\%
  
 
99% 了,但还有一些细节要处理。
  • 我们希望神经网络能够根据数据集自动调整输入层结点数和输出层结点数。
  • 一些参数可以预先设置好,例如学习率,容忍度等。
  • 我们需要进行一些数据预处理,即将 X X X 归一化。

对于前两个,我们需要修改

__init__()

,如下:

def__init__(self, X, y, hiddennodes, learningrate=0.01, tol=1e-3, max_iter=1000):

    self.X, self.y = X, y
    
    self.classes = np.unique(self.y)
    self.ins, self.hns, self.ons =len(X[0]), hiddennodes,len(self.classes)
    self.lr = learningrate
    self.tol = tol
    self.max_iter = max_iter

    self.V = np.random.rand(self.hns, self.ins)
    self.W = np.random.rand(self.ons, self.hns)
    self.gamma = np.random.rand(self.hns)
    self.theta = np.random.rand(self.ons)

    self.sigmoid =lambda x:1/(1+ np.power(np.e,-x))

同时还需要修改一下

train()

deftrain(self):

    convergence =Falsefor _ inrange(self.max_iter):for idx inrange(len(self.X)):
            inputs, targets = self.X[idx], np.zeros(self.ons)
            targets[list(self.classes).index(self.y[idx])]=1
            alpha, b, beta, outputs, error = self.propagate(inputs, targets)if error <= self.tol:
                convergence =Truebreakelse:
                self.back_propagate(inputs, targets, alpha, b, beta, outputs)if convergence:breakifnot convergence:raise RuntimeError('神经网络的训练未收敛,请调大max_iter的值')

对于第三个,我们希望将

    X
   
  
  
   X
  
 
X 归一化,但又不希望 

 
  
   
    X
   
  
  
   X
  
 
X 中有太多的 

 
  
   
    0
   
  
  
   0
  
 
0,否则会造成权重更新失败,因此需要作变换:

 
  
   
    
     X
    
    
     :
    
    
     =
    
    
     
      (
     
     
      
       
        X
       
       
        −
       
       
        min
       
       
        ⁡
       
       
        (
       
       
        X
       
       
        )
       
      
      
       
        max
       
       
        ⁡
       
       
        (
       
       
        X
       
       
        )
       
       
        −
       
       
        min
       
       
        ⁡
       
       
        (
       
       
        X
       
       
        )
       
      
     
     
      )
     
    
    
     ⋅
    
    
     0.99
    
    
     +
    
    
     0.01
    
   
   
     X:=\left(\frac{X-\min(X)}{\max(X)-\min(X)}\right)\cdot 0.99 +0.01 
   
  
 X:=(max(X)−min(X)X−min(X)​)⋅0.99+0.01

该变换能将

    X
   
  
  
   X
  
 
X 中的元素映射到 

 
  
   
    [
   
   
    0.01
   
   
    ,
   
   
    1
   
   
    ]
   
  
  
   [0.01,1]
  
 
[0.01,1] 中。

该步骤需要在数据集传入到神经网络实例之前完成。


完整的单隐层神经网络代码如下:

import numpy as np

classNeuralNetwork:def__init__(self, X, y, hiddennodes, learningrate=0.01, tol=1e-3, max_iter=1000):

        self.X, self.y = X, y

        self.classes = np.unique(self.y)
        self.ins, self.hns, self.ons =len(X[0]), hiddennodes,len(self.classes)
        self.lr = learningrate
        self.tol = tol
        self.max_iter = max_iter

        self.V = np.random.rand(self.hns, self.ins)
        self.W = np.random.rand(self.ons, self.hns)
        self.gamma = np.random.rand(self.hns)
        self.theta = np.random.rand(self.ons)

        self.sigmoid =lambda x:1/(1+ np.power(np.e,-x))defpropagate(self, inputs, targets):

        alpha = np.dot(self.V, inputs)
        b = self.sigmoid(alpha - self.gamma)
        beta = np.dot(self.W, b)
        outputs = self.sigmoid(beta - self.theta)

        error = np.linalg.norm(targets - outputs,ord=2)**2/2return alpha, b, beta, outputs, error

    defback_propagate(self, inputs, targets, alpha, b, beta, outputs):

        g =(targets - outputs)* outputs *(np.ones(len(outputs))- outputs)
        e = np.dot(self.W.T, g)* b *(np.ones(len(b))- b)

        self.W += self.lr * np.outer(g, b)
        self.theta +=-self.lr * g
        self.V += self.lr * np.outer(e, inputs)
        self.gamma +=-self.lr * e

    deftrain(self):

        convergence =Falsefor _ inrange(self.max_iter):for idx inrange(len(self.X)):
                inputs, targets = self.X[idx], np.zeros(self.ons)
                targets[list(self.classes).index(self.y[idx])]=1
                alpha, b, beta, outputs, error = self.propagate(inputs, targets)if error <= self.tol:
                    convergence =Truebreakelse:
                    self.back_propagate(inputs, targets, alpha, b, beta, outputs)if convergence:breakifnot convergence:raise RuntimeError('神经网络的训练未收敛,请调大max_iter的值')defpredict(self, sample):

        alpha = np.dot(self.V, sample)
        b = self.sigmoid(alpha - self.gamma)
        beta = np.dot(self.W, b)
        outputs = self.sigmoid(beta - self.theta)return self.classes[list(outputs).index(max(outputs))]

我们将其保存到

nn.py

中。

三、实战演练

本章节中,我们使用

sklearn

中的鸢尾花数据集来训练并测试神经网络。

另起一个新的

.py

文件,首先需要导入:

from nn import NeuralNetwork # 导入我们的神经网络from sklearn.model_selection import train_test_split # 划分训练集和测试集from sklearn.metrics import accuracy_score # 计算准确率from sklearn.datasets import load_iris # 鸢尾花数据集import numpy as np

先做数据预处理:

X, y = load_iris(return_X_y=True)
X =((X - X.min())/(X.max()- X.min()))*0.99+0.01
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

创建一个神经网络实例,将隐藏层结点数设为 10,然后进行训练:

bpnn = NeuralNetwork(X_train, y_train,10, max_iter=3000)# max_iter过小会导致不收敛
bpnn.train()

定义一个测试函数用来测试神经网络在测试集上的分类准确率:

deftest(bpnn, X_test, y_test):
    y_pred =[bpnn.predict(X_test[i])for i inrange(len(X_test))]return accuracy_score(y_test, y_pred)print(test(bpnn, X_test, y_test))# 1.0

可见训练完成的神经网络在测试集上的分类准确率达

    100
   
   
    %
   
  
  
   100\%
  
 
100%。

完整的训练/测试代码如下:

from nn import NeuralNetwork
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
from sklearn.datasets import load_iris
import numpy as np

deftest(bpnn, X_test, y_test):
    y_pred =[bpnn.predict(X_test[i])for i inrange(len(X_test))]return accuracy_score(y_test, y_pred)

X, y = load_iris(return_X_y=True)
X =((X - X.min())/(X.max()- X.min()))*0.99+0.01
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

bpnn = NeuralNetwork(X_train, y_train,10, max_iter=3000)
bpnn.train()print(test(bpnn, X_test, y_test))

本文转载自: https://blog.csdn.net/weixin_44022472/article/details/123315557
版权归原作者 serity 所有, 如有侵权,请联系我们删除。

“手把手教你用numpy搭建一个单隐层神经网络”的评论:

还没有评论