メインコンテンツまでスキップ

「機械学習」タグの記事が3件件あります

全てのタグを見る

· 約6分
moritalous
お知らせ

過去にQiitaに投稿した内容のアーカイブです。

[2018/9/2更新]


俺とか言ってごめんなさい。

MNISTを元に学習したモデルを使って、私の文字を認識させました。 全部ちゃんと認識できるんですよね?

ルール

  • 正しく認識する
    →MNISTの勝ち
  • 正しく認識しない
    →私の勝ち(字がヘタって言われている気もしますが。。)

学習モデルの生成

kerasにサンプルコードがあったのでそのまま利用。

mnist_cnn.py https://github.com/keras-team/keras/blob/master/examples/mnist_cnn.py

生成したモデルを保存する1行だけ追加しました。

model.save('mnist_model.h5')

学習結果はこちら。見方はよくわかりません。99%正解するってことでしょうか。 詳しい人ヘルプ!

  from ._conv import register_converters as _register_converters
Using TensorFlow backend.
x_train shape: (60000, 28, 28, 1)
60000 train samples
10000 test samples
Train on 60000 samples, validate on 10000 samples
Epoch 1/12
60000/60000 [==============================] - 513s 9ms/step - loss: 0.2750 - acc: 0.9163 - val_loss: 0.0586 - val_acc: 0.9806
Epoch 2/12
60000/60000 [==============================] - 559s 9ms/step - loss: 0.0894 - acc: 0.9734 - val_loss: 0.0464 - val_acc: 0.9850
Epoch 3/12
60000/60000 [==============================] - 688s 11ms/step - loss: 0.0658 - acc: 0.9803 - val_loss: 0.0370 - val_acc: 0.9880
Epoch 4/12
60000/60000 [==============================] - 688s 11ms/step - loss: 0.0542 - acc: 0.9834 - val_loss: 0.0309 - val_acc: 0.9895
Epoch 5/12
60000/60000 [==============================] - 693s 12ms/step - loss: 0.0464 - acc: 0.9858 - val_loss: 0.0318 - val_acc: 0.9889
Epoch 6/12
60000/60000 [==============================] - 674s 11ms/step - loss: 0.0417 - acc: 0.9874 - val_loss: 0.0294 - val_acc: 0.9903
Epoch 7/12
60000/60000 [==============================] - 654s 11ms/step - loss: 0.0365 - acc: 0.9889 - val_loss: 0.0292 - val_acc: 0.9900
Epoch 8/12
60000/60000 [==============================] - 665s 11ms/step - loss: 0.0345 - acc: 0.9893 - val_loss: 0.0287 - val_acc: 0.9908
Epoch 9/12
60000/60000 [==============================] - 772s 13ms/step - loss: 0.0322 - acc: 0.9902 - val_loss: 0.0270 - val_acc: 0.9910
Epoch 10/12
60000/60000 [==============================] - 684s 11ms/step - loss: 0.0306 - acc: 0.9907 - val_loss: 0.0295 - val_acc: 0.9908
Epoch 11/12
60000/60000 [==============================] - 748s 12ms/step - loss: 0.0282 - acc: 0.9912 - val_loss: 0.0272 - val_acc: 0.9911
Epoch 12/12
60000/60000 [==============================] - 657s 11ms/step - loss: 0.0259 - acc: 0.9918 - val_loss: 0.0252 - val_acc: 0.9916
Test loss: 0.025242764521988738
Test accuracy: 0.9916

予測

以下のコードにて、予測させました。features.argmax()を予測した文字としてます。

## coding:utf-8

import keras
import numpy as np
from keras.models import load_model
from keras.preprocessing.image import array_to_img, img_to_array,load_img
import os
import re

model = load_model('mnist_model.h5')

def list_pictures(directory, ext='jpg|jpeg|bmp|png|ppm'):
return [os.path.join(root, f)
for root, _, files in os.walk(directory) for f in files
if re.match(r'([\w]+\.(?:' + ext + '))', f.lower())]

for picture in list_pictures('./tegaki/'):
X = []
img = img_to_array(
load_img(picture, target_size=(28, 28), grayscale=True))
X.append(img)

X = np.asarray(X)
X = X.astype('float32')
X = X / 255.0

features = model.predict(X)

print('----------')
print(picture)
print(features.argmax())
print('----------')

手書き文字の作成

iPadのGoogle Keepアプリで手書きのメモを作成。pngになったファイルを取得。こんな感じ。

スクリーンショット (304).png

MNISTの画像は黒背景に白文字のようなので、ペイントで加工しました。

