この記事は個人開発サービスに用いられている技術 Advent Calendar 2018 の22日目です。
こんにちは、2z(Twitter: @2zn01 )です。
普段は会社員でWeb系の開発エンジニアとして働き、週末に趣味で個人開発をしています。
今年の7月に話題のAIをweb上で誰でも気軽に作れる「AIメーカー」というサービスをリリースしました!
■AIメーカー
https://aimaker.io/
この記事では、この「AIメーカー」で使っている技術をまとめたいと思います。
作ったもの
以下の3ステップで誰でも簡単にAIを作れます!
- AIに覚えさせたいタグを入力
- タグから自動で画像データを収集
- AIがデータから学習
今話題のAIをweb上で誰でも気軽に作れる「AIメーカー」を開発しました!
— 2z / AIメーカー開発 (@2zn01) July 19, 2018
①AIに覚えさせたいタグを入力
②タグから自動で画像データを収集
③AIがデータから学習
の3ステップで誰でも簡単にAIを作れます!
動画では手相占いのAIに挑戦!
みんなもAIを作って遊んでみてね!https://t.co/66DFU7GRZ2 pic.twitter.com/ie1LmioyA1
画面イメージ
学習データの登録画面
学習データを各ラベル名から自動で収集する機能を実装!
— 2z / AIメーカー開発 (@2zn01) 2018年7月8日
これはなんとAidemyの石川さん(@ai_aidemy)よりアドバイス頂いたアイディアです!大感謝!!
僕も最近始めたところですが、Aidemyは機械学習、ブロックチェーンなど最新の技術も勉強できておすすめです!https://t.co/gORhd5P7Ls#AIメーカー pic.twitter.com/2cNpjzjPAl
モデルの学習画面
複数AIのモデル学習を並列で走らせる対応も無事完了!
— 2z / AIメーカー開発 (@2zn01) 2018年7月7日
(処理の裏側では複数のGPUサーバが走っている)
学習には時間がかかってしまうため、エポック数(訓練データを何回繰り返して学習させるか)は500に調整し、10分以内には終わるように。
精度よく学習させたい人は応相談にしておこう#AIメーカー pic.twitter.com/ukM3sg9rNG
モデルの学習履歴
学習履歴を一覧表示して、グラフを切り替えれるようにしてみた。#AIメーカー pic.twitter.com/wxcxZ3HXLE
— 2z / AIメーカー開発 (@2zn01) July 8, 2018
モデルの推論結果画面
AIメーカーの診断結果へ無駄にグラフを追加してみた!#AIメーカー pic.twitter.com/YCTaBDawhh
— 2z / AIメーカー開発 (@2zn01) July 14, 2018
システム構成図
AIメーカーのシステム構成図は以下の通りです。
大きな構成としては、主にユーザからの様々なリクエストを受け付けるフロントサーバと機械学習の処理を取り扱うバックエンドサーバの2つがあります。
使用している技術
Linux
クラウドのホスティングは、Amazon Web Services(以下、AWS)をメインで使用しており、Amazon EC2でサーバを立てています。
サーバのOSはLinuxでAmazon Linux 2を使っています。
AWSがメインですが、文字起こし機能の方ではGoogle Cloud Platformで、Google Compute Engine(GCE)でサーバを立てています。
サーバのOSはLinuxでCentOSの7系を使っています。
なぜAWSの他にGCPも使っているかというと、文字起こし機能の方でGoogle Cloud Vision APIやGoogle Cloud Speech APIを使っており、大容量の音声ファイルや画像ファイルを取扱うのにGoogle Cloud Storage経由で使った方が都合がいいからというのが理由になります。
Apache
webサーバはApacheを使っています。
Nginxもありますが、Apacheは普段から使っており、設定も把握していたため、いつも通りの安定の選択としました。
Welcome! - The Apache HTTP Server Project
MySQL
Amazon RDSを使ってMySQLを立てています。
Amazon EFS
複数のインスタンスで学習データや学習済みモデルを共有できるようにAWSのAmazon EFSというネットワークファイルシステムを使っています。
AIメーカーではフロントサーバとバックエンドサーバで分かれており、そこの連携が肝になってきます。
そこでAmazon EFSを使うことで、全インスタンスで同じファイルを共有することができるので、めんどいことを考えなくてもよくなります。
サーバをスケールさせる際に問題となってくるのがデータが格納されるDBとファイルになるかと思います。 Amazon EFSを使うことでファイルの読み込みや書き込みの速度は犠牲になるため、ユースケース次第かと思いますが、この辺の問題を考えなくてもよくなります。
ただ、ストレージ料金が高いのが悩みの種です。。><
PHP
フロントサーバ側のプログラムはPHPを使って実装しました。
フレームワークはZend Frameworkを使用しています。
Python
バックエンドサーバ側のプログラムはPythonを使って実装しました。
フレームワークはFlaskを使用しています。
Welcome | Flask (A Python Microframework)
Caffe
Deep LearningのフレームワークはCaffeを使用しています。
Caffe | Deep Learning Framework
jQuery
クライアント側のJavaScriptは、jQueryを使って実装しました。
実装方法
AIメーカーを作るにあたって、一般的なwebサービスにはない機能をどう実装しているかをご紹介します。
主に以下の機能について、まとめてみます。
- 学習データの自動収集
- モデルの学習
- モデルの推論
学習データの自動収集
ディープラーニングで画像分類のモデルを作る際には、AIにこの画像は〇〇であるということを教えるため、学習データにラベル付けを行います。
この学習データのラベル付けは、モデルの精度に大きく影響する重要な作業ですが、単調な作業なためにとても退屈です。
そこで、AIメーカーでは事前に登録していたラベル名から画像データを自動で収集する機能を用意いたしました。
ちなみにこちらの機能はAidemyの石川さんよりアドバイス頂いた機能です。大感謝!
学習データを各ラベル名から自動で収集する機能を実装!
— 2z / AIメーカー開発 (@2zn01) 2018年7月8日
これはなんとAidemyの石川さん(@ai_aidemy)よりアドバイス頂いたアイディアです!大感謝!!
僕も最近始めたところですが、Aidemyは機械学習、ブロックチェーンなど最新の技術も勉強できておすすめです!https://t.co/gORhd5P7Ls#AIメーカー pic.twitter.com/2cNpjzjPAl
ラベル名からの画像データの収集は、Bing Image Search APIを使用しています。
一つのラベルごとに50件の画像データを収集するようにしています。
この学習データの収集はブラウザからAjax通信でリクエストを投げ、サーバ側でバックグラウンドで処理させています。
処理時間はラベル数によりますが、少なくとも数分はかかるので、単純にリクエストを投げて応答を待っていると通信がタイムアウトしてしまう可能性があります。
そこで、サーバ側にリクエストを投げたら一度データベースへその処理をタスクとして保存しておき、一旦ブラウザ側へレスポンスを返しています。
サーバの裏側では常にデーモンが監視(待機)しているので、データベースへ学習データの収集タスクが登録されたら、収集処理が開始されるようになっています。
また、ブラウザ側では定期的にその進捗状況をAjax通信で見に行く(ポーリングする)ようにしています。
なお、AIメーカーでは手軽に利用できるように学習データの自動収集機能は用意しておりますが、それだけだと質の良い学習データは用意できないため、JPG、PNG、ZIPによる画像データのアップロードにももちろん対応しています。
モデルの学習
モデルの学習といえば、AIメーカーの根幹の機能になります。登録された学習データをもとにモデルを学習させます。
先のシステム構成図で示しましたが、AIメーカーにはフロントサーバとバックエンドサーバがあり、モデルの学習はバックエンドサーバで行います。
具体的には以下の流れで行います。
1. フロントサーバ側で学習データに不足がないかチェック
2. フロントサーバ側でCaffeで学習を開始するのに必要なファイルを生成する
- deploy.prototxt、solver.prototxt、train_val.prototxtを生成
- 学習データのファイルパス、ラベルのテキストデータを生成(全データのうち、90%を学習に使用)
- テストデータのファイルパス、ラベルのテキストデータを生成(全データのうち、10%をテストに使用)
3. フロントサーバ側からAmazon EC2のGPUインスタンス(バックエンドサーバ)を起動する
- 既に作成済みのインスタンスがある場合はそのインスタンスを起動する
- まだ起動済みのインスタンスがない場合は新たにインスタンスを作成して起動する
4. インスタンスの起動後、セットアップスクリプトを実行(具体的には以下のことをやっています)
- Amazon EFSのマウント
- 最新のソースをGitHubからpull
- FlaskをuWSGIサーバで起動し、リクエストを受付できるようにする
5. バックエンドサーバへの疎通確認後、フロントサーバからバックエンドサーバへCaffeの学習開始のリクエストを投げる
6. バックエンドサーバ側でリクエストを受け、Caffeの学習コマンドを実行する
- LMDBの作成
リストファイルは先の2で生成しておいたテキストデータを指定します。
EFSでファイルを共有しているため、そのままファイルの同期とか考えなくてもそのまま使えます
convert_imageset -resize_height=227 -resize_width=227 -shuffle / {学習データのリストファイル} train_lmdb convert_imageset -resize_height=227 -resize_width=227 -shuffle / {テストデータのリストファイル} test_lmdb
- 平均画像の作成
compute_image_mean train_lmdb mean.binaryproto compute_image_mean test_lmdb test_mean.binaryproto
- 学習を実行
学習ログファイルへ進捗状況が出力されていきます
caffe train -solver=solver.prototxt -weights {モデル} 2>&1 | tee {学習ログファイル} &")
7. フロントエンドサーバ側で学習ログファイルから進捗状況を把握し、学習状況をグラフで表示
学習ログファイルはAmazon EFSで共有しているので、そのログの中から正規表現でせっせと該当値を抽出します
if (preg_match('@] Test net output #0: accuracy = ([0-9.e\-]+)@', $record[$i], $matches)) { $accuracy = rtrim(rtrim(sprintf('%F', $matches[1]), '0'), '.'); } if (preg_match('@] Test net output #1: loss = ([0-9.e\-]+)@', $record[$i], $matches)) { $loss_test = rtrim(rtrim(sprintf('%F', $matches[1]), '0'), '.'); } if (preg_match('@] Iteration [0-9]+, loss = ([0-9.e\-]+)@', $record[$i], $matches)) { $loss_train = rtrim(rtrim(sprintf('%F', $matches[1]), '0'), '.'); }
8. 学習完了後、バックエンドサーバ側でモデルが生成される
9. フロントサーバ側でログから学習完了を検知し、学習結果をデータベースへ保存し、EC2インスタンスを停止する
以上が処理の流れになります。
モデルの推論
学習が完了し、生成されたモデルを使って画像分類の推論を行う機能です。
こちらは以下の処理で行っています。
1. ユーザーさんが推論したい画像をブラウザからアップロード
2. フロントサーバで画像データを保存し、バックエンドサーバへ画像ファイルパスをパラメータに推論のリクエストを投げる
3. バックエンドサーバでリクエストを受け、Caffeで推論処理を実行し、結果をJSON形式で返す
4. フロントサーバでレスポンスを受け取り、推論結果をグラフで表示する
最後に
今回、特にAIメーカー特有の機能に絞って、実装方法をまとめてみました。
AIメーカーではフロントサーバとバックエンドサーバの複数インスタンスで構成し、それぞれを連携させて実現している箇所が多いため、多少複雑になっています。
実際に作ってるときは頭の中でシステム構成をイメージして実装を進めていますが、後で見返すとどうだったっけな?となることがほとんどです。
このへんはきちんとメモするか、図解するかしてきちんと残しておいた方がよさそうですね。
なお、AIメーカーでは誰もが手軽にシンプルに使えること、そして学習が早く終わるようにするため、現時点ではモデルの精度を犠牲にしています。
そのため、今後は精度向上のために学習の際のハイパーパラメータのチューニングをしたいとか、学習の回数をもっと増やしたいとかなどの要望に応えられるようにする必要があると感じています。
学習自体はサーバ側でGPUを使ってやってます。
— 2z / AIメーカー開発 (@2zn01) July 21, 2018
ただ、まずは手軽に利用できるように学習時間を大幅に削減するべく、本来もっと学習すべきエポック数を少なくしてるので、精度はそんなに出ないのが現状です。
こちら、精度を上げたい方はオプションでパラメータ調整を可能にしたり等、今後の課題です! https://t.co/ZNfOUGxtS9
今後、このあたりの機能拡張も行っていきたいと思います。
この記事に少しでも興味をもって頂けましたら、本ブログの読者登録やTwitter: @2zn01をフォローして頂くと更新の励みになります!
皆さんもぜひ自分のサービスを作っていきましょう!