레이블이 aarch64인 게시물을 표시합니다. 모든 게시물 표시
레이블이 aarch64인 게시물을 표시합니다. 모든 게시물 표시

2022년 3월 6일 일요일

Build Tensorflow 2.7 python wheel for Jetpack 4.6 (Xavier NX)

 In the previous few articles, I learned how to build Tensorflow directly on Raspberry Pi and cross-build Tensorflow Lite on the host computer.


In this article, I will finally look at how to build Tensorflow in the Jetson series.

The Jetson development environment used in this article is as follows.

  • JetPack : 4.6 (TensorRT : 8.0.1, CUDA 10.2, cuDNN:8.2.1)
  • Python : 3.8 (Ananconda Virtual Environment)
  • Numpy : 1.21.5
  • gcc : 7.5.0 (CUDA does not compile in 8 or higher)
  • bazel : 4.2.1
  • Jetson : Jetson Xavier NX


To be honest, I've had several failures to make this build a success. The biggest reason is the memory problem. Because it takes a long time to build, it is not easy to monitor the system environments like cpu, memory, processes when an error occurs. As a result of monitoring several times using htop, it was found that insufficient memory was the cause of various errors.

Xavier NX has 8GB of memory, but not enough to build TensorFlow.

Therefore, virtual memory should be secured using swap file and zram and memory usage should be reduced by adjusting bazel build parameters.


Prerequisite


Creating a Python 3.8 Anaconda Virtual Environment


As you can see from the table below, TensorFlow 2.7 or higher requires Python 3.7 or higher. Therefore, prepare Python 3.8 as an anaconda (miniconda) virtual environment.
For information on installing Anaconda on Jetson Xavier NX and preparing the virtual environment, refer to the following article.


<TensorFlow build environment>


The work from now on is the work in the Anaconda Python 3.8 virtual environment.



spypiggy@spypiggy-desktop:~/src$ conda create --name py_38 python=3.8
spypiggy@spypiggy-desktop:~/src$ conda activate py_38
(py_38) spypiggy@spypiggy-desktop:~/src$ 


nvpmodel

Power models of Xavier NX range from 0 to 8. For more information on the power model of Xavier NX, refer to the following article.


Building TensorFlow takes a lot of time. In the case of Xavier NX, it takes about 10 hours, and in the case of Nano, it takes more than 24 hours. Therefore, it is advantageous to use the CPU as much as possible. If nvpmodel is set to 8, the system's performance can be maximized because 6 CPUs are used with 20W power. 
However, even though job=4 parameter was set during the Basel build process, at some point, all CPUs(6 Cores) were operating at 100%, and memory usage was also outside the specified range. So, in my case, I set nvpmode to 7 and set four high-performance CPUs to use 20W power. I rarely use Basel, so I lack a deep understanding of Basel. It might be possible in nvpmodel 8 as well if you fine tune your basel build settings. But I would safely use nvpmodel 7.


spypiggy@spypiggy-desktop:~/src$ sudo nvpmodel -m 7
NVPM WARN: patching tpc_pg_mask: (0x1:0x4)
NVPM WARN: patched tpc_pg_mask: 0x4
spypiggy@spypiggy-desktop:~/src$ sudo nvpmodel -q
NV Fan Mode:quiet
NV Power Mode: MODE_20W_4CORE
7


tmux 

tmux is an open-source terminal multiplexer for Unix-like operating systems. It allows multiple terminal sessions to be accessed simultaneously in a single window. It is useful for running more than one command-line program at the same time. It can also be used to detach processes from their controlling terminals, allowing remote sessions to remain active without being visible
<From Wikipedia>

tmux installation is not always required. However, since you have to work on the remote ssh console for more than 10 hours, it is convenient to stop the console in the middle or check the progress of the work by reconnecting after a long time after shutting down the host. If you build directly from the ssh console, the entire build process may be stopped if the console is terminated or a network failure occurs. 10 hours of work can be in vain. To prevent this unfortunate situation., tmux allows you to maintain a session even when ssh is terminated.


Install required packages to build tensorflow 

Packages that can be installed with conda always take precedence over pip to be installed with conda.


(py_38) spypiggy@spypiggy-desktop:~/src$ conda install Pillow matplotlib pandas mock scipy portpicker \
    scikit-learn pybind11 h5py==3.1.0 six wheel enum34

Also, packages that cannot be installed with conda can be installed with pip. You do not need to use the pip3 command in a virtual environment.


(py_38) spypiggy@spypiggy-desktop:~/src$ pip install keras_applications==1.0.8 --no-deps 
(py_38) spypiggy@spypiggy-desktop:~/src$ pip install keras_preprocessing==1.1.2 --no-deps 
(py_38) spypiggy@spypiggy-desktop:~/src$ pip install gdown


And the package using apt-get is also installed.

(py_38) spypiggy@spypiggy-desktop:~/src$  sudo apt-get update
(py_38) spypiggy@spypiggy-desktop:~/src$  sudo apt-get install -y  \
        build-essential gfortran  curl git  libcurl3-dev  libfreetype6-dev \
        libhdf5-serial-dev libhdf5-dev libc-ares-dev libeigen3-dev \
        libatlas-base-dev libopenblas-dev libblas-dev \
        liblapack-dev libzmq3-dev  pkg-config  rsync  software-properties-common \
        swig  unzip  python3-h5py zip  zlib1g-dev


Install bazel 

TensorFlow builds use the Basel build system. So we install the Basel build system. Just install open jdk 11 to be used in Basel 4.2.1.


(py_38) spypiggy@spypiggy-desktop:~/src$  sudo apt-get install -y  openjdk-11-jdk \
        openjdk-11-jre-headless 


Then, download the basel source code and build it.

(py_38) spypiggy@spypiggy-desktop:~/src$ mkdir bazel
(py_38) spypiggy@spypiggy-desktop:~/src$ cd bazel
(py_38) spypiggy@spypiggy-desktop:~/src/bazel$ curl -fSsL -O https://github.com/bazelbuild/bazel/releases/download/4.2.1/bazel-4.2.1-dist.zip
(py_38) spypiggy@spypiggy-desktop:~/src/bazel$ unzip bazel-4.2.1-dist.zip
(py_38) spypiggy@spypiggy-desktop:~/src/bazel$ bash ./compile.sh
(py_38) spypiggy@spypiggy-desktop:~/src/bazel$ sudo cp output/bazel /usr/local/bin/


If the Basel build ended without any issues, you can check it as follows.


(py_38) spypiggy@spypiggy-desktop:~/src$ bazel --version
bazel 4.2.1- (@non-git)


Increase memory using ZRAM

The 8GB memory of Xavier NX is 2 or 4 times that of Nano, but if you start the build without any preparation, the probability of an error is very high. Free up as much memory as possible with the following operations. And when the work is finished, adjust the swap memory capacity again.


install zram tool

Since there is already a well-made installation script file, download it from git.

$ git clone https://github.com/StuartIanNaylor/zram-swap-config \
&& cd zram-swap-config
$ sudo ./install.sh


The following is an example of setting in Xavier NX. Zram is applied to 40% of the memory.

(py_38) spypiggy@spypiggy-desktop:~/src$ cat /etc/zram-swap-config.conf
MEM_FACTOR=40
DRIVE_FACTOR=300
COMP_ALG=lz4
SWAP_DEVICES=1
SWAP_PRI=75
PAGE_CLUSTER=0
SWAPPINESS=90


install swap tool

When you build a large software packages like openCV, you may experience an out of memory phenomenon. Increasing the swap file size can prevent this malfunction.



git clone https://github.com/JetsonHacksNano/installSwapfile
cd installSwapfile
./installSwapfile.sh


Above script file will increase 6GB swap files. You can change the swap file size by modifying the scripts. If you want to uninstall the swap setting, open the fstab file and delete the swap file line and reboot.

My Xavier NX's memory looks like this after all.

(py_38) spypiggy@spypiggy-desktop:~/src$ sudo cat /proc/swaps
Filename                                Type            Size    Used    Priority
/mnt/swapfile                           file            6291452 412     -1
/dev/zram0                              partition       9551992 485960  75
(py_38) spypiggy@spypiggy-desktop:~/src$ free -m
              total        used        free      shared  buff/cache   available
Mem:           7773         923        3188           2        3660        6632
Swap:         15472         474       14997

7.7 GB of memory and 15 GB of swap memory(zram + swap file) were prepared.


Building the tensorflow python wheel

Now, download the TensorFlow source code and start building.

First, download the source code and do configure.


cd src
git clone -b v2.7.0 https://github.com/tensorflow/tensorflow.git
cd tensorflow
./configure

The config operation is important because it prepares the bazel build environment.





Python environment shows the virtual environment value of anaconda (miniconda). Just press Enter to use it. "compute capability" corresponds to the NVidia GPU model number. These values are detailed at https://en.wikipedia.org/wiki/CUDA.

And numa is not supported by ARM64 CPU, so remove that option from .bashrc file

<modify the .bashrc file>

config=v1 option will be replaced by v2 later build step.


And add the link environment.


sudo sh -c "echo '/usr/local/cuda/lib64' >> /etc/ld.so.conf.d/nvidia-tegra.conf"
sudo ldconfig


Now, before starting work, create a session using tmux and work. This process can be omitted when working directly in Xavier NX. However, if you are working with remote ssh and you omit it, the ssh program should not exit until the build is complete. The tmux command resets the Python virtual environment. So, start the virtual environment again.


(py_38) spypiggy@spypiggy-desktop:~/src/tensorflow$ tmux new tf
(base) spypiggy@spypiggy-desktop:~/src/tensorflow$ conda activate py_38
(py_38) spypiggy@spypiggy-desktop:~/src/tensorflow$ t


The appearance of the ssh remote console will change slightly. If you see a green area at the bottom of the screen, this is normal.

Finally, it's build time.


