2018/03/31

Deep Learningでハリーポッターの組分け帽子を作りました

ホグワーツには"グリフィンドール"、"レイブンクロー"、"ハッフルパフ"、"スリザリン"という4つの寮があり、映画の作品を見てみると、顔だったり雰囲気だったりになんとなく違いがあると思います。
誰しも「自分はどの寮に入るのかな??」と思ったことがありますよね!

よって、任意の画像から顔を判別し、その人が4つの寮のどれに入るのかをDeep Learningで判断するソフト"Sorting Deep Hat"を作りました!

(調べたところ、全く同じ動機から、全く同じようなソフトを作った人がいらっしゃいますし、そちらのほうがわかりやすいかもしれません。このSorting Deep Hatもこの記事の影響を大きく受けています。)
https://qiita.com/tokkuman/items/aec887ff918fc164567e

ソースはGithubに公開しています。
https://github.com/naonaorange/sorting_deep_hat

動作環境

Deep Learingライブラリとしては、"Keras"を使っています。
  • Ubuntu 16.04 64bit
  • Python 3.6 64bit
  • Jupyter 4.4
  • Tensorflow 1.5
  • Keras 2.1.5
  • OpenCV 3.4

画像集め

映画内で各寮に入っているキャラクターの顔画像を集めます。
学習画像としては各寮100枚ずつの計400枚。
評価画像としては各寮20枚ずつの計80枚を準備しました。

データ集めはDeep Learingにおいて、一番重要で一番大変な作業なので、
他でも参考できるように別記事にします。

下の記事で簡単に説明しました。
「Bing Image Search APIでネット上の画像を集める」
http://kowaimononantenai.blogspot.jp/2018/03/bing-image-search-api.html


モデル作成

CNNで実装していきます。
最終的に全結合層で出力数を4にしています。
Deep Learingについて、始めたばかりなので、パラメータ等もっとよいものがあるのかもしれません。
from keras.models import Sequential
from keras.layers import Dense, Dropout, Flatten, Activation
from keras.layers import Conv2D, MaxPooling2D, ZeroPadding2D
from keras import optimizers
from keras.preprocessing.image import ImageDataGenerator
from keras.callbacks import EarlyStopping, CSVLogger
from keras import backend as K
import matplotlib.pyplot as plt
import numpy as np 


img_width = 100
img_height = 100
train_data_dir = 'data/train'
valid_data_dir = 'data/validation'

datagen = ImageDataGenerator(rescale = 1./255)

train_generator = datagen.flow_from_directory(directory=train_data_dir,
                                              target_size=(img_width,img_height),
                                              classes=['Glyffindor','Hufflpuff','Ravenclaw','Slytherin'],
                                              batch_size=16)

validation_generator = datagen.flow_from_directory(directory=valid_data_dir,
                                                   target_size=(img_width,img_height),
                                                   classes=['Glyffindor','Hufflpuff','Ravenclaw','Slytherin'],
                                                   batch_size=16)

model =Sequential()

model.add(Conv2D(32,(3,3), input_shape=(img_width, img_height, 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2,2)))

model.add(Conv2D(32,(3,3), input_shape=(img_width, img_height, 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2,2)))

model.add(Conv2D(64,(3,3), input_shape=(img_width, img_height, 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2,2)))

model.add(Flatten())
model.add(Dense(64))
model.add(Activation('relu'))
model.add(Dropout(0.5))
model.add(Dense(4))
model.add(Activation('softmax'))

model.summary()

model.compile(loss='categorical_crossentropy',optimizer='rmsprop',metrics=['accuracy'])

es = EarlyStopping(monitor='val_loss', patience=2)
training = model.fit_generator(generator=train_generator,
                               steps_per_epoch=400 // 16,
                               epochs=20,
                               validation_data=validation_generator,
                               validation_steps=80//16,
                               callbacks=[es])

model.save('models/sorting_deep_hat.h5')


