Pri začínaní s TensorFlow knižnicou bindings pre NodeJS, napríklad inštaláciou:

npm i @tensorflow/tfjs-node

A následným importovaním v node module:

import * as tf from "@tensorflow/tfjs-node"

Možno vidieť nasledujúcu chybu:

This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN) to use the following CPU instructions in performance-critical operations:
 AVX2 FMA
To enable them in other operations, rebuild TensorFlow with the appropriate compiler flags.

Varovanie možno ignorovať v TypeScript pomocou:

import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'

Pri používaní JavaScriptu vyššie uvedené nefunguje, ale nasledujúci export funguje pre oba:

export TF_CPP_MIN_LOG_LEVEL=2

Každopádne, keďže ignorovanie chyby bez hlbšieho skúmania nie je to, čo tu zvyčajne robíme, pozrime sa na to, ako zostaviť TensorFlow so správnymi príznakmi kompilátora (správne riešenie).

Zostavenie TensorFlow zo zdrojového kódu #

Kroky sú zdokumentované v oficiálnom repozitári tfjs pod kotvou:

Optional: Build optimal TensorFlow from source

Na prvý pohľad vyzerá, že je to len niekoľko krokov, ale situácia je definitívne komplikovanejšia. Nebojte sa, tento návod by mal pomôcť.

Krok 1: Klonovanie oficiálneho repozitára TensorFlow #

Najprv získajte oficiálny repozitár TensorFlow. Je mimochodom dosť veľký:

git clone https://github.com/tensorflow/tensorflow
cd tensorflow

Pokyny v nasledujúcich krokoch sa všetky vykonávajú v tomto adresári, pokiaľ nie je uvedené inak.

Krok 2: Inštalácia bazel #

Čo je bazel? Jedna definícia, ktorú som našiel, je nasledujúca:

Correct, reproducible, and fast builds for everyone

No, existuje veľa nástrojov na zostavovanie a toto je jeden z nich. Skúsme:

sudo pacman -S bazel

Tým sa nainštaluje oficiálna verzia z repozitára community, v čase písania je to 4.2.0. Nainštaluje sa samozrejme, ale pre naše účely sa nezdá byť správnou voľbou, keďže pri pokuse o zostavenie TensorFlow sa objavujú nasledujúce chyby:

WARNING: current bazel installation is not a release version.
Make sure you are running at least bazel 3.7.2

Alebo podrobnejšia:

ERROR: The project you're trying to build requires Bazel 3.7.2 (specified in /home/peterbabic/throw/tensorflow/.bazelversion), but it wasn't found in /usr/bin.

Bazel binaries for all official releases can be downloaded from here:
  https://github.com/bazelbuild/bazel/releases

Please put the downloaded Bazel binary into this location:
  /usr/bin/bazel-3.7.2-linux-x86_64

V AUR sú dva balíčky presne označené verziou 3.7.2: bazel3 a bazel3-bin.

Prvý vyžadoval ručný import GPG kľúča cez:

gpg --keyserver keys.openpgp.org --recv-keys 3D5919B448457EE0

Druhý mi fungoval.

Pozor: vždy skontrolujte obsah AUR balíčkov pred ich inštaláciou!

Skontrolujte verziu bazel, len pre istotu:

bazel --version
# bazel 3.7.2

Nie som si istý, ako to v tejto chvíli spriechodniť s oficiálnou vydanou verziou.

Krok 3: Úprava nastavení Java #

Samotná inštalácia bazel nemusí byť dostačujúca, najmä ak je na zariadení prítomných viacero verzií Java. Moje malo nainštalovaný jdk-openjdk, ktorý v čase písania bol na verzii 17. Existuje viacero indícií, najzjavnejšia je táto možná chyba:

Extracting Bazel installation...
FATAL: Could not find system javabase. Ensure JAVA_HOME is set, or javac is on your PATH.

Kde by mohol sídliť javac? Je možné to zistiť:

pacman -F javac

Dostaneme niekoľko náznakov:

extra/bash-completion 2.11-1
    usr/share/bash-completion/completions/javac