(py_38) spypiggy@spypiggy-desktop:~/src/tensorflow$ sudo bazel  \
  --host_jvm_args=-Xmx7g  \
  build \
  --discard_analysis_cache --notrack_incremental_state --nokeep_state_after_build \
  --config=monolithic \
  --config=noaws \
  --config=nohdfs \
  --config=nonccl \
  --config=v2 \
  --define=tflite_pip_with_flex=true \
  --define=tflite_with_xnnpack=true \
  --jobs=4 \
  --local_ram_resources=HOST_RAM*.5 \
  //tensorflow/tools/pip_package:build_pip_package


This command takes about 10 hours on Xavier NX if successful. Therefore, if you are a tmux user, you can exit the session with "Ctrl + b , d" commands.  To completely delete the session, type exit in the tmux environment(You can do this after the build work is finished.).

And you can quit ssh.  It's a good time interval to watch the Netflix Squid Game series.

To reconnect later, do the following:


(py_38) spypiggy@spypiggy-desktop:~/src/tensorflow$ tmux ls
tf-0: 1 windows (created Sat Mar  5 21:23:25 2022) [84x41] (group tf)
(py_38) spypiggy@spypiggy-desktop:~/src/tensorflow$ tmux attach -t tf


Finally, after about 10 hours, the build work was finished.


INFO: Reading rc options for 'build' from /home/spypiggy/src/tensorflow/.bazelrc:
  'build' options: --define framework_shared_object=true --java_toolchain=@tf_toolchains//toolchains/java:tf_java_toolchain --host_java_toolchain=@tf_toolchains//toolchains/java:tf_java_toolchain --define=use_fast_cpp_protos=true --define=allow_oversize_protos=true --spawn_strategy=standalone -c opt --announce_rc --define=grpc_no_ares=true --noincompatible_remove_legacy_whole_archive --enable_platform_specific_config --define=with_xla_support=true --config=short_logs --config=v2 --define=no_aws_support=true --define=no_hdfs_support=true
INFO: Reading rc options for 'build' from /home/spypiggy/src/tensorflow/.tf_configure.bazelrc:
  'build' options: --action_env PYTHON_BIN_PATH=/home/spypiggy/miniconda3/envs/py_38/bin/python3 --action_env PYTHON_LIB_PATH=/home/spypiggy/miniconda3/envs/py_38/lib/python3.8/site-packages --python_path=/home/spypiggy/miniconda3/envs/py_38/bin/python3 --config=tensorrt --action_env CUDA_TOOLKIT_PATH=/usr/local/cuda-10.2 --action_env TF_CUDA_COMPUTE_CAPABILITIES=7.2 --action_env GCC_HOST_COMPILER_PATH=/usr/bin/aarch64-linux-gnu-gcc-7 --config=cuda
INFO: Reading rc options for 'build' from /home/spypiggy/src/tensorflow/.bazelrc:
  'build' options: --deleted_packages=tensorflow/compiler/mlir/tfrt,tensorflow/compiler/mlir/tfrt/benchmarks,tensorflow/compiler/mlir/tfrt/jit/python_binding,tensorflow/compiler/mlir/tfrt/jit/transforms,tensorflow/compiler/mlir/tfrt/python_tests,tensorflow/compiler/mlir/tfrt/tests,tensorflow/compiler/mlir/tfrt/tests/saved_model,tensorflow/compiler/mlir/tfrt/transforms/lhlo_gpu_to_tfrt_gpu,tensorflow/core/runtime_fallback,tensorflow/core/runtime_fallback/conversion,tensorflow/core/runtime_fallback/kernel,tensorflow/core/runtime_fallback/opdefs,tensorflow/core/runtime_fallback/runtime,tensorflow/core/runtime_fallback/util,tensorflow/core/tfrt/common,tensorflow/core/tfrt/eager,tensorflow/core/tfrt/eager/backends/cpu,tensorflow/core/tfrt/eager/backends/gpu,tensorflow/core/tfrt/eager/core_runtime,tensorflow/core/tfrt/eager/cpp_tests/core_runtime,tensorflow/core/tfrt/fallback,tensorflow/core/tfrt/gpu,tensorflow/core/tfrt/run_handler_thread_pool,tensorflow/core/tfrt/runtime,tensorflow/core/tfrt/saved_model,tensorflow/core/tfrt/saved_model/tests,tensorflow/core/tfrt/tpu,tensorflow/core/tfrt/utils
INFO: Found applicable config definition build:short_logs in file /home/spypiggy/src/tensorflow/.bazelrc: --output_filter=DONT_MATCH_ANYTHING
INFO: Found applicable config definition build:v2 in file /home/spypiggy/src/tensorflow/.bazelrc: --define=tf_api_version=2 --action_env=TF2_BEHAVIOR=1
INFO: Found applicable config definition build:tensorrt in file /home/spypiggy/src/tensorflow/.bazelrc: --repo_env TF_NEED_TENSORRT=1
INFO: Found applicable config definition build:cuda in file /home/spypiggy/src/tensorflow/.bazelrc: --repo_env TF_NEED_CUDA=1 --crosstool_top=@local_config_cuda//crosstool:toolchain --@local_config_cuda//:enable_cuda
INFO: Found applicable config definition build:monolithic in file /home/spypiggy/src/tensorflow/.bazelrc: --define framework_shared_object=false
INFO: Found applicable config definition build:noaws in file /home/spypiggy/src/tensorflow/.bazelrc: --define=no_aws_support=true
INFO: Found applicable config definition build:nohdfs in file /home/spypiggy/src/tensorflow/.bazelrc: --define=no_hdfs_support=true
INFO: Found applicable config definition build:nonccl in file /home/spypiggy/src/tensorflow/.bazelrc: --define=no_nccl_support=true
INFO: Found applicable config definition build:v2 in file /home/spypiggy/src/tensorflow/.bazelrc: --define=tf_api_version=2 --action_env=TF2_BEHAVIOR=1
INFO: Found applicable config definition build:linux in file /home/spypiggy/src/tensorflow/.bazelrc: --copt=-w --host_copt=-w --define=PREFIX=/usr --define=LIBDIR=$(PREFIX)/lib --define=INCLUDEDIR=$(PREFIX)/include --define=PROTOBUF_INCLUDE_PATH=$(PREFIX)/include --cxxopt=-std=c++14 --host_cxxopt=-std=c++14 --config=dynamic_kernels --distinct_host_configuration=false --experimental_guard_against_concurrent_changes
INFO: Found applicable config definition build:dynamic_kernels in file /home/spypiggy/src/tensorflow/.bazelrc: --define=dynamic_loaded_kernels=true --copt=-DAUTOLOAD_DYNAMIC_KERNELS
INFO: Analyzed target //tensorflow/tools/pip_package:build_pip_package (455 packages loaded, 29475 targets configured).
INFO: Found 1 target...
Target //tensorflow/tools/pip_package:build_pip_package up-to-date:
  bazel-bin/tensorflow/tools/pip_package/build_pip_package
INFO: Elapsed time: 32535.484s, Critical Path: 1596.45s
INFO: 6481 processes: 753 internal, 5728 local.
INFO: Build completed successfully, 6481 total actions


Now build the wheel like this:


(py_38) spypiggy@spypiggy-desktop:~/src/tensorflow$ ./tensorflow/tools/pip_package/build_pip_package.sh /tmp/tensorflow_pkg
2022. 03. 06. (일) 19:43:08 KST : === Preparing sources in dir: /tmp/tmp.cfIiYxCqoF
~/src/tensorflow ~/src/tensorflow
~/src/tensorflow
~/src/tensorflow/bazel-bin/tensorflow/tools/pip_package/build_pip_package.runfiles/org_tensorflow ~/src/tensorflow
~/src/tensorflow
/tmp/tmp.cfIiYxCqoF/tensorflow/include ~/src/tensorflow
~/src/tensorflow
2022. 03. 06. (일) 19:44:03 KST : === Building wheel
warning: no files found matching 'README'
warning: no files found matching '*.pyd' under directory '*'
warning: no files found matching '*.pyi' under directory '*'
warning: no files found matching '*.pd' under directory '*'
warning: no files found matching '*.so.[0-9]' under directory '*'
warning: no files found matching '*.dylib' under directory '*'
warning: no files found matching '*.dll' under directory '*'
warning: no files found matching '*.lib' under directory '*'
warning: no files found matching '*.csv' under directory '*'
warning: no files found matching '*.h' under directory 'tensorflow/include/tensorflow'
warning: no files found matching '*.proto' under directory 'tensorflow/include/tensorflow'
warning: no files found matching '*' under directory 'tensorflow/include/third_party'
2022. 03. 06. (일) 19:46:11 KST : === Output wheel file is in: /tmp/tensorflow_pkg

(py_38) spypiggy@spypiggy-desktop:~/src/tensorflow$ ls -al /tmp/tensorflow_pkg/
total 394860
drwxrwxr-x  2 spypiggy spypiggy      4096  3월  6 19:46 .
drwxrwxrwt 17 root     root         36864  3월  6 19:48 ..
-rw-rw-r--  1 spypiggy spypiggy 404288101  3월  6 19:46 tensorflow-2.7.0-cp38-cp38-linux_aarch64.whl


Finally, I succeeded in building TensorFlow 2.7. Let's check by installing Anaconda Python 3.8 in a virtual environment. Since we built for Python 3.8, it is of course correct to install it in a virtual environment where Python 3.8 is installed.

 


(py_38) spypiggy@spypiggy-desktop:/tmp/tensorflow_pkg$ pip install tensorflow-2.7.0-cp38-cp38-linux_aarch64.whl 
Processing ./tensorflow-2.7.0-cp38-cp38-linux_aarch64.whl
Collecting tensorflow-io-gcs-filesystem>=0.21.0
  Downloading tensorflow_io_gcs_filesystem-0.24.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (2.8 MB)
     |████████████████████████████████| 2.8 MB 45 kB/s 