精度確認

作ったモデルの精度を確認していきます。
最終的には、学習画像については約85%。評価画像については約73%の精度となっています。
まずはこの程度でしょうか。
引き続き精度向上のため変更していきます。

動作確認

任意の画像からOpenCVで顔画像を切り取り、作成したモデルで寮を判別します。
その結果に応じて、顔に矩形と寮名を描画します。
from keras.models import load_model
import cv2
import matplotlib.pyplot as plt
import numpy as np

model = load_model('models/sorting_deep_hat.h5')

image = cv2.imread('data/sample/harrypotter.jpg')

gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
faces = face_cascade.detectMultiScale(gray, 1.1, 3)

for (x, y, w, h) in faces:
    face_image = image[y:y+h, x:x+w]
    face_image = cv2.resize(face_image, (100, 100))
    
    b,g,r = cv2.split(image)
    i = cv2.merge([r,g,b])
    i = cv2.resize(i,(100, 100))
    i = np.array([i / 255.])
    
    house = np.argmax(model.predict(i))
    if house == 0:
        house_name = 'Glyffindor'
        color = (0, 0, 255)
    elif house == 1:
        house_name = 'Hufflpuff'
        color = (0, 255, 255)
    elif house == 2:
        house_name = 'Ravenclaw'
        color = (255, 0, 0)
    elif house == 3:
        house_name = 'Slytherin'
        color = (0, 255, 0) 
    
    cv2.rectangle(image, (x, y), (x + w, y + h), color, 2)
    cv2.putText(image, house_name, (x, y), cv2.FONT_HERSHEY_PLAIN, 2, color, 4)
    
plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
plt.show()

実際にハリーポッターの画像を入力してみると、こんな感じになりました。
きちんとハリーはグリフィンドールに判断されています。
マルフォイはスリザリン。

いろんな人を何枚か試しましたが、確かに間違えるときはありますが、それなりに判断しています。

いろんな人で試してみる

イチローはグリフィンドール。
確かに、勇気とか騎士道精神とかありそうですね。
トランプ大統領はレイブンクロー。
確かに、頭はいいからね!(スリザリンだと思ったのに。。。)
ジョブズはスリザリン。
ちょっと意外ですが、確かに「巧妙さ」とかはあるかなと、自伝を読んで感じました。


ガッキーはグリフィンドール。まあ、どの寮でもかわいいからOK!

参考サイト


2018/03/27

pyenvとpyenv-virtualenvのインストール

同一PCで複数のPythonのバージョンを使い分ける必要ができてしまったので、調べてみるとpyenvというものがあるそうです。
また、pyenv-virtualenvも使うと幸せになれるそうです。

簡単に説明すると、以下。
  • pyenv
同一PC内に複数のバージョンのPythonの共存させるソフト。
2系と3系とかのレベルではなく、3.5.2と3.6.4を共存させたりできる。
  • pyenv-virtualenv
pyenvを使いやすくするためのソフト。
virtualenvとは別物(かなりややこしい。ネットでは一緒のものとして誤って説明されていたりするのでググるときには要注意!!)
pyenvだけでも使えるが、pyenv-virtualenvを使うことで何が嬉しいかというと。。。

(以下、URLからの引用)
https://qiita.com/maskedw/items/aaa2fd7abfd493cf2820
pyenv-virtualenvはpyenvのプラグインです。pyenvでは複数のPythonバージョンをインストールできますが、各Pythonバージョンのモジュールを管理するsite-packagesというディレクトリは共通です。pyenv-virtualenvを使用すると同じPythonバージョンで別々のsite-packagesを管理することができます。
開発中のアプリーケーションで使用しているモジュールのバージョンを全て固定したり、必要最小限だけのモジュールをインストールしたりすることによって、開発環境と実行環境の違いを最小限にすることができます。



pyenvのインストール

