TensorFlow 2.xでObject Detection APIを使うにはTensorFlowバージョンを揃える必要がある話

こんにちは、ピリカ開発チームの九鬼(niccari)です。

機械学習周りで物体検出したいとき、TensorFlowとともにObject Detection APIを利用することがあります。

Object Detection API側のアップデートで新規Docker環境が動かなくなったことがありました。

TL; DR

tensorflowおよびtensorflow関連ライブラリでバージョンを揃えればOKです。以下どちらかを行います。

  1. ベースとなるimageで最新のTensorFlow (GPU)バージョンのimageを使用する
  2. (workaround) Dockerfile内で同一バージョンのtensorflow, tensorflow-text, tf-models-officialをインストールする
    • TensorFlow 2.4.0未満の場合、Object Detection APIの特定コミットをチェックアウトする

検証環境

  • Ubuntu 20.04 LTS(カーネル: 5.4.0-81-generic)
  • Docker version 19.03.13
  • Dockerfile: Object Detection API公式で提供されているDockerfileから、ベースとなるimageをtensorflow/tensorflow:2.4.0-gpuに変更したもの

発生した問題

Object Detection API学習用のDockerコンテナを作って、model_main_tf2.pyで学習をかけました。すると、tensorflow-textのライブラリ部分で参照エラーが発生しクラッシュしました。

tensorflow.python.framework.errors_impl.NotFoundError: /usr/local/lib/python3.6/dist-packages/tensorflow_text/python/metrics/_text_similarity_metric_ops.so: undefined symbol: _ZN10tensorflow8OpKernel11TraceStringEPNS_15OpKernelContextEb

このエラーが出る理由は、tensorflow関連ライブラリ間でバージョンが一致していないためです。バージョンが異なると、tensorflow関連ライブラリのバイナリ間で差異が出ます。そのため、一部シンボルを読み出せなくなる可能性があります。

なぜバージョンが一致しなくなるかですが、Object Detection API(object_detectionライブラリ)のインストール時、常に最新のtensorflowライブラリをインストールしてしまうためです。これにより、2つのバージョンのtensorflowライブラリがインストールされてしまい、整合性が取れなくなります(詳しい理由については付記を参照ください)。

対策

tensorflowライブラリとその関連ライブラリのバージョンを合わせればよいので、以下のどちらかで解消されます。

  1. ベースとなるimageで最新のTensorFlow (GPU)バージョンのimageを使用する
  2. Dockerfile内で同一バージョンのtensorflow, tensorflow-text, tf-models-officialをインストールする
    • TensorFlow 2.4.0未満の場合、Object Detection APIの特定コミットをチェックアウトする

1.ベースとなるimageで最新のTensorFlow (GPU)バージョンのimageを使用する

DockerfileでベースにしているTensorFlow (GPU)を最新版に変更します。

2021.09.23現在、2.6.0が最新です。そこで、Dockerfileを以下の通り書き換えます(適宜、最新のバージョンに読み替えてください)。

- FROM tensorflow/tensorflow:2.2.0-gpu
+ FROM tensorflow/tensorflow:2.6.0-gpu

2. (workaround) Dockerfile内で同一バージョンのtensorflow, tensorflow-text, tf-models-officialをインストールする

学習環境側で制約があり、どうしてもTensorFlowのバージョンを特定のバージョンに揃えたい場合があります。

その場合、Dockerfileを以下のように書き換えます。

※ TensorFlow 2.5.0をNVIDIA GPUと共に使いたい場合

FROM tensorflow/tensorflow:2.5.0-gpu
ARG DEBIAN_FRONTEND=noninteractive

# Install apt dependencies
RUN apt-get update && apt-get install -y \
    git \
    gpg-agent \
    python3-cairocffi \
    protobuf-compiler \
    python3-pil \
    python3-lxml \
    python3-tk \
    wget

# Add new user to avoid running as root
RUN useradd -ms /bin/bash tensorflow
USER tensorflow
WORKDIR /home/tensorflow

# Clone Object Detection API
RUN git clone https://github.com/tensorflow/models/ /home/tensorflow/models/

# Workaround: If you use TF 2.2.x, uncomment the line below.
# WORKDIR /home/tensorflow/models/
# RUN git checkout 03a6d6c8e79b426231a4d5ba0cf45be9afc8bad5

# Workaround: If you use TF 2.3.x, uncomment the line below.
# WORKDIR /home/tensorflow/models/
# RUN git checkout cf82a72480a41a62b4bbe0f1378d319f0d6f5d5c