Collecting termcolor>=1.1.0
  Downloading termcolor-1.1.0.tar.gz (3.9 kB)
Collecting keras<2.8,>=2.7.0rc0
  Downloading keras-2.7.0-py2.py3-none-any.whl (1.3 MB)
     |████████████████████████████████| 1.3 MB 42 kB/s 
Collecting astunparse>=1.6.0
  Downloading astunparse-1.6.3-py2.py3-none-any.whl (12 kB)
Collecting opt-einsum>=2.3.2
  Downloading opt_einsum-3.3.0-py3-none-any.whl (65 kB)
     |████████████████████████████████| 65 kB 38 kB/s 
Collecting typing-extensions>=3.6.6
  Downloading typing_extensions-4.1.1-py3-none-any.whl (26 kB)
Requirement already satisfied: keras-preprocessing>=1.1.1 in /home/spypiggy/miniconda3/envs/py_38/lib/python3.8/site-packages (from tensorflow==2.7.0) (1.1.2)
Collecting grpcio<2.0,>=1.24.3
  Downloading grpcio-1.44.0-cp38-cp38-manylinux_2_17_aarch64.whl (54.8 MB)
     |████████████████████████████████| 54.8 MB 42 kB/s 
Collecting google-pasta>=0.1.1
  Downloading google_pasta-0.2.0-py3-none-any.whl (57 kB)
     |████████████████████████████████| 57 kB 35 kB/s 
Collecting absl-py>=0.4.0
  Downloading absl_py-1.0.0-py3-none-any.whl (126 kB)
     |████████████████████████████████| 126 kB 45 kB/s 
Collecting libclang>=9.0.1
  Downloading libclang-13.0.0-py2.py3-none-manylinux2014_aarch64.whl (26.0 MB)
     |████████████████████████████████| 26.0 MB 45 kB/s 
Collecting flatbuffers<3.0,>=1.12
  Downloading flatbuffers-2.0-py2.py3-none-any.whl (26 kB)
Collecting gast<0.5.0,>=0.2.1
  Downloading gast-0.4.0-py3-none-any.whl (9.8 kB)
Requirement already satisfied: wheel<1.0,>=0.32.0 in /home/spypiggy/miniconda3/envs/py_38/lib/python3.8/site-packages (from tensorflow==2.7.0) (0.37.1)
Requirement already satisfied: numpy>=1.14.5 in /home/spypiggy/miniconda3/envs/py_38/lib/python3.8/site-packages (from tensorflow==2.7.0) (1.21.5)
Requirement already satisfied: six>=1.12.0 in /home/spypiggy/miniconda3/envs/py_38/lib/python3.8/site-packages (from tensorflow==2.7.0) (1.16.0)
Collecting wrapt>=1.11.0
  Downloading wrapt-1.13.3.tar.gz (48 kB)
     |████████████████████████████████| 48 kB 45 kB/s 
Requirement already satisfied: h5py>=2.9.0 in /home/spypiggy/miniconda3/envs/py_38/lib/python3.8/site-packages (from tensorflow==2.7.0) (3.1.0)
Collecting tensorflow-estimator<2.8,~=2.7.0rc0
  Downloading tensorflow_estimator-2.7.0-py2.py3-none-any.whl (463 kB)
     |████████████████████████████████| 463 kB 55 kB/s 
Collecting protobuf>=3.9.2
  Downloading protobuf-3.19.4-cp38-cp38-manylinux2014_aarch64.whl (913 kB)
     |████████████████████████████████| 913 kB 36 kB/s 
Collecting tensorboard~=2.6
  Downloading tensorboard-2.8.0-py3-none-any.whl (5.8 MB)
     |████████████████████████████████| 5.8 MB 32 kB/s 
Collecting google-auth-oauthlib<0.5,>=0.4.1
  Downloading google_auth_oauthlib-0.4.6-py2.py3-none-any.whl (18 kB)
Collecting werkzeug>=0.11.15
  Downloading Werkzeug-2.0.3-py3-none-any.whl (289 kB)
     |████████████████████████████████| 289 kB 87 kB/s 
Collecting tensorboard-plugin-wit>=1.6.0
  Downloading tensorboard_plugin_wit-1.8.1-py3-none-any.whl (781 kB)
     |████████████████████████████████| 781 kB 46 kB/s 
Collecting markdown>=2.6.8
  Downloading Markdown-3.3.6-py3-none-any.whl (97 kB)
     |████████████████████████████████| 97 kB 61 kB/s 
Requirement already satisfied: requests<3,>=2.21.0 in /home/spypiggy/miniconda3/envs/py_38/lib/python3.8/site-packages (from tensorboard~=2.6->tensorflow==2.7.0) (2.27.1)
Collecting tensorboard-data-server<0.7.0,>=0.6.0
  Downloading tensorboard_data_server-0.6.1-py3-none-any.whl (2.4 kB)
Collecting google-auth<3,>=1.6.3
  Downloading google_auth-2.6.0-py2.py3-none-any.whl (156 kB)
     |████████████████████████████████| 156 kB 21 kB/s 
Requirement already satisfied: setuptools>=41.0.0 in /home/spypiggy/miniconda3/envs/py_38/lib/python3.8/site-packages (from tensorboard~=2.6->tensorflow==2.7.0) (58.0.4)
Collecting rsa<5,>=3.1.4
  Downloading rsa-4.8-py3-none-any.whl (39 kB)
Collecting cachetools<6.0,>=2.0.0
  Downloading cachetools-5.0.0-py3-none-any.whl (9.1 kB)
Collecting pyasn1-modules>=0.2.1
  Downloading pyasn1_modules-0.2.8-py2.py3-none-any.whl (155 kB)
     |████████████████████████████████| 155 kB 45 kB/s 
Collecting requests-oauthlib>=0.7.0
  Downloading requests_oauthlib-1.3.1-py2.py3-none-any.whl (23 kB)
Collecting importlib-metadata>=4.4
  Downloading importlib_metadata-4.11.2-py3-none-any.whl (17 kB)
Collecting zipp>=0.5
  Downloading zipp-3.7.0-py3-none-any.whl (5.3 kB)
Collecting pyasn1<0.5.0,>=0.4.6
  Downloading pyasn1-0.4.8-py2.py3-none-any.whl (77 kB)
     |████████████████████████████████| 77 kB 36 kB/s 
Requirement already satisfied: idna<4,>=2.5 in /home/spypiggy/miniconda3/envs/py_38/lib/python3.8/site-packages (from requests<3,>=2.21.0->tensorboard~=2.6->tensorflow==2.7.0) (3.3)
Requirement already satisfied: certifi>=2017.4.17 in /home/spypiggy/miniconda3/envs/py_38/lib/python3.8/site-packages (from requests<3,>=2.21.0->tensorboard~=2.6->tensorflow==2.7.0) (2021.10.8)
Requirement already satisfied: charset-normalizer~=2.0.0 in /home/spypiggy/miniconda3/envs/py_38/lib/python3.8/site-packages (from requests<3,>=2.21.0->tensorboard~=2.6->tensorflow==2.7.0) (2.0.12)
Requirement already satisfied: urllib3<1.27,>=1.21.1 in /home/spypiggy/miniconda3/envs/py_38/lib/python3.8/site-packages (from requests<3,>=2.21.0->tensorboard~=2.6->tensorflow==2.7.0) (1.26.8)
Collecting oauthlib>=3.0.0
  Downloading oauthlib-3.2.0-py3-none-any.whl (151 kB)
     |████████████████████████████████| 151 kB 32 kB/s 
Building wheels for collected packages: termcolor, wrapt
  Building wheel for termcolor (setup.py) ... done
  Created wheel for termcolor: filename=termcolor-1.1.0-py3-none-any.whl size=4848 sha256=53a718cbd76bfb53bb1a186a9613af9bc21ac6ff050e264c576bf7185c53359e
  Stored in directory: /home/spypiggy/.cache/pip/wheels/a0/16/9c/5473df82468f958445479c59e784896fa24f4a5fc024b0f501
  Building wheel for wrapt (setup.py) ... done
  Created wheel for wrapt: filename=wrapt-1.13.3-cp38-cp38-linux_aarch64.whl size=81199 sha256=c9a1fdd72b276337b7e2ea8ad397ece37ad2828c307a6e3544959407c546d012
  Stored in directory: /home/spypiggy/.cache/pip/wheels/bb/05/57/f0c531fdf04b11be18b21ab4d1ec5586a6897caa6710c2a1a5
Successfully built termcolor wrapt
Installing collected packages: pyasn1, zipp, rsa, pyasn1-modules, oauthlib, cachetools, requests-oauthlib, importlib-metadata, google-auth, werkzeug, tensorboard-plugin-wit, tensorboard-data-server, protobuf, markdown, grpcio, google-auth-oauthlib, absl-py, wrapt, typing-extensions, termcolor, tensorflow-io-gcs-filesystem, tensorflow-estimator, tensorboard, opt-einsum, libclang, keras, google-pasta, gast, flatbuffers, astunparse, tensorflow
Successfully installed absl-py-1.0.0 astunparse-1.6.3 cachetools-5.0.0 flatbuffers-2.0 gast-0.4.0 google-auth-2.6.0 google-auth-oauthlib-0.4.6 google-pasta-0.2.0 grpcio-1.44.0 importlib-metadata-4.11.2 keras-2.7.0 libclang-13.0.0 markdown-3.3.6 oauthlib-3.2.0 opt-einsum-3.3.0 protobuf-3.19.4 pyasn1-0.4.8 pyasn1-modules-0.2.8 requests-oauthlib-1.3.1 rsa-4.8 tensorboard-2.8.0 tensorboard-data-server-0.6.1 tensorboard-plugin-wit-1.8.1 tensorflow-2.7.0 tensorflow-estimator-2.7.0 tensorflow-io-gcs-filesystem-0.24.0 termcolor-1.1.0 typing-extensions-4.1.1 werkzeug-2.0.3 wrapt-1.13.3 zipp-3.7.0


