Object detection APIで二度とハマりたくないメモ

Tensorflowで提供されているObject detection APIに手を出したのですが、ハマりにハマってしまいました。

自身の知識不足が何よりも大きいところではあるのですが、チュートリアルどおりにやってもたくさんのエラーに悩まされたので、個人的なメモも兼ねて出くわしたエラーとその対応方法をメモしていきます。

# 実践したチュートリアル
今回は公式チュートリアルの[Quick Start: Training a pet detector](https://github.com/tensorflow/models/blob/master/research/object_detection/g3doc/running_pets.md)を実施しました。

https://github.com/tensorflow/models/blob/master/research/object_detection/g3doc/running_pets.md

このチュートリアルでは、ローカル環境で諸々を準備して、GCPのML EngineでGPUを使い学習を行います。

学習したモデルにより、画像の中から動物（ペット）の顔を検出することができるようになります。

# 環境
**GCP ML Engine（runtime1.8）
Python3.5
Tensorflow1.8/1.9**

**Windows10**（ローカルクライアント）

Tensorflow1.8で始めたのですが、エラーで躓いているうちにGitHubが更新され1.9に乗り換えました。が、1.8で発生したエラーについても記しておきます。

それと。GCPのML Engineで実行する場合には、できる限りローカル環境もUNIXとしておくことをオススメします。

# Object detection APIでハマったエラー
ここから私が出くわしたエラーと解決方法についてもメモしていきます。

## "ModuleNotFoundError: No module named 'pycocotools._mask"（Tensorflow1.8）
**原因：pycocotoolsのコンパイル環境と実行環境が異なる
解決案：環境を揃える、もしくはTensorflow1.9以降を利用する**

pycocotoolsではCythonを用いて、PythonコードをC/C++に変換したモジュールを利用しています。そのため事前にコンパイルを行っています。

```python
#cocoapi/PythonAPI/
python setup.py build_ext install
```

このためWindows環境でpycocotoolsのコンパイルを行うとGCPでの実行時に標記のエラーが発生します。

対応としてはGCPのコンソールからpycocotoolsをコンパイルしてローカルにダウンロードしました。

なおTensorflow1.9以降は、ジョブの実行時にGCP上でpycocotoolsのコンパイルを行うようになったため、最新バージョンであれば当該エラーは発生しないと思われます。

## "pycocotools/_mask.c:547:21: fatal error: maskApi.h: No such file or directory"
**原因：GCP上にCythonがインストールされていない
解決方法：GCPコンソールからCythonをインストールしておく**

pycocotoolsを使うにはCythonが必要です。チュートリアルに従えばローカル環境には導入しているのですが、実行先のGCPにも導入する必要があります。

GCPのコンソールからCythonをインストールしておく必要があります。

```python
pip3 install Cython
```

## "Check failed: DeviceNameUtils::ParseFullName"
**原因：バケット上に前回失敗ジョブのファイルが滞留している
解決方法：ジョブの再実行時はバケットをキレイにする**

GCPバケットの学習モデル作成場所（ `gs://bucket/model_dir`や`gs://bucket/train` など）に前回失敗ジョブの過程で作成されたファイルが残っていた場合に発生するようです。

ジョブの再実行時はバケットをキレイにしておきましょう。

## "SyntaxError: Missing parentheses in call to 'print'"
**原因：printの使い方が間違っている
解決方法：コードを直す**
（※最近のcommitでこの辺のバグは修正されているようです）

見ての通りSyntaxErrorです。自分でソースを修正しました。

```diff:object_detection/utils/object_detection_evaluation.py
         all_tp_fp_labels = np.append(all_tp_fp_labels, tp_fp_labels)
-      print 'Scores and tpfp per class label: {}'.format(class_index)
-      print tp_fp_labels
-      print scores
+      print('Scores and tpfp per class label: {}'.format(class_index))

+      print(tp_fp_labels)
+      print(scores)
       precision, recall = metrics.compute_precision_recall(
```

## "AttributeError: 'dict' object has no attribute 'itervalues'"他
**原因：python2のメソッドが使われている**
**解決方法：python3に合わせて修正する**
（※最近のcommitでこの辺のバグは修正されているようです。）

python3ではdictオブジェクトのメソッド `itervalues` , `iterkeys` , `iteritems`が削除されていますが、object_detection_apiのGitHubソースが修正されていません。

このためメソッドを呼び出し箇所および、その値を受けて処理を行っている箇所を修正しました。

```diff:object_detection/model_lib.py
-      losses = [loss_tensor for loss_tensor in losses_dict.itervalues()]
+      losses = [loss_tensor for loss_tensor in losses_dict.values()]

-      eval_metric_ops = {str(k): v for k, v in eval_metric_ops.iteritems()}
+      eval_metric_ops = {str(k): v for k, v in eval_metric_ops.items()}
```

```diff:object_detection/utils/learning_schedules.py
  rate_index = tf.reduce_max(tf.where(tf.greater_equal(global_step, boundaries),
-                                      range(num_boundaries),
+                                      list(range(num_boundaries)),
                                       [0] * num_boundaries))
```

```diff:object_detection/metrics/coco_tools.py
     if (set(annotation_img_ids) != (set(annotation_img_ids)
                                     & set(self.getImgIds()))):
-    results.dataset['categories'] = copy.deepcopy(self.dataset['categories'])

+    results.dataset['categories'] = copy.deepcopy(list(self.dataset['categories']))
     if self._detection_type == 'bbox':
```

## "UnavailableError: OS Error"
**原因：よく分からない
解決方法：諦めた（Tensorflow1.9で発生しなくなった）**

このエラーは原因が分からずに結局解決できませんでした。途中までは学習が進んでいくのですが、突然エラーが発生します。そして発生タイミングが不定です。

Githubのissueを見ると、GCPの実行構成を変える（ `cloud.yml` のMachineTypeやworker数を変える）、学習モデルを変える（ `rcnn` から `mobilenet` など）、等でできたという報告もあります。
https://github.com/tensorflow/models/issues/3757#issuecomment-376419016

しかし私の環境で色々試してみると、ステップは進むようになるのですが、結局正常終了まではたどりつけませんでした。

半ば諦めていた時にObject detection apiがTensorflow1.9対応版に更新され、一からやり直すとこのエラーは発生しなくなりました。

ということで最新バージョンを使って取り組みましょう。

## tensorboard実行時に"File system scheme 'gs' not implemented"
**原因：Windows環境で実行している
解決方法：UNIX環境で実行する**

GCPで実行したジョブの学習状況を確認するためには、ローカル環境で`tensorboard`を実行します。

```
tensorboard --log_dir=gs://bucket/models_dir
```

しかし上記のコマンドをWindowsで実行すると標題のエラーが発生します。

「gsutilは使えたのになんでなん？」

と思うのですが、解決方法が分からず結局UNIX（MacOS）で確認しました。もちろん学習をローカル環境で実行している場合には問題ありません。

# とりあえず最新バージョンを使おう
以上、私がGCPのML EngineでObject detection apiを使った際に出くわしたエラーでした。

この他にも細かな設定ミスなどを山のように出しています。その結果**GCPの365日の無料利用枠を2週間で使い切ってしまいました。**

私はGCPもTensorflowも初学者だったので非常に辛い結果になりましたが、これから試してみようと考えている初学者の一助になれば幸いです。

なお、Object detection apiはそれなりの頻度で更新されています。また、ここに記載したとおり単純バグも多いため、できるだけ最新の環境で実行すると良い気がします。