人工智能学习之路

多层神经网络,从零开始——(六)、激活函数

2018-07-12  本文已影响0人  忆霜晨

维基百科上总结了各种激活函数列表如下,详细表格参见维基百科的词条 Activation function。其中,较为常用的激活函数是ReLU。

BaseActivationFunction 是一个抽象类,定义了激活函数的函数值和导数值。由于个别激活函数例如 softmax 需要整层的信息,因此计算函数值的时候需要传入数组,而不是单个变量。

最后的代码给出了激活函数 softmax 的实现,softmax 实现的时候,需要注意的是,要防止指数计算的时候发生溢出,防止溢出只需要计算的时候减去输入数组的最大值即可。(我们知道双精度浮点数上限是 1.7x10308,也就是说 Ex,当 x > 163.44 的时候就会发生溢出。)

module mod_BaseActivationFunction
implicit none
    
!-------------------
! 抽象类:激活函数 |
!-------------------
type, abstract, public :: BaseActivationFunction

!||||||||||||    
contains   !|
!||||||||||||

    !* 激活函数
    procedure(abs_f), deferred, public :: f 
    !* 接收向量参数的激活函数
    procedure(abs_f_vect), deferred, public :: f_vect 
    !* 激活函数导数
    procedure(abs_df), deferred, public :: df 
    !* 接收向量参数的激活函数导数
    procedure(abs_df_vect), deferred, public :: df_vect  

end type BaseActivationFunction
!===================
    

!-------------------
! 抽象类:函数接口 |
!-------------------    
abstract interface 

    !* 注:对于Sigmoid等激活函数,其是单变量函数,
    !* 而对于softmax函数来说,它的输入是一个向量,
    !* 是多变量函数,因此函数应接收向量 x.

    !* 激活函数
    subroutine abs_f( this, index, x, y )
    use mod_Precision
    import :: BaseActivationFunction
    implicit none
        class(BaseActivationFunction), intent(inout) :: this
        !* index 表示返回 f( x(index) ) 的值
        integer, intent(in) :: index
        real(PRECISION), dimension(:), intent(in) :: x
        real(PRECISION), intent(out) :: y
        
        
    end subroutine
    !====
    
    !* 接收向量参数的激活函数
    subroutine abs_f_vect( this, x, y )
    use mod_Precision
    import :: BaseActivationFunction
    implicit none
        class(BaseActivationFunction), intent(inout) :: this
        real(PRECISION), dimension(:), intent(in) :: x
        real(PRECISION), dimension(:), intent(out) :: y
        
    end subroutine
    !====
    
    !* 激活函数一阶导数
    subroutine abs_df( this, index, x, dy  )
    use mod_Precision
    import :: BaseActivationFunction
    implicit none
        class(BaseActivationFunction), intent(inout) :: this
        !* index 表示返回 f'( x(index) ) 的值
        integer, intent(in) :: index
        real(PRECISION), dimension(:), intent(in) :: x
        real(PRECISION), intent(out) :: dy

    end subroutine
    !====
    
    !* 接收向量参数的激活函数一阶导数
    subroutine abs_df_vect( this, x, dy )
    use mod_Precision
    import :: BaseActivationFunction
    implicit none
        class(BaseActivationFunction), intent(inout) :: this
        real(PRECISION), dimension(:), intent(in) :: x
        real(PRECISION), dimension(:), intent(out) :: dy

    end subroutine
    !====

end interface
!===================
    
end module
module mod_Softmax
use mod_Precision
use mod_BaseActivationFunction
implicit none    

!-------------------
! 工作类:激活函数 |
!-------------------
type, extends(BaseActivationFunction), public :: Softmax
    !* 继承自BaseActivationFunction并实现其接口

!||||||||||||    
contains   !|
!||||||||||||

    procedure, public :: f       => m_fun_Softmax
    procedure, public :: f_vect  => m_fun_Softmax_vect 
    procedure, public :: df      => m_df_Softmax
    procedure, public :: df_vect => m_df_Softmax_vect

end type Softmax
!===================

    !-------------------------
    private :: m_fun_Softmax
    private :: m_df_Softmax
    private :: m_fun_Softmax_vect
    private :: m_df_Softmax_vect
    !-------------------------
    
!||||||||||||    
contains   !|
!||||||||||||

    !* Softmax函数
    subroutine m_fun_Softmax( this, index, x, y )
    implicit none
        class(Softmax), intent(inout) :: this
        integer, intent(in) :: index
        real(PRECISION), dimension(:), intent(in) :: x
        real(PRECISION), intent(out) :: y
    
        real(PRECISION), dimension(:), allocatable :: x_c
        real(PRECISION) :: sum_exp_x, max_x
    
        allocate( x_c, SOURCE=x )
    
        max_x = MAXVAL(x_c)
        x_c = x_c - max_x
    
        sum_exp_x = SUM(EXP(x_c))
        y = EXP(x_c(index)) / sum_exp_x 
        
        deallocate( x_c )
    
        return
    end subroutine
    !====
    
    !* 接收向量输入的Softmax函数
    subroutine m_fun_Softmax_vect( this, x, y )
    implicit none
        class(Softmax), intent(inout) :: this
        real(PRECISION), dimension(:), intent(in) :: x
        real(PRECISION), dimension(:), intent(out) :: y 
    
        real(PRECISION), dimension(:), allocatable :: x_c
        real(PRECISION) :: sum_exp_x, max_x
    
        allocate( x_c, SOURCE=x )
    
        max_x = MAXVAL(x_c)
        x_c = x_c - max_x
    
        sum_exp_x = SUM(EXP(x_c))
        y = EXP(x_c) / sum_exp_x 
        
        deallocate( x_c )
        
        return
    end subroutine
    !====
    
    !* Softmax函数的一阶导数
    subroutine m_df_Softmax( this, index, x, dy  )
    implicit none
        class(Softmax), intent(inout) :: this
        integer, intent(in) :: index
        real(PRECISION), dimension(:), intent(in) :: x
        real(PRECISION), intent(out) :: dy
    
        real(PRECISION) :: y, sum_exp_x
    
        sum_exp_x = SUM(EXP(x))
        y = EXP(x(index)) / sum_exp_x 
    
        dy = y * (1 - y)
    
        return
    end subroutine
    !====
    
    !* 接收向量输入的Softmax函数的一阶导数
    subroutine m_df_Softmax_vect( this, x, dy )
    implicit none
        class(Softmax), intent(inout) :: this
        real(PRECISION), dimension(:), intent(in) :: x
        real(PRECISION), dimension(:), intent(out) :: dy
    
        real(PRECISION) :: sum_exp_x
        real(PRECISION), dimension(:), allocatable :: y
    
        allocate(y, SOURCE=x)
    
        sum_exp_x = SUM(EXP(x))
        y = EXP(x) / sum_exp_x 
    
        dy = y * (1 - y)
    
        deallocate(y)
    
        return
    end subroutine
    !====

end module

附录

多层神经网络,从零开始——(一)、Fortran读取MNIST数据集
多层神经网络,从零开始——(二)、Fortran随机生成“双月”分类问题数据
多层神经网络,从零开始——(三)、BP神经网络公式的详细推导
多层神经网络,从零开始——(四)、多层BP神经网络的矩阵形式
多层神经网络,从零开始——(五)、定义数据结构
多层神经网络,从零开始——(六)、激活函数
多层神经网络,从零开始——(七)、损失函数
多层神经网络,从零开始——(八)、分类问题中为什么使用交叉熵作为损失函数
多层神经网络,从零开始——(九)、优化函数
多层神经网络,从零开始——(十)、参数初始化
多层神经网络,从零开始——(十一)、实现训练类
多层神经网络,从零开始——(十二)、实现算例类
多层神经网络,从零开始——(十三)、关于并行计算的简单探讨

上一篇 下一篇

猜你喜欢

热点阅读