Installation is complete. Now let's check if the tensorflow package is working properly. You can check that it works with the GPU version

(py_38) spypiggy@spypiggy-desktop:/tmp/tensorflow_pkg$ python
Python 3.8.12 (default, Nov  5 2021, 09:55:51) 
[GCC 10.2.0] :: Anaconda, Inc. on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import tensorflow as tf
>>> tf.__version__
'2.7.0'
>>> print(tf.config.list_physical_devices('GPU'))
[PhysicalDevice(name='/physical_device:GPU:0', device_type='GPU')]


Wrapping up

Many developers have already released the tensorflow wheel package for Jetson on GitHub. And NVidia is also releasing packages such as TensorFlow PyTorch for Jetson series.  NVidia's download page is as follows.


<NVidia tensorflow download page>


Downloading from this page and using it is the most common way. However, if you need TensorFlow to work with a higher Python version (we used 3.8), you have to build it yourself using the method introduced above.


2022년 2월 26일 토요일

Build Tensorflow python wheel for Raspberry Pi OS 64bit

Machine learning packages like TensorFlow perform much better on a 64-bit OS than on a 32-bit OS.

If you are going to use TensorFlow on Raspberry Pi, make sure to run it on a 64-bit OS. 

In a previous article, I looked at how to cross-build the Raspberry Pi OS 64-bit version of TensorFlow Lite on your x86 PC and then install it on the Raspberry Pi. Since TensorFlow Lite can be installed not only on Raspberry Pi but also on Android devices using arm CPU, cross-build is often used. Isn't it too difficult to download and build the TensorFlow Lite source code on your Android smartphone? 

In this article, we will look at how to build a TensorFlow Python on Raspberry Pi OS 64-bit . To be honest, I tried to cross-build the TensorFlow package, but it failed due to several issues. 

For Raspberry Pi, 8GB model must be prepared. The reason is that the Basel build requires a lot of memory. If a build error occurs even when using 8GB of memory,

Increase memory using ZRAM

If an error occurs during the Basel build process during the following tasks despite using the 8GB model, increase the memory using zram. It is also faster than using a swap file. And since it reduces the IO of the SD card that occurs when using the swap file, it also helps the life of the SD card.

install zram tool

Since there is already a well-made installation script file, download it from git.

$ git clone https://github.com/StuartIanNaylor/zram-swap-config \
&& cd zram-swap-config
$ sudo ./install.sh


zram settings

Edit the /etc/zram-swap-config.conf file. The description of the item values is as follows.

  • MEM_FACTOR = Percentage of available ram to allocate to all zram swap devices which is divided equally by swap_devices number
  • DRIVE_FACTOR = Virtual uncompressed zram drive size estimate approx alg compression ratio
  • COMP_ALG lz4 is faster than lzo but some distro's show compile and operational difference and in use lzo depending on binary may be faster. Compression rates list below are minimums and generally far bigger in operation but dependent on content.
  • SWAP_DEVICES = number of indivial drives sharing memeory provided by MEM_FACTOR each device support multiple streams 1 large drive is generally better
  • SWAP_PRI = swap_priority for each drive 75 is a high order preference and should be well above other swap drives
  • PAGE_CLUSTER default page cluster is 3 which caches fetches in batches of 8 and helps with HDD paging, with zram mem 0 forces single page fetches This can help reduce latency and increase performance
  • SWAPPINESS default swappiness is 60 but with increased performance of zram swap 80 garners overall performance gain without excessive load Because zram uses compression load is created and even if minimal at intense load periods such as boot any extra load is unwanted Unfortunately there is no dynamic load balancing of swappiness as with zram in general operation SWAPINESS=100 will garner performance benefit If the overall load is reasonable at high load it will cause load to accumulate. If you check my repo there will also be a simple dynamic load based SWAPPINESS governor that will get of the hurdle of a static compromise on swappiness

<from https://github.com/StuartIanNaylor/zram-swap-config>


The following is an example of setting in Raspberry Pi 4B with 8GB memory. Zram is applied to 40% of the memory.

root@raspberrypi:~# cat /etc/zram-swap-config.conf
MEM_FACTOR=40
DRIVE_FACTOR=300
COMP_ALG=lz4
SWAP_DEVICES=1
SWAP_PRI=75
PAGE_CLUSTER=0
SWAPPINESS=90


pi@raspberrypi:~ $ sudo cat /proc/swaps
Filename                                Type            Size            Used            Priority
/dev/zram0                              partition       9600608         0               75
/var/swap                               file            102396          0               -2
pi@raspberrypi:~ $ free -m
               total        used        free      shared  buff/cache   available
Mem:            7813         358        7012          36         441        7306
Swap:           9475           0        9475

Change the /var/swap swap file to use only zram. This operation is performed as the root user (you can omit this operation).


pi@raspberrypi:~ $ sudo su -

SSH is enabled and the default password for the 'pi' user has not been changed.
This is a security risk - please login as the 'pi' user and type 'passwd' to set a new password.

root@raspberrypi:~#
root@raspberrypi:~#
root@raspberrypi:~# dphys-swapfile swapoff \
&& dphys-swapfile uninstall \
&& update-rc.d dphys-swapfile disable
root@raspberrypi:~#
root@raspberrypi:~#
root@raspberrypi:~#
root@raspberrypi:~# free -m
               total        used        free      shared  buff/cache   available
Mem:            7813         363        7004          36         445        7302
Swap:           9375           0        9375

Reboot for zram changes to take effect.


Install required packages to build tensorflow

For reference, the build work was carried out on the Raspberry Pi OS 64-bit Bullseye Desktop version.

First, install the packages required for the build task.

apt-get update
apt-get install -y  \
        build-essential \
        curl \
        git \
        libcurl3-dev \
        libfreetype6-dev \
        libhdf5-serial-dev \
        libzmq3-dev \
        pkg-config \
        rsync \
        software-properties-common \
        sudo \
        unzip \
        zip \
        zlib1g-dev 
apt-get install -y  openjdk-11-jdk \
        openjdk-11-jre-headless 
apt-get install -y  python3-pip

python3 -m pip --no-cache-dir install --upgrade \
    "pip<20.3" \
    setuptools

apt-get install -y \
    python3-dev \
    virtualenv \
    swig \
    gfortran \
    libblas-dev \
    liblapack-dev


python3 -m pip --no-cache-dir install \
    Pillow \
    keras_preprocessing \
    h5py \
    matplotlib \
    mock \
    scipy \
    sklearn \
    pandas \
    portpicker \
    enum34


And install Basel.

mkdir bazel
cd bazel
curl -fSsL -O https://github.com/bazelbuild/bazel/releases/download/4.2.1/bazel-4.2.1-dist.zip
unzip bazel-4.2.1-dist.zip
bash ./compile.sh
cp output/bazel /usr/local/bin/

If Basel is installed properly, you can check as follows.

pi@raspberrypi:~/src/bazel $ bazel --version
bazel 4.2.1- (@non-git)


Copy the TensorFlow source code.

pi@raspberrypi64:~ $ cd src
pi@raspberrypi64:~/src $git clone -b v2.8.0 https://github.com/tensorflow/tensorflow.git
cd tensorflow


It's time to build the python wheel

The following command takes more than 10 hours. Therefore, please avoid working on remote ssh if possible. When the ssh connection is disconnected, the build process is terminated.

pi@raspberrypi:~/src/tensorflow $ sudo bazel build \
--config=monolithic \
--config=noaws \
--config=nohdfs \
--config=nonccl \
--config=v2 \
--define=tflite_pip_with_flex=true \
--define=tflite_with_xnnpack=true \
--ui_actions_shown=64 \
//tensorflow/tools/pip_package:build_pip_package


The build ended after about 10 hours.

......
......
Target //tensorflow/tools/pip_package:build_pip_package up-to-date:
  bazel-bin/tensorflow/tools/pip_package/build_pip_package
INFO: Elapsed time: 53061.319s, Critical Path: 3604.28s
INFO: 11853 processes: 1175 internal, 10678 local.
INFO: Build completed successfully, 11853 total actions


Finally, build the TensorFlow Python wheel.

