diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..4fef88d --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,57 @@ +cmake_minimum_required(VERSION 3.8 FATAL_ERROR) + +project(cppflow LANGUAGES CXX) +find_library(TENSORFLOW_LIB tensorflow HINT $ENV{HOME}/libtensorflow2/lib) +set(CMAKE_CXX_STANDARD 17) + +add_library(cppflow INTERFACE) + + +set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib) +set(INSTALL_LIB_DIR lib CACHE PATH "Installation directory for libraries") +set(INSTALL_BIN_DIR bin CACHE PATH "Installation directory for executables") +set(INSTALL_INCLUDE_DIR include CACHE PATH + "Installation directory for header files") + + +foreach(p LIB BIN INCLUDE CMAKE) + set(var INSTALL_${p}_DIR) + if(NOT IS_ABSOLUTE "${${var}}") + set(${var} "${CMAKE_INSTALL_PREFIX}/${${var}}") + endif() +endforeach() + + +target_compile_features(cppflow INTERFACE cxx_std_17) + +target_include_directories(cppflow INTERFACE + $ + $ +) + +target_link_libraries(cppflow INTERFACE + ${TENSORFLOW_LIB} +) + +#set_target_properties(cppflow PROPERTIES +# POSITION_INDEPENDENT_CODE ON +#) + +install(TARGETS cppflow + EXPORT cppflow-targets + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + PUBLIC_HEADER DESTINATION "${INSTALL_INCLUDE_DIR}/cppflow" +) + +install(EXPORT cppflow-targets + FILE cppflowConfig.cmake + DESTINATION ${INSTALL_CMAKE_DIR}/cmake/cppflow +) + +export(TARGETS cppflow + FILE cppflowConfig.cmake) + + +set(CMAKE_EXPORT_PACKAGE_REGISTRY ON) +export(PACKAGE cppflow) diff --git a/docs/Doxyfile b/docs/Doxyfile deleted file mode 100644 index be27a54..0000000 --- a/docs/Doxyfile +++ /dev/null @@ -1,15 +0,0 @@ -PROJECT_NAME = "cppflow" -XML_OUTPUT = xml -INPUT = ../include -GENERATE_LATEX = NO -GENERATE_MAN = NO -GENERATE_RTF = NO -CASE_SENSE_NAMES = NO -GENERATE_HTML = NO -GENERATE_XML = YES -RECURSIVE = YES -QUIET = YES -JAVADOC_AUTOBRIEF = YES -WARN_IF_UNDOCUMENTED = NO -MACRO_EXPANSION = YES -PREDEFINED = IN_DOXYGEN diff --git a/docs/Makefile b/docs/Makefile deleted file mode 100644 index 3979c08..0000000 --- a/docs/Makefile +++ /dev/null @@ -1,21 +0,0 @@ -# Minimal makefile for Sphinx documentation -# - -# You can set these variables from the command line, and also -# from the environment for the first two. -SPHINXOPTS ?= -SPHINXBUILD ?= sphinx-build -SOURCEDIR = source -BUILDDIR = build - -# Put it first so that "make" without argument is like "make help". -help: - @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) - -.PHONY: help Makefile - -# Catch-all target: route all unknown targets to Sphinx using the new -# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). -%: Makefile - doxygen - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/make.bat b/docs/make.bat deleted file mode 100644 index 6247f7e..0000000 --- a/docs/make.bat +++ /dev/null @@ -1,35 +0,0 @@ -@ECHO OFF - -pushd %~dp0 - -REM Command file for Sphinx documentation - -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=sphinx-build -) -set SOURCEDIR=source -set BUILDDIR=build - -if "%1" == "" goto help - -%SPHINXBUILD% >NUL 2>NUL -if errorlevel 9009 ( - echo. - echo.The 'sphinx-build' command was not found. Make sure you have Sphinx - echo.installed, then set the SPHINXBUILD environment variable to point - echo.to the full path of the 'sphinx-build' executable. Alternatively you - echo.may add the Sphinx directory to PATH. - echo. - echo.If you don't have Sphinx installed, grab it from - echo.http://sphinx-doc.org/ - exit /b 1 -) - -%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% -goto end - -:help -%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% - -:end -popd diff --git a/docs/source/conf.py b/docs/source/conf.py deleted file mode 100644 index 03862cd..0000000 --- a/docs/source/conf.py +++ /dev/null @@ -1,70 +0,0 @@ -# Configuration file for the Sphinx documentation builder. -# -# This file only contains a selection of the most common options. For a full -# list see the documentation: -# https://www.sphinx-doc.org/en/master/usage/configuration.html - -# -- Path setup -------------------------------------------------------------- - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -# -# import os -# import sys -# sys.path.insert(0, os.path.abspath('.')) - -# Workaround for issue https://github.com/sphinx-contrib/googleanalytics/issues/2 -# Note that a warning still will be issued "unsupported object from its setup() function" -# Remove this workaround when the issue has been resolved upstream -import sphinx.application -import sphinx.errors -sphinx.application.ExtensionError = sphinx.errors.ExtensionError - - -# -- Project information ----------------------------------------------------- - -project = 'cppflow' -copyright = '2020, Sergio Izquierdo' -author = 'Sergio Izquierdo' - -# The full version, including alpha/beta/rc tags -release = '2.0' - - -# -- General configuration --------------------------------------------------- - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -extensions = [ - 'breathe', - 'sphinxcontrib.googleanalytics', -] - -breathe_projects = { 'cppflow': '../xml' } - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -# This pattern also affects html_static_path and html_extra_path. -exclude_patterns = [] - - -# -- Options for HTML output ------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -# -html_theme = 'sphinx_rtd_theme' - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = [] - -# -- Google Analytics -------------------------------------------------------- - -googleanalytics_id = 'UA-110983956-1' \ No newline at end of file diff --git a/docs/source/cppflow.svg b/docs/source/cppflow.svg deleted file mode 100644 index 9ea748f..0000000 --- a/docs/source/cppflow.svg +++ /dev/null @@ -1,221 +0,0 @@ - - - - - - image/svg+xml - - FullColorPrimary Horizontal - - - - - - - - - - - - - - - - - - - - - - - - - FullColorPrimary Horizontal - - - - - ++ - - - - - CppFlow - - diff --git a/docs/source/examples.rst b/docs/source/examples.rst deleted file mode 100644 index 50bb5cb..0000000 --- a/docs/source/examples.rst +++ /dev/null @@ -1,178 +0,0 @@ -Examples -======== - -This guide show how to create and run some basic examples that show the functionality of cppflow. The code of these examples is available on the `GitHub repo `_. To run these examples, just use the provided CMake on each of them (after having installed the TF C API as in :ref:`Installation`): - -.. code:: bash - - git clone git@github.com:serizba/cppflow.git - cd cppflow/examples/load_model - mkdir build - cd build - cmake .. - make - ./example - - -Create and load model ---------------------- - -To create a model that you can open with cppflow you just need to create a ``tf.Module`` or a ``tf.keras.Model`` and save it. Using the functional API of keras this is as easy as: - -.. code:: python - - import tensorflow as tf - - - input = tf.keras.Input(shape=(5,)) - - output = tf.keras.layers.Dense(5, activation=tf.nn.relu)(input) - output = tf.keras.layers.Dense(1, activation=tf.nn.sigmoid)(output) - model = tf.keras.Model(inputs=input, outputs=output) - - model.compile() - - # Export the model to a SavedModel - model.save('model', save_format='tf') - -Now a new directory named ``model`` is created, and it contains the saved model. You can open it from cppflow using the ``model`` class, to then feed it with a tensor to obtain the output. - -.. code:: c++ - - #include - #include "cppflow/cppflow.h" - - - int main() { - - auto input = cppflow::fill({10, 5}, 1.0f); - cppflow::model model("../model"); - auto output = model(input); - - std::cout << output << std::endl; - - return 0; - } - -.. _EfficientNet: - -Inference on EfficientNet -------------------------- - -For this example we use a pretrained EfficientNet network that is available in `Keras applications `_. Running the following code will create a ``model`` directory with the definition of the EfficientNet and its weights. - -.. code:: python - - import tensorflow as tf - - model = tf.keras.applications.EfficientNetB0() - - # Export the model to a SavedModel - model.save('model', save_format='tf') - -Now we can open the model from cppflow and perform inference with a real image. - -.. image:: my_cat.jpg - :width: 300 - :alt: Inference on EfficientNet from c++ with a picture of a cat - -We can load the image using ``cppflow::read_file`` and ``cppflow::decode_jpeg``. Then we have to convert it to float and feed it to the network. - -.. code:: c++ - - #include - #include "cppflow/cppflow.h" - - - int main() { - - auto input = cppflow::decode_jpeg(cppflow::read_file(std::string("../my_cat.jpg"))); - input = cppflow::cast(input, TF_UINT8, TF_FLOAT); - input = cppflow::expand_dims(input, 0); - cppflow::model model("../model"); - auto output = model(input); - - std::cout << "It's a tiger cat: " << cppflow::arg_max(output, 1) << std::endl; - - return 0; - } - -To see the prediction of the network we apply ``cppflow::arg_max`` to the ouput and it will show the number of the predicted class, which corresponds with a tiger cat. - -.. _MultiInputOutput: - -Multi input/output model ------------------------- - -For this example we will create a Keras model that takes two inputs and produce two outputs: - -.. code:: python - - import tensorflow as tf - - input_1 = tf.keras.Input(shape=(5,), name='my_input_1') - input_2 = tf.keras.Input(shape=(5,), name='my_input_2') - - x1 = tf.keras.layers.Dense(5, activation=tf.nn.relu)(input_1) - x2 = tf.keras.layers.Dense(5, activation=tf.nn.relu)(input_2) - - output_1 = tf.keras.layers.Dense(1, activation=tf.nn.sigmoid, name='my_outputs_1')(x1) - output_2 = tf.keras.layers.Dense(1, activation=tf.nn.sigmoid, name='my_outputs_2')(x2) - - model = tf.keras.Model(inputs=[input_1, input_2], outputs=[output_1, output_2]) - - model.compile() - - # Export the model to a SavedModel - model.save('model', save_format='tf') - -Now, we will inspect the model with the `saved_model_cli `_ to retrieve the name of the operations, and to know how to call the model. - -.. code-block:: shell-session - - $ saved_model_cli show --dir model - 'serve' - $ saved_model_cli show --dir model --tag_set serve - SignatureDef key: "__saved_model_init_op" - SignatureDef key: "serving_default" - $ saved_model_cli show --dir model --tag_set serve --signature_def serving_default - The given SavedModel SignatureDef contains the following input(s): - inputs['my_input_1'] tensor_info: - dtype: DT_FLOAT - shape: (-1, 5) - name: serving_default_my_input_1:0 - inputs['my_input_2'] tensor_info: - dtype: DT_FLOAT - shape: (-1, 5) - name: serving_default_my_input_2:0 - The given SavedModel SignatureDef contains the following output(s): - outputs['my_outputs_1'] tensor_info: - dtype: DT_FLOAT - shape: (-1, 1) - name: StatefulPartitionedCall:0 - outputs['my_outputs_2'] tensor_info: - dtype: DT_FLOAT - shape: (-1, 1) - name: StatefulPartitionedCall:1 - Method name is: tensorflow/serving/predict - -From this output we can see that there are two inputs (``serving_default_my_input_1:0`` and ``serving_default_my_input_2:0``) and two outputs (``StatefulPartitionedCall:0`` and ``StatefulPartitionedCall:1``). You can run the model specifying multiple inputs as a vector of tuples `` - #include "cppflow/cppflow.h" - - int main() { - - auto input_1 = cppflow::fill({10, 5}, 1.0f); - auto input_2 = cppflow::fill({10, 5}, -1.0f); - cppflow::model model("../model"); - - auto output = model({{"serving_default_my_input_1:0", input_1}, {"serving_default_my_input_2:0", input_2}}, {"StatefulPartitionedCall:0", "StatefulPartitionedCall:1"}); - - std::cout << "output_1: " << output[0] << std::endl; - std::cout << "output_2: " << output[1] << std::endl; - return 0; - } diff --git a/docs/source/index.rst b/docs/source/index.rst deleted file mode 100644 index 30f421a..0000000 --- a/docs/source/index.rst +++ /dev/null @@ -1,33 +0,0 @@ -.. cppflow documentation master file, created by - sphinx-quickstart on Mon Oct 26 18:42:22 2020. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - -.. image:: cppflow.svg - :alt: cppflow - -Easily run TensorFlow models from C++ -===================================== - -With cppflow you can easily run TensorFlow models in C++ without Bazel, without TensorFlow installation and without compiling Tensorflow. Perform tensor manipulation, use eager execution and run saved models directly from C++. - -.. toctree:: - :maxdepth: 2 - :caption: Guide - - installation - quickstart - examples - - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` - - -Remark ------- -CppFlow is not related with TensorFlow. The CppFlow icon is a modified version of the TensorFlow logo. TensorFlow, the TensorFlow logo and any related marks are trademarks of Google Inc. \ No newline at end of file diff --git a/docs/source/installation.rst b/docs/source/installation.rst deleted file mode 100644 index 4358714..0000000 --- a/docs/source/installation.rst +++ /dev/null @@ -1,47 +0,0 @@ -.. _Installation: - -Installation -============ - -One of the advantages of cppflow is that you don't need to compile or install TensorFlow, you just need to download the `TF C API `_. As cppflow is a header-only library, once you have the C API, the only thing you need to do is include the cppflow files from your project. - -To install the C API in your system you have two options: - -Install the TF C API globally ------------------------------ -You can install the C API in a system directory and do not worry about it again. For this, you just have to `download it `_ it and then: - -.. code:: bash - - sudo tar -C /usr/local -xzf (downloaded file) - sudo ldconfig - -Install the TF C API in custom directory ----------------------------------------- -.. note:: - The easiest way is to extract the library into your HOME directory, in a folder called ``libtensorflow2``. In this case, you can directly use the CMake files from the examples, which will search for the library in your HOME directory. - - ``mkdir -p ~/libtensorflow2/ && tar -C ~/libtensorflow2/ -xzf (downloaded file)`` - -You can also install the library in a custom directory. In this case, after `downloading it `_ and unpacking it you will need to update your PATH or add a hint to your ``CMakeLists.txt`` to find the library. - -.. code:: bash - - mkdir -p /path/to/mydir/ - tar -C /path/to/mydir -xzf (downloaded file) - -Now, update your path: - -.. code:: bash - - export LIBRARY_PATH=$LIBRARY_PATH:/path/to/mydir/lib - export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/path/to/mydir/lib - -Or add a hint in ``CMakeLists.txt`` as in the examples: - -.. code:: cmake - - find_library(TENSORFLOW_LIB tensorflow HINT /path/to/mydir/lib) - - -You are done, now you can proceed to build your :ref:`first example`. diff --git a/docs/source/my_cat.jpg b/docs/source/my_cat.jpg deleted file mode 100644 index 951abe5..0000000 Binary files a/docs/source/my_cat.jpg and /dev/null differ diff --git a/docs/source/quickstart.rst b/docs/source/quickstart.rst deleted file mode 100644 index 928b0a7..0000000 --- a/docs/source/quickstart.rst +++ /dev/null @@ -1,203 +0,0 @@ - -Quickstart -========== - -.. _First example: - -First example -------------- - -Once you have downloaded the TF C API and cppflow you can start playing with tensors from C++: - -.. code:: c++ - - #include - #include "cppflow/cppflow.h" - - int main() { - - // Create a tensor from a list, a = [1.0, 2.0, 3.0] - auto a = cppflow::tensor({1.0, 2.0, 3.0}); - // Create a tensor of shape 3 filled with 1.0, b = [1.0, 2.0, 3.0] - auto b = cppflow::fill({3}, 1.0); - - std::cout << a + b << std::endl; - - return 0; - } - -Easy right?, now you can compile it with the terminal (if you have configured the TF C API as stated in :ref:`Installation`) using the following command: - -.. code:: bash - - g++ -std=c++17 -o main.out -I /path/to/libtensorflow2/include/ -I/path/to/cppflow/include/ main.cpp -ltensorflow - ./main.out - -You should see the result of ``a + b``: - -.. code:: - - (tensor: shape=[3], data= - [2 3 4]) - -Using CMake ------------ - -Probably a more convenient way of compiling your code is using CMake. - -.. code:: cmake - - cmake_minimum_required(VERSION 3.10) - project(example) - - find_library(TENSORFLOW_LIB tensorflow HINT $ENV{HOME}/libtensorflow2/lib) - - set(CMAKE_CXX_STANDARD 17) - - add_executable(example main.cpp) - target_include_directories(example PRIVATE /path/to/cppflow/include/ $ENV{HOME}/libtensorflow2/include) - target_link_libraries (example "${TENSORFLOW_LIB}") - - - -Load a model ------------- - -You can easily run TensorFlow models with cppflow by loading a `saved model `_. Imagine you have a model saved on the folder ``coolpredictor`` that takes an image as an input and produces a vector of probabilities of the class belonging to each possible class. You can load the model, read your image, preprocess it, run the model and get the output just using cppflow: - -.. code:: c++ - - #include - #include "cppflow/cppflow.h" - - - int main() { - - // Load the model - cppflow::model model("coolpredictor"); - - // Load an image - auto input = cppflow::decode_jpeg(cppflow::read_file(std::string("image.jpg"))); - - // Cast it to float, normalize to range [0, 1], and add batch_dimension - input = cppflow::cast(input, TF_UINT8, TF_FLOAT); - input = input / 255.f; - input = cppflow::expand_dims(input, 0); - - // Run - auto output = model(input); - - // Show the predicted class - std::cout << cppflow::arg_max(output, 1) << std::endl; - } - -For a complete (runnable) example you can check :ref:`this example`, which performs inference on an EfficientNet trained on ImageNet. - -Complex model call (multi input/output models) ----------------------------------------------- - -By default, calling ``model(input)`` will use the input operation named ``serving_default_input_1`` and output operation ``StatefulPartitionedCall``. If you need to use other operations or you need to use multiple inputs or outputs you can directly specify your desired inputs and outputs operations: - -.. code:: c++ - - - // Calling model in default mode - auto output = model(input); - - // Calling model as in default mode (but specifying signature) - auto output = model({{"serving_default_input_1:0", input}},{"StatefulPartitionedCall:0"}); - - // Calling model with two inputs, named "serving_default_input_1" and "serving_default_input_2" - auto output = model({{"serving_default_input_1:0", input1}, {"serving_default_input_2:0", input2}},{"StatefulPartitionedCall:0"}); - - // Calling model with two outputs, named "StatefulPartitionedCall:0" and "StatefulPartitionedCall:1" - auto output = model({{"serving_default_input_1:0", input}},{"StatefulPartitionedCall:0", "StatefulPartitionedCall:1"}); - - // Calling model with two inputs and two outputs - auto output = model({{"serving_default_my_input_1:0", input_1}, {"serving_default_my_input_2:0", input_2}}, {"StatefulPartitionedCall:0", "StatefulPartitionedCall:1"}); - -.. note:: - If you don't know the name of the operations of your model you can use the `saved_model_cli `_ to print all the information: - - ``saved_model_cli show --dir /path/to/model --all`` - - Or you can use ``model::get_operations()`` to retrieve the name of the available operations. - - -For a complete (runnable) example you can check :ref:`this example`., which uses a toy model with two inputs and two outputs. - -GPU Config Options ------------------- - -You can specify TensorFlow's GPU Options to prevent it from reserving all your GPU memory. To do so in cppflow2, you need to change the global context and set your serialized options: - -.. code:: c++ - - - // Serialized config options (example of 30% memory fraction) - // Read more to see how to obtain the serialized options - std::vector config{0x32,0xb,0x9,0x34,0x33,0x33,0x33,0x33,0x33,0xd3,0x3f,0x20,0x1}; - // Create new options with your configuration - TFE_ContextOptions* options = TFE_NewContextOptions(); - TFE_ContextOptionsSetConfig(options, config.data(), config.size(), cppflow::context::get_status()); - // Replace the global context with your options - cppflow::get_global_context() = cppflow::context(options); - -To obtain your desired serialized config options you can just run a small python script to print them: - -.. code:: python - - import tensorflow.compat.v1 as tf - - def create_serialized_options(fraction, growth): - config = tf.ConfigProto() - config.gpu_options.per_process_gpu_memory_fraction = fraction - config.gpu_options.allow_growth = growth - serialized = config.SerializeToString() - return '{' + ','.join(list(map(hex, serialized))) + '}' - - # Example with 30% and enable memory growth - # {0x32,0xb,0x9,0x33,0x33,0x33,0x33,0x33,0x33,0xd3,0x3f,0x20,0x1} - print(create_serialized_options(fraction=0.3, growth=True)) - -Also, for convenience, here is a list with some precomputed serialized options: - -+-----------------+---------------+------------------------------------------------------------------+ -| Memory Fraction | Memory Growth | Serialized Options | -+=================+===============+==================================================================+ -| 10% | True | {0x32,0xb,0x9,0x9a,0x99,0x99,0x99,0x99,0x99,0xb9,0x3f,0x20,0x1} | -+ +---------------+------------------------------------------------------------------+ -| | False | {0x32,0x9,0x9,0x9a,0x99,0x99,0x99,0x99,0x99,0xb9,0x3f} | -+-----------------+---------------+------------------------------------------------------------------+ -| 20% | True | {0x32,0xb,0x9,0x9a,0x99,0x99,0x99,0x99,0x99,0xc9,0x3f,0x20,0x1} | -+ +---------------+------------------------------------------------------------------+ -| | False | {0x32,0x9,0x9,0x9a,0x99,0x99,0x99,0x99,0x99,0xc9,0x3f} | -+-----------------+---------------+------------------------------------------------------------------+ -| 30% | True | {0x32,0xb,0x9,0x34,0x33,0x33,0x33,0x33,0x33,0xd3,0x3f,0x20,0x1} | -+ +---------------+------------------------------------------------------------------+ -| | False | {0x32,0x9,0x9,0x34,0x33,0x33,0x33,0x33,0x33,0xd3,0x3f} | -+-----------------+---------------+------------------------------------------------------------------+ -| 40% | True | {0x32,0xb,0x9,0x9a,0x99,0x99,0x99,0x99,0x99,0xd9,0x3f,0x20,0x1} | -+ +---------------+------------------------------------------------------------------+ -| | False | {0x32,0x9,0x9,0x9a,0x99,0x99,0x99,0x99,0x99,0xd9,0x3f} | -+-----------------+---------------+------------------------------------------------------------------+ -| 50% | True | {0x32,0xb,0x9,0x0,0x0,0x0,0x0,0x0,0x0,0xe0,0x3f,0x20,0x1} | -+ +---------------+------------------------------------------------------------------+ -| | False | {0x32,0x9,0x9,0x0,0x0,0x0,0x0,0x0,0x0,0xe0,0x3f} | -+-----------------+---------------+------------------------------------------------------------------+ -| 60% | True | {0x32,0xb,0x9,0x34,0x33,0x33,0x33,0x33,0x33,0xe3,0x3f,0x20,0x1} | -+ +---------------+------------------------------------------------------------------+ -| | False | {0x32,0x9,0x9,0x34,0x33,0x33,0x33,0x33,0x33,0xe3,0x3f} | -+-----------------+---------------+------------------------------------------------------------------+ -| 70% | True | {0x32,0xb,0x9,0x67,0x66,0x66,0x66,0x66,0x66,0xe6,0x3f,0x20,0x1} | -+ +---------------+------------------------------------------------------------------+ -| | False | {0x32,0x9,0x9,0x67,0x66,0x66,0x66,0x66,0x66,0xe6,0x3f} | -+-----------------+---------------+------------------------------------------------------------------+ -| 80% | True | {0x32,0xb,0x9,0x9a,0x99,0x99,0x99,0x99,0x99,0xe9,0x3f,0x20,0x1} | -+ +---------------+------------------------------------------------------------------+ -| | False | {0x32,0x9,0x9,0x9a,0x99,0x99,0x99,0x99,0x99,0xe9,0x3f} | -+-----------------+---------------+------------------------------------------------------------------+ -| 90% | True | {0x32,0xb,0x9,0xcd,0xcc,0xcc,0xcc,0xcc,0xcc,0xec,0x3f,0x20,0x1} | -+ +---------------+------------------------------------------------------------------+ -| | False | {0x32,0x9,0x9,0xcd,0xcc,0xcc,0xcc,0xcc,0xcc,0xec,0x3f} | -+-----------------+---------------+------------------------------------------------------------------+ \ No newline at end of file diff --git a/examples/eager_op_multithread/CMakeLists.txt b/examples/eager_op_multithread/CMakeLists.txt deleted file mode 100644 index 3876ca0..0000000 --- a/examples/eager_op_multithread/CMakeLists.txt +++ /dev/null @@ -1,14 +0,0 @@ -cmake_minimum_required(VERSION 3.10) -project(example) - -find_library(TENSORFLOW_LIB tensorflow HINT $ENV{HOME}/libtensorflow2/lib) -find_package(Threads REQUIRED) - -set(CMAKE_CXX_STANDARD 17) - -#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-omit-frame-pointer -fsanitize=thread") -#set(CMAKE_LINKER_FLAGS "${CMAKE_LINKER_FLAGS} -fno-omit-frame-pointer -fsanitize=thread") - -add_executable(example main.cpp) -target_include_directories(example PRIVATE ../../include $ENV{HOME}/libtensorflow2/include) -target_link_libraries(example "${TENSORFLOW_LIB}" Threads::Threads) diff --git a/examples/eager_op_multithread/main.cpp b/examples/eager_op_multithread/main.cpp deleted file mode 100644 index 8ef7045..0000000 --- a/examples/eager_op_multithread/main.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include -#include -#include -#include - -#include "cppflow/cppflow.h" - -constexpr size_t num_iter = 10240; -constexpr size_t num_threads = 32; - -void test1(float input1, float input2, float input3) { - float target = (input1+input2)*input3; - for(size_t i = 0; i < num_iter; i++) { - cppflow::tensor t1(input1), t2(input2), t3(input3); - auto result = (t1+t2)*t3; - float result_value = result.get_data()[0]; - if(std::abs(target/result_value-1.0f) > 1e-6) { - std::cout << "error: result_value=" << result_value << ", target=" << target << std::endl; - } - } -} - -int main() { - std::vector threads; - for(size_t i = 0; i < num_threads; i++) { - if(i % 2 == 0) { - std::thread t1(test1, 3, 10, 100); - threads.push_back(std::move(t1)); - } else { - std::thread t2(test1, 130, 10, 100); - threads.push_back(std::move(t2)); - } - } - - for(auto& t: threads) { - t.join(); - } - - return 0; -} diff --git a/examples/efficientnet/CMakeLists.txt b/examples/efficientnet/CMakeLists.txt deleted file mode 100644 index 64662c9..0000000 --- a/examples/efficientnet/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -cmake_minimum_required(VERSION 3.10) -project(example) - -find_library(TENSORFLOW_LIB tensorflow HINT $ENV{HOME}/libtensorflow2/lib) - -set(CMAKE_CXX_STANDARD 17) - -add_executable(example main.cpp) -target_include_directories(example PRIVATE ../../include $ENV{HOME}/libtensorflow2/include) -target_link_libraries (example "${TENSORFLOW_LIB}") \ No newline at end of file diff --git a/examples/efficientnet/create_model.py b/examples/efficientnet/create_model.py deleted file mode 100644 index 48afa2e..0000000 --- a/examples/efficientnet/create_model.py +++ /dev/null @@ -1,8 +0,0 @@ -import tensorflow as tf - -model = tf.keras.applications.EfficientNetB0() - -# Export the model to a SavedModel -model.save('model', save_format='tf') - - diff --git a/examples/efficientnet/main.cpp b/examples/efficientnet/main.cpp deleted file mode 100644 index ac2dac7..0000000 --- a/examples/efficientnet/main.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include - -#include "cppflow/cppflow.h" - - -int main() { - - auto input = cppflow::decode_jpeg(cppflow::read_file(std::string("../my_cat.jpg"))); - input = cppflow::cast(input, TF_UINT8, TF_FLOAT); - input = cppflow::expand_dims(input, 0); - cppflow::model model("../model"); - auto output = model(input); - - std::cout << "It's a tiger cat: " << cppflow::arg_max(output, 1) << std::endl; - - return 0; -} diff --git a/examples/efficientnet/my_cat.jpg b/examples/efficientnet/my_cat.jpg deleted file mode 100644 index 951abe5..0000000 Binary files a/examples/efficientnet/my_cat.jpg and /dev/null differ diff --git a/examples/load_model/CMakeLists.txt b/examples/load_model/CMakeLists.txt deleted file mode 100644 index 430da95..0000000 --- a/examples/load_model/CMakeLists.txt +++ /dev/null @@ -1,12 +0,0 @@ -cmake_minimum_required(VERSION 3.10) -project(example) - -find_library(TENSORFLOW_LIB tensorflow HINT $ENV{HOME}/libtensorflow2/lib) - -set(CMAKE_CXX_STANDARD 17) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-omit-frame-pointer -fsanitize=address") -set(CMAKE_LINKER_FLAGS "${CMAKE_LINKER_FLAGS} -lasan") - -add_executable(example main.cpp) -target_include_directories(example PRIVATE ../../include $ENV{HOME}/libtensorflow2/include) -target_link_libraries (example "${TENSORFLOW_LIB}") diff --git a/examples/load_model/create_model.py b/examples/load_model/create_model.py deleted file mode 100644 index 5b5107b..0000000 --- a/examples/load_model/create_model.py +++ /dev/null @@ -1,14 +0,0 @@ -import tensorflow as tf -import numpy as np - - -input = tf.keras.Input(shape=(5,)) - -output = tf.keras.layers.Dense(5, activation=tf.nn.relu)(input) -output = tf.keras.layers.Dense(1, activation=tf.nn.sigmoid)(output) -model = tf.keras.Model(inputs=input, outputs=output) - -model.compile() - -# Export the model to a SavedModel -model.save('model', save_format='tf') \ No newline at end of file diff --git a/examples/load_model/main.cpp b/examples/load_model/main.cpp deleted file mode 100644 index 58a8f95..0000000 --- a/examples/load_model/main.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include - -#include "cppflow/ops.h" -#include "cppflow/model.h" - - -int main() { - - auto input = cppflow::fill({10, 5}, 1.0f); - cppflow::model model("../model"); - auto output = model(input); - - std::cout << output << std::endl; - - auto values = output.get_data(); - - for (auto v : values) { - std::cout << v << std::endl; - } - return 0; -} diff --git a/examples/load_model/model/saved_model.pb b/examples/load_model/model/saved_model.pb deleted file mode 100644 index 9cd0058..0000000 Binary files a/examples/load_model/model/saved_model.pb and /dev/null differ diff --git a/examples/load_model/model/variables/variables.data-00000-of-00001 b/examples/load_model/model/variables/variables.data-00000-of-00001 deleted file mode 100644 index def833b..0000000 Binary files a/examples/load_model/model/variables/variables.data-00000-of-00001 and /dev/null differ diff --git a/examples/load_model/model/variables/variables.index b/examples/load_model/model/variables/variables.index deleted file mode 100644 index 7b2f01e..0000000 Binary files a/examples/load_model/model/variables/variables.index and /dev/null differ diff --git a/examples/multi_input_output/CMakeLists.txt b/examples/multi_input_output/CMakeLists.txt deleted file mode 100644 index 64662c9..0000000 --- a/examples/multi_input_output/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -cmake_minimum_required(VERSION 3.10) -project(example) - -find_library(TENSORFLOW_LIB tensorflow HINT $ENV{HOME}/libtensorflow2/lib) - -set(CMAKE_CXX_STANDARD 17) - -add_executable(example main.cpp) -target_include_directories(example PRIVATE ../../include $ENV{HOME}/libtensorflow2/include) -target_link_libraries (example "${TENSORFLOW_LIB}") \ No newline at end of file diff --git a/examples/multi_input_output/create_model.py b/examples/multi_input_output/create_model.py deleted file mode 100644 index e7dabfe..0000000 --- a/examples/multi_input_output/create_model.py +++ /dev/null @@ -1,19 +0,0 @@ -import tensorflow as tf -import numpy as np - - -input_1 = tf.keras.Input(shape=(5,), name='my_input_1') -input_2 = tf.keras.Input(shape=(5,), name='my_input_2') - -x1 = tf.keras.layers.Dense(5, activation=tf.nn.relu)(input_1) -x2 = tf.keras.layers.Dense(5, activation=tf.nn.relu)(input_2) - -output_1 = tf.keras.layers.Dense(1, activation=tf.nn.sigmoid, name='my_outputs_1')(x1) -output_2 = tf.keras.layers.Dense(1, activation=tf.nn.sigmoid, name='my_outputs_2')(x2) - -model = tf.keras.Model(inputs=[input_1, input_2], outputs=[output_1, output_2]) - -model.compile() - -# Export the model to a SavedModel -model.save('model', save_format='tf') diff --git a/examples/multi_input_output/main.cpp b/examples/multi_input_output/main.cpp deleted file mode 100644 index b537174..0000000 --- a/examples/multi_input_output/main.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include - -#include "cppflow/ops.h" -#include "cppflow/model.h" - -int main() { - - auto input_1 = cppflow::fill({10, 5}, 1.0f); - auto input_2 = cppflow::fill({10, 5}, -1.0f); - cppflow::model model("../model"); - - auto output = model({{"serving_default_my_input_1:0", input_1}, {"serving_default_my_input_2:0", input_2}}, {"StatefulPartitionedCall:0", "StatefulPartitionedCall:1"}); - - std::cout << "output_1: " << output[0] << std::endl; - std::cout << "output_2: " << output[1] << std::endl; - return 0; -} diff --git a/examples/multi_input_output/model/saved_model.pb b/examples/multi_input_output/model/saved_model.pb deleted file mode 100644 index 94ea4ee..0000000 Binary files a/examples/multi_input_output/model/saved_model.pb and /dev/null differ diff --git a/examples/multi_input_output/model/variables/variables.data-00000-of-00001 b/examples/multi_input_output/model/variables/variables.data-00000-of-00001 deleted file mode 100644 index 95973d1..0000000 Binary files a/examples/multi_input_output/model/variables/variables.data-00000-of-00001 and /dev/null differ diff --git a/examples/multi_input_output/model/variables/variables.index b/examples/multi_input_output/model/variables/variables.index deleted file mode 100644 index a26b949..0000000 Binary files a/examples/multi_input_output/model/variables/variables.index and /dev/null differ diff --git a/examples/tensor/CMakeLists.txt b/examples/tensor/CMakeLists.txt deleted file mode 100644 index eef291f..0000000 --- a/examples/tensor/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -cmake_minimum_required(VERSION 3.10) -project(example) - -find_library(TENSORFLOW_LIB tensorflow HINT $ENV{HOME}/libtensorflow2/lib) - -set(CMAKE_CXX_STANDARD 17) - -add_executable(example main.cpp odr.cpp) -target_include_directories(example PRIVATE ../../include $ENV{HOME}/libtensorflow2/include) -target_link_libraries(example "${TENSORFLOW_LIB}") diff --git a/examples/tensor/main.cpp b/examples/tensor/main.cpp deleted file mode 100644 index b0b437b..0000000 --- a/examples/tensor/main.cpp +++ /dev/null @@ -1,88 +0,0 @@ -#include -#include -#include -#include - -#include "cppflow/cppflow.h" - -bool float_equal(const float f1, const float f2) { - return std::abs(f1/f2-1.0f) < 1e-6; -} - -void test1(const bool is_cpu) { - std::cout << "test1 starts: is_cpu=" << is_cpu << std::endl; - float target = 1.0; - int64_t ndim = 2; - cppflow::tensor t1; - - if(is_cpu) { - std::vector _data(ndim, target); - t1 = cppflow::tensor(_data, {ndim}); - } else { - t1 = cppflow::fill({ndim}, target); - } - - std::cout << "tensor::device(true) : " << t1.device(true) << std::endl; - std::cout << "tensor::device(false) : " << t1.device(false) << std::endl; - - auto t1_tensor = t1.get_tensor(); - auto raw_data = static_cast(TF_TensorData(t1_tensor.get())); - float result_value = raw_data[0]; - if(float_equal(result_value, target)) { - std::cout << "tensor::get_tensor() test1-1: pass" << std::endl; - } else { - std::cout << "tensor::get_tensor() test1-1: result_value=" << result_value << ", target=" << target << std::endl; - throw std::runtime_error("tensor::get_tensor() test1-1: failed"); - } - - // IMPORTANT NOTE: CANNOT modify the returned cache - float target2 = target + 10.0; - raw_data[1] = target2; - result_value = t1.get_data()[0]; - float result_value2 = t1.get_data()[1]; - if(float_equal(result_value, target)) { - std::cout << "tensor::get_tensor() test1-2: pass" << std::endl; - } else { - std::cout << "tensor::get_tensor() test1-2: failed, result_value=" << result_value << ", target=" << target << std::endl; - throw std::runtime_error("tensor::get_tensor() test1-2: failed"); - } - if(float_equal(result_value2, target2)) { - std::cout << "tensor::get_tensor() test1-3: pass" << std::endl; - } else { - std::cout << "The failure of test1-3 is not considered as a bug." << std::endl; - std::cout << "tensor::get_tensor() test1-3: failed, result_value=" << result_value2 << ", target2=" << target2 << std::endl; - } - - auto t2 = t1 + cppflow::tensor(0.f); - std::cout << "Can NOT modify the cache!" << std::endl; - std::cout << "t2: " << t2 << std::endl; - - auto dt = cppflow::to_string(t1.dtype()); - std::string expected_dtype{"TF_FLOAT"}; - if(dt == expected_dtype) { - std::cout << "tensor::get_tensor() test1-4: pass" << std::endl; - } else { - std::cout << "tensor::get_tensor() test1-4: dtype=" << dt << ", expected_dtype=" << expected_dtype << std::endl; - throw std::runtime_error("tensor::get_tensor() test1-4: failed"); - } - - auto shape_tensor = t1.shape(); - auto shape = shape_tensor.get_data()[0]; - if(shape == ndim) { - std::cout << "tensor::get_tensor() test1-5: pass" << std::endl; - } else { - std::cout << "tensor::get_tensor() test1-5: shape_tensor.dtype()=" << cppflow::to_string(shape_tensor.dtype()) << std::endl; - std::cout << "tensor::get_tensor() test1-5: shape_tensor=" << shape_tensor << std::endl; - std::cout << "tensor::get_tensor() test1-5: shape()=" << shape << ", ndim=" << ndim << std::endl; - throw std::runtime_error("tensor::get_tensor() test1-5: failed"); - } - - std::cout << std::endl; -} - -int main() { - test1(true); - test1(false); - - return 0; -} diff --git a/examples/tensor/odr.cpp b/examples/tensor/odr.cpp deleted file mode 100644 index 1534985..0000000 --- a/examples/tensor/odr.cpp +++ /dev/null @@ -1,4 +0,0 @@ -#include "cppflow/cppflow.h" - -// Do NOT remove this file -// test ODR violation