Commit 48fb75dd authored by Cianciosa, Mark's avatar Cianciosa, Mark
Browse files

Add C and Fortran Bindings.

parent 55a9a787
Loading
Loading
Loading
Loading
+34 −11
Original line number Diff line number Diff line
cmake_minimum_required (VERSION 3.21)

project (ml_model_embeder CXX)
project (ml_model_embedder CXX)

#-------------------------------------------------------------------------------
#  Build Options
#-------------------------------------------------------------------------------
option (USE_PCH "Enable the use of precompiled headers" ON)
option (BUILD_C_BINDING "Build C interface." OFF)
option (BUILD_Fortran_BINDING "Build Fortran interface." OFF)

#-------------------------------------------------------------------------------
#  Setup access method.
@@ -26,8 +28,8 @@ if (NOT CMAKE_BUILD_TYPE)
    set (CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build." FORCE)
endif ()
set_property (CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
              Debug
              Release
              Debug
              MinSizeRel
              RelWithDebInfo
)
@@ -92,20 +94,45 @@ add_dependencies (zip pull_zip)

add_subdirectory (source)

if (${BUILD_Fortran_BINDING})
    set (BUILD_C_BINDING ON CACHE STRING "Build C interface." FORCE)
endif ()

if (${BUILD_C_BINDING})
    enable_language (C)
    add_subdirectory (c_binding)
endif ()

if (${BUILD_Fortran_BINDING})
    enable_language (Fortran)
    add_subdirectory (fortran_binding)
endif ()

#-------------------------------------------------------------------------------
#  Tool setup
#-------------------------------------------------------------------------------
macro (add_tool_target target)
macro (add_tool_target target lang)
    add_executable (x${target})
    target_sources (x${target}
                    PRIVATE
                    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/${target}.cpp>
                    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/${target}.${lang}>
    )

    target_link_libraries (x${target}
                           PUBLIC
                           ml_embeder
                           ml_embedder
    )

    if (${lang} STREQUAL "c")
        set_source_files_properties (${CMAKE_CURRENT_SOURCE_DIR}/${target}.${lang}
                                     PROPERTIES
                                     SKIP_PRECOMPILE_HEADERS ON
        )
    endif ()

    if (${USE_PCH} AND ${BUILD_C_BINDING})
        target_precompile_headers (x${target} REUSE_FROM ml_c_embedder)
    endif ()
endmacro ()

#-------------------------------------------------------------------------------
@@ -116,16 +143,12 @@ enable_testing ()
#-------------------------------------------------------------------------------
#  Define macro function to register tests.
#-------------------------------------------------------------------------------
macro (add_test_target target)
    add_tool_target (${target})
macro (add_test_target target lang)
    add_tool_target (${target} ${lang})

    add_test (NAME ${target}
              COMMAND x${target}
    )

#    if (${USE_PCH})
#        target_precompile_headers (x${target} REUSE_FROM xml_embeder_test)
#    endif ()
endmacro ()

add_subdirectory (tests)
+17 −8
Original line number Diff line number Diff line
# ml_model_embeder
# ml_model_embedder

This is a beginnings of a library to load machine learning models into a C++ 
library which can be called from C, C++ and Fortran codes. Currently, this only
@@ -18,14 +18,14 @@ retrived except for HDF5.

The build system is generated using [cmake](https://cmake.org). To build the 
code first clone the 
[ml_model_embeder](https://code.ornl.gov/m4c/ml_model_embeder.git) repository.
[ml_model_embedder](https://code.ornl.gov/m4c/ml_model_embedder.git) repository.
```
git clone https://code.ornl.gov/m4c/ml_model_embeder.git
git clone https://code.ornl.gov/m4c/ml_model_embedder.git
```
The change into the directory git generated and create a build directory then 
navigate to the build directory.
```
cd ml_model_embeder
cd ml_model_embedder
mkdir build
cd build
```
@@ -36,16 +36,25 @@ cmake ../
make -j
```

Alternatively you can use the `ccmake` command to interactively set build 
parameters.

###  Build Paramaters

`CMAKE_BUILD_TYPE` Chooses the build type. Values are
- `Release`        Optimized builds (Default)
- `Debug`          Build without optimiation and debug info.
- `MinSizeRel`     Optimize for executable size.
- `RelWithDebInfo` Optimized build with debug info.


##
There is an example case which can be run from inside the build directory using
the command
```
./tests/xml_embeder_test
./tests/xml_embedder_test
```

# Todo:

- Clean up code into function to build models.
- Build C Bindings.
- Build Fortran Bindings.
- Setup unit tests.
+18 −0
Original line number Diff line number Diff line
add_library (ml_c_embedder)

target_include_directories (ml_c_embedder
                            PUBLIC
                            $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
)
target_link_libraries (ml_c_embedder
                       PUBLIC
                       ml_embedder
)
target_sources (ml_c_embedder
                PRIVATE
                $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/ml_c_embedder.cpp>
)
target_compile_features (ml_c_embedder
                         PUBLIC
                         c_std_17
)
+77 −0
Original line number Diff line number Diff line
//------------------------------------------------------------------------------
///  @file ml_c_embedder.h
///  @brief Implimentation of the c binding library.
//------------------------------------------------------------------------------

#include "ml_c_embedder.h"
#include <ml_embedder.hpp>

//------------------------------------------------------------------------------
///  @@brief Initialize a keras model.
///
///  @param[in] filename Path to the keras model.
//------------------------------------------------------------------------------
ml_model mlce_init_keras(const char *filename) {
    return reinterpret_cast<ml_model> (new ml_embedder::keras(std::string(filename)));
}

//------------------------------------------------------------------------------
///  @brief Finalize a model.
///
///  @param[in] m The model model instance.
//------------------------------------------------------------------------------
void mlce_finalize(ml_model m) {
    delete reinterpret_cast<ml_embedder::model *> (m);
}

//------------------------------------------------------------------------------
///  @brief Get a the input shape.
///
///  @param[in]  m The model model instance.
///  @param[out] s The number of elements in the shape.
///  @returns The input shape array.
//------------------------------------------------------------------------------
int *mlce_in_shape(ml_model m, size_t *s) {
    ml_embedder::model *model = reinterpret_cast<ml_embedder::model *> (m);
    s[0] = model->input_shape.size();
    return reinterpret_cast<int *> (model->input_shape.data());
}

//------------------------------------------------------------------------------
///  @brief Get a the output shape.
///
///  @param[in]  m The model model instance.
///  @param[out] s The number of elements in the shape.
///  @returns The output shape array.
//------------------------------------------------------------------------------
int *mlce_out_shape(ml_model m, size_t *s) {
    ml_embedder::model *model = reinterpret_cast<ml_embedder::model *> (m);
    s[0] = model->input_shape.size();
    return reinterpret_cast<int *> (model->output_shape.data());
}

//------------------------------------------------------------------------------
///  @brief Run a model.
///
///  @note The user is require to allocate an output buffer of the correct size.
///
///  @param[in] m          The model model instance.
///  @param[in] in         The input buffer.
///  @param[in] out        The output buffer.
///  @param[in] batch_size The size of a batch.
///  @param[in] input_size The size of a batch.
//------------------------------------------------------------------------------
void mlce_run_float(ml_model m, void *in, void *out, const int batch_size) {
    ml_embedder::model *model = reinterpret_cast<ml_embedder::model *> (m);

    mlx::core::SmallVector<int> shape;
    shape.push_back(batch_size);
    for (auto i : model->input_shape) {
        shape.push_back(i);
    }

    mlx::core::array input = mlx::core::array((float *)in, shape, mlx::core::float32);
    mlx::core::array y = model->func({input})[0];
    y.eval();
    std::memcpy(out, y.data<float> (), y.nbytes());
}
+69 −0
Original line number Diff line number Diff line
//------------------------------------------------------------------------------
///  @file ml_c_embedder.h
///  @brief Header file for the c binding library.
//------------------------------------------------------------------------------

#ifndef ml_c_embedder_h
#define ml_c_embedder_h

#ifndef __cplusplus
#include <stddef.h>
#endif

#ifdef __cplusplus
extern "C" {
#endif

///  ml_model type for C interface.
    typedef void *ml_model;

//------------------------------------------------------------------------------
///  @brief Initialize a keras model.
///
///  @param[in] filename Path to the keras model.
//------------------------------------------------------------------------------
    ml_model mlce_init_keras(const char *filename);

//------------------------------------------------------------------------------
///  @brief Finalize a model.
///
///  @param[in] m The model model instance.
//------------------------------------------------------------------------------
    void mlce_finalize(ml_model m);

//------------------------------------------------------------------------------
///  @brief Get a the input shape.
///
///  @param[in]  m The model model instance.
///  @param[out] s The number of elements in the shape.
///  @returns The input shape array.
//------------------------------------------------------------------------------
    int *mlce_in_shape(ml_model m, size_t *s);

//------------------------------------------------------------------------------
///  @brief Get a the output shape.
///
///  @param[in]  m The model model instance.
///  @param[out] s The number of elements in the shape.
///  @returns The output shape array.
//------------------------------------------------------------------------------
    int *mlce_out_shape(ml_model m, size_t *s);

//------------------------------------------------------------------------------
///  @brief Run a model with float inputs.
///
///  @note The user is required to allocate an output buffer of the correct
///        size.
///
///  @param[in] m          The model model instance.
///  @param[in] in         The input buffer.
///  @param[in] out        The output buffer.
///  @param[in] batch_size The size of a batch.
//------------------------------------------------------------------------------
    void mlce_run_float(ml_model m, void *in, void *out, const int batch_size);

#ifdef __cplusplus
}
#endif

#endif /* ml_c_embedder_h */
Loading