基本的にGithubのREADMEと同じです。
https://github.com/pyenv/pyenv
gitから持ってきます(pipでインストールできればいいのに。。。)
git clone https://github.com/pyenv/pyenv.git ~/.pyenv
次に、設定をしていきます。
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bashrc
echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bashrc
echo -e 'if command -v pyenv 1>/dev/null 2>&1; then\n  eval "$(pyenv init -)"\nfi' >> ~/.bashrc
pyenvコマンドを実行して使えるかどうかを確認してください。

pyenv-virtualenvのインストール

こちらもGithubの説明と同様です。
https://github.com/pyenv/pyenv-virtualenv
git clone https://github.com/pyenv/pyenv-virtualenv.git ~/.pyenv/plugins/pyenv-virtualenv
echo 'eval "$(pyenv virtualenv-init -)"' >> ~/.bash_profile

使い方

#Pythonのコンパイルに必要なライブラリ軍をまずはインストール
sudo apt-get install git gcc make openssl libssl-dev libbz2-dev libreadline-dev libsqlite3-dev

#pyenvでインストールできるバージョンの確認
pyenv install --list
#使用するバージョンのPythonをコンパイル
pyenv install 3.6.4

#仮想環境を作成
#ENV_NAMEは仮想環境の名前を入れます
pyenv virtualenv 3.6.4 ENV_NAME

#現在ある仮想環境を確認
pyenv virtualenvs

#仮想環境の有効化、無効化
pyenv activate ENV_NAME
pyenv deactivate

#仮想環境の削除
pyenv uninstall ENV_NAME

参考にしたサイト

https://qiita.com/akito1986/items/be5dcd1a502aaf22010b

2018/03/23

Jupyter Notebookを起動するとAttributeError: type object 'IOLoop' has no attribute 'initialized'とエラーが出る

Jupyterをインストール後、Jupyter Notebookを起動すると、下記のようなエラーが出てしまいます。

AttributeError: type object 'IOLoop' has no attribute 'initialized'

GitHubにはissueがすでに上がっているそうで、
https://github.com/ipython/ipython/issues/8374

下記コマンドを実行して、tornadoというソフトをダウングレードすることで、一時的に回避できるそうです。
pip3 uninstall tornado
pip3 install tornado==4.5.3

2018/03/21

Tensorflowが"Illegal instruction (コアダンプ)"で動かない

Tensorflowをインストールして実行しようとしたところ、エラーで動かなくなってしまいました。
Python 3.5.2 (default, Nov 23 2017, 16:37:01) 
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import tensorflow as tf
Illegal instruction (コアダンプ)
環境は下記です。
  • Tensorflow 1.6
  • Python 3.5
原因はよくわかっていませんが、一応TensorflowのVerを1.5にすることでエラーが出なくなりました。
(Ver 1.5.1では同様のエラーが出てしまいました。)
とりあえずはこれでやっていきます。
pip uninstall tensorflow tensorflow-tensorboard
pip install tensorflow==1.5

2018/01/26

Galaxy S7 Edge SC-02H をAndroid6にダウングレード

Galaxy S7 Edge SC-02HをAndroid6にダウングレードしてみました。

ROMを書き込むにはOdinを使用するので、ダウンロードします。
現時点での最新3.12.3をとってきました。
https://samsungodin.com/

次にSC-02H用Android6のROMをダウンロードし、展開しておきます。
下記URLのStock ODIN firmwareを落とします。
https://forum.xda-developers.com/s7-edge/samsung-galaxy-s7-edge-snapdragon-roms-kernels-recoveries--other-development/rom-kernel-twrp-snapdragon-sm-g935d-t3540431

次はGalaxy S7 Edgeの設定です。
  1. 開発者モード内のOEMロック解除をON
  2. 一度電源を切り、電源ボタン+音量下ボタン+ホームボタンを同時長押ししてDownloadモードで起動
  3. 注意事項を読み、音量上ボタンで承諾
  4. USBでPCとつなぐ
  5. Galaxy S7 Edgeが認識されたか(ドライバは入ったか)確認
