DEVELOPER’s BLOG
技術ブログ
無人レジ実現に挑戦 -ドーナツ金額の自動算出 Part 1-
アクセルユニバースの栗木です。
今回実務の練習として、同じインターン生の入江君と共に模擬案件に取り組みました。
模擬案件とは、機械学習を用いることで実生活におけるどのような問題を解決できるかを考え、課題設定からデータの準備、前処理、学習、検証までの一連の作業を経験するための問題です。
今回の取り組みの中で僕達が取り組んた内容や理論を各ステップ毎に紹介していきたいと思います。記事は2部構成として、本記事では前半部分を記します。
Step. 1 課題設定
今回は無人レジの実現に挑戦します。
僕は並ぶことが苦手なので、どうにかレジの混雑を解消できないか考えました。
レジ処理は「いらっしゃいませー」「レジに商品を登録」「支払い」「ありがとうございましたー」の流れですよね。ここの「レジに商品を登録」をどうにかして効率化できれば、レジの混雑を解消でき、普及すれば、僕みたいな並びたくない族もたくさん買い物に行くはずです。
今回の目標は画像検出を用いてレジを打つことなくカメラに映すだけで合計金額を計算することとします。
画像を利用する価値を高めるためにタグが付けられない商品(食べ物)で、誰もが大好きなドーナツを対象とします。特にまだ無人化が進んでいないドーナツ屋さんの商品をトレーに載せた状態を想定しました。検出が成功すれば金額だけでなくカロリーなど+αの情報も表示が可能になりますね。
まずはじめにPart1ではひとつひとつのドーナツが何であるかを判定しました。先に結果だけお伝えすると、現時点で正答率が99%を超えていて今後の検討も楽しみです。
実際にシステムを作っていきます。まずは学習データを用意していきましょう。
Step. 2 学習データの準備
早速7種類のドーナツを購入し撮影を行いました。
角度や裏表を変えつつそれぞれ100枚の写真を撮りました。以下に写真の一例を示しておきます。
ちなみに撮影後においしく頂きました。^^
また、それぞれのドーナツの名前(ラベル)は以下とします。
8枚目の写真は物体検出する際にアノテーションされたデータが必要となるのでそのためのものです。アノテーションに関する詳細は後半の記事で説明したいと思います。
1.エンゼルフレンチ
2.ダブルチョコレート
3.エンゼルクリーム
4.ポン・デ・リング
5.オールドファッションハニー
6.ストロベリーカスタードフレンチ
7.チョコファッション
8.複数ドーナツ(物体検出用)
Step. 3 画像データの読み込み
学習のための画像データが準備出来たので、学習に備えてデータの読み込みとサイズを統一するためリサイズを行います。
今回はGoogle Colabratoryを使用するため、Google Driveに先程の画像をアップロードし以下のようにマウントすることでGoogle Colabratoryからデータにアクセス出来るようにします。
Google DriveにはDonuts Filesディレクトリを作成し、そこに先程の画像のうち複数ドーナツ以外の7種類の画像をディレクトリ毎にまとめてあります。(複数ドーナツの画像は後半で扱います)
from google.colab import drive drive.mount('/content/drive')
次にDonuts Files内の画像をディレクトリごとに読み込みリサイズを行います。
#必要なライブラリのimport import os import numpy as np import glob import cv2 from keras.utils import np_utils IMAGE_SIZE = 100 #リサイズ後のサイズ指定 # Donuts Filesディレクトリから画像の読み込み及びリサイズ def get_data_and_label(path): X = [] Y = [] label = {} i = 0 for dir_name in os.listdir(path): label[dir_name] = i for file_path in glob.glob(path+'/'+dir_name+'/'+'*'): img = cv2.imread(file_path) img = cv2.resize(img,(IMAGE_SIZE,IMAGE_SIZE)) #100*100にリサイズ X.append(img) Y.append(i) i += 1 X = np.array(X) Y = np.array(Y) X = X.astype('float32') X = X / 255.0 #RGBの値を正規化 Y = np_utils.to_categorical(Y, len(label)) #One-hotベクトルの作成 return X, Y, label X, Y, label = get_data_and_label('drive/My Drive/Donuts Files')
これでデータの読み込みとリサイズは完了です。最後に精度の評価用にデータの分割を行います。
from sklearn.model_selection import train_test_split # 学習データのうち20%を検証データにする X_train, X_test, y_train, y_test = train_test_split(X, Y, test_size=0.20)
データの準備が出来たので、実際にモデルの学習と精度の検証を行いましょう。
最終目標は物体検出を行うことですが、前半である本記事ではまず1枚の画像に対して1つのラベルの予測を行う画像認識を実装しどの程度分類出来るか確認します。
Step. 4 モデル構築&学習
今回の問題は画像認識なので、モデルはCNN(畳み込みニューラルネットワーク)を使用します。
CNNの詳細については多くの方が記事にされているのでそちらを参考にして下さい。
簡単に説明すると、CNNは畳み込み層、プーリング層、全結合層から成り立っており、まず畳み込み層では複数のフィルタを使用して画像を畳み込むことでエッジやパターンなどの特徴を抽出します。
次にプーリング層でデータサイズを減らしつつ平行移動などの処理に対するロバスト性を獲得し、最後に通常のディープラーニングと同様の全結合層でこれまでに抽出した特徴とラベルの関係性を学習します。
CNNは2012年の画像認識コンペ(ILSVRC)で圧倒的な成績を残して注目されて以来、急速に発展を続けているので是非色々と調べてみて下さい。
それではKerasを用いてモデル構築を行いましょう。KerasはバックエンドでTensorFlowを利用するディープラーニングライブラリラッパーです。
#必要なライブラリのimport import tensorflow as tf import keras from keras.models import Sequential from keras.layers import Dense, Activation, Flatten from keras.layers.convolutional import Conv2D from keras.layers.pooling import MaxPool2D from keras.optimizers import RMSprop #最適化手法としてRMSpropを使用 # モデルの定義 model = Sequential() model.add(Conv2D(32, (3, 3), activation='relu', padding='same', input_shape=(IMAGE_SIZE, IMAGE_SIZE, 3))) model.add(MaxPool2D((2, 2), padding='same')) model.add(Conv2D(64, (3, 3), activation='relu', padding='same')) model.add(MaxPool2D((2, 2), padding='same')) model.add(Conv2D(128, (3, 3), activation='relu', padding='same')) model.add(MaxPool2D((2, 2), padding='same')) model.add(Flatten()) model.add(Dense(64, activation='relu')) model.add(Dense(len(label), activation='softmax', name='predicton'))
Kerasではモデルの構造をmodel.summary()から以下のように簡単に確認できるので非常に便利ですね。
_________________________________________________________________ Layer (type) Output Shape Param # ================================================================= conv2d_1 (Conv2D) (None, 100, 100, 32) 896 _________________________________________________________________ max_pooling2d_1 (MaxPooling2 (None, 50, 50, 32) 0 _________________________________________________________________ conv2d_2 (Conv2D) (None, 50, 50, 64) 18496 _________________________________________________________________ max_pooling2d_2 (MaxPooling2 (None, 25, 25, 64) 0 _________________________________________________________________ conv2d_3 (Conv2D) (None, 25, 25, 128) 73856 _________________________________________________________________ max_pooling2d_3 (MaxPooling2 (None, 13, 13, 128) 0 _________________________________________________________________ flatten_1 (Flatten) (None, 21632) 0 _________________________________________________________________ dense_1 (Dense) (None, 64) 1384512 _________________________________________________________________ predicton (Dense) (None, 7) 455 ================================================================= Total params: 1,478,215 Trainable params: 1,478,215 Non-trainable params: 0 _________________________________________________________________
それでは最後にモデルの学習と評価を行います。
# モデルのコンパイル model.compile(loss='categorical_crossentropy', optimizer=RMSprop(), metrics=['accuracy']) #パラメータの指定 batch_size = 64 epochs = 20 # 学習 history = model.fit(X_train, y_train, epochs=epochs, batch_size=batch_size) # 検証データによるモデルの評価 print(model.evaluate(X_test, y_test))
最終的なlossと正解率は以下のようになりました。
loss = 0.02750563397655182 accuracy = 0.9927007299270073
正答率が99%を超えており非常に高いスコアとなりました。
今回はかなり問題設定が単純だったことと、本来は同じ種類であっても多くのドーナツを用意すべきところを1つのドーナツから学習データを作成したことがこのスコアにつながったと考えられます。
終わりに
ドーナツ検出に向けて前半である本記事では、目的を設定し画像を収集するところから単純な画像認識を行うところまでご紹介しました。
最近は画像認識を簡単に実装出来るので、是非身近なものなどの分類に挑戦してみて下さい。
さてドーナツの分類は高精度で行えることが確認できたので、後半はいよいよレジの無人化という課題に向けて検出に挑戦しようと思います。
後半では物体検出のアルゴリズムの概要や検出の様子を紹介したいと考えているので、後半もよろしくお願いします!
アクセルユニバース株式会社(以下当社)では、人が対応している業務を画像認識、音声認識、文字認識等を活用して効率化する機械学習ソリューション開発をおこなっています。
今回挑戦している無人レジだけではなく、人と会話するかのようにシステムに問合せができるチャットボットや、カメラの前の人が誰であるか判別できる認証システムも検討しております。
- 機械学習でどんな事ができるのか興味がある
- 課題と感じている業務がある
- 効率化したい業務がある
上記のような方はぜひ問い合わせページにご連絡ください。
Twitter・Facebookで定期的に情報発信しています!
Follow @acceluniverse