diff options
Diffstat (limited to 'infra/packaging')
-rw-r--r-- | infra/packaging/build | 95 | ||||
-rw-r--r-- | infra/packaging/chklist/LAYOUT_191115 | 47 | ||||
-rw-r--r-- | infra/packaging/chklist/LAYOUT_191215 | 39 | ||||
-rw-r--r-- | infra/packaging/chklist/TF2CIRCLE_EXIST | 13 | ||||
-rw-r--r-- | infra/packaging/chklist/TF2CIRCLE_RUNNABLE | 16 | ||||
-rw-r--r-- | infra/packaging/chklist/TF2NNPKG_EXIST | 13 | ||||
-rw-r--r-- | infra/packaging/chklist/TF2TFLITE_EXIST | 13 | ||||
-rw-r--r-- | infra/packaging/chklist/TF2TFLITE_RUNNABLE | 13 | ||||
-rw-r--r-- | infra/packaging/preset/20191115 | 49 | ||||
-rw-r--r-- | infra/packaging/preset/20191215 | 42 | ||||
-rw-r--r-- | infra/packaging/preset/20191231_windows | 51 | ||||
-rw-r--r-- | infra/packaging/preset/20200115_windows | 50 | ||||
-rw-r--r-- | infra/packaging/res/tf2nnpkg | 87 | ||||
-rw-r--r-- | infra/packaging/res/tf2nnpkg.20191215 | 68 | ||||
-rw-r--r-- | infra/packaging/res/tflite_schema.fbs | 698 | ||||
-rw-r--r-- | infra/packaging/verify | 82 |
16 files changed, 1376 insertions, 0 deletions
diff --git a/infra/packaging/build b/infra/packaging/build new file mode 100644 index 000000000..81ab2ec49 --- /dev/null +++ b/infra/packaging/build @@ -0,0 +1,95 @@ +#!/bin/bash + +SCRIPT_PATH="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +if [[ -z "${NNAS_PROJECT_PATH}" ]]; then + echo "ERROR: NNAS_PROJECT_PATH is not specified" + exit 255 +fi + +# The default preset +PRESET="20191215" + +EXTRA_OPTIONS=() +while [ "$#" -ne 0 ]; do + CUR="$1" + + case $CUR in + '--prefix') + NNAS_INSTALL_PREFIX="$2" + shift 2 + ;; + '--preset') + PRESET="$2" + shift 2 + ;; + '--') + shift + while [ "$#" -ne 0 ]; do + EXTRA_OPTIONS+=("$1") + shift + done + ;; + *) + echo "ERROR: '${CUR}' is invalid" + exit 255 + ;; + esac +done + +# Q. Is it better to have the default value for NNAS_INSTALL_PREFIX? +# TODO Show USAGE +if [[ -z "${NNAS_INSTALL_PREFIX}" ]]; then + echo "ERROR: --prefix is not specified" + exit 255 +fi + +PRESET_PATH="${SCRIPT_PATH}/preset/${PRESET}" + +if [[ ! -f "${PRESET_PATH}" ]]; then + echo "ERROR: ${PRESET} is unavailable" + # TODO Show available presets + exit 255 +fi + +echo "-- Use '${PRESET}' SDK preset" + +source "${PRESET_PATH}" + +# Normalize to absolute path +if [[ "${NNAS_INSTALL_PREFIX}" != /* ]]; then + NNAS_INSTALL_PREFIX=${PWD}/${NNAS_INSTALL_PREFIX} +fi + +if [[ -z "${NNAS_BUILD_PREFIX}" ]]; then + # Create a temporary directory and use it! + NNAS_BUILD_PREFIX=$(mktemp -d) + trap "{ rm -rf $NNAS_BUILD_PREFIX; }" EXIT +fi + +# Create a release directory +mkdir -p "${NNAS_INSTALL_PREFIX}" + +# Build and Install NNCC +NNCC_BUILD_PREFIX="${NNAS_BUILD_PREFIX}/nncc" +NNCC_INSTALL_PREFIX="${NNAS_INSTALL_PREFIX}" + +mkdir -p "${NNCC_BUILD_PREFIX}" +cd "${NNCC_BUILD_PREFIX}" + +function join_by +{ + local IFS="$1"; shift; echo "$*" +} + +# Invoke "preset_configure" function that the preset provides +preset_configure + +NPROC=$(cat /proc/cpuinfo | grep -c processor) +cmake --build . -- -j$((NPROC/2)) all +cmake --build . -- install +# Install NN Package tools +NNPKG_INSTALL_PREFIX="${NNAS_INSTALL_PREFIX}" + +# Invoke "preset_install" function that the preset provides +preset_install diff --git a/infra/packaging/chklist/LAYOUT_191115 b/infra/packaging/chklist/LAYOUT_191115 new file mode 100644 index 000000000..e041a2c80 --- /dev/null +++ b/infra/packaging/chklist/LAYOUT_191115 @@ -0,0 +1,47 @@ +#!/bin/bash + +# Check whether the package has the following layout: +# +# bin/ +# model2nnpkg.sh +# tf2circle +# tf2nnpkg +# tf2tflite +# tflite2circle.sh +# tflitejson2circlejson.py +# lib/ +# libexo.so +# liblocoex_customop.so +# libloco.so +# libmoco_import.so +# libmoco_lang.so +# libmoco_log.so +# libmoco_pass.so +# libmoco_service.so +# libmoco_support.so +# libmoco_tf_frontend.so +# res/ +# circle_schema.fbs +# tflite_schema.fbs + +function prepare() +{ + export QUESTION="Is compatible with the 2019/11/15 layout?" +} + +function run() +{ + # The result of running "find . -print | sort | tr -d '\n\0'" from the expected package + EXPECTED="." + EXPECTED+="./bin./bin/model2nnpkg.sh./bin/tf2circle./bin/tf2nnpkg./bin/tf2tflite./bin/tflite2circle.sh" + EXPECTED+="./bin/tflitejson2circlejson.py./lib./lib/libexo.so./lib/liblocoex_customop.so./lib/libloco.so" + EXPECTED+="./lib/libmoco_import.so./lib/libmoco_lang.so./lib/libmoco_log.so./lib/libmoco_pass.so" + EXPECTED+="./lib/libmoco_service.so./lib/libmoco_support.so./lib/libmoco_tf_frontend.so./res" + EXPECTED+="./res/circle_schema.fbs./res/tflite_schema.fbs" + + OBTAINED=$(cd "${NNAS_INSTALL_PREFIX}" && find . -print | sort | tr -d '\n\0') + + if [[ "${OBTAINED}" = "${EXPECTED}" ]]; then + export PASSED=1 + fi +} diff --git a/infra/packaging/chklist/LAYOUT_191215 b/infra/packaging/chklist/LAYOUT_191215 new file mode 100644 index 000000000..8095197f6 --- /dev/null +++ b/infra/packaging/chklist/LAYOUT_191215 @@ -0,0 +1,39 @@ +#!/bin/bash + +# Check whether the package has the following layout: +# +# bin/ +# model2nnpkg.sh +# tf2circle +# tf2nnpkg +# lib/ +# libexo.so +# liblocoex_customop.so +# libloco.so +# libmoco_import.so +# libmoco_lang.so +# libmoco_log.so +# libmoco_pass.so +# libmoco_service.so +# libmoco_support.so +# libmoco_tf_frontend.so + +function prepare() +{ + export QUESTION="Is compatible with the 2019/12/15 layout?" +} + +function run() +{ + # The result of running "find . -print | sort | tr -d '\n\0'" from the expected package + EXPECTED="." + EXPECTED+="./bin./bin/model2nnpkg.sh./bin/tf2circle./bin/tf2nnpkg" + EXPECTED+="./lib./lib/libexo.so./lib/liblocoex_customop.so" + EXPECTED+="./lib/libloco.so./lib/libmoco_import.so./lib/libmoco_lang.so./lib/libmoco_log.so./lib/libmoco_pass.so./lib/libmoco_service.so./lib/libmoco_support.so./lib/libmoco_tf_frontend.so" + + OBTAINED=$(cd "${NNAS_INSTALL_PREFIX}" && find . -print | sort | tr -d '\n\0') + + if [[ "${OBTAINED}" = "${EXPECTED}" ]]; then + export PASSED=1 + fi +} diff --git a/infra/packaging/chklist/TF2CIRCLE_EXIST b/infra/packaging/chklist/TF2CIRCLE_EXIST new file mode 100644 index 000000000..b0834fc27 --- /dev/null +++ b/infra/packaging/chklist/TF2CIRCLE_EXIST @@ -0,0 +1,13 @@ +#!/bin/bash + +function prepare() +{ + export QUESTION="Is there tf2circle?" +} + +function run() +{ + if [[ -f "${NNAS_INSTALL_PREFIX}/bin/tf2circle" ]]; then + export PASSED=1 + fi +} diff --git a/infra/packaging/chklist/TF2CIRCLE_RUNNABLE b/infra/packaging/chklist/TF2CIRCLE_RUNNABLE new file mode 100644 index 000000000..597778ff4 --- /dev/null +++ b/infra/packaging/chklist/TF2CIRCLE_RUNNABLE @@ -0,0 +1,16 @@ +#!/bin/bash + +function prepare() +{ + export QUESTION="Is it possible to run tf2circle?" +} + +function run() +{ + BIN="${NNAS_INSTALL_PREFIX}/bin/tf2circle" + if [[ -f "${BIN}" ]]; then + if [[ $(ldd -r "${BIN}" | grep '^undefined' | wc -l) -eq 0 ]]; then + export PASSED=1 + fi + fi +} diff --git a/infra/packaging/chklist/TF2NNPKG_EXIST b/infra/packaging/chklist/TF2NNPKG_EXIST new file mode 100644 index 000000000..bbe9a3157 --- /dev/null +++ b/infra/packaging/chklist/TF2NNPKG_EXIST @@ -0,0 +1,13 @@ +#!/bin/bash + +function prepare() +{ + export QUESTION="Is there tf2nnpkg?" +} + +function run() +{ + if [[ -f "${NNAS_INSTALL_PREFIX}/bin/tf2nnpkg" ]]; then + export PASSED=1 + fi +} diff --git a/infra/packaging/chklist/TF2TFLITE_EXIST b/infra/packaging/chklist/TF2TFLITE_EXIST new file mode 100644 index 000000000..1a1c65cbc --- /dev/null +++ b/infra/packaging/chklist/TF2TFLITE_EXIST @@ -0,0 +1,13 @@ +#!/bin/bash + +function prepare() +{ + export QUESTION="Is there tf2tflite?" +} + +function run() +{ + if [[ -f "${NNAS_INSTALL_PREFIX}/bin/tf2tflite" ]]; then + export PASSED=1 + fi +} diff --git a/infra/packaging/chklist/TF2TFLITE_RUNNABLE b/infra/packaging/chklist/TF2TFLITE_RUNNABLE new file mode 100644 index 000000000..4c1239c33 --- /dev/null +++ b/infra/packaging/chklist/TF2TFLITE_RUNNABLE @@ -0,0 +1,13 @@ +#!/bin/bash + +function prepare() +{ + export QUESTION="Is it possible to run tf2tflite?" +} + +function run() +{ + if [[ $(ldd -r "${NNAS_INSTALL_PREFIX}/bin/tf2tflite" | grep '^undefined' | wc -l) -eq 0 ]]; then + export PASSED=1 + fi +} diff --git a/infra/packaging/preset/20191115 b/infra/packaging/preset/20191115 new file mode 100644 index 000000000..e2f6f8c73 --- /dev/null +++ b/infra/packaging/preset/20191115 @@ -0,0 +1,49 @@ +#!/bin/bash + +function preset_configure() +{ + REQUIRED_UNITS=() + # Common Libraries + REQUIRED_UNITS+=("angkor" "bino" "cwrap" "fipe" "pepper-str" "pepper-strcast" "pp" "stdex") + REQUIRED_UNITS+=("oops" "pepper-assert") + # Hermes Logging Framework + REQUIRED_UNITS+=("hermes" "hermes-std") + # loco IR and related utilities + REQUIRED_UNITS+=("loco" "locop" "locomotiv" "logo-core" "logo") + # loco IR extension: Custom Op Support + REQUIRED_UNITS+=("locoex-customop") + # TensorFlow Libraries + REQUIRED_UNITS+=("tfinfo" "plier-tf") + # TensorFlow GraphDef I/O + REQUIRED_UNITS+=("mio-tf") + # TensorFlow Frontend (.pb/.pbtxt -> loco.caninical) + REQUIRED_UNITS+=("moco-log" "moco" "moco-tf") + # TensorFlow Lite/Circle Backend (loco.canonical -> .tflite, loco.circle -> .circle) + REQUIRED_UNITS+=("exo") + # Tools + REQUIRED_UNITS+=("tf2tflite" "tf2circle") + + # TODO Use "nncc configure" and "nncc build" + cmake \ + -DCMAKE_INSTALL_PREFIX="${NNCC_INSTALL_PREFIX}" \ + -DCMAKE_BUILD_TYPE=release \ + -DBUILD_WHITELIST=$(join_by ";" "${REQUIRED_UNITS[@]}") \ + ${EXTRA_OPTIONS[@]} \ + "${NNAS_PROJECT_PATH}/infra/nncc" +} + +function preset_install() +{ + install -t "${NNPKG_INSTALL_PREFIX}/bin" -D \ + "${NNAS_PROJECT_PATH}/tools/nnpackage_tool/model2nnpkg/model2nnpkg.sh" \ + "${NNAS_PROJECT_PATH}/tools/nnpackage_tool/tflite2circle/tflite2circle.sh" \ + "${NNAS_PROJECT_PATH}/tools/nnpackage_tool/tflite2circle/tflitejson2circlejson.py" + + install -T -m 644 -D \ + "${SCRIPT_PATH}/res/tflite_schema.fbs" "${NNPKG_INSTALL_PREFIX}/res/tflite_schema.fbs" + install -T -m 644 -D \ + "${NNAS_PROJECT_PATH}/nnpackage/schema/circle_schema.fbs" "${NNPKG_INSTALL_PREFIX}/res/circle_schema.fbs" + + # Install tf2nnpkg + install -T -m 755 -D "${SCRIPT_PATH}/res/tf2nnpkg" "${NNAS_INSTALL_PREFIX}/bin/tf2nnpkg" +} diff --git a/infra/packaging/preset/20191215 b/infra/packaging/preset/20191215 new file mode 100644 index 000000000..980d729fc --- /dev/null +++ b/infra/packaging/preset/20191215 @@ -0,0 +1,42 @@ +#!/bin/bash + +function preset_configure() +{ + REQUIRED_UNITS=() + # Common Libraries + REQUIRED_UNITS+=("angkor" "bino" "cwrap" "fipe" "pepper-str" "pepper-strcast" "pp" "stdex") + REQUIRED_UNITS+=("oops" "pepper-assert") + # Hermes Logging Framework + REQUIRED_UNITS+=("hermes" "hermes-std") + # loco IR and related utilities + REQUIRED_UNITS+=("loco" "locop" "locomotiv" "logo-core" "logo") + # loco IR extension: Custom Op Support + REQUIRED_UNITS+=("locoex-customop") + # TensorFlow Libraries + REQUIRED_UNITS+=("tfinfo" "plier-tf") + # TensorFlow GraphDef I/O + REQUIRED_UNITS+=("mio-tf") + # TensorFlow Frontend (.pb/.pbtxt -> loco.caninical) + REQUIRED_UNITS+=("moco-log" "moco" "moco-tf") + # TensorFlow Lite/Circle Backend (loco.canonical -> .tflite, loco.circle -> .circle) + REQUIRED_UNITS+=("exo") + # Tools + REQUIRED_UNITS+=("tf2circle") + + # TODO Use "nncc configure" and "nncc build" + cmake \ + -DCMAKE_INSTALL_PREFIX="${NNCC_INSTALL_PREFIX}" \ + -DCMAKE_BUILD_TYPE=release \ + -DBUILD_WHITELIST=$(join_by ";" "${REQUIRED_UNITS[@]}") \ + ${EXTRA_OPTIONS[@]} \ + "${NNAS_PROJECT_PATH}/infra/nncc" +} + +function preset_install() +{ + install -t "${NNPKG_INSTALL_PREFIX}/bin" -D \ + "${NNAS_PROJECT_PATH}/tools/nnpackage_tool/model2nnpkg/model2nnpkg.sh" + + # Install tf2nnpkg + install -T -m 755 -D "${SCRIPT_PATH}/res/tf2nnpkg.20191215" "${NNAS_INSTALL_PREFIX}/bin/tf2nnpkg" +} diff --git a/infra/packaging/preset/20191231_windows b/infra/packaging/preset/20191231_windows new file mode 100644 index 000000000..7b511196f --- /dev/null +++ b/infra/packaging/preset/20191231_windows @@ -0,0 +1,51 @@ +#!/bin/bash + +function preset_configure() +{ + REQUIRED_UNITS=() + # Common Libraries + REQUIRED_UNITS+=("angkor" "bino" "cwrap" "fipe" "pepper-str" "pepper-strcast" "pp" "stdex") + REQUIRED_UNITS+=("oops" "pepper-assert") + # Hermes Logging Framework + REQUIRED_UNITS+=("hermes" "hermes-std") + # loco IR and related utilities + REQUIRED_UNITS+=("loco" "locop" "locomotiv" "logo-core" "logo") + # loco IR extension: Custom Op Support + REQUIRED_UNITS+=("locoex-customop") + # TensorFlow Libraries + REQUIRED_UNITS+=("tfinfo" "plier-tf") + # TensorFlow GraphDef I/O + REQUIRED_UNITS+=("mio-tf") + # TensorFlow Frontend (.pb/.pbtxt -> loco.caninical) + REQUIRED_UNITS+=("moco-log" "moco" "moco-tf") + # TensorFlow Lite/Circle Backend (loco.canonical -> .tflite, loco.circle -> .circle) + REQUIRED_UNITS+=("exo") + # Tools + REQUIRED_UNITS+=("tf2circle") + + # TODO Use "nncc configure" and "nncc build" + cmake \ + -G "MSYS Makefiles" \ + -DUSE_PROTOBUF_LEGACY_IMPORT=ON \ + -DCMAKE_EXE_LINKER_FLAGS="-Wl,--allow-multiple-definition" \ + -DCMAKE_SHARED_LINKER_FLAGS="-Wl,--allow-multiple-definition" \ + -DENABLE_TEST=OFF \ + -DDOWNLOAD_GTEST=OFF \ + -DBUILD_GTEST=OFF \ + -DCMAKE_C_COMPILER=gcc \ + -DCMAKE_CXX_COMPILER=g++ \ + -DCMAKE_INSTALL_PREFIX="${NNCC_INSTALL_PREFIX}" \ + -DCMAKE_BUILD_TYPE=release \ + -DBUILD_WHITELIST=$(join_by ";" "${REQUIRED_UNITS[@]}") \ + ${EXTRA_OPTIONS[@]} \ + "${NNAS_PROJECT_PATH}/infra/nncc" +} + +function preset_install() +{ + install -t "${NNPKG_INSTALL_PREFIX}/bin" -D \ + "${NNAS_PROJECT_PATH}/tools/nnpackage_tool/model2nnpkg/model2nnpkg.sh" + + # Install tf2nnpkg + install -T -m 755 -D "${SCRIPT_PATH}/res/tf2nnpkg.20191215" "${NNAS_INSTALL_PREFIX}/bin/tf2nnpkg" +} diff --git a/infra/packaging/preset/20200115_windows b/infra/packaging/preset/20200115_windows new file mode 100644 index 000000000..da349bb3a --- /dev/null +++ b/infra/packaging/preset/20200115_windows @@ -0,0 +1,50 @@ +#!/bin/bash + +function preset_configure() +{ + REQUIRED_UNITS=() + # Common Libraries + REQUIRED_UNITS+=("angkor" "bino" "cwrap" "fipe" "pepper-str" "pepper-strcast" "pp" "stdex") + REQUIRED_UNITS+=("oops" "pepper-assert") + # Hermes Logging Framework + REQUIRED_UNITS+=("hermes" "hermes-std") + # loco IR and related utilities + REQUIRED_UNITS+=("loco" "locop" "locomotiv" "logo-core" "logo") + # loco IR extension: Custom Op Support + REQUIRED_UNITS+=("locoex-customop") + # TensorFlow Libraries + REQUIRED_UNITS+=("tfinfo" "plier-tf") + # TensorFlow GraphDef I/O + REQUIRED_UNITS+=("mio-tf") + # TensorFlow Frontend (.pb/.pbtxt -> loco.caninical) + REQUIRED_UNITS+=("moco-log" "moco" "moco-tf") + # TensorFlow Lite/Circle Backend (loco.canonical -> .tflite, loco.circle -> .circle) + REQUIRED_UNITS+=("exo") + # Tools + REQUIRED_UNITS+=("tf2nnpkg") + + # TODO Use "nncc configure" and "nncc build" + cmake \ + -G "MSYS Makefiles" \ + -DTF2NNPKG_FOR_WINDOWS=ON \ + -DUSE_PROTOBUF_LEGACY_IMPORT=ON \ + -DCMAKE_EXE_LINKER_FLAGS="-Wl,--allow-multiple-definition" \ + -DCMAKE_SHARED_LINKER_FLAGS="-Wl,--allow-multiple-definition" \ + -DENABLE_TEST=OFF \ + -DDOWNLOAD_GTEST=OFF \ + -DBUILD_GTEST=OFF \ + -DCMAKE_C_COMPILER=gcc \ + -DCMAKE_CXX_COMPILER=g++ \ + -DCMAKE_INSTALL_PREFIX="${NNCC_INSTALL_PREFIX}" \ + -DCMAKE_BUILD_TYPE=release \ + -DBUILD_WHITELIST=$(join_by ";" "${REQUIRED_UNITS[@]}") \ + ${EXTRA_OPTIONS[@]} \ + "${NNAS_PROJECT_PATH}/infra/nncc" +} + +function preset_install() +{ + # Install libraries to bin/ for Windows release + mv ${NNCC_INSTALL_PREFIX}/lib/*.dll ${NNCC_INSTALL_PREFIX}/bin + rm -rf ${NNCC_INSTALL_PREFIX}/lib +} diff --git a/infra/packaging/res/tf2nnpkg b/infra/packaging/res/tf2nnpkg new file mode 100644 index 000000000..c300eb856 --- /dev/null +++ b/infra/packaging/res/tf2nnpkg @@ -0,0 +1,87 @@ +#!/bin/bash + +set -e + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" + +command_exists() { + if [ "$#" -le 0 ]; then + return 1 + fi + command -v "$@" > /dev/null 2>&1 +} + +usage() +{ + echo "Usage: tf2nnpkg --info <path/to/info> --graphdef <path/to/pb> -o <path/to/nnpkg/directory>" + exit 0 +} + +USE_TF2CIRCLE=0 + +# Parse command-line arguments +# +while [ "$#" -ne 0 ]; do + CUR="$1" + + case $CUR in + '--help') + usage + ;; + '--info') + export INFO_FILE="$2" + shift 2 + ;; + '--graphdef') + export GRAPHDEF_FILE="$2" + shift 2 + ;; + '-o') + export OUTPUT_DIR="$2" + shift 2 + ;; + '--use-tf2circle') + USE_TF2CIRCLE=1 + shift 1 + ;; + *) + echo "${CUR}" + shift + ;; + esac +done + +if [ -z ${GRAPHDEF_FILE} ] || [ ! -e ${GRAPHDEF_FILE} ]; then + echo "pb is not found. Please check --graphdef is correct." + exit 2 +fi + +if [ -z ${INFO_FILE} ] || [ ! -e ${INFO_FILE} ]; then + echo "info is not found. Please check --info is correct." + exit 2 +fi + +FILE_BASE=$(basename ${GRAPHDEF_FILE}) +MODEL_NAME="${FILE_BASE%.*}" + +if [[ ${USE_TF2CIRCLE} -eq 0 ]]; then + export flatc=$(which flatc) + export tflite_schema="${ROOT}/res/tflite_schema.fbs" + export circle_schema="${ROOT}/res/circle_schema.fbs" + + if ! command_exists $flatc; then + echo "Please make sure flatc is in path" + exit 2 + fi +fi + +TMPDIR=$(mktemp -d) +trap "{ rm -rf $TMPDIR; }" EXIT + +if [[ ${USE_TF2CIRCLE} -eq 0 ]]; then + "${ROOT}/bin/tf2tflite" "${INFO_FILE}" "${GRAPHDEF_FILE}" "${TMPDIR}/${MODEL_NAME}.tflite" + "${ROOT}/bin/tflite2circle.sh" -o "${TMPDIR}" "${TMPDIR}/${MODEL_NAME}.tflite" +else + "${ROOT}/bin/tf2circle" "${INFO_FILE}" "${GRAPHDEF_FILE}" "${TMPDIR}/${MODEL_NAME}.circle" +fi +"${ROOT}/bin/model2nnpkg.sh" -o "${OUTPUT_DIR}" "${TMPDIR}/${MODEL_NAME}.circle" diff --git a/infra/packaging/res/tf2nnpkg.20191215 b/infra/packaging/res/tf2nnpkg.20191215 new file mode 100644 index 000000000..d334a908d --- /dev/null +++ b/infra/packaging/res/tf2nnpkg.20191215 @@ -0,0 +1,68 @@ +#!/bin/bash + +set -e + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" + +command_exists() { + if [ "$#" -le 0 ]; then + return 1 + fi + command -v "$@" > /dev/null 2>&1 +} + +usage() +{ + echo "Usage: tf2nnpkg --info <path/to/info> --graphdef <path/to/pb> -o <path/to/nnpkg/directory>" + exit 0 +} + +# Parse command-line arguments +# +while [ "$#" -ne 0 ]; do + CUR="$1" + + case $CUR in + '--help') + usage + ;; + '--info') + export INFO_FILE="$2" + shift 2 + ;; + '--graphdef') + export GRAPHDEF_FILE="$2" + shift 2 + ;; + '-o') + export OUTPUT_DIR="$2" + shift 2 + ;; + '--use-tf2circle') + echo "WARNING! --use-tf2circle is deprecated" + shift 1 + ;; + *) + echo "${CUR}" + shift + ;; + esac +done + +if [ -z ${GRAPHDEF_FILE} ] || [ ! -e ${GRAPHDEF_FILE} ]; then + echo "pb is not found. Please check --graphdef is correct." + exit 2 +fi + +if [ -z ${INFO_FILE} ] || [ ! -e ${INFO_FILE} ]; then + echo "info is not found. Please check --info is correct." + exit 2 +fi + +FILE_BASE=$(basename ${GRAPHDEF_FILE}) +MODEL_NAME="${FILE_BASE%.*}" +TMPDIR=$(mktemp -d) +trap "{ rm -rf $TMPDIR; }" EXIT + +"${ROOT}/bin/tf2circle" "${INFO_FILE}" "${GRAPHDEF_FILE}" "${TMPDIR}/${MODEL_NAME}.circle" +"${ROOT}/bin/model2nnpkg.sh" -o "${OUTPUT_DIR}" "${TMPDIR}/${MODEL_NAME}.circle" diff --git a/infra/packaging/res/tflite_schema.fbs b/infra/packaging/res/tflite_schema.fbs new file mode 100644 index 000000000..3da3188c3 --- /dev/null +++ b/infra/packaging/res/tflite_schema.fbs @@ -0,0 +1,698 @@ +// Copyright 2017 The TensorFlow Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Revision History +// Version 0: Initial version. +// Version 1: Add subgraphs to schema. +// Version 2: Rename operators to conform to NN API. +// Version 3: Move buffer data from Model.Subgraph.Tensors to Model.Buffers. + +namespace tflite; + +// This corresponds to the version. +file_identifier "TFL3"; +// File extension of any written files. +file_extension "tflite"; + +// The type of data stored in a tensor. +enum TensorType : byte { + FLOAT32 = 0, + FLOAT16 = 1, + INT32 = 2, + UINT8 = 3, + INT64 = 4, + STRING = 5, + BOOL = 6, + INT16 = 7, + COMPLEX64 = 8, +} + +// Parameters for converting a quantized tensor back to float. Given a +// quantized value q, the corresponding float value f should be: +// f = scale * (q - zero_point) +table QuantizationParameters { + min:[float]; // For importing back into tensorflow. + max:[float]; // For importing back into tensorflow. + scale:[float]; // For dequantizing the tensor's values. + zero_point:[long]; +} + +table Tensor { + // The tensor shape. The meaning of each entry is operator-specific but + // builtin ops use: [batch size, height, width, number of channels] (That's + // Tensorflow's NHWC). + shape:[int]; + type:TensorType; + // An index that refers to the buffers table at the root of the model. Or, + // if there is no data buffer associated (i.e. intermediate results), then + // this is 0 (which refers to an always existent empty buffer). + // + // The data_buffer itself is an opaque container, with the assumption that the + // target device is little-endian. In addition, all builtin operators assume + // the memory is ordered such that if `shape` is [4, 3, 2], then index + // [i, j, k] maps to data_buffer[i*3*2 + j*2 + k]. + buffer:uint; + name:string; // For debugging and importing back into tensorflow. + quantization:QuantizationParameters; // Optional. + + is_variable:bool = false; +} + +// A list of builtin operators. Builtin operators are slightly faster than custom +// ones, but not by much. Moreover, while custom operators accept an opaque +// object containing configuration parameters, builtins have a predetermined +// set of acceptable options. +enum BuiltinOperator : byte { + ADD = 0, + AVERAGE_POOL_2D = 1, + CONCATENATION = 2, + CONV_2D = 3, + DEPTHWISE_CONV_2D = 4, + // DEPTH_TO_SPACE = 5, + DEQUANTIZE = 6, + EMBEDDING_LOOKUP = 7, + FLOOR = 8, + FULLY_CONNECTED = 9, + HASHTABLE_LOOKUP = 10, + L2_NORMALIZATION = 11, + L2_POOL_2D = 12, + LOCAL_RESPONSE_NORMALIZATION = 13, + LOGISTIC = 14, + LSH_PROJECTION = 15, + LSTM = 16, + MAX_POOL_2D = 17, + MUL = 18, + RELU = 19, + // NOTE(aselle): RELU_N1_TO_1 used to be called RELU1, but it was renamed + // since different model developers use RELU1 in different ways. Never + // create another op called RELU1. + RELU_N1_TO_1 = 20, + RELU6 = 21, + RESHAPE = 22, + RESIZE_BILINEAR = 23, + RNN = 24, + SOFTMAX = 25, + SPACE_TO_DEPTH = 26, + SVDF = 27, + TANH = 28, + // TODO(aselle): Consider rename to CONCATENATE_EMBEDDINGS + CONCAT_EMBEDDINGS = 29, + SKIP_GRAM = 30, + CALL = 31, + CUSTOM = 32, + EMBEDDING_LOOKUP_SPARSE = 33, + PAD = 34, + UNIDIRECTIONAL_SEQUENCE_RNN = 35, + GATHER = 36, + BATCH_TO_SPACE_ND = 37, + SPACE_TO_BATCH_ND = 38, + TRANSPOSE = 39, + MEAN = 40, + SUB = 41, + DIV = 42, + SQUEEZE = 43, + UNIDIRECTIONAL_SEQUENCE_LSTM = 44, + STRIDED_SLICE = 45, + BIDIRECTIONAL_SEQUENCE_RNN = 46, + EXP = 47, + TOPK_V2 = 48, + SPLIT = 49, + LOG_SOFTMAX = 50, + // DELEGATE is a special op type for the operations which are delegated to + // other backends. + // WARNING: Experimental interface, subject to change + DELEGATE = 51, + BIDIRECTIONAL_SEQUENCE_LSTM = 52, + CAST = 53, + PRELU = 54, + MAXIMUM = 55, + ARG_MAX = 56, + MINIMUM = 57, + LESS = 58, + NEG = 59, + PADV2 = 60, + GREATER = 61, + GREATER_EQUAL = 62, + LESS_EQUAL = 63, + SELECT = 64, + SLICE = 65, + SIN = 66, + TRANSPOSE_CONV = 67, + SPARSE_TO_DENSE = 68, + TILE = 69, + EXPAND_DIMS = 70, + EQUAL = 71, + NOT_EQUAL = 72, + LOG = 73, + SUM = 74, + SQRT = 75, + RSQRT = 76, + SHAPE = 77, + POW = 78, + ARG_MIN = 79, + FAKE_QUANT = 80, + REDUCE_PROD = 81, + REDUCE_MAX = 82, + PACK = 83, + LOGICAL_OR = 84, + ONE_HOT = 85, + LOGICAL_AND = 86, + LOGICAL_NOT = 87, + UNPACK = 88, + REDUCE_MIN = 89, + FLOOR_DIV = 90, + REDUCE_ANY = 91, + SQUARE = 92, + ZEROS_LIKE = 93, + FILL = 94, +} + +// Options for the builtin operators. +union BuiltinOptions { + Conv2DOptions, + DepthwiseConv2DOptions, + ConcatEmbeddingsOptions, + LSHProjectionOptions, + Pool2DOptions, + SVDFOptions, + RNNOptions, + FullyConnectedOptions, + SoftmaxOptions, + ConcatenationOptions, + AddOptions, + L2NormOptions, + LocalResponseNormalizationOptions, + LSTMOptions, + ResizeBilinearOptions, + CallOptions, + ReshapeOptions, + SkipGramOptions, + SpaceToDepthOptions, + EmbeddingLookupSparseOptions, + MulOptions, + PadOptions, + GatherOptions, + BatchToSpaceNDOptions, + SpaceToBatchNDOptions, + TransposeOptions, + ReducerOptions, + SubOptions, + DivOptions, + SqueezeOptions, + SequenceRNNOptions, + StridedSliceOptions, + ExpOptions, + TopKV2Options, + SplitOptions, + LogSoftmaxOptions, + CastOptions, + DequantizeOptions, + MaximumMinimumOptions, + ArgMaxOptions, + LessOptions, + NegOptions, + PadV2Options, + GreaterOptions, + GreaterEqualOptions, + LessEqualOptions, + SelectOptions, + SliceOptions, + TransposeConvOptions, + SparseToDenseOptions, + TileOptions, + ExpandDimsOptions, + EqualOptions, + NotEqualOptions, + ShapeOptions, + PowOptions, + ArgMinOptions, + FakeQuantOptions, + PackOptions, + LogicalOrOptions, + OneHotOptions, + LogicalAndOptions, + LogicalNotOptions, + UnpackOptions, + FloorDivOptions, + SquareOptions, + ZerosLikeOptions, + FillOptions, +} + +enum Padding : byte { SAME, VALID } + +enum ActivationFunctionType : byte { + NONE = 0, + RELU = 1, + RELU_N1_TO_1 = 2, + RELU6 = 3, + TANH = 4, + SIGN_BIT = 5, +} + +table Conv2DOptions { + padding:Padding; + stride_w:int; + stride_h:int; + fused_activation_function:ActivationFunctionType; + dilation_w_factor:int = 1; + dilation_h_factor:int = 1; +} + +table Pool2DOptions { + padding:Padding; + stride_w:int; + stride_h:int; + filter_width:int; + filter_height:int; + fused_activation_function:ActivationFunctionType; +} + +table DepthwiseConv2DOptions { + // Parameters for DepthwiseConv version 1 or above. + padding:Padding; + stride_w:int; + stride_h:int; + depth_multiplier:int; + fused_activation_function:ActivationFunctionType; + // Parameters for DepthwiseConv version 2 or above. + dilation_w_factor:int = 1; + dilation_h_factor:int = 1; +} + +table ConcatEmbeddingsOptions { + num_channels:int; + num_columns_per_channel:[int]; + embedding_dim_per_channel:[int]; // This could be inferred from parameters. +} + +enum LSHProjectionType: byte { + UNKNOWN = 0, + SPARSE = 1, + DENSE = 2, +} + +table LSHProjectionOptions { + type: LSHProjectionType; +} + +table SVDFOptions { + rank:int; + fused_activation_function:ActivationFunctionType; +} + +// An implementation of TensorFlow RNNCell. +table RNNOptions { + fused_activation_function:ActivationFunctionType; +} + +// An implementation of TensorFlow dynamic_rnn with RNNCell. +table SequenceRNNOptions { + time_major:bool; + fused_activation_function:ActivationFunctionType; +} + +// An implementation of TensorFlow bidrectional_dynamic_rnn with RNNCell. +table BidirectionalSequenceRNNOptions { + time_major:bool; + fused_activation_function:ActivationFunctionType; +} + +enum FullyConnectedOptionsWeightsFormat: byte { + DEFAULT = 0, + SHUFFLED4x16INT8 = 1, +} + +// An implementation of TensorFlow fully_connected (a.k.a Dense) layer. +table FullyConnectedOptions { + // Parameters for FullyConnected version 1 or above. + fused_activation_function:ActivationFunctionType; + + // Parameters for FullyConnected version 2 or above. + weights_format:FullyConnectedOptionsWeightsFormat = DEFAULT; +} + +table SoftmaxOptions { + beta: float; +} + +// An implementation of TensorFlow concat. +table ConcatenationOptions { + axis:int; + fused_activation_function:ActivationFunctionType; +} + +table AddOptions { + fused_activation_function:ActivationFunctionType; +} + +table MulOptions { + fused_activation_function:ActivationFunctionType; +} + +table L2NormOptions { + fused_activation_function:ActivationFunctionType; +} + +table LocalResponseNormalizationOptions { + radius:int; + bias:float; + alpha:float; + beta:float; +} + +enum LSTMKernelType : byte { + // Full LSTM kernel which supports peephole and projection. + FULL = 0, + // Basic LSTM kernels. Equivalent to TensorFlow BasicLSTMCell. + BASIC = 1, +} + +// An implementation of TensorFlow LSTMCell and CoupledInputForgetGateLSTMCell +table LSTMOptions { + // Parameters for LSTM version 1 or above. + fused_activation_function:ActivationFunctionType; + cell_clip: float; // Optional, 0.0 means no clipping + proj_clip: float; // Optional, 0.0 means no clipping + + // Parameters for LSTM version 2 or above. + // Basic kernel is only supported in version 2 or above. + kernel_type: LSTMKernelType = FULL; +} + +table ResizeBilinearOptions { + new_height: int (deprecated); + new_width: int (deprecated); + align_corners: bool; +} + +// A call operation options +table CallOptions { + // The subgraph index that needs to be called. + subgraph:uint; +} + +table PadOptions { +} + +table PadV2Options { +} + +table ReshapeOptions { + new_shape:[int]; +} + +table SpaceToBatchNDOptions { +} + +table BatchToSpaceNDOptions { +} + +table SkipGramOptions { + ngram_size: int; + max_skip_size: int; + include_all_ngrams: bool; +} + +table SpaceToDepthOptions { + block_size: int; +} + +table SubOptions { + fused_activation_function:ActivationFunctionType; +} + +table DivOptions { + fused_activation_function:ActivationFunctionType; +} + +table TopKV2Options { +} + +enum CombinerType : byte { + SUM = 0, + MEAN = 1, + SQRTN = 2, +} + +table EmbeddingLookupSparseOptions { + combiner:CombinerType; +} + +table GatherOptions { + axis: int; +} + +table TransposeOptions { +} + +table ExpOptions { +} + +table ReducerOptions { + keep_dims: bool; +} + +table SqueezeOptions { + squeeze_dims:[int]; +} + +table SplitOptions { + num_splits: int; +} + +table StridedSliceOptions { + begin_mask: int; + end_mask: int; + ellipsis_mask: int; + new_axis_mask: int; + shrink_axis_mask: int; +} + +table LogSoftmaxOptions { +} + +table CastOptions { + in_data_type: TensorType; + out_data_type: TensorType; +} + +table DequantizeOptions { +} + +table MaximumMinimumOptions { +} + +table TileOptions { +} + +table ArgMaxOptions { + output_type : TensorType; +} + +table ArgMinOptions { + output_type : TensorType; +} + +table GreaterOptions { +} + +table GreaterEqualOptions { +} + +table LessOptions { +} + +table LessEqualOptions { +} + +table NegOptions { +} + +table SelectOptions { +} + +table SliceOptions { +} + +table TransposeConvOptions { + padding:Padding; + stride_w:int; + stride_h:int; +} + +table ExpandDimsOptions { +} + +table SparseToDenseOptions { + validate_indices:bool; +} + +table EqualOptions { +} + +table NotEqualOptions { +} + +table ShapeOptions { + // Optional output type of the operation (int32 or int64). Defaults to int32. + out_type : TensorType; +} + +table PowOptions { +} + +table FakeQuantOptions { + // Parameters supported by version 1: + min:float; + max:float; + num_bits:int; + + // Parameters supported by version 2: + narrow_range:bool; +} + +table PackOptions { + values_count:int; + axis:int; +} + +table LogicalOrOptions { +} + +table OneHotOptions { + axis:int; +} + +table LogicalAndOptions { +} + +table LogicalNotOptions { +} + +table UnpackOptions { + num:int; + axis:int; +} + +table FloorDivOptions { +} + +table SquareOptions { +} + +table ZerosLikeOptions { +} + +table FillOptions { +} + +// An OperatorCode can be an enum value (BuiltinOperator) if the operator is a +// builtin, or a string if the operator is custom. +table OperatorCode { + builtin_code:BuiltinOperator; + custom_code:string; + + // The version of the operator. The version need to be bumped whenever new + // parameters are introduced into an op. + version:int = 1; +} + +enum CustomOptionsFormat : byte { + FLEXBUFFERS = 0, +} + +// An operator takes tensors as inputs and outputs. The type of operation being +// performed is determined by an index into the list of valid OperatorCodes, +// while the specifics of each operations is configured using builtin_options +// or custom_options. +table Operator { + // Index into the operator_codes array. Using an integer here avoids + // complicate map lookups. + opcode_index:uint; + + // Optional input and output tensors are indicated by -1. + inputs:[int]; + outputs:[int]; + + builtin_options:BuiltinOptions; + custom_options:[ubyte]; + custom_options_format:CustomOptionsFormat; + + // A list of booleans indicating the input tensors which are being mutated by + // this operator.(e.g. used by RNN and LSTM). + // For example, if the "inputs" array refers to 5 tensors and the second and + // fifth are mutable variables, then this list will contain + // [false, true, false, false, true]. + // + // If the list is empty, no variable is mutated in this operator. + // The list either has the same length as `inputs`, or is empty. + mutating_variable_inputs:[bool]; +} + +// The root type, defining a subgraph, which typically represents an entire +// model. +table SubGraph { + // A list of all tensors used in this subgraph. + tensors:[Tensor]; + + // Indices of the tensors that are inputs into this subgraph. Note this is + // the list of non-static tensors that feed into the subgraph for inference. + inputs:[int]; + + // Indices of the tensors that are outputs out of this subgraph. Note this is + // the list of output tensors that are considered the product of the + // subgraph's inference. + outputs:[int]; + + // All operators, in execution order. + operators:[Operator]; + + // Name of this subgraph (used for debugging). + name:string; +} + +// Table of raw data buffers (used for constant tensors). Referenced by tensors +// by index. The generous alignment accommodates mmap-friendly data structures. +table Buffer { + data:[ubyte] (force_align: 16); +} + +table Model { + // Version of the schema. + version:uint; + + // A list of all operator codes used in this model. This is + // kept in order because operators carry an index into this + // vector. + operator_codes:[OperatorCode]; + + // All the subgraphs of the model. The 0th is assumed to be the main + // model. + subgraphs:[SubGraph]; + + // A description of the model. + description:string; + + // Buffers of the model. + // Note the 0th entry of this array must be an empty buffer (sentinel). + // This is a convention so that tensors without a buffer can provide 0 as + // their buffer. + buffers:[Buffer]; + + // Metadata about the model. Indirects into the existings buffers list. + metadata_buffer:[int]; +} + +root_type Model; diff --git a/infra/packaging/verify b/infra/packaging/verify new file mode 100644 index 000000000..4d5e610af --- /dev/null +++ b/infra/packaging/verify @@ -0,0 +1,82 @@ +#!/bin/bash + +# +# HOW TO USE +# +# ./nnas verify-package [CHECK 1] [CHECK 2] ... [CHECK N] +# +# REQUIRE: N >= 1 +# +SCRIPT_PATH="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +if [[ -z "${NNAS_PROJECT_PATH}" ]]; then + echo "ERROR: NNAS_PROJECT_PATH is not specified" + exit 255 +fi + +CHECKLIST=() + +while [ "$#" -ne 0 ]; do + CUR="$1" + + case $CUR in + '--prefix') + NNAS_INSTALL_PREFIX="$2" + shift 2 + ;; + *) + if [[ ! -f "${SCRIPT_PATH}/chklist/$CUR" ]]; then + echo "ERROR: '${CUR}' is invalid" + # TODO Show supported checks + exit 255 + fi + + CHECKLIST+=("${CUR}") + shift 1 + ;; + esac +done + +# Q. Is it better to have the default value for NNAS_INSTALL_PREFIX? +# TODO Show USAGE +# TODO Use a proper exitcode on error (http://tldp.org/LDP/abs/html/exitcodes.html) +if [[ -z "${NNAS_INSTALL_PREFIX}" ]]; then + echo "ERROR: --prefix is not specified" + exit 255 +fi + +if [[ ${#CHECKLIST[@]} -eq 0 ]]; then + echo "ERROR: Check is not specified" + exit 255 +fi + +EXITCODE=0 + +for CHECK_NAME in ${CHECKLIST[@]}; do + source "${SCRIPT_PATH}/chklist/${CHECK_NAME}" + + prepare + + echo -n "${QUESTION}" + + PASSED=0 + + run + + if [[ ${PASSED} -ne 0 ]]; then + ANSWER="Yes" + else + ANSWER="No" + # Reference: https://www.tldp.org/LDP/abs/html/exitcodes.html + EXITCODE=1 + fi + + echo " - ${ANSWER}" +done + +if [[ ${EXITCODE} -ne 0 ]]; then + echo + echo "FAIL" +fi + +exit ${EXITCODE} |