pi@raspberrypi:~/src/tensorflow $ ./tensorflow/tools/pip_package/build_pip_package.sh /tmp/tensorflow_pkg
/home/pi/src/tensorflow
/tmp/tmp.wiZjwBgJfY/tensorflow/include /home/pi/src/tensorflow
/home/pi/src/tensorflow
Sat 26 Feb 14:27:09 KST 2022 : === Building wheel
warning: no files found matching 'README'
warning: no files found matching '*.pyd' under directory '*'
warning: no files found matching '*.pyi' under directory '*'
warning: no files found matching '*.pd' under directory '*'
warning: no files found matching '*.so.[0-9]' under directory '*'
warning: no files found matching '*.dylib' under directory '*'
warning: no files found matching '*.dll' under directory '*'
warning: no files found matching '*.lib' under directory '*'
warning: no files found matching '*.csv' under directory '*'
warning: no files found matching '*.h' under directory 'tensorflow/include/tensorflow'
warning: no files found matching '*.proto' under directory 'tensorflow/include/tensorflow'
warning: no files found matching '*' under directory 'tensorflow/include/third_party'
/usr/local/lib/python3.9/dist-packages/setuptools/command/install.py:34: SetuptoolsDeprecationWarning: setup.py install is deprecated. Use build and pip and other standards-based tools.
  warnings.warn(
Sat 26 Feb 14:31:58 KST 2022 : === Output wheel file is in: /tmp/tensorflow_pkg

You can see the message that the tensorflow python wheel has been created in the tmp/tensorflow_pkg directory.

pi@raspberrypi:~/src/tensorflow $ ls -al /tmp/tensorflow_pkg/
total 279968
drwxr-xr-x   2 root root      4096 Feb 26 14:31 .
drwxrwxrwt 735 root root     36864 Feb 26 14:32 ..
-rw-r--r--   1 root root 286646178 Feb 26 14:31 tensorflow-2.8.0-cp39-cp39-linux_aarch64.whl


The reason the Python version of wheel is 3.9 is because the Python version installed on the Raspberry Pi OS 64-bit Bullseye version is 3.9. If you want to make a different version of Python wheel such as 3.8, install Python 3.8 and connect the python3 symbolic link in the /usr/bin directory to python3.8.

pi@raspberrypi:~/src/tensorflow $ ls -al /usr/bin/python3
lrwxrwxrwx 1 root root 9 Apr  5  2021 /usr/bin/python3 -> python3.9


Install the Tensorflow wheel 

To install the wheel file you just built, you must first install the packages required to use TensorFlow.

$ sudo apt-get install -y libhdf5-dev libc-ares-dev libeigen3-dev gcc gfortran libgfortran5 \
                          libatlas3-base libatlas-base-dev libopenblas-dev libopenblas-base libblas-dev \
                          liblapack-dev cython3 libatlas-base-dev openmpi-bin libopenmpi-dev
$ sudo pip3 install pip --upgrade
$ sudo pip3 install keras_applications==1.0.8 --no-deps
$ sudo pip3 install keras_preprocessing==1.1.0 --no-deps
$ sudo pip3 install h5py==3.1.0 
$ sudo pip3 install pybind11
$ pip3 install -U --user six wheel mock


It's time to install the python wheel

Finally, it's time to install the Python TensorFlow package.

pi@raspberrypi:~/src/tensorflow $ pip3 install /tmp/tensorflow_pkg/tensorflow-2.8.0-cp39-cp39-linux_aarch64.whl 

......

Successfully installed absl-py-1.0.0 astunparse-1.6.3 cachetools-5.0.0 flatbuffers-20181003210633 gast-0.5.3 google-auth-2.6.0 google-auth-oauthlib-0.4.6 google-pasta-0.2.0 grpcio-1.44.0 importlib-metadata-4.11.1 keras-2.8.0 keras-preprocessing-1.1.2 libclang-13.0.0 markdown-3.3.6 opt-einsum-3.3.0 protobuf-3.19.4 pyasn1-0.4.8 pyasn1-modules-0.2.8 rsa-4.8 tensorboard-2.8.0 tensorboard-data-server-0.6.1 tensorboard-plugin-wit-1.8.1 tensorflow-2.8.0 tensorflow-io-gcs-filesystem-0.24.0 termcolor-1.1.0 tf-estimator-nightly-2.8.0.dev2021122109


Let's check if TensorFlow is installed properly. You should not test in the tensorflow source directory. Because the tensorflow directory exists in this directory, an error occurs in import tensorflow.

pi@raspberrypi:~/src/tensorflow $ cd ..
pi@raspberrypi:~/src $ python3
Python 3.9.2 (default, Feb 28 2021, 17:03:44) 
[GCC 10.2.1 20210110] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import tensorflow as tf
>>> tf.__version__
'2.8.0'


Wrapping up

On Github, many developers have already created and provided a Python wheel for Raspberry Pi OS 64-bit. You can download the wheel they made and use it, but it's also a good job to build a TensorFlow package yourself that matches the Python version and OS version you want.


2022년 2월 19일 토요일

Cross Build Tensorflow Lite python wheel for Raspberry Pi OS 64bit on your PC

 Raspberry Pi OS 64-bit version was finally released in February 2022. Let's take a quick look at the differences between a 64-bit OS and a 32-bit OS.


Memory

If you are using a Pi model with less than 4GB of memory, there is not much difference between 32-bit and 64-bit when it comes to memory usage. However, if you plan to use the Rpi4 8GB memory model or a model with more than 8GB of memory among future models, it is good to know the memory usage according to the OS.

In principle, you cannot use more than 4GB of memory in a 32-bit OS. This is because the range of integer values ​​that can be stored in 32-bit is 0 to 4,294,967,295. This limitation is a limitation common to all OS including Windows as well as Raspberry Pi OS.

The reason for expressing the principle above is that 32-bit OSs use some tricks to overcome these limitations. 32-bit Linux running on ARM CPUs, including Raspberry Pi OS, uses a method called LPAE (Large Physical Address Extension), which enables addressing of more than 4 GB of memory. However, there is a big weakness here. Although the system as a whole can use more than 4GB of memory, there is a memory limit of 4GB per process because the 32-bit limit is not exceeded on a per-process basis. And 1 GB of this is allocated to the kernel, so the memory available to the actual process is within 3 GB.

This limitation may or may not be a problem depending on the user. If the purpose is to run a machine learning program or database server that requires a large amount of memory, this weakness of the 32-bit OS will be a problem, but if you mainly run light programs, the 32-bit OS will not be a problem.

And on a 64-bit OS, the memory usage increases a bit more. The main reason is that the memory value occupied by these variables is doubled because the variables for memory management are changed from 32-bit to 64-bit. If you install the 32-bit and 64-bit versions of Raspberry Pi OS Lite on the 512MB Zero 2, you can see that the OS occupies 48MB and 66MB of memory. But it's not a big difference. There's absolutely no reason not to use a 64-bit OS because of these differences.


Modern OS is 64 bit

SW compatibility is the main reason you should be interested in 64-bit OS in the future. Most mainstream OSs today are 64-bit, and numerous software packages are also created for these 64-bit OSs. Even if you do support a 32-bit compatible version, it is very likely that support will be discontinued at some point in the future. And the OS is also going in the direction that 32-bit OS will no longer offer new upgrades. Debian, the one used by the Raspberry Pi OS, still supports 32-bit OS, but obviously will stop supporting it at some point in the future. Perhaps for example the search engine elasticsearch no longer supports 32-bit Pi OS. Therefore, it is desirable for users who use the latest software to pay more attention to the 64-bit OS.

Nowadays, most software provides a Docker image to provide microservices in a Docker environment. The figure below compares the number of ARM-based Docker images. The number of Docker images provided by ARM64 is approximately doubled. Since most of the latest SWs are developed and updated targeting the 64-bit version, this difference is likely to widen further in the future. It feels like the reasons for moving to a 64-bit OS are increasing.


<Number of Dockers supporting ARM 32-bit and 64-bit OS>


Raspberry Pi models for use with 64-bit OS

The earliest Raspberry Pi models use 32-bit ARM CPUs. So it won't work on 64-bit OS. As can be seen from the following table, it is possible to use a 64-bit OS on Raspberry Pi models 3, 4, and Zero 2 models. 

<CPU by Raspberry Pi model>


Why you should use the 64-bit version of OS in TensorFlow

In Android mobile devices that mainly use ARM CPU or SBCs such as Raspberry Pi and Odroid, TensorFlow Lite is mainly used instead of heavy TensorFlow. However, NVidia's Jetson series is an exception because it has a GPU that supports CUDA.

Before the official version of Raspberry Pi OS 64-bit was released, the 64-bit OS used a lot in Raspberry Pi was Ubuntu 18.04+ aarch64 (64bit). As a result of testing, in Ubuntu 18.04+ aarch64 (64bit), TensorFlow Lite showed 4 times better performance than the 32-bit version of Raspberry Pi OS. 

4 times the performance is possible, isn't there any reason not to use it?

Google has well-equipped support and manuals for TensorFlow x86 CPUs and GPUs with CUDA, but ARM is quite lacking except for Android devices. It is possible to build and use the source code directly or use the packages made by preceding giants.

I mainly use Python. So, let's try to create a tensorflow light wheel file. The official website for building a wheel for TensorFlow Lite Python is https://www.tensorflow.org/lite/guide/build_cmake_pip

However, those who have visited this page will find it lacking in content.


ARM cross compilation

Until now, most users would have built on Raspberry Pi to make packages for Raspberry Pi, and Jetson Nano to create packages for Jetson Nano. For simple package builds, this method is the safest and safest. However, TensorFlow is a fairly large package and uses cmake, bazel, etc. as a build system. And since the build process requires a lot of memory, it is not easy to build on a Raspberry Pi or Jetson nano with 1 to 8GB of memory. During the build process, the system may freeze due to insufficient memory. Even if the build is successful, a huge build time is required. So it's a good idea to build such a large system on your desktop system. Mac, Windows, and Linux systems are all possible, but personally, I recommend the Linux system the most. As a cross-build platform, Ubuntu 18.04 was used, and 16 GB of memory and 16 GB of swap memory were used. A larger memory capacity would be more helpful.

And since a lot of software needs to be installed during the build process, I recommend using Docker. Google also recommends building based on Docker. So you need to install Docker on your Ubuntu 18.04 host first.


Install docker on the host machine

Install Docker with the following steps. How to install Docker on Ubuntu is well explained at https://docs.docker.com/engine/install/ubuntu/.

$ sudo apt-get update
$ sudo apt-get install  ca-certificates  curl   gnupg  lsb-release
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg

$ echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

$ sudo apt-get update
$ sudo apt-get install docker-ce docker-ce-cli containerd.io


If the output is as below, it is installed normally.

$ sudo docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
2db29710123e: Pull complete 
Digest: sha256:2498fce14358aa50ead0cc6c19990fc6ff866ce72aeb5546e1d59caac3d0d60f
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.


This time, we install bazel, Google's build system.

Install bazel on the host machine

For more information on installing Basel, please refer to https://docs.bazel.build/versions/5.0.0/install-ubuntu.html.

The following is preparation for bazel installation, and you only need to run it once.

sudo apt install apt-transport-https curl gnupg
curl -fsSL https://bazel.build/bazel-release.pub.gpg | gpg --dearmor > bazel.gpg
sudo mv bazel.gpg /etc/apt/trusted.gpg.d/
echo "deb [arch=amd64] https://storage.googleapis.com/bazel-apt stable jdk1.8" | sudo tee /etc/apt/sources.list.d/bazel.list

Now install bazel.

sudo apt update && sudo apt install bazel
#latest version update
sudo apt update && sudo apt full-upgrade


Copy the tensorflow source code

The TensorFlow source code will use the latest version 2.8 as of February 2022. Older versions under version 2.2 have a slightly different build method.

git clone -b v2.8.0 https://github.com/tensorflow/tensorflow.git
cd tensorflow


The build process of method1 and method is basically the same. After installing all the software required for building Tensorflow Lite using the Docker image, Tensorflow Lite whell is built by running the Docker image.

Currently, in the case of TensorFlow version 2.8, there is no problem building up to Python 3.8, but an error occurs in the 3.9 version build. The following mainly describes the corrections needed in addition to 3.9.

Build Method 1 - Using Makefile 

This is a method introduced on the TensorFlow official website. It is easier to set up and faster than method2. Up to the process of copying the source code described in "ARM cross compilation", method1 and method2 are the same.

According to the website https://www.tensorflow.org/lite/guide/build_cmake_arm#check_your_target_environment content, it is said to build as in the following figure. 



However, the 64-bit version of Raspberry Pi OS we want to apply uses Python 3.9. However, even if you change the parameter in the above figure to 3.9, only version 3.7 is created. This is because there are some errors in the Makefile. Modify the Makefile as follows.

In the above figure, the Makefile is located in the directory (tensorflow/lite/tools/pip_package) where the make command is applied. Modify the following part in the Makefile.

docker-image:
ifeq ($(BASE_IMAGE),ubuntu:16.04)
	docker build -t $(TAG_IMAGE) --build-arg IMAGE=$(BASE_IMAGE) --build-arg PYTHON_VERSION=3.8 -f Dockerfile.py3 .
else
	docker build -t $(TAG_IMAGE) --build-arg IMAGE=$(BASE_IMAGE) .
endif

<original Makefile >

Change the Ubuntu 16.04 Docker image used in the Makefile to 18.04 and modify the Python version to use the value received as a parameter.

docker-image:
ifeq ($(BASE_IMAGE),ubuntu:18.04)
	@echo  "Python version  $(PYTHON_VERSION)"
	docker build -t $(TAG_IMAGE) --build-arg IMAGE=$(BASE_IMAGE) --build-arg PYTHON_VERSION=$(PYTHON_VERSION) -f Dockerfile.py3 .
else
	docker build -t $(TAG_IMAGE) --build-arg IMAGE=$(BASE_IMAGE) .endif

<modified Makefile>


And the tensorflow/lite/tools/pip_package/Dockerfile.py3 file needs some modifications to use it in Python 3.9.

ARG IMAGE
FROM ${IMAGE}
ARG PYTHON_VERSION
COPY update_sources.sh /
RUN /update_sources.sh

RUN dpkg --add-architecture armhf
RUN dpkg --add-architecture arm64

<original Dockerfile.py3>

And to remove the user interface such as time zone setting during docker image creation, I added the line "ARG DEBIAN_FRONTEND=noninteractive". And I added some repo information those you can find at "/usr/local/src/study/docker/tensorflow/tensorflow/tools/ci_build/install/install_pi_python3x_toolchain.sh" that used in method2.

ARG IMAGE
FROM ${IMAGE}
ARG PYTHON_VERSION

ARG DEBIAN_FRONTEND=noninteractive

COPY update_sources.sh /
RUN /update_sources.sh
RUN dpkg --add-architecture armhf
RUN dpkg --add-architecture arm64

RUN echo 'deb [arch=arm64,armhf] http://ports.ubuntu.com/ bionic main restricted universe multiverse' >> /etc/apt/sources.list.d/armhf.list
RUN echo 'deb [arch=arm64,armhf] http://ports.ubuntu.com/ bionic-updates main restricted universe multiverse' >> /etc/apt/sources.list.d/armhf.list
RUN echo 'deb [arch=arm64,armhf] http://ports.ubuntu.com/ bionic-security main restricted universe multiverse' >> /etc/apt/sources.list.d/armhf.list
RUN echo 'deb [arch=arm64,armhf] http://ports.ubuntu.com/ bionic-backports main restricted universe multiverse' >> /etc/apt/sources.list.d/armhf.list
RUN sed -i 's#deb http://archive.ubuntu.com/ubuntu/#deb [arch=amd64] http://archive.ubuntu.com/ubuntu/#g' /etc/apt/sources.list

<modified Dockerfile.py3>

It's time to build the python wheel

The part to pay attention to in the build command is that BASE_IMAGE must be set to Ubuntu 18.04.

make -C tensorflow/lite/tools/pip_package docker-build \
  TENSORFLOW_TARGET=aarch64 PYTHON_VERSION=3.9 BASE_IMAGE=ubuntu:18.04

After a while, the build is finished and you can check the Tensorflow Lite wheel file for Python 3.9 created as follows.

...... SKIP

adding 'tflite_runtime-2.8.0.dist-info/METADATA'
adding 'tflite_runtime-2.8.0.dist-info/WHEEL'
adding 'tflite_runtime-2.8.0.dist-info/top_level.txt'
adding 'tflite_runtime-2.8.0.dist-info/RECORD'
removing build/bdist.linux-aarch64/wheel
+ echo 'Output can be found here:'
Output can be found here:
+ find /tensorflow/tensorflow/lite/tools/pip_package/gen/tflite_pip/python3/dist
/tensorflow/tensorflow/lite/tools/pip_package/gen/tflite_pip/python3/dist
/tensorflow/tensorflow/lite/tools/pip_package/gen/tflite_pip/python3/dist/tflite-runtime-2.8.0.linux-aarch64.tar.gz
/tensorflow/tensorflow/lite/tools/pip_package/gen/tflite_pip/python3/dist/tflite_runtime-2.8.0-cp39-cp39-linux_aarch64.whl
+ [[ n != \y ]]
+ exit 0
make: Leaving directory '/usr/local/src/study/docker/tensorflow/tensorflow/lite/tools/pip_package'

As you can see from the file name, it is a TensorFlow Lite runtime, and the TensorFlow version is 2.8, the supported Python is 3.9, and the supported platform is aarch64.

If you use armhf instead of aarch64 as the parameter of build_pip_package_with_bazel.sh command, you can create a 32-bit version of the wheel, and if you use native, you will be able to create a wheel for the x86 64-bit version.


Docker Images

If the build is successful, you can also check that the tf_ci.pi-python39 Docker image has been created. You now have a docker image with build environment for aarch64, python 3.9. If the build process is performed again, the build time will be significantly reduced because the Docker image build process is omitted.

root@ubuntu:/usr/local/src/study/docker/tensorflow/tensorflow/tools/pip_package# docker images
REPOSITORY                            TAG       IMAGE ID       CREATED          SIZE
tflite-runtime-builder-ubuntu-18.04   latest    f7296e034586   23 minutes ago   1.22GB
ubuntu                                18.04     886eca19e611   6 weeks ago      63.1MB


Build Method 2 - Using bash script file 

This is how to use the build_pip_package_with_bazel.sh script file. It is slightly more complicated than method1. Up to the process of copying the source code described in ARM cross compilation, method1 and method2 are the same.


Modify the build file

Modify the aarch64 part of the tensorflow/lite/tools/pip_package/build_pip_package_with_bazel.sh file as follows. 

# Build python interpreter_wrapper.
cd "${BUILD_DIR}"
case "${TENSORFLOW_TARGET}" in
  armhf)
    BAZEL_FLAGS="--config=elinux_armhf
      --copt=-march=armv7-a --copt=-mfpu=neon-vfpv4
      --copt=-O3 --copt=-fno-tree-pre --copt=-fpermissive
      --define tensorflow_mkldnn_contraction_kernel=0
      --define=raspberry_pi_with_neon=true"
    ;;
  aarch64)
    BAZEL_FLAGS="--config=elinux_aarch64
      --define tensorflow_mkldnn_contraction_kernel=0
      --copt=-O3"
    ;;
  native)
    BAZEL_FLAGS="--copt=-O3 --copt=-march=native"
    ;;
  *)
    BAZEL_FLAGS="--copt=-O3"
    ;;
