Skip to content

Commit

Permalink
[fix] Apple silicon compile errors
Browse files Browse the repository at this point in the history
  • Loading branch information
poinwater authored and rhdong committed Nov 8, 2022
1 parent 7077fc5 commit 4776470
Show file tree
Hide file tree
Showing 9 changed files with 99 additions and 69 deletions.
10 changes: 2 additions & 8 deletions .github/workflows/make_wheel_macOS_arm64.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,12 @@
#
# Making wheel for macOS arm64 architecture
# Requirements:
# MacOS Monterey 12.0.0 +, Tensorflow-macos 2.5.0, ARM64 Apple Silicon, Bazel 4.1.0 +
# MacOS Monterey 12.0.0 +, Tensorflow-macos 2.6.0 or 2.8.0, ARM64 Apple Silicon, Bazel 4.1.0 +
# Please don't install tensorflow-metal, it may cause incorrect GPU devices detection issue.
set -e -x

# Install CPU version
export TF_NEED_CUDA=0

python --version

python -m pip install tensorflow-io
python -m pip install --upgrade protobuf==3.20.0
python configure.py

bazel build \
Expand All @@ -26,5 +21,4 @@ bazel build \
build_pip_pkg

# Output the wheel file to the artifacts directory
bazel-bin/build_pip_pkg artifacts "--plat-name macosx_12_0_arm64 $NIGHTLY_FLAG"
delocate-wheel -w wheelhouse artifacts/*.whl
bazel-bin/build_pip_pkg artifacts $NIGHTLY_FLAG
74 changes: 40 additions & 34 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ who have provided GPU acceleration technology support and code contribution.
<kbd> <img src="./assets/merilin.png" height="70" /> </kbd>
</a>


## Tutorials & Demos
See [tutorials](docs/tutorials/) and [demo](demo/) for end-to-end examples of each subpackages.

Expand Down Expand Up @@ -107,7 +108,7 @@ is compiled differently. A typical example of this would be `conda`-installed Te
| TFRA | TensorFlow | Compiler | CUDA | CUDNN | Compute Capability | CPU |
|:------|:-----------|:-----------|:-----|:------|:-----------------------------|:--------------|
| 0.5.0 | 2.8.3 | GCC 7.3.1 | 11.2 | 8.1 | 6.0, 6.1, 7.0, 7.5, 8.0, 8.6 | x86 |
| 0.5.0 | 2.8.3 | Xcode 13.1 | - | - | - | Apple M1 |
| 0.5.0 | 2.8.0 | Xcode 13.1 | - | - | - | Apple M1 |
| 0.4.0 | 2.5.1 | GCC 7.3.1 | 11.2 | 8.1 | 6.0, 6.1, 7.0, 7.5, 8.0, 8.6 | x86 |
| 0.4.0 | 2.5.0 | Xcode 13.1 | - | - | - | Apple M1 |
| 0.3.1 | 2.5.1 | GCC 7.3.1 | 11.2 | 8.1 | 6.0, 6.1, 7.0, 7.5, 8.0, 8.6 | x86 |
Expand All @@ -122,7 +123,7 @@ Check [nvidia-support-matrix](https://docs.nvidia.com/deeplearning/cudnn/support
- The release packages have a strict version binding relationship with TensorFlow.
- Due to the significant changes in the Tensorflow API, we can only ensure version 0.2.0 compatibility with TF1.15.2 on CPU & GPU,
but **there are no official releases**, you can only get it through compiling by the following:
```shell
```sh
PY_VERSION="3.7" \
TF_VERSION="1.15.2" \
TF_NEED_CUDA=1 \
Expand All @@ -135,20 +136,20 @@ sh .github/workflows/make_wheel_Linux_x86.sh
but maybe this doc can help you : [Extract headers from TensorFlow compiling directory](./build_deps/tf_header/README.md).
At the same time, we find some OPs used by TRFA have better performance, so we highly recommend you update TensorFlow to 2.x.

#### Installing from Source
### Installing from Source

For all developers, we recommend you use the development docker containers which are all GPU enabled:
```shell
```sh
docker pull tfra/dev_container:latest-python3.8 # "3.7", "3.9" are all avaliable.
docker run --privileged --gpus all -it --rm -v $(pwd):$(pwd) tfra/dev_container:latest-3.8
```

##### CPU Only
#### CPU Only
You can also install from source. This requires the [Bazel](https://bazel.build/) build system (version == 5.1.1).
Please install a TensorFlow on your compiling machine, The compiler needs to know the version of Tensorflow and
its headers according to the installed TensorFlow.

```shell
```sh
export TF_VERSION="2.8.3" # "2.6.3" are well tested.
pip install tensorflow[-gpu]==$TF_VERSION

Expand All @@ -163,10 +164,9 @@ bazel-bin/build_pip_pkg artifacts

pip install artifacts/tensorflow_recommenders_addons-*.whl
```

##### GPU Support
#### GPU Support
Only `TF_NEED_CUDA=1` is required and other environment variables are optional:
```shell
```sh
export TF_VERSION="2.8.3" # "2.6.3" is well tested.
export PY_VERSION="3.8"
export TF_NEED_CUDA=1
Expand All @@ -178,55 +178,61 @@ export CUDNN_INSTALL_PATH="/usr/lib/x86_64-linux-gnu"
python configure.py
```
And then build the pip package and install:
```shell
```sh
bazel build --enable_runfiles build_pip_pkg
bazel-bin/build_pip_pkg artifacts
pip install artifacts/tensorflow_recommenders_addons_gpu-*.whl
```
##### Apple Silicon Support (Beta Release)

#### Apple Silicon Support (Beta Release)
Requirements:

- macOS 12.0.0+
- Python 3.8 or 3.9
- tensorflow-macos 2.8.0
- tensorflow-macos 2.6.0 or 2.8.0
- bazel 4.1.0+

Before installing **TFRA** from source, you need to install tensorflow-macos from Apple. To install the natively supported version of tensorflow-macos, it's required to install the [Conda environment](https://github.com/conda-forge/miniforge).
The natively supported TensorFlow is maintained by Apple. Please see the instruction [Get started with tensorflow-metal](https://developer.apple.com/metal/tensorflow-plugin/) to install the natively supported Tensorflow on apple silicon devices.

After installing conda environment, run the following commands in the terminal.
To specify the TensorFlow version, please pass the version and replace the `$TF_VERSION` in the following commands from the instruction:

```sh
# Create a virtual environment
conda create -n $YOUR-ENVIRONMENT-NAME Python=$PYTHON_VERSION

# Activate your environment
conda activate $YOUR-ENVIRONMENT-NAME
export TF_VERSION="2.8.0" # "2.6.0" is well tested.
export PY_VERSION="3.8" # “3.9" is well tested.

# Install TensorFlow macOS dependencies via miniforge
conda install -c apple tensorflow-deps==2.5.0
# Install TensorFlow macOS dependencies
conda install -c apple tensorflow-deps==$TF_VERSION

# Install base TensorFlow
python -m pip install tensorflow-macos==2.5.0

# Install TensorFlow Recommenders Addons from PyPi distribution (optional)
python -m pip install tensorflow-recommenders-addons --no-deps
python -m pip install tensorflow-macos==$TF_VERSION
```

There is a difference between the [tensorflow-macos installation instruction](https://developer.apple.com/metal/tensorflow-plugin/) and our instruction because this build requires Python 3.8 or 3.9 and tensorflow-macos 2.5.0.
If you have any issues about installing `tensorflow-macos`, please contact the [Apple Developer Forums: tensorflow-metal](https://developer.apple.com/forums/tags/tensorflow-metal) for help.

The building script has been tested on macOS Monterey, If you are using macOS Big Sur, you may need to customize the building script.
**Install TFRA on Apple Silicon from Source**

```shell
# Build arm64 wheel from source
PY_VERSION=$PYTHON_VERSION TF_VERSION="2.5.0" TF_NEED_CUDA="0" sh .github/workflows/make_wheel_macOS_arm64.sh
```sh
# Building TFRA wheel
PY_VERSION=$PY_VERSION TF_VERSION=$TF_VERSION TF_NEED_CUDA="0" sh .github/workflows/make_wheel_macOS_arm64.sh

# Install
# Install the wheel
python -m pip install --no-deps ./artifacts/*.whl
```

**NOTICE:**
**Known Issues:**

The Apple silicon version of TFRA doesn't support:

* Data type **float16**
* Synchronous training based on **Horovod**
* `save_to_file_system`
* `load_from_file_system`
* `warm_start_util`

`save_to_file_system` and `load_from_file_system` are not supported because TFIO is not supported on apple silicon devices. Horovod and `warm_start_util` are not supported because the natively supported tensorflow-macos doesn't support V1 Tensorflow networks.

These issues may be fixed in the future release.

- The Apple silicon version TFRA doesn't support data type **float16**, the issue may be fixed in the future release.

##### Data Type Matrix for `tfra.dynamic_embedding.Variable`

Expand Down Expand Up @@ -280,7 +286,7 @@ sess_config.gpu_options.allow_growth = True

#### CPU or GPU Serving TensorFlow models with custom ops
When compiling, set the environment variable:
```
```sh
export FOR_TF_SERVING = "1"
```
Tensorflow Serving modification(**model_servers/BUILD**):
Expand Down
11 changes: 10 additions & 1 deletion build_deps/build_pip_pkg.sh
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ set -e
set -x

PLATFORM="$(uname -s | tr 'A-Z' 'a-z')"
ARCHITECTURE="$(uname -m)"

function is_windows() {
# On windows, the shell script is actually running in msys
Expand All @@ -27,6 +28,10 @@ function is_macos() {
[[ "${PLATFORM}" == "darwin" ]]
}

function is_arm64() {
[[ "${ARCHITECTURE}" == "arm64" ]]
}

if is_windows; then
PIP_FILE_PREFIX="bazel-bin/build_pip_pkg.exe.runfiles/tf_recommenders_addons/"
else
Expand Down Expand Up @@ -77,7 +82,11 @@ function main() {

BUILD_CMD="setup.py bdist_wheel --platlib-patch"
if is_macos; then
BUILD_CMD="${BUILD_CMD} --plat-name macosx_10_13_x86_64"
if is_arm64; then
BUILD_CMD="${BUILD_CMD} --plat-name macosx_12_0_arm64"
else
BUILD_CMD="${BUILD_CMD} --plat-name macosx_10_13_x86_64"
fi
fi

if [[ -z ${NIGHTLY_FLAG} ]]; then
Expand Down
24 changes: 9 additions & 15 deletions configure.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@
def _VALID_BAZEL_VERSION(tf_version):
if is_macos() and is_arm64():
target_bazel = "4.1.0"
logging.warn(
'Only Bazel version greater than 4.1.0 supports macOS arm64 platform.')
return target_bazel
elif tf_version < "2.0.0":
target_bazel = "0.26.1"
Expand Down Expand Up @@ -176,21 +174,17 @@ def _get_installed_and_valid_bazel_version():
return installed_bazel_version, valid_bazel_version


def check_bazel_version():
installed_bazel_version, valid_bazel_version = _get_installed_and_valid_bazel_version(
)
if installed_bazel_version != valid_bazel_version:
raise ValueError('Bazel version is {}, but {} is needed.'.format(
installed_bazel_version, valid_bazel_version))


def check_bazel_version_for_macOS_arm64():
def check_bazel_version(is_macos_arm64: bool = False):
installed_bazel_version, valid_bazel_version = _get_installed_and_valid_bazel_version(
)
if installed_bazel_version < valid_bazel_version:
raise ValueError(
'Bazel version is {}. For macOS arm64 platform, Bazel version must be at least {}.'
.format(installed_bazel_version, valid_bazel_version))
if is_macos_arm64:
raise ValueError(
'Bazel version is {}. For macOS arm64 platform, the Bazel version must be at least {}.'
.format(installed_bazel_version, valid_bazel_version))
else:
raise ValueError('Bazel version is {}, but {} is needed.'.format(
installed_bazel_version, valid_bazel_version))


def extract_tf_header():
Expand All @@ -217,7 +211,7 @@ def create_build_configuration():
if is_linux():
check_bazel_version()
if is_macos() and is_arm64():
check_bazel_version_for_macOS_arm64()
check_bazel_version(is_macos_arm64=True)
extract_tf_header()
logging.disable(logging.WARNING)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -520,12 +520,12 @@ inline const char *KContentPointer<tstring>(const tstring *in) {

inline uint32_t crc32c_hash(uint32_t crc, const uint8_t *p, size_t length) {
#if defined(__arm64__) || defined(__aarch64__)
int64_t_t len_int64_t = length;
while ((len_int64_t -= sizeof(uint64_t_t)) >= 0) {
CRC32CX(crc, *((uint64_t_t *)p));
p += sizeof(uint64_t_t);
int64_t len_int64_t = length;
while ((len_int64_t -= sizeof(uint64_t)) >= 0) {
CRC32CX(crc, *((uint64_t *)p));
p += sizeof(uint64_t);
}
length &= (sizeof(uint64_t_t) - 1);
length &= (sizeof(uint64_t) - 1);
#elif defined(__x86_64__)
int32_t len_int32 = length;
while ((len_int32 -= sizeof(uint32_t)) >= 0) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
from tensorflow.python.training import adam
from tensorflow.python.training import monitored_session
from tensorflow.python.training import training_util
from tensorflow_recommenders_addons.utils.check_platform import is_macos, is_arm64

default_config = config_pb2.ConfigProto(
allow_soft_placement=True,
Expand All @@ -48,12 +49,16 @@ def test_adam_minimize_trainable(self):
self.common_minimize_trainable(base_opt, test_opt, name="adam")

def common_minimize_trainable(self, base_opt, test_opt, name):
if (is_macos() and is_arm64()):
self.skipTest(
"Apple silicon devices don't support synchronous training based on Horovod."
)
from tensorflow.python.framework.errors_impl import NotFoundError

# TODO(rhdong): Recover the testing, if the horovod import error is fixed on macOS+TF2.7+.
try:
import horovod.tensorflow as hvd
except NotFoundError:
except (NotFoundError):
self.skipTest(
"Skip the test for horovod import error with Tensorflow-2.7.0 on MacOS-12."
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -788,8 +788,11 @@ def test_save_restore_file_system(self):

def test_save_restore_local_file_system(self):
if _redis_health_check(redis_config_params["redis_host_ip"][0],
redis_config_params["redis_host_port"][0]) == False:
self.skipTest('skip redis test when unable to access the redis service.')
redis_config_params["redis_host_port"][0]) == False \
or (is_macos() and is_arm64()):
self.skipTest(
"skip save restore file system test because TFIO doesn't support apple silicon."
)
if context.executing_eagerly():
self.skipTest('skip eager test when using legacy Saver.')
save_dir = os.path.join(self.get_temp_dir(), "save_restore")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import shutil

from tensorflow_recommenders_addons import dynamic_embedding as de
from tensorflow_recommenders_addons.utils.check_platform import is_macos, is_arm64

try:
from tensorflow.python.keras.initializers import initializers_v2 as kinit2
Expand Down Expand Up @@ -146,6 +147,10 @@ def _test_warm_start_rename(self, num_shards, use_regex):
self.assertAllEqual(emb, val_list)

def _test_warm_start_estimator(self, num_shards, use_regex):
if (is_macos() and is_arm64()):
self.skipTest(
"skip save restore file system test because TFIO doesn't support apple silicon."
)
devices = ["/cpu:0" for _ in range(num_shards)]
ckpt_prefix = os.path.join(self.get_temp_dir(), "ckpt")
id_list = [x for x in range(100)]
Expand Down Expand Up @@ -215,4 +220,4 @@ def test_warm_start_estimator(self):


if __name__ == "__main__":
test.main()
test.main()
18 changes: 16 additions & 2 deletions tensorflow_recommenders_addons/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,24 @@
"""Define TensorFlow Recommenders Addons version information."""

import os
import platform


def is_macos():
return platform.system() == "Darwin"


def is_arm64():
return platform.machine() == "arm64"


# Required TensorFlow version [min, max)
MIN_TF_VERSION = os.getenv("TF_VERSION", "2.6.3")
MAX_TF_VERSION = os.getenv("TF_VERSION", "2.8.3")
if (is_macos() and is_arm64()):
MIN_TF_VERSION = os.getenv("TF_VERSION", "2.6.0")
MAX_TF_VERSION = os.getenv("TF_VERSION", "2.8.0")
else:
MIN_TF_VERSION = os.getenv("TF_VERSION", "2.6.3")
MAX_TF_VERSION = os.getenv("TF_VERSION", "2.8.3")

# We follow Semantic Versioning (https://semver.org/)
_MAJOR_VERSION = "0"
Expand Down

0 comments on commit 4776470

Please sign in to comment.