diff --git a/.clang-format-include b/.clang-format-include index 63e032dc5d8..9d49d8aba2d 100644 --- a/.clang-format-include +++ b/.clang-format-include @@ -2,6 +2,7 @@ # enforcement in the CI. src/gallium/drivers/i915 +src/gallium/targets/teflon/**/* src/amd/vulkan/**/* src/amd/compiler/**/* src/egl/**/* diff --git a/.gitlab-ci/build/gitlab-ci.yml b/.gitlab-ci/build/gitlab-ci.yml index 0c31760045a..acff5ed641d 100644 --- a/.gitlab-ci/build/gitlab-ci.yml +++ b/.gitlab-ci/build/gitlab-ci.yml @@ -267,6 +267,7 @@ fedora-release: -D vulkan-layers=device-select,overlay -D intel-clc=enabled -D imagination-srv=true + -D teflon=true GALLIUM_DRIVERS: "crocus,etnaviv,freedreno,i915,iris,kmsro,lima,nouveau,panfrost,r300,r600,radeonsi,svga,swrast,tegra,v3d,vc4,virgl,zink" GALLIUM_ST: > -D dri3=enabled @@ -416,6 +417,7 @@ debian-arm64: -D imagination-srv=true -D perfetto=true -D freedreno-kmds=msm,virtio + -D teflon=true S3_ARTIFACT_NAME: mesa-arm64-default-${BUILDTYPE} script: - .gitlab-ci/meson/build.sh @@ -507,6 +509,7 @@ debian-clang: -D build-aco-tests=true -D intel-clc=enabled -D imagination-srv=true + -D teflon=true CC: clang-${LLVM_VERSION} CXX: clang++-${LLVM_VERSION} diff --git a/.gitlab-ci/container/debian/arm64_build.sh b/.gitlab-ci/container/debian/arm64_build.sh index 54a18558a99..07f2a0be2ee 100644 --- a/.gitlab-ci/container/debian/arm64_build.sh +++ b/.gitlab-ci/container/debian/arm64_build.sh @@ -27,6 +27,7 @@ DEPS=( cmake curl fastboot + flatbuffers-compiler flex g++ git @@ -36,6 +37,7 @@ DEPS=( libdrm-dev libelf-dev libexpat1-dev + libflatbuffers-dev libvulkan-dev libx11-dev libx11-xcb-dev @@ -50,6 +52,7 @@ DEPS=( libxext-dev libxrandr-dev libxshmfence-dev + libxtensor-dev libxxf86vm-dev libwayland-dev libwayland-egl-backend-dev diff --git a/.gitlab-ci/container/debian/x86_64_build-base.sh b/.gitlab-ci/container/debian/x86_64_build-base.sh index bb451fcdf82..641fa63b648 100644 --- a/.gitlab-ci/container/debian/x86_64_build-base.sh +++ b/.gitlab-ci/container/debian/x86_64_build-base.sh @@ -29,6 +29,7 @@ DEPS=( dpkg-cross findutils flex + flatbuffers-compiler g++ cmake gcc @@ -41,6 +42,7 @@ DEPS=( libelf-dev libepoxy-dev libexpat1-dev + libflatbuffers-dev libgtk-3-dev "libllvm${LLVM_VERSION}" libomxil-bellagio-dev @@ -56,6 +58,7 @@ DEPS=( libxrandr-dev libxrender-dev libxshmfence-dev + libxtensor-dev libxxf86vm-dev libwayland-egl-backend-dev make diff --git a/.gitlab-ci/container/fedora/x86_64_build.sh b/.gitlab-ci/container/fedora/x86_64_build.sh index 72c0235e4d7..9ddaf06ff56 100644 --- a/.gitlab-ci/container/fedora/x86_64_build.sh +++ b/.gitlab-ci/container/fedora/x86_64_build.sh @@ -30,6 +30,7 @@ DEPS=( ccache clang-devel flex + flatbuffers-compiler gcc gcc-c++ gettext @@ -41,6 +42,7 @@ DEPS=( "pkgconfig(SPIRV-Tools)" "pkgconfig(dri2proto)" "pkgconfig(expat)" + "pkgconfig(flatbuffers)" "pkgconfig(glproto)" "pkgconfig(libclc)" "pkgconfig(libelf)" @@ -66,6 +68,7 @@ DEPS=( "pkgconfig(xfixes)" "pkgconfig(xrandr)" "pkgconfig(xshmfence)" + "pkgconfig(xtensor)" "pkgconfig(xxf86vm)" "pkgconfig(zlib)" procps-ng diff --git a/.gitlab-ci/image-tags.yml b/.gitlab-ci/image-tags.yml index ebe4c9b96d2..18f14a2dd21 100644 --- a/.gitlab-ci/image-tags.yml +++ b/.gitlab-ci/image-tags.yml @@ -7,7 +7,7 @@ variables: DEBIAN_X86_64_BUILD_BASE_IMAGE: "debian/x86_64_build-base" - DEBIAN_BASE_TAG: "2024-01-14-runner" + DEBIAN_BASE_TAG: "2024-01-23-teflon-3" DEBIAN_X86_64_BUILD_IMAGE_PATH: "debian/x86_64_build" DEBIAN_BUILD_TAG: "2024-01-04-find" @@ -24,7 +24,7 @@ variables: ALPINE_X86_64_BUILD_TAG: "2023-01-07-libdrm2_4_119" ALPINE_X86_64_LAVA_SSH_TAG: "2023-06-26-first-version" - FEDORA_X86_64_BUILD_TAG: "2024-01-06-libdrm" + FEDORA_X86_64_BUILD_TAG: "2024-01-23-teflon-3" KERNEL_ROOTFS_TAG: "2024-01-19-zlib" KERNEL_TAG: "v6.6.12-for-mesa-ci-5a92d0709d0b" KERNEL_REPO: "gfx-ci/linux" diff --git a/.gitlab-ci/test-source-dep.yml b/.gitlab-ci/test-source-dep.yml index bee4d9c5772..c715a0afe47 100644 --- a/.gitlab-ci/test-source-dep.yml +++ b/.gitlab-ci/test-source-dep.yml @@ -254,6 +254,7 @@ - src/amd/vulkan/**/* - src/amd/compiler/**/* - src/etnaviv/isa/**/* + - src/gallium/targets/teflon/**/* when: on_success allow_failure: false # in other pipelines, formatting checks are allowed to fail diff --git a/docs/index.rst b/docs/index.rst index 3fc5959a1b8..551320be8b9 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -76,6 +76,7 @@ Linux, FreeBSD, and other operating systems. gallium-nine viewperf xlibdriver + teflon .. toctree:: :maxdepth: 1 diff --git a/docs/teflon.rst b/docs/teflon.rst new file mode 100644 index 00000000000..9b5599e577c --- /dev/null +++ b/docs/teflon.rst @@ -0,0 +1,140 @@ +TensorFlow Lite delegate +======================== + +Mesa contains a TensorFlow Lite delegate that can make use of NPUs to accelerate ML inference. It is implemented in the form of a *external delegate*, a shared library that the TensorFlow Lite runtime can load at startup. See https://www.tensorflow.org/api_docs/python/tf/lite/experimental/load_delegate. + +.. list-table:: Supported acceleration hardware + :header-rows: 1 + + * - Gallium driver + - NPU supported + - Hardware tested + * - Etnaviv + - ``VeriSilicon VIPNano-QI.7120`` + - ``Amlogic A311D on Libre Computer AML-A311D-CC Alta and Khadas VIM3`` + +Build +----- + +Build Mesa as usual, with the -Dteflon=true argument. + +Example instructions: + +.. code-block:: console + + # Install build dependencies + ~ # apt-get -y build-dep mesa + ~ # apt-get -y install git cmake + + # Download sources + ~ $ git clone https://gitlab.freedesktop.org/mesa/mesa.git + + # Build Mesa + ~ $ cd mesa + mesa $ meson setup build -Dgallium-drivers=etnaviv -Dvulkan-drivers= -Dteflon=true + mesa $ meson compile -C build + +Install runtime dependencies +---------------------------- + +Your board should have booted into a mainline 6.7 or greater kernel and have the etnaviv driver loaded. You will also need to enable the NPU device in the device tree by means of an overlay or by a change such as the below (and rebuild the DTB): + +.. code-block:: diff + + diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b-a311d-khadas-vim3.dts b/arch/arm64/boot/dts/amlogic/meson-g12b-a311d-khadas-vim3.dts + index 4aa2b20bfbf2..4e8266056bca 100644 + --- a/arch/arm64/boot/dts/amlogic/meson-g12b-a311d-khadas-vim3.dts + +++ b/arch/arm64/boot/dts/amlogic/meson-g12b-a311d-khadas-vim3.dts + @@ -50,6 +50,10 @@ galcore { + }; + }; + + +&npu { + + status = "okay"; + +}; + + + /* + * The VIM3 on-board MCU can mux the PCIe/USB3.0 shared differential + * lines using a FUSB340TMX USB 3.1 SuperSpeed Data Switch between + + +.. code-block:: console + + # Install Python 3.10 and dependencies (as root) + ~ # echo deb-src http://deb.debian.org/debian testing main >> /etc/apt/sources.list + ~ # echo deb http://deb.debian.org/debian unstable main >> /etc/apt/sources.list + ~ # echo 'APT::Default-Release "testing";' >> /etc/apt/apt.conf + ~ # apt-get update + ~ # apt-get -y install python3.10 python3-pytest python3-exceptiongroup + + # Install TensorFlow Lite Python package (as non-root) + ~ $ python3.10 -m pip install --break-system-packages tflite-runtime==2.13.0 + +Do some inference with MobileNetV1 +---------------------------------- + +.. code-block:: console + + ~ $ cd mesa/ + mesa $ TEFLON_DEBUG=verbose ETNA_MESA_DEBUG=ml_dbgs python3.10 src/gallium/frontends/teflon/tests/classification.py -i ~/tensorflow/assets/grace_hopper.bmp -m src/gallium/targets/teflon/tests/mobilenet_v1_1.0_224_quant.tflite -l src/gallium/frontends/teflon/tests/labels_mobilenet_quant_v1_224.txt -e build/src/gallium/targets/teflon/libteflon.so + + Loading external delegate from build/src/gallium/targets/teflon/libteflon.so with args: {} + Teflon delegate: loaded etnaviv driver + + teflon: compiling graph: 89 tensors 28 operations + idx scale zp has_data size + ======================================= + 0 0.023528 0 no 1x1x1x1024 + 1 0.166099 42 no 1x1x1x1001 + 2 0.000117 0 yes 1001x0x0x0 + 3 0.004987 4a yes 1001x1x1x1024 + 4 0.166099 42 no 1x1001x0x0 + 5 0.166099 42 yes 2x0x0x0 + 6 0.000171 0 yes 32x0x0x0 + 7 0.023528 0 no 1x112x112x32 + 8 0.021827 97 yes 32x3x3x3 + 9 0.023528 0 no 1x14x14x512 + ... + + idx type in out operation type-specific + ================================================================================================ + 0 CONV 88 7 w: 8 b: 6 stride: 2 pad: SAME + 1 DWCONV 7 33 w: 35 b: 34 stride: 1 pad: SAME + 2 CONV 33 37 w: 38 b: 36 stride: 1 pad: SAME + 3 DWCONV 37 39 w: 41 b: 40 stride: 2 pad: SAME + 4 CONV 39 43 w: 44 b: 42 stride: 1 pad: SAME + 5 DWCONV 43 45 w: 47 b: 46 stride: 1 pad: SAME + 6 CONV 45 49 w: 50 b: 48 stride: 1 pad: SAME + 7 DWCONV 49 51 w: 53 b: 52 stride: 2 pad: SAME + 8 CONV 51 55 w: 56 b: 54 stride: 1 pad: SAME + 9 DWCONV 55 57 w: 59 b: 58 stride: 1 pad: SAME + 10 CONV 57 61 w: 62 b: 60 stride: 1 pad: SAME + 11 DWCONV 61 63 w: 65 b: 64 stride: 2 pad: SAME + 12 CONV 63 67 w: 68 b: 66 stride: 1 pad: SAME + 13 DWCONV 67 69 w: 71 b: 70 stride: 1 pad: SAME + 14 CONV 69 73 w: 74 b: 72 stride: 1 pad: SAME + 15 DWCONV 73 75 w: 77 b: 76 stride: 1 pad: SAME + 16 CONV 75 79 w: 80 b: 78 stride: 1 pad: SAME + 17 DWCONV 79 81 w: 83 b: 82 stride: 1 pad: SAME + 18 CONV 81 85 w: 86 b: 84 stride: 1 pad: SAME + 19 DWCONV 85 9 w: 11 b: 10 stride: 1 pad: SAME + 20 CONV 9 13 w: 14 b: 12 stride: 1 pad: SAME + 21 DWCONV 13 15 w: 17 b: 16 stride: 1 pad: SAME + 22 CONV 15 19 w: 20 b: 18 stride: 1 pad: SAME + 23 DWCONV 19 21 w: 23 b: 22 stride: 2 pad: SAME + 24 CONV 21 25 w: 26 b: 24 stride: 1 pad: SAME + 25 DWCONV 25 27 w: 29 b: 28 stride: 1 pad: SAME + 26 CONV 27 31 w: 32 b: 30 stride: 1 pad: SAME + 27 POOL 31 0 filter: 0x0 stride: 0 pad: VALID + + teflon: compiled graph, took 10307 ms + teflon: invoked graph, took 21 ms + teflon: invoked graph, took 17 ms + teflon: invoked graph, took 17 ms + teflon: invoked graph, took 17 ms + teflon: invoked graph, took 16 ms + 0.866667: military uniform + 0.031373: Windsor tie + 0.015686: mortarboard + 0.007843: bow tie + 0.007843: academic diff --git a/meson.build b/meson.build index 6d10219f067..a8d84c00b20 100644 --- a/meson.build +++ b/meson.build @@ -2144,6 +2144,13 @@ if with_perfetto pre_args += '-DHAVE_PERFETTO' endif +with_teflon = get_option('teflon') +if with_teflon and with_tests + dep_xtensor = dependency('xtensor') + dep_flatbuffers = dependency('flatbuffers') + prog_flatc = find_program('flatc') +endif + with_gpuvis = get_option('gpuvis') if with_gpuvis pre_args += '-DHAVE_GPUVIS' @@ -2362,3 +2369,6 @@ if with_perfetto and with_any_datasource perfetto_summary += {'Data source': with_datasources} endif summary(perfetto_summary, section: 'Perfetto', bool_yn: true, list_sep: ' ') + +teflon_summary = {'Enabled': with_teflon} +summary(teflon_summary, section: 'Teflon (TensorFlow Lite delegate)', bool_yn: true, list_sep: ' ') diff --git a/meson_options.txt b/meson_options.txt index d75691d7fbc..e5dacd54fd9 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -591,6 +591,13 @@ option( 'Default: [`auto`]' ) +option( + 'teflon', + type : 'boolean', + value : false, + description : 'Enable TensorFlow Lite delegate. Default: false' +) + option( 'gpuvis', type : 'boolean', diff --git a/src/gallium/frontends/teflon/meson.build b/src/gallium/frontends/teflon/meson.build new file mode 100644 index 00000000000..aedde1c363f --- /dev/null +++ b/src/gallium/frontends/teflon/meson.build @@ -0,0 +1,11 @@ +libtfl_files = files( + 'tfl_device.c') + +libteflon_st = static_library( + 'teflon_st', + [libtfl_files, sha1_h], + c_args : [ ], + gnu_symbol_visibility : 'hidden', + include_directories : [ inc_include, inc_src, inc_util, inc_gallium, inc_gallium_aux ], + dependencies : [ idep_mesautil ] +) diff --git a/src/gallium/frontends/teflon/tfl_device.c b/src/gallium/frontends/teflon/tfl_device.c new file mode 100644 index 00000000000..6d3a431c872 --- /dev/null +++ b/src/gallium/frontends/teflon/tfl_device.c @@ -0,0 +1,492 @@ +/* + * Copyright (c) 2023-2024 Tomeu Vizoso + * SPDX-License-Identifier: MIT + */ + +#include "pipe-loader/pipe_loader.h" +#include "pipe/p_context.h" +#include "pipe/p_screen.h" +#include "pipe/p_state.h" +#include "util/format/u_format.h" +#include "util/u_inlines.h" + +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/builtin_ops.h" +#include "tensorflow/lite/core/c/builtin_op_data.h" + +/* TODO: Move to TfLiteAsyncKernel for zero-copy of buffers */ + +enum teflon_debug_flags { + TEFLON_DEBUG_VERBOSE = 1 << 1, +}; + +static const struct debug_named_value teflon_debug_flags[] = { + { "verbose", TEFLON_DEBUG_VERBOSE, "Verbose logging." }, + DEBUG_NAMED_VALUE_END +}; + +DEBUG_GET_ONCE_FLAGS_OPTION(debug_teflon, "TEFLON_DEBUG", teflon_debug_flags, 0) + +static inline void +teflon_debug(const char *format, ...) +{ + if (unlikely(debug_get_option_debug_teflon() & TEFLON_DEBUG_VERBOSE)) { + va_list ap; + va_start(ap, format); + _debug_vprintf(format, ap); + va_end(ap); + } +} + +struct teflon_delegate +{ + TfLiteDelegate base; + struct pipe_loader_device *dev; + struct pipe_context *context; +}; + +struct teflon_subgraph +{ + struct pipe_ml_subgraph *base; + + unsigned *input_tensors; + unsigned input_count; + + unsigned *output_tensors; + unsigned output_count; +}; + +static struct pipe_resource * +create_resource(struct pipe_context *context, TfLiteTensor tensor) +{ + unsigned bytes; + unsigned size = 1; + + for (int i = 0; i < tensor.dims->size; i++) + size *= tensor.dims->data[i]; + + switch(tensor.type) { + case kTfLiteInt8: + case kTfLiteUInt8: + bytes = 1; + break; + case kTfLiteInt16: + case kTfLiteUInt16: + case kTfLiteFloat16: + bytes = 2; + break; + case kTfLiteInt32: + case kTfLiteUInt32: + case kTfLiteFloat32: + bytes = 4; + break; + case kTfLiteInt64: + case kTfLiteUInt64: + case kTfLiteFloat64: + case kTfLiteComplex64: + bytes = 8; + break; + default: + unreachable("Unsupported TF type"); + } + + return pipe_buffer_create_with_data(context, 0, PIPE_USAGE_DEFAULT, size * bytes, tensor.data.data); +} + +static void +fill_operation(struct teflon_delegate *delegate, TfLiteContext *tf_context, TfLiteNode *node, TfLiteRegistration *node_registration, struct pipe_ml_operation *operation, struct pipe_tensor *tensors) +{ + TfLiteConvParams* params = (TfLiteConvParams*)node->builtin_data; + + operation->input_tensor = &tensors[node->inputs->data[0]]; + operation->output_tensor = &tensors[node->outputs->data[0]]; + + switch(node_registration->builtin_code) { + case kTfLiteBuiltinConv2d: + case kTfLiteBuiltinDepthwiseConv2d: + operation->type = PIPE_ML_OPERATION_TYPE_CONVOLUTION; + operation->conv.weight_tensor = &tensors[node->inputs->data[1]]; + operation->conv.bias_tensor = &tensors[node->inputs->data[2]]; + operation->conv.stride_x = params->stride_width; + operation->conv.stride_y = params->stride_height; + operation->conv.padding_same = params->padding == kTfLitePaddingSame; + operation->conv.depthwise = node_registration->builtin_code == kTfLiteBuiltinDepthwiseConv2d; + operation->conv.pointwise = operation->conv.weight_tensor->dims[1] == 1 && \ + operation->conv.weight_tensor->dims[2] == 1; + break; + case kTfLiteBuiltinAveragePool2d: + operation->type = PIPE_ML_OPERATION_TYPE_POOLING; + break; + case kTfLiteBuiltinAdd: + operation->type = PIPE_ML_OPERATION_TYPE_ADD; + operation->add.input_tensor = &tensors[node->inputs->data[1]]; + break; + default: + unreachable("Unsupported ML operation type"); + } +} + +static void +fill_tensor(struct teflon_delegate *delegate, TfLiteContext *tf_context, struct pipe_tensor *tensor, unsigned index) +{ + struct pipe_context *context = delegate->context; + TfLiteTensor tf_tensor = tf_context->tensors[index]; + const TfLiteAffineQuantization *quant = (const TfLiteAffineQuantization *)tf_tensor.quantization.params; + + if (tf_tensor.type == kTfLiteNoType) + return; /* Placeholder tensor */ + + if (tf_tensor.data.data) + tensor->resource = create_resource(context, tf_tensor); + + tensor->index = index; + memcpy(tensor->dims, tf_tensor.dims->data, tf_tensor.dims->size * sizeof(*tensor->dims)); + tensor->scale = quant->scale->data[0]; + tensor->zero_point = quant->zero_point->data[0]; + + switch(tf_tensor.type) { + case kTfLiteUInt8: + case kTfLiteUInt16: + case kTfLiteUInt32: + case kTfLiteUInt64: + tensor->is_signed = false; + break; + default: + tensor->is_signed = true; + } +} + +static void +dump_graph(struct pipe_tensor *tensors, unsigned tensor_count, struct pipe_ml_operation *operations, unsigned operation_count) +{ + teflon_debug("\n"); + teflon_debug("teflon: compiling graph: %d tensors %d operations\n", + tensor_count, operation_count); + + teflon_debug("%3s %-8s %3s %s %-12s\n", "idx", "scale", "zp", "has_data", "size"); + teflon_debug("=======================================\n"); + for (int i = 0; i < tensor_count; i++) { + teflon_debug("%3d %6f %3x %-8s %dx%dx%dx%d\n", + tensors[i].index, + tensors[i].scale, + tensors[i].zero_point, + tensors[i].resource == NULL ? "no" : "yes", + tensors[i].dims[0], tensors[i].dims[1], tensors[i].dims[2], tensors[i].dims[3]); + } + + teflon_debug("\n"); + teflon_debug("%3s %-6s %3s %3s %s\n", "idx", "type", "in", "out", "operation type-specific"); + teflon_debug("================================================================================================\n"); + for (int i = 0; i < operation_count; i++) { + switch(operations[i].type) { + case PIPE_ML_OPERATION_TYPE_ADD: + teflon_debug("%3d %-6s %3d %3d in: %d", + i, + "ADD", + operations[i].input_tensor->index, + operations[i].output_tensor->index, + operations[i].add.input_tensor->index); + break; + case PIPE_ML_OPERATION_TYPE_CONVOLUTION: + teflon_debug("%3d %-6s %3d %3d w: %d b: %d stride: %d pad: %s", + i, + operations[i].conv.depthwise ? "DWCONV" : "CONV", + operations[i].input_tensor->index, + operations[i].output_tensor->index, + operations[i].conv.weight_tensor->index, + operations[i].conv.bias_tensor->index, + operations[i].conv.stride_x, + operations[i].conv.padding_same ? "SAME" : "VALID"); + break; + case PIPE_ML_OPERATION_TYPE_POOLING: + teflon_debug("%3d %-6s %3d %3d filter: %dx%d stride: %d pad: %s", + i, + "POOL", + operations[i].input_tensor->index, + operations[i].output_tensor->index, + operations[i].pooling.filter_height, + operations[i].pooling.filter_width, + operations[i].pooling.stride_x, + operations[i].pooling.padding_same ? "SAME" : "VALID"); + break; + } + + teflon_debug("\n"); + } + teflon_debug("\n"); +} + +static void * +partition_init(TfLiteContext *tf_context, const char *buffer, size_t length) +{ + const TfLiteDelegateParams *params = (const TfLiteDelegateParams *)buffer; + struct teflon_delegate *delegate = (struct teflon_delegate *)params->delegate; + struct pipe_context *context = delegate->context; + struct pipe_ml_operation operations[params->nodes_to_replace->size]; + struct pipe_tensor tensors[tf_context->tensors_size]; + long start = 0, end = 0; + + memset(operations, 0, sizeof(operations)); + memset(tensors, 0, sizeof(tensors)); + + if (unlikely(debug_get_option_debug_teflon() & TEFLON_DEBUG_VERBOSE)) { + struct timespec time; + clock_gettime(CLOCK_MONOTONIC, &time); + start = (long)time.tv_sec * 1000 + (long)time.tv_nsec / 1000000; + } + + for (int i = 0; i < tf_context->tensors_size; i++) + fill_tensor(delegate, tf_context, &tensors[i], i); + + for (int i = 0; i < params->nodes_to_replace->size; i++) + { + const int node_index = params->nodes_to_replace->data[i]; + TfLiteNode *delegated_node = NULL; + TfLiteRegistration *delegated_node_registration = NULL; + tf_context->GetNodeAndRegistration(tf_context, node_index, &delegated_node, + &delegated_node_registration); + + fill_operation(delegate, tf_context, delegated_node, delegated_node_registration, &operations[i], tensors); + } + + if (debug_get_option_debug_teflon() & TEFLON_DEBUG_VERBOSE) + dump_graph(tensors, tf_context->tensors_size, operations, params->nodes_to_replace->size); + + struct pipe_ml_subgraph *subgraph; + subgraph = context->ml_subgraph_create(context, + operations, + params->nodes_to_replace->size); + + for (int i = 0; i < tf_context->tensors_size; i++) + pipe_resource_reference(&tensors[i].resource, NULL); + + struct teflon_subgraph *tsubgraph = calloc(1, sizeof(*tsubgraph)); + tsubgraph->base = subgraph; + + tsubgraph->input_tensors = malloc(params->input_tensors->size * sizeof(*tsubgraph->input_tensors)); + for (int i = 0; i < params->input_tensors->size; i++) { + unsigned tensor_idx = params->input_tensors->data[i]; + TfLiteTensor *tensor = &tf_context->tensors[tensor_idx]; + if (tensor->allocation_type == kTfLiteMmapRo) + continue; + tsubgraph->input_tensors[tsubgraph->input_count] = tensor_idx; + tsubgraph->input_count++; + } + + tsubgraph->output_count = params->output_tensors->size; + tsubgraph->output_tensors = malloc(params->output_tensors->size * sizeof(*tsubgraph->output_tensors)); + memcpy(tsubgraph->output_tensors, params->output_tensors->data, + params->output_tensors->size * sizeof(*tsubgraph->output_tensors)); + + if (unlikely(debug_get_option_debug_teflon() & TEFLON_DEBUG_VERBOSE)) { + struct timespec time; + clock_gettime(CLOCK_MONOTONIC, &time); + end = (long)time.tv_sec * 1000 + (long)time.tv_nsec / 1000000; + teflon_debug("teflon: compiled graph, took %ld ms\n", (end - start)); + } + + return tsubgraph; +} + +static TfLiteStatus +partition_prepare(TfLiteContext *context, TfLiteNode *node) +{ + // TODO: If input size has changed, resize input, intermediate and output buffers + + return kTfLiteOk; +} + +// De-allocates the per-node-and-Interpreter custom data. +static void +partition_free(TfLiteContext *tf_context, void *buffer) +{ + struct teflon_subgraph *tsubgraph = (struct teflon_subgraph *)buffer; + struct pipe_ml_subgraph *subgraph = tsubgraph->base; + struct pipe_context *context = subgraph->context; + + context->ml_subgraph_destroy(context, subgraph); + free(tsubgraph->input_tensors); + free(tsubgraph->output_tensors); + free(tsubgraph); +} + +static TfLiteStatus +partition_invoke(TfLiteContext *tf_context, TfLiteNode *node) +{ + struct teflon_delegate *delegate = (struct teflon_delegate *)node->delegate; + struct teflon_subgraph *tsubgraph = (struct teflon_subgraph *)node->user_data; + struct pipe_ml_subgraph *subgraph = tsubgraph->base; + struct pipe_context *context = delegate->context; + long start = 0, end = 0; + + if (unlikely(debug_get_option_debug_teflon() & TEFLON_DEBUG_VERBOSE)) { + struct timespec time; + clock_gettime(CLOCK_MONOTONIC, &time); + start = (long)time.tv_sec * 1000 + (long)time.tv_nsec / 1000000; + } + + struct pipe_tensor input = {0}; + /* FIXME: Support mutiple inputs */ + fill_tensor(delegate, tf_context, &input, tsubgraph->input_tensors[0]); + context->ml_subgraph_invoke(context, subgraph, &input); + + void **buffers = malloc(tsubgraph->output_count * sizeof(*buffers)); + for (unsigned i = 0; i < tsubgraph->output_count; i++) + buffers[i] = tf_context->tensors[tsubgraph->output_tensors[i]].data.data; + context->ml_subgraph_read_output(context, subgraph, tsubgraph->output_count, tsubgraph->output_tensors, buffers); + free(buffers); + + pipe_resource_reference(&input.resource, NULL); + + if (unlikely(debug_get_option_debug_teflon() & TEFLON_DEBUG_VERBOSE)) { + struct timespec time; + clock_gettime(CLOCK_MONOTONIC, &time); + end = (long)time.tv_sec * 1000 + (long)time.tv_nsec / 1000000; + teflon_debug("teflon: invoked graph, took %ld ms\n", (end - start)); + } + + return kTfLiteOk; +} + +static TfLiteStatus +PrepareDelegate(TfLiteContext *context, TfLiteDelegate *delegate) +{ + TfLiteIntArray *plan; + TfLiteNode *node; + TF_LITE_ENSURE_STATUS(context->GetExecutionPlan(context, &plan)); + + // Get a list of supported nodes. + TfLiteIntArray *supported_nodes = malloc(plan->size * sizeof(int) + sizeof(*supported_nodes)); + supported_nodes->size = plan->size; + unsigned node_count = 0; + for (int i = 0; i < plan->size; i++) { + int node_index = plan->data[i]; + bool supported = false; + TfLiteRegistration *registration; + TF_LITE_ENSURE_STATUS(context->GetNodeAndRegistration( + context, node_index, &node, ®istration)); + + switch(registration->builtin_code) { + case kTfLiteBuiltinConv2d: + case kTfLiteBuiltinDepthwiseConv2d: { + TfLiteTensor bias_tensor = context->tensors[node->inputs->data[2]]; + /* Skip out channel numbers that the HW doesn't support */ + if (bias_tensor.dims->data[0] > 8 && bias_tensor.dims->data[0] % 8 != 0) + supported = false; + else + supported = true; + break; + } + case kTfLiteBuiltinAdd: + supported = true; + break; + } + + if (supported) + supported_nodes->data[node_count++] = node_index; + } + supported_nodes->size = node_count; + + TfLiteRegistration registration; + + registration.init = partition_init; + registration.free = partition_free; + registration.prepare = partition_prepare; + registration.invoke = partition_invoke; + + registration.profiling_string = NULL; + registration.builtin_code = kTfLiteBuiltinDelegate; + registration.version = 1; + registration.registration_external = NULL; + registration.custom_name = "Teflon Delegate"; + + // Replace supported subgraphs. + TfLiteStatus status = context->ReplaceNodeSubsetsWithDelegateKernels( + context, + registration, + supported_nodes, + delegate); + + free(supported_nodes); + + return status; +} + +static TfLiteStatus +CopyFromBufferHandle(TfLiteContext *context, + TfLiteDelegate *delegate, + TfLiteBufferHandle buffer_handle, + TfLiteTensor *tensor) +{ + return kTfLiteOk; +} + +static void +FreeBufferHandle(TfLiteContext *context, + TfLiteDelegate *delegate, + TfLiteBufferHandle *handle) +{ +} + +TfLiteDelegate *tflite_plugin_create_delegate(char **options_keys, + char **options_values, + size_t num_options, + void (*report_error)(const char *)); + +void tflite_plugin_destroy_delegate(TfLiteDelegate *delegate); + +__attribute__((visibility("default"))) TfLiteDelegate *tflite_plugin_create_delegate(char **options_keys, + char **options_values, + size_t num_options, + void (*report_error)(const char *)) +{ + struct teflon_delegate *delegate = (struct teflon_delegate *)calloc(1, sizeof(*delegate)); + struct pipe_screen *screen; + struct pipe_loader_device **devs; + + delegate->base.flags = kTfLiteDelegateFlagsAllowDynamicTensors | kTfLiteDelegateFlagsRequirePropagatedShapes; + delegate->base.Prepare = &PrepareDelegate; + delegate->base.CopyFromBufferHandle = &CopyFromBufferHandle; + delegate->base.FreeBufferHandle = &FreeBufferHandle; + + int n = pipe_loader_probe(NULL, 0, false); + devs = (struct pipe_loader_device **)malloc(sizeof(*devs) * n); + pipe_loader_probe(devs, n, false); + + for (int i = 0; i < n; i++) { + if (strstr("etnaviv", devs[i]->driver_name)) + delegate->dev = devs[i]; + else + pipe_loader_release(&devs[i], 1); + } + free(devs); + + if (delegate->dev == NULL) { + fprintf(stderr, "Couldn't open kernel device\n"); + return NULL; + } + + teflon_debug("Teflon delegate: loaded %s driver\n", delegate->dev->driver_name); + + screen = pipe_loader_create_screen(delegate->dev); + delegate->context = screen->context_create(screen, NULL, PIPE_CONTEXT_COMPUTE_ONLY); + + return &delegate->base; +} + +__attribute__((visibility("default"))) void tflite_plugin_destroy_delegate(TfLiteDelegate *tflite_delegate) +{ + struct teflon_delegate *delegate = (struct teflon_delegate *)tflite_delegate; + struct pipe_screen *screen; + + if (tflite_delegate == NULL) { + fprintf(stderr, "tflite_plugin_destroy_delegate: NULL delegate!\n"); + return; + } + + screen = delegate->context->screen; + delegate->context->destroy(delegate->context); + screen->destroy(screen); + pipe_loader_release(&delegate->dev, 1); + free(delegate); +} diff --git a/src/gallium/include/pipe/p_context.h b/src/gallium/include/pipe/p_context.h index 689622409d5..e08e5c66441 100644 --- a/src/gallium/include/pipe/p_context.h +++ b/src/gallium/include/pipe/p_context.h @@ -79,6 +79,8 @@ struct pipe_video_buffer; struct pipe_video_codec; struct pipe_viewport_state; struct pipe_compute_state; +struct pipe_ml_operation; +struct pipe_tensor; union pipe_color_union; union pipe_query_result; struct u_log_context; @@ -1223,6 +1225,53 @@ struct pipe_context { struct winsys_handle *handle, unsigned usage ); + /** + * Compiles a ML subgraph, to be executed later. The returned pipe_ml_subgraph + * should contain all information needed to execute the subgraph with as + * little effort as strictly needed. + * + * \param ctx pipe context + * \param operations array containing the definitions of the operations in the graph + * \param count number of operations + * \return a newly allocated pipe_ml_subgraph + */ + struct pipe_ml_subgraph *(*ml_subgraph_create)(struct pipe_context *context, + const struct pipe_ml_operation *operations, + unsigned count); + + /** + * Invokes a ML subgraph for a given input tensor. + * + * \param ctx pipe context + * \param subgraph previously-compiled subgraph + * \param input tensor to use as the input + */ + void (*ml_subgraph_invoke)(struct pipe_context *context, + struct pipe_ml_subgraph *subgraph, + struct pipe_tensor *input); + + /** + * After a ML subgraph has been invoked, copy the contents of the output + * tensors to the provided buffers. + * + * \param ctx pipe context + * \param subgraph previously-executed subgraph + * \param outputs_count number of output tensors to copy out + * \param output_idxs array with the indices of output tensors + * \param outputs array of buffers to copy the tensor data to + */ + void (*ml_subgraph_read_output)(struct pipe_context *context, + struct pipe_ml_subgraph *subgraph, + unsigned outputs_count, unsigned output_idxs[], void *outputs[]); + + /** + * Release all resources allocated by the implementation of ml_subgraph_create + * + * \param ctx pipe context + * \param subgraph subgraph to release + */ + void (*ml_subgraph_destroy)(struct pipe_context *context, + struct pipe_ml_subgraph *subgraph); }; diff --git a/src/gallium/include/pipe/p_state.h b/src/gallium/include/pipe/p_state.h index 069c32b1fa0..109aba8e8ab 100644 --- a/src/gallium/include/pipe/p_state.h +++ b/src/gallium/include/pipe/p_state.h @@ -1020,6 +1020,148 @@ struct pipe_grid_info struct pipe_resource *indirect_draw_count; }; +/** + * Encapsulates all info about a tensor. Only types supported are INT8 and UINT8. + */ +struct pipe_tensor { + /** + * Memory-backing for this tensor (use pipe_buffer_*). + */ + struct pipe_resource *resource; + /** + * Index of this tensor in the subgraph that contains it. + */ + unsigned index; + /** + * Dimensions of this tensor. + */ + unsigned dims[4]; + /** + * Scale used to quantize this tensor. Only per-tensor quantization is supported. + */ + float scale; + /** + * Zero-point used to quantize this tensor. + */ + int zero_point; + /** + * Whether the tensor contains data in INT8 or UINT8 format. + */ + bool is_signed; +}; + +/** + * Type of a pipe_ml_operation. + */ +enum pipe_ml_operation_type { + PIPE_ML_OPERATION_TYPE_ADD, + PIPE_ML_OPERATION_TYPE_CONVOLUTION, + PIPE_ML_OPERATION_TYPE_POOLING, +}; + +/** + * Information about a single operation inside a ML subgraph. + */ +struct pipe_ml_operation +{ + /** + * Type of operation. + */ + enum pipe_ml_operation_type type; + + /** + * Tensor used as input. + */ + struct pipe_tensor *input_tensor; + + /** + * Tensor used as output. + */ + struct pipe_tensor *output_tensor; + + union { + struct { + /** + * For convolutions, tensor containing the weights. + */ + struct pipe_tensor *weight_tensor; + /** + * For convolutions, tensor containing the biases. + */ + struct pipe_tensor *bias_tensor; + + /** + * Stride used to access the input tensor on the x axis. + */ + unsigned stride_x; + + /** + * Stride used to access the input tensor on the x axis. + */ + unsigned stride_y; + + /** + * Whether to use padding of type same when accessing the input tensor. + */ + bool padding_same; + + /** + * Whether this is a pointwise (1x1 kernels) convolution. + */ + bool pointwise; + + /** + * Whether this is a depthwise convolution. + */ + bool depthwise; + } conv; + struct { + /** + * Stride used to access the input tensor on the x axis. + */ + unsigned stride_x; + + /** + * Stride used to access the input tensor on the x axis. + */ + unsigned stride_y; + + /** + * Width of the area used for pooling. + */ + unsigned filter_width; + + /** + * Height of the area used for pooling. + */ + unsigned filter_height; + + /** + * Whether to use padding of type same when accessing the input tensor. + */ + bool padding_same; + } pooling; + struct { + /** + * Additional input tensor, to be added to the other one. + */ + struct pipe_tensor *input_tensor; + } add; + }; +}; + +/** + * Subgraph that drivers can subclass to keep the output of the subgraph + * compilation process. + */ +struct pipe_ml_subgraph +{ + /** + * pipe_context that owns this subgraph. + */ + struct pipe_context *context; +}; + /** * Structure used as a header for serialized compute programs. */ diff --git a/src/gallium/meson.build b/src/gallium/meson.build index 42b93365d1f..e2b84e19276 100644 --- a/src/gallium/meson.build +++ b/src/gallium/meson.build @@ -260,3 +260,8 @@ if with_swrast_vk subdir('frontends/lavapipe') subdir('targets/lavapipe') endif + +if with_teflon + subdir('frontends/teflon') + subdir('targets/teflon') +endif diff --git a/src/gallium/targets/teflon/meson.build b/src/gallium/targets/teflon/meson.build new file mode 100644 index 00000000000..be05252d2b5 --- /dev/null +++ b/src/gallium/targets/teflon/meson.build @@ -0,0 +1,47 @@ +libteflon = shared_library( + 'teflon', + [ 'target.c' ], + include_directories : [ inc_src, inc_util, inc_include, inc_gallium, inc_gallium_aux, inc_gallium_winsys, inc_gallium_drivers ], + link_whole : [ libteflon_st ], + link_with : [libpipe_loader_static, libws_null, libwsw, libswdri, libswkmsdri, libgallium ], + gnu_symbol_visibility : 'hidden', + link_args : ld_args_build_id, + dependencies : [ + driver_etnaviv, + idep_nir, + ], + install : true, +) + +if with_tests + tensorflow_lite = shared_library( + 'tensorflow-lite', + [ 'tflite-stub.c' ], + include_directories : [ inc_include ], + install : false, + ) + + tflite_flatbuffer_h_name = 'tflite-schema-v2.15.0_generated.h' + tflite_flatbuffer_h = custom_target('tflite_flatbuffer.h', + output: tflite_flatbuffer_h_name, + input: 'tflite-schema-v2.15.0.fbs', + command : [ + prog_flatc, + '--cpp', + '--cpp-ptr-type', 'std::shared_ptr', + '--gen-object-api', + '-o', meson.current_build_dir(), + '@INPUT@' + ], + ) + + executable( + 'test_teflon', + 'test_teflon.cpp', + 'test_executor.cpp', + tflite_flatbuffer_h, + dependencies : [ idep_mesautil, idep_gtest ], + link_with : [ tensorflow_lite ], + include_directories : [ inc_include ], + ) +endif \ No newline at end of file diff --git a/src/gallium/targets/teflon/target.c b/src/gallium/targets/teflon/target.c new file mode 100644 index 00000000000..308e23bb4a0 --- /dev/null +++ b/src/gallium/targets/teflon/target.c @@ -0,0 +1,2 @@ +#include "target-helpers/drm_helper.h" +#include "target-helpers/sw_helper.h" diff --git a/src/gallium/targets/teflon/test_executor.cpp b/src/gallium/targets/teflon/test_executor.cpp new file mode 100644 index 00000000000..ea3fc6f20f1 --- /dev/null +++ b/src/gallium/targets/teflon/test_executor.cpp @@ -0,0 +1,318 @@ +/* + * Copyright (c) 2023-2024 Tomeu Vizoso + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include +#include + +#include "util/macros.h" + +#include "tensorflow/lite/c/c_api.h" +#include "tensorflow/lite/c/common.h" + +#include +#include "test_executor.h" +#include "tflite-schema-v2.15.0_generated.h" + +static float +randf(float min, float max) +{ + return ((max - min) * ((float)rand() / (float)RAND_MAX)) + min; +} + +static void +read_model(const char *file_name, tflite::ModelT &model) +{ + std::ostringstream file_path; + assert(getenv("TEFLON_TEST_DATA")); + file_path << getenv("TEFLON_TEST_DATA") << "/" << file_name; + + FILE *f = fopen(file_path.str().c_str(), "rb"); + assert(f); + fseek(f, 0, SEEK_END); + long fsize = ftell(f); + fseek(f, 0, SEEK_SET); + void *buf = malloc(fsize); + fread(buf, fsize, 1, f); + fclose(f); + + tflite::GetModel(buf)->UnPackTo(&model); +} + +static void +patch_conv2d(unsigned operation_index, + tflite::ModelT *model, + int input_size, + int weight_size, + int input_channels, + int output_channels, + int stride, + bool padding_same, + bool is_signed, + bool depthwise) +{ + unsigned output_size = 0; + unsigned input_index; + unsigned weights_index; + unsigned bias_index; + unsigned output_index; + unsigned weights_buffer_index; + unsigned bias_buffer_index; + + auto subgraph = model->subgraphs[0]; + + /* Operation */ + if (depthwise) { + auto value = new tflite::DepthwiseConv2DOptionsT(); + value->depth_multiplier = 1; + value->padding = padding_same ? tflite::Padding_SAME : tflite::Padding_VALID; + value->stride_w = stride; + value->stride_h = stride; + value->dilation_w_factor = 1; + value->dilation_h_factor = 1; + subgraph->operators[operation_index]->builtin_options.value = value; + subgraph->operators[operation_index]->builtin_options.type = tflite::BuiltinOptions_DepthwiseConv2DOptions; + + model->operator_codes[0]->deprecated_builtin_code = 4; + model->operator_codes[0]->builtin_code = tflite::BuiltinOperator_DEPTHWISE_CONV_2D; + } else { + auto value = new tflite::Conv2DOptionsT(); + value->padding = padding_same ? tflite::Padding_SAME : tflite::Padding_VALID; + value->stride_w = stride; + value->stride_h = stride; + subgraph->operators[operation_index]->builtin_options.value = value; + } + + input_index = subgraph->operators[operation_index]->inputs.data()[0]; + weights_index = subgraph->operators[operation_index]->inputs.data()[1]; + bias_index = subgraph->operators[operation_index]->inputs.data()[2]; + output_index = subgraph->operators[operation_index]->outputs.data()[0]; + + /* Input */ + auto input_tensor = subgraph->tensors[input_index]; + input_tensor->shape.data()[0] = 1; + input_tensor->shape.data()[1] = input_size; + input_tensor->shape.data()[2] = input_size; + input_tensor->shape.data()[3] = input_channels; + input_tensor->type = is_signed ? tflite::TensorType_INT8 : tflite::TensorType_UINT8; + + /* Bias */ + auto bias_tensor = subgraph->tensors[bias_index]; + bias_buffer_index = bias_tensor->buffer; + bias_tensor->shape.data()[0] = output_channels; + + auto bias_data = &model->buffers[bias_buffer_index]->data; + xt::xarray bias_array = xt::random::randint({output_channels}, -20000, 20000); + bias_data->resize(bias_array.size() * sizeof(int32_t)); + memcpy(bias_data->data(), bias_array.data(), bias_array.size() * sizeof(int32_t)); + + /* Weight */ + auto weight_tensor = subgraph->tensors[weights_index]; + weights_buffer_index = weight_tensor->buffer; + if (depthwise) { + weight_tensor->shape.data()[0] = 1; + weight_tensor->shape.data()[1] = weight_size; + weight_tensor->shape.data()[2] = weight_size; + weight_tensor->shape.data()[3] = output_channels; + } else { + weight_tensor->shape.data()[0] = output_channels; + weight_tensor->shape.data()[1] = weight_size; + weight_tensor->shape.data()[2] = weight_size; + weight_tensor->shape.data()[3] = input_channels; + } + weight_tensor->type = is_signed ? tflite::TensorType_INT8 : tflite::TensorType_UINT8; + + auto weights_data = &model->buffers[weights_buffer_index]->data; + std::vector weight_shape; + if (depthwise) + weight_shape = {1, weight_size, weight_size, output_channels}; + else + weight_shape = {output_channels, weight_size, weight_size, input_channels}; + + xt::xarray weights_array = xt::random::randint(weight_shape, 0, 255); + weights_data->resize(weights_array.size()); + memcpy(weights_data->data(), weights_array.data(), weights_array.size()); + + /* Output */ + if (padding_same) + output_size = (input_size + stride - 1) / stride; + else + output_size = (input_size + stride - weight_size) / stride; + + auto output_tensor = subgraph->tensors[output_index]; + output_tensor->shape.data()[0] = 1; + output_tensor->shape.data()[1] = output_size; + output_tensor->shape.data()[2] = output_size; + output_tensor->shape.data()[3] = output_channels; + output_tensor->type = is_signed ? tflite::TensorType_INT8 : tflite::TensorType_UINT8; +} + +std::vector +conv2d_generate_model(int input_size, + int weight_size, + int input_channels, + int output_channels, + int stride, + bool padding_same, + bool is_signed, + bool depthwise) +{ + tflite::ModelT model; + read_model("conv2d.tflite", model); + + patch_conv2d(0, &model, input_size, weight_size, input_channels, output_channels, stride, padding_same, is_signed, depthwise); + + flatbuffers::FlatBufferBuilder builder; + builder.Finish(tflite::Model::Pack(builder, &model), "TFL3"); + + return {builder.GetBufferPointer(), builder.GetBufferPointer() + builder.GetSize()}; +} + +static void +patch_quant_for_add(tflite::ModelT *model) +{ + auto subgraph = model->subgraphs[0]; + auto add_op = subgraph->operators[2]; + + auto input_index = add_op->inputs.data()[0]; + auto input_tensor = subgraph->tensors[input_index]; + input_tensor->quantization->scale[0] = randf(0.0078125, 0.4386410117149353); + input_tensor->quantization->zero_point[0] = rand() % 255; + + input_index = add_op->inputs.data()[1]; + input_tensor = subgraph->tensors[input_index]; + input_tensor->quantization->scale[0] = randf(0.0078125, 0.4386410117149353); + input_tensor->quantization->zero_point[0] = rand() % 255; +} + +std::vector +add_generate_model(int input_size, + int weight_size, + int input_channels, + int output_channels, + int stride, + bool padding_same, + bool is_signed, + bool depthwise) +{ + tflite::ModelT model; + read_model("add.tflite", model); + + patch_conv2d(0, &model, input_size, weight_size, input_channels, output_channels, stride, padding_same, is_signed, depthwise); + patch_conv2d(1, &model, input_size, weight_size, input_channels, output_channels, stride, padding_same, is_signed, depthwise); + patch_quant_for_add(&model); + + /* Output */ + auto subgraph = model.subgraphs[0]; + unsigned input_index = subgraph->operators[2]->inputs.data()[0]; + unsigned output_index = subgraph->operators[2]->outputs.data()[0]; + + auto input_tensor = subgraph->tensors[input_index]; + auto output_tensor = subgraph->tensors[output_index]; + output_tensor->shape.data()[0] = input_tensor->shape.data()[0]; + output_tensor->shape.data()[1] = input_tensor->shape.data()[1]; + output_tensor->shape.data()[2] = input_tensor->shape.data()[2]; + output_tensor->shape.data()[3] = input_tensor->shape.data()[3]; + output_tensor->type = is_signed ? tflite::TensorType_INT8 : tflite::TensorType_UINT8; + + flatbuffers::FlatBufferBuilder builder; + builder.Finish(tflite::Model::Pack(builder, &model), "TFL3"); + + return {builder.GetBufferPointer(), builder.GetBufferPointer() + builder.GetSize()}; +} + +static void +tflite_error_cb(void *user_data, const char *format, va_list args) +{ + vfprintf(stderr, format, args); +} + +TfLiteDelegate *(*tflite_plugin_create_delegate)(char **options_keys, + char **options_values, + size_t num_options, + void (*report_error)(const char *)); + +void (*tflite_plugin_destroy_delegate)(TfLiteDelegate *delegate); + +static void +load_delegate() +{ + const char *delegate_path = getenv("TEFLON_TEST_DELEGATE"); + assert(delegate_path); + + void *delegate_lib = dlopen(delegate_path, RTLD_LAZY | RTLD_LOCAL); + assert(delegate_lib); + + tflite_plugin_create_delegate = reinterpret_cast( + dlsym(delegate_lib, "tflite_plugin_create_delegate")); + assert(tflite_plugin_create_delegate); + + tflite_plugin_destroy_delegate = reinterpret_cast( + dlsym(delegate_lib, "tflite_plugin_destroy_delegate")); + assert(tflite_plugin_destroy_delegate); +} + +std::vector> +run_model(TfLiteModel *model, enum executor executor, std::vector> &input) +{ + TfLiteDelegate *delegate = NULL; + TfLiteInterpreterOptions *options = TfLiteInterpreterOptionsCreate(); + bool generate_random_input = input.empty(); + std::vector> output; + + if (executor == EXECUTOR_NPU) { + load_delegate(); + delegate = tflite_plugin_create_delegate(NULL, NULL, 0, NULL); + TfLiteInterpreterOptionsAddDelegate(options, delegate); + } + + TfLiteInterpreterOptionsSetErrorReporter(options, tflite_error_cb, NULL); + + TfLiteInterpreter *interpreter = TfLiteInterpreterCreate(model, options); + assert(interpreter); + + TfLiteInterpreterAllocateTensors(interpreter); + + unsigned input_tensors = TfLiteInterpreterGetInputTensorCount(interpreter); + for (unsigned i = 0; i < input_tensors; i++) { + TfLiteTensor *input_tensor = TfLiteInterpreterGetInputTensor(interpreter, i); + + if (generate_random_input) { + int shape[4] = {input_tensor->dims->data[0], + input_tensor->dims->data[1], + input_tensor->dims->data[2], + input_tensor->dims->data[3]}; + xt::xarray a = xt::random::randint(shape, 0, 255); + input.push_back({a.begin(), a.end()}); + } + + TfLiteTensorCopyFromBuffer(input_tensor, input[i].data(), input_tensor->bytes); + } + + EXPECT_EQ(TfLiteInterpreterInvoke(interpreter), kTfLiteOk); + + unsigned output_tensors = TfLiteInterpreterGetOutputTensorCount(interpreter); + for (unsigned i = 0; i < output_tensors; i++) { + const TfLiteTensor *output_tensor = TfLiteInterpreterGetOutputTensor(interpreter, i); + + std::vector out; + out.resize(output_tensor->bytes); + EXPECT_EQ(TfLiteTensorCopyToBuffer(output_tensor, out.data(), output_tensor->bytes), kTfLiteOk); + + output.push_back(out); + } + + TfLiteInterpreterDelete(interpreter); + if (executor == EXECUTOR_NPU) + tflite_plugin_destroy_delegate(delegate); + TfLiteInterpreterOptionsDelete(options); + + return output; +} diff --git a/src/gallium/targets/teflon/test_executor.h b/src/gallium/targets/teflon/test_executor.h new file mode 100644 index 00000000000..8e1c9d746e9 --- /dev/null +++ b/src/gallium/targets/teflon/test_executor.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2023-2024 Tomeu Vizoso + * SPDX-License-Identifier: MIT + */ + +enum executor { + EXECUTOR_CPU, + EXECUTOR_NPU, +}; + +struct TfLiteModel; + +std::vector conv2d_generate_model(int input_size, + int weight_size, + int input_channels, + int output_channels, + int stride, + bool padding_same, + bool is_signed, + bool depthwise); + +std::vector add_generate_model(int input_size, + int weight_size, + int input_channels, + int output_channels, + int stride, + bool padding_same, + bool is_signed, + bool depthwise); + +std::vector> run_model(TfLiteModel *model, enum executor executor, std::vector> &input); \ No newline at end of file diff --git a/src/gallium/targets/teflon/test_model_generation.py b/src/gallium/targets/teflon/test_model_generation.py new file mode 100644 index 00000000000..a018de90666 --- /dev/null +++ b/src/gallium/targets/teflon/test_model_generation.py @@ -0,0 +1,218 @@ +# MIT License +# +# Copyright (c) 2021 VeriSilicon, INC. +# Copyright (c) 2023 Tomeu Vizoso +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +import math +import os +import os.path +import re +import sys +import tempfile +import time + +import numpy as np +import pytest +import json + +import tensorflow as tf +from tensorflow import keras + +MODEL_PATH = "conv2d.tflite" + +def create_model_keras(batch_size, in_w, in_h, k_w, k_h, in_ch, out_ch, stride, padding, signed, seed, depthwise): + tf.random.set_seed(seed) + + input_shape = [batch_size, in_h, in_w, in_ch] + out_channel = out_ch + kernel_shape = [k_w, k_h] + input_dtype = tf.float32 + + if depthwise: + conv = keras.layers.DepthwiseConv2D(kernel_size=kernel_shape, strides=stride, padding=padding, depth_multiplier=1) + else: + conv = keras.layers.Conv2D(filters=out_channel, kernel_size=kernel_shape, strides=stride, padding=padding) + + model = keras.models.Sequential([ + keras.layers.InputLayer(input_shape=input_shape[1:], batch_size=input_shape[0]), + conv + ]) + model.build(input_shape=input_shape) + + if depthwise: + weight_shape = [k_w, k_h, in_ch, 1] + else: + weight_shape = [k_w, k_h, in_ch, out_ch] + + weight_data = tf.random.normal(weight_shape, 0, 127, input_dtype, seed=seed) + bias_data = tf.random.normal((out_ch, ), 0, 127, input_dtype, seed=seed) + model.set_weights([np.asarray(weight_data, dtype=np.float32), np.asarray(bias_data, dtype=np.float32)]) + + tmp = tempfile.NamedTemporaryFile(delete=False, prefix="conv2d-", suffix=".h5", mode="w") + model.save(tmp.name) + tmp.close() + converter = tf.compat.v1.lite.TFLiteConverter.from_keras_model_file(tmp.name) + os.unlink(tmp.name) + + converter.quantized_input_stats = {model.layers[0].input.name: (128, 128.0)} + converter.default_ranges_stats = (0.0, 6.0) + + if signed: + converter.inference_input_type = tf.int8 + converter.inference_output_type = tf.int8 + converter.inference_type = tf.int8 + else: + converter.inference_input_type = tf.uint8 + converter.inference_output_type = tf.uint8 + converter.inference_type = tf.uint8 + + tflite_model = converter.convert() + + fp = open(MODEL_PATH, "wb") + fp.write(tflite_model) + fp.flush() + + tf.lite.experimental.Analyzer.analyze(model_path=MODEL_PATH, gpu_compatibility=True) + + return MODEL_PATH + +def tflite_to_json(file_path): + ret = os.system("flatc --json src/gallium/frontends/teflon/tests/tflite_schema.fbs -- " + file_path) + assert(ret == 0) + return os.path.splitext(file_path)[0] + ".json" + +WEIGHTS_BUFFER = 2 +BIAS_BUFFER = 3 +VERSION_BUFFER = 5 + +def zero_irrelevant_values(file_path, signed): + model_data = open(file_path).read() + model_data = re.sub("(\\\"(.*?)\\\"|(\\w+))(\\s*:\\s*(\\\".*?\\\"|.))", "\"\\2\\3\"\\4", model_data) + model = json.loads(model_data) + #print(json.dumps(model, indent=4)) + if "version" in model["operator_codes"][0].keys(): + del model["operator_codes"][0]["version"] + for subgraph in model["subgraphs"]: + for tensor in subgraph["tensors"]: + tensor["name"] = "" + if signed: + tensor["quantization"]["scale"] = [0.0] * len(tensor["quantization"]["scale"]) + else: + tensor["quantization"]["scale"] = [0.0] + if signed: + tensor["quantization"]["zero_point"] = [0] * len(tensor["quantization"]["zero_point"]) + else: + tensor["quantization"]["zero_point"] = [0] + + model["buffers"][BIAS_BUFFER]["data"] = [0] * len(model["buffers"][BIAS_BUFFER]["data"]) + model["buffers"][WEIGHTS_BUFFER]["data"] = [0] * len(model["buffers"][WEIGHTS_BUFFER]["data"]) + model["buffers"][VERSION_BUFFER]["data"] = [0] + + if "signature_defs" in model: + del model["signature_defs"] + + open(file_path, "w").write(json.dumps(model, indent=4)) + +def diff(file_1, file_2): + ret = os.system("diff -U30 -u " + file_1 + " " + file_2) + assert(ret == 0) + +def create_model(batch_size, in_w, in_h, k_w, k_h, in_ch, out_ch, stride, padding, signed, seed, depthwise): + args = ['build/src/gallium/targets/teflon/test_teflon', + 'generate_model', + str(in_w), + str(k_w), + str(in_ch), + str(out_ch), + str(stride), + "1" if padding == "same" else "0", + str(int(signed)), + str(int(depthwise)), + str(seed)] + print(' '.join(args)) + os.system(' '.join(args)) + return "model.tflite" + +def convolution(batch_size, input_size, weight_size, in_ch, out_ch, stride, padding, signed, seed, depthwise): + + in_w = input_size + in_h = input_size + k_w = weight_size + k_h = weight_size + + # Depthwise convolutions require the out channels to be a multiple of input channels + assert not (depthwise and out_ch % in_ch != 0) + + # Depthwise convolutions with a single IFM don't make sense + assert not (depthwise and in_ch == 1) + + # Depthwise convolutions with IFM != OFM are not supported + assert not (depthwise and out_ch != in_ch) + + np.random.seed(seed) + + model_file = create_model_keras(batch_size, in_w, in_h, k_w, k_h, in_ch, out_ch, stride, padding, signed, seed, depthwise) + model_file_2 = create_model(batch_size, in_w, in_h, k_w, k_h, in_ch, out_ch, stride, padding, signed, seed, depthwise) + + json_file = tflite_to_json(model_file) + json_file_2 = tflite_to_json(model_file_2) + + os.unlink(model_file) + os.unlink(model_file_2) + + zero_irrelevant_values(json_file, signed) + zero_irrelevant_values(json_file_2, signed) + + #print(json.dumps(json.loads(open(json_file).read()), indent=4)) + + diff(json_file, json_file_2) + + os.unlink(json_file) + os.unlink(json_file_2) + +@pytest.mark.parametrize("batch_size", [1]) +@pytest.mark.parametrize("input_size", [4, 112]) +@pytest.mark.parametrize("weight_size", [1, 3]) +@pytest.mark.parametrize("in_ch", [1, 32, 120, 128, 256]) +@pytest.mark.parametrize("out_ch", [1, 32, 120, 128, 256, 480]) +@pytest.mark.parametrize("stride", [1, 2]) +@pytest.mark.parametrize("padding", ["valid", "same"]) +@pytest.mark.parametrize("signed", [False]) +@pytest.mark.parametrize("seed", [4, 5]) +def test_conv2d(batch_size, input_size, weight_size, in_ch, out_ch, stride, padding, signed, seed): + s = "%r-%r-%s-%r-%r-%r-%r-%r-%r" % (seed, signed, padding, stride, out_ch, in_ch, weight_size, input_size, batch_size) + print(s, file=sys.stderr) + convolution(batch_size, input_size, weight_size, in_ch, out_ch, stride, padding, signed, seed, depthwise=False) + +@pytest.mark.parametrize("batch_size", [1]) +@pytest.mark.parametrize("input_size", [4, 112]) +@pytest.mark.parametrize("weight_size", [3]) +@pytest.mark.parametrize("channels", [32, 128, 256]) +@pytest.mark.parametrize("stride", [1, 2]) +@pytest.mark.parametrize("padding", ["valid", "same"]) +@pytest.mark.parametrize("signed", [False]) +@pytest.mark.parametrize("seed", [4, 5]) +def test_depthwise(batch_size, input_size, weight_size, channels, stride, padding, signed, seed): + s = "%r-%s-%r-%r-%r-%r-%r-%r" % (seed, signed, padding, stride, channels, weight_size, input_size, batch_size) + print(s, file=sys.stderr) + convolution(batch_size, input_size, weight_size, channels, channels, stride, padding, signed, seed, depthwise=True) + +test_conv2d(1, 80, 5, 16, 128, 2, "same", False, 4) \ No newline at end of file diff --git a/src/gallium/targets/teflon/test_teflon.cpp b/src/gallium/targets/teflon/test_teflon.cpp new file mode 100644 index 00000000000..f9f9ebe1a34 --- /dev/null +++ b/src/gallium/targets/teflon/test_teflon.cpp @@ -0,0 +1,514 @@ +/* + * Copyright (c) 2023-2024 Tomeu Vizoso + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include +#include + +#include +#include "tensorflow/lite/c/c_api.h" +#include "test_executor.h" + +#define TEST_CONV2D 1 +#define TEST_DEPTHWISE 1 +#define TEST_ADD 1 +#define TEST_MOBILENETV1 1 +#define TEST_MOBILEDET 1 + +#define TOLERANCE 2 +#define MODEL_TOLERANCE 8 +#define QUANT_TOLERANCE 2 + +std::vector is_signed{false}; /* TODO: Support INT8? */ +std::vector padding_same{false, true}; +std::vector stride{1, 2}; +std::vector output_channels{1, 32, 120, 128, 160, 256}; +std::vector input_channels{1, 32, 120, 128, 256}; +std::vector dw_channels{1, 32, 120, 128, 256}; +std::vector dw_weight_size{3, 5}; +std::vector weight_size{1, 3, 5}; +std::vector input_size{3, 5, 8, 80, 112}; + +static bool +cache_is_enabled(void) +{ + return getenv("TEFLON_ENABLE_CACHE"); +} + +static bool +read_into(const char *path, std::vector &buf) +{ + FILE *f = fopen(path, "rb"); + if (f == NULL) + return false; + + fseek(f, 0, SEEK_END); + long fsize = ftell(f); + fseek(f, 0, SEEK_SET); + + buf.resize(fsize); + fread(buf.data(), fsize, 1, f); + + fclose(f); + + return true; +} + +static void +set_seed(unsigned seed) +{ + srand(seed); + xt::random::seed(seed); +} + +static void +test_model(std::vector buf, std::string cache_dir, unsigned tolerance) +{ + std::vector> input; + std::vector> cpu_output; + std::ostringstream input_cache; + input_cache << cache_dir << "/" + << "input.data"; + + std::ostringstream output_cache; + output_cache << cache_dir << "/" + << "output.data"; + + TfLiteModel *model = TfLiteModelCreate(buf.data(), buf.size()); + assert(model); + + if (cache_is_enabled()) { + input.resize(1); + bool ret = read_into(input_cache.str().c_str(), input[0]); + + if (ret) { + cpu_output.resize(1); + ret = read_into(output_cache.str().c_str(), cpu_output[0]); + } + } + + if (cpu_output.size() == 0 || cpu_output[0].size() == 0) { + input.resize(0); + cpu_output.resize(0); + + cpu_output = run_model(model, EXECUTOR_CPU, input); + + if (cache_is_enabled()) { + std::ofstream file(input_cache.str().c_str(), std::ios::out | std::ios::binary); + file.write(reinterpret_cast(input[0].data()), input[0].size()); + file.close(); + + file = std::ofstream(output_cache.str().c_str(), std::ios::out | std::ios::binary); + file.write(reinterpret_cast(cpu_output[0].data()), cpu_output[0].size()); + file.close(); + } + } + + std::vector> npu_output = run_model(model, EXECUTOR_NPU, input); + + EXPECT_EQ(cpu_output.size(), npu_output.size()) << "Array sizes differ."; + for (size_t i = 0; i < cpu_output.size(); i++) { + EXPECT_EQ(cpu_output[i].size(), npu_output[i].size()) << "Array sizes differ (" << i << ")."; + + for (size_t j = 0; j < cpu_output[i].size(); j++) { + if (abs(cpu_output[i][j] - npu_output[i][j]) > tolerance) { + std::cout << "CPU: "; + for (int k = 0; k < std::min(int(cpu_output[i].size()), 24); k++) + std::cout << std::setfill('0') << std::setw(2) << std::hex << int(cpu_output[i][k]) << " "; + std::cout << "\n"; + std::cout << "NPU: "; + for (int k = 0; k < std::min(int(npu_output[i].size()), 24); k++) + std::cout << std::setfill('0') << std::setw(2) << std::hex << int(npu_output[i][k]) << " "; + std::cout << "\n"; + + FAIL() << "Output at " << j << " from the NPU (" << std::setfill('0') << std::setw(2) << std::hex << int(npu_output[i][j]) << ") doesn't match that from the CPU (" << std::setfill('0') << std::setw(2) << std::hex << int(cpu_output[i][j]) << ")."; + } + } + } + + TfLiteModelDelete(model); +} + +static void +test_model_file(std::string file_name) +{ + set_seed(4); + + std::ifstream model_file(file_name, std::ios::binary); + std::vector buffer((std::istreambuf_iterator(model_file)), + std::istreambuf_iterator()); + test_model(buffer, "", MODEL_TOLERANCE); +} + +void +test_conv(int input_size, int weight_size, int input_channels, int output_channels, + int stride, bool padding_same, bool is_signed, bool depthwise, int seed) +{ + std::vector buf; + std::ostringstream cache_dir, model_cache; + cache_dir << "/var/cache/teflon_tests/" << input_size << "_" << weight_size << "_" << input_channels << "_" << output_channels << "_" << stride << "_" << padding_same << "_" << is_signed << "_" << depthwise << "_" << seed; + model_cache << cache_dir.str() << "/" + << "model.tflite"; + + if (weight_size > input_size) + GTEST_SKIP(); + + set_seed(seed); + + if (cache_is_enabled()) { + if (access(model_cache.str().c_str(), F_OK) == 0) { + read_into(model_cache.str().c_str(), buf); + } + } + + if (buf.size() == 0) { + buf = conv2d_generate_model(input_size, weight_size, + input_channels, output_channels, + stride, padding_same, is_signed, + depthwise); + + if (cache_is_enabled()) { + if (access(cache_dir.str().c_str(), F_OK) != 0) { + ASSERT_TRUE(std::filesystem::create_directories(cache_dir.str().c_str())); + } + std::ofstream file(model_cache.str().c_str(), std::ios::out | std::ios::binary); + file.write(reinterpret_cast(buf.data()), buf.size()); + file.close(); + } + } + + test_model(buf, cache_dir.str(), TOLERANCE); +} + +void +test_add(int input_size, int weight_size, int input_channels, int output_channels, + int stride, bool padding_same, bool is_signed, bool depthwise, int seed, + unsigned tolerance) +{ + std::vector buf; + std::ostringstream cache_dir, model_cache; + cache_dir << "/var/cache/teflon_tests/" + << "add_" << input_size << "_" << weight_size << "_" << input_channels << "_" << output_channels << "_" << stride << "_" << padding_same << "_" << is_signed << "_" << depthwise << "_" << seed; + model_cache << cache_dir.str() << "/" + << "model.tflite"; + + if (weight_size > input_size) + GTEST_SKIP(); + + set_seed(seed); + + if (cache_is_enabled()) { + if (access(model_cache.str().c_str(), F_OK) == 0) { + read_into(model_cache.str().c_str(), buf); + } + } + + if (buf.size() == 0) { + buf = add_generate_model(input_size, weight_size, + input_channels, output_channels, + stride, padding_same, is_signed, + depthwise); + + if (cache_is_enabled()) { + if (access(cache_dir.str().c_str(), F_OK) != 0) { + ASSERT_TRUE(std::filesystem::create_directories(cache_dir.str().c_str())); + } + std::ofstream file(model_cache.str().c_str(), std::ios::out | std::ios::binary); + file.write(reinterpret_cast(buf.data()), buf.size()); + file.close(); + } + } + + test_model(buf, cache_dir.str(), tolerance); +} + +#if TEST_CONV2D + +class Conv2D : public testing::TestWithParam> {}; + +TEST_P(Conv2D, Op) +{ + test_conv(std::get<6>(GetParam()), + std::get<5>(GetParam()), + std::get<4>(GetParam()), + std::get<3>(GetParam()), + std::get<2>(GetParam()), + std::get<1>(GetParam()), + std::get<0>(GetParam()), + false, /* depthwise */ + 4); +} + +static inline std::string +Conv2DTestCaseName( + const testing::TestParamInfo> &info) +{ + std::string name = ""; + + name += "input_size_" + std::to_string(std::get<6>(info.param)); + name += "_weight_size_" + std::to_string(std::get<5>(info.param)); + name += "_input_channels_" + std::to_string(std::get<4>(info.param)); + name += "_output_channels_" + std::to_string(std::get<3>(info.param)); + name += "_stride_" + std::to_string(std::get<2>(info.param)); + name += "_padding_same_" + std::to_string(std::get<1>(info.param)); + name += "_is_signed_" + std::to_string(std::get<0>(info.param)); + + return name; +} + +INSTANTIATE_TEST_SUITE_P( + , Conv2D, + ::testing::Combine(::testing::ValuesIn(is_signed), + ::testing::ValuesIn(padding_same), + ::testing::ValuesIn(stride), + ::testing::ValuesIn(output_channels), + ::testing::ValuesIn(input_channels), + ::testing::ValuesIn(weight_size), + ::testing::ValuesIn(input_size)), + Conv2DTestCaseName); + +#endif + +#if TEST_DEPTHWISE + +class DepthwiseConv2D : public testing::TestWithParam> {}; + +TEST_P(DepthwiseConv2D, Op) +{ + test_conv(std::get<5>(GetParam()), + std::get<4>(GetParam()), + std::get<3>(GetParam()), + std::get<3>(GetParam()), + std::get<2>(GetParam()), + std::get<1>(GetParam()), + std::get<0>(GetParam()), + true, /* depthwise */ + 4); +} + +static inline std::string +DepthwiseConv2DTestCaseName( + const testing::TestParamInfo> &info) +{ + std::string name = ""; + + name += "input_size_" + std::to_string(std::get<5>(info.param)); + name += "_weight_size_" + std::to_string(std::get<4>(info.param)); + name += "_channels_" + std::to_string(std::get<3>(info.param)); + name += "_stride_" + std::to_string(std::get<2>(info.param)); + name += "_padding_same_" + std::to_string(std::get<1>(info.param)); + name += "_is_signed_" + std::to_string(std::get<0>(info.param)); + + return name; +} + +INSTANTIATE_TEST_SUITE_P( + , DepthwiseConv2D, + ::testing::Combine(::testing::ValuesIn(is_signed), + ::testing::ValuesIn(padding_same), + ::testing::ValuesIn(stride), + ::testing::ValuesIn(dw_channels), + ::testing::ValuesIn(dw_weight_size), + ::testing::ValuesIn(input_size)), + DepthwiseConv2DTestCaseName); + +#endif + +#if TEST_ADD + +class Add : public testing::TestWithParam> {}; + +TEST_P(Add, Op) +{ + test_add(std::get<6>(GetParam()), + std::get<5>(GetParam()), + std::get<4>(GetParam()), + std::get<3>(GetParam()), + std::get<2>(GetParam()), + std::get<1>(GetParam()), + std::get<0>(GetParam()), + false, /* depthwise */ + 4, + TOLERANCE); +} + +static inline std::string +AddTestCaseName( + const testing::TestParamInfo> &info) +{ + std::string name = ""; + + name += "input_size_" + std::to_string(std::get<6>(info.param)); + name += "_weight_size_" + std::to_string(std::get<5>(info.param)); + name += "_input_channels_" + std::to_string(std::get<4>(info.param)); + name += "_output_channels_" + std::to_string(std::get<3>(info.param)); + name += "_stride_" + std::to_string(std::get<2>(info.param)); + name += "_padding_same_" + std::to_string(std::get<1>(info.param)); + name += "_is_signed_" + std::to_string(std::get<0>(info.param)); + + return name; +} + +INSTANTIATE_TEST_SUITE_P( + , Add, + ::testing::Combine(::testing::ValuesIn(is_signed), + ::testing::ValuesIn(padding_same), + ::testing::ValuesIn(stride), + ::testing::ValuesIn(output_channels), + ::testing::ValuesIn(input_channels), + ::testing::ValuesIn(weight_size), + ::testing::ValuesIn(input_size)), + AddTestCaseName); + +class AddQuant : public testing::TestWithParam {}; + +TEST_P(AddQuant, Op) +{ + test_add(40, + 1, + 1, + 1, + 1, + false, /* padding_same */ + false, /* is_signed */ + false, /* depthwise */ + GetParam(), + QUANT_TOLERANCE); +} + +INSTANTIATE_TEST_SUITE_P( + , AddQuant, + ::testing::Range(0, 100)); + +#endif + +#if TEST_MOBILENETV1 + +class MobileNetV1 : public ::testing::Test {}; + +class MobileNetV1Param : public testing::TestWithParam {}; + +TEST(MobileNetV1, Whole) +{ + std::ostringstream file_path; + assert(getenv("TEFLON_TEST_DATA")); + file_path << getenv("TEFLON_TEST_DATA") << "/mobilenet_v1_1.0_224_quant.tflite"; + + test_model_file(file_path.str()); +} + +TEST_P(MobileNetV1Param, Op) +{ + std::ostringstream file_path; + assert(getenv("TEFLON_TEST_DATA")); + file_path << getenv("TEFLON_TEST_DATA") << "/mb" << GetParam() << ".tflite"; + + test_model_file(file_path.str()); +} + +static inline std::string +MobileNetV1TestCaseName( + const testing::TestParamInfo &info) +{ + std::string name = ""; + + name += "mb"; + name += std::to_string(info.param); + + return name; +} + +INSTANTIATE_TEST_SUITE_P( + , MobileNetV1Param, + ::testing::Range(0, 28), + MobileNetV1TestCaseName); + +#endif + +#if TEST_MOBILEDET + +class MobileDet : public ::testing::Test {}; + +class MobileDetParam : public testing::TestWithParam {}; + +TEST(MobileDet, Whole) +{ + std::ostringstream file_path; + assert(getenv("TEFLON_TEST_DATA")); + file_path << getenv("TEFLON_TEST_DATA") << "/ssdlite_mobiledet_coco_qat_postprocess.tflite"; + + test_model_file(file_path.str()); +} + +TEST_P(MobileDetParam, Op) +{ + std::ostringstream file_path; + assert(getenv("TEFLON_TEST_DATA")); + file_path << getenv("TEFLON_TEST_DATA") << "/mobiledet" << GetParam() << ".tflite"; + + test_model_file(file_path.str()); +} + +static inline std::string +MobileDetTestCaseName( + const testing::TestParamInfo &info) +{ + std::string name = ""; + + name += "mobiledet"; + name += std::to_string(info.param); + + return name; +} + +INSTANTIATE_TEST_SUITE_P( + , MobileDetParam, + ::testing::Range(0, 121), + MobileDetTestCaseName); + +#endif + +int +main(int argc, char **argv) +{ + if (argc > 1 && !strcmp(argv[1], "generate_model")) { + std::vector buf; + + assert(argc == 11); + + std::cout << "Generating model to ./model.tflite\n"; + + int n = 2; + int input_size = atoi(argv[n++]); + int weight_size = atoi(argv[n++]); + int input_channels = atoi(argv[n++]); + int output_channels = atoi(argv[n++]); + int stride = atoi(argv[n++]); + int padding_same = atoi(argv[n++]); + int is_signed = atoi(argv[n++]); + int depthwise = atoi(argv[n++]); + int seed = atoi(argv[n++]); + + set_seed(seed); + + buf = conv2d_generate_model(input_size, weight_size, + input_channels, output_channels, + stride, padding_same, is_signed, + depthwise); + + int fd = open("model.tflite", O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + write(fd, buf.data(), buf.size()); + close(fd); + + return 0; + } else if (argc > 1 && !strcmp(argv[1], "run_model")) { + test_model_file(std::string(argv[2])); + } else { + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); + } +} diff --git a/src/gallium/targets/teflon/tests/add.tflite b/src/gallium/targets/teflon/tests/add.tflite new file mode 100644 index 00000000000..63029db8d24 Binary files /dev/null and b/src/gallium/targets/teflon/tests/add.tflite differ diff --git a/src/gallium/targets/teflon/tests/conv2d.tflite b/src/gallium/targets/teflon/tests/conv2d.tflite new file mode 100644 index 00000000000..07b89fd1321 Binary files /dev/null and b/src/gallium/targets/teflon/tests/conv2d.tflite differ diff --git a/src/gallium/targets/teflon/tests/mb0.tflite b/src/gallium/targets/teflon/tests/mb0.tflite new file mode 100644 index 00000000000..e1145b7182f Binary files /dev/null and b/src/gallium/targets/teflon/tests/mb0.tflite differ diff --git a/src/gallium/targets/teflon/tests/mb01.tflite b/src/gallium/targets/teflon/tests/mb01.tflite new file mode 100644 index 00000000000..71d65ed460d Binary files /dev/null and b/src/gallium/targets/teflon/tests/mb01.tflite differ diff --git a/src/gallium/targets/teflon/tests/mb1.tflite b/src/gallium/targets/teflon/tests/mb1.tflite new file mode 100644 index 00000000000..f2626d9ac34 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mb1.tflite differ diff --git a/src/gallium/targets/teflon/tests/mb10.tflite b/src/gallium/targets/teflon/tests/mb10.tflite new file mode 100644 index 00000000000..3f56fc1799d Binary files /dev/null and b/src/gallium/targets/teflon/tests/mb10.tflite differ diff --git a/src/gallium/targets/teflon/tests/mb11.tflite b/src/gallium/targets/teflon/tests/mb11.tflite new file mode 100644 index 00000000000..a0d7ad1daeb Binary files /dev/null and b/src/gallium/targets/teflon/tests/mb11.tflite differ diff --git a/src/gallium/targets/teflon/tests/mb12.tflite b/src/gallium/targets/teflon/tests/mb12.tflite new file mode 100644 index 00000000000..542883db300 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mb12.tflite differ diff --git a/src/gallium/targets/teflon/tests/mb13.tflite b/src/gallium/targets/teflon/tests/mb13.tflite new file mode 100644 index 00000000000..7ceda9bd7d1 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mb13.tflite differ diff --git a/src/gallium/targets/teflon/tests/mb14.tflite b/src/gallium/targets/teflon/tests/mb14.tflite new file mode 100644 index 00000000000..7ff70685fdb Binary files /dev/null and b/src/gallium/targets/teflon/tests/mb14.tflite differ diff --git a/src/gallium/targets/teflon/tests/mb15.tflite b/src/gallium/targets/teflon/tests/mb15.tflite new file mode 100644 index 00000000000..2ce9c93805c Binary files /dev/null and b/src/gallium/targets/teflon/tests/mb15.tflite differ diff --git a/src/gallium/targets/teflon/tests/mb16.tflite b/src/gallium/targets/teflon/tests/mb16.tflite new file mode 100644 index 00000000000..e84d37851b1 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mb16.tflite differ diff --git a/src/gallium/targets/teflon/tests/mb17.tflite b/src/gallium/targets/teflon/tests/mb17.tflite new file mode 100644 index 00000000000..c1957809a8a Binary files /dev/null and b/src/gallium/targets/teflon/tests/mb17.tflite differ diff --git a/src/gallium/targets/teflon/tests/mb18.tflite b/src/gallium/targets/teflon/tests/mb18.tflite new file mode 100644 index 00000000000..71306c00a96 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mb18.tflite differ diff --git a/src/gallium/targets/teflon/tests/mb19.tflite b/src/gallium/targets/teflon/tests/mb19.tflite new file mode 100644 index 00000000000..f817d39edd9 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mb19.tflite differ diff --git a/src/gallium/targets/teflon/tests/mb2.tflite b/src/gallium/targets/teflon/tests/mb2.tflite new file mode 100644 index 00000000000..074069bd7ba Binary files /dev/null and b/src/gallium/targets/teflon/tests/mb2.tflite differ diff --git a/src/gallium/targets/teflon/tests/mb20.tflite b/src/gallium/targets/teflon/tests/mb20.tflite new file mode 100644 index 00000000000..f4d738402ad Binary files /dev/null and b/src/gallium/targets/teflon/tests/mb20.tflite differ diff --git a/src/gallium/targets/teflon/tests/mb21.tflite b/src/gallium/targets/teflon/tests/mb21.tflite new file mode 100644 index 00000000000..fa7a3841bfd Binary files /dev/null and b/src/gallium/targets/teflon/tests/mb21.tflite differ diff --git a/src/gallium/targets/teflon/tests/mb22.tflite b/src/gallium/targets/teflon/tests/mb22.tflite new file mode 100644 index 00000000000..30d12a4b319 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mb22.tflite differ diff --git a/src/gallium/targets/teflon/tests/mb23.tflite b/src/gallium/targets/teflon/tests/mb23.tflite new file mode 100644 index 00000000000..d7dfe668690 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mb23.tflite differ diff --git a/src/gallium/targets/teflon/tests/mb24.tflite b/src/gallium/targets/teflon/tests/mb24.tflite new file mode 100644 index 00000000000..eb9e9ee376e Binary files /dev/null and b/src/gallium/targets/teflon/tests/mb24.tflite differ diff --git a/src/gallium/targets/teflon/tests/mb25.tflite b/src/gallium/targets/teflon/tests/mb25.tflite new file mode 100644 index 00000000000..591b6b52430 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mb25.tflite differ diff --git a/src/gallium/targets/teflon/tests/mb26.tflite b/src/gallium/targets/teflon/tests/mb26.tflite new file mode 100644 index 00000000000..3824df36d84 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mb26.tflite differ diff --git a/src/gallium/targets/teflon/tests/mb27.tflite b/src/gallium/targets/teflon/tests/mb27.tflite new file mode 100644 index 00000000000..f0731814eb6 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mb27.tflite differ diff --git a/src/gallium/targets/teflon/tests/mb28.tflite b/src/gallium/targets/teflon/tests/mb28.tflite new file mode 100644 index 00000000000..459619c8bd8 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mb28.tflite differ diff --git a/src/gallium/targets/teflon/tests/mb29.tflite b/src/gallium/targets/teflon/tests/mb29.tflite new file mode 100644 index 00000000000..385cc3e7563 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mb29.tflite differ diff --git a/src/gallium/targets/teflon/tests/mb3.tflite b/src/gallium/targets/teflon/tests/mb3.tflite new file mode 100644 index 00000000000..75662f85e37 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mb3.tflite differ diff --git a/src/gallium/targets/teflon/tests/mb30.tflite b/src/gallium/targets/teflon/tests/mb30.tflite new file mode 100644 index 00000000000..c8970c17361 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mb30.tflite differ diff --git a/src/gallium/targets/teflon/tests/mb4.tflite b/src/gallium/targets/teflon/tests/mb4.tflite new file mode 100644 index 00000000000..217f0cf63c7 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mb4.tflite differ diff --git a/src/gallium/targets/teflon/tests/mb5.tflite b/src/gallium/targets/teflon/tests/mb5.tflite new file mode 100644 index 00000000000..62ffbb9d577 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mb5.tflite differ diff --git a/src/gallium/targets/teflon/tests/mb6.tflite b/src/gallium/targets/teflon/tests/mb6.tflite new file mode 100644 index 00000000000..5f8499a5a30 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mb6.tflite differ diff --git a/src/gallium/targets/teflon/tests/mb7.tflite b/src/gallium/targets/teflon/tests/mb7.tflite new file mode 100644 index 00000000000..b39b619da04 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mb7.tflite differ diff --git a/src/gallium/targets/teflon/tests/mb8.tflite b/src/gallium/targets/teflon/tests/mb8.tflite new file mode 100644 index 00000000000..00de033e316 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mb8.tflite differ diff --git a/src/gallium/targets/teflon/tests/mb9.tflite b/src/gallium/targets/teflon/tests/mb9.tflite new file mode 100644 index 00000000000..289c281443d Binary files /dev/null and b/src/gallium/targets/teflon/tests/mb9.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet0.tflite b/src/gallium/targets/teflon/tests/mobiledet0.tflite new file mode 100644 index 00000000000..5439001b42f Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet0.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet1.tflite b/src/gallium/targets/teflon/tests/mobiledet1.tflite new file mode 100644 index 00000000000..bde11b84851 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet1.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet10.tflite b/src/gallium/targets/teflon/tests/mobiledet10.tflite new file mode 100644 index 00000000000..fb488eec695 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet10.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet100.tflite b/src/gallium/targets/teflon/tests/mobiledet100.tflite new file mode 100644 index 00000000000..0193ebb60ad Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet100.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet101.tflite b/src/gallium/targets/teflon/tests/mobiledet101.tflite new file mode 100644 index 00000000000..de9ce09ced7 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet101.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet102.tflite b/src/gallium/targets/teflon/tests/mobiledet102.tflite new file mode 100644 index 00000000000..69bf103f0be Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet102.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet103.tflite b/src/gallium/targets/teflon/tests/mobiledet103.tflite new file mode 100644 index 00000000000..cabc8e57f91 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet103.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet104.tflite b/src/gallium/targets/teflon/tests/mobiledet104.tflite new file mode 100644 index 00000000000..b8c3a4d1f6f Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet104.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet105.tflite b/src/gallium/targets/teflon/tests/mobiledet105.tflite new file mode 100644 index 00000000000..3925eac0dab Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet105.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet106.tflite b/src/gallium/targets/teflon/tests/mobiledet106.tflite new file mode 100644 index 00000000000..b93f46bd1d4 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet106.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet107.tflite b/src/gallium/targets/teflon/tests/mobiledet107.tflite new file mode 100644 index 00000000000..241932d61bb Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet107.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet108.tflite b/src/gallium/targets/teflon/tests/mobiledet108.tflite new file mode 100644 index 00000000000..caae46fdce6 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet108.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet109.tflite b/src/gallium/targets/teflon/tests/mobiledet109.tflite new file mode 100644 index 00000000000..536082e0976 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet109.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet11.tflite b/src/gallium/targets/teflon/tests/mobiledet11.tflite new file mode 100644 index 00000000000..e7024bf5b99 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet11.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet110.tflite b/src/gallium/targets/teflon/tests/mobiledet110.tflite new file mode 100644 index 00000000000..b97441515d7 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet110.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet111.tflite b/src/gallium/targets/teflon/tests/mobiledet111.tflite new file mode 100644 index 00000000000..76884a284c2 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet111.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet112.tflite b/src/gallium/targets/teflon/tests/mobiledet112.tflite new file mode 100644 index 00000000000..d7fbbcf8173 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet112.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet113.tflite b/src/gallium/targets/teflon/tests/mobiledet113.tflite new file mode 100644 index 00000000000..0d539669aef Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet113.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet114.tflite b/src/gallium/targets/teflon/tests/mobiledet114.tflite new file mode 100644 index 00000000000..61d6969bb66 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet114.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet115.tflite b/src/gallium/targets/teflon/tests/mobiledet115.tflite new file mode 100644 index 00000000000..8c6a29b5cf2 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet115.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet116.tflite b/src/gallium/targets/teflon/tests/mobiledet116.tflite new file mode 100644 index 00000000000..3d42c8f336c Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet116.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet117.tflite b/src/gallium/targets/teflon/tests/mobiledet117.tflite new file mode 100644 index 00000000000..3331f442f32 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet117.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet118.tflite b/src/gallium/targets/teflon/tests/mobiledet118.tflite new file mode 100644 index 00000000000..c9bab7cd94c Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet118.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet119.tflite b/src/gallium/targets/teflon/tests/mobiledet119.tflite new file mode 100644 index 00000000000..b572aa43cdf Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet119.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet12.tflite b/src/gallium/targets/teflon/tests/mobiledet12.tflite new file mode 100644 index 00000000000..68b75bc5a0e Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet12.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet120.tflite b/src/gallium/targets/teflon/tests/mobiledet120.tflite new file mode 100644 index 00000000000..519d25099e4 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet120.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet121.tflite b/src/gallium/targets/teflon/tests/mobiledet121.tflite new file mode 100644 index 00000000000..43712e4b4eb Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet121.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet122.tflite b/src/gallium/targets/teflon/tests/mobiledet122.tflite new file mode 100644 index 00000000000..4981f356d5e Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet122.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet123.tflite b/src/gallium/targets/teflon/tests/mobiledet123.tflite new file mode 100644 index 00000000000..25a731a4811 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet123.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet13.tflite b/src/gallium/targets/teflon/tests/mobiledet13.tflite new file mode 100644 index 00000000000..87715d78c3e Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet13.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet14.tflite b/src/gallium/targets/teflon/tests/mobiledet14.tflite new file mode 100644 index 00000000000..e6be3eb32a3 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet14.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet15.tflite b/src/gallium/targets/teflon/tests/mobiledet15.tflite new file mode 100644 index 00000000000..509d8ae482d Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet15.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet16.tflite b/src/gallium/targets/teflon/tests/mobiledet16.tflite new file mode 100644 index 00000000000..cf5b4f12ec5 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet16.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet17.tflite b/src/gallium/targets/teflon/tests/mobiledet17.tflite new file mode 100644 index 00000000000..29d17ddd7d2 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet17.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet18.tflite b/src/gallium/targets/teflon/tests/mobiledet18.tflite new file mode 100644 index 00000000000..adedf49b063 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet18.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet19.tflite b/src/gallium/targets/teflon/tests/mobiledet19.tflite new file mode 100644 index 00000000000..d9f1b24d08a Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet19.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet2.tflite b/src/gallium/targets/teflon/tests/mobiledet2.tflite new file mode 100644 index 00000000000..22691c2aebd Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet2.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet20.tflite b/src/gallium/targets/teflon/tests/mobiledet20.tflite new file mode 100644 index 00000000000..a7626e4efe4 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet20.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet21.tflite b/src/gallium/targets/teflon/tests/mobiledet21.tflite new file mode 100644 index 00000000000..b420753d869 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet21.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet22.tflite b/src/gallium/targets/teflon/tests/mobiledet22.tflite new file mode 100644 index 00000000000..8734f889971 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet22.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet23.tflite b/src/gallium/targets/teflon/tests/mobiledet23.tflite new file mode 100644 index 00000000000..01dbc526e13 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet23.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet24.tflite b/src/gallium/targets/teflon/tests/mobiledet24.tflite new file mode 100644 index 00000000000..46819702533 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet24.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet25.tflite b/src/gallium/targets/teflon/tests/mobiledet25.tflite new file mode 100644 index 00000000000..f263c288c6f Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet25.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet26.tflite b/src/gallium/targets/teflon/tests/mobiledet26.tflite new file mode 100644 index 00000000000..5ab9c7ec5c3 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet26.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet27.tflite b/src/gallium/targets/teflon/tests/mobiledet27.tflite new file mode 100644 index 00000000000..bb004ccc363 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet27.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet28.tflite b/src/gallium/targets/teflon/tests/mobiledet28.tflite new file mode 100644 index 00000000000..e0a6b197391 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet28.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet29.tflite b/src/gallium/targets/teflon/tests/mobiledet29.tflite new file mode 100644 index 00000000000..a50488b6e63 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet29.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet3.tflite b/src/gallium/targets/teflon/tests/mobiledet3.tflite new file mode 100644 index 00000000000..f94359a5919 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet3.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet30.tflite b/src/gallium/targets/teflon/tests/mobiledet30.tflite new file mode 100644 index 00000000000..8dc571c3cbb Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet30.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet31.tflite b/src/gallium/targets/teflon/tests/mobiledet31.tflite new file mode 100644 index 00000000000..d727847391d Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet31.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet32.tflite b/src/gallium/targets/teflon/tests/mobiledet32.tflite new file mode 100644 index 00000000000..2b57d761a8c Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet32.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet33.tflite b/src/gallium/targets/teflon/tests/mobiledet33.tflite new file mode 100644 index 00000000000..0a86dbf0bc6 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet33.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet34.tflite b/src/gallium/targets/teflon/tests/mobiledet34.tflite new file mode 100644 index 00000000000..97363e2ad6b Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet34.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet35.tflite b/src/gallium/targets/teflon/tests/mobiledet35.tflite new file mode 100644 index 00000000000..5798ccc6dca Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet35.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet36.tflite b/src/gallium/targets/teflon/tests/mobiledet36.tflite new file mode 100644 index 00000000000..2344d6e74fb Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet36.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet37.tflite b/src/gallium/targets/teflon/tests/mobiledet37.tflite new file mode 100644 index 00000000000..7d9ad97f956 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet37.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet38.tflite b/src/gallium/targets/teflon/tests/mobiledet38.tflite new file mode 100644 index 00000000000..2037b21441e Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet38.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet39.tflite b/src/gallium/targets/teflon/tests/mobiledet39.tflite new file mode 100644 index 00000000000..e48b11a9b33 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet39.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet4.tflite b/src/gallium/targets/teflon/tests/mobiledet4.tflite new file mode 100644 index 00000000000..3f23771f479 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet4.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet40.tflite b/src/gallium/targets/teflon/tests/mobiledet40.tflite new file mode 100644 index 00000000000..c2aa7b02dfe Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet40.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet41.tflite b/src/gallium/targets/teflon/tests/mobiledet41.tflite new file mode 100644 index 00000000000..9bdaad598fc Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet41.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet42.tflite b/src/gallium/targets/teflon/tests/mobiledet42.tflite new file mode 100644 index 00000000000..ad5966056f5 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet42.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet43.tflite b/src/gallium/targets/teflon/tests/mobiledet43.tflite new file mode 100644 index 00000000000..a2204212abb Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet43.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet44.tflite b/src/gallium/targets/teflon/tests/mobiledet44.tflite new file mode 100644 index 00000000000..8e46f839312 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet44.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet45.tflite b/src/gallium/targets/teflon/tests/mobiledet45.tflite new file mode 100644 index 00000000000..c96d7c8d92d Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet45.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet46.tflite b/src/gallium/targets/teflon/tests/mobiledet46.tflite new file mode 100644 index 00000000000..b007f694e65 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet46.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet47.tflite b/src/gallium/targets/teflon/tests/mobiledet47.tflite new file mode 100644 index 00000000000..27719a96aaa Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet47.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet48.tflite b/src/gallium/targets/teflon/tests/mobiledet48.tflite new file mode 100644 index 00000000000..7ac82267c25 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet48.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet49.tflite b/src/gallium/targets/teflon/tests/mobiledet49.tflite new file mode 100644 index 00000000000..718d6b1d2df Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet49.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet5.tflite b/src/gallium/targets/teflon/tests/mobiledet5.tflite new file mode 100644 index 00000000000..3af8fa651df Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet5.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet50.tflite b/src/gallium/targets/teflon/tests/mobiledet50.tflite new file mode 100644 index 00000000000..07f1ea4d460 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet50.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet51.tflite b/src/gallium/targets/teflon/tests/mobiledet51.tflite new file mode 100644 index 00000000000..3cd1070a460 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet51.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet52.tflite b/src/gallium/targets/teflon/tests/mobiledet52.tflite new file mode 100644 index 00000000000..8a70a7b6b13 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet52.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet53.tflite b/src/gallium/targets/teflon/tests/mobiledet53.tflite new file mode 100644 index 00000000000..f2b39a3d2d7 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet53.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet54.tflite b/src/gallium/targets/teflon/tests/mobiledet54.tflite new file mode 100644 index 00000000000..74cc33cbf83 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet54.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet55.tflite b/src/gallium/targets/teflon/tests/mobiledet55.tflite new file mode 100644 index 00000000000..77fe88f9e33 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet55.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet56.tflite b/src/gallium/targets/teflon/tests/mobiledet56.tflite new file mode 100644 index 00000000000..07892cca12a Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet56.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet57.tflite b/src/gallium/targets/teflon/tests/mobiledet57.tflite new file mode 100644 index 00000000000..94d76118806 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet57.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet58.tflite b/src/gallium/targets/teflon/tests/mobiledet58.tflite new file mode 100644 index 00000000000..41462b79299 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet58.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet59.tflite b/src/gallium/targets/teflon/tests/mobiledet59.tflite new file mode 100644 index 00000000000..4d49a33ea8e Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet59.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet6.tflite b/src/gallium/targets/teflon/tests/mobiledet6.tflite new file mode 100644 index 00000000000..aee54318ca6 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet6.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet60.tflite b/src/gallium/targets/teflon/tests/mobiledet60.tflite new file mode 100644 index 00000000000..f10375e58ca Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet60.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet61.tflite b/src/gallium/targets/teflon/tests/mobiledet61.tflite new file mode 100644 index 00000000000..a41591def73 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet61.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet62.tflite b/src/gallium/targets/teflon/tests/mobiledet62.tflite new file mode 100644 index 00000000000..acf8a25f633 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet62.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet63.tflite b/src/gallium/targets/teflon/tests/mobiledet63.tflite new file mode 100644 index 00000000000..558930875b4 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet63.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet64.tflite b/src/gallium/targets/teflon/tests/mobiledet64.tflite new file mode 100644 index 00000000000..fddcc147da7 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet64.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet65.tflite b/src/gallium/targets/teflon/tests/mobiledet65.tflite new file mode 100644 index 00000000000..395d6a9ce82 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet65.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet66.tflite b/src/gallium/targets/teflon/tests/mobiledet66.tflite new file mode 100644 index 00000000000..d5b062d5738 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet66.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet67.tflite b/src/gallium/targets/teflon/tests/mobiledet67.tflite new file mode 100644 index 00000000000..6990c2d6988 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet67.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet68.tflite b/src/gallium/targets/teflon/tests/mobiledet68.tflite new file mode 100644 index 00000000000..0cbbda48d13 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet68.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet69.tflite b/src/gallium/targets/teflon/tests/mobiledet69.tflite new file mode 100644 index 00000000000..74eb13be6a6 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet69.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet7.tflite b/src/gallium/targets/teflon/tests/mobiledet7.tflite new file mode 100644 index 00000000000..953a95ca4bf Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet7.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet70.tflite b/src/gallium/targets/teflon/tests/mobiledet70.tflite new file mode 100644 index 00000000000..10adba095ed Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet70.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet71.tflite b/src/gallium/targets/teflon/tests/mobiledet71.tflite new file mode 100644 index 00000000000..66921ce14fd Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet71.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet72.tflite b/src/gallium/targets/teflon/tests/mobiledet72.tflite new file mode 100644 index 00000000000..8126db02827 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet72.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet73.tflite b/src/gallium/targets/teflon/tests/mobiledet73.tflite new file mode 100644 index 00000000000..ab6051f161e Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet73.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet74.tflite b/src/gallium/targets/teflon/tests/mobiledet74.tflite new file mode 100644 index 00000000000..ae367054147 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet74.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet75.tflite b/src/gallium/targets/teflon/tests/mobiledet75.tflite new file mode 100644 index 00000000000..a4023022bf8 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet75.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet76.tflite b/src/gallium/targets/teflon/tests/mobiledet76.tflite new file mode 100644 index 00000000000..359c745ba56 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet76.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet77.tflite b/src/gallium/targets/teflon/tests/mobiledet77.tflite new file mode 100644 index 00000000000..5fe1d487d2f Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet77.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet78.tflite b/src/gallium/targets/teflon/tests/mobiledet78.tflite new file mode 100644 index 00000000000..6e27d9081a1 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet78.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet79.tflite b/src/gallium/targets/teflon/tests/mobiledet79.tflite new file mode 100644 index 00000000000..0197966ff33 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet79.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet8.tflite b/src/gallium/targets/teflon/tests/mobiledet8.tflite new file mode 100644 index 00000000000..f82f5707f5d Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet8.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet80.tflite b/src/gallium/targets/teflon/tests/mobiledet80.tflite new file mode 100644 index 00000000000..108ea5e5e36 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet80.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet81.tflite b/src/gallium/targets/teflon/tests/mobiledet81.tflite new file mode 100644 index 00000000000..2c934db3843 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet81.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet82.tflite b/src/gallium/targets/teflon/tests/mobiledet82.tflite new file mode 100644 index 00000000000..6bc38cc5a07 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet82.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet83.tflite b/src/gallium/targets/teflon/tests/mobiledet83.tflite new file mode 100644 index 00000000000..77f87e1b93c Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet83.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet84.tflite b/src/gallium/targets/teflon/tests/mobiledet84.tflite new file mode 100644 index 00000000000..57661f8619a Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet84.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet85.tflite b/src/gallium/targets/teflon/tests/mobiledet85.tflite new file mode 100644 index 00000000000..922464fee21 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet85.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet86.tflite b/src/gallium/targets/teflon/tests/mobiledet86.tflite new file mode 100644 index 00000000000..891aa5a0ea9 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet86.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet87.tflite b/src/gallium/targets/teflon/tests/mobiledet87.tflite new file mode 100644 index 00000000000..54378c14482 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet87.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet88.tflite b/src/gallium/targets/teflon/tests/mobiledet88.tflite new file mode 100644 index 00000000000..3e44e1bca8c Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet88.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet89.tflite b/src/gallium/targets/teflon/tests/mobiledet89.tflite new file mode 100644 index 00000000000..fcf9a15fef4 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet89.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet9.tflite b/src/gallium/targets/teflon/tests/mobiledet9.tflite new file mode 100644 index 00000000000..8db64d3e3b1 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet9.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet90.tflite b/src/gallium/targets/teflon/tests/mobiledet90.tflite new file mode 100644 index 00000000000..f2592f2badf Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet90.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet91.tflite b/src/gallium/targets/teflon/tests/mobiledet91.tflite new file mode 100644 index 00000000000..847941f5e80 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet91.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet92.tflite b/src/gallium/targets/teflon/tests/mobiledet92.tflite new file mode 100644 index 00000000000..0413ce81505 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet92.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet93.tflite b/src/gallium/targets/teflon/tests/mobiledet93.tflite new file mode 100644 index 00000000000..ed4d3d22865 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet93.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet94.tflite b/src/gallium/targets/teflon/tests/mobiledet94.tflite new file mode 100644 index 00000000000..c086c4bd55d Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet94.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet95.tflite b/src/gallium/targets/teflon/tests/mobiledet95.tflite new file mode 100644 index 00000000000..542313c7c1b Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet95.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet96.tflite b/src/gallium/targets/teflon/tests/mobiledet96.tflite new file mode 100644 index 00000000000..0c3cb5a9e5b Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet96.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet97.tflite b/src/gallium/targets/teflon/tests/mobiledet97.tflite new file mode 100644 index 00000000000..89641e529f9 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet97.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet98.tflite b/src/gallium/targets/teflon/tests/mobiledet98.tflite new file mode 100644 index 00000000000..ed3fe0d5424 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet98.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobiledet99.tflite b/src/gallium/targets/teflon/tests/mobiledet99.tflite new file mode 100644 index 00000000000..d32e87b4975 Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobiledet99.tflite differ diff --git a/src/gallium/targets/teflon/tests/mobilenet_v1_1.0_224_quant.tflite b/src/gallium/targets/teflon/tests/mobilenet_v1_1.0_224_quant.tflite new file mode 100644 index 00000000000..51d9d1648dc Binary files /dev/null and b/src/gallium/targets/teflon/tests/mobilenet_v1_1.0_224_quant.tflite differ diff --git a/src/gallium/targets/teflon/tests/ssdlite_mobiledet_coco_qat_postprocess.tflite b/src/gallium/targets/teflon/tests/ssdlite_mobiledet_coco_qat_postprocess.tflite new file mode 100644 index 00000000000..66f6f3a5422 Binary files /dev/null and b/src/gallium/targets/teflon/tests/ssdlite_mobiledet_coco_qat_postprocess.tflite differ diff --git a/src/gallium/targets/teflon/tflite-schema-v2.15.0.fbs b/src/gallium/targets/teflon/tflite-schema-v2.15.0.fbs new file mode 100644 index 00000000000..993c069e461 --- /dev/null +++ b/src/gallium/targets/teflon/tflite-schema-v2.15.0.fbs @@ -0,0 +1,1642 @@ +// 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. +// Version 3a: Add new builtin op code field. Has backward compatibility with +// version 3. +// Version 3b: Rename fields in SignatureDef. Has backward compatibility with +// version 3 and 3a. +// Version 3c: Move constant tensor buffers & custom op buffers outside from +// Flatbuffers. Has backward compatibility with version 3, 3a and +// 3b. + +namespace tflite; + +// This corresponds to the version. +file_identifier "TFL3"; +// File extension of any written files. +file_extension "tflite"; + +// IMPORTANT: All new members of tables, enums and unions must be added at the +// end to ensure backwards compatibility. + +// 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, + INT8 = 9, + FLOAT64 = 10, + COMPLEX128 = 11, + UINT64 = 12, + // Experimental: Resource and variant types are experimental, that are subject + // to change. Do not implement custom kernels using resource & variant types + // now. + RESOURCE = 13, + VARIANT = 14, + UINT32 = 15, + UINT16 = 16, + INT4 = 17, +} + +// Custom quantization parameters for experimenting with new quantization +// techniques. +table CustomQuantization { + custom:[ubyte] (force_align: 16); +} + +// Represents a specific quantization technique's parameters. +union QuantizationDetails { + CustomQuantization, +} + +// Parameters for converting a quantized tensor back to float. +table QuantizationParameters { + // These four parameters are the asymmetric linear quantization parameters. + // Given a quantized value q, the corresponding float value f should be: + // f = scale * (q - zero_point) + // For other quantization types, the QuantizationDetails below is used. + 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]; + + // If this is not none, the other quantization parameters (i.e. min, max, + // scale, zero_point fields above) are ignored and the value of the + // QuantizationDetails union should be used. + details:QuantizationDetails; + + // Specifies the dimension of the Tensor's shape that the scales and + // zero_points correspond to. For example, a tensor t, with dims=[4, 3, 2, 1] + // with quantization params: + // scale=[1.0, 2.0, 3.0], zero_point=[1, 2, 3], quantization_dimension=1 + // will be quantized across the second dimension of t. + // t[:, 0, :, :] will have scale[0]=1.0, zero_point[0]=1 + // t[:, 1, :, :] will have scale[1]=2.0, zero_point[0]=2 + // t[:, 2, :, :] will have scale[2]=3.0, zero_point[0]=3 + quantized_dimension:int; +} + +// Sparse tensors. +// We use a modification of the TACO format. +// Reference: http://tensor-compiler.org/kjolstad-oopsla17-tensor-compiler.pdf +// +// To encode a conceptual n-dimensional dense tensor with dims (d0, ..., dn-1), +// potentially with a k-dimensional block (0 <= k <= n) with dims +// (dn, ..., dn+k-1), the format needs to specify: +// 1. In what order to traverse these dimensions. For example, to store a 2-D +// matrix in row major order, the traversal order would be (d0, d1), +// whereas to store it in column major order, the traversal order would be +// (d1, d0). If the 2-D matrix has a 2-D inner block, the traversal order +// could be (d0, d1, d2, d3). +// 2. How each block dimension in (dn, ..., dn+k-1) maps to the original +// tensor dimension in (d0, ..., dn-1). +// 3. In the traversal order defined above, the format (dense vs. sparse) and +// index metadata for each dimension. For a dense dimension, this is just +// the size of that dimension. For a sparse dimension, it's the same as +// the compressed index defined in the Compressed Sparse Row (CSR) format. +// (http://scipy-lectures.org/advanced/scipy_sparse/csr_matrix.html) + +// The storage type for a dimension. Currently we support: +// 1. DENSE: each coordinate in this dimension is stored implicitly. +// 2. SPARSE_CSR: only the coordinates with non-zero elements are stored. The +// compression technique is the same what CSR uses. +// More types like a sparse dimension with a different compression technique +// could be added to the list in the future. +enum DimensionType : byte { + DENSE = 0, + SPARSE_CSR = 1, +} + +table Int32Vector { + values:[int]; +} + +table Uint16Vector { + values:[ushort] (force_align: 4); +} + +table Uint8Vector { + values:[ubyte] (force_align: 4); +} + +// Variable-typed buffer to store the index metadata for a sparse dimension. +// The widest type is Int32 instead of UInt32 because tensor's shape is a int32 +// vector. We don't want the per-dimensional index to overflow that range. +union SparseIndexVector { + Int32Vector, + Uint16Vector, + Uint8Vector +} + +table DimensionMetadata { + // Whether a dimension is dense or sparse. + format:DimensionType; + // Index metadata used for a dimension. + // - If format is DimensionType.DENSE then we use the dense_size field to + // store the size of that dimension. Each index in that dimension is + // stored implicitly. + // - If format is DimensionType.SPARSE_CSR then we use array_segments and + // array_indices to encode that dimension. array_segments represents how + // to segment the indices array, each segment corresponds to one element + // in the previous dimension. array_indices represents the index of the + // non-zero elements within this dimension (as those in the CSR matrix + // format, where the first array is row pointers and the second array is + // column indices). + dense_size:int; + array_segments:SparseIndexVector; + array_indices:SparseIndexVector; +} + +// Parameters to encode a sparse TfLite tensor. +table SparsityParameters { + // The traversal order of the dimensions defined in the `shape` field of the + // conceptual dense tensor. For a n-dimensional tensors with dims (d0, d1, + // ..., dn-1), + // - if not block sparse, the traversal_order is just a permutation of (d0, + // ..., dn-1). For example, a 2-D matrix stored in row-major order would + // have traversal_order = (d0, d1). + // - if block sparse with a k-dimensional block (0 <= k <= n), the + // traversal_order has n + k elements. The first n elements are still a + // permutation of (d0, ..., dn-1). The lask k elements are a permutation + // of (dn, ..., dn+k-1), defining how to traverse a block internally. For + // example, a 2-D matrix with 2-D blocks, both stored in row-major order + // would have traversal_order = (d0, d1, d2, d3). + traversal_order:[int]; + // For an n-dimensional tensor with a k-dimensional block (0 <= k <= n), + // stores how a block dimension in (dn, ..., dn+k-1) maps to the original + // tensor dimension in (d0, ..., dn). + // It's stored in the order of (dn, ..., dn+k-1). + // If not block-sparse, this field is NULL. + block_map:[int]; + // In the traversal order defined above, the metadata needed for + // each dimension to locate the non-zero values in the original dense tensor. + // The size of the dim_metadata array = the size of the traversal_order array + // = n + k. + dim_metadata:[DimensionMetadata]; +} + +// The nested tensor type for VARIANT type. +table VariantSubType { + // The tensor shape. + shape:[int]; + type:TensorType; + // If false, the rank or the number of tensor dimensions is unknown. + // If false, "shape" must be []. + has_rank: bool = false; +} + +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; + + // Parameters to encode a sparse tensor. See the example in + // tensorflow/lite/testdata/sparse_tensor.json. + sparsity:SparsityParameters; // Optional. + + // Encodes `shape` with unknown dimensions. Unknown dimensions are + // represented with -1. + shape_signature:[int]; // Optional. + + // This field is added to distinguish between scalars and tensors of unknown + // ranks (both of which shape is []). + // For scalars (rank = 0), shape = [] and has_rank = true. + // For tensors with known rank (rank > 0) and shape, shape = [...] and + // has_rank = true. + // For tensors with unknown rank and shape, shape = [] and has_rank = false. + has_rank: bool = false; + + // The nested Tensor types for VARIANT type. This is always empty for + // non-VARIANT types. This is optional because the nested type can be omitted. + // Currently only 1 subtype is supported. The field is defined as an array for + // flexibility of supporting multiple subtypes in the future. + variant_tensors:[VariantSubType]; +} + +// 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. +// LINT.IfChange +enum BuiltinOperator : int32 { + 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, + 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, + FLOOR_MOD = 95, + RANGE = 96, + RESIZE_NEAREST_NEIGHBOR = 97, + LEAKY_RELU = 98, + SQUARED_DIFFERENCE = 99, + MIRROR_PAD = 100, + ABS = 101, + SPLIT_V = 102, + UNIQUE = 103, + CEIL = 104, + REVERSE_V2 = 105, + ADD_N = 106, + GATHER_ND = 107, + COS = 108, + WHERE = 109, + RANK = 110, + ELU = 111, + REVERSE_SEQUENCE = 112, + MATRIX_DIAG = 113, + QUANTIZE = 114, + MATRIX_SET_DIAG = 115, + ROUND = 116, + HARD_SWISH = 117, + IF = 118, + WHILE = 119, + NON_MAX_SUPPRESSION_V4 = 120, + NON_MAX_SUPPRESSION_V5 = 121, + SCATTER_ND = 122, + SELECT_V2 = 123, + DENSIFY = 124, + SEGMENT_SUM = 125, + BATCH_MATMUL = 126, + PLACEHOLDER_FOR_GREATER_OP_CODES = 127, + CUMSUM = 128, + CALL_ONCE = 129, + BROADCAST_TO = 130, + RFFT2D = 131, + CONV_3D = 132, + IMAG=133, + REAL=134, + COMPLEX_ABS=135, + HASHTABLE = 136, + HASHTABLE_FIND = 137, + HASHTABLE_IMPORT = 138, + HASHTABLE_SIZE = 139, + REDUCE_ALL = 140, + CONV_3D_TRANSPOSE = 141, + VAR_HANDLE = 142, + READ_VARIABLE = 143, + ASSIGN_VARIABLE = 144, + BROADCAST_ARGS = 145, + RANDOM_STANDARD_NORMAL = 146, + BUCKETIZE = 147, + RANDOM_UNIFORM = 148, + MULTINOMIAL = 149, + GELU = 150, + DYNAMIC_UPDATE_SLICE = 151, + RELU_0_TO_1 = 152, + UNSORTED_SEGMENT_PROD = 153, + UNSORTED_SEGMENT_MAX = 154, + UNSORTED_SEGMENT_SUM = 155, + ATAN2 = 156, + UNSORTED_SEGMENT_MIN = 157, + SIGN = 158, + BITCAST = 159, + BITWISE_XOR = 160, + RIGHT_SHIFT = 161, + // All Operators start with STABLEHLO_ prefixes are subject to change + // Many of the ops below can not be executed by TFlite runtime + STABLEHLO_LOGISTIC = 162, // WARNING: Do not have runtime support + STABLEHLO_ADD = 163, // WARNING: No runtime support yet + STABLEHLO_DIVIDE = 164, // WARNING: No runtime support yet + STABLEHLO_MULTIPLY = 165, // WARNING: No runtime support yet + STABLEHLO_MAXIMUM = 166, // WARNING: No runtime support yet + STABLEHLO_RESHAPE = 167, // WARNING: No runtime support yet + STABLEHLO_CLAMP = 168, // WARNING: No runtime support + STABLEHLO_CONCATENATE = 169, // WARNING: No runtime support + STABLEHLO_BROADCAST_IN_DIM = 170, // WARNING: No runtime support + STABLEHLO_CONVOLUTION = 171, // WARNING: No runtime support + STABLEHLO_SLICE = 172, // WARNING: No runtime support + STABLEHLO_CUSTOM_CALL = 173, // WARNING: No runtime support + STABLEHLO_REDUCE = 174, // WARNING: No runtime support + STABLEHLO_ABS = 175, // WARNING: No runtime support + STABLEHLO_AND = 176, // WARNING: No runtime support + STABLEHLO_COSINE = 177, // WARNING: No runtime support + STABLEHLO_EXPONENTIAL = 178, // WARNING: No runtime support + STABLEHLO_FLOOR = 179, // WARNING: No runtime support + STABLEHLO_LOG = 180, // WARNING: No runtime support + STABLEHLO_MINIMUM = 181, // WARNING: No runtime support + STABLEHLO_NEGATE = 182, // WARNING: No runtime support + STABLEHLO_OR = 183, // WARNING: No runtime support + STABLEHLO_POWER = 184, // WARNING: No runtime support + STABLEHLO_REMAINDER = 185, // WARNING: No runtime support + STABLEHLO_RSQRT = 186, // WARNING: No runtime support + STABLEHLO_SELECT = 187, // WARNING: No runtime support + STABLEHLO_SUBTRACT = 188, // WARNING: No runtime support + STABLEHLO_TANH = 189, // WARNING: No runtime support + STABLEHLO_SCATTER = 190, + STABLEHLO_COMPARE = 191, // WARNING: No runtime support + STABLEHLO_CONVERT = 192, // WARNING: No runtime support + STABLEHLO_DYNAMIC_SLICE = 193, // WARNING: No runtime support + STABLEHLO_DYNAMIC_UPDATE_SLICE = 194, // WARNING: No runtime support + STABLEHLO_PAD = 195, // WARNING: No runtime support + STABLEHLO_IOTA = 196, // WARNING: No runtime support + STABLEHLO_DOT_GENERAL = 197, // WARNING: No runtime support + STABLEHLO_REDUCE_WINDOW = 198, // WARNING: No runtime support + STABLEHLO_SORT = 199, // WARNING: No runtime support + STABLEHLO_WHILE = 200, // WARNING: No runtime support + STABLEHLO_GATHER = 201, // WARNING: No runtime support + STABLEHLO_TRANSPOSE = 202, // WARNING: No runtime support + DILATE = 203, + STABLEHLO_RNG_BIT_GENERATOR = 204, + REDUCE_WINDOW = 205, +} +// LINT.ThenChange(nnapi_linter/linter.proto) + +// 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, + BidirectionalSequenceLSTMOptions, + BidirectionalSequenceRNNOptions, + UnidirectionalSequenceLSTMOptions, + FloorModOptions, + RangeOptions, + ResizeNearestNeighborOptions, + LeakyReluOptions, + SquaredDifferenceOptions, + MirrorPadOptions, + AbsOptions, + SplitVOptions, + UniqueOptions, + ReverseV2Options, + AddNOptions, + GatherNdOptions, + CosOptions, + WhereOptions, + RankOptions, + ReverseSequenceOptions, + MatrixDiagOptions, + QuantizeOptions, + MatrixSetDiagOptions, + HardSwishOptions, + IfOptions, + WhileOptions, + DepthToSpaceOptions, + NonMaxSuppressionV4Options, + NonMaxSuppressionV5Options, + ScatterNdOptions, + SelectV2Options, + DensifyOptions, + SegmentSumOptions, + BatchMatMulOptions, + CumsumOptions, + CallOnceOptions, + BroadcastToOptions, + Rfft2dOptions, + Conv3DOptions, + HashtableOptions, + HashtableFindOptions, + HashtableImportOptions, + HashtableSizeOptions, + VarHandleOptions, + ReadVariableOptions, + AssignVariableOptions, + RandomOptions, + BucketizeOptions, + GeluOptions, + DynamicUpdateSliceOptions, + UnsortedSegmentProdOptions, + UnsortedSegmentMaxOptions, + UnsortedSegmentMinOptions, + UnsortedSegmentSumOptions, + ATan2Options, + SignOptions, + BitcastOptions, + BitwiseXorOptions, + RightShiftOptions, + // DO NOT add new options this union, will cause failure in Java api + // generation otherwise + // Add new builtin options into builtin options 2 instead +} + +union BuiltinOptions2{ + StablehloConcatenateOptions, + StablehloBroadcastInDimOptions, + StablehloSliceOptions, + StablehloConvolutionOptions, + StablehloCustomCallOptions, + StablehloReduceOptions, + StablehloScatterOptions, + StablehloCompareOptions, + StablehloDynamicSliceOptions, + StablehloPadOptions, + StablehloIotaOptions, + StablehloDotGeneralOptions, + StablehloReduceWindowOptions, + StablehloSortOptions, + StablehloWhileOptions, + StablehloGatherOptions, + StablehloTransposeOptions, + DilateOptions, + StablehloRngBitGeneratorOptions, + ReduceWindowOptions, +} + +table StablehloGatherOptions{ + offset_dims : [long]; + collapsed_slice_dims : [long]; + start_index_map : [long]; + index_vector_dim : long; + slice_sizes : [long]; + indices_are_sorted : bool; +} + +table StablehloTransposeOptions{ + permutation : [long]; +} + +enum StablehloPrecisionConfig : uint { + DEFAULT, + HIGH, + HIGHEST, +} + +table StablehloDotGeneralOptions{ + lhs_batching_dimensions : [long]; + rhs_batching_dimensions : [long]; + lhs_contracting_dimensions : [long]; + rhs_contracting_dimensions : [long]; + precision_config : [StablehloPrecisionConfig]; +} + +table StablehloReduceWindowOptions{ + window_dimensions : [long]; + window_strides : [long]; + base_dilations : [long]; + window_dilations : [long]; + padding : [long]; + body_subgraph_index : int; +} + +table StablehloWhileOptions{ + cond_subgraph_index : int; + body_subgraph_index : int; +} + +table StablehloSortOptions{ + dimension : long; + is_stable : bool; + comparator_subgraph_index : int; +} + +table StablehloConcatenateOptions { + dimension : long; +} + +table StablehloBroadcastInDimOptions{ + broadcast_dimensions : [long]; +} + +enum StablehloComparisonDirection : uint { + STABLEHLO_COMPARISON_DIRECTION_EQ, + STABLEHLO_COMPARISON_DIRECTION_NE, + STABLEHLO_COMPARISON_DIRECTION_GE, + STABLEHLO_COMPARISON_DIRECTION_GT, + STABLEHLO_COMPARISON_DIRECTION_LE, + STABLEHLO_COMPARISON_DIRECTION_LT, + +} + +enum StablehloComparisonType : uint { + STABLEHLO_COMPARISON_TYPE_NOTYPE, + STABLEHLO_COMPARISON_TYPE_FLOAT, + STABLEHLO_COMPARISON_TYPE_FLOAT_TOTAL_ORDER, + STABLEHLO_COMPARISON_TYPE_SIGNED, + STABLEHLO_COMPARISON_TYPE_UNSIGNED, +} + +table StablehloCompareOptions{ + comparison_direction : StablehloComparisonDirection; + compare_type : StablehloComparisonType; +} + +table StablehloDynamicSliceOptions{ + slice_sizes : [long]; +} + +table StablehloPadOptions{ + edge_padding_low : [long]; + edge_padding_high : [long]; + interior_padding : [long]; +} + +table StablehloIotaOptions{ + iota_dimension : long; +} + +table StablehloCustomCallOptions { + call_target_name : string; + has_side_effect : bool; + backend_config: string; + api_version : int; // will be decprecated + called_computations: [int]; // should point to subgraphs of the computations + custom_attributes : [ubyte]; +} + +table StablehloReduceOptions { + dimensions : [long]; + body_subgraph_index : int; +} + +table StablehloSliceOptions{ + start_indices : [long]; + limit_indices : [long]; + strides : [long]; +} + +table StablehloConvolutionOptions{ + window_strides : [long]; + padding : [long]; + lhs_dilation : [long]; + rhs_dilation : [long]; + window_reversal : [bool]; + input_batch_dimension : long; + input_feature_dimension : long; + input_spatial_dimensions : [long]; + kernel_input_feature_dimension : long; + kernel_output_feature_dimension : long; + kernel_spatial_dimensions : [long]; + output_batch_dimension : long; + output_feature_dimension : long; + output_spatial_dimensions : [long]; + feature_group_count : long; + batch_group_count : long; + precision_config : [StablehloPrecisionConfig]; +} + +table StablehloScatterOptions { + indices_are_sorted: bool; + update_window_dims: [long]; + inserted_window_dims: [long]; + scatter_dims_to_operand_dims: [long]; + index_vector_dim: long; + unique_indices: bool; + update_computation_subgraph_index: int; +} + +enum RngAlgorithm : byte { + // An algorithm auto-selected by the system according to device type. + DEFAULT = 0, + // The Philox algorithm, as described in paper + // ['Parallel Random Numbers: As Easy as 1, 2, 3'] + // (https://www.thesalmons.org/john/random123/papers/random123sc11.pdf) + PHILOX = 1, + // The ThreeFry algorithm, as described in paper + // ['Parallel Random Numbers: As Easy as 1, 2, 3'] + // (https://www.thesalmons.org/john/random123/papers/random123sc11.pdf) + THREEFRY = 2, +} + +table StablehloRngBitGeneratorOptions { + algorithm:RngAlgorithm; +} + +// LINT.IfChange +enum Padding : byte { SAME, VALID } +// LINT.ThenChange(//tensorflow/compiler/mlir/lite/ir/tfl_op_enums.td) + +// LINT.IfChange +enum ActivationFunctionType : byte { + NONE = 0, + RELU = 1, + RELU_N1_TO_1 = 2, + RELU6 = 3, + TANH = 4, + SIGN_BIT = 5, +} +// LINT.ThenChange(//tensorflow/compiler/mlir/lite/ir/tfl_op_enums.td) + +table Conv2DOptions { + padding:Padding; + stride_w:int; + stride_h:int; + fused_activation_function:ActivationFunctionType; + dilation_w_factor:int = 1; + dilation_h_factor:int = 1; + // Parameters for Conv2D version 8 or above. + // When set, quantized_bias_type defines the dtype for both bias and accumulator. + quantized_bias_type: TensorType; +} + +// Options for both Conv3D and Conv3DTranspose. +table Conv3DOptions { + padding:Padding; + stride_d:int; + stride_w:int; + stride_h:int; + fused_activation_function:ActivationFunctionType; + dilation_d_factor:int = 1; + 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` is redundant. It's used by CPU kernels in + // TensorFlow 2.0 or below, but ignored in versions above. + // See comments in lite/c/builtin_op_data.h for more details. + 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; + // For weights-only quantization, use asymmetric quantization for non + // constant inputs at evaluation time. + asymmetric_quantize_inputs:bool; +} + +// An implementation of TensorFlow RNNCell. +table RNNOptions { + fused_activation_function:ActivationFunctionType; + asymmetric_quantize_inputs:bool; +} + +// An implementation of TensorFlow dynamic_rnn with RNNCell. +table SequenceRNNOptions { + time_major:bool; + fused_activation_function:ActivationFunctionType; + asymmetric_quantize_inputs:bool; +} + +// An implementation of TensorFlow bidrectional_dynamic_rnn with RNNCell. +table BidirectionalSequenceRNNOptions { + time_major:bool; + fused_activation_function:ActivationFunctionType; + merge_outputs: bool; + asymmetric_quantize_inputs:bool; +} + +// LINT.IfChange +enum FullyConnectedOptionsWeightsFormat: byte { + DEFAULT = 0, + SHUFFLED4x16INT8 = 1, +} +// LINT.ThenChange(//tensorflow/compiler/mlir/lite/ir/tfl_op_enums.td) + +// 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; + + // Parameters for FullyConnected version 5 or above. + // If set to true, then the number of dimension is preserved. Furthermore, + // all but the last dimension of the input and output shapes will be equal. + keep_num_dims: bool; + + // Parameters for FullyConnected version 7 or above. + // If set to true, then weights-only op will use asymmetric quantization for + // inputs. + asymmetric_quantize_inputs: bool; + + // Parameters for FullyConnected version 11 or above. + // When set, quantized_bias_type defines the dtype for both bias and accumulator. + quantized_bias_type: TensorType; +} + +table SoftmaxOptions { + beta: float; +} + +// An implementation of TensorFlow concat. +table ConcatenationOptions { + axis:int; + fused_activation_function:ActivationFunctionType; +} + +table AddOptions { + fused_activation_function:ActivationFunctionType; + // Parameters supported by version 3. + pot_scale_int16:bool = true; +} + +table MulOptions { + fused_activation_function:ActivationFunctionType; +} + +table L2NormOptions { + // This field is currently ignored in the L2 Norm Op. + fused_activation_function:ActivationFunctionType; +} + +table LocalResponseNormalizationOptions { + radius:int; + bias:float; + alpha:float; + beta:float; +} + +// LINT.IfChange +enum LSTMKernelType : byte { + // Full LSTM kernel which supports peephole and projection. + FULL = 0, + // Basic LSTM kernels. Equivalent to TensorFlow BasicLSTMCell. + BASIC = 1, +} +// LINT.ThenChange(//tensorflow/compiler/mlir/lite/ir/tfl_op_enums.td) + +// 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; + + // Parameters for LSTM version 4 or above. + asymmetric_quantize_inputs: bool; +} + +// An implementation of TensorFlow dynamic_rnn with LSTMCell. +table UnidirectionalSequenceLSTMOptions { + fused_activation_function:ActivationFunctionType; + cell_clip: float; // Optional, 0.0 means no clipping + proj_clip: float; // Optional, 0.0 means no clipping + + // If true then first dimension is sequence, otherwise batch. + time_major:bool; + + // Parameter for Unidirectional Sequence LSTM version 3. + asymmetric_quantize_inputs:bool; + + // Parameter for unidirectional sequence RNN version 4. + diagonal_recurrent_tensors:bool; +} + +table BidirectionalSequenceLSTMOptions { + // Parameters supported by version 1: + fused_activation_function:ActivationFunctionType; + cell_clip: float; // Optional, 0.0 means no clipping + proj_clip: float; // Optional, 0.0 means no clipping + + // If true, store the outputs of both directions into the first output. + merge_outputs: bool; + + // Parameters supported by version 2: + // If true then first dimension is sequence, otherwise batch. + // Version 1 implementations assumed time_major to be true, so this default + // value should never change. + time_major: bool = true; + + // Parameters for version 3 or above. + asymmetric_quantize_inputs:bool; +} + +table ResizeBilinearOptions { + new_height: int (deprecated); + new_width: int (deprecated); + align_corners: bool; + half_pixel_centers: bool; +} + +table ResizeNearestNeighborOptions { + align_corners: bool; + half_pixel_centers: 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 DepthToSpaceOptions { + block_size: int; +} + +table SubOptions { + fused_activation_function:ActivationFunctionType; + // Parameters supported by version 5 + pot_scale_int16:bool = true; +} + +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; + // Parameters for Gather version 5 or above. + batch_dims: int = 0; +} + +table TransposeOptions { +} + +table ExpOptions { +} + +table CosOptions { +} + +table ReducerOptions { + keep_dims: bool; +} + +table SqueezeOptions { + squeeze_dims:[int]; +} + +table SplitOptions { + num_splits: int; +} + +table SplitVOptions { + num_splits: int; +} + +table StridedSliceOptions { + begin_mask: int; + end_mask: int; + ellipsis_mask: int; + new_axis_mask: int; + shrink_axis_mask: int; + // If true, then the end tensor is an offset of the begin tensor. + offset: bool; +} + +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 { + // Parameters supported by version 1, 2, 3: + padding:Padding; + stride_w:int; + stride_h:int; + + // Parameters supported by version 4: + fused_activation_function:ActivationFunctionType = NONE; + + // Parameters for TransposeConv version 5 or above. + // If set, use this for bias and accumulator. + // When set, quantized_bias_type defines the dtype for both bias and accumulator. + quantized_bias_type: TensorType; +} + +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 RankOptions { +} + +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 AbsOptions { +} + + +table HardSwishOptions { +} + +table LogicalAndOptions { +} + +table LogicalNotOptions { +} + +table UnpackOptions { + num:int; + axis:int; +} + +table FloorDivOptions { +} + +table SquareOptions { +} + +table ZerosLikeOptions { +} + +table FillOptions { +} + +table FloorModOptions { +} + +table RangeOptions { +} + +table LeakyReluOptions { + alpha:float; +} + +table SquaredDifferenceOptions { +} + +// LINT.IfChange +enum MirrorPadMode : byte { + // Doesn't include borders. + REFLECT = 0, + // Includes borders. + SYMMETRIC = 1, +} +// LINT.ThenChange(//tensorflow/compiler/mlir/lite/ir/tfl_op_enums.td) + +table MirrorPadOptions { + mode:MirrorPadMode; +} + +table UniqueOptions { + idx_out_type:TensorType = INT32; +} + +table ReverseV2Options { +} + +table AddNOptions { +} + +table GatherNdOptions { +} + +table WhereOptions { +} + +table ReverseSequenceOptions { + seq_dim:int; + batch_dim:int = 0; +} + +table MatrixDiagOptions { +} + +table QuantizeOptions { +} + +table MatrixSetDiagOptions { +} + +table IfOptions { + then_subgraph_index:int; + else_subgraph_index:int; +} + +table CallOnceOptions { + init_subgraph_index:int; +} + +table WhileOptions { + cond_subgraph_index:int; + body_subgraph_index:int; +} + +table NonMaxSuppressionV4Options { +} + +table NonMaxSuppressionV5Options { +} + +table ScatterNdOptions { +} + +table SelectV2Options { +} + +table DensifyOptions { +} + +table SegmentSumOptions { +} + +table BatchMatMulOptions { + adj_x:bool; + adj_y:bool; + // Parameters for BatchMatMul version 4 or above. + // If set to true, then weights-only op will use asymmetric quantization for + // inputs. + asymmetric_quantize_inputs: bool; +} + +table CumsumOptions { + exclusive:bool; + reverse:bool; +} + +table BroadcastToOptions { +} + +table Rfft2dOptions { +} + +table HashtableOptions { + // The identity of hash tables. This identity will be used across different + // subgraphs in the same interpreter instance. + table_id:int; + key_dtype:TensorType; + value_dtype:TensorType; +} + +table HashtableFindOptions { +} + +table HashtableImportOptions { +} + +table HashtableSizeOptions { +} + +table VarHandleOptions { + container:string; + shared_name:string; +} + +table ReadVariableOptions { +} + +table AssignVariableOptions { +} + +table RandomOptions { + seed: long; + seed2: long; +} + +table BucketizeOptions { + boundaries: [float]; // The bucket boundaries. +} + +table GeluOptions { + approximate: bool; +} + +table DynamicUpdateSliceOptions { +} + +table UnsortedSegmentProdOptions { +} + +table UnsortedSegmentMaxOptions { +} + +table UnsortedSegmentSumOptions { +} + +table ATan2Options { +} + +table UnsortedSegmentMinOptions{ +} + +table SignOptions { +} + +table BitcastOptions { +} + +table BitwiseXorOptions { +} + +table RightShiftOptions { +} + +table DilateOptions { +} + +enum ReduceWindowFunction : int { + UNSUPPORTED, + ADD, + MUL, + MINIMUM, + MAXIMUM, + ALL, + ANY, +} + +table ReduceWindowOptions{ + reduce_function: ReduceWindowFunction; +} + +// An OperatorCode can be an enum value (BuiltinOperator) if the operator is a +// builtin, or a string if the operator is custom. +table OperatorCode { + // This field is for backward compatibility. This field will be used when + // the value of the extended builtin_code field has less than + // BulitinOperator_PLACEHOLDER_FOR_GREATER_OP_CODES. + deprecated_builtin_code:byte; + 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; + + // This field is introduced for resolving op builtin code shortage problem + // (the original BuiltinOperator enum field was represented as a byte). + // This field will be used when the value of the extended builtin_code field + // has greater than BulitinOperator_PLACEHOLDER_FOR_GREATER_OP_CODES. + builtin_code:BuiltinOperator; +} + +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 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]; + + // A list of indices to the subgraph's "tensors" that are internal to an Op. + // Internal tensors are those that do not flow in or out of the operation, + // but instead are part of internal computation. As such, the operation's + // implementation may manage its memory more efficiently. They are needed + // however (i.e. not just an implementation detail) since they are part of the + // computation, which may require relevant metadata such as quantization + // parameters. + intermediates:[int]; + + // When an op is using custom_options in a model that is larger than 2GB, then + // we instead use the following attributes to find the buffer location which + // is stored outside of flatbuffers, the offset is calculated relative to the + // beginning of the file and is only valid if > 1 + large_custom_options_offset: ulong; + large_custom_options_size: ulong; + + // Flatbuffers union struct has a 128 elements limit in JAVA, so a second + // union is added, in the case of where BuitlinOptions2 runs out, a third + // one can be added + builtin_options_2 : BuiltinOptions2; +} + +// 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); + + // In a model that is larger than 2GB, then buffers instead uses the following + // attributes to find stored data, which is outside of flatbuffers + // the offset is calculated relative to the beginning of the file and is only + // valid if > 1. + offset: ulong; + size: ulong; +} + +table Metadata { + // A human readable string to uniquely identify a Metadata. + name:string; + // An index to the buffers table. + buffer:uint; +} + +// Map from an alias name of tensor to tensor index in the graph. +// This is used in Signature def. +table TensorMap { + // Represents the alias to use for this tensor. + name:string; + + // The actual tensor index in the primary graph, that 'name' corresponds to. + tensor_index:uint; +} + +// This corresponds to SignatureDef in Tensorflow SavedModel. +// The SignatureDef will be part of the SavedModel provided for conversion. +table SignatureDef { + // Named inputs for this signature. + inputs:[TensorMap]; + + // Named outputs for this signature. + outputs:[TensorMap]; + + // Key value which was in the Tensorflow SavedModel SignatureDef map. + signature_key:string; + + // Model tag, deprecated. + deprecated_tag:string (deprecated); + + // Index of subgraphs that corresponds to the exported method. + subgraph_index:uint; +} + +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. + // Deprecated, prefer to use metadata field. + metadata_buffer:[int]; + + // Metadata about the model. + metadata:[Metadata]; + + // Optional SignatureDefs for the model. + signature_defs:[SignatureDef]; +} + +root_type Model; diff --git a/src/gallium/targets/teflon/tflite-stub.c b/src/gallium/targets/teflon/tflite-stub.c new file mode 100644 index 00000000000..f1d72f1dbfe --- /dev/null +++ b/src/gallium/targets/teflon/tflite-stub.c @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2023-2024 Tomeu Vizoso + * SPDX-License-Identifier: MIT + */ + +#include "tensorflow/lite/c/c_api.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/core/c/c_api.h" + +void +TfLiteInterpreterOptionsAddDelegate(TfLiteInterpreterOptions *options, TfLiteOpaqueDelegate *delegate) +{ +} + +void +TfLiteInterpreterOptionsSetErrorReporter( + TfLiteInterpreterOptions *options, + void (*reporter)(void *user_data, const char *format, va_list args), + void *user_data) +{ +} + +TfLiteInterpreter * +TfLiteInterpreterCreate( + const TfLiteModel *model, + const TfLiteInterpreterOptions *optional_options) +{ + return NULL; +} + +TfLiteStatus +TfLiteInterpreterAllocateTensors(TfLiteInterpreter *interpreter) +{ + return 0; +} + +int32_t +TfLiteInterpreterGetInputTensorCount(const TfLiteInterpreter *interpreter) +{ + return 0; +} + +TfLiteTensor * +TfLiteInterpreterGetInputTensor(const TfLiteInterpreter *interpreter, int32_t input_index) +{ + return NULL; +} + +TfLiteStatus +TfLiteTensorCopyFromBuffer(TfLiteTensor *tensor, + const void *input_data, + size_t input_data_size) +{ + return 0; +} + +TfLiteStatus +TfLiteInterpreterInvoke(TfLiteInterpreter *interpreter) +{ + return 0; +} + +int32_t +TfLiteInterpreterGetOutputTensorCount(const TfLiteInterpreter *interpreter) +{ + return 0; +} + +const TfLiteTensor * +TfLiteInterpreterGetOutputTensor(const TfLiteInterpreter *interpreter, int32_t output_index) +{ + return NULL; +} + +TfLiteStatus +TfLiteTensorCopyToBuffer(const TfLiteTensor *tensor, + void *output_data, + size_t output_data_size) +{ + return 0; +} + +void +TfLiteInterpreterDelete(TfLiteInterpreter *interpreter) +{ +} + +void +TfLiteInterpreterOptionsDelete(TfLiteInterpreterOptions *options) +{ +} + +TfLiteModel * +TfLiteModelCreate(const void *model_data, size_t model_size) +{ + return NULL; +} + +void +TfLiteModelDelete(TfLiteModel *model) +{ +} + +/* FIXME: Why do we need to redeclare the prototype for this one here? */ +TfLiteInterpreterOptions *TfLiteInterpreterOptionsCreate(void); + +TfLiteInterpreterOptions * +TfLiteInterpreterOptionsCreate(void) +{ + return NULL; +}