esac

<original build_pip_package_with_bazel.sh>

The following is the modified tensorflow/lite/tools/pip_package/build_pip_package_with_bazel.sh file.

# Build python interpreter_wrapper.
cd "${BUILD_DIR}"
case "${TENSORFLOW_TARGET}" in
  armhf)
    BAZEL_FLAGS="--config=elinux_armhf
      --copt=-march=armv7-a --copt=-mfpu=neon-vfpv4
      --copt=-O3 --copt=-fno-tree-pre --copt=-fpermissive
      --define tensorflow_mkldnn_contraction_kernel=0
      --define=raspberry_pi_with_neon=true
      --define=tflite_pip_with_flex=true
      --define=tflite_with_xnnpack=false"
    ;;
  aarch64)
    BAZEL_FLAGS="--config=elinux_aarch64
      --define tensorflow_mkldnn_contraction_kernel=0
      --define=tflite_pip_with_flex=true
      --define=tflite_with_xnnpack=true
      --copt=-O3"
    ;;
  native)
    BAZEL_FLAGS="--copt=-O3 --copt=-march=native
      --define=tflite_pip_with_flex=true
      --define=tflite_with_xnnpack=true"
    ;;
  *)
    BAZEL_FLAGS="--copt=-O3
      --define=tflite_pip_with_flex=true
      --define=tflite_with_xnnpack=true"
    ;;
esac

<modified build_pip_package_with_bazel.sh>

Modify the tensorflow/tools/ci_build/Dockerfile.pi-python39 file as follows. 

FROM ubuntu:16.04

