Skip to content

Commit

Permalink
Fixes builds for cpp examples.
Browse files Browse the repository at this point in the history
- Upgrade to latest libedgetpu with matching tensorflow library
- Use bazel and share WORKSPACE for both examples
- Added docker with cross compile supports
  • Loading branch information
Namburger committed May 9, 2022
1 parent eced31a commit b01fbfc
Show file tree
Hide file tree
Showing 18 changed files with 342 additions and 204 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.idea
7 changes: 7 additions & 0 deletions cpp/examples/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.bazelrc
/bazel-*
/out

** Editors **
*.swp
*.idea
82 changes: 82 additions & 0 deletions cpp/examples/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# Copyright 2022 Google LLC
#
# 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
#
# https://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.
SHELL := /bin/bash
MAKEFILE_DIR := $(realpath $(dir $(lastword $(MAKEFILE_LIST))))
OS := $(shell uname -s)

# Allowed CPU values: k8, armv7a, aarch64
ifeq ($(OS),Linux)
CPU ?= k8
else
$(error $(OS) is not supported)
endif
ifeq ($(filter $(CPU),k8 armv7a aarch64),)
$(error CPU must be k8, armv7a, aarch64)
endif

# Allowed COMPILATION_MODE values: opt, dbg
COMPILATION_MODE ?= opt
ifeq ($(filter $(COMPILATION_MODE),opt dbg),)
$(error COMPILATION_MODE must be opt or dbg)
endif

BAZEL_OUT_DIR := $(MAKEFILE_DIR)/bazel-out/$(CPU)-$(COMPILATION_MODE)/bin
BAZEL_BUILD_FLAGS := --crosstool_top=@crosstool//:toolchains \
--compiler=gcc \
--compilation_mode=$(COMPILATION_MODE) \
--copt=-DNPY_NO_DEPRECATED_API=NPY_1_7_API_VERSION \
--copt=-std=c++14 \
--verbose_failures \
--cpu=$(CPU) \
--experimental_repo_remote_exec

ifeq ($(COMPILATION_MODE), opt)
BAZEL_BUILD_FLAGS += --linkopt=-Wl,--strip-all
else ifeq ($(COMPILATION_MODE), dbg)
# for now, disable arm_neon in dbg.
# see: https://github.com/tensorflow/tensorflow/issues/33360
BAZEL_BUILD_FLAGS += --cxxopt -DTF_LITE_DISABLE_X86_NEON
endif

ifeq ($(CPU),k8)
BAZEL_BUILD_FLAGS += --copt=-includeglibc_compat.h
else ifeq ($(CPU),aarch64)
BAZEL_BUILD_FLAGS += --copt=-ffp-contract=off
else ifeq ($(CPU),armv7a)
BAZEL_BUILD_FLAGS += --copt=-ffp-contract=off
endif


DEMO_OUT_DIR := $(MAKEFILE_DIR)/out/$(CPU)/

.PHONY: all lstpu classify clean


examples:
bazel build $(BAZEL_BUILD_FLAGS) //classification:classify
bazel build $(BAZEL_BUILD_FLAGS) //lstpu:lstpu
mkdir -p $(DEMO_OUT_DIR)
cp -f $(BAZEL_OUT_DIR)/classification/classify \
$(DEMO_OUT_DIR)
cp -f $(BAZEL_OUT_DIR)/lstpu/lstpu \
$(DEMO_OUT_DIR)
rm -rf $(MAKEFILE_DIR)/bazel-*

clean:
rm -rf $(MAKEFILE_DIR)/out

DOCKER_WORKSPACE=$(MAKEFILE_DIR)
DOCKER_CPUS=k8 armv7a aarch64 armv6
DOCKER_TAG_BASE=tflite-coral-examples
include $(MAKEFILE_DIR)/docker/docker.mk
14 changes: 14 additions & 0 deletions cpp/examples/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Simple C++ code example

These examples show how to build a simple C++ program that uses the EdgeTPU
runtime library. This subdirectory contains 2 different examples:

- lstpu:
- lists available Edge TPU devices (It does not perform inference).
- classification:
- classify a bmp image using a classification model.

## Compile the examples
```bash
$ make DOCKER_TARGET=examples DOCKER_CPUS=k8 docker-build
```
49 changes: 49 additions & 0 deletions cpp/examples/WORKSPACE
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Copyright 2020 Google LLC
#
# 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
#
# https://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.
workspace(name = "tflite_examples")

load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")

