HerokuとTensorFlowを利用した、顔画像の推論

# はじめに
- `Django` で作成した `TensorFlow` のアプリケーションを、`Heroku` へ移植します。
- `Heroku` の `Ubuntu 18.04` のコンテナを利用することで、`OpenCV` を利用出来るようになります。
- ソース一式は [ここ](https://github.com/maedamikio/public/tree/master/abe_or_ishihara/django) です。
- アプリケーションは https://abe-or-ishihara.herokuapp.com/ です。


# Herokuのセットアップ
- アカウントは、事前に作成しています。
- Mac でのセットアップしています。
- `Heroku` でコンテナを利用し、かつ `yml` ファイルによる `Postgres` のデプロイには、`beta` のプラグインが必要です。

```shell
$ brew install heroku/brew/heroku

$ heroku login

$ heroku update beta

$ heroku plugins:install @heroku-cli/plugin-manifest
```

- `Procfile` には、`gunicorn` で `Django` のプロジェクトを起動するように設定します。
- `Heroku` でコンテナを使う場合は、不要な設定です。ただし、ローカル環境でデバッグする場合は必要です。
- なので、デプロイには、必要ありません。

```Procfile
web: gunicorn project.wsgi --log-file -
```

- `Heroku` で利用する `Python` のバージョンを指定します。特にこだわりがないので、最新にしています。

```runtime.txt
python-3.7.5
```

- ライブラリをインストールします。`Heroku` へデプロイするために追加したのは、`django-heroku` と `gunicorn` です。
- `django-heroku` は、`Heroku` で `Django` を利用するための色々な設定等をしてくれるものです。

```requirements.txt
boto3
django
django-heroku
gunicorn
numpy==1.16.5
opencv-python
pillow
tensorflow==1.14.0
```

- `.env` に `Heroku` をローカルでデバッグする時の環境変数を設定します。

```.env
AWS_ACCESS_KEY_ID='your-aws-access-key'
AWS_SECRET_ACCESS_KEY='your-aws-secret-access-key'
BUCKET=abe-or-ishihara
```

- 設定ファイルの末尾に、`Heroku` 関連の設定をします。

```project/settings.py
STATIC_URL = '/static/'
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')]
import django_heroku
django_heroku.settings(locals())
```

# Heroku ローカルサーバーの起動
- `.env` の環境変数を読み込みローカルサーバを起動します。
- `http://0.0.0.0:5000/` や `http://0.0.0.0:5000/admin/` へのアクセスを確認します。
- 推論API や S3 へデータが保存されることを確認しました。

```shell
$ heroku local web
[OKAY] Loaded ENV .env File as KEY=VALUE Format
22:07:55 web.1   |  [2019-12-21 22:07:55 +0900] [59955] [INFO] Starting gunicorn 20.0.4
22:07:55 web.1   |  [2019-12-21 22:07:55 +0900] [59955] [INFO] Listening at: http://0.0.0.0:5000 (59955)
22:07:55 web.1   |  [2019-12-21 22:07:55 +0900] [59955] [INFO] Using worker: sync
22:07:55 web.1   |  [2019-12-21 22:07:55 +0900] [59973] [INFO] Booting worker with pid: 59973
```


# デバッグモード、許可ホストの修正
- 設定ファイルを修正します。

```project/settings.py
DEBUG = False

ALLOWED_HOSTS = ['abe-or-ishihara.herokuapp.com']
```


# Heroku へデプロイ

- `Heroku` のコンテナの設定をします。
- アドオンで `PostgreSQL` を設定しています。コンテナではない、通常の `Heroku` なら設定無しでOKなのですが、コンテナの場合は明示が必要です。
- `AWS S3` の設定をします。これは、`Heroku` のコンパネに環境変数が設定され、コンテナの起動時に利用される感じです。
- `languages` で `python` を指定します。バージョンは、`runtime.txt` に記載のバージョンが利用されます。
- `pip` の `opencv-python` には、`apt` の `libopencv-dev` が必要なので、インストールします。

```heroku.yml
setup:
  addons:
    - plan: 'heroku-postgresql:hobby-dev'
      as: DATABASE
  config:
    AWS_ACCESS_KEY_ID: 'your-aws-access-key'
    AWS_SECRET_ACCESS_KEY: 'your-aws-secret-access-key'
    BUCKET: abe-or-ishihara
build:
  languages:
    - python
  packages:
    - libopencv-dev
run:
  web: gunicorn project.wsgi --log-file -
```

- `Heroku` に環境を作ります。上記の `heroku.yml` 等に基づき環境が作成されます。

```shell
$ heroku create abe-or-ishihara --manifest
Reading heroku.yml manifest... done
Creating ⬢ abe-or-ishihara... done, stack is container
Adding heroku-postgresql:hobby-dev... done
Setting config vars... done
https://abe-or-ishihara.herokuapp.com/ | https://git.heroku.com/abe-or-ishihara.git
```

- デプロイするフォルダを `git init` します。
- フォルダを `Heroku` のリポジトリと連携します。

```shell
$ git init
Initialized empty Git repository in /Users/maeda_mikio/abe_or_ishihara/django/.git/

$ heroku git:remote -a abe-or-ishihara
set git remote heroku to https://git.heroku.com/abe-or-ishihara.git
```

- デプロイ対象を `git add .` します。

```shell
$ git add .

$ git status
On branch master

No commits yet

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)

	new file:   app/__init__.py
	new file:   app/admin.py
	new file:   app/apps.py
	new file:   app/data/checkpoint
	new file:   app/data/model.data-00000-of-00001
	new file:   app/data/model.index
	new file:   app/data/model.meta
	new file:   app/font.ttf
	new file:   app/haarcascade_frontalface_default.xml
	new file:   app/migrations/0001_initial.py
	new file:   app/migrations/__init__.py
	new file:   app/models.py
	new file:   app/tests.py
	new file:   app/views.py
	new file:   heroku.yml
	new file:   manage.py
	new file:   project/__init__.py
	new file:   project/asgi.py
	new file:   project/settings.py
	new file:   project/urls.py
	new file:   project/wsgi.py
	new file:   requirements.txt
	new file:   runtime.txt
	new file:   static/abe_or_ishihara.png
	new file:   static/index.css
	new file:   static/index.js
	new file:   static/spinner.css
	new file:   static/title.png
	new file:   templates/index.html
```

- コミットして、デプロイします。

```shell
$ git commit -am "create tensorflow face predict app"

$ git push heroku master
```

- `Heroku` 上でデータベースの確認、マイグレーションと管理ユーザーの作成をします。

```shell
$ heroku pg
=== DATABASE_URL
Plan:                  Hobby-dev
Status:                Available
Connections:           0/20
PG Version:            11.6
Created:               2019-12-21 13:39 UTC
Data Size:             7.7 MB
Tables:                0
Rows:                  0/10000 (In compliance)
Fork/Follow:           Unsupported
Rollback:              Unsupported
Continuous Protection: Off
Add-on:                postgresql-tapered-15660
```

```shell
$ heroku run python manage.py migrate
```

```shell
$ heroku run python manage.py createsuperuser
Running python manage.py createsuperuser on ⬢ abe-or-ishihara... up, run.2569 (Free)
ユーザー名 (leave blank to use 'u49624'):
メールアドレス:
Password:
Password (again):
Superuser created successfully.
```

# Heroku へアクセス
- https://abe-or-ishihara.herokuapp.com/ でアプリケーションを確認します。
- https://abe-or-ishihara.herokuapp.com/admin/app/log/ でログを確認します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/68632/32d5e482-aece-ef33-8251-9049f2af60d1.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/68632/8c27c38f-3d9c-cbba-13b9-5d303f53a5b5.png)


# おわりに
- `Heroku` で `Django` `TensorFlow` と `OpenCV` を利用したアプリケーションのデプロイをしました。
- `Heroku` は、コンテナで `Ubuntu` を使えるので、大体の事ができます。今回は、`OpenCV` を使うため、コンテナを利用しました。
- `CPU` は、`AVX （Advanced Vector Extensions）` に対応しているので、`TensorFlow` もOKです。今時、`AVX`対応していない方が、珍しいですけどね。
- これで、一連のアプリケーション作成が終了しました。次回は、まとめをしたく思っております。