Build pip_package with Bazel

Added new script build_pip_package_with_bazel.sh.
This scirpt can be used with ci_build.sh of TF for cross building.

ex) Build armhf Python3 based PIP
$ CI_DOCKER_EXTRA_PARAMS="-e CI_BUILD_PYTHON=python3 -e CROSSTOOL_PYTHON_INCLUDE_PATH=/usr/include/python3.5" \
  tensorflow/tools/ci_build/ci_build.sh PI-PYTHON3 \
  tensorflow/lite/tools/pip_package/build_pip_package_with_bazel.sh armhf

PiperOrigin-RevId: 312420603
Change-Id: I5504fb22248e6a9d29560fa9216113a8705b7399
This commit is contained in:
Terry Heo 2020-05-19 22:15:54 -07:00 committed by TensorFlower Gardener
parent cd0322fa0e
commit ff99778343
7 changed files with 275 additions and 8 deletions

View File

@ -49,6 +49,52 @@ BUILD_DEB=y to the make command (only for python3):
make BASE_IMAGE=debian:buster PYTHON=python3 TENSORFLOW_TARGET=rpi BUILD_DEB=y docker-build
```
## Alternative build with Bazel (experimental)
There is another build steps to build a binary wheel which uses Bazel instead of
Makefile. You don't need to install additional dependencies.
This approach can leverage TF's ci_build.sh for ARM cross builds.
### Native build for your workstation
```sh
tensorflow/lite/tools/pip_package/build_pip_package_with_bazel.sh
```
### Cross build for armhf Python 3.5
```sh
CI_DOCKER_EXTRA_PARAMS="-e CI_BUILD_PYTHON=python3 -e CROSSTOOL_PYTHON_INCLUDE_PATH=/usr/include/python3.5" \
tensorflow/tools/ci_build/ci_build.sh PI-PYTHON3 \
tensorflow/lite/tools/pip_package/build_pip_package_with_bazel.sh armhf
```
### Cross build for armhf Python 3.7
```sh
CI_DOCKER_EXTRA_PARAMS="-e CI_BUILD_PYTHON=python3 -e CROSSTOOL_PYTHON_INCLUDE_PATH=/usr/include/python3.7" \
tensorflow/tools/ci_build/ci_build.sh PI-PYTHON37 \
tensorflow/lite/tools/pip_package/build_pip_package_with_bazel.sh armhf
```
### Cross build for aarch64 Python 3.5
```sh
CI_DOCKER_EXTRA_PARAMS="-e CI_BUILD_PYTHON=python3 -e CROSSTOOL_PYTHON_INCLUDE_PATH=/usr/include/python3.5" \
tensorflow/tools/ci_build/ci_build.sh PI-PYTHON3 \
tensorflow/lite/tools/pip_package/build_pip_package_with_bazel.sh aarch64
```
### Cross build for aarch64 Python 3.7
```sh
CI_DOCKER_EXTRA_PARAMS="-e CI_BUILD_PYTHON=python3 -e CROSSTOOL_PYTHON_INCLUDE_PATH=/usr/include/python3.7" \
tensorflow/tools/ci_build/ci_build.sh PI-PYTHON37 \
tensorflow/lite/tools/pip_package/build_pip_package_with_bazel.sh aarch64
```
## Usage
Note, unlike tensorflow this will be installed to a tflite_runtime namespace.
You can then use the Tensorflow Lite interpreter as.

View File

@ -0,0 +1,126 @@
#!/usr/bin/env bash
# Copyright 2020 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.
# ==============================================================================
set -ex
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PYTHON="${PYTHON:-python3}"
VERSION_SUFFIX=${VERSION_SUFFIX:-}
export TENSORFLOW_DIR="${SCRIPT_DIR}/../../../.."
TENSORFLOW_LITE_DIR="${TENSORFLOW_DIR}/tensorflow/lite"
TENSORFLOW_VERSION=$(grep "_VERSION = " "${TENSORFLOW_DIR}/tensorflow/tools/pip_package/setup.py" | cut -d= -f2 | sed "s/[ '-]//g")
export PACKAGE_VERSION="${TENSORFLOW_VERSION}${VERSION_SUFFIX}"
BUILD_DIR="${SCRIPT_DIR}/gen/tflite_pip/${PYTHON}"
TENSORFLOW_TARGET=$1
# Build source tree.
rm -rf "${BUILD_DIR}" && mkdir -p "${BUILD_DIR}/tflite_runtime"
cp -r "${TENSORFLOW_LITE_DIR}/tools/pip_package/debian" \
"${TENSORFLOW_LITE_DIR}/tools/pip_package/setup_with_bazel.py" \
"${TENSORFLOW_LITE_DIR}/tools/pip_package/MANIFEST.in" \
"${TENSORFLOW_LITE_DIR}/python/interpreter_wrapper" \
"${BUILD_DIR}"
cp "${TENSORFLOW_LITE_DIR}/python/interpreter.py" \
"${BUILD_DIR}/tflite_runtime"
echo "__version__ = '${PACKAGE_VERSION}'" >> "${BUILD_DIR}/tflite_runtime/__init__.py"
echo "__git_version__ = '$(git -C "${TENSORFLOW_DIR}" describe)'" >> "${BUILD_DIR}/tflite_runtime/__init__.py"
# Build python interpreter_wrapper.
cd "${BUILD_DIR}"
case "${TENSORFLOW_TARGET}" in
rpi|armhf)
BAZEL_FLAGS="--config=elinux_armhf
--copt=-march=armv7-a --copt=-mfpu=neon-vfpv4
--copt=-O3 --copt=-fno-tree-pre --copt=-fpermissive
--define=raspberry_pi_with_neon=true"
;;
aarch64)
BAZEL_FLAGS="--config=elinux_aarch64
--copt=-O3"
;;
*)
;;
esac
# We need to pass down the environment variable with a possible alternate Python
# include path for Python 3.x builds to work.
export CROSSTOOL_PYTHON_INCLUDE_PATH
bazel build -c opt -s --config=monolithic ${BAZEL_FLAGS} //tensorflow/lite/python/interpreter_wrapper:_pywrap_tensorflow_interpreter_wrapper
cp "${TENSORFLOW_DIR}/bazel-bin/tensorflow/lite/python/interpreter_wrapper/_pywrap_tensorflow_interpreter_wrapper.so" \
"${BUILD_DIR}/tflite_runtime"
# Build python wheel.
cd "${BUILD_DIR}"
case "${TENSORFLOW_TARGET}" in
rpi|armhf)
${PYTHON} setup_with_bazel.py bdist --plat-name=linux-armv7l \
bdist_wheel --plat-name=linux-armv7l
;;
aarch64)
${PYTHON} setup_with_bazel.py bdist --plat-name=linux-aarch64 \
bdist_wheel --plat-name=linux-aarch64
;;
*)
if [[ -n "${TENSORFLOW_TARGET}" ]] && [[ -n "${TENSORFLOW_TARGET_ARCH}" ]]; then
${PYTHON} setup_with_bazel.py bdist --plat-name=${TENSORFLOW_TARGET}-${TENSORFLOW_TARGET_ARCH} \
bdist_wheel --plat-name=${TENSORFLOW_TARGET}-${TENSORFLOW_TARGET_ARCH}
else
${PYTHON} setup_with_bazel.py bdist bdist_wheel
fi
;;
esac
echo "Output can be found here:"
find "${BUILD_DIR}"
# Build debian package.
if [[ "${BUILD_DEB}" != "y" ]]; then
exit 0
fi
PYTHON_VERSION=$(${PYTHON} -c "import sys;print(sys.version_info.major)")
if [[ ${PYTHON_VERSION} != 3 ]]; then
echo "Debian package can only be generated for python3." >&2
exit 1
fi
DEB_VERSION=$(dpkg-parsechangelog --show-field Version | cut -d- -f1)
if [[ "${DEB_VERSION}" != "${PACKAGE_VERSION}" ]]; then
cat << EOF > "${BUILD_DIR}/debian/changelog"
tflite-runtime (${PACKAGE_VERSION}-1) unstable; urgency=low
* Bump version to ${PACKAGE_VERSION}.
-- TensorFlow team <packages@tensorflow.org> $(date -R)
$(<"${BUILD_DIR}/debian/changelog")
EOF
fi
case "${TENSORFLOW_TARGET}" in
rpi|armhf)
dpkg-buildpackage -b -rfakeroot -us -uc -tc -d -a armhf
;;
aarch64)
dpkg-buildpackage -b -rfakeroot -us -uc -tc -d -a arm64
;;
*)
dpkg-buildpackage -b -rfakeroot -us -uc -tc -d
;;
esac
cat "${BUILD_DIR}/debian/changelog"

View File

@ -0,0 +1,70 @@
# Copyright 2020 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.
# ==============================================================================
"""TensorFlow Lite is for mobile and embedded devices.
TensorFlow Lite is the official solution for running machine learning models on
mobile and embedded devices. It enables on-device machine learning inference
with low latency and a small binary size on Android, iOS, and other operating
systems.
"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import os
from setuptools import find_packages
from setuptools import setup
PACKAGE_NAME = 'tflite_runtime'
PACKAGE_VERSION = os.environ['PACKAGE_VERSION']
DOCLINES = __doc__.split('\n')
setup(
name=PACKAGE_NAME.replace('_', '-'),
version=PACKAGE_VERSION,
description=DOCLINES[0],
long_description='\n'.join(DOCLINES[2:]),
url='https://www.tensorflow.org/lite/',
author='Google, LLC',
author_email='packages@tensorflow.org',
license='Apache 2.0',
include_package_data=True,
keywords='tflite tensorflow tensor machine learning',
classifiers=[
'Development Status :: 5 - Production/Stable',
'Intended Audience :: Developers',
'Intended Audience :: Education',
'Intended Audience :: Science/Research',
'License :: OSI Approved :: Apache Software License',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Topic :: Scientific/Engineering',
'Topic :: Scientific/Engineering :: Mathematics',
'Topic :: Scientific/Engineering :: Artificial Intelligence',
'Topic :: Software Development',
'Topic :: Software Development :: Libraries',
'Topic :: Software Development :: Libraries :: Python Modules',
],
packages=find_packages(exclude=[]),
package_dir={'': '.'},
package_data={'': ['*.so']},
install_requires=[
'numpy >= 1.16.0',
'pybind11 >= 2.4.3',
])

View File

@ -15,12 +15,14 @@
# ==============================================================================
dpkg --add-architecture armhf
echo 'deb [arch=armhf] http://ports.ubuntu.com/ xenial main restricted universe multiverse' >> /etc/apt/sources.list.d/armhf.list
echo 'deb [arch=armhf] http://ports.ubuntu.com/ xenial-updates main restricted universe multiverse' >> /etc/apt/sources.list.d/armhf.list
echo 'deb [arch=armhf] http://ports.ubuntu.com/ xenial-security main restricted universe multiverse' >> /etc/apt/sources.list.d/armhf.list
echo 'deb [arch=armhf] http://ports.ubuntu.com/ xenial-backports main restricted universe multiverse' >> /etc/apt/sources.list.d/armhf.list
dpkg --add-architecture arm64
echo 'deb [arch=arm64,armhf] http://ports.ubuntu.com/ xenial main restricted universe multiverse' >> /etc/apt/sources.list.d/armhf.list
echo 'deb [arch=arm64,armhf] http://ports.ubuntu.com/ xenial-updates main restricted universe multiverse' >> /etc/apt/sources.list.d/armhf.list
echo 'deb [arch=arm64,armhf] http://ports.ubuntu.com/ xenial-security main restricted universe multiverse' >> /etc/apt/sources.list.d/armhf.list
echo 'deb [arch=arm64,armhf] http://ports.ubuntu.com/ xenial-backports main restricted universe multiverse' >> /etc/apt/sources.list.d/armhf.list
sed -i 's#deb http://archive.ubuntu.com/ubuntu/#deb [arch=amd64] http://archive.ubuntu.com/ubuntu/#g' /etc/apt/sources.list
yes | add-apt-repository ppa:deadsnakes/ppa
apt-get update
apt-get install -y python3.7 python3-numpy python3.7-dev python3-pip
apt-get install -y libpython3.7-dev:armhf
apt-get install -y libpython3.7-dev:arm64

View File

@ -15,11 +15,13 @@
# ==============================================================================
dpkg --add-architecture armhf
echo 'deb [arch=armhf] http://ports.ubuntu.com/ xenial main restricted universe multiverse' >> /etc/apt/sources.list.d/armhf.list
echo 'deb [arch=armhf] http://ports.ubuntu.com/ xenial-updates main restricted universe multiverse' >> /etc/apt/sources.list.d/armhf.list
echo 'deb [arch=armhf] http://ports.ubuntu.com/ xenial-security main restricted universe multiverse' >> /etc/apt/sources.list.d/armhf.list
echo 'deb [arch=armhf] http://ports.ubuntu.com/ xenial-backports main restricted universe multiverse' >> /etc/apt/sources.list.d/armhf.list
dpkg --add-architecture arm64
echo 'deb [arch=arm64,armhf] http://ports.ubuntu.com/ xenial main restricted universe multiverse' >> /etc/apt/sources.list.d/armhf.list
echo 'deb [arch=arm64,armhf] http://ports.ubuntu.com/ xenial-updates main restricted universe multiverse' >> /etc/apt/sources.list.d/armhf.list
echo 'deb [arch=arm64,armhf] http://ports.ubuntu.com/ xenial-security main restricted universe multiverse' >> /etc/apt/sources.list.d/armhf.list
echo 'deb [arch=arm64,armhf] http://ports.ubuntu.com/ xenial-backports main restricted universe multiverse' >> /etc/apt/sources.list.d/armhf.list
sed -i 's#deb http://archive.ubuntu.com/ubuntu/#deb [arch=amd64] http://archive.ubuntu.com/ubuntu/#g' /etc/apt/sources.list
apt-get update
apt-get install -y libpython3-all-dev:armhf
apt-get install -y libpython3-all-dev:arm64
apt-get install -y python3 python3-numpy python3-dev python3-pip

View File

@ -10,6 +10,16 @@ def _tpl(repository_ctx, tpl, substitutions = {}, out = None):
)
def _arm_linux_toolchain_configure_impl(repository_ctx):
# We need to find a cross-compilation include directory for Python, so look
# for an environment variable. Be warned, this crosstool template is only
# regenerated on the first run of Bazel, so if you change the variable after
# it may not be reflected in later builds. Doing a shutdown and clean of Bazel
# doesn't fix this, you'll need to delete the generated file at something like:
# external/local_config_arm_compiler/CROSSTOOL in your Bazel install.
if "CROSSTOOL_PYTHON_INCLUDE_PATH" in repository_ctx.os.environ:
python_include_path = repository_ctx.os.environ["CROSSTOOL_PYTHON_INCLUDE_PATH"]
else:
python_include_path = "/usr/include/python3.5"
_tpl(repository_ctx, "cc_config.bzl", {
"%{AARCH64_COMPILER_PATH}%": str(repository_ctx.path(
repository_ctx.attr.aarch64_repo,
@ -17,6 +27,7 @@ def _arm_linux_toolchain_configure_impl(repository_ctx):
"%{ARMHF_COMPILER_PATH}%": str(repository_ctx.path(
repository_ctx.attr.armhf_repo,
)),
"%{PYTHON_INCLUDE_PATH}%": python_include_path,
})
repository_ctx.symlink(repository_ctx.attr.build_file, "BUILD")

View File

@ -252,6 +252,10 @@ def _impl(ctx):
"%{AARCH64_COMPILER_PATH}%/aarch64-linux-gnu/include/c++/8.3.0/",
"-isystem",
"%{AARCH64_COMPILER_PATH}%/aarch64-linux-gnu/libc/usr/include/",
"-isystem",
"%{PYTHON_INCLUDE_PATH}%",
"-isystem",
"/usr/include/",
],
),
],
@ -347,6 +351,10 @@ def _impl(ctx):
"%{ARMHF_COMPILER_PATH}%/arm-linux-gnueabihf/include/c++/8.3.0/",
"-isystem",
"%{ARMHF_COMPILER_PATH}%/arm-linux-gnueabihf/libc/usr/include/",
"-isystem",
"%{PYTHON_INCLUDE_PATH}%",
"-isystem",
"/usr/include/",
],
),
],
@ -466,6 +474,7 @@ def _impl(ctx):
"%{AARCH64_COMPILER_PATH}%/lib/gcc/aarch64-linux-gnu/8.3.0/include-fixed",
"%{AARCH64_COMPILER_PATH}%/aarch64-linux-gnu/include/c++/8.3.0/",
"%{AARCH64_COMPILER_PATH}%/aarch64-linux-gnu/libc/usr/include/",
"/usr/include",
]
elif (ctx.attr.cpu == "armhf"):
cxx_builtin_include_directories = [
@ -473,6 +482,7 @@ def _impl(ctx):
"%{ARMHF_COMPILER_PATH}%/lib/gcc/arm-linux-gnueabihf/8.3.0/include-fixed",
"%{ARMHF_COMPILER_PATH}%/arm-linux-gnueabihf/include/c++/8.3.0/",
"%{ARMHF_COMPILER_PATH}%/arm-linux-gnueabihf/libc/usr/include/",
"/usr/include",
]
else:
fail("Unreachable")