TENSORFLOW_COMMIT = "48c3bae94a8b324525b45f157d638dfd4e8c3be1"
TENSORFLOW_SHA256 = "363420a67b4cfa271cd21e5c8fac0d7d91b18b02180671c3f943c887122499d8"

# These values come from the Tensorflow workspace. If the TF commit is updated,
# these should be updated to match.
IO_BAZEL_RULES_CLOSURE_COMMIT = "308b05b2419edb5c8ee0471b67a40403df940149"
IO_BAZEL_RULES_CLOSURE_SHA256 = "5b00383d08dd71f28503736db0500b6fb4dda47489ff5fc6bed42557c07c6ba9"

CORAL_CROSSTOOL_COMMIT = "142e930ac6bf1295ff3ba7ba2b5b6324dfb42839"
CORAL_CROSSTOOL_SHA256 = "088ef98b19a45d7224be13636487e3af57b1564880b67df7be8b3b7eee4a1bfc"

# Configure libedgetpu and downstream libraries (TF and Crosstool).
http_archive(
name = "libedgetpu",
sha256 = "d76d18c5a96758dd620057028cdd4e129bd885480087a5c7334070bba3797e58",
strip_prefix = "libedgetpu-14eee1a076aa1af7ec1ae3c752be79ae2604a708",
urls = [
"https://github.com/google-coral/libedgetpu/archive/14eee1a076aa1af7ec1ae3c752be79ae2604a708.tar.gz"
],
)

load("@libedgetpu//:workspace.bzl", "libedgetpu_dependencies")
libedgetpu_dependencies(TENSORFLOW_COMMIT, TENSORFLOW_SHA256,
IO_BAZEL_RULES_CLOSURE_COMMIT,IO_BAZEL_RULES_CLOSURE_SHA256,
CORAL_CROSSTOOL_COMMIT,CORAL_CROSSTOOL_SHA256)


load("@org_tensorflow//tensorflow:workspace.bzl", "tf_workspace")
tf_workspace(tf_repo_name = "org_tensorflow")

load("@coral_crosstool//:configure.bzl", "cc_crosstool")
cc_crosstool(name = "crosstool", additional_system_include_directories=["//docker/include"])
23 changes: 23 additions & 0 deletions cpp/examples/classification/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Copyright 2019 Google LLC
#
# 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
#
# https://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.
cc_binary(
name = "classify",
srcs = ["classify.cc"],
deps = [
"@libedgetpu//tflite/public:oss_edgetpu_direct_all",
"@org_tensorflow//tensorflow/lite:builtin_op_data",
"@org_tensorflow//tensorflow/lite:framework",
"@org_tensorflow//tensorflow/lite/kernels:builtin_ops",
],
)
46 changes: 0 additions & 46 deletions cpp/examples/classification/Makefile

This file was deleted.

28 changes: 10 additions & 18 deletions cpp/examples/classification/classify.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@
#include <utility>
#include <vector>

#include "edgetpu_c.h"
#include "tensorflow/lite/builtin_op_data.h"
#include "tensorflow/lite/interpreter.h"
#include "tensorflow/lite/kernels/register.h"
#include "tensorflow/lite/model.h"
#include "tflite/public/edgetpu.h"

