2022년 2월 27일 일요일

Effective Jetson Xavier NX Setup - Anaconda Development Environment

 This article is related to the previous article Effective Jetson Xavier NX Setup - SSD Booting. In the previous article, I explained how to use an SSD instead of an SD card in Xavier NX. When using an SSD, you can get much faster IO speed and superior stability than when using an SD card. And since a large amount of storage space is secured, you do not have to suffer from the small memory capacity of the SD card.

This time, we will think about how to create a SW development environment. Most of the development in the Jetson series will be for vision processing, machine learning, edge AI, device control, etc.

The development language will probably use Python and C/C++ heavily. The most difficult part of building a development environment in Xavier NX is the Python development environment.

For example, if you want to use TensorFlow 1.X and 2.X at the same time, you need to install different Python and packages, so you often use Python virtual environment or Anaconda. And many developers also use Docker. Unlike a virtual machine, Docker is a lightweight microservice that does not have an operating system. However, Docker images are often too large to be used in Jetson series.

In this article, I will explain how to create and work with a Python virtual environment using Anaconda instead of Docker.


Why use a Python virtual environment?

Different versions of Python are available in different versions.

If you have to use TensorFlow 2.8 and 1.12 versions as indicated in the table above, Python is not compatible. So we need two Pythons.

And the versions of packages required for each version of TensorFlow are different. Numpy packages, which are always used in TensorFlow and PyTorch, sometimes cause version problems. For example, if you change the version for a specific package, other packages do not work.

Because of this problem, the TensorFlow installation guide recommends using a virtual environment or Docker image like this.

<Installing TensorFlow in a Python virtual environment>

However, this method creates a virtual environment based on a specific Python version that the system already has installed. So it's not a good idea if you need to use more than one python. The best way is to create a virtual environment using Anaconda, install the version you want from Python, and then install TensorFlow in the virtual environment again.


Anaconda

Anaconda is a conditional free and open source software name that facilitates package/dependency management and distribution of Python and R languages, suitable for scientific research and machine learning fields.

It was originally free, but starting in 2020, it is free only for individual users, universities, non-profit organizations, and small and medium-sized enterprises (SMEs) with less than 200 employees, and has been changed to a fee for the government and companies with 200 or more employees.

And in 2020, the site that used to be anaconda.org was changed to anaconda.com, which was the cloud.

Now anaconda.org is the cloud site.


Anaconda includes most of the packages suitable for scientific research and machine learning applications. Therefore, there is a drawback that the size is quite large. Miniconda is a solution to this problem. Unlike anaconda, only the minimum required for operation is provided, and the user has to find and install the necessary packages himself. However, for this reason, the file is smaller and lighter than Anaconda.

Miniconda is a free minimal installer for conda. It is a small, bootstrap version of Anaconda that includes only conda, Python, the packages they depend on, and a small number of other useful packages, including pip, zlib and a few others. Use the conda install command to install 720+ additional conda packages from the Anaconda repository.

I'm going to install Anaconda on the Xavier NX. Because I am using an SSD with sufficient capacity.


Installing Anaconda on Xavier NX

There are instructions for installing Anaconda at https://www.anaconda.com/products/individual#Downloads

Since the Xavier NX we are using is an arrch64 CPU, right-click the link in the picture below to copy the path or download the installation script.


<Anaconda installation script download page>


Install Anaconda

wget https://repo.anaconda.com/archive/Anaconda3-2021.11-Linux-aarch64.sh
chmod 755 Anaconda3-2021.11-Linux-aarch64.sh
./Anaconda3-2021.11-Linux-aarch64.sh


When Anaconda is installed, the following content is added to the ~/.bashrc file.

So, whenever you open a new shell in the future, these lines will be executed.

# >>> conda initialize >>>
# !! Contents within this block are managed by 'conda init' !!
__conda_setup="$('/home/spypiggy/anaconda3/bin/conda' 'shell.bash' 'hook' 2> /dev/null)"
if [ $? -eq 0 ]; then
    eval "$__conda_setup"
else
    if [ -f "/home/spypiggy/anaconda3/etc/profile.d/conda.sh" ]; then
        . "/home/spypiggy/anaconda3/etc/profile.d/conda.sh"
    else
        export PATH="/home/spypiggy/anaconda3/bin:$PATH"
    fi
fi
unset __conda_setup
# <<< conda initialize <<<


And in the new shell prompt, (base) is added as follows:

(base) spypiggy@spypiggy-desktop:~$

If you do not want to initialize anaconda automatically, you can delete the conda initialization part from your ~/.bashrc file. And only one line related to the following path is left in the ~/.bashrc file.

# >>> conda initialize >>>
export PATH="/home/spypiggy/anaconda3/bin:$PATH"
# <<< conda initialize <<<


Important conda commands

The following are important commands to create a virtual environment using anaconda.


  • conda search python : Shows the Python versions that can be installed in Anaconda.

(base) spypiggy@spypiggy-xavierNX:~/anaconda3$ conda list
# packages in environment at /home/spypiggy/anaconda3:
#
# Name                    Version                   Build  Channel
_ipyw_jlab_nb_ext_conf    0.1.0            py39hd43f75c_0  
_libgcc_mutex             0.1                        main  
_openmp_mutex             5.1                      51_gnu  
adwaita-icon-theme        40.1.1               hd43f75c_1  
alabaster                 0.7.12             pyhd3eb1b0_0  
anaconda                  2021.11                  py39_0  
anaconda-client           1.9.0            py39hd43f75c_0  
anaconda-navigator        2.1.1                    py39_0  
anaconda-project          0.10.1             pyhd3eb1b0_0  
anyio                     2.2.0            py39hd43f75c_1  
appdirs                   1.4.4              pyhd3eb1b0_0  
argh                      0.26.2           py39hd43f75c_0  
argon2-cffi               20.1.0           py39h2f4d8fa_1  
arrow                     0.13.1           py39hd43f75c_0  
asn1crypto                1.4.0                      py_0  
astroid                   2.5              py39hd43f75c_1  
astropy                   4.3.1            py39h08bb699_0  
async_generator           1.10               pyhd3eb1b0_0  
at-spi2-atk               2.34.2               hf975c6d_0  
at-spi2-core              2.36.0               hf975c6d_1  
atk-1.0                   2.36.0               h920789f_0  
atomicwrites              1.4.0                      py_0  
attrs                     21.2.0             pyhd3eb1b0_0  
autopep8                  1.5.7              pyhd3eb1b0_0  
babel                     2.9.1              pyhd3eb1b0_0  
backcall                  0.2.0              pyhd3eb1b0_0  
backports                 1.0                pyhd3eb1b0_2  
backports.functools_lru_cache 1.6.4              pyhd3eb1b0_0  
backports.shutil_get_terminal_size 1.0.0              pyhd3eb1b0_3  
backports.tempfile        1.0                pyhd3eb1b0_1  
backports.weakref         1.0.post1                  py_1  
beautifulsoup4            4.10.0             pyh06a4308_0  
binaryornot               0.4.4              pyhd3eb1b0_1  
bitarray                  1.7.0            py39hfd63f10_1  
bkcharts                  0.2              py39hd43f75c_0  
black                     19.10b0                    py_0  
blas                      1.0                    openblas  
bleach                    4.0.0              pyhd3eb1b0_0  
blosc                     1.21.0               h2f720b1_0  
bokeh                     2.4.1            py39hd43f75c_0  
boto                      2.49.0           py39hd43f75c_0  
bottleneck                1.3.2            py39hfd0a847_1  
brotli                    1.0.9                h4de3ea5_4  
brotlipy                  0.7.0           py39hfd63f10_1002  
brunsli                   0.1                  h7c1a80f_1  
bzip2                     1.0.8                hfd63f10_2  
c-ares                    1.17.1               hfd63f10_0  
ca-certificates           2021.10.26           hd43f75c_2  
cached-property           1.5.2                      py_0  
cairo                     1.16.0               h81ccd62_1  
certifi                   2021.10.8        py39hd43f75c_0  
cffi                      1.14.5           py39hdced402_0  
cfitsio                   3.470                hd546d51_6  
chardet                   4.0.0           py39hd43f75c_1003  
charls                    2.2.0                h7c1a80f_0  
charset-normalizer        2.0.4              pyhd3eb1b0_0  
click                     8.0.3              pyhd3eb1b0_0  
cloudpickle               2.0.0              pyhd3eb1b0_0  
clyent                    1.2.2            py39hd43f75c_1  
colorama                  0.4.4              pyhd3eb1b0_0  
conda                     4.10.3                   py39_0  
conda-build               3.21.5           py39hd43f75c_0  
conda-content-trust       0.1.1              pyhd3eb1b0_0  
conda-env                 2.6.0                hd43f75c_1  
conda-pack                0.6.0              pyhd3eb1b0_0  
conda-package-handling    1.7.3            py39h2f4d8fa_1  
conda-repo-cli            1.0.4              pyhd3eb1b0_0  
conda-token               0.3.0              pyhd3eb1b0_0  
conda-verify              3.4.2                      py_1  
contextlib2               0.6.0.post1        pyhd3eb1b0_0  
cookiecutter              1.7.2              pyhd3eb1b0_0  
cryptography              3.4.7            py39hc8f1c36_0  
curl                      7.71.1               h8ea0f78_1  
cycler                    0.10.0           py39hd43f75c_0  
cython                    0.29.24          py39h2f4d8fa_0  
cytoolz                   0.11.0           py39hfd63f10_0  
dask                      2021.10.0          pyhd3eb1b0_0  
dask-core                 2021.10.0          pyhd3eb1b0_0  
dataclasses               0.8                pyh6d0b6a4_7  
dbus                      1.13.18              h821dc26_0  
debugpy                   1.4.1            py39h22f4aa5_0  
decorator                 5.1.0              pyhd3eb1b0_0  
defusedxml                0.7.1              pyhd3eb1b0_0  
diff-match-patch          20200713           pyhd3eb1b0_0  
distributed               2021.10.0        py39hd43f75c_0  
docutils                  0.17             py39hd43f75c_1  
entrypoints               0.3              py39hd43f75c_0  
epoxy                     1.5.4                h2f4d8fa_2  
et_xmlfile                1.1.0            py39hd43f75c_0  
expat                     2.4.1                h22f4aa5_2  
fastcache                 1.1.0            py39hfd63f10_0  
filelock                  3.3.1              pyhd3eb1b0_1  
flake8                    3.9.2              pyhd3eb1b0_0  
flask                     1.1.2              pyhd3eb1b0_0  
fontconfig                2.13.1               hbe5a0c3_0  
fonttools                 4.25.0             pyhd3eb1b0_0  
freetype                  2.10.4               hbbbf32d_1  
fribidi                   1.0.10               hfd63f10_0  
fsspec                    2021.8.1           pyhd3eb1b0_0  
future                    0.18.2           py39hd43f75c_1  
gdk-pixbuf                2.38.2               h920789f_4  
get_terminal_size         1.0.0                hd43f75c_0  
gettext                   0.21.0               h8e1abe2_0  
gevent                    21.8.0           py39h2f4d8fa_1  
giflib                    5.2.1                hfd63f10_0  
glib                      2.69.1               h7cb9b0f_0  
glob2                     0.7                pyhd3eb1b0_0  
gmp                       6.2.1                h7c1a80f_1  
gmpy2                     2.0.8            py39h3d095b0_3  
gobject-introspection     1.68.0           py39h5d90252_2  
graphite2                 1.3.14               h0b239d7_0  
greenlet                  1.1.1            py39h22f4aa5_0  
gst-plugins-base          1.14.1               hfb8a71d_0  
gstreamer                 1.14.1               h982c5ff_0  
gtk3                      3.24.21              h1c650a6_2  
h5py                      3.1.0            py39ha894db9_0  
harfbuzz                  2.8.0                h905054b_0  
hdf5                      1.12.0               h702ddfa_1  
heapdict                  1.0.1              pyhd3eb1b0_0  
hicolor-icon-theme        0.17                 hd43f75c_2  
html5lib                  1.1                pyhd3eb1b0_0  
icu                       68.1                 h7c1a80f_0  
idna                      3.2                pyhd3eb1b0_0  
imagecodecs               2021.8.26        py39h586b9b7_0  
imageio                   2.9.0              pyhd3eb1b0_0  
imagesize                 1.2.0              pyhd3eb1b0_0  
importlib-metadata        4.8.1            py39hd43f75c_0  
importlib_metadata        4.8.1                hd3eb1b0_0  
inflection                0.5.1            py39hd43f75c_0  
iniconfig                 1.1.1              pyhd3eb1b0_0  
intervaltree              3.1.0              pyhd3eb1b0_0  
ipykernel                 6.4.1            py39hd43f75c_1  
ipython                   7.29.0           py39hf83f34d_0  
ipython_genutils          0.2.0              pyhd3eb1b0_1  
ipywidgets                7.6.5              pyhd3eb1b0_1  
isort                     5.9.3              pyhd3eb1b0_0  
itsdangerous              2.0.1              pyhd3eb1b0_0  
jbig                      2.1                  hfd63f10_0  
jdcal                     1.4.1              pyhd3eb1b0_0  
jedi                      0.18.0           py39hd43f75c_1  
jeepney                   0.7.1              pyhd3eb1b0_0  
jinja2                    2.11.3             pyhd3eb1b0_0  
jinja2-time               0.2.0              pyhd3eb1b0_2  
joblib                    1.1.0              pyhd3eb1b0_0  
jpeg                      9d                   h2f4d8fa_0  
json5                     0.9.6              pyhd3eb1b0_0  
jsonschema                3.2.0              pyhd3eb1b0_2  
jupyter                   1.0.0            py39hd43f75c_7  
jupyter_client            6.1.12             pyhd3eb1b0_0  
jupyter_console           6.4.0              pyhd3eb1b0_0  
jupyter_core              4.8.1            py39hd43f75c_0  
jupyter_server            1.4.1            py39hd43f75c_0  
jupyterlab                3.2.1              pyhd3eb1b0_1  
jupyterlab_pygments       0.1.2                      py_0  
jupyterlab_server         2.8.2              pyhd3eb1b0_0  
jupyterlab_widgets        1.0.0              pyhd3eb1b0_1  
jxrlib                    1.1                  hfd63f10_2  
keyring                   22.3.0           py39hd43f75c_0  
kiwisolver                1.3.1            py39h7c1a80f_0  
krb5                      1.19.2               h9f0e0cd_0  
lazy-object-proxy         1.6.0            py39hfd63f10_0  
lcms2                     2.12                 h5246980_0  
ld_impl_linux-aarch64     2.36.1               h0ab8de2_3  
lerc                      3.0                  h22f4aa5_0  
libaec                    1.0.4                h7c1a80f_1  
libarchive                3.4.2                hbc894fb_0  
libcups                   2.2.12               h549d06d_1  
libcurl                   7.71.1               h48584d0_1  
libdeflate                1.7                  hfd63f10_5  
libedit                   3.1.20210910         h2f4d8fa_0  
libev                     4.33                 hfd63f10_1  
libevent                  2.1.10               hcd09bdd_2  
libffi                    3.3                  h7c1a80f_2  
libgcc-ng                 10.2.0              h1234567_51  
libgfortran-ng            10.2.0              h9534d94_51  
libgfortran5              10.2.0              h1234567_51  
libgomp                   10.2.0              h1234567_51  
liblief                   0.10.1               h7c1a80f_1  
libllvm11                 11.1.0               h6c8bc22_0  
libopenblas               0.3.13               hf4835c0_1  
libpng                    1.6.37               h8ea0f78_0  
libpq                     12.2                 h2007d8e_0  
librsvg                   2.50.7               h7ed7576_0  
libsodium                 1.0.18               hfd63f10_0  
libspatialindex           1.9.3                h7c1a80f_0  
libssh2                   1.9.0                hcd09bdd_1  
libstdcxx-ng              10.2.0              h1234567_51  
libtiff                   4.2.0                he67034a_0  
libtool                   2.4.6             h7c1a80f_1007  
libuuid                   1.0.3                hfd63f10_2  
libuv                     1.40.0               hfd63f10_0  
libwebp                   1.2.0                h5bb14bb_0  
libwebp-base              1.2.0                h4e544f5_0  
libxcb                    1.14                 hfd63f10_0  
libxkbcommon              1.0.1                h1897131_0  
libxml2                   2.9.12               he30c317_0  
libxslt                   1.1.34               hececbcc_0  
libzopfli                 1.0.3                h7c1a80f_0  
llvmlite                  0.37.0           py39h22f4aa5_0  
locket                    0.2.1            py39hd43f75c_1  
lxml                      4.6.3            py39h8430397_0  
lz4-c                     1.9.3                h7c1a80f_0  
lzo                       2.10                 hfd63f10_4  
markupsafe                1.1.1            py39hfd63f10_0  
matplotlib                3.4.3            py39hd43f75c_0  
matplotlib-base           3.4.3            py39h78f1600_0  
matplotlib-inline         0.1.2              pyhd3eb1b0_2  
mccabe                    0.6.1            py39hd43f75c_1  
mistune                   0.8.4           py39hfd63f10_1000  
mock                      4.0.3              pyhd3eb1b0_0  
more-itertools            8.10.0             pyhd3eb1b0_0  
mpc                       1.1.0                h3d095b0_1  
mpfr                      4.0.2                h51dc842_1  
mpmath                    1.2.1            py39hd43f75c_0  
msgpack-python            1.0.2            py39h949e957_1  
multipledispatch          0.6.0            py39hd43f75c_0  
munkres                   1.1.4                      py_0  
mypy_extensions           0.4.1            py39hd43f75c_0  
navigator-updater         0.2.1                    py39_0  
nbclassic                 0.2.6              pyhd3eb1b0_0  
nbclient                  0.5.3              pyhd3eb1b0_0  
nbconvert                 6.1.0            py39hd43f75c_0  
nbformat                  5.1.3              pyhd3eb1b0_0  
ncurses                   6.3                  h2f4d8fa_1  
nest-asyncio              1.5.1              pyhd3eb1b0_0  
networkx                  2.6.3              pyhd3eb1b0_0  
ninja                     1.10.2           py39h949e957_0  
nltk                      3.6.5              pyhd3eb1b0_0  
nomkl                     3.0                           0  
nose                      1.3.7           pyhd3eb1b0_1006  
notebook                  6.4.5            py39hd43f75c_0  
numba                     0.54.1           py39h839d321_0  
numexpr                   2.7.3            py39hfbfe6b9_0  
numpy                     1.20.3           py39h6fc94f6_0  
numpy-base                1.20.3           py39h6ba5a95_0  
numpydoc                  1.1.0              pyhd3eb1b0_1  
olefile                   0.46               pyhd3eb1b0_0  
openblas                  0.3.13               hd43f75c_1  
openblas-devel            0.3.13               hd43f75c_1  
openjpeg                  2.4.0                hf3eb033_0  
openpyxl                  3.0.9              pyhd3eb1b0_0  
openssl                   1.1.1l               h2f4d8fa_0  
packaging                 21.0               pyhd3eb1b0_0  
pandas                    1.3.4            py39h337a648_0  
pandocfilters             1.4.3            py39hd43f75c_1  
pango                     1.45.3               hef97164_0  
parso                     0.8.2              pyhd3eb1b0_0  
partd                     1.2.0              pyhd3eb1b0_0  
patchelf                  0.13                 h22f4aa5_0  
path                      16.0.0             pyhd3eb1b0_0  
path.py                   12.5.0               hd3eb1b0_0  
pathlib2                  2.3.6            py39hd43f75c_2  
pathspec                  0.7.0                      py_0  
patsy                     0.5.2            py39hd43f75c_0  
pcre                      8.45                 h22f4aa5_0  
pep8                      1.7.1            py39hd43f75c_0  
pexpect                   4.8.0              pyhd3eb1b0_3  
pickleshare               0.7.5           pyhd3eb1b0_1003  
pillow                    8.4.0            py39hc5d9b3f_0  
pip                       21.2.4           py39hd43f75c_0  
pixman                    0.40.0               h2f4d8fa_1  
pkginfo                   1.7.1            py39hd43f75c_0  
pluggy                    0.13.1           py39hd43f75c_0  
ply                       3.11             py39hd43f75c_0  
poyo                      0.5.0              pyhd3eb1b0_0  
prometheus_client         0.11.0             pyhd3eb1b0_0  
prompt-toolkit            3.0.20             pyhd3eb1b0_0  
prompt_toolkit            3.0.20               hd3eb1b0_0  
psutil                    5.8.0            py39hfd63f10_1  
ptyprocess                0.7.0              pyhd3eb1b0_2  
py                        1.10.0             pyhd3eb1b0_0  
py-lief                   0.10.1           py39h7c1a80f_1  
pycodestyle               2.7.0              pyhd3eb1b0_0  
pycosat                   0.6.3            py39hfd63f10_2  
pycparser                 2.20                       py_2  
pycurl                    7.44.1           py39ha9ffb65_1  
pydocstyle                6.1.1              pyhd3eb1b0_0  
pyerfa                    2.0.0            py39h2f4d8fa_0  
pyflakes                  2.3.1              pyhd3eb1b0_0  
pygments                  2.10.0             pyhd3eb1b0_0  
pyjwt                     2.1.0            py39hd43f75c_0  
pylint                    2.7.4            py39hd43f75c_1  
pyls-spyder               0.4.0              pyhd3eb1b0_0  
pyodbc                    4.0.30           py39h7c1a80f_0  
pyopenssl                 21.0.0             pyhd3eb1b0_1  
pyparsing                 3.0.4              pyhd3eb1b0_0  
pyqt                      5.15.2           py39h22f4aa5_0  
pyqt5-sip                 4.19.25                  pypi_0    pypi
pyqtchart                 5.15.2                   pypi_0    pypi
pyqtwebengine             5.15.2                   pypi_0    pypi
pyrsistent                0.18.0           py39h2f4d8fa_0  
pysocks                   1.7.1            py39hd43f75c_0  
pytables                  3.6.1            py39he7eab4e_1  
pytest                    6.2.3            py39hd43f75c_2  
python                    3.9.7                hc137634_1  
python-dateutil           2.8.2              pyhd3eb1b0_0  
python-libarchive-c       2.9                pyhd3eb1b0_1  
python-lsp-black          1.0.0              pyhd3eb1b0_0  
python-lsp-jsonrpc        1.0.0              pyhd3eb1b0_0  
python-lsp-server         1.2.4              pyhd3eb1b0_0  
python-slugify            5.0.2              pyhd3eb1b0_0  
pytz                      2021.3             pyhd3eb1b0_0  
pywavelets                1.1.1            py39hfd0a847_4  
pyxdg                     0.27               pyhd3eb1b0_0  
pyyaml                    5.4.1            py39hfd63f10_2  
pyzmq                     20.0.0           py39h7c1a80f_1  
qdarkstyle                3.0.2              pyhd3eb1b0_0  
qstylizer                 0.1.10             pyhd3eb1b0_0  
qt                        5.15.2               h4236ef2_3  
qtawesome                 1.0.2              pyhd3eb1b0_0  
qtconsole                 5.1.1              pyhd3eb1b0_0  
qtpy                      1.10.0             pyhd3eb1b0_0  
readline                  8.1                  hfd63f10_0  
regex                     2021.8.3         py39h2f4d8fa_0  
requests                  2.26.0             pyhd3eb1b0_0  
rope                      0.19.0             pyhd3eb1b0_0  
rtree                     0.9.7            py39hd43f75c_1  
ruamel_yaml               0.15.80          py39hfd63f10_0  
scikit-image              0.18.3           py39h839d321_0  
scikit-learn              0.24.2           py39h839d321_1  
scipy                     1.7.1            py39ha4eada7_2  
seaborn                   0.11.2             pyhd3eb1b0_0  
secretstorage             3.3.1            py39hd43f75c_0  
send2trash                1.8.0              pyhd3eb1b0_1  
setuptools                58.0.4           py39hd43f75c_0  
simplegeneric             0.8.1            py39hd43f75c_2  
singledispatch            3.7.0           pyhd3eb1b0_1001  
sip                       4.19.25          py39h7c1a80f_0  
six                       1.16.0             pyhd3eb1b0_0  
snappy                    1.1.8                h7c1a80f_0  
sniffio                   1.2.0            py39hd43f75c_1  
snowballstemmer           2.1.0              pyhd3eb1b0_0  
sortedcollections         2.1.0              pyhd3eb1b0_0  
sortedcontainers          2.4.0              pyhd3eb1b0_0  
soupsieve                 2.2.1              pyhd3eb1b0_0  
sphinx                    4.2.0              pyhd3eb1b0_1  
sphinxcontrib             1.0              py39hd43f75c_1  
sphinxcontrib-applehelp   1.0.2              pyhd3eb1b0_0  
sphinxcontrib-devhelp     1.0.2              pyhd3eb1b0_0  
sphinxcontrib-htmlhelp    2.0.0              pyhd3eb1b0_0  
sphinxcontrib-jsmath      1.0.1              pyhd3eb1b0_0  
sphinxcontrib-qthelp      1.0.3              pyhd3eb1b0_0  
sphinxcontrib-serializinghtml 1.1.5              pyhd3eb1b0_0  
sphinxcontrib-websupport  1.2.4                      py_0  
spyder                    5.1.5            py39hd43f75c_0  
spyder-kernels            2.1.3            py39hd43f75c_0  
sqlalchemy                1.3.23           py39hfd63f10_0  
sqlite                    3.36.0               h6632b73_0  
statsmodels               0.13.0           py39h2f4d8fa_0  
sympy                     1.9              py39hd43f75c_0  
tbb                       2021.4.0             h59a28a9_0  
tbb4py                    2021.4.0         py39h59a28a9_0  
tblib                     1.7.0              pyhd3eb1b0_0  
terminado                 0.9.4            py39hd43f75c_0  
testpath                  0.5.0              pyhd3eb1b0_0  
text-unidecode            1.3                pyhd3eb1b0_0  
textdistance              4.2.1              pyhd3eb1b0_0  
threadpoolctl             2.2.0              pyh0d69192_0  
three-merge               0.1.1              pyhd3eb1b0_0  
tifffile                  2021.7.2           pyhd3eb1b0_2  
tinycss                   0.4             pyhd3eb1b0_1002  
tk                        8.6.11               h241ca14_0  
toml                      0.10.2             pyhd3eb1b0_0  
toolz                     0.11.1             pyhd3eb1b0_0  
tornado                   6.1              py39hfd63f10_0  
tqdm                      4.62.3             pyhd3eb1b0_1  
traitlets                 5.1.0              pyhd3eb1b0_0  
typed-ast                 1.4.3            py39h2f4d8fa_1  
typing_extensions         3.10.0.2           pyh06a4308_0  
tzdata                    2021e                hda174b7_0  
ujson                     4.0.2            py39h7c1a80f_0  
unicodecsv                0.14.1           py39hd43f75c_0  
unidecode                 1.2.0              pyhd3eb1b0_0  
unixodbc                  2.3.9                hfd63f10_0  
urllib3                   1.26.7             pyhd3eb1b0_0  
watchdog                  1.0.2            py39hd43f75c_1  
wcwidth                   0.2.5              pyhd3eb1b0_0  
webencodings              0.5.1            py39hd43f75c_1  
werkzeug                  2.0.2              pyhd3eb1b0_0  
wheel                     0.37.0             pyhd3eb1b0_1  
whichcraft                0.6.1              pyhd3eb1b0_0  
widgetsnbextension        3.5.1            py39hd43f75c_0  
wrapt                     1.12.1           py39hfd63f10_1  
wurlitzer                 2.0.1            py39hd43f75c_0  
xlrd                      2.0.1              pyhd3eb1b0_0  
xlsxwriter                3.0.1              pyhd3eb1b0_0  
xlwt                      1.3.0            py39hd43f75c_0  
xmltodict                 0.12.0             pyhd3eb1b0_0  
xz                        5.2.5                hfd63f10_1  
yaml                      0.1.7                hfd63f10_4  
yapf                      0.31.0             pyhd3eb1b0_0  
zeromq                    4.3.4                h7c1a80f_0  
zict                      2.0.0              pyhd3eb1b0_0  
zipp                      3.6.0              pyhd3eb1b0_0  
zlib                      1.2.11               hfd63f10_5  
zope                      1.0              py39hd43f75c_1  
zope.event                4.5.0            py39hd43f75c_0  
zope.interface            5.4.0            py39h2f4d8fa_0  
zstd                      1.4.9                h20642d3_2 


  • conda create --name(-n) <package name> python=3.x : Create an anaconda virtual environment with "package name" and install python 3.x. If possible, it is recommended to set a naming convention for the package name so that the installed version of Python and its important purpose are known. The virtual environment name created in this way can be changed later if necessary.

  • conda activate package name : Enter the virtual environment of the package name. 


Changed Python Environment

The following are Python commands and versions without anaconda environment applied.

root@spypiggy-desktop:~# python
Python 2.7.17 (default, Feb 27 2021, 15:10:58) 
[GCC 7.5.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.

 
root@spypiggy-desktop:~# python3
Python 3.6.9 (default, Jan 26 2021, 15:33:00) 
[GCC 8.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.

JetPack 4.6 uses Python 2.7 and 3.6.

However, in the anaconda environment, the default Python is changed to 3.9. Of course, this version can use the new Python version while creating a new anaconda virtual environment.


When the anaconda environment variable is applied, both python and python3 commands run Python 3.9.

spypiggy@spypiggy-desktop:~$ python
Python 3.9.7 (default, Sep 16 2021, 16:31:42) 
[GCC 10.2.0] :: Anaconda, Inc. on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> 
spypiggy@spypiggy-desktop:~$ python3
Python 3.9.7 (default, Sep 16 2021, 16:31:42) 
[GCC 10.2.0] :: Anaconda, Inc. on linux
Type "help", "copyright", "credits" or "license" for more information.

But this version of Python doesn't mean much. This is because we will use a new version of Python by creating a new anaconda virtual environment.


Creating a new conda virtual environment

JetPack 4.6 comes with Python 3.6 installed as we saw earlier. And Anaconda installs Python 3.9 by default. I'm going to create a virtual environment using Python 3.8. 


spypiggy@spypiggy-desktop:~$ conda create -n py_38 python=3.8.12  
Collecting package metadata (current_repodata.json): done
Solving environment: done

## Package Plan ##

  environment location: /home/spypiggy/anaconda3/envs/py_38

  added / updated specs:
    - python=3.8.12


The following packages will be downloaded:

    package                    |            build
    ---------------------------|-----------------
    certifi-2021.10.8          |   py38hd43f75c_2         143 KB
    pip-21.2.4                 |   py38hd43f75c_0         1.8 MB
    python-3.8.12              |       hc137634_0         9.6 MB
    setuptools-58.0.4          |   py38hd43f75c_0         763 KB
    sqlite-3.37.2              |       h6632b73_0         1.3 MB
    ------------------------------------------------------------
                                           Total:        13.5 MB

The following NEW packages will be INSTALLED:

  _libgcc_mutex      pkgs/main/linux-aarch64::_libgcc_mutex-0.1-main
  _openmp_mutex      pkgs/main/linux-aarch64::_openmp_mutex-5.1-51_gnu
  ca-certificates    pkgs/main/linux-aarch64::ca-certificates-2021.10.26-hd43f75c_2
  certifi            pkgs/main/linux-aarch64::certifi-2021.10.8-py38hd43f75c_2
  ld_impl_linux-aar~ pkgs/main/linux-aarch64::ld_impl_linux-aarch64-2.36.1-h0ab8de2_3
  libffi             pkgs/main/linux-aarch64::libffi-3.3-h7c1a80f_2
  libgcc-ng          pkgs/main/linux-aarch64::libgcc-ng-10.2.0-h1234567_51
  libgomp            pkgs/main/linux-aarch64::libgomp-10.2.0-h1234567_51
  libstdcxx-ng       pkgs/main/linux-aarch64::libstdcxx-ng-10.2.0-h1234567_51
  ncurses            pkgs/main/linux-aarch64::ncurses-6.3-h2f4d8fa_2
  openssl            pkgs/main/linux-aarch64::openssl-1.1.1m-h2f4d8fa_0
  pip                pkgs/main/linux-aarch64::pip-21.2.4-py38hd43f75c_0
  python             pkgs/main/linux-aarch64::python-3.8.12-hc137634_0
  readline           pkgs/main/linux-aarch64::readline-8.1.2-h2f4d8fa_1
  setuptools         pkgs/main/linux-aarch64::setuptools-58.0.4-py38hd43f75c_0
  sqlite             pkgs/main/linux-aarch64::sqlite-3.37.2-h6632b73_0
  tk                 pkgs/main/linux-aarch64::tk-8.6.11-h241ca14_0
  wheel              pkgs/main/noarch::wheel-0.37.1-pyhd3eb1b0_0
  xz                 pkgs/main/linux-aarch64::xz-5.2.5-hfd63f10_1
  zlib               pkgs/main/linux-aarch64::zlib-1.2.11-hfd63f10_5


Proceed ([y]/n)? y


Downloading and Extracting Packages
pip-21.2.4           | 1.8 MB    | ##################################################################################################### | 100% 
sqlite-3.37.2        | 1.3 MB    | ##################################################################################################### | 100% 
certifi-2021.10.8    | 143 KB    | ##################################################################################################### | 100% 
setuptools-58.0.4    | 763 KB    | ##################################################################################################### | 100% 
python-3.8.12        | 9.6 MB    | ##################################################################################################### | 100% 
Preparing transaction: done
Verifying transaction: done
Executing transaction: done
#
# To activate this environment, use
#
#     $ conda activate py_38
#
# To deactivate an active environment, use
#
#     $ conda deactivate

You can see that packages such as pip and sqlite are installed together with Python 3.8.12. Packages included in Anaconda can be added with the conda install command, and packages not included can be added with the pip install command.

You can check the newly created anaconda virtual environment with the conda env list command.

spypiggy@spypiggy-desktop:~$ conda env list
# conda environments:
#
base                  *  /home/spypiggy/anaconda3
py_38                    /home/spypiggy/anaconda3/envs/py_38


Wrapping Up

Machine learning packages each require their own version of Python and packages. When multiple packages are run on one Xavier NX, package version problems inevitably occur. The best way to solve this problem is to use anaconda (anaconda). Anaconda has the advantage of specifying the Python version at the time of creating a virtual environment, so various Python versions can be run on a single host. In the next article, we will install various TensorFlow and PyTorch in the Anaconda environment.



Effective Jetson Xavier NX Setup - SSD Booting

 Let's see how to install JetPack 4.6 on Jetson xavier nx and use it effectively.

Jetson Nano uses SD card. Therefore, multiple SD card images can be prepared and used. For example, an SD card for Tensorflow and an SD card for PyTorch are prepared separately and used while replacing the SD card as needed.

Xavier NX allows additional SSD installation. SSDs are much faster and more stable than SD cards. Therefore, it is better to install various software using an SSD rather than using multiple SD cards.  

Jetson Xavier NX -Run from SSD

To use SSDs with Xavier NX, you need a standalone x86 Ubuntu server.

The documentation says that Ubuntu 18.04 and 16.04 are available, but as a result of my testing, it failed in 18.04. Please prepare one x86 PC with Ubuntu 16.04 installed. If you have used Jetxon TX2 or AGX Xavier, you probably have experience installing and using NVidia SDK Manager on an x86 PC.

However, SDK manager is not used in this work. We will directly transfer the JetPack 4.6 image to Xavier NX using a bash script.

I know that NVidia is working on integrating this SSD bootable method into SDK Manager. Maybe JetPack 4.7 will use the SDK Manager.

And since booting from the SSD drive proceeds, there is no need to use the SD card anymore.

The following content is taken from the JetsonHacks homepage. Thanks to JetsonHacks for the nice introduction.

<JetsonHack's Youube>


SSD Installation

Be sure to prepare an M.2 NVMe type SSD. I prepared a 128GB Samsung SSD, but it would be better if I prepared a larger size SSD. How to install the SSD is detailed in the video above.


Install SW on the Host

Install the software required for the host first. Since JetsonHacks has made the necessary scripts for the job well, I will clone the git he made and use it.


$ git clone https://github.com/jetsonhacks/bootFromExternalStorage.git

$ cd bootFromExternalStorage

$ ./install_dependencies.sh

$ ./get_jetson_files.sh

It may takes several minutes.


Xavier NX Recovery Mode

After installing the SSD, set Xavier NX to Force Recovery mode. To set the Force Recovery Mode, connect pins 9 and 10 among the pins below the SD card slot. In the picture below, a jumper is used, but you can use a breadboard female cable. It is well explained in the video above.

<recovery mode jumper connection from https://www.stereolabs.com/blog/getting-started-with-jetson-xavier-nx/>


USB Connection

Now connect Xavier NX to the x86 host computer.

<USB Connection> 


Bootup the Xavier NX

Connect the power of Xavier NX in force recovery mode. Xavier NX will show a green light. And check the connection status on the host computer as follows. You can check the Xavier NX connected to the USB port with the lsusb command. If it is not confirmed, there is a high possibility that the Force Recovery Mode jumper connection is wrong or the USB cable is bad.


Flashing the Xavier NX

Now run the last script to install the Jetpack 4.6 image to the Xavier NX's SSD.

 ./flash_jetson_external_storage.sh

Running the script will search for connected Xavier NX. And it asks to cancel the Force Recovery mode. You can then remove the jumper cable and continue. 

This work takes about ten minutes. Once this has been done successfully, the host computer is no longer needed.

Then, connect the mouse, keyboard, monitor, and LAN cable to Xavier NX and boot it. Now the last task remains.  This must be done in Xavier NX.

$ git clone https://github.com/jetsonhacks/bootFromExternalStorage.git

$ cd bootFromExternalStorage

./install_jetson_default_packages.sh

     

Wrapping UP

Now reboot Xavier NX and proceed with initial setup. Note that the current Xavier NX does not have an SD card, only an SSD. If the capacity seems to be low due to the unallocated partition on the ssd, install the gparted program to extend the partition.

Now you can use Xavier NX much faster and more reliably than when using an SD card.

I highly recommend reading JetsonHack's blog post as well.

Today we learned how to install an SSD in Xavier NX to get the best hardware performance. In the next article, we will learn how to efficiently use Python, OpenCV, TensorFlow, and PyTorch.






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.