Windows 7のペイントで画像の色を反転させる方法 https://121ware.com/qasearch/1007/app/servlet/relatedqa?QID=013654

画像のサイズは1694x2048ですがload_imgのときに画像サイズを変更しているので、そのまま利用しました。

試合開始

手書き画像予測結果勝敗
1.png1MNISTの勝ち
2.png2MNISTの勝ち
3.png3MNISTの勝ち
4.png4MNISTの勝ち
5.png5MNISTの勝ち
6.png6MNISTの勝ち
7.png1私の勝ち
8.png5私の勝ち
9.png4私の勝ち

試合結果

6勝3敗でMNISTの勝ち~ でも、3勝もしちゃった。。。 (7と1、8と5、9と4が似てると言われれば似てるような気もしますが。)

試しに画像を予めペイントで28x28にして試しても結果は同じでした。ちゃんと読めますよね?

スクリーンショット (307).png

モデル生成のソースコードに(there is still a lot of margin for parameter tuning).とあるので、もっとすごいモデルを使わないといけないのかな?

終わりに

あれ、こんなもん? 「ディープラーニングで行うペン習字講座」を期待したのですが先は遠そうです。 まずは「MNISTに勝たせる7の書き方講座」からですね。

· 約6分
moritalous
お知らせ

過去にQiitaに投稿した内容のアーカイブです。

前回 は失敗してしまいましたが、試行錯誤の上、上手く識別できるようになりました。 試行錯誤の軌跡を残します。

今回もこれ! 68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f34313537342f37326136333766332d653430372d356363342d643166302d3633393963396131316138632e706e67.png

画像の水増し

前回使用した画像は全部で400枚(正常200枚、異常200枚)でした。画像が少なすぎるのかと思い、画像を増やすことにしました。Kerasに便利な機能がありました。

自前のDeep Learning用のデータセットを拡張して水増しする https://qiita.com/halspring/items/7692504afcba97ece249

画像の前処理 - Keras Documentation https://keras.io/ja/preprocessing/image/

参考にしたサイトほぼそのままですが、今回のキッチンばかりの場合、画像の角度が重要だと考え、画像の回転はしないようにしました。

パラメーター設定値
rotation_rangeコメントアウト
horizontal_flipFalse
vertical_flipFalse
    # 拡張する際の設定
generator = ImageDataGenerator(
# rotation_range=90, # 90°まで回転
width_shift_range=0.1, # 水平方向にランダムでシフト
height_shift_range=0.1, # 垂直方向にランダムでシフト
channel_shift_range=50.0, # 色調をランダム変更
shear_range=0.39, # 斜め方向(pi/8まで)に引っ張る
horizontal_flip=False, # 垂直方向にランダムで反転
vertical_flip=False # 水平方向にランダムで反転
)

この方法で画像を10倍の4000枚(正常2000枚、異常2000枚)にすることができました。

スクリーンショット (298).png

モデルのパラメーターの変更

Kerasのドキュメントを眺めて、今回の問題は「イヌ」「ネコ」「ゾウ」のように複数に分けるのではなく、「正常値」「異常値」の2つに分類するだけの問題だと気づきました。

Sequentialモデルのガイド - Keras Documentation https://keras.io/ja/getting-started/sequential-model-guide/

## マルチクラス分類問題の場合
model.compile(optimizer='rmsprop',
loss='categorical_crossentropy',
metrics=['accuracy'])
## 2値分類問題の場合
model.compile(optimizer='rmsprop',
loss='binary_crossentropy',
metrics=['accuracy'])
## 前回のコード(参考元のコピペです)
model.compile(loss='categorical_crossentropy',
optimizer='SGD',
metrics=['accuracy'])

真ん中の「2値分類問題」のコードに変更しました。 optimizerの意味は勉強します。

Optimizer : 深層学習における勾配法について https://qiita.com/tokkuman/items/1944c00415d129ca0ee9

画像のグレースケール化

水増しした画像を見たときに、今回の問題は色情報は関係ないと思いました。 これもKerasで簡単にできました。(すごいね、Keras!!)

img = img_to_array(load_img(picture, target_size=(224,224), grayscale=True))

グレースケールにすることで、色情報がRGBの3から1になるので、input_shapeを追加で指定する必要があります。(指定なしだと3扱いなのかな?)

model = MobileNet(include_top=True, weights=None, classes=2,input_shape=(224, 224, 1))

モデルの変更(今回は不採用)

モデルを変えると結果も変わるのかなと思って試したのですが、Raspberry Pi Zeroで予測させようとすると、メモリ不足で動作させることができませんでした。感覚がわかりませんが、Raspberry Pi Zeroの512MBのメモリで動作するって、すごいことなのでしょうね。