namespace {
constexpr size_t kBmpFileHeaderSize = 14;
Expand Down Expand Up @@ -130,17 +131,6 @@ int main(int argc, char* argv[]) {
const std::string image_file = argv[3];
const float threshold = std::stof(argv[4]);

// Find TPU device.
size_t num_devices;
std::unique_ptr<edgetpu_device, decltype(&edgetpu_free_devices)> devices(
edgetpu_list_devices(&num_devices), &edgetpu_free_devices);

if (num_devices == 0) {
std::cerr << "No connected TPU found" << std::endl;
return 1;
}
const auto& device = devices.get()[0];

// Load labels.
auto labels = ReadLabels(label_file);
if (labels.empty()) {
Expand All @@ -164,17 +154,19 @@ int main(int argc, char* argv[]) {
return 1;
}

// Create interpreter.
// Get edgetpu context.
auto edgetpu_context = edgetpu::EdgeTpuManager::GetSingleton()->OpenDevice();
tflite::ops::builtin::BuiltinOpResolver resolver;
resolver.AddCustom(edgetpu::kCustomOp, edgetpu::RegisterCustomOp());

// Create interpreter.
std::unique_ptr<tflite::Interpreter> interpreter;
if (tflite::InterpreterBuilder(*model, resolver)(&interpreter) != kTfLiteOk) {
std::cerr << "Cannot create interpreter" << std::endl;
return 1;
exit(EXIT_FAILURE);
}

auto* delegate =
edgetpu_create_delegate(device.type, device.path, nullptr, 0);
interpreter->ModifyGraphWithDelegate({delegate, edgetpu_free_delegate});
interpreter->SetExternalContext(kTfLiteEdgeTpuContext, edgetpu_context.get());
interpreter->SetNumThreads(1);

// Allocate tensors.
if (interpreter->AllocateTensors() != kTfLiteOk) {
Expand Down
66 changes: 66 additions & 0 deletions cpp/examples/docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Copyright 2021 Google LLC
#
# 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.

ARG IMAGE
FROM ${IMAGE}

COPY update_sources.sh /
RUN /update_sources.sh

RUN dpkg --add-architecture armhf
RUN dpkg --add-architecture arm64
RUN apt-get update && apt-get install -y \
sudo \
debhelper \
build-essential \
crossbuild-essential-armhf \
crossbuild-essential-arm64 \
libusb-1.0-0-dev \
libusb-1.0-0-dev:arm64 \
libusb-1.0-0-dev:armhf \
libglib2.0-dev \
libglib2.0-dev:armhf \
libglib2.0-dev:arm64 \
libgstreamer1.0-dev \
libgstreamer1.0-dev:armhf \
libgstreamer1.0-dev:arm64 \
libgstreamer-plugins-base1.0-dev \
libgstreamer-plugins-base1.0-dev:armhf \
libgstreamer-plugins-base1.0-dev:arm64 \
libgtk-3-dev \
libgtk-3-dev:arm64 \
libgtk-3-dev:armhf \
python \
python3-all \
python3-six \
zlib1g-dev \
zlib1g-dev:armhf \
zlib1g-dev:arm64 \
pkg-config \
zip \
unzip \
curl \
wget \
git \
subversion \
vim \
python3-numpy

ARG BAZEL_VERSION=2.1.0
RUN wget -O /bazel https://github.com/bazelbuild/bazel/releases/download/${BAZEL_VERSION}/bazel-${BAZEL_VERSION}-installer-linux-x86_64.sh && \
bash /bazel && \
rm -f /bazel

RUN svn export https://github.com/google-coral/edgetpu/trunk/libedgetpu /libedgetpu

39 changes: 39 additions & 0 deletions cpp/examples/docker/docker.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
DOCKER_MK_DIR := $(realpath $(dir $(lastword $(MAKEFILE_LIST))))

# Docker
DOCKER_CPUS ?= k8 armv7a armv6 aarch64
DOCKER_TARGETS ?=
DOCKER_IMAGE ?= debian:buster
DOCKER_TAG_BASE ?= "bazel-cross"
DOCKER_TAG := "$(DOCKER_TAG_BASE)-$(subst :,-,$(DOCKER_IMAGE))"
DOCKER_SHELL_COMMAND ?=

ifndef DOCKER_WORKSPACE
$(error DOCKER_WORKSPACE is not defined)
endif

WORKSPACE := /workspace
MAKE_COMMAND := \
for cpu in $(DOCKER_CPUS); do \
make CPU=\$${cpu} COMPILATION_MODE=$(COMPILATION_MODE) -C /workspace $(DOCKER_TARGETS) || exit 1; \
done

define run_command
chmod a+w /; \
groupadd --gid $(shell id -g) $(shell id -g -n); \
useradd -m -e '' -s /bin/bash --gid $(shell id -g) --uid $(shell id -u) $(shell id -u -n); \
echo '$(shell id -u -n) ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers; \
su $(shell id -u -n) $(if $(1),-c '$(1)',)
endef

docker-image:
docker build $(DOCKER_IMAGE_OPTIONS) -t $(DOCKER_TAG) \
--build-arg IMAGE=$(DOCKER_IMAGE) $(DOCKER_MK_DIR)

docker-shell: docker-image
docker run --rm -i --tty -v $(DOCKER_WORKSPACE):$(WORKSPACE) --workdir $(WORKSPACE) \
$(DOCKER_TAG) /bin/bash -c "$(call run_command,$(DOCKER_SHELL_COMMAND))"

docker-build: docker-image
docker run --rm -i $(shell tty -s && echo --tty) -v $(DOCKER_WORKSPACE):$(WORKSPACE) \
$(DOCKER_TAG) /bin/bash -c "$(call run_command,$(MAKE_COMMAND))"
Empty file.
Loading

0 comments on commit b01fbfc

Please sign in to comment.