次に、Odinを起動します。
ログ画面に"Added."と出力されていれば、スマホが認識されています。

Odinの画面の右側に"BL"、"AP"、"CP"、"CSC"の入力欄があります。そこにダウンロードしたROMファイルの先頭の名前が対応するように選択していきます。
(APなどの容量の大きいファイルを選択した際には、認識までに時間がかかるので、待ちます。)

次に"Start"を押します。

これでOKです。
しばらく待つと、スマホが自動的に再起動して、初期設定画面になります。

参考にしたサイト
http://reviewdays.com/archives/56765

2017/11/25

pybluezを利用すると"untimeError: Channel or attrib not ready"とエラーになる

pybluezをインストールしたので、サンプルなどを動作させようとしたのですが、、、
https://github.com/karulis/pybluez/tree/master/examples/ble
"read_name.py"を実行したのですが、下記のエラーで動作しません。
Connecting... Traceback (most recent call last):
  File "read_name.py", line 41, in 
    Reader("C7:7A:98:EA:17:17")
  File "read_name.py", line 16, in __init__
    self.connect()
  File "read_name.py", line 23, in connect
    self.requester.connect(True)
RuntimeError: Channel or attrib not ready
エラー名でぐぐってみると、gattlibが古いことが原因かもしれないと書いてあるので、
https://github.com/ev3dev/ev3dev/issues/775
pybluez, pygattlibともにソースからインストールしましたが、現状変わりません。
https://github.com/karulis/pybluez
https://bitbucket.org/OscarAcena/pygattlib
(というか、pygattlibは2年更新があまり無いですね。。。)

解決したら、また記事にする予定ですが、一応pybluez以外も試してみます。。。


2017/10/31

Choregrapheで独自ライブラリの作成方法

Choregrapheで分散開発を行う時に、各モジュールを「ボックスライブラリ」として分割することで、
各人でモジュールごとに開発して、別プロジェクトで利用することができます。

今回は例として"hello"というボックスライブラリを新規作成して、別プロジェクトに持っていき、実行してみます。

"Hello"というプロジェクトを新規作成して、サンプルとしてsayボックスを配置します。

次に全ボックスを選択し、右クリック->ボックスに変換 を行います。
このようにすることで、複数あるボックスを1つにまとめることができます。
今回は"Hello"というボックス名としました。

次に空のボックスライブラリを作成します。
下記画面部で新規作成します。
今回は"Hello"というライブラリ名にしました。
cblという拡張子で保存します。

ボックスライブラリはできました。
しかし、中身が空なので展開等はできません。


次に、先ほど1つのボックスにした"Hello"ボックスを"Hello"ボックスライブラリにドラッグ&ドロップします。そして、ボックスライブラリを保存します。
これで、"Hello"という独自ボックスを他のプロジェクトでも利用できるようになります。

次は、独自ボックスを利用したいプロジェクトでの利用方法です。
"Main"というプロジェクトを新規作成します。
次に、「ボックスライブラリを開く」で"Hello.cbl"を選択します。
このようにすることで、利用側でも"Hello"ボックスを使うことができるようになります。
利用方法は他のボックスと同じです。

参考にしたサイト
https://qiita.com/Atelier-Akihabara/items/db907ed319b8af0984db

https://qiita.com/ForexRobotics/items/5258892f1588319d0204

2017/09/04

Ubuntuにpybluezをインストール

UbuntuでBLEアプリを開発するので、pybluezをインストールします。

まずは、BlueZをインストールします。
ネットでは、ソースコードをコンパイルしている記事が多いですが、apt-getでインストールしたものでも動作確認できました。
sudo apt-get install bluez
次は、pybluezをインストールしていきます。
これもapt-getで入れてみたんですが、pythonで使おうとすると、「bluetooth.bleパッケージがない」と怒られてしまいます。。。