予測

画像結果
1.jpg[[9.9999988e-01 1.2415921e-07]]
200g以下!

正解!
2.jpg[[1.0000000e+00 5.4107854e-08]]
200g以下!

正解!
3.jpg[[8.696176e-06 9.999913e-01]]
200g以上

正解!
4.jpg[[7.8308704e-10 1.0000000e+00]]
200g以上!

正解!
5.jpg[[4.8343203e-08 1.0000000e+00]]
200g以上!

正解!
6.jpg[[1.0000000e+00 1.5057713e-08]]
200g以下!

不正解!
(キッチンばかりの裏側)
想定外の画像のときってどうすればいいんだろう

予測のソース

## coding:utf-8

from time import sleep

from keras.applications import mobilenet

from keras.models import load_model
from keras.preprocessing import image
from keras.preprocessing.image import img_to_array, load_img
import numpy as np
from keras.utils import np_utils

model = load_model('0212_my_model_0216.h5', custom_objects={
'relu6': mobilenet.relu6,
'DepthwiseConv2D': mobilenet.DepthwiseConv2D})

while True:
X = []

picture = '/home/pi/motion/capture/lastsnap.jpg'
img = img_to_array(load_img(picture, target_size=(224, 224), grayscale=True))
X.append(img)

X = np.asarray(X)
X = X.astype('float32')
X = X / 255.0

features = model.predict(X)

print(features)
if features[0][0] > features[0][1]:
print('200g以下!')
else:
print('200g以上!')

sleep(5)

終わりに

なんとか上手く分類させることができました。 ただ、閾値を200gから300gに変えたくなったらもう一回学習させないといけないのかな? 「マルチクラス分類」にすればいいのかな?

おまけ

予測に使った画像と予測結果をLINE Notifyで通知したら、なんか、やったった感。

スクリーンショット (300).png

PythonからLINE NotifyでLINEにメッセージを送る https://qiita.com/tadaken3/items/0998c18df11d4a1c7427

· 約8分
moritalous
お知らせ

過去にQiitaに投稿した内容のアーカイブです。

ディープラーニングの本をいくつか読んだけど、いまいちピンとこない。 技術的にすごいことはわかったけど、で?って感じでした。 画像認識したかったらAmazon Rekognitionとか使えばいいんでしょ?自分でディープラーニングすることなくない?と思ってました。

手を動かすことにしました。 →上手くいかなかった。。原因をだれか、教えて!!

題材

ダイソーで秤を買いました。 メモリが200g以下になったことを検知して「もうすぐ無くなるよ!」と言えれば、何かと役に立つのではないかと考えました。

スクリーンショット (294).png

画像の取得

画像はRaspberry Pi Zero にUSBカメラ(Logicool C200)をつけて撮りました。

環境セットアップ

Raspberry Pi でカメラ https://qiita.com/suppy193/items/e9faedbc268d439bd02b を参考に、インストールとmotion.confを変更。起動はこちらの方法で行いました。

sudo motion -n

起動後、http://xxx.xxx.xxx.xxx:8080にアクセスし、以下の設定を変えました。

設定項目変更後の値
target_dir/home/pi/motion
text_right(not defined)
text_event(not defined)
snapshot_interval1

設定変更は即時反映のようです。 こうして1秒間隔で画像を取得しました。

取得した画像

秤のうえに牛乳パックをおいて、水をチョロチョロいてれるところを1秒間隔でキャプチャ。 こんな感じです。

スクリーンショット (296).png

200g以下の画像を200枚、200g以上の画像を200枚ほど用意しました。

学習

Kerasを使いました。主にこちらを参考にしました。

kerasでCNN 自分で拾った画像でやってみる https://qiita.com/haru1977/items/17833e508fe07c004119

モデルもそのまま参考にしても良かったのですが、何がなんやらわからなかったので、Kerasが予め対応している有名なモデルをそのまま使うことにしました。Googleの人が作ったものだとすごいんでしょ的な発想でMobileNetを選びました。

利用可能なモデル https://keras.io/ja/applications/

また、作ったモデルを保存しました。

Keras modelを保存するには? https://keras.io/ja/getting-started/faq/#keras-model

できたコードがこちら

0212_train.py
## coding:utf-8

from keras.applications.mobilenet import MobileNet

from keras.preprocessing import image
from keras.preprocessing.image import array_to_img, img_to_array, list_pictures, load_img
import numpy as np
from keras.utils import np_utils
from sklearn.model_selection import train_test_split

X = []
Y = []

## 対象Aの画像
for picture in list_pictures('./test0212_1_50/'):
img = img_to_array(load_img(picture, target_size=(224,224)))
X.append(img)

