AutoGluonの画像分類（Image Classification）を試してみた

# はじめに

Google Colaboratoryの環境でAutoMLのライブラリであるAutoGluon（ https://autogluon.mxnet.io/index.html ）の画像分類を試してみました。
基本的には公式のQuickStartの内容にプラスアルファした内容になります。

# 環境

Google Colaboratoryで実施しています。

# 実行

## Google Colabの設定

画像分類の場合はDeepLearningのモデルを使用するため、GPUを使用するように設定します（下図参照）。

![GoogleColab_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329888/117e53a5-fa1d-5087-ea7f-7116398354b3.png)

![GoogleColab_02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329888/4ed45eb9-db5e-e241-2219-e2181bf88ae3.png)

## Google Colabでのライブラリインストール

上の設定だけだと、AutoGluonを動かしたときに、GPUがないとエラーがでます。
そのため、こちらの記事（ https://qiita.com/tasmas/items/22cf80a4be80f7ad458e ）を参考にインストールしました。特にエラーも出ず、うまくできました。

```python

!pip uninstall -y mkl
!pip install --upgrade mxnet-cu100
!pip install autogluon
!pip install -U ipykernel

```
実行後にランタイムを再起動します。

## AutoGluonの実行

公式のQuickStartに沿って実行していきます。
https://autogluon.mxnet.io/tutorials/image_classification/beginner.html

まずはライブラリのインポートとデータのダウンロードです。
データはKaggleにあったShopee-IETの画像データで、洋服などの画像を「BabyPants」「BabyShirt」「womencasualshoes」「womenchiffontop」の4つのカテゴリに分類するものになります。
ただし、AutoGluonのページにあるKaggleへのリンクは切れていました。
（Kaggleにもページはあるものの、ぱっとデータが見つからず。昔のコンペのデータなので、削除されてしまったのかもしれません。）


```python
import autogluon as ag
from autogluon import ImageClassification as task

filename = ag.download('https://autogluon.s3.amazonaws.com/datasets/shopee-iet.zip')
ag.unzip(filename)
```

学習用のデータと評価用のデータをそれぞれ読み込みます。

```python
train_dataset = task.Dataset('data/train')
test_dataset = task.Dataset('data/test', train=False)
```

学習用データを「fit」させるだけで、画像識別のモデルが構築されます。
めちゃくちゃ簡単...

```python
classifier = task.fit(train_dataset,
                      epochs=5,
                      ngpus_per_trial=1,
                      verbose=False)
```

以下、fit時の標準出力結果です。
どうやらResNet50を持ってきているようです。
最終的に学習曲線も出してくれます。今回は5 epochしか学習していないので、数分で終了しました。

```bash

scheduler_options: Key 'training_history_callback_delta_secs': Imputing default value 60
scheduler_options: Key 'delay_get_config': Imputing default value True

Starting Experiments
Num of Finished Tasks is 0
Num of Pending Tasks is 2
scheduler: FIFOScheduler(
DistributedResourceManager{
(Remote: Remote REMOTE_ID: 0, 
	<Remote: 'inproc://172.28.0.2/371/1' processes=1 threads=2, memory=13.65 GB>, Resource: NodeResourceManager(2 CPUs, 1 GPUs))
})

100%
2/2 [03:58<00:00, 119.19s/it]
Model file not found. Downloading.
Downloading /root/.mxnet/models/resnet50_v1b-0ecdba34.zip from https://apache-mxnet.s3-accelerate.dualstack.amazonaws.com/gluon/models/resnet50_v1b-0ecdba34.zip...
100%|██████████| 55344/55344 [00:01<00:00, 45529.30KB/s]
[Epoch 5] Validation: 0.456: 100%
5/5 [01:06<00:00, 13.29s/it]




Saving Training Curve in checkpoint/plot_training_curves.png
```
![autogluon_result.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329888/30fd04ee-d87e-bfc1-3d98-9a165e2e2b43.png)

学習時におけるAccuracyは50%程度でした。今の設定じゃ仕方ないかなと思います。

```python

print('Top-1 val acc: %.3f' % classifier.results['best_reward'])
# Top-1 val acc: 0.469
```

とある画像データに対して予測させてみます。「BabyShirt」のデータに対して予測させると確かに「BabyShirt」と分類されています。

```python

image = 'data/test/BabyShirt/BabyShirt_323.jpg'
ind, prob, _ = classifier.predict(image, plot=True)

print('The input picture is classified as [%s], with probability %.2f.' %
  (train_dataset.init().classes[ind.asscalar()], prob.asscalar()))

# The input picture is classified as [BabyShirt], with probability 0.61.
```

評価用のデータを使ってAccuracyを計算すると70%程度でした。

```python
test_acc = classifier.evaluate(test_dataset)
print('Top-1 test acc: %.3f' % test_acc)
# Top-1 test acc: 0.703
```

