En este post trata sobre la compilación de TensorFlow. Aunque existe documentación oficial detallada para realizarla aquí resumo el proceso. El documento original en está en Compila con el código fuente
¿Por qué es necesario compilarlo?. La respuesta es sencilla, la versión pre-compilada no siempre funciona debido a la CPU sobre la que se ejecute. En mi caso, no dispone de soporte para instrucciones AVX. Esto se detecta rápidamente al obtener el mensaje: Instrucción Ilegal al intentar importar la librería tensorflow. Basta con ejecutar ese código para ver si necesitas una versión diferente, si aparece el error necesitas compilarlo:
python3 -m pip install tensorflow
python3 -c "import tensorflow"
Antes de empezar incluyo algunas versiones ya compiladas por si son de utilidad ya que la compilación es lenta. También se incluye una versión para RaspberryPi, aunque la compilación para esta plataforma es un poco diferente y por ello, está detallada en la última sección.
Arquitectura | Version | Fichero |
---|---|---|
x86-64 | v1.13.2 | tensorflow-1.13.2-cp37-cp37m-linux_x86_64.whl |
x86-64 | v1.15.2 | tensorflow-1.15.0-cp37-cp37m-linux_x86_64.whl |
x86-64 | v2.4.1 | tensorflow-2.4.1-cp38-cp38-linux_x86_64.whl |
ARM64 | v2.4.1 | tensorflow-2.4.1-cp37-cp37m-linux_aarch64.whl |
x86-64 | v2.8.0 | tensorflow-2.8.0-cp39-cp39-linux_x86_64.whl |
ARM64 | v2.8.0 | tensorflow-2.8.0-cp39-cp39-linux_aarch64.whl |
Antes compilar considera los siguientes tiempos de ejecución:
- Intel(R) Celeron(R) CPU N3150 1.60GHz, tiempo: ~16 horas
- Raspberry Pi 4 Model B Rev 1.4: ~30 horas
Instrucciones generales
Para la compilación de TensorFlow se utiliza una herramienta avanzada de compilación llamada Bazel que se ejecuta sobre Java, pero cada versión de TensorFlow está ligada a una versión/versiones determinadas de Bazel. Para conseguir una compilación se deben tener en consideración estos dos aspectos:
- Asegurarse de usar la versión correcta de Bazel
- Revisar incompatibilidades con algunas librerías python.
En todas las compilaciones he usado Debian 11 con el python3 de serie. En primer lugar, la versión de Bazel que viene con APT de Debian no sirve, por lo que se debe desinstalar con
apt remove bazel
A continuación muestro detalles de la compilación de las versiones 2.X y de la compilación para Raspberry Pi
Compilando versiones 2.x
Para poder cambiar rápidamente de versión de TensorFlow prefiero descargarlo con git muestro el ejemplo con la versión 2.8.0
git clone https://github.com/tensorflow/tensorflow
git checkout v2.8.0
Para compilar estas versiones se puede hacer con el python de serie de Debian 11 De nuevo el entorno de compilación es el python 3.9 que viene con la distribución. Los paquetes necesarios son:
apt install python3-dev python3-pip python3-wheel
Para compilarlo la mejor opción es crear un entorno virtual python aunque no es necesario. En las pruebas que he hecho funciona de las dos formas.
Tras esto debes ejecutar el python que desees para instalar las dependencias en el siguiente ejemplo se usa el python predeterminado de Debian:
python3 -m pip install numpy
python3 -m pip install keras_preprocessing --no-deps
Hay que instalar la versión adecuada de Bazel. En el caso de la versión 2.8 mediante grep BAZEL configure.py aparecen las siguientes versiones de Bazel:
_TF_MIN_BAZEL_VERSION = '4.2.1'
_TF_MAX_BAZEL_VERSION = '4.99.0'
La versión correcta para Debian está en Bazel Releases y se puede descargar e instalar directamente el paquete Debian (deb). En la última compilación que he hecho, uso la versión 4.2.2 de Bazel
Siguiendo las instrucciones oficiales se ejecuta ./configure y se ejecuta la compilación con:
./configure
bazel build //tensorflow/tools/pip_package:build_pip_package
Esta ejecución puede dar errores si no hay suficiente memoria disponible, se requiere mas de 8GB. Para hacerla con pocos recursos recomiendo ejecutar Bazel con de esta forma:
bazel build --config=monolithic --local_cpu_resources=1 --jobs=1 //tensorflow/tools/pip_package:build_pip_package
Si la compilación termina sin errores la compilación genera un ejecutable encargado de generar el paquete PIP. Para crear el ejecutable hay que ejecutar:
./bazel-bin/tensorflow/tools/pip_package/build_pip_package ~
Este proceso es más rápido, solo un par de minutos y el resultado queda en el directorio de la cuenta de usuario:
ls -lh $HOME
-rw-r--r-- 1 user user 170M mar 14 15:44 tensorflow-2.8.0-cp39-cp39-linux_x86_64.whl
El paquete puede ser instalado con PIP mediante:
python3 -m pip ./tensorflow-2.8.0-cp39-cp39-linux_x86_64.whl
Compilando en RaspberryPi 4
La compilación en esta plataforma es un poco diferente. El entorno usado es RaspiOS de 64 bits:
uname -a
Linux mcpi 5.10.103-v8+ #1529 SMP PREEMPT Tue Mar 8 12:26:46 GMT 2022 aarch64 GNU/Linux
En estas referencias están las fuentes originales con las que he conseguido realizar la compilación:
Para instalar Bazel en este caso he descargado el binario ejecutable para ARM desde bazel-4.2.2-linux-arm64 e instalándolo del siguiente modo:
sudo wget https://github.com/bazelbuild/bazel/releases/download/4.2.2/bazel-4.2.2-linux-arm64
sudo install -m 665 bazel-4.2.2-linux-arm64 /usr/local/bin/bazel
Ahora viene la peor parte, compilar TensorFlow dentro de la RaspberryPi. Tras varios intentos me aparecen errores relacionados con la librería h5py. Para que compile correctamente esa librería hay que añadir esta dependencia:
sudo apt-get install pkg-config libhdf5-dev git
También como usuario no root, o en el entorno virtual python, es recomendable actualizar PIP antes de comenzar el proceso de compilación:
python3 -m pip install pip --upgrade
Y otro problema que suele aparecer es que siguiendo los ejemplos enlazados anteriormente es que suele faltar memoria: Out of memory. Como no tengo prisa, una forma rápida de solucionarlo es limitar el paralelismo de la compilación a un único hilo de la siguiente forma:
bazel build --config=monolithic --local_cpu_resources=1 --jobs=1 //tensorflow/tools/pip_package:build_pip_package
Armado de paciencia y tras unas 30 horas ya se puede construir el paquete PIP
bazel-bin/tensorflow/tools/pip_package/build_pip_package $HOME
Si no quieres esperar las 30 horas en la tabla inicial he dejado algunas versiónes precompiladas.