エクサウィザーズ Engineer Blog

株式会社エクサウィザーズのエンジニアチームブログ

ブラウザで動く落書き判定モデルの作り方

はじめに

こんにちは。エクサウィザーズAIエンジニアの須藤です。

昨年の弊社忘年会の出し物として、落書き判定モデルを作りました。 お題に合わせて絵を書いて、AIにそれと判定させたら勝ちになるゲームです。 思いのほかちゃんと判定してくれて、ほっとしました。 取り立てて目新しさはありませんが、皆さんにも遊んでいただきたいと思い、ここで紹介します。

exaBaseのモデル詳細ページで実際に遊べます。 ブラウザだけで動作しますので、お気軽にお試しください。

データセット

Googleが提供しているQuick, Draw!というゲームのデータを使用します。 これは、お題に合う絵を描いて、AIに判定してもらうというゲームです。 制限時間は20秒で、AIが候補に挙げた時点でクリアとなります。 世界中のプレーヤーによって描かれた絵が、学習用データベースとして無償で提供されています

データセットには

  • ストローク
  • ストロークを画像(28x28x1)にしたもの
  • カテゴリー
  • 国情報
  • 時刻情報

などが含まれています。今回は画像とカテゴリーだけを用いて学習を行います。 ストロークを利用する学習モデルについては、以前の川畑さんの記事をご覧ください。

画像データはカテゴリー別にNumPy形式のバイナリファイルになっていて、Pythonで

np.load('cat.npy', mmap_mode='r')

とすると読み込むことができます。 1500万人が遊んだというだけあって、約5千万サンプル、約40GBの巨大なデータです。

カテゴリーは以下の通りで、全部で347あります。

エッフェル塔 万里の長城 モナリザ 空母 飛行機 目覚まし時計 救急車 天使 動物の移動 蟻 金床 りんご 腕 アスパラガス 斧 バックパック バナナ 包帯 納屋 バット 野球 バスケット バスケットボール コウモリ バスタブ ビーチ くま あごひげ ベッド 蜂 ベルト ベンチ 自転車 双眼鏡 鳥 誕生日ケーキ ブラックベリー ブルーベリー 本 ブーメラン ボトルキャップ 蝶ネクタイ ブレスレット 脳 パン 橋 ブロッコリー ほうき バケツ ブルドーザー バス ブッシュ 蝶 サボテン ケーキ 電卓 カレンダー ラクダ カメラ 迷彩 キャンプファイヤー ろうそく 大砲 カヌー 車 人参 城 ネコ 天井ファン 携帯電話 チェロ 椅子 シャンデリア 教会 サークル クラリネット 時計 雲 コーヒーカップ コンパス コンピューター クッキー 冷却装置 ソファー 牛 カニ クレヨン クロコダイル 王冠 遊覧船 カップ ダイヤモンド 食器洗い機 飛び込み台 犬 イルカ ドーナツ ドア ドラゴン 化粧ダンス ドリル ドラム アヒル ダンベル 耳 肘 象 封筒 消しゴム 眼 めがね 面 扇風機 羽 柵 指 消火栓 暖炉 消防車 魚 フラミンゴ 懐中電灯 ビーチサンダル フロアランプ 花 空飛ぶ円盤 足 フォーク カエル フライパン 庭用ホース 庭 キリン あごひげ ゴルフクラブ ぶどう 草 ギター ハンバーガー ハンマー 手 ハープ 帽子 ヘッドホン ハリネズミ ヘリコプター ヘルメット 六角形 ホッケーパック ホッケースティック 馬 病院 熱気球 ホットドッグ 温水浴槽 砂時計 観葉植物 家 ハリケーン アイスクリーム ジャケット 刑務所 カンガルー 鍵 キーボード 膝 ナイフ はしご ランタン ノートパソコン 葉 脚 電球 ライター 灯台 稲妻 線 ライオン 口紅 ロブスター ロリポップ メールボックス 地図 マーカー マッチ メガホン マーメイド マイクロフォン 電子レンジ 猿 月 蚊 バイク 山 マウス 口ひげ 口 マグカップ キノコ 爪 ネックレス 鼻 海洋 八角形 たこ 玉ねぎ オーブン ふくろう ペンキ缶 絵筆 ヤシの木 パンダ ズボン ペーパークリップ パラシュート オウム パスポート 落花生 梨 豆 鉛筆 ペンギン ピアノ ピックアップトラック 額縁 豚 枕 パイナップル ピザ ペンチ 警察車 池 プール アイスキャンデー はがき じゃがいも コンセント 財布 ウサギ アライグマ 無線 雨 虹 レーキ リモコン サイ ライフル 川 ジェットコースター ローラースケート ヨット サンドイッチ のこぎり サックス スクールバス はさみ サソリ ドライバー ウミガメ シーソー 鮫 羊 靴 ショーツ シャベル シンク スケートボード 頭蓋骨 超高層ビル 寝袋 笑顔 かたつむり ヘビ スノーケル スノーフレーク 雪だるま サッカーボール 靴下 快速艇 クモ スプーン スプレッドシート 四角 殴り書き リス 階段 星 ステーキ ステレオ 聴診器 縫い目 一時停止標識 コンロ イチゴ 街路灯 サヤインゲン 潜水艦 スーツケース 太陽 白鳥 セーター スイングセット 剣 注射器 Tシャツ テーブル ティーポット テディベア 電話 テレビ テニスラケット テント 虎 トースター つま先 トイレ 歯 歯ブラシ 歯磨き粉 竜巻 トラクター 信号機 列車 木 三角形 トロンボーン トラック トランペット 傘 下着 バン 花瓶 バイオリン 洗濯機 スイカ ウォータースライダー 鯨 ホイール 風車 ワインボトル ワイングラス 腕時計 ヨガ シマウマ ジグザグ

