PlaidMLの画像判定をMacで動かしてみる

[MacBookPro でOpenPose その2](https://qiita.com/drafts/2c0ac47ab16985b063c3/edit) でMacのGPUを利用して動作するPlaidMLを使ってみて、ベンチマークの他に何が動くのかな？ということで調べてみるとqiitaでこのような記事を見つけたので、現状(2020年)で動作するのか試してみました。

- [PlaidMLを使ってMacのGPU(AMD)で画像分類を試してみた](https://qiita.com/1O1/items/a9d99ec16a640b203543)

# 環境

- MacBook Pro 15in 2018 2.2 GHz Core i7 32GB Memory
- Mojave 10.14.6
- python 3.7.5
- homebrew でpythonとvirtualenv、wgetをインストール

# 準備

Pythonの仮想環境を設定します。

```
仮想環境を作成
$ virtualenv plaidvison-plaidml

仮想環境へ入る
$ source plaidvison-plaidml/bin/activate
```

# 設定

## PlaidML設定、動作確認

仮想環境へ入った後、PlaidMLパッケージのインストールと使用するデバイスの設定を行います。ここは [MacBookPro でOpenPose その2](https://qiita.com/drafts/2c0ac47ab16985b063c3/edit) と同じです。


```
PlaidMLとベンチマークのパッケージをインストール
$ pip install plaidml-keras plaidbench

PlaidMLで使用するデバイスを設定
$ plaidml-setup
※デバイスの設定以外は y で
・・・
< 中略 >
・・・
デバイスの設定箇所では一覧に表示されたデバイスの番号を選択してEnter
Multiple devices detected (You can override by setting PLAIDML_DEVICE_IDS).
Please choose a default device:

   1 : llvm_cpu.0
   2 : opencl_intel_uhd_graphics_630.0
   3 : opencl_cpu.0
   4 : opencl_amd_radeon_pro_555x_compute_engine.0
   5 : metal_intel(r)_uhd_graphics_630.0
   6 : metal_amd_radeon_pro_555x.0

Default device? (1,2,3,4,5,6)[1]:6
・・・
< 中略 >
・・・
```
パッケージのインストールとデバイスの設定が終わったら、動作確認を行います。

```
ベンチマークで動作を確認
$ plaidbench keras mobilenet
Running 1024 examples with mobilenet, batch size 1, on backend plaid
INFO:plaidml:Opening device "metal_amd_radeon_pro_555x.0" ※この表示が出ていれば選択したデバイスで動作している
Compiling network... Warming up... Running...
Example finished, elapsed: 0.545s (compile), 14.425s (execution)

-----------------------------------------------------------------------------------------
Network Name         Inference Latency         Time / FPS          
-----------------------------------------------------------------------------------------
mobilenet            14.09 ms                  0.00 ms / 1000000000.00 fps
Correctness: PASS, max_error: 1.675534622336272e-05, max_abs_error: 7.674098014831543e-07, fail_ratio: 0.0
```

# plaidvisionの設定

## 設定、しかしエラー終了

参考記事掲載時にはPlaidMLのリポジトリにソースはあったようなのですが、私が試したところ
リンク切れとなっており、調べてみたところ[こちら](https://github.com/jbruestle/plaidvision.git)にありました。

ということでgitよりクローンします。

```
$ git clone https://github.com/jbruestle/plaidvision.git
```

クローン後、ディレクトリに入ります。

```
$ cd plaidvision
```

必要なパッケージをインストールします。

```
$ pip install -r requirements.txt 
```

パッケージインストール後に、下記コマンドで起動しましたが何故かエラー終了してしまいました。

```
$ python plaidvision.py mobilenet
pygame 1.9.6
Hello from the pygame community. https://www.pygame.org/contribute.html
Using PlaidML backend.
INFO:plaidml:Opening device "metal_amd_radeon_pro_555x.0"
Traceback (most recent call last):
  File "plaidvision.py", line 320, in <module>
    main()
  File "plaidvision.py", line 289, in main
    predictions = model.classify(frame)
  File "plaidvision.py", line 219, in classify
    img = scipy.misc.imresize(img, self.shape).astype(float)
AttributeError: module 'scipy.misc' has no attribute 'imresize'
```

## エラーの調査と修正、しかし

どうもimresizeというattributeがないのでエラーとなっているということなので調べてみたところ、下記を参考にしつつplaidvision.pyのソースを修正してみました。

- [深層学習とかでのPythonエラー「AttributeError: module 'scipy.misc' has no attribute 'imresize'」への対処](https://qiita.com/enoughspacefor/items/678226cd149d6afec72c)
- [scipy.misc.imresizeはどこへ行った？](https://walkingmask.hatenablog.com/entry/2019/08/09/205651)

```
<中略>
import pygame
import scipy.misc
from PIL import Image <- この行を追加

<中略>

ここのimresizeを呼び出している部分を

    def classify(self, img, top_n=5):
        if img.shape != self.shape:
            img = scipy.misc.imresize(img, self.shape).astype(float)   <== ここを
        data = np.expand_dims(img, axis=0)
        data = self.preprocess_input(data)
        predictions = self.model.predict(data)
        return self.decode_predictions(predictions, top=top_n)[0]

下記のように変更

    def classify(self, img, top_n=5):
        if img.shape != self.shape:
            img = np.array(Image.fromarray(img).resize((int(self.shape[1]),int(self.shape[0])), resample=0)).astype(float)  <== このように変更
        data = np.expand_dims(img, axis=0)
        data = self.preprocess_input(data)
        predictions = self.model.predict(data)
        return self.decode_predictions(predictions, top=top_n)[0]

```

修正後、再度実行してみたところエラー終了は表示されなくなったですが、グレーのウィンドウが表示されたまま何も表示されない状態となってしまいました。

<img width="500" alt="graywindow.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25988/979525ee-1df4-117c-4838-50dccdc9ebf5.png">

## 表示の問題を修正

なぜだろうと調べてみたところ、このような情報がありました。

- [macOS Mojaveでpygameが動かない](https://qiita.com/ganbarubaru/items/ba88169effdf8dda9c55)

どうやらデフォルトでインストールしたpygameとMacの相性に問題があるようで、別のバージョンのpygameをインストールする必要があったようです。

ということで現在入っているpygameをアンインストールします。

```
$ pip uninstall pygame
```

そしてバージョンを指定してインストールします。

```
$ pip install pygame==2.0.0.dev6
```

## 結果は

pygameをインストール後、実行してみました。

```
$ python plaidvision.py mobilenet
```

今度は、問題なく動作し画像判定も行えました。

<img width="500" alt="success.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25988/12c510ee-d7d3-4e0e-3851-861465c6f35f.png">