githubの学習コードを使ってABEJA Platformで簡単に学習する


## はじめのはじめに

この記事は、ABEJA Platformを用いて、Deep Learningのモデルを運用するためのステップ１となります。モデルの運用までは通常は、

- 初期実験
- チューニング
- 運用フェーズ

のフローから成ります。例えば、「手の位置を認識しよう」としたら、まずは既存のgithubをベースにして試す、上手くいかなければフルスクラッチでモデルを作成します。ある程度モデルが動くことが分かりましたら、パラメータのチューニングを行います。最後に、実運用に進み、失敗したデータも含めて継続的に学習を回します。

ここでは、クイックに既存の学習モデルを動かすための方法を紹介します。

## はじめに

githubには膨大なDeep Learningの資産があり、これを用いることで、開発を大幅に加速することができます。githubにある多くのコードは、独自のアノテーションフォーマットで前提として構成されており、以前紹介したプラットフォームのデータ形式と異なります（[プラットフォームのデータ形式で学習データを用意する例](https://qiita.com/advent-calendar/2018/abejaplatform)）。そのため、これまでの解説で紹介した方法ではgithubの資産をそのまま使うことはできません。

ABEJA Platformでは学習ジョブとノートブックのストレージが共有化されており、ノートブックの領域に置いたデータを学習ジョブから利用できます。これによって、データ形式によらない学習が実行できます。すなわち、既存のgithubの学習コードのデータのパスを修正するだけで、手軽に既存のgithubの学習ジョブを走らせることができます。

ジョブは学習が終わったら自動で終了しますので、自身でAWSインスタンスを借りて終了させる必要もなく、当然ながら手元の計算環境を占有することもありません。並列でジョブを回すこともできるため、PoCをする際の強力なツールとなります。さらに、ここで実験が終了してから、データのフォーマットを書き換えることで、アノテーションツールとの連携や、継続的な運用へ繋げることができるようになります。

本記事では、既存のgithubコードを用いてplatformで簡単に学習する手順について解説します。

## 今回のターゲット

この記事では、花の画像データセットである[Flowers17データセット](http://www.robots.ox.ac.uk/~vgg/data/flowers/17/)を用いて、17種類の花の画像の分類を行なっていきます。

画像のサンプルはこちらです。

![Kobito.4AFnbh.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146529/e4a5249d-17f8-d0ee-37e2-4a8fe347fbae.png "Kobito.4AFnbh.png")


## 手順

### 概要

大まかには以下の4つの手順から成ります。複雑な手順に見えますが、大まかには前処理をして、動作確認をし、パスを書き換えるだけです。

- 作業環境の準備
- データの準備・前処理
- 学習コードのテスト実施
- ABEJA Platformに学習ジョブを投入

### 作業環境の準備

はじめに作業をするためのジョブを作ります。上記で述べた作業用ノートブックは、ジョブに紐づいています。そこで、まずはジョブの作成からはじめます。ジョブの作成は、左のメニューからJob Definitionを選択し、右上のCreate Training Job Definitionボタンを押し、ジョブを作成します。

![Kobito.CO4xBO.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146529/6a13b519-c57c-f2b3-fb37-74c6ccef9928.png "Kobito.CO4xBO.png")


ジョブを作成すると、指定した名前のBoxができます。そこからNoteboosを指定することで、ノートブックの画面に移動できます。右上のCreate Notebookを選択するとノートブックを作成できます。ここでは、データを展開するだけですので`cpu-1`インスタンスを選択しておきます。

![Kobito.8d375I.png](https://qiita-image-store.s3.amazonaws.com/0/146529/efe33a8d-d0b0-c2bf-871d-b86ef9ac3fb8.png "Kobito.8d375I.png")

![Kobito.Oh2iEa.png](https://qiita-image-store.s3.amazonaws.com/0/146529/3398c6ba-7c7d-f5f9-b7af-421a0f9aa66e.png "Kobito.Oh2iEa.png")

以上で、ノートブックが作成されます。Open Notebookを選択すると、Jupyter notebookの画面に進みます。

![Kobito.Ffw2XX.png](https://qiita-image-store.s3.amazonaws.com/0/146529/34468938-4d32-af9c-e4f6-16359da8214e.png "Kobito.Ffw2XX.png")

![Kobito.xyuZ8G.png](https://qiita-image-store.s3.amazonaws.com/0/146529/4e86f3c8-24a3-b23c-a531-3a75837a5694.png "Kobito.xyuZ8G.png")

### データの準備・前処理

ここまでに、作業用のノートブックの作成を行いました。ここからは、データの準備を行なっていきましょう。まずは、ノートブックに画像データを持って来ましょう。Webページから手元のPCに一度データを落としてからノートブックの機能を用いてアップロードするか、直接Webページからダウンロードします。ここでは、Webページからダウンロードしましょう。Notebookの右上のメニューのNewからPython3を選ぶと新しいノートブックを作成できます。ここにダウンロードのコードを書いていきましょう。

ダウンロードとデータの展開コードは以下となります。ノートブックに下記を移してRunボタンで実行しましょう。数分程度待つとデータが生成されます。

```
!wget http://www.robots.ox.ac.uk/~vgg/data/flowers/17/17flowers.tgz
!tar xzvf 17flowers.tgz
```

実行中の画面は以下のようになります。

![Kobito.xWcfSd.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146529/3a19035b-9f0e-9136-2a58-86155f7eec32.png "Kobito.xWcfSd.png")

Flowers17データセットは画像のサイズが不定なので、前処理でデータのサイズを固定します。新しいノートブックを作成して、前処理のスクリプトを動かしましょう。画像を開いて、サイズを64x64に変換して保存します。保存先として`images`ディレクトリを作成します。以下を実行すると、`images`ディレクトリに元の`jpg`ディレクトリと同じファイル名でリサイズ済みのファイルが保存されます。

```
import os
import glob
from PIL import Image

os.makedirs('images', exist_ok=True)
files = glob.glob('jpg/*.jpg')
for f in files:
    img = Image.open(f)
    img = img.resize((64, 64))
    target = os.path.join('images', os.path.basename(f))
    img.save(target)
```

### 学習コードの確認

まずはテストのため、ノートブック上で学習を実行してみましょう。ここでは、最初のステップとして、以下のリポジトリの学習コードを使います。

```
https://github.com/peisuke/flowers17_recognition.chainer
```

学習のテストでは、jupyter notebookのターミナルに進み、学習のコードを落としましょう。ノートブックのトップからNew→Terminalを選択します。

![Kobito.XXpYTR.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146529/da8f00f0-0d9e-590a-abe9-1479df75f45d.png "Kobito.XXpYTR.png")

すると、以下のような黒い画面が表れます。

![Kobito.aLlYrY.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146529/2b92fb9a-83da-a5bf-7952-417f24d755d6.png "Kobito.aLlYrY.png")

この画面上で先ほどのgithubのリポジトリをcloneします。

```
git clone https://github.com/peisuke/flowers17_recognition.chainer.git
```

すると、元のノートブック上に以下のように`flowers17_recognition.chainer`ディレクトリが作成されます。

![Kobito.BeQkmZ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146529/6151761b-7762-a2dd-5c1d-31cb5bfc7a04.png "Kobito.BeQkmZ.png")

次に作成されたモデルを実行してみます。`flowers17_recognition.chainer/train`を開いてソースコードを眺めてみましょう。34行目に画像のディレクトリを指定するコードが見つかると思います。

![Kobito.bxEGNb.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146529/2757c351-e885-95b6-9e6f-be1d4240d893.png "Kobito.bxEGNb.png")![Kobito.Cymw8b.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146529/e4825b77-1680-a6df-acd5-a2d75253c53d.png "Kobito.Cymw8b.png")


一旦は、このデータを参照する形として実行してみましょう。

![Kobito.ntCSf1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146529/e4587059-ae8c-3967-dbb6-c33dd838f7bf.png "Kobito.ntCSf1.png")

・・・と上記画面で数分間止まると思います。画像全部に対して、１周分学習されるまでは何も表示されないので、エラーが出ないのだけ確認して、ここで終了しておきましょう。終了はCtrl+Cです。

## テスト学習の実行

さて、精度は分かりませんが、ここまでで学習が走ることを確認できました。では一旦モデルが動作するかどうかを確認するために、GPUで実行してみましょう。Platformのノートブックの選択画面から、今度はgpu-1でノートブックを作成しましょう。

![Kobito.2QifGq.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146529/5b355262-6d89-3a4a-1341-f6900a5b96b6.png "Kobito.2QifGq.png")

さて、また先程と同様に、ターミナルを開いてgithubからモデルをcloneして来ましょう。

```
git clone https://github.com/peisuke/flowers17_recognition.chainer.git
```

次にノートブックの画面に戻り、`flowers17_recognition.chainer/train.py`を編集します。まずはgpuで動くように`gpu=-1`となっている所を`gpu=0`に修正します。

![Kobito.X2HNGz.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146529/ea0c7c5c-ae5c-e4c0-b6e3-71a3dbe7f73e.png "Kobito.X2HNGz.png")

また、データの位置を修正しましょう。データは先ほどのCPUのノートブックのIDのディレクトリに入っています。CPUのノートブックのIDはターミナル上から確認できます。ここでは、`1745249968478`とします。

![Kobito.u3Aqbn.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146529/7021694b-e314-4108-1119-1e400ee95447.png "Kobito.u3Aqbn.png")

この場合、`/mnt/notebooks/1745249968478/images`に画像データが格納されている事になります。そこで、`train.py`の34行目の画像格納位置を変更します。変更後は必ずファイルを保存しましょう。

![Kobito.dWbA3o.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146529/b8c03325-e773-b72e-bd09-d3af8a3188a3.png "Kobito.dWbA3o.png")

さて、再度モデルを実行していきましょう。同様にターミナルを開いて、実行します。

![Kobito.9tqZNK.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146529/1f2108cd-4094-8c82-9f8f-130f24c0a251.png "Kobito.9tqZNK.png")


このような感じで実行できました。

## ジョブの立ち上げ

では、プラットフォームにジョブを作っていきましょう。ジョブを作ると言っても、先ほどのコードを少しだけ終始＆zip化してプラットフォームに送るだけです。まずは、ローカルの環境にgithubを落として来ましょう。また、`train.py`を先程と同様に修正します。続いて、エントリポイントを修正します。プラットフォームは、`context`を引数とした`handler`関数からスタートするので、`main()`を修正します。

![Kobito.vaIISG.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146529/c7b1f609-27c5-ce4f-dce1-a8fa55ed0cc2.png "Kobito.vaIISG.png")

続いて、コードをzipに纏めます。

```
$ zip -r archive.zip *
```

とすると、zipファイルができます。JOBのダッシュボード上からCreate Versionを選択し、Handlerの項目に`train:handler`を設定します。これはtrain.pyのhandler関数から開始されることを意味します。続いて、下のSOURCE CODEから先程作成した`archive.zip`をアップロードし、Job Versionを作成します。以下のように新しいバージョンが作成されます。

![Kobito.WF06LM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146529/69f6fb52-25dd-fd80-eb36-0f0e88293778.png "Kobito.WF06LM.png")

Jobsをクリックし、右上のCreate Training Jobを選択し、先程作成したJob versionとGPUの種類を選び、Create Training Jobを用いて、ジョブを立ち上げます。

![Kobito.RfaBqQ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146529/8bc179dd-87c4-f6dc-d002-91cbdd572011.png "Kobito.RfaBqQ.png")

![Kobito.awCREP.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146529/b47affaa-8a87-7bbf-9b9e-946159364aa8.png "Kobito.awCREP.png")

すると、以下のようにジョブの待ち状態になります。

![Kobito.g59KFh.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146529/3e71a014-d8d4-3031-657c-397c7e3aafb3.png "Kobito.g59KFh.png")

しばらくすると、以下のように学習がスタートします。Logsから学習状況や精度を確認できます。なお、ダッシュボードとの連携コードは書いていないので、画面上に進捗状況や精度などは表示されません。

![Kobito.FS9iUB.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146529/23e1fbe2-3bea-76aa-dc7d-0d0077dc11cc.png 
"Kobito.FS9iUB.png")

## 追記：ジョブの立ち上げ（CLI版）

ジョブを立ち上げるのに、わざわざzipをダウンロードするのは面倒です。ABEJA CLIを用いることで、より簡単にジョブを作成できます。jupyterのターミナル上からCLIを用いる事ができます。まずは、クレデンシャルを設定しましょう。

```
$ abeja configure
abeja-platform-user  : {User-ID}
personal-access-token: {Token}
organization-name    : {Organization-ID or Organization-Name}
```

続いてジョブの立ち上げです。まずは、以下のようにyamlファイルを作成します。ファイル名は`training.yml`です。

```yaml
name: {Job-name}
handler: train:handler
image: abeja-inc/all-gpu:18.10
```

設定ができたならば、バージョンの作成とジョブを立ち上げましょう！

```
$ abeja training create-version
$ abeja training create-job
```

## 片付け

使用したノートブックは落としておきましょう。ノートブックのダッシュボードからノートブックを停止します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146529/cae37a6e-2bea-860d-48c8-e4b0cd289014.png)

## まとめ

以上のようにnotebookにデータをアップロードすれば、trainingコードのデータのパスをそこに指定するだけど、既存の学習コードがそのまま動作することを確認できました。今回はチュートリアルということもあり、非常に簡単なモデルで実験をしました。実際に実験をする際には、ここからパラメータをチューニングして精度を上げる必要があります。次回は、精度を上げる手順について、ご紹介しようと思います。