画像を可視化してみると、かなり雑で記号的な絵になっていることがわかります。

f:id:kentaro-suto:20190110180140j:plain f:id:kentaro-suto:20190110180208j:plain f:id:kentaro-suto:20190110180218j:plain f:id:kentaro-suto:20190121170519j:plain f:id:kentaro-suto:20190121170607j:plain f:id:kentaro-suto:20190121170631j:plain f:id:kentaro-suto:20190121170716j:plain f:id:kentaro-suto:20190121170745j:plain f:id:kentaro-suto:20190121170815j:plain f:id:kentaro-suto:20190121170851j:plain

モデル

畳み込みと全結合による、ごくシンプルなモデルです。 Python+Kerasで実装しました。

model = Sequential()
model.add(Reshape((28,28,1), input_shape=(784,)))
model.add(Conv2D(64, 5, padding='same')) #畳み込み
model.add(BatchNormalization())
model.add(Activation('relu'))
model.add(Conv2D(64, 5, padding='same'))
model.add(BatchNormalization())
model.add(Activation('relu'))
model.add(MaxPooling2D())
model.add(Conv2D(128, 5, padding='same'))
model.add(BatchNormalization())
model.add(Activation('relu'))
model.add(Conv2D(128, 5, padding='same'))
model.add(BatchNormalization())
model.add(Activation('relu'))
model.add(MaxPooling2D())
model.add(Conv2D(128, 5, padding='same'))
model.add(BatchNormalization())
model.add(Activation('relu'))
model.add(Conv2D(128, 5, padding='same'))
model.add(BatchNormalization())
model.add(Activation('relu'))
model.add(Flatten()) #ここから全結合
model.add(Dense(1024, activation='relu'))
model.add(Dropout(0.2))
model.add(Dense(345, activation='softmax'))
model.compile(loss='sparse_categorical_crossentropy', optimizer='adam', metrics=['accuracy'])

学習

データセットからランダムにサンプルを選んで、入力(画像データ)から出力(カテゴリーごとの確率)が得られるように、学習を行います。

学習量は

  • バッチサイズ=100
  • ステップ数=40000
  • エポック数=100
  • のべ=4億サンプル

でした。

インターフェイスと使い方

使い方を、実装詳細とともに解説します。 インターフェイスはHTML+JavaScript+Tensorflow.jsで作成しました。 Tensorflow.jsの基本的な使い方については以前の記事をご参照ください。

1.ページを開く

このページにアクセスします。 ページを開くとすぐに読み込みが始まります。 ダウンロードデータは全部で8.4MBあります。ネットワーク環境によってはお時間をいただくかもしれません。

2.絵を描く

ページ全体がキャンバスになっています。 ドラッグで線を描いてください。 f:id:kentaro-suto:20190111194202p:plain

判定時には線が描かれた領域だけがモデルに合わせてリサイズされるので、どこにどんな大きさで描いても大丈夫です。 間違えたら「リセット」で全消去できます。

リサイズで線の太さがバラつかないように、線を描画するとき、同時にストロークデータとしても保存しています。

3.判定させる

「送信」ボタンを押すと判定処理を開始します。

保存したストロークデータを用いて28×28の領域に再描画をします*1。 描いたピクセルを配列に変換し*2、モデルに入力します。

4.結果を見る

判定結果を表示します。

f:id:kentaro-suto:20190111195534p:plain

モデルの出力は各カテゴリーの確率として得られます。 その中で、最も大きなものに対応するカテゴリー名を表示します。 他のカテゴリーの確率は、詳細をクリックすると見られるテーブルに書き出します。

実行例

f:id:kentaro-suto:20190111200253p:plain f:id:kentaro-suto:20190111200309p:plain f:id:kentaro-suto:20190111200346p:plain f:id:kentaro-suto:20190115103611p:plain
これはドアで、 これが枕です。 四角と判定させるには、場違いな正確さが要求されます。 円については、そこまでシビアではありません。
f:id:kentaro-suto:20190111200204p:plain f:id:kentaro-suto:20190115103907p:plain f:id:kentaro-suto:20190111203526p:plain f:id:kentaro-suto:20190115101151p:plain
うっかりネコにしましまを描くと、高確率で虎になります。 学習データ全部、殴り書きのようなものなので、 リアルさにこだわると、却って判別されないことがあります。 極限まで図案化するのがいいようです。
f:id:kentaro-suto:20190115143611p:plain f:id:kentaro-suto:20190111202410p:plain f:id:kentaro-suto:20190115143713p:plain f:id:kentaro-suto:20190111201550p:plain
よくわからないなにかを描いても 必ず、347カテゴリーのどれかに判定します。 難しそうなカテゴリーも 意外に簡単な特徴で判定している場合があります。

まとめ

落書き判定モデルを作りました。 花とか月といった、誰でも同じようになる絵は高い精度で認識します。 期待通りに認識しない場合もありますが、間違い方に妙な納得感があったりします。 機械学習の面白くて不思議なところです。

尚、エクサウィザーズは優秀なエンジニア、社会課題を一緒に解決してくれる魔法使い”ウィザーズ”を募集しています。ご興味を持たれた方はぜひご応募ください。 採用情報|株式会社エクサウィザーズ

ExaWizards Engineer Blogでは、定期的にAIなどの技術情報を発信していきます。Twitter (https://twitter.com/BlogExawizards) で更新情報を配信していきますので、ぜひフォローをよろしくお願いします!

*1:このとき学習データに合わせて線の太さを1.5ピクセルにするのが重要です。 1ピクセルではまともに判定しません。 この対策を思いつくまでに大分手こずりました。

*2:このとき背景が0になるように、明るさの反転も行います。