extra/java-environment-common 3-3 [installed]
    usr/bin/javac
extra/jdk11-openjdk 11.0.10.u9-1 [installed: 11.0.13.u8-1]
    usr/lib/jvm/java-11-openjdk/bin/javac
extra/jdk7-openjdk 7.u261_2.6.22-1
    usr/lib/jvm/java-7-openjdk/bin/javac
extra/jdk8-openjdk 8.u282-1 [installed: 8.u292-1]
    usr/lib/jvm/java-8-openjdk/bin/javac
extra/jre-openjdk-headless 15.0.2.u7-1 [installed: 17.u35-1]
    usr/lib/jvm/java-15-openjdk/bin/javac

V tomto momente som bol zmätený, keďže mnohé zdroje navrhovali túto nesprávnu hodnotu:

export JAVA_HOME=/usr/lib/jvm/default

Čo vyprodukovalo túto chybu:

WARNING: Ignoring JAVA_HOME, because it must point to a JDK, not a JRE.

Ďalší užitočný náznak bol pri inštalácii bazel z oficiálneho repozitára:

Packages (4) jdk11-openjdk-11.0.13.u8-1  jre11-openjdk-11.0.13.u8-1
             jre11-openjdk-headless-11.0.13.u8-1  bazel-4.2.0-2

Nainštaloval rodinu jdk11-openjdk ako závislosti. Toto možno ďalej potvrdiť:

yay -Qi bazel3 | grep -i depend
# Depends On      : java-environment=11

Nainštalovaný bazel vyžaduje JDK11, preto som sa rozhodol pre nasledovné:

export JAVA_HOME=/usr/lib/jvm/java-11-openjdk

Trafené! Fungovalo to.

Poznámka: na úpravu funkčného Java prostredia si pozrite archlinux-java help.

Krok 4: Konfigurácia balíčka #

Tu to začína byť zákerné:

./configure

Pri stlačení ENTER sa stane nasledovné:

You have bazel 3.7.2 installed.
Please specify the location of python. [Default is /usr/bin/python3]:


Found possible Python library paths:
  /usr/lib/python3.9/site-packages
Please input the desired Python library path to use.  Default is [/usr/lib/python3.9/site-packages]

Do you wish to build TensorFlow with ROCm support? [y/N]:
No ROCm support will be enabled for TensorFlow.

Do you wish to build TensorFlow with CUDA support? [y/N]:
No CUDA support will be enabled for TensorFlow.

Do you wish to download a fresh release of clang? (Experimental) [y/N]:
Clang will not be downloaded.

Please specify optimization flags to use during compilation when bazel option "--config=opt" is specified [Default is -Wno-sign-compare]:


Would you like to interactively configure ./WORKSPACE for Android builds? [y/N]:
Not configuring the WORKSPACE for Android builds.

Preconfigured Bazel build configs. You can use any of the below by adding "--config=<>" to your build command. See .bazelrc for more details.
	--config=mkl         	# Build with MKL support.
	--config=mkl_aarch64 	# Build with oneDNN and Compute Library for the Arm Architecture (ACL).
	--config=monolithic  	# Config for mostly static monolithic build.
	--config=numa        	# Build with NUMA support.
	--config=dynamic_kernels	# (Experimental) Build kernels into separate shared objects.
	--config=v1          	# Build with TensorFlow 1 API instead of TF 2 API.
Preconfigured Bazel build configs to DISABLE default on features:
	--config=nogcp       	# Disable GCP support.
	--config=nonccl      	# Disable NVIDIA NCCL support.
Configuration finished

Ale musíme upraviť príznaky, aby sme získali podporu inštrukcií, pamätáte? Bez akýchkoľvek úprav by sme skončili ešte horšie ako na začiatku:

This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN) to use the following CPU instructions in performance-critical operations:
 SSE3 SSE4.1 SSE4.2 AVX AVX2 FMA
To enable them in other operations, rebuild TensorFlow with the appropriate compiler flags.

Teraz máme 6 možných CPU inštrukcií nevyužitých namiesto len dvoch s vydanou verziou balíčka tfjs-node. Trik spočíva v použití správnych príznakov pri otázke --config=opt:

Please specify optimization flags to use during compilation when bazel option "--config=opt" is specified [Default is -Wno-sign-compare]: -mavx -mavx2 -mfma -msse3 -msse4.1 -msse4.2

Smutná časť je tá, že nemám tušenie, ako vopred zistiť parametre. Musel som kompilovať bez príznakov a potom znovu skompilovať so všetkými, ktoré boli údajne chýbajúce. Ak viete, ako to spoľahlivo urobiť naraz, dajte mi vedieť.

Krok 5: Zostavenie balíčka libtensorflow #

Zostavenie bez ohľadu na zadané príznaky sa spustí takto:

bazel build --config=opt --config=monolithic //tensorflow/tools/lib_package:libtensorflow

Proces zostavenia produkuje záhadný výstup končiaci týmto zmätkom (skrátené):

DEBUG: Repository io_bazel_rules_docker instantiated at:
  /home/peterbabic/throw/tensorflow/WORKSPACE:23:14: in <toplevel>
  /home/peterbabic/throw/tensorflow/tensorflow/workspace0.bzl:108:34: in workspace
  /home/peterbabic/.cache/bazel/_bazel_peterbabic/0a4f750584c5f2d6b197cb4128047fc4/external/bazel_toolchains/repositories/repositories.bzl:35:23: in repositories
Repository rule git_repository defined at:
  /home/peterbabic/.cache/bazel/_bazel_peterbabic/0a4f750584c5f2d6b197cb4128047fc4/external/bazel_tools/tools/build_defs/repo/git.bzl:199:33: in <toplevel>
INFO: Analyzed target //tensorflow/tools/lib_package:libtensorflow (0 packages loaded, 0 t
argets configured).
INFO: Found 1 target...
Target //tensorflow/tools/lib_package:libtensorflow up-to-date:
  bazel-bin/tensorflow/tools/lib_package/libtensorflow.tar.gz
INFO: Elapsed time: 10752.573s, Critical Path: 516.72s
INFO: 4050 processes: 166 internal, 3884 local.
INFO: Build completed successfully, 4050 total actions

Nie príliš zaujímavé. Vidíme, že to trvalo len pár sekúnd menej ako celé tri hodiny. Okrem toho sú tam nejaké náznaky, kde súbory zostavenia skutočne sídlia, keďže ma prekvapilo, že neboli nikde v blízkosti priečinka repozitára tensorflow. V skutočnosti mi ani výstup príliš nepomohol kvôli štruktúre adresárov. Musel som urobiť nasledovné:

fd -HI libtensorflow.tar.gz ~
#/home/peterbabic/.cache/bazel/_bazel_peterbabic/0a4f750584c5f2d6b197cb4128047fc4/execroot/org_tensorflow/bazel-out/k8-opt/bin/tensorflow/tools/lib_package/libtensorflow.tar.gz

Skrátene, súbor, ktorý hľadáme, je veľmi hlboko vnútri adresára ~/.cache/bazel.

Krok 5: Nahradenie závislostí tfjs-node #

Posledným krokom je dostať skompilované závislosti do projektu. Prispôsobte nasledujúce riadky podľa potreby:

cp ~/long-bazel-path/libtensorflow.tar.gz ~/myproject/node_modules/@tensorflow/tfjs-node/deps
cd ~/myproject/node_modules/@tensorflow/tfjs-node/deps
tar -xf libtensorflow.tar.gz

Teraz by node projekt nemal hlásiť chybu a využívanie TensorFlow by malo byť na vašom hardvéri čo najefektívnejšie. Niektorí používatelia hlásili zvýšenie rýchlosti v rozmedzí od 2x do 30x. Na toto zatiaľ nemám žiadne dáta, ale ak je to pravda, rozhodne stojí za to zvážiť podstúpenie všetkého tohto trápenia. V každom prípade, dúfam, že to bolo pre vás užitočné a ak nie, možno ste sa aspoň naučili niečo nové. Príjemnú prácu!

Odkazy #