pipでインストールすると、bluetooth.bleパッケージができました。
(apt-getでもpipでもどちらでも0.22が入るはずなので、同じだろうと思うのですが、
実際にはpipではbleパッケージが追加されていました。)
pip install pybluez
pipでインストールにエラーが出てしまう場合は、下記のサイトのトラブルシューティングで解決できました。
http://qiita.com/dz_/items/4e858e4d50db19b57491

2017/08/21

PCE-AC55BTを購入しました

Bluetooth Low Energyを利用したソフトの開発を行うにあたって、デスクトップPCにBluetoothがついていなかったので、PCI Expressで拡張しました。

USBドングルでも拡張できますが、ほとんどがBluetooth 4.0までしか対応していないですし、ものによって動作の安定性が異なるのでPCI Expressでの拡張を行いました。

実際に取り付けたかったのは「Intel Dual Band Wireless-AC8260」.。
https://www.intel.com/content/dam/www/public/us/en/documents/product-briefs/dual-band-wireless-ac-8260-brief.pdf

アマゾンでも単体で売っていますが、m2をPCI Expressに変換するものを別途買う必要があります。

そこで注目したのが、PCE-AC55BTです。PCI Expressへの変換ボードも含めて売られています。
http://akiba-pc.watch.impress.co.jp/docs/news/news/1063334.html

こちらもアマゾンでも見つけたんですが。。。
https://www.amazon.co.jp/gp/product/B071PDKP7F/ref=oh_aui_detailpage_o00_s00?ie=UTF8&psc=1

ん!?
画像がちょっと違うくね!?
端子がmini PCI Expressじゃね?
説明にもBluetooth 4.0ってかいてね?
しかも、ついてんの「Intel Dual Band Wireless-AC 7260」じゃね!??


詳しく調べると、今までは7260がついていたのですが、最近8260がついた新モデルが出たらしい。
だけど、どちらも同じ型番なので区別がつかない。。。

一か八かでアマゾンから買ってみました。

届いたのを見てみるとアマゾンの画像のものではなく、記事と同じもの。
8260がついていて、Bluetooth 4.2まで対応と書いていました。


おー。よかった。
これからUWPやXamarinでBLEアプリケーションを開発していきます!

2017/08/13

global::System.Diagnostics.Debugger.Breakdeでデバッグが止まったら・・・

UWPでサンプルプログラムを作成したとき、次の下記の位置でデバッグが停止してしまいました。。。
ちなみに、環境は、
  • Windows 10 64bit
  • Visual Studio 2015 Express
  • UWPアプリケーション
  • NugetでPrism.Unityをインストール済み
if (global::System.Diagnostics.Debugger.IsAttached) global::System.Diagnostics.Debugger.Break();


そこで、エラーとなっている内容を確認すると、、、
Could not load file or assembly 'System.Runtime.WindowsRuntime, Version=4.0.11.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)

どうやら、WindowsRuntimeのバージョンが悪いそうです。
また、ビルドしたとき下記のWarningも出ています。
Warning        Detected package downgrade: Microsoft.NETCore.UniversalWindowsPlatform from 5.2.2 to 5.1.0
 uwp_sample (>= 1.0.0) -> Prism.Unity (>= 6.3.0) -> Prism.Windows (>= 6.3.0) -> Microsoft.NETCore.UniversalWindowsPlatform (>= 5.2.2)
 uwp_sample (>= 1.0.0) -> Microsoft.NETCore.UniversalWindowsPlatform (>= 5.1.0)            0   
そこで、NugetでMicrosoft.NETCore.UniversalWindowsPlattformのバージョンを5.1.0→5.2.2にへんこうしたら、デバッグで止まらなくなりました。
本当は最新の5.4.0にしたかったんですが、VisualStudio2017のみそうだったので、5.2.2で、