# Compile protobuf configs
RUN (cd /home/tensorflow/models/research/ && protoc object_detection/protos/*.proto --python_out=.)
WORKDIR /home/tensorflow/models/research/

RUN cp object_detection/packages/tf2/setup.py ./
ENV PATH="/home/tensorflow/.local/bin:${PATH}"

# Workaround (For Tensorflow < 2.5.1): Remove tf-models-official dependency from object_detection, will install it manually.
RUN sed -i -e 's/^.*tf-models-official.*$//g' ./setup.py

RUN python -m pip install -U pip

# Workaround: Lock tensorflow and corresponding tf-models-official versions.
RUN python -m pip install tensorflow==2.5.0 tensorflow-text==2.5.0 tf-models-official==2.5.0
RUN python -m pip install .

ENV TF_CPP_MIN_LOG_LEVEL 3

変更点1. 使いたいバージョンのtensorflow、および対応するtensorflow-textとtf-models-official(学習済みモデル利用のためのライブラリ)を手動でインストールします。なお、tensorflow/tensorflow:x.x.x-gpuをベースimageとして使う場合、初期状態でtensorflowライブラリは入っていないため、特定バージョンのTensorFlowを指定する必要があります。

RUN python -m pip install -U pip
+ 
+ # Workaround: install tensorflow and corresponding tf-models-official versions.
+ RUN python -m pip install tensorflow==2.5.0 tensorflow-text==2.5.0 tf-models-official==2.5.0
RUN python -m pip install .

ENV TF_CPP_MIN_LOG_LEVEL 3

変更点2. (使いたいTensorFlowのバージョンが2.5.1未満の場合) object_detectionライブラリの依存関係から、tf-models-officialを削除してください(その代わりに、変更点1でtensorflowに対応したバージョンのtf-models-officialをインストールしています)。

ENV PATH="/home/tensorflow/.local/bin:${PATH}"

+ # Workaround (For tensorflow < 2.5.1): Remove tf-models-official dependency from object_detection, will install it manually.
+ RUN sed -i -e 's/^.*tf-models-official.*$//g' ./setup.py

RUN python -m pip install -U pip

最新のobject_detectionライブラリのsetup.pyでは、tf-models-official>=2.5.1に依存関係に指定されています。そのため、それ以前のtf-models-officialを依存関係を含めるために上記変更が必要です(object_detectionライブラリはバージョニング未対応で、過去のリリースバージョンを特定することが難しいことが理由です)。

変更点3. (使いたいTensorFlowのバージョンが2.4.0未満の場合) インストールに使うobject_detectionのソースコードについて、古いコミットを指定します。最新のobject_detectionライブラリでは、tf-models-officialの2.4.0未満に対応していないため実行時エラーになります*1

以下の部分について、TensorFlow 2.2.xを使う場合は上の2行、2.3.xを使う場合は下の2行をコメントアウトしてください。

TensorFlow 2.2.xの場合

+ 
+ # Workaround: If you use TF 2.2.x, uncomment the line below.
+ WORKDIR /home/tensorflow/models/
+ RUN git checkout 03a6d6c8e79b426231a4d5ba0cf45be9afc8bad5

TensorFlow 2.3.xの場合

+ 
+ # Workaround: If you use TF 2.3.x, uncomment the line below.
+ WORKDIR /home/tensorflow/models/
+ RUN git checkout cf82a72480a41a62b4bbe0f1378d319f0d6f5d5c

以上の変更により、使いたいバージョンのTensorFlowのみがインストールされ、学習が可能になります。

付記: なぜObject Detection APIで最新のTensorFlowライブラリがインストールされてしまうのか?

object_detectionライブラリは、setup.py上でtf-models-officialライブラリ(学習済みモデルを使うためのライブラリ)を依存関係に持ちます。

REQUIRED_PACKAGES = [
    ...,
    'tf-models-official>=2.5.1',
]

tf-models-officialライブラリのsetup.pyを見てみると、

...
if project_name == 'tf-models-nightly':
  version += '.dev' + datetime.datetime.now().strftime('%Y%m%d')
  install_requires.append('tf-nightly')
  install_requires.append('tensorflow-text-nightly')
else:
  install_requires.append('tensorflow>=2.4.0')
  install_requires.append('tensorflow-text>=2.4.0')
...

となっていて、特定バージョン*2以上のtensorflow, tensorflow-textライブラリを依存関係を持ちます。そのため、すでにtensorflowライブラリをインストールしていても最新のバージョンがインストールされます。

一方で、tensorflow-gpuは自動的にアップデートされません。そのため、前述の通りtensorflowとバージョンが不整合になり得ます。

参考: どうすればこの問題が起こらないか?

ライブラリ側で以下の2点が対応されれば、本問題は解消されます。また、TensorFlow 2.4.0未満でObject Detection APIが実行時エラー問題も解消されます。

  • object_detectionライブラリがtf-models-officialライブラリ同様にTensorFlowのバージョンに揃えてバージョニングされている
    • 例えば、TensorFlow 2.4.0に対し、tf-models-officialとobject_detectionのバージョンがともに2.4.0になる
  • tf-models-officialが特定のTensorFlowのバージョンに依存関係が固定されている
    • 例えば、TensorFlow 2.4.0に対し、tensorflow==2.4.0, tensorflow-text==2.4.0が依存関係で固定されている

参考ページ

公式GitHub issue #9911: Dockerfile installs two tensorflow versions when building


以上、ご覧いただきありがとうございました!

*1:object_detectionライブラリがtf-models-officialライブラリと対応してバージョニングされていないため、特定のコミットを指定する必要があります

*2:tf-models-officialのバージョンは対応するtensorflowライブラリのバージョンと同じになっており、そのバージョンが依存関係の下限になります