Google Cloud ML Engine 花のデータセットを使用した画像の分類

google cloud の cloud ml engine の tutoarial の備忘録。
https://cloud.google.com/ml-engine/docs/flowers-tutorial?hl=ja

python実行環境を構築するにあたり docker を活用します。google が提供する tensorflow コンテナを利用することで、手軽で確実に、かつローカル環境を汚さずに構築します。

# 環境整備

今回は、ローカルのmac book pro で docker を使用する。

### tutorial用のサンプルを入手
GitHub リポジトリからクローンする。
https://github.com/GoogleCloudPlatform/cloudml-samples
<pre>
git clone https://github.com/GoogleCloudPlatform/cloudml-samples.git
</pre>

### Google Cloud SDK を入手
アーカイブをダウンロード、任意の場所に展開しておく。
<pre>
https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-sdk-180.0.0-darwin-x86_64.tar.gz?hl=ja
</pre>

reference:
https://cloud.google.com/sdk/docs/quickstart-mac-os-x?hl=ja#before-you-begin

### docker コンテナを起動
前述のtutorialサンプルと、SDKをコンテナにマウントする。

```bash
$ docker run -it \
  -v <tutorial サンプルのpath>:/opt/cloudml-samples-master \
  -v <sdkのpath>:/opt/google-cloud-sdk \
  -p 6006:6006 \
  --name tensorflow-cloudml-samples-master \
  tensorflow/tensorflow \
  /bin/bash
```

- 6006ポートは、tensorboad用。

起動したコンテナに入る。

<pre>
$ docker exec -it tensorflow-cloudml-samples-master /bin/bash
</pre>

起動したコンテナ上で、SDKを初期化する。
<pre>
\# export PATH=$PATH:/opt/google-cloud-sdk/bin/  ====> pathを通す

\# cd /opt

\# ./google-cloud-sdk/install.sh

\# gcloud init    ====> SDK の初期化
</pre>
Google ユーザー アカウントを使用してログインし、対話形式で初期化を行う。
詳細については、以下を参照。
reference:
https://cloud.google.com/sdk/docs/quickstart-mac-os-x?hl=ja#initialize_the_sdk

つぎに、必要なpythonコンポーネントをインストールする。
はじめに、nose 1.2をインストール。
<pre>
\# pip install nose
</pre>
これをやっておかないと、つぎの requirementsのinstallで怒られた。
`distutils.errors.DistutilsError: Could not find suitable distribution for Requirement.parse('nose>=1.0')`

そして、tutorialのrequirementsをインストールする。

```bash
cd /opt/cloudml-samples-master/flowers

pip install -r requirements.txt
```


### Google Cloud SDK のコンポーネントを確認
以下のコマンドを実行。

```bash
gcloud ml-engine models list
```

コマンドから空のリストなどが返されることを確認。
あと、単純な TensorFlow Python プログラムを実行できればOK。
reference: https://cloud.google.com/ml-engine/docs/flowers-tutorial?hl=ja

### Dataflow APIを有効化
google cloud console で、Dataflow APIを有効化する。
https://console.cloud.google.com/home/dashboard

# Tutorial開始
- Storageにbucketを作成する。名前は Cloud Storage のすべてのバケット全体で重複しないように任意に決定します。Tutorialではこの形式でした。 `#{project_name}-#{project_id}-mlengine`
- docker containerの以下のディレクトリで行う。

```bash
cd /opt/cloudml-samples-master/flowers/
```
### 以後のコマンドで使用する変数を宣言する。

```bash
BUCKET_NAME="gs://${your_bucket_name}"
REGION=us-central1
PROJECT_ID=$(gcloud config list project --format "value(core.project)")
JOB_NAME="flowers_$(date +%Y%m%d_%H%M%S)"
GCS_PATH="${BUCKET_NAME}/${JOB_NAME}"
DICT_FILE=gs://cloud-ml-data/img/flower_photos/dict.txt
MODEL_NAME=flowers
VERSION_NAME=v1
```

regionの選択肢は、オンライン予測を使うので、us-central1 か europe-west1 のみ。
reference:
https://cloud.google.com/ml-engine/docs/regions?hl=ja

### 評価データの前処理を行う

```bash
python trainer/preprocess.py \
  --input_dict "$DICT_FILE" \
  --input_path "gs://cloud-ml-data/img/flower_photos/eval_set.csv" \
  --output_path "${GCS_PATH}/preproc/eval" \
  --cloud
```

### トレーニングデータの前処理を行う

```bash
python trainer/preprocess.py \
  --input_dict "$DICT_FILE" \
  --input_path "gs://cloud-ml-data/img/flower_photos/train_set.csv" \
  --output_path "${GCS_PATH}/preproc/train" \
  --cloud
```

### トレーニングを行う

```bash
gcloud ml-engine jobs submit training "$JOB_NAME" \
  --stream-logs \
  --module-name trainer.task \
  --package-path trainer \
  --staging-bucket "$BUCKET_NAME" \
  --region "$REGION" \
  --runtime-version=1.2\
  -- \
  --output_path "${GCS_PATH}/training" \
  --eval_data_paths "${GCS_PATH}/preproc/eval*" \
  --train_data_paths "${GCS_PATH}/preproc/train*"
```

### モデルのデプロイ

モデルのコンテナを作成する。

```bash
gcloud ml-engine models create "$MODEL_NAME" \
  --regions "$REGION"
```

最初のバージョンを作成する。

```bash
gcloud ml-engine versions create "$VERSION_NAME" \
  --model "$MODEL_NAME" \
  --origin "${GCS_PATH}/training/model" \
  --runtime-version=1.2
```

### 予測リクエストを送信してみる

画像を入手する。

```bash
gsutil cp \
  gs://cloud-ml-data/img/flower_photos/daisy/100080576_f52e8ee070_n.jpg \
  daisy.jpg
```

base64エンコードする。

```basgh
python -c 'import base64, sys, json; img = base64.b64encode(open(sys.argv[1], "rb").read()); print json.dumps({"key":"0", "image_bytes": {"b64": img}})' daisy.jpg &> request.json
```

APIに送信する。

```bash
gcloud ml-engine predict --model ${MODEL_NAME} --json-instances request.json
```

レスポンスを得る！

```bash
KEY  PREDICTION                SCORES
0      0                    [0.9980067610740662, 0.00011650333908619359,
0.00028453863342292607, 0.0006193328299559653, 0.0009433324448764324,
2.9501752578653395e-05]
```