Skip to content

Commit

Permalink
[WIP] add coreml exporters
Browse files Browse the repository at this point in the history
  • Loading branch information
vigsterkr committed Feb 8, 2019
1 parent 229a008 commit d2c4fd2
Show file tree
Hide file tree
Showing 53 changed files with 1,684 additions and 64 deletions.
6 changes: 6 additions & 0 deletions .ci/ci.yml
Expand Up @@ -104,6 +104,12 @@ jobs:
CXX: "clang++"
cmakeOptions: '$(commonSWIGCMakeFlags) -DINTERFACE_RUBY=ON'
interfaceName: 'ruby'
coreml:
CC: "clang"
CXX: "clang++"
cmakeOptions: '$(commonSWIGCMakeFlags) -DINTERFACE_COREML=ON'
interfaceName: 'coreml'


variables:
testRunTitle: '$(build.sourceBranchName)-debian'
Expand Down
36 changes: 36 additions & 0 deletions cmake/ShogunUtils.cmake
Expand Up @@ -315,3 +315,39 @@ function(ADD_SHOGUN_BENCHMARK REL_BENCHMARK_NAME)
set_tests_properties(${BENCHMARK_NAME} PROPERTIES ${ARGN})
endif()
endfunction()

function(ADD_SHOGUN_UNITTEST)
set(options)
set(oneValueArgs TARGET)
set(multiValueArgs LABELS)
cmake_parse_arguments(ADD_SHOGUN_UNITTEST "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

if(NOT ENABLE_TESTING)
return()
endif()
get_filename_component(UNITTEST_NAME ${ADD_SHOGUN_UNITTEST_TARGET} NAME_WE)

if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${ADD_SHOGUN_UNITTEST_TARGET}.cc)
# This benchmark has a corresponding .cc file, set it up as an executable.
add_executable(${UNITTEST_NAME} "${ADD_SHOGUN_UNITTEST_TARGET}.cc")
set_target_properties (${UNITTEST_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set_target_properties (${UNITTEST_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR}/bin)
set_target_properties (${UNITTEST_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR}/bin)
target_link_libraries(${UNITTEST_NAME} ${SHOGUN_UNITTEST_LINK_LIBS})
add_dependencies(${UNITTEST_NAME} GoogleMock shogun::shogun)
target_include_directories(${UNITTEST_NAME} PRIVATE ${source_dir}/googlemock/include ${source_dir}/googletest/include)
set(NO_COLOR "--color_print=false")
endif()

add_test(${UNITTEST_NAME} ${CMAKE_BINARY_DIR}/bin/${UNITTEST_NAME} ${NO_COLOR})
if (ADD_SHOGUN_UNITTEST_LABELS)
set_tests_properties(${UNITTEST_NAME} PROPERTIES LABELS ${ADD_SHOGUN_UNITTEST_LABELS})
else ()
set_tests_properties(${UNITTEST_NAME} PROPERTIES LABELS "unit")
endif()

if(ARGN)
set_tests_properties(${UNITTEST_NAME} PROPERTIES ${ARGN})
endif()
endfunction()

84 changes: 43 additions & 41 deletions cmake/external/GoogleTestNMock.cmake
@@ -1,44 +1,46 @@
MergeCFLAGS()
include(ExternalProject)
IF (NOT TARGET GoogleMock)
MergeCFLAGS()
include(ExternalProject)

IF (MSVC)
SET (CUSTOM_CMAKE_ARGS -DCMAKE_ARCHIVE_OUTPUT_DIRECTORY:PATH=${THIRD_PARTY_DIR}/libs/gmock
-DCMAKE_LIBRARY_OUTPUT_DIRECTORY:PATH=${THIRD_PARTY_DIR}/libs/gmock
-DCMAKE_CXX_FLAGS:STRING=${CMAKE_CXX_FLAGS}${CMAKE_DEFINITIONS}
-DCMAKE_CXX_FLAGS_RELEASE:STRING=${CMAKE_CXX_FLAGS_RELEASE}
-DCMAKE_CXX_FLAGS_DISTRIBUTION:STRING=${CMAKE_CXX_FLAGS_DISTRIBUTION}
-DCMAKE_CXX_FLAGS_DEBUG:STRING=${CMAKE_CXX_FLAGS_DEBUG}
-DCMAKE_C_COMPILER:STRING=${CMAKE_C_COMPILER}
-DCMAKE_CXX_COMPILER:STRING=${CMAKE_CXX_COMPILER}
)
ELSE ()
SET(MERGED_CXX_FLAGS "${MERGED_CXX_FLAGS} -fPIC")
SET (CUSTOM_CMAKE_ARGS -DCMAKE_ARCHIVE_OUTPUT_DIRECTORY:PATH=${THIRD_PARTY_DIR}/libs/gmock
-DCMAKE_LIBRARY_OUTPUT_DIRECTORY:PATH=${THIRD_PARTY_DIR}/libs/gmock
-DCMAKE_CXX_FLAGS:STRING=${MERGED_CXX_FLAGS}${CMAKE_DEFINITIONS}
-DCMAKE_C_COMPILER:STRING=${CMAKE_C_COMPILER}
-DCMAKE_CXX_COMPILER:STRING=${CMAKE_CXX_COMPILER}
)
ENDIF()
IF (MSVC)
SET (CUSTOM_CMAKE_ARGS -DCMAKE_ARCHIVE_OUTPUT_DIRECTORY:PATH=${THIRD_PARTY_DIR}/libs/gmock
-DCMAKE_LIBRARY_OUTPUT_DIRECTORY:PATH=${THIRD_PARTY_DIR}/libs/gmock
-DCMAKE_CXX_FLAGS:STRING=${CMAKE_CXX_FLAGS}${CMAKE_DEFINITIONS}
-DCMAKE_CXX_FLAGS_RELEASE:STRING=${CMAKE_CXX_FLAGS_RELEASE}
-DCMAKE_CXX_FLAGS_DISTRIBUTION:STRING=${CMAKE_CXX_FLAGS_DISTRIBUTION}
-DCMAKE_CXX_FLAGS_DEBUG:STRING=${CMAKE_CXX_FLAGS_DEBUG}
-DCMAKE_C_COMPILER:STRING=${CMAKE_C_COMPILER}
-DCMAKE_CXX_COMPILER:STRING=${CMAKE_CXX_COMPILER}
)
ELSE ()
SET(MERGED_CXX_FLAGS "${MERGED_CXX_FLAGS} -fPIC")
SET (CUSTOM_CMAKE_ARGS -DCMAKE_ARCHIVE_OUTPUT_DIRECTORY:PATH=${THIRD_PARTY_DIR}/libs/gmock
-DCMAKE_LIBRARY_OUTPUT_DIRECTORY:PATH=${THIRD_PARTY_DIR}/libs/gmock
-DCMAKE_CXX_FLAGS:STRING=${MERGED_CXX_FLAGS}${CMAKE_DEFINITIONS}
-DCMAKE_C_COMPILER:STRING=${CMAKE_C_COMPILER}
-DCMAKE_CXX_COMPILER:STRING=${CMAKE_CXX_COMPILER}
)
ENDIF()

IF(EXISTS /usr/src/googletest)
ExternalProject_Add(
GoogleMock
DOWNLOAD_COMMAND ""
SOURCE_DIR /usr/src/googletest
PREFIX ${CMAKE_BINARY_DIR}/GoogleMock
INSTALL_COMMAND ""
CMAKE_ARGS ${CUSTOM_CMAKE_ARGS}
)
ELSE()
ExternalProject_Add(
GoogleMock
URL https://github.com/google/googletest/archive/release-1.8.1.tar.gz
URL_MD5 2e6fbeb6a91310a16efe181886c59596
TIMEOUT 10
PREFIX ${CMAKE_BINARY_DIR}/GoogleMock
DOWNLOAD_DIR ${THIRD_PARTY_DIR}/GoogleMock
INSTALL_COMMAND ""
CMAKE_ARGS ${CUSTOM_CMAKE_ARGS}
)
IF(EXISTS /usr/src/googletest)
ExternalProject_Add(
GoogleMock
DOWNLOAD_COMMAND ""
SOURCE_DIR /usr/src/googletest
PREFIX ${CMAKE_BINARY_DIR}/GoogleMock
INSTALL_COMMAND ""
CMAKE_ARGS ${CUSTOM_CMAKE_ARGS}
)
ELSE()
ExternalProject_Add(
GoogleMock
URL https://github.com/google/googletest/archive/release-1.8.1.tar.gz
URL_MD5 2e6fbeb6a91310a16efe181886c59596
TIMEOUT 10
PREFIX ${CMAKE_BINARY_DIR}/GoogleMock
DOWNLOAD_DIR ${THIRD_PARTY_DIR}/GoogleMock
INSTALL_COMMAND ""
CMAKE_ARGS ${CUSTOM_CMAKE_ARGS}
)
ENDIF()
ENDIF()
79 changes: 56 additions & 23 deletions src/interfaces/coreml/CMakeLists.txt
@@ -1,23 +1,56 @@
IF (PROTOBUF_FOUND AND ENABLE_PROTOBUF)
FILE(GLOB COREML_SRC "${CMAKE_CURRENT_SOURCE_DIR}/*.proto")
FILE(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
FOREACH (SRC_FILE ${COREML_SRC})
GET_FILENAME_COMPONENT(SRC_FILE_WE ${SRC_FILE} NAME_WE)
SET(COMPILED_SRC "${CMAKE_CURRENT_BINARY_DIR}/coreml/${SRC_FILE_WE}")
SET(COMPILED_SRC_H "${COMPILED_SRC}.pb.h")
SET(COMPILED_SRC_CPP "${COMPILED_SRC}.pb.cpp")
ADD_CUSTOM_COMMAND(
OUTPUT "${COMPILED_SRC_H}" "${COMPILED_SRC_CPP}"
COMMAND "${PROTOBUF_PROTOC_EXECUTABLE}"
"${SRC_FILE}"
--cpp_out "${CMAKE_CURRENT_BINARY_DIR}"
--proto_path "${CMAKE_CURRENT_SOURCE_DIR}"
COMMENT "Compiling CoreML Protobuf for ${SRC_FILE_WE}"
)
SET(PROTO_TARGET_NAME "CoreML_${SRC_FILE_WE}")
ADD_CUSTOM_TARGET("${PROTO_TARGET_NAME}" DEPENDS "${COMPILED_SRC_H}" "${COMPILED_SRC_CPP}")
ADD_DEPENDENCIES(libshogun "${PROTO_TARGET_NAME}")
ENDFOREACH()
ELSE()
MESSAGE(FATAL_ERROR "Protobuf is required for CoreML")
ENDIF()
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(shogun_coreml_version 0.1.0)

add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/format")

set(HEADER_FILES ShogunCoreML.h CoreMLModel.h)
add_library(shogun-coreml SHARED
CoreMLModel.cc
internal/CoreMLConverter.cc
internal/GLMRegressorConverter.cc
internal/GLMClassifierConverter.cc
internal/KernelConverter.cc
internal/SVMClassifierConverter.cc
internal/SVMRegressorConverter.cc)
set_property(TARGET shogun-coreml PROPERTY POSITION_INDEPENDENT_CODE ON)
set_target_properties(
shogun-coreml
PROPERTIES
SOVERSION 0
VERSION "${shogun_coreml_version}"
PUBLIC_HEADER "${HEADER_FILES}"
ARCHIVE_OUTPUT_DIRECTORY "lib"
LIBRARY_OUTPUT_DIRECTORY "lib"
)
target_link_libraries(shogun-coreml PUBLIC shogun::shogun ${Protobuf_LITE_LIBRARIES})
target_link_libraries(shogun-coreml PRIVATE coreml)
target_include_directories(shogun-coreml PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>
$<INSTALL_INTERFACE:include/shogun-coreml>
)
add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/internal")

set(SHOGUN_COREML_LIB_INSTALL lib)
file(TO_CMAKE_PATH ${SHOGUN_COREML_LIB_INSTALL}/cmake/shogun-coreml CONFIG_PACKAGE_DIR)

install(
TARGETS shogun-coreml
EXPORT ShogunCoreMLTarget
ARCHIVE DESTINATION ${SHOGUN_COREML_LIB_INSTALL}
RUNTIME DESTINATION ${SHOGUN_COREML_LIB_INSTALL}
LIBRARY DESTINATION ${SHOGUN_COREML_LIB_INSTALL}
INCLUDES DESTINATION include/shogun-coreml
PUBLIC_HEADER DESTINATION include/shogun-coreml
)

export(EXPORT ShogunCoreMLTarget
FILE "${CMAKE_CURRENT_BINARY_DIR}/ShogunCoreMLTarget.cmake"
NAMESPACE shogun::
)

install(EXPORT ShogunCoreMLTarget
FILE ShogunCoreMLTarget.cmake
NAMESPACE shogun::
DESTINATION ${CONFIG_PACKAGE_DIR}
)
53 changes: 53 additions & 0 deletions src/interfaces/coreml/CoreMLModel.cc
@@ -0,0 +1,53 @@
#include "CoreMLModel.h"

#include <fstream>

#include <google/protobuf/io/zero_copy_stream_impl.h>

#include "format/Model.pb.h"

using namespace shogun::coreml;

CoreMLModel::CoreMLModel():
m_spec(std::make_shared<CoreML::Specification::Model>())
{
}

CoreMLModel::CoreMLModel(std::shared_ptr<CoreML::Specification::Model> spec):
m_spec(spec)
{
}

CoreMLModel::~CoreMLModel()
{
m_spec.reset();
}

void CoreMLModel::save(const std::string& filename) const
{
std::fstream out(filename, std::ios::binary | std::ios::out);
this->save(out);
out.close();
}

void CoreMLModel::save(std::ostream& out) const
{
::google::protobuf::io::OstreamOutputStream pb_out(&out);
if (!m_spec->SerializeToZeroCopyStream(&pb_out))
throw std::runtime_error("could not save");
}

void CoreMLModel::set_short_description(const std::string& desc)
{
m_spec->mutable_description()->mutable_metadata()->set_shortdescription(desc);
}

void CoreMLModel::set_license(const std::string& license)
{
m_spec->mutable_description()->mutable_metadata()->set_license(license);
}

void CoreMLModel::set_author(const std::string& author)
{
m_spec->mutable_description()->mutable_metadata()->set_author(author);
}
38 changes: 38 additions & 0 deletions src/interfaces/coreml/CoreMLModel.h
@@ -0,0 +1,38 @@
#ifndef __COREML_MODEL_H__
#define __COREML_MODEL_H__

#include <memory>
#include <ostream>
#include <string>

namespace CoreML
{
namespace Specification
{
class Model;
}
}

namespace shogun
{
namespace coreml
{
class CoreMLModel
{
public:
CoreMLModel();
CoreMLModel(std::shared_ptr<CoreML::Specification::Model>);
~CoreMLModel();

void save(const std::string& filename) const;
void save(std::ostream& out) const;
void set_short_description(const std::string& desc);
void set_license(const std::string& license);
void set_author(const std::string& author);

private:
std::shared_ptr<CoreML::Specification::Model> m_spec;
};
}
}
#endif
16 changes: 16 additions & 0 deletions src/interfaces/coreml/ShogunCoreML.h
@@ -0,0 +1,16 @@
#ifndef __SHOGUN_COREML_H__
#define __SHOGUN_COREML_H__

#include <shogun/machine/Machine.h>

#include "CoreMLModel.h"

namespace shogun
{
namespace coreml
{
std::shared_ptr<CoreMLModel> convert(const CMachine* m) noexcept(false);
}
}

#endif
25 changes: 25 additions & 0 deletions src/interfaces/coreml/format/CMakeLists.txt
@@ -0,0 +1,25 @@
IF (PROTOBUF_FOUND AND ENABLE_PROTOBUF)
FILE(GLOB COREML_SRC "${CMAKE_CURRENT_SOURCE_DIR}/*.proto")
FILE(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
SET(COREML_SOURCES)
FOREACH (SRC_FILE ${COREML_SRC})
GET_FILENAME_COMPONENT(SRC_FILE_WE ${SRC_FILE} NAME_WE)
SET(COMPILED_SRC "${CMAKE_CURRENT_BINARY_DIR}/${SRC_FILE_WE}")
SET(COMPILED_SRC_H "${COMPILED_SRC}.pb.h")
SET(COMPILED_SRC_CPP "${COMPILED_SRC}.pb.cc")
ADD_CUSTOM_COMMAND(
OUTPUT "${COMPILED_SRC_H}" "${COMPILED_SRC_CPP}"
COMMAND "${PROTOBUF_PROTOC_EXECUTABLE}"
"${SRC_FILE}"
--cpp_out "${CMAKE_CURRENT_BINARY_DIR}"
--proto_path "${CMAKE_CURRENT_SOURCE_DIR}"
COMMENT "Compiling CoreML Protobuf for ${SRC_FILE_WE}"
)
SET(PROTO_TARGET_NAME "CoreML_${SRC_FILE_WE}")
ADD_CUSTOM_TARGET("${PROTO_TARGET_NAME}" DEPENDS "${COMPILED_SRC_H}" "${COMPILED_SRC_CPP}")
LIST(APPEND COREML_SOURCES ${COMPILED_SRC_CPP})
ENDFOREACH()
add_library(coreml STATIC ${COREML_SOURCES})
ELSE()
MESSAGE(FATAL_ERROR "Protobuf is required for CoreML")
ENDIF()
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
21 changes: 21 additions & 0 deletions src/interfaces/coreml/internal/CMakeLists.txt
@@ -0,0 +1,21 @@
IF (ENABLE_TESTING)
include(external/GoogleTestNMock)
ExternalProject_Get_Property(GoogleMock source_dir)
LINK_DIRECTORIES(${THIRD_PARTY_DIR}/libs/gmock)

enable_testing()
add_library(coreml_unittest_main ${CMAKE_CURRENT_SOURCE_DIR}/unittest_main.cc)
target_link_libraries(coreml_unittest_main gmock gtest shogun::shogun)
add_dependencies(coreml_unittest_main GoogleMock shogun::shogun)
target_include_directories(coreml_unittest_main
PRIVATE
${source_dir}/googlemock/include
${source_dir}/googletest/include)
set(SHOGUN_UNITTEST_LINK_LIBS coreml_unittest_main shogun::shogun shogun-coreml gmock gtest)

ADD_SHOGUN_UNITTEST(TARGET SVMRegressorConverter_test LABELS coreml-unit)
ADD_SHOGUN_UNITTEST(TARGET SVMClassifierConverter_test LABELS coreml-unit)
ADD_SHOGUN_UNITTEST(TARGET KernelConverter_test LABELS coreml-unit)
ADD_SHOGUN_UNITTEST(TARGET GLMRegressorConverter_test LABELS coreml-unit)
ADD_SHOGUN_UNITTEST(TARGET GLMClassifierConverter_test LABELS coreml-unit)
ENDIF()

0 comments on commit d2c4fd2

Please sign in to comment.