LABEL maintainer="Katsuya Hyodo <rmsdh122@yahoo.co.jp>"

ENV CI_BUILD_PYTHON=python3.9
ENV CROSSTOOL_PYTHON_INCLUDE_PATH=/usr/include/python3.9

# Copy and run the install scripts.
COPY install/*.sh /install/
RUN /install/install_bootstrap_deb_packages.sh
RUN add-apt-repository -y ppa:openjdk-r/ppa
RUN /install/install_deb_packages.sh --without_cmake
RUN /install/install_cmake.sh

# The following line installs the Python 3.9 cross-compilation toolchain.
RUN /install/install_pi_python3x_toolchain.sh "3.9"

RUN /install/install_bazel.sh
RUN /install/install_proto3.sh
RUN /install/install_buildifier.sh
RUN /install/install_auditwheel.sh
RUN /install/install_golang.sh

# Set up the master bazelrc configuration file.
COPY install/.bazelrc /etc/bazel.bazelrc
RUN chmod 644 /etc/bazel.bazelrc

# XLA is not needed for PI
ENV TF_ENABLE_XLA=0

<original Dockerfile.pi-python39>


I made three corrections. Changed docker image from Ubuntu 16 to 18.

And to remove the user interface such as time zone setting during docker image creation, I added the line "ARG DEBIAN_FRONTEND=noninteractive".

Finally, in the install_auditwhell.sh file, we added a parameter "3.9" to add Python 3.9 related actions.

FROM ubuntu:18.04

LABEL maintainer="Katsuya Hyodo <rmsdh122@yahoo.co.jp>"

ENV CI_BUILD_PYTHON=python3.9
ENV CROSSTOOL_PYTHON_INCLUDE_PATH=/usr/include/python3.9

ARG DEBIAN_FRONTEND=noninteractive
# Copy and run the install scripts.
COPY install/*.sh /install/

RUN /install/install_bootstrap_deb_packages.sh
RUN add-apt-repository -y ppa:openjdk-r/ppa
RUN /install/install_deb_packages.sh --without_cmake
RUN /install/install_cmake.sh

# The following line installs the Python 3.9 cross-compilation toolchain.
RUN /install/install_pi_python3x_toolchain.sh "3.9"

RUN /install/install_bazel.sh
RUN /install/install_proto3.sh
RUN /install/install_buildifier.sh
RUN /install/install_auditwheel.sh  "3.9"
RUN /install/install_golang.sh

# Set up the master bazelrc configuration file.
COPY install/.bazelrc /etc/bazel.bazelrc
RUN chmod 644 /etc/bazel.bazelrc

# XLA is not needed for PI
ENV TF_ENABLE_XLA=0

<modified Dockerfile.pi-python39>


Modify the tensorflow/tools/ci_build/install/install_pi_python3x_toolchain.sh file as follows.

PYTHON_VERSION=$1
dpkg --add-architecture armhf
dpkg --add-architecture arm64
echo 'deb [arch=arm64,armhf] http://ports.ubuntu.com/ bionic main restricted universe multiverse' >> /etc/apt/sources.list.d/armhf.list
echo 'deb [arch=arm64,armhf] http://ports.ubuntu.com/ bionic-updates main restricted universe multiverse' >> /etc/apt/sources.list.d/armhf.list
echo 'deb [arch=arm64,armhf] http://ports.ubuntu.com/ bionic-security main restricted universe multiverse' >> /etc/apt/sources.list.d/armhf.list
echo 'deb [arch=arm64,armhf] http://ports.ubuntu.com/ bionic-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 python${PYTHON_VERSION} python${PYTHON_VERSION}-dev
#/usr/local/bin/python3.x is needed to use /install/install_pip_packages_by_version.sh
ln -sf /usr/bin/python${PYTHON_VERSION} /usr/local/bin/python${PYTHON_VERSION}
apt-get install -y libpython${PYTHON_VERSION}-dev:armhf
apt-get install -y libpython${PYTHON_VERSION}-dev:arm64

SPLIT_VERSION=(`echo ${PYTHON_VERSION} | tr -s '.' ' '`)
if [[ SPLIT_VERSION[0] -eq 3 ]] && [[ SPLIT_VERSION[1] -ge 8 ]]; then
  apt-get install -y python${PYTHON_VERSION}-distutils
fi

/install/install_pip_packages_by_version.sh "/usr/local/bin/pip${PYTHON_VERSION}"
ln -sf /usr/local/lib/python${PYTHON_VERSION}/dist-packages/numpy/core/include/numpy /usr/include/python${PYTHON_VERSION}/numpy

<original install_pi_python3x_toolchain.sh>

make a symbolic link of python3.9. Now Python3 command will automatically execute Python3.9 command.

PYTHON_VERSION=$1
dpkg --add-architecture armhf
dpkg --add-architecture arm64
echo 'deb [arch=arm64,armhf] http://ports.ubuntu.com/ bionic main restricted universe multiverse' >> /etc/apt/sources.list.d/armhf.list
echo 'deb [arch=arm64,armhf] http://ports.ubuntu.com/ bionic-updates main restricted universe multiverse' >> /etc/apt/sources.list.d/armhf.list
echo 'deb [arch=arm64,armhf] http://ports.ubuntu.com/ bionic-security main restricted universe multiverse' >> /etc/apt/sources.list.d/armhf.list
echo 'deb [arch=arm64,armhf] http://ports.ubuntu.com/ bionic-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 python${PYTHON_VERSION} python${PYTHON_VERSION}-dev
#/usr/local/bin/python3.x is needed to use /install/install_pip_packages_by_version.sh
ln -sf /usr/bin/python${PYTHON_VERSION} /usr/local/bin/python${PYTHON_VERSION}
#Add this Line
ln -sf /usr/bin/python${PYTHON_VERSION} /usr/bin/python3
apt-get install -y libpython${PYTHON_VERSION}-dev:armhf
apt-get install -y libpython${PYTHON_VERSION}-dev:arm64

SPLIT_VERSION=(`echo ${PYTHON_VERSION} | tr -s '.' ' '`)
if [[ SPLIT_VERSION[0] -eq 3 ]] && [[ SPLIT_VERSION[1] -ge 8 ]]; then
  apt-get install -y python${PYTHON_VERSION}-distutils
fi

/install/install_pip_packages_by_version.sh "/usr/local/bin/pip${PYTHON_VERSION}"
ln -sf /usr/local/lib/python${PYTHON_VERSION}/dist-packages/numpy/core/include/numpy /usr/include/python${PYTHON_VERSION}/numpy

<modified install_pi_python3x_toolchain.sh>


Modify the tensorflow/tools/ci_build/install/install_auditwheel.sh file as follows.

set -e

sudo pip3 install auditwheel==2.0.0

# Pin wheel==0.31.1 to work around issue
# https://github.com/pypa/auditwheel/issues/102
sudo pip3 install wheel==0.31.1

set +e
patchelf_location=$(which patchelf)
if [[ -z "$patchelf_location" ]]; then
  set -e
  # Install patchelf from source (it does not come with trusty package)
  wget https://nixos.org/releases/patchelf/patchelf-0.9/patchelf-0.9.tar.bz2
  tar xfa patchelf-0.9.tar.bz2
  cd patchelf-0.9
  ./configure --prefix=/usr/local
  make
  sudo make install
fi
cd ..

<original install_auditwheel.sh>


For Python 3.9, the numpy and setuptools installation lines have been added. This process is not required in Python 3.8.

set -e
PYTHON_VERSION=$1

if [[ "$PYTHON_VERSION" == "3.9" ]]; then
  sudo pip3 install setuptools==60.7.0
  sudo pip3 install numpy==1.22.1
fi

sudo pip3 install auditwheel==2.0.0

# Pin wheel==0.31.1 to work around issue
# https://github.com/pypa/auditwheel/issues/102
sudo pip3 install wheel==0.31.1

set +e
patchelf_location=$(which patchelf)
if [[ -z "$patchelf_location" ]]; then
  set -e
  # Install patchelf from source (it does not come with trusty package)
  wget https://nixos.org/releases/patchelf/patchelf-0.9/patchelf-0.9.tar.bz2
  tar xfa patchelf-0.9.tar.bz2
  cd patchelf-0.9
  ./configure --prefix=/usr/local
  make
  sudo make install
fi
cd ..

<modified install_auditwheel.sh>

And tensorflow/tools/ci_build/Dockerfile.pi-python38, Dockerfile.pi-python37 files are also recommended to change the Docker image from Ubuntu 16.04 to 18.04.


It's time to build the python wheel

The part to be concerned about in the build options is the Python 3 version to be used in the target Raspberry Pi OS. 3.7 or higher can be set. I will build with the Python 3.9 target. This is because the version of Python 3 installed on the Raspberry Pi OS 64-bit is 3.9. Note that the build may take several hours depending on your computer's performance.

### Python 3.9
sudo CI_DOCKER_EXTRA_PARAMS="-e CI_BUILD_PYTHON=python3.9 -e CROSSTOOL_PYTHON_INCLUDE_PATH=/usr/include/python3.9" \
  tensorflow/tools/ci_build/ci_build.sh PI-PYTHON39 \
  tensorflow/lite/tools/pip_package/build_pip_package_with_bazel.sh aarch64

After a while, the build is finished and you can check the Tensorflow Lite wheel file for Python 3.9 created as follows.

...... SKIP


wrapper.cc
/workspace/tensorflow/lite/tools/pip_package/gen/tflite_pip/python3.9/interpreter_wrapper/python_utils.h
/workspace/tensorflow/lite/tools/pip_package/gen/tflite_pip/python3.9/interpreter_wrapper/interpreter_wrapper_pybind11.cc
/workspace/tensorflow/lite/tools/pip_package/gen/tflite_pip/python3.9/interpreter_wrapper/numpy.h
/workspace/tensorflow/lite/tools/pip_package/gen/tflite_pip/python3.9/interpreter_wrapper/numpy.cc
/workspace/tensorflow/lite/tools/pip_package/gen/tflite_pip/python3.9/interpreter_wrapper/python_utils.cc
/workspace/tensorflow/lite/tools/pip_package/gen/tflite_pip/python3.9/interpreter_wrapper/python_error_reporter.h
/workspace/tensorflow/lite/tools/pip_package/gen/tflite_pip/python3.9/interpreter_wrapper/python_error_reporter.cc
/workspace/tensorflow/lite/tools/pip_package/gen/tflite_pip/python3.9/interpreter_wrapper/interpreter_wrapper.h
/workspace/tensorflow/lite/tools/pip_package/gen/tflite_pip/python3.9/setup.py
root@ubuntu:/usr/local/src/study/docker/tensorflow# find . -name *.whl
./tensorflow/lite/tools/pip_package/gen/tflite_pip/python3.9/dist/tflite_runtime-2.8.0-cp39-cp39-linux_aarch64.whl

As you can see from the file name, it is a TensorFlow Lite runtime, and the TensorFlow version is 2.8, the supported Python is 3.9, and the supported platform is aarch64.

If you use armhf instead of aarch64 as the parameter of build_pip_package_with_bazel.sh command, you can create a 32-bit version of the wheel, and if you use native, you will be able to create a wheel for the x86 64-bit version.


Docker Images

If the build is successful, you can also check that the tf_ci.pi-python39 Docker image has been created. You now have a docker image with build environment for aarch64, python 3.9. If the build process is performed again, the build time will be significantly reduced because the Docker image build process is omitted.

root@ubuntu:/tmp# docker images
REPOSITORY          TAG       IMAGE ID       CREATED             SIZE
tf_ci.pi-python39   latest    3b1e395a1cb5   43 minutes ago      2GB
ubuntu              18.04     886eca19e611   6 weeks ago         63.1MB



Install TensorFlow Lite wheel on Raspberry Pi OS 64-bit

Now, install the TensorFlow lite wheel you just built on the Raspberry Pi OS 64-bit version and check whether it works properly.

First, install the Raspberry Pi OS 64-bit desktop version on the Raspberry Pi. For reference, enable ssh in Raspberry Pi Imager when creating an image. And if you are going to use a wireless LAN, it is good to include the wireless LAN information as well.

<Enable SSH and WLAN>


Installation

Before installing the TensorFlow light wheel you just built, first install the necessary packages on the Raspberry Pi.

pi@raspberrypi64:~ $ sudo apt install swig libjpeg-dev zlib1g-dev python3-dev \
                   unzip wget python3-pip curl git cmake make libgl1-mesa-glx
pi@raspberrypi64:~ $ sudo pip3 install numpy==1.22.1


And install OpenCV required for testing.

pi@raspberrypi64:~ $ pip3 install opencv-python~=4.5.3.56
Looking in indexes: https://pypi.org/simple, https://www.piwheels.org/simple
Collecting opencv-python~=4.5.3.56
  Downloading opencv_python-4.5.3.56-cp39-cp39-manylinux2014_aarch64.whl (34.2 MB)
     |████████████████████████████████| 34.2 MB 19 kB/s 
Requirement already satisfied: numpy>=1.19.3 in /usr/local/lib/python3.9/dist-packages (from opencv-python~=4.5.3.56) (1.22.1)
Installing collected packages: opencv-python
Successfully installed opencv-python-4.5.3.56


Then, copy the TensorFlow light wheel file to the Raspberry Pi and install it with the pip3 command.

pi@raspberrypi64:~ $ pip3 install tflite_runtime-2.8.0-cp39-cp39-linux_aarch64.whl 
Looking in indexes: https://pypi.org/simple, https://www.piwheels.org/simple
Processing ./tflite_runtime-2.8.0-cp39-cp39-linux_aarch64.whl
Requirement already satisfied: numpy>=1.19.2 in /usr/local/lib/python3.9/dist-packages (from tflite-runtime==2.8.0) (1.22.1)
Installing collected packages: tflite-runtime
Successfully installed tflite-runtime-2.8.0


And install the tflite-support>=0.3.1 package. The tflite-support package helps to get meta information such as labeling data from the model. I'll show you how to use it in an example later. 

pi@raspberrypi64:~ $ pip3 install tflite-support>=0.3.1


And simply check if the package is working properly.

pi@raspberrypi64:~ $ python3
Python 3.9.2 (default, Feb 28 2021, 17:03:44) 
[GCC 10.2.1 20210110] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from tflite_runtime.interpreter import Interpreter
>>> 

Yes it seems to be working fine. Then we will load the actual TensorFlow light model and make it work.


Testing TensorFlow Lite


Sample Python File

I made a simple python codes. I will test remotely using ssh. Therefore, we will use an image file instead of a camera.

First, download the model to be used for testing. The Efficient model is a model for object recognition and has much better performance than the previously used MobileNet.

pi@raspberrypi64:~ $ mkdir data   #copy sample test image this directory
pi@raspberrypi64:~ $ mkdir test
pi@raspberrypi64:~ $ cd test pi@raspberrypi64:~/test $ curl -L https://tfhub.dev/tensorflow/lite-model/efficientdet/lite0/detection/metadata/1?lite-format=tflite -o efficientdet_lite0.tflite

<download efficientdet_lite0.tflite>

And the following is the Python code for testing.

import argparse
import sys
import time, json
import cv2
import numpy as np
from tflite_runtime.interpreter import Interpreter
from tflite_support import metadata

parser = argparse.ArgumentParser(description='object detection')
parser.add_argument("--image", default="/home/pi/data/sample_image.jpg", help="test working directory where the image file exists")
parser.add_argument("--model", default="./efficientdet_lite0.tflite", help="model")
args = parser.parse_args()    


interpreter = Interpreter(model_path=args.model, num_threads=4)
interpreter.allocate_tensors()
input_details = interpreter.get_input_details()
output_details = interpreter.get_output_details()
height = input_details[0]['shape'][1]
width = input_details[0]['shape'][2]
#model requires these size
print('Inference Image Height:', height)
print('Inference Image Width:', width)
min_conf_threshold = 0.5

displayer = metadata.MetadataDisplayer.with_model_file(args.model)
model_metadata = json.loads(displayer.get_metadata_json())
# Load label list from metadata.
file_name = displayer.get_packed_associated_file_list()[0]
label_map_file = displayer.get_associated_file_buffer(file_name).decode()
label_list = list(filter(len, label_map_file.splitlines()))

image = cv2.imread(args.image)
image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
imH, imW, _ = image.shape 
image_resized = cv2.resize(image_rgb, (width, height))
input_data = np.expand_dims(image_resized, axis=0)


# Perform the actual detection by running the model with the image as input
interpreter.set_tensor(input_details[0]['index'],input_data)
interpreter.invoke()

boxes = interpreter.get_tensor(output_details[0]['index'])[0] # Bounding box coordinates of detected objects
classes = interpreter.get_tensor(output_details[1]['index'])[0] # Class index of detected objects
scores = interpreter.get_tensor(output_details[2]['index'])[0] # Confidence of detected objects


for i in range(len(scores)):
    if ((scores[i] > min_conf_threshold) and (scores[i] <= 1.0)):

        # Get bounding box coordinates and draw box
        # Interpreter can return coordinates that are outside of image dimensions, need to force them to be within image using max() and min()
        ymin = int(max(1,(boxes[i][0] * imH)))
        xmin = int(max(1,(boxes[i][1] * imW)))
        ymax = int(min(imH,(boxes[i][2] * imH)))
        xmax = int(min(imW,(boxes[i][3] * imW)))
        
        cv2.rectangle(image, (xmin,ymin), (xmax,ymax), (10, 255, 0), 2)
        object_name = label_list[int(classes[i])]
        label = '%s: %d%%' % (object_name, int(scores[i]*100)) # Example: 'person: 72%'
        labelSize, baseLine = cv2.getTextSize(label, cv2.FONT_HERSHEY_SIMPLEX, 0.7, 2) # Get font size
        label_ymin = max(ymin, labelSize[1] + 10) # Make sure not to draw label too close to top of window
        cv2.rectangle(image, (xmin, label_ymin-labelSize[1]-10), (xmin+labelSize[0], label_ymin+baseLine-10), (255, 255, 255), cv2.FILLED) # Draw white box to put label text in
        cv2.putText(image, label, (xmin, label_ymin-7), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 0), 2) # Draw label text
        # Draw label

        
cv2.imwrite('./result.jpg', image) 

<test_tflite_aarcg64.py>

Now run the sample code.

@raspberrypi64:~/test $ python test_tflite_aarcg64.py 
INFO: Created TensorFlow Lite XNNPACK delegate for CPU.
Inference Height: 320
Inference Width: 320
pi@raspberrypi64:~/test $ ls -al
total 5212
drwxr-xr-x 2 pi pi    4096 Feb 19 16:01 .
drwxr-xr-x 9 pi pi    4096 Feb 19 15:33 ..
-rw-r--r-- 1 pi pi 4563519 Feb 19 14:09 efficientdet_lite0.tflite
-rw-r--r-- 1 pi pi  756451 Feb 19 16:01 result.jpg
-rw-r--r-- 1 pi pi    3239 Feb 19 15:59 test_tflite_aarcg64.py


This  is the result image. Tensorflow lite model for aarch64 works successfully.



Wrapping up

I explained how to make a Tensorflow Lite wheel for Raspberry Pi 32-bit and 64-bit OS. It has the advantage of being able to build according to various versions of Python, and it is also possible to directly build TensorFlow that can be used on other systems using ARM CPU such as Odroid and Jetson series.

Most of this article is by PINTO0309 (Katsuya Hyodo).

There is an article I referenced at https://github.com/PINTO0309/TensorflowLite-bin.

You can download the codes at my github.