この記事はABEJA Platform Advent Calendar 2018の24日目です。
はじめに
どうも、緒方です。
世はAI戦国時代、皆さんの会社ではAI活用進んでいますか?😃
自分たちのプロダクトでDeep Learningを活用する際、データ収集からアノテーション、学習モデル作成やプロダクトへの組み込み(API化等)を一通りこなす必要があります。 今回はクリスマス・イブなので、 サンタクロースを題材にDeep Learningをフルスクラッチでサービスインしたら・・・?という内容でお送りしたいと思います。
やりたいこと
クリスマスといえば、サンタクロース。きっと子供の頃は待ちわびたことだと思います。 しかし世の中には様々なサンタが存在します。 はたしてDeep Learningは世の中に複数存在するサンタの属性を見分けられるのか、、、?
今回のDeep Learningのプロダクトをサービス化するにあたり、下記のタスクをこなしていきたいと思います。
- Webから画像をクローリング
- 教師データのタグ付
- 学習モデルの作成
- Web API化
Webから画像をクローリング
まずはJupyterを使ってクローリングを行います。
まずはJupyterインスタンスを立ち上げたいので Training > Job Definition
から新規のジョブ定義を作成します。
Notebookの画面です。
開くと、Jupyterが起動します
普段のJupyterの使い方と同じようにNotebookを作成してコードを書きます。
ここでは、
- キーワードに対する画像Webのクローリング
- ABEJA PlatformのDatalakeへの画像アップロード
の2つのタスクを行います。
クローリングに関しては、神パッケージの icrawler
を利用します。キーワードを入れるとよしなにクローリングしてきてくれます。
今回は サンタ
と サンタコス
をキーワードに、画像合計1000枚程度取得します。
実行すると image/<検索ワード>
に画像が保存されます。
画像がクローリングできたら、ABEJA PlatformのSDKを利用してDatalakeのChannelへ画像をアップロードします。
認証情報をSDKに渡して datalake_client.channels.create()
にてClientを生成したあと、
まずはDatalakeに新規Channel(s3のbucketのようなもの)を作成します。
channel.upload_dir()
関数は、指定したディレクトリにある画像ファイルを全部Datalakeへアップロードしてくれるいいヤツです。
下記にベタ書きコードを貼っています。
from pathlib import Path from icrawler.builtin import GoogleImageCrawler from abeja.datalake import Client as DatalakeClient from abeja.datalake.storage_type import StorageType organization_id = '123456789' credential = { 'user_id': 'user-123456789', 'personal_access_token': '123456789123456789123456789123456789123456789' } image_root_dir = Path('image') # download images keyword = u'サンタクロース' max_num = 800 filters = { 'type': 'photo' } crawler = GoogleImageCrawler(storage={'root_dir': image_root_dir / keyword}) crawler.crawl(keyword=keyword, max_num=max_num, filters=filters) keyword = u'サンタコス' max_num = 300 filters = { 'type': 'photo' } crawler = GoogleImageCrawler(storage={'root_dir': image_root_dir / keyword}) crawler.crawl(keyword=keyword, max_num=max_num, filters=filters) # create channel datalake_client = DatalakeClient(organization_id=organization_id, credential=credential) name = 'santa-dataset' description = 'created by my crawler' channel = datalake_client.channels.create(name, description, StorageType.DATALAKE.value) # upload images ret = channel.upload_dir(image_root_dir)
*集めた画像を眺めてみるとわかるのですが、世の中に存在するサンタ画像は サンタ画像
>> サンタコス画像
だったため、枚数を調整しています
これをJupyter上で実行することで、Datalakeに有効なファイルがUploadされました。
これにてデータ収集完了です!
教師データのタグ付
教師データを作成するために次のステップへ進みます。 PlatformのAnnotationをクリックし、タグ付けのためのプロジェクトを作成します。 Annotation Toolでは各タスクに特化したテンプレートを用意しており、画面に従って入力するだけで簡単にワーカーへ依頼することが可能になります。 アカウント管理や品質管理のためのレビュー機能もついており、コードを開発すること無く教師データの作成ができます。
トップ画面はこのような形になっており、プロジェクトを管理できるようになっています。
タスク準備編
Create a new Project
をクリックし、タスクを作成すると次の画面がでます。
現在は下記のようなテンプレートを準備しており、随時汎用的なタスクは開発・追加していきます!
- 画像識別
- 物体検出
- 動画タグ付け
- 音声書き起こし
- テキストラベリング
- セグメンテーション
- 画像のテキスト化
もちろん裏ではABEJA PlatformのAPIコールしているだけなので、あなただけのオリジナルアノテーションツール
も開発することが可能です。WebでもWindows EXEでもスマホアプリでも、なんでもOKです。
今回は、サンタ or サンタコス
の分類問題を解いてみようと思うので、classification
タスクを選択します。
選択するとタスク作成画面に移ります。 ここでラベルの設計を行います(割と自由にかけます)。
今回は、サンタクロース
、サンタコス
、それ以外
の3つのタグを作成しました。
DatalakeのChannelとプロジェクトの依頼内容を設定します。
最後に内容を確認してプロジェクトスタート!
Project SANTA 始動
タスク実行編
Annotationの管理画面から、作業タスクを依頼するためにアカウントを作成します。 試しに僕のアカウントを発行します。
ワーカー用のリンクをアクセスして、こんな感じでログインすると
アサイン可能なプロジェクト一覧を見ることができます。
作業
ボタンを押すとタスク作業画面がでます。
進捗状況もこんな感じで見ることができます。
これ、全部1人てアノテーションするの辛いなー、辛いなー
そんな人のために、ABEJA Platform Annotationというクラウドソーシングサービスがあります。 これは、作成したタスクをアノテーターに依頼するサービスで、10万件のデータを1週間で作成するアノテーションリソース(*当社調べ) があるそうです。 早速課金しましょう(AIも課金ゲーかもしれませんね)
依頼が完了するとこのようなプログレスになります。
あとは管理画面からアノテーションをダウンロードして一旦準備完了です!
*本来はある程度のボリュームがないと依頼できないのですが、今回は特別にお願いを聞いてもらいました、感謝
学習モデルの作成
Datasetsの整備
まずは作成した教師データをABEJA Platformの Datasets
に取り込みます。
Datasetsは学習データを管理する仕組みで、Train/Valのデータセットを管理したり、データのバージョン管理をしたり、複数人で共同開発を行う場合に非常に役立ちます。
詳細はここ を見ると非常にわかりやすいです。
すると、このように Datasets
内に、利用可能なデータが用意されます。
便利な機能として、データセットの中身がどんなものかを確認できるPreview機能があります。
タグ毎の絞り込みも可能なので、コードを書くことなくデータの確認ができます
学習モデルの作成
ここでは下記の3つをやっていきます。
- 学習/評価データの作成
- 学習コードの作成/実行
- 精度評価
学習/評価データの作成
学習モデルを作成する際に重要なポイントの一つとして 学習/評価データ
があります。
これは学習モデルを複数人で作成したり、後々評価する際に 僕の環境では○○だった
をなくすために非常に重要なことです。
まずは Datasetsの整備
の項目を参考にデータセットを分割してスナップショットを作ります(今回は7:3の割合でデータを分割しました)
下記の画面のようにtrain
/ val
の名前を追加し作成してます。
学習コードの作成/実行
あとは普段どおりの学習コードをサンプルコードを見ながら書いていきます。 ほとんど普段Deep Learningのコードを書くのと同じようにかけます。
あとは、書いたコードをアップロードして実行ボタンを押すと下記のように学習がスタートします。お茶やコーヒーを入れてプログレスバーを眺めましょう。
ルール通りに書けば設定変数を外部からも変更できるので、同じコードでパラメーターを実験ごとに変えたい場合はEnvironments
を学習時に変更すれば並列で実験可能です。
ステータスがsuccess
になっていれば学習完了です!
精度評価
AIエンジニアたるもの、識別問題をやった際にはConfusion Matrixを確認したくなるものです。 そこで登場するのがpycm です(≠pymc)。 使い方は非常に簡単で、予測値と真値のベクターを入れるだけなので使っていきましょう。
学習済みモデルをABEJA Platformから読み込み
import io import os import zipfile import requests import keras from abeja.datasets.dataset_item import DatasetItem from abeja.datasets import Client as DatasetClient from abeja.train import APIClient as TrainAPIClient # download model file train_api_client = TrainAPIClient(credential=credential) result = train_api_client.get_training_result(organization_id, job_definition_name, training_job_id) res = requests.get(result['artifacts']['complete']['uri']) binary = io.BytesIO(res.content) # extract model file with zipfile.ZipFile(binary) as existing_zip: # print(existing_zip.namelist()) existing_zip.extractall(download_dir) # load model model_path = os.path.join(download_dir, 'model.h5') model = keras.models.load_model(model_path)
推論して
def read_data_from_dataset_item(dataset_item: DatasetItem): img = np.array(Image.open(io.BytesIO(dataset_item.source_data[0].get_content())), dtype=np.float32) label = int(item.attributes['classification'][0]['label_id']) return img, label dataset_client = DatasetClient(organization_id=organization_id, credential=credential) dataset = dataset_client.get_dataset(dataset_id) dataset_list = list(dataset.dataset_items.list(prefetch=True)) x_list, y_list = load_dataset_from_api(dataset_id) x_arr = np.array(x_list) y_pred = model.predict(x_arr) y_pred = np.argmax(y_pred, axis=1)
評価すると?
このように精度を簡単に確認することができます。
(大体8割程度はDeep Learningでサンタとサンタコスを見分けられるっぽい?!?!?)
今回何の工夫もないモデル(ResNet50)をFinetuingしたのですが、精度を見るとサンタかサンタコスという軸ではほとんど見分けられているようです(それ以外
と間違うことが多いみたいですが)
Deploy
それなりに精度が出るモデルができたので、早速WebAPI化してみようと思います。 API化のためには下記のステップを行います。
- 推論コードの開発
- Model Version作成
- Web API化
あんまりAWSやGCPとかのクラウド詳しくないという人や、Webとかロードバランサーとかよくわかんないという人でもそのあたりはABEJA Platformがマネージしてくれます。
推論コードの開発
ABEJA Platformのサンプルコードを元に雑なコードをサクッと書きます。 このコードは画像のリクエストを受け付けて、推論結果をjsonで返すコードになります。
import os from keras.preprocessing import image from keras.models import load_model from keras.applications.imagenet_utils import preprocess_input import numpy as np from PIL import Image img_rows, img_cols = 224, 224 model = load_model(os.path.join(os.environ.get('ABEJA_TRAINING_RESULT_DIR', '.'), 'model.h5')) def decode_predictions(result): categories = { 0: u'santa', 1: u'santa-cos', 2: u'others' } result_with_labels = [{"label": categories[i], "probability": score} for i, score in enumerate(result)] return sorted(result_with_labels, key=lambda x: x['probability'], reverse=True) def handler(_iter, ctx): for img in _iter: img = Image.fromarray(img) img = img.resize((img_rows, img_cols)) x = image.img_to_array(img) x = np.expand_dims(x, axis=0) x = preprocess_input(x, mode='tf') result = model.predict(x)[0] sorted_result = decode_predictions(result.tolist()) yield {"result": sorted_result}
Model Version作成
学習済みモデルと推論コードを紐づけて、Model Versionというものを作成します。
これにより、あとからあの時のモデルは良かった
コードとモデルの対応が取れてなくてもう動かし方がわからない
などのツラみを解消できます。
Web API化
先程作成したModel Versionを選択して、インスタンスタイプや台数を選んでDeployしましょう!インフラ周りは全部ABEJA Platformにお任せします。
APIのテストをしてみます。UIにcheck
機構があるので使ってみます。
推論結果がきちんとJsonで返ってきました。 このAPIをアプリの裏側やLine Botに組み込めば、いつでもサンタクロースとサンタコスを見分ける事ができます、やったね!
考察
今回のデータセット&学習モデルだと、サンタクロースかサンタコス(その他含む)を大体8割程度見分けられるようです。
今回、フルスクラッチでデータ収集からサービス化してみて改めて勉強になりました。 特にデータ収集のところでは、大きな学びがありました。 データを集めてみて、眺めてみないとなかなかわからないこともあるものです。 例えば今回の例だと、下記のような課題が見つかりました。
- イラスト・アニメ画像はどうするのか?
- 若い男性のサンタ姿はサンタコス?
- サンタとサンタコスの姿の人が同時に写ってる場合はどうするの?
- 赤ちゃんもサンタコスに入れる?
- 緑や黒の服装はどうする?
- 世の中には本物のサンタの画像が少ないのでデータのバランスが悪くなるけど大丈夫?
そもそもすべてのサンタってコスプレなのでは
こういった課題は、アノテーションをする前のデータ収集の段階からしっかりと設計しないと、いざクラウドソーシングした後悲しい事になってしまいますね。
また、誤認識されたデータはこのようなものでした。
サンタと誤認識された画像例
サンタコスと誤認識された画像例
それ以外と誤認識された画像例
ラベル付けが難しそうだったり、サンタが複数人写り込んでいたりと、なかなかムズカシイものもありました。
一重にサンタとサンタコスを分けるだけでも、意外と考えなければいけないことが多く、いかにデータ精査とTry&Errorが重要かを感じられますね!
それでは良いクリスマスを!
宣伝
ABEJAではイケてるしヤバい人材募集中です!インターンとかも興味があればぜひご連絡くださいー www.wantedly.com
ABEJAの中の人と話ししたい!オフィス見学してみたいも随時受け付けておりますので、気軽にポチッとどうぞ↓↓