Y.append(0)

## 対象Bの画像
for picture in list_pictures('./test0212_2_100/'):
img = img_to_array(load_img(picture, target_size=(224,224)))
X.append(img)

Y.append(1)

## arrayに変換
X = np.asarray(X)
Y = np.asarray(Y)

## 画素値を0から1の範囲に変換
X = X.astype('float32')
X = X / 255.0

## クラスの形式を変換
Y = np_utils.to_categorical(Y, 2)

## 学習用データとテストデータ
X_train, X_test, y_train, y_test = train_test_split(X, Y, test_size=0.33, random_state=111)

## MobileNetのモデルを利用
model = MobileNet(include_top=True, weights=None, classes=2)

## コンパイル
model.compile(loss='categorical_crossentropy',
optimizer='SGD',
metrics=['accuracy'])

## 学習
history = model.fit(X_train, y_train, epochs=15,
validation_data = (X_test, y_test), verbose = 1)

filepath = '0212_my_model.h5'
model.save(filepath)

学習開始!

python -m 0212_train

処理が終わるとモデルが出来上がります。

躓いた点1「ファイル名問題」

画像のファイル名に-があるとだめでした。-はファイル名に使えないってそういうもんなんでしょうか?-_に一括置換して対処しました。

ファイル名を一括置換するワンライナー https://qiita.com/goking/items/ff6ea22a4b5559d30896

ls -1 *.jpg | awk '{print;gsub(/-/,"_");print}' | xargs -n 2 mv

躓いた点2「パソコンスペック低すぎ問題」

書くのも恥ずかしいスペックのパソコンしか持ってないので、学習にすごーーーーく時間がかかりました。 正確には、時間がかかりそうだったので途中でやめました。 ちょうど見つけた以下の内容を参考にColaboratoryを使いました。するとあっという間に終わりました。すごい、GPU!!

【秒速で無料GPUを使う】深層学習実践Tips on Colaboratory https://qiita.com/tomo_makes/items/b3c60b10f7b25a0a5935

予測

Raspberyy Pi zeroにkerasとTensorFlowをインストールしようとしましたが、pip install kerasでは時間がめっちゃかかるのとエラーになっちゃいました。調べると、ビルド済みのものがあるようなので、そちらを利用することにしました。

RasPiでKeras/TensorFlowを動かす https://qiita.com/kazunori279/items/1e23679c534a49c0e837

http://ci.tensorflow.org/view/Nightly/ にあるnightly-pi-zero-python3の成果物tensorflow-1.6.0rc0-cp34-none-any.whlを使うことにしました。

その先のインストールが結構手間取ったので、正しい手順が示せません。。

ソースはこちら

0212_predict.py
## coding:utf-8

from time import sleep

from keras.applications import mobilenet

from keras.models import load_model
from keras.preprocessing import image
from keras.preprocessing.image import img_to_array, load_img
import numpy as np
from keras.utils import np_utils

model = load_model('0212_my_model.h5', custom_objects={
'relu6': mobilenet.relu6,
'DepthwiseConv2D': mobilenet.DepthwiseConv2D})

while True:
X = []

picture = '/home/pi/motion/lastsnap.jpg'
img = img_to_array(load_img(picture, target_size=(224, 224)))
X.append(img)

X = np.asarray(X)
X = X.astype('float32')
X = X / 255.0

features = model.predict(X)

print(features)

if features[0][0] > 0.5:
print('水が減っています! (' + str(features[0][0]) + ')')
else:
print('水は十分あります! (' + str(features[0][0]) + ')')

sleep(60)

予測結果

失敗。。。 ものをおいても、置かなくても「水が減っています!」

(venv) pi@pizero:~/motion/python/project $ python -m 0212_predict
Using TensorFlow backend.
[[1.000000e+00 5.362379e-25]]
水が減っています! (1.0)
[[1.000000e+00 6.591085e-25]]
水が減っています! (1.0)
[[1.0000000e+00 6.2064603e-25]]
水が減っています! (1.0)
[[1.000000e+00 6.305497e-25]]
水が減っています! (1.0)
[[1.0000000e+00 1.2839705e-24]]
水が減っています! (1.0)

終わりに

ダイソーの秤が200g以下かどうかは、残念ながらAmazon Rekognitionではわかりません。 クラウドが提供しているものはあくまで汎用的な画像認識。 クラウドのAPIでできない画像認識/分類をしたければ、自分でモデルを作らなくちゃいけない。逆にモデルさえ作っちゃえば、世界にひとつだけの、画像認識システムができるんですね。 失敗しちゃったけど。。。