In this post, I demonstrate how to build Tensorflow 1.5 from source on MacOS 10.13 High Sierra. To verify that building indeed works, I show how to change some Tensorflow Python code, do an incremental build and observe the change in action via a simple test program.
Installing Pre-Requisites
Tensorflow Source Code
You will most likely want to fork the main Tensorflow git repository on Github and clone your own fork to your local computer. The following clone instruction clones our Knowm fork of Tensorflow, containing a custom build script not present in the main Tensorflow project.
1 2 |
git clone https://github.com/knowm/tensorflow.git |
XCode
Install XCode via AppStore. I unsuccessfully tried to avoid this step, by installing just the command line XCode tools using xcode-select --install
, but later found out by trial and error that I indeed needed to install XCode.
Bazel
Bazel is a software dependency and build tool similar to ANT and Maven. Installation Instructions are here.
1 2 3 4 5 6 |
brew install bazel bazel version brew upgrade bazel pip3 install six numpy wheel brew install coreutils |
Custom Build Script
We need a custom build_tf.sh
because we didn’t install Python the recommended way using VirtualEnv. The inspiration of our build file is here. This retrieves all CPU features and applies some of them to build TF, which makes TF faster as it will utilize specialized CPU instructions if your computer has them.
Here is our build_tf.sh
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
#!/bin/bash # Author: Sasha Nikiforov # source of inspiration # https://stackoverflow.com/questions/41293077/how-to-compile-tensorflow-with-sse4-2-and-avx-instructions raw_cpu_flags=`sysctl -a | grep machdep.cpu.features | cut -d ":" -f 2 | tr '[:upper:]' '[:lower:]'` COPT="--copt=-march=native" for cpu_feature in $raw_cpu_flags do case "$cpu_feature" in "sse4.1" | "sse4.2" | "ssse3" | "fma" | "cx16" | "popcnt" | "maes") COPT+=" --copt=-m$cpu_feature" ;; "avx1.0") COPT+=" --copt=-mavx" ;; *) # noop ;; esac done mkdir /tmp/tensorflow_pkg chmod 777 /tmp/tensorflow_pkg bazel clean ./configure bazel build -c opt $COPT -k //tensorflow/tools/pip_package:build_pip_package bazel-bin/tensorflow/tools/pip_package/build_pip_package /tmp/tensorflow_pkg pip3 install --upgrade /tmp/tensorflow_pkg/`ls /tmp/tensorflow_pkg/ | grep tensorflow` |
Notice the commented out line: #./configure
, which you’ll need to run the first time to configure tensorflow. To run the script run:
1 2 3 |
cd path/to/tensorflow ./build_tf.sh |
Make sure the file is executable! chmod +x build_tf.sh
Path to python, when asked, is: /usr/local/bin/python3
The first build might take over two hours!
Getting Tensorboard to Also Work After Building from Source
This references an issue I opened: https://github.com/tensorflow/tensorboard/issues/812, which referenced an error: ImportError: cannot import name 'run_main'
after running Tensorboard. If you are running into this issue, just run pip3 install tb-nightly
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
pip3 install tb-nightly Collecting tb-nightly Downloading tb_nightly-1.5.0a20171213-py3-none-any.whl (3.0MB) 100% |████████████████████████████████| 3.0MB 425kB/s Requirement already satisfied: numpy>=1.12.0 in /usr/local/lib/python3.6/site-packages (from tb-nightly) Requirement already satisfied: html5lib==0.9999999 in /usr/local/lib/python3.6/site-packages (from tb-nightly) Requirement already satisfied: werkzeug>=0.11.10 in /usr/local/lib/python3.6/site-packages (from tb-nightly) Requirement already satisfied: wheel>=0.26; python_version >= "3" in /usr/local/lib/python3.6/site-packages (from tb-nightly) Requirement already satisfied: protobuf>=3.4.0 in /usr/local/lib/python3.6/site-packages (from tb-nightly) Requirement already satisfied: six>=1.10.0 in /usr/local/lib/python3.6/site-packages (from tb-nightly) Requirement already satisfied: markdown>=2.6.8 in /usr/local/lib/python3.6/site-packages (from tb-nightly) Requirement already satisfied: bleach==1.5.0 in /usr/local/lib/python3.6/site-packages (from tb-nightly) Requirement already satisfied: setuptools in /usr/local/lib/python3.6/site-packages (from protobuf>=3.4.0->tb-nightly) Installing collected packages: tb-nightly Successfully installed tb-nightly-1.5.0a20171213 |
Run an Example
Now that Tensorflow was built from source, you should run an example in the main Tensorflow project to verify that everything works:
1 2 |
python3 tensorflow/examples/tutorials/mnist/mnist_softmax.py |
Congratulations!!
Incrementally Building Tensorflow
For developing Tensorflow, we obviously don’t want to have to build the entire source tree from scratch every single time a change is made. Therefore, we want to build TF incrementally each time a change is made.
To accomplish this, we need to first understand what our build file build_tf.sh
does, in particular the last few steps:
1 2 3 4 5 6 7 |
bazel clean ./configure bazel build -c opt $COPT -k //tensorflow/tools/pip_package:build_pip_package bazel-bin/tensorflow/tools/pip_package/build_pip_package /tmp/tensorflow_pkg pip3 install --upgrade /tmp/tensorflow_pkg/`ls /tmp/tensorflow_pkg/ | grep tensorflow` |
bazel clean
This deletes all the build artifacts.
./configure
This causes the GUI to ask the user a list of questions to configure the build.
bazel build -c opt $COPT -k //tensorflow/tools/pip_package:build_pip_package
This does the compiling. It is smart enough to know to only build source that has been modified since the last build.
bazel-bin/tensorflow/tools/pip_package/build_pip_package /tmp/tensorflow_pkg
This creates a python wheel file in /tmp/tensorflow_pkg
pip3 install –upgrade /tmp/tensorflow_pkg/ls /tmp/tensorflow_pkg/ | grep tensorflow
This takes the wheel file and makes it an executable on the system via calling tensorflow
.
For an incremental build we only want to run the last 3 (of 5) lines of the build file and to do so we can just comment out the first 2 lines of code. the incremental build then takes less than 2 minutes.
Hacking Tensorflow at the Python Level
Let’s see if we can change some code in TF itself in a trivial way, recompile, re-run asimple hello world program such as hellotf.py
from our HelloTensorflow Project and verify that our incremental build setup is working as expected. We’ll use the following simple TF program:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
# https://mubaris.com/2017-10-21/tensorflow-101 # Import TensorFlow import tensorflow as tf # Define Constant output = tf.constant("Hello, World") # To print the value of constant you need to start a session. sess = tf.Session() # Print print(sess.run(output)) # Close the session sess.close() |
, which produces:
1 2 |
b'Hello, World' |
What if we change the tf.constant
code to append the String _hack
onto the end of the inputted constant?
In constant_op.py
(source here), line 212, we can modify it like this:
1 2 |
value+'_hack', dtype=dtype, shape=shape, verify_shape=verify_shape)) |
After re-building and re-running hellotf.py
, we get:
1 2 |
b'Hello, World_hack' |
, which confirms that our incremental build setup is indeed working!
1 Comment