美文网首页人工智能学习之路
多层神经网络,从零开始——(五)、定义数据结构

多层神经网络,从零开始——(五)、定义数据结构

作者: 忆霜晨 | 来源:发表于2018-07-12 23:48 被阅读0次

    一、 一层的数据结构

    多层神经网络结构的示意图如上图所示,首先需要定义每一层的数据。每一层中的权值、阈值是需要保存的信息,因此各自单独定义了一个结构体 Layer_WeightLayer_Threshold

    每一层中还包含了其他信息有:

    • S:每一层的输入;
    • R:每一层激活函数的输入 ;
    • Z:每一层的输出 ;
    • d_Matrix_part:上篇博客中公式(26)-(31)中向量 eiT后面的部分;
    • dW:损失函数对权值的导数;
    • avg_dW:所有样本损失函数对权值的导数的平均;
    • dTheta:损失函数对阈值的导数
    • avg_dTheta:所有样本损失函数对阈值的导数的平均;
    • act_fun:每一层对应的激活函数,这里的激活函数 BaseActivationFunction 是一个抽象类,因为激活函数常用的有许多种,比如:sigmoid、tanh、ReLU等等。
    !* 该模块定义了神经网络各层用到的数组结构,
    !* 具体的参数意义参见PDF文档。
    module mod_NNParameter
    use mod_Precision
    use mod_BaseActivationFunction
    implicit none
        !---------------------------------------------------------
        ! 层与层之间的权重
        !---------------------------------------------------------
        type :: Layer_Weight
            !* 注意:W连接两层的结点数目分别为 M,N
            !*       则W为 N×M 的矩阵.
            real(kind=PRECISION), dimension(:,:), allocatable :: W    
        end type
        !=========================================================
    
        
        
        !---------------------------------------------------------
        ! 层的阈值
        !---------------------------------------------------------
        type :: Layer_Threshold
            !* 数组的大小是该阈值对应层的节点数目
            real(kind=PRECISION), dimension(:), allocatable :: Theta     
        end type
        !=========================================================
    
        
        
        !---------------------------------------------------------
        ! 层中用到的局部数组:输入、输出等
        !---------------------------------------------------------
        type :: Layer_Local_Array
            !* 数组的大小是该阈值对应层的节点数目
            !* S是输入数组,R=S-theta,Z是输出数组,Z=f(R)=f(S-Theta)
            real(kind=PRECISION), dimension(:), allocatable :: S
            real(kind=PRECISION), dimension(:), allocatable :: R
            real(kind=PRECISION), dimension(:), allocatable :: Z
            
            !* (Gamma^{k+1} W^{k+1})^T ... (Gamma^{n} W^{n}) p_zeta/p_zn
            real(kind=PRECISION), dimension(:), allocatable :: d_Matrix_part
            
            !* 以下zeta表示误差函数。
            !* zeta对W的导数
            !* 数组行、列大小分别是该权重W连接的两层的节点数目
            real(kind=PRECISION), dimension(:,:), allocatable :: dW
            
            !* 所有样本zeta对W的导数的求平均
            real(kind=PRECISION), dimension(:,:), allocatable :: avg_dW
            
            !* zeta对Theta的导数
            !* 数组的大小是该阈值对应层的节点数目
            real(kind=PRECISION), dimension(:), allocatable :: dTheta   
            
            !* 所有样本zeta对Theta的导数的求平均
            real(kind=PRECISION), dimension(:), allocatable :: avg_dTheta  
            
            !* 激活函数
            !* 注:BaseActivationFunction 是抽象类,不能使用动态数组.
            class(BaseActivationFunction), pointer :: act_fun
        end type 
        !=========================================================
        
        
        !* W、Theta 数组也可以统一放到 Layer_Local_Array 结构体中,
        !* 这里单独放置是为了应对未来代码可能的修改。
        
    end module
    

    二、多层神经网络结构

    使用指针数组即可构造出整个神经网络的结构,需要增加的一些数据为:

    • X:为神经网络的输入;
    • t:为神经网络的目标输出;
    • loss_function:为损失函数,这里的 BaseLossFunction 是一个抽象类,因为损失函数需要根据具体的需求定义,常用的损失函数有MSE、交叉熵等。

    另外最重要的是需要将神经网络的前向计算,以及反向误差计算等方法实现。

    !* 该模块定义了神经网络结构,以及神经网络结构相应的运算,
    !* 如:前向传播计算各层值、反向传播计算误差导数等。
    !* 具体的参数、函数意义参见PDF文档。
    module mod_NNStructure
    use mod_Precision
    use mod_NNParameter
    use mod_Log
    use mod_BaseActivationFunction
    use mod_BaseLossFunction
    implicit none
    
        !-------------------------
        ! 工作类:网络结构的数据 |
        !-------------------------
        type, public :: NNStructure
    
            ! 是否初始化完成的标识
            logical, private :: is_init_basic = .false.
            
            ! 是否初始化内存空间
            logical, private :: is_allocate_done = .false.
            
            ! 是否初始化权值矩阵、阈值
            logical, private :: is_init_weight = .false.
            logical, private :: is_init_threshold = .false.
            
            !* 是否初始化损失函数
            logical, private :: is_init_loss_fun = .false.
            
            ! 层的数目,不含输入层
            integer, public :: layers_count
        
            ! 每层节点数目构成的数组: 
            !     数组的大小是所有层的数目(含输入层)
            integer, dimension(:), allocatable, public :: layers_node_count
    
            ! 指向所有层权重的指针数组: 
            !     数组的大小是所有层的数目(不含输入层)  
            type (Layer_Weight), dimension(:), pointer, public :: pt_W
        
            ! 指向所有层阈值的指针数组: 
            !     数组的大小是所有层的数目(不含输入层)   
            type (Layer_Threshold), dimension(:), pointer, public :: pt_Theta
        
            ! 指向所有层局部数组结构的指针数组: 
            !     数组的大小是所有层的数目(不含输入层)   
            type (Layer_Local_Array), dimension(:), pointer, public :: pt_Layer
    
            ! 网络的目标输入
            real(PRECISION), dimension(:), allocatable, private :: X
            ! 网络的目标输出
            real(PRECISION), dimension(:), allocatable, private :: t
            
            !* 损失函数
            class(BaseLossFunction), pointer, private :: loss_function
            
        !||||||||||||    
        contains   !|
        !||||||||||||
    
            !* 初始化:
            !* (1). 给定网络基本结构、申请内存空间;
            !* (2). 随机初始化权值、阈值.
            procedure, public :: init_basic            => m_init_basic
            
            !* 是否初始化
            procedure, public :: get_init_basic_status => c_is_init_basic
            !* 前向计算,根据输入值,计算神经网络各层的值,
            !* 并返回预测值
            !* Tips:需要初始化结构、设置各层激活函数.       
            procedure, public :: forward_propagation  => m_forward_propagation
            !* 反向计算,计算误差函数对神经网络各层的导数
            !* Tips:需要初始化结构、设置各层激活函数、设置损失函数.
            procedure, public :: backward_propagation => m_backward_propagation
            
            !* 计算参数的平均梯度
            !* 完成一次m_backward_propagation计算后调用
            procedure, public :: calc_average_gradient     => m_calc_avg_gradient
            !* 将平均梯度置 0
            procedure, public :: set_average_gradient_zero => m_set_average_gradient_zero
            !* 设置损失函数
            procedure, public :: set_loss_function             => m_set_loss_function
            !* 设置指定层的激活函数
            procedure, public :: set_activation_function_layer => m_set_act_fun_layer   
            
            !* 计算所有求导变量的值 
            procedure, private :: get_all_derivative_variable => m_get_all_derivative_variable                
           
            !* 设置输入层
            procedure, private :: set_input_layer  => m_set_input_layer
            !* 设置输出层
            procedure, private :: set_output_layer => m_set_output_layer
            !* 随机初始化阈值,默认初始化到(-1,1)
            !* 在Train方法中,可以重新设置初始化.
            procedure, private :: init_layer_weight    => m_init_layer_weight
            !* 随机初始化阈值,默认初始化到(-1,1)
            !* 在Train方法中,可以重新设置初始化.
            procedure, private :: init_layer_threshold => m_init_layer_threshold
    
            !* 计算所有层中的局部变量 S、R、Z:
            !*      激活函数、输入层、W、Theta已随机初始化
            procedure, private :: get_all_layer_local_var => m_get_all_layer_local_var 
            !* 计算所有的d_Matrix_part:
            !*      目标输出层已初始化. 
            procedure, private :: get_all_d_Matrix_part   => m_get_all_d_Matrix_part
            
            !* 计算目标层的dW
            procedure, private :: get_layer_dW => m_get_layer_dW
            !* 计算所有的dW
            procedure, private :: get_all_dW   => m_get_all_dW
            
            !* 计算目标层的 dTheta
            procedure, private :: get_layer_dTheta => m_get_layer_dTheta
            !* 计算所有的 dTheta
            procedure, private :: get_all_dTheta   => m_get_all_dTheta
            !* 输出网络结构信息到日志
            procedure, private :: print_NN_Structrue => m_print_NN_Structrue
            !* 申请NNStructure包含的指针所需空间
            procedure, private :: allocate_pointer   => m_allocate_pointer
            !* 申请每层所需的内存空间
            procedure, private :: allocate_memory    => m_allocate_memory
            !* 销毁指针 
            procedure, private :: deallocate_pointer => m_deallocate_pointer
            !* 销毁内存空间
            procedure, private :: deallocate_memory  => m_deallocate_memory
    
            !* 析构函数,清理内存空间
            final :: NNStructure_clean_space
    
        end type NNStructure
        !--------------------------------------------------------
    
        
        !-------------------------
        !* 略... ...
        !-------------------------
    
    !||||||||||||    
    contains   !|
    !||||||||||||
    
        !* 具体实现略...
         
    end module
    

    附录

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

    相关文章

      网友评论

        本文标题:多层神经网络,从零开始——(五)、定义数据结构

        本文链接:https://www.haomeiwen.com/subject/wuhcpftx.html