このような感じであっという間にモデル構築できてしまうので、本当に便利である一方、
fitの関数がやはり肝という感じがしたので、少し調べてみました。

## fitについて少し調べたこと

### fit関数の引数

今回は画像識別におけるfit関数を使いました。そのソースコード（ https://github.com/awslabs/autogluon/blob/15c105b0f1d8bdbebc86bd7e7a3a1b71e83e82b9/autogluon/task/image_classification/image_classification.py#L63 ）を下に抜粋しています。

```python

    @staticmethod
    def fit(dataset,
            net=Categorical('ResNet50_v1b', 'ResNet18_v1b'),
            optimizer=NAG(
                learning_rate=Real(1e-3, 1e-2, log=True),
                wd=Real(1e-4, 1e-3, log=True),
                multi_precision=False
            ),
            loss=SoftmaxCrossEntropyLoss(),
            split_ratio=0.8,
            batch_size=64,
            input_size=224,
            epochs=20,
            final_fit_epochs=None,
            ensemble=1,
            metric='accuracy',
            nthreads_per_trial=60,
            ngpus_per_trial=1,
            hybridize=True,
            scheduler_options=None,
            search_strategy='random',
            search_options=None,
            plot_results=False,
            verbose=False,
            num_trials=None,
            time_limits=None,
            resume=False,
            output_directory='checkpoint/',
            visualizer='none',
            dist_ip_addrs=None,
            auto_search=True,
            lr_config=Dict(
                lr_mode='cosine',
                lr_decay=0.1,
                lr_decay_period=0,
                lr_decay_epoch='40,80',
                warmup_lr=0.0,
                warmup_epochs=0
            ),
            tricks=Dict(
                last_gamma=False,
                use_pretrained=True,
                use_se=False,
                mixup=False,
                mixup_alpha=0.2,
                mixup_off_epoch=0,
                label_smoothing=False,
                no_wd=False,
                teacher_name=None,
                temperature=20.0,
                hard_weight=0.5,
                batch_norm=False,
                use_gn=False),
            **kwargs):
```

引数の一つである```net```にResNet50をデフォルトで呼ぶようにしていたため、
先ほど呼ばれていたことが分かります。
では、他のモデルを試したいときに、どんなモデルを選べるのかということが疑問になります。

### 呼び出すモデルについて

公式ページ（ https://autogluon.mxnet.io/tutorials/image_classification/hpo.html ）に記載されているように、gluoncvのmodel_zoo（ https://gluon-cv.mxnet.io/model_zoo/classification.html
 ）にあるモデルを取って来れるようです。
2020年9月4日現在の登録されているモデルは下図のようになっていました。

![gluon.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329888/40c50753-9c20-c6bb-e959-968651fce2b4.png)

上述のResNetだけではなく、MobileNetやVGGなど、学習済みモデルがいくつかあることがわかりました。
すでにモデルがaccuracy順に並べられて表示されているので、選ぶのも楽だと思います。

### 自作のモデルについて

一方で、自分でNeuralNetworkを組みたい場合、AutoGluonのベースで使われている```mxnet```を使って作れそうです。

https://github.com/awslabs/autogluon/blob/15c105b0f1d8bdbebc86bd7e7a3a1b71e83e82b9/autogluon/task/image_classification/nets.py#L52

```python
def mnist_net():
    mnist_net = gluon.nn.Sequential()
    mnist_net.add(ResUnit(1, 8, hidden_channels=8, kernel=3, stride=2))
    mnist_net.add(ResUnit(8, 8, hidden_channels=8, kernel=5, stride=2))
    mnist_net.add(ResUnit(8, 16, hidden_channels=8, kernel=3, stride=2))
    mnist_net.add(nn.GlobalAvgPool2D())
    mnist_net.add(nn.Flatten())
    mnist_net.add(nn.Activation('relu'))
    mnist_net.add(nn.Dense(10, in_units=16))
    return mnist_net

```


そのほかに、```metric```や```optimiser```も設定できるので、DeepLearningするにもやりやすいなーと思いました。

# さいごに

画像系の分析だとTensorflowやkerasなどを用いて、計算ロジックを組むようなイメージがありましたが、ここまで簡単にモデル構築ができるとなると、画像データの処理（ノイズ除去や、Augmentationなど）にかけられる時間が相対的に増えそうで大変良さそうだなと思いました。

AutoGluonのベースがDeepLearningのライブラリ（あるいはプラットフォーム）のmxnetになっているので、自然言語処理（NLP）もAutoGluonでサポートしていることも納得がいきました。むしろAutoGluon-Tabularがプラスアルファな要素という感じなのでしょうか。

AutoGluonもmxnetもAWSがサポートしているので、AWSのMLサービスにはこの辺のライブラリが使われているのかな...と思いつつここまでとしたいと思います。