Compilando Tensorflow 2 para Raspberry Pi

Actualizado el 31 de Octubre de 2020

Introducción

Raspberry instala por defecto TensorFlow 1.x, existen varias opciones para instalar TensorFlow 2, una de ellas es acceder a la página de TensorFlow y descargarse la versión 2 para Python 3.5, en la parte inferior veremos el enlace actualmente con esta dirección:

https://storage.googleapis.com/tensorflow/raspberrypi/tensorflow-2.3.0-cp35-none-linux_armv6l.whl
https://storage.googleapis.com/tensorflow/raspberrypi/tensorflow-2.3.0-cp35-none-linux_armv7l.whl

Ambos paquetes instalarán tensorflow 2.3 para una versión de Python 3.5 el primero para una Raspberry 0 o 1 (arquitectura ARMv6) y el segundo para una Raspberry 2 o 3 (ARMv7).

Puede ser que junto con TensorFlow 2 queramos usar una versión de Python superior (actualmente está disponible la 3.7) en ese caso la mejor opción será crear la versión desde el propio código fuente. Este proceso se puede realizar desde la propia Raspberry pero el proceso es bastante largo debido a las limitaciones de la Raspberry así que vamos a apoyarnos en otra máquina (escritorio, portátil,…) para agilizar el proceso y también tenerlo preparado para futuras versiones.

El proceso se puede realizar de varias formas, en este caso nos apoyaremos en Windows Linux Subsytem.

Windows Linux Subsystem

Lo primero será instalar Windows Linux Subsystem, siguiendo los pasos que se dan en la página se puede preparar Windows 10 para ejecutar Linux sin problemas. Vamos a elegir como distribución a instalar Ubuntu 20.04 LTS.

Una vez arrancado y creado un usuario Linux seguimos los siguientes pasos:

Descargar el código fuente

El código fuente de TensorFlow lo podemos descargar de su repositorio oficial, vamos a trabajar con las ramas release en concreto para este caso la 2.4 que es la última disponible:

git clone https://github.com/tensorflow/tensorflow.git
git checkout r2.4

Compilación del código

TensorFlow 2 se compila a través de Docker, si estamos usando Windows 10 podemos habilitar la integración con WSL, la información completa esta aquí, pero con los siguientes pasos podemos verificar rápidamente si todo está correcto.

  1. Dentro de Settings -> General
    Habilitar Use the WSL 2 based engine (habilitado por defecto). Apply & restart.
  2. Verificar que WSL se está ejecutando en modo 2, ejecutamos este comando en una línea de comandos (cmd): wsl -l -v
    Tenemos que ver que la versión es la 2.
  3. En Settings -> Resources -> WSL Integration habilitamos Enable integration with my default WSL distro y marcamos todas las imágenes en las que queramos habilitar WSL 2. Después Apply & restart.
    Sino vemos la opción de WSL Integration es que estamos ejecutando Docker con contenedores Windows, tenemos que usar contenedores Linux esta opción la tenemos en el menú contextual de Docker Switch to Linux containers.

Ahora nos movemos a la carpeta donde lanzaremos la compilación, que típicamente estará en tensorflow/tensorflow/tools/ci_build (hay dos carpetas tensorflow, la de descarga del código y otra propia del repositorio).

En este caso tenemos que cambiar un par de detalles en el archivo Dockerfile.pi-python37 tenemos que quitar las librerías de Python 2.7, esto hará que no sea compatible con Python 2.7 pero no es un problema ya que Python 2 está en desuso y además la compilación será más rápida, también asociaremos la versión de Python de la imagen Docker con la 3.7, normalmente se hace con update-alternatives pero en este caso lo vamos a simplificar modificando el enlace simbólico.

El siguiente código lo vamos a colocar justo después de la instalación de Python.

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

# Code to remove Python 2.7 and update symbolic link
RUN ln -sf /usr/bin/python3.7 /usr/bin/python
RUN apt-get remove -y libpython2.7-dev

RUN /install/install_bazel.sh
...

Ahora lanzamos este comando y comenzará la compilación, este comando (ci_build.sh) acepta dos parámetros.

  • El primero sirve para indicar en que maquina Docker se ejecutará (PI-PYTHON37), hay otros valores para compilar para otras máquinas Raspberry, si se quiere compilar para todas se puede usar el parámetro PI_ONE.
  • El segundo parámetro (build_raspberry_pi.sh) indica el comando que se ejecutará dentro de la máquina virtual.
./ci_build.sh PI-PYTHON37 \
    tensorflow/tools/ci_build/pi/build_raspberry_pi.sh

Durante la compilación nos irá sacando información del proceso, el tiempo que tarda depende de la máquina en particular, en este caso concreto en una máquina i7-6700K@4Ghz con 16GB RAM y en un disco SSD tarda alrededor de 30′-45′.

El resultado de la compilación lo tendréis en la carpeta tensorflow/output-artifacts y el paquete a instalar tendrá este nombre:
tensorflow-2.4.0rc0-cp37-none-linux_armv7l.whl

Vemos que hemos compilado una release candidate #0 de la versión 2.4 (2.4.0rc0) para una versión de Python 3.7 (cp37) y una arquitectura ARMv7 (armv7l) el none simplemente indica que no está compilado pensando en optimizaciones para GPU (Raspberry no soporta CUDA) o versiones especiales de Python (las versiones m).

Si tarda más de 60′ es posible que el proceso no termine, en ese caso la mejor opción es detener el proceso (Ctrl+Z) buscar el trabajo parado y coger el id (jobs -l) y matar el proceso (kill -9 #id).

Después de esto probamos a volver a lanzar el comando pero antes es muy recomendable reiniciar Docker, volver a abrir la máquina Ubuntu y hacer una limpieza de ficheros con git clean -fxd desde el raíz del repositorio.

Instalación

Ahora solo tenemos que copiar el fichero a la Raspberry, la forma más cómoda posiblemente sea usando el comando scp, por ejemplo:

scp tensorflow-2.4.0rc0-cp37-none-linux_armv7l.whl pi@192.168.1.5:/home/pi

En este ejemplo estamos copiando el fichero a una máquina remota 192.168.1.5 en la carpeta /home/pi y para acceder a esa máquina usamos el usuario pi, al conectar nos pedirá contraseña.

Una vez en la máquina Raspberry nos movemos a la carpeta donde hayamos copiado el fichero (/home/pi) primero vamos a actualizar pip, después actualizaremos setuptools y finalmente instalaremos el paquete TensorFlow 2:

sudo python3 -m pip install --upgrade pip
sudo pip3 install --upgrade setuptools
sudo pip3 install tensorflow-2.4.0rc0-cp37-none-linux_armv7l.whl

También hace falta tener instalado la librería ATLAS

sudo apt-get install libatlas-base-dev

La instalación tarda un poco pero nos irá información del proceso, al terminar para verificar que está bien instalado podemos usar:

sudo python3 -c 'import tensorflow as tf; print(tf.__version__)'

Y deberíamos ver…


2.4.0-rc0

Bonus

Es posible también coger paquetes precompilados desde varios orígenes de terceros y evitar tener que hacer este proceso, pero al no ser repositorios oficiales no se puede asegurar el funcionamiento del mismo.

Otra opción sería usar TensorFlow lite una versión más apropiada para dispositivos de menores prestaciones.

Problemas

Durante el desarrollo de este artículo me he encontrado varios problemas, los enumero aquí para la posteridad (muchos de ellos relacionados con la rama master).

Cannot add PPA: ‘ppa:~openjdk-r/ubuntu/ppa’.
ERROR: ‘~openjdk-r’ user or team does not exist.
Es un problema de certificados, ejecutamos:

sudo apt-get install --reinstall ca-certificates

wget: unable to resolve host address ‘xxx’
Es un problema con los DNS, se puede editar el fichero resolv.conf (sudo nano /etc/resolv.conf) y añadir la siguiente línea para configurar el DNS de Google.

nameserver 8.8.8.8

sudo: pip3: command not found
Hay que instalar el gestor de paquetes de Python pip, en este caso estamos obligados a modificar la imagen de TensorFlow, en el fichero DockerFile que corresponda (en este caso Dockerfile.pi-python37) añadimos esta línea encima de la línea que haya fallado, por ejemplo en este caso ha fallado la instalación del paquete auditwheel

...
RUN /install/install_buildifier.sh
RUN apt install -y python3-pip
RUN pip install --upgrade pip
RUN /install/install_auditwheel.sh
...

ERROR: An error occurred during the fetch of repository ‘local_config_python’:
…
Problem getting numpy include path.
…
ModuleNotFoundError: No module named ‘numpy’

Hay que hacer dos cosas, por un lado es un problema con la versión de Python, por defecto la versión de Python es la 3.5 cuando tendría que ser la 3.7 y además también hay que instalar numpy

Referencias

https://github.com/tensorflow/tensorflow/issues/26947
http://www.itworkman.com/97618.html
https://devblogs.microsoft.com/commandline/a-guide-to-invoking-wsl/
https://github.com/tensorflow/tensorflow/issues/39340

Compilando Tensorflow 2 para Raspberry Pi