build_from_onnx Module Subroutine

module subroutine build_from_onnx(this, nodes, initialisers, inputs, value_info, verbose)

Uses

    • coreutils

Build network from ONNX nodes and initialisers

Arguments

Type IntentOptional Attributes Name
class(network_type), intent(inout) :: this

Instance of network

type(onnx_node_type), intent(in), dimension(:) :: nodes

Array of ONNX nodes

type(onnx_initialiser_type), intent(in), dimension(:) :: initialisers

Array of ONNX initialisers

type(onnx_tensor_type), intent(in), dimension(:) :: inputs

Array of ONNX inputs

type(onnx_tensor_type), intent(in), dimension(:) :: value_info

Array of ONNX value infos

integer, intent(in), optional :: verbose

Verbosity level


Source Code

  module subroutine build_from_onnx( &
       this, nodes, initialisers, inputs, value_info, verbose &
  )
    !! Build network from ONNX nodes and initialisers
    use coreutils, only: to_lower
    implicit none

    ! Arguments
    class(network_type), intent(inout) :: this
    !! Instance of network
    type(onnx_node_type), dimension(:), intent(in) :: nodes
    !! Array of ONNX nodes
    type(onnx_initialiser_type), dimension(:), intent(in) :: initialisers
    !! Array of ONNX initialisers
    type(onnx_tensor_type), dimension(:), intent(in) :: inputs
    !! Array of ONNX inputs
    type(onnx_tensor_type), dimension(:), intent(in) :: value_info
    !! Array of ONNX value infos
    integer, optional, intent(in) :: verbose
    !! Verbosity level

    ! Local variables
    integer :: i, j, k, j_out, layer_index
    !! Loop indices
    integer :: verbose_ = 0
    !! Verbosity level
    character(20) :: op_type
    !! Lowercase op_type
    character(64) :: tmp_name
    !! Temporary name for matching
    character(256) :: err_msg
    !! Error message
    integer, dimension(:), allocatable :: input_shape
    !! Shape of input layer
    integer, dimension(:), allocatable :: input_list
    !! List of input layers
    type(onnx_initialiser_type), dimension(:), allocatable :: init_list
    !! List of initialisers for a specific node
    type(onnx_tensor_type), dimension(:), allocatable :: value_info_list
    !! List of value info tensors

    verbose_ = 0
    if(present(verbose)) verbose_ = verbose


    if(.not.allocated(list_of_onnx_layer_creators))then
       call allocate_list_of_onnx_layer_creators()
    end if

    do i = 1, size(inputs)
       input_shape = inputs(i)%dims(2:size(inputs(i)%dims))

       call this%add( &
            input_layer_type(input_shape, index=i) &
       )
    end do

    ! Loop through nodes and create layers
    do i = 1, size(nodes)
       if(verbose_.gt.0) write(*,*) "Processing ONNX node: ", trim(nodes(i)%name), &
            " (", trim(nodes(i)%op_type), ")"
       op_type = trim(adjustl(nodes(i)%op_type))

       layer_index = &
            findloc( &
                 [ list_of_onnx_layer_creators(:)%op_type ], &
                 op_type, &
                 dim = 1 &
            )
       if(layer_index.eq.0)then
          write(err_msg,'("unrecognised op_type ''",A)') trim(adjustl(nodes(i)%op_type))
          call stop_program(err_msg)
          return
       end if

       ! find all input layers and initialisers for this node
       ! ... i.e. check over inputs for name matches
       j_out = 0
       allocate(init_list(0))
       allocate(input_list(0))
       allocate(value_info_list(0))
       do j = 1, size(nodes(i)%inputs)
          do k = 1, size(initialisers)
             if(trim(nodes(i)%inputs(j)) .eq. trim(initialisers(k)%name))then
                init_list = [ init_list, initialisers(k) ]
             end if
          end do
          do k = 1, size(inputs)
             if(trim(nodes(i)%inputs(j)) .eq. trim(inputs(k)%name))then
                input_list = [ input_list, k ]
             end if
          end do
          tmp_name = trim(nodes(i)%inputs(j))
          if(index(tmp_name, "_output").gt.0) &
               tmp_name = trim(tmp_name(:index(tmp_name, "_output")-1))
          do k = 1, size(nodes)
             if(trim(tmp_name) .eq. trim(nodes(k)%name))then
                input_list = [ input_list, k + size(inputs) ]
             end if
          end do
       end do
       do j = 1, size(nodes(i)%outputs)
          do k = 1, size(value_info)
             if(trim(nodes(i)%outputs(j)) .eq. trim(value_info(k)%name))then
                value_info_list = [ value_info_list, value_info(k) ]
             end if
          end do
       end do
       if(size(init_list)+size(input_list).ne.size(nodes(i)%inputs))then
          if(verbose_.gt.0)then
             write(0,*) "WARNING: not all inputs found for node ", &
                  trim(nodes(i)%name)
          end if
       end if

       ! assume default operator

       call this%add( &
            list_of_onnx_layer_creators(layer_index)%create_ptr( &
                 nodes(i), init_list, value_info_list &
            ), &
            input_list = input_list &
            ! operator = operator_in &
       )
       deallocate(input_list)
       deallocate(init_list)
       deallocate(value_info_list)
    end do

    if(verbose_.gt.0) write(*,*) "ONNX model built with ", this%num_layers, " layers."

  end subroutine build_from_onnx