Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Python初心者がKerasで画像判別をやってみた

3,455 views

Published on

自分で収集した画像(リンゴとバナナ)を使ってKerasの簡単なコーディングで学習&判別させるまでの内容。コード解説メイン

Published in: Technology
  • You can ask here for a help. They helped me a lot an i`m highly satisfied with quality of work done. I can promise you 100% un-plagiarized text and good experts there. Use with pleasure! ⇒ www.HelpWriting.net ⇐
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here

Python初心者がKerasで画像判別をやってみた

  1. 1. Python初心者がKerasで 画像判別をやってみた
  2. 2. • 甲斐 研造(Ka-k) 名前 • 福岡県産業・科学技術振興財団(ふくおかIST) • システム開発技術カレッジ事務局 所属 • ゲーム、イラスト 趣味 • 色彩検定1級 • パーソナルカラー検定モジュール3 特技 自己紹介 大分県のマスコット めじろん
  3. 3. こういうことやってます 主に技術者さん、技術を学びたい人向けに、ハンズオン or 勉強会形式で実施している少人数制の企画 CONNPASS上でグループ運営しています URL:https://tech-cafe.connpass.com/
  4. 4. おしながき 前置き Kerasとは まずはMNISTチュートリアル 自分で集めた画像でやってみる 画像をたくさん集める まとめ
  5. 5. 前置き
  6. 6. モチベーション 君たちの部署でAI関連 の講座つくって ぼく 偉い人 先生探して講座 やってってお願い すればいいから
  7. 7. モチベーション AI講座ってなんやねん 定義広すぎやろ 自分たちがこういうこ としたいってのないと 交渉できんやろ ディープラーニング… ディープラーニング??? いろいろ調べた結果 Pythonを使うと簡単 に実装できるらしい? じゃあ、試しに自分 でやってみよう
  8. 8. じゃあ、自分でやってみよう
  9. 9. それが間違いのはじまりだっ た・・・
  10. 10. Pythonってなにさ? • Linux系でよく使われているスクリプト言語 • 構文ルールが厳格でコードが綺麗なので読みやすいと評判 • 一方でコードの書き方に自由度がないので受けつけない人もい るらしい • データ分析業界ではR言語とシェアを分ける主流の言語
  11. 11. Pythonで深層学習? • AIの実装で使われている言語はPythonが多い • スクリプト言語としては高速 • データサイエンティストさんの主要言語 • TensorFlow等のライブラリが充実 • AI開発の主流言語になったから 考えられる理由
  12. 12. AIと機械学習と深層学習 AI(人工知能) マシンラーニン グ(機械学習) ディープラーニ ング(深層学 習) マシンラーニング(機械学習)はAIに判断材料を学習 させる手法の一つ。ディープラーニング(深層学習) はさらにそのうちの1ジャンル DLとDL以外のMLの違いは、「隠れ層(中間層)」を 持つかどうか、とのこと コンピュータが学習した結果によって、未知の事象に 対しても応用して対応できるようになる仕組み AI(人工知能)
  13. 13. TensorFlowって? • 読み方は「テンソルフロー」。 • Googleが提供している機械学習ライブラリ • 自分で1からコーディングしなくてもDLモデルを構築できる • CPUだけじゃなくてGPUも使える テンソル 出典: フリー百科事典『ウィキペディア(Wikipedia)』 ナビゲーションに移動検索に移動 テンソル(英: tensor, 独: Tensor)とは、線形的な量または線形的な幾何概念を一般化したもので、基底を選べば、多次元の配列として表現できるようなも のである。しかし、テンソル自身は、特定の座標系によらないで定まる対象である。個々のテンソルについて、対応する量を記述するのに必要な配列の添 字の組の数は、そのテンソルの階数とよばれる。 例えば、質量や温度などのスカラー量は階数0のテンソルだと理解される。同様にして力や運動量などのベクトル的な量は階数1のテンソルであり、力や加 速度ベクトルの間の異方的な関係などをあらわす線型変換は階数2のテンソルで表される。 物理学や工学においてしばしば「テンソル」と呼ばれているものは、実際には位置や時刻を引数としテンソル量を返す関数である「テンソル場」であるこ とに注意しなければならない。いずれにせよテンソル場の理解のためにはテンソルそのものの概念の理解が不可欠である。
  14. 14. ・・・TensorFlow難しくね? # データのインポート from tensorflow.examples.tutorials.mnist import input_data import tensorflow as tf mnist = input_data.read_data_sets("/tmp/data/", one_hot=True) sess = tf.InteractiveSession() # モデルの作成 x = tf.placeholder(tf.float32, [None, 784]) W = tf.Variable(tf.zeros([784, 10])) b = tf.Variable(tf.zeros([10])) y = tf.nn.softmax(tf.matmul(x, W) + b) # 損失とオプティマイザーを定義 y_ = tf.placeholder(tf.float32, [None, 10]) cross_entropy = -tf.reduce_sum(y_ * tf.log(y)) train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy) # 訓練 tf.initialize_all_variables().run() for i in range(1000): batch_xs, batch_ys = mnist.train.next_batch(100) train_step.run({x: batch_xs, y_: batch_ys}) # 訓練モデルのテスト correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1)) accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32)) print(accuracy.eval({x: mnist.test.images, y_: mnist.test.labels})) 入門者向けのMNISTチュートリアルのコード例 http://tensorflow.classcat.com/2016/03/09/tensorflow-cc- mnist-for-ml-beginners/ 引用元 このコードをすっと理解できる人には、 以降の内容は不要だと思います
  15. 15. Kerasとは
  16. 16. Kerasとは ディープラーニング用のライブラリ バックエンドでTheano(テアノ)やTensorFlow等が動く (公式はTensorFlow推奨) 直感的に記述できる反面、処理そのものはブラックボックス (裏でTensorFlow等がどう動いているかは可視化されない) 要するに、(主に)TensorFlowを操作するためのインターフェース的なもの 読み方は「ケラス」
  17. 17. Kerasのいいところ そもそもTensorFlowのチュートリアルがKeras前提になってる model = Sequential(dense(units, input_shape(batch_size, input_dim)), Activation(“softmax”)) 例えば全結合層を1層書きたいとき これで1層分書けてしまう 入力 畳み込み層 • Relu プーリング 層 全結合層 • Softmax 出力 Conv2d() Activation(“Relu”) Maxpooling2d() Dense() Activation(“Softmax”) Kerasでの記述 DLのフロー図 理論とコードが一致しているので直感的に理解しやすい コードが簡単
  18. 18. ここから本題 Kerasを触ってみる
  19. 19. まずはMNISTチュートリアル
  20. 20. MNISTとは ・0~9の手書き数字のデータセット ・60,000の訓練用データと10,000のテスト用データ ・それに対応したラベルセット ・Kerasには内包されているので、importで呼び出せる ディープラーニング界の「Hallo World!」 こういうデータがたくさん入っている
  21. 21. コーディング 1 • MNISTデータセットの読み込み 2 • データセットをKerasで使えるように加工 3 • ディープラーニングモデルの構築 4 • 学習の実行 5 • 学習結果の評価 ・Kerasでは0~1の値の1次元配列しか扱えない ・ラベルは、バイナリデータしか扱えない モデルの構築と、実際の学習が別々の命令に分 かれている 今回は正解率(acc)と、グラフによって可視化 チュートリアルなので構成の説明だけ・・・
  22. 22. コーディング from keras.datasets import mnist from keras.models import Sequential from keras.layers.core import Dense, Activation from keras.utils import np_utils # MNISTデータのダウンロード # MNISTは60,000件の訓練用データと10,000件のテストデータを持つ # (a, b), (c, d) 2セットのタプル # a,c:shape(num_samples,28,28)の白黒画像uint8配列 # b,d:shape(num_samples,)のカテゴリラベル(1~9)のuint8配列を戻り値として返す (X_train, y_train),(X_test, y_test) = mnist.load_data() 1 必要なライブラリの読み込み+データセットの読み込み
  23. 23. コーディング # X_train,X_testは28×28(0~255の値を持つ)の2次元配列なので、1次元配列に変換 # 0~1の値じゃないと扱えないので、255で割って0~1の範囲の値に変換 X_train = X_train.reshape(60000, 784) / 255 X_test = X_test.reshape(10000, 784) / 255 # カテゴリラベルをバイナリのダミー変数に変換する y_train = np_utils.to_categorical(y_train) y_test = np_utils.to_categorical(y_test) 2 データセットをKerasで使えるように加工
  24. 24. コーディング # モデルネットワークの定義 # ノード数784の値を持つ入力データを指定、ノード数512の値を出力 # 2層目は10個(答えが0~9なので)の出力 # Dense()1つで1層の全結合NN。計2層のモデル # activation:活性化関数(ここではシグモイドとソフトマックスを指定) model = Sequential([ Dense(512, input_dim=784), Activation("sigmoid"), Dense(10), Activation("softmax") ]) 3 ディープラーニングモデルの構築
  25. 25. コーディング # モデルのコンパイル # 損失関数:交差エントロピー、最適化関数:sgd、評価関数:正解率(acc) model.compile(loss="categorical_crossentropy", optimizer="sgd", metrics=["accuracy"]) # 学習。バッチサイズ:200、ログ出力:プログレスバー、反復数:20、検証データの割合:0.1 hist = model.fit(X_train, y_train, batch_size=200, verbose=1, epochs=20, validation_split=0.1) 4 学習の実行 Train on 54000 samples, validate on 6000 samples Epoch 1/20 54000/54000 [==============================] - 6s 116us/step - loss: 0.8034 - acc: 0.8361 - val_loss: 0.6953 - val_acc: 0.8763 Epoch 2/20 54000/54000 [==============================] - 5s 91us/step - loss: 0.7366 - acc: 0.8430 - val_loss: 0.6353 - val_acc: 0.8787 Epoch 3/20 54000/54000 [==============================] - 4s 83us/step - loss: 0.6847 - acc: 0.8494 - val_loss: 0.5884 - val_acc: 0.8830 ・ ・ ・ Epoch 18/20 54000/54000 [==============================] - 6s 112us/step - loss: 0.4304 - acc: 0.8848 - val_loss: 0.3553 - val_acc: 0.9085 Epoch 19/20 54000/54000 [==============================] - 6s 113us/step - loss: 0.4243 - acc: 0.8857 - val_loss: 0.3497 - val_acc: 0.9083 - loss: 0.4228 - ETA: 1s - loss: 0.4 Epoch 20/20 54000/54000 [==============================] - 6s 103us/step - loss: 0.4187 - acc: 0.8866 - val_loss: 0.3454 - val_acc: 0.9090 実行結果
  26. 26. コーディング # 学習結果の評価。今回は正解率(acc)で評価。 score = model.evaluate(X_test, y_test, verbose=1) ("test accuracy : ", score[1]) 10000/10000 [==============================] - 1s 95us/step test accuracy : 0.8951 5 学習結果の評価(acc) 実行結果 正答率90%程度
  27. 27. コーディング 5 学習結果の評価(損失のグラフ化) # モデルの可視化を行っていく。 import matplotlib.pyplot as plt loss = hist.history["loss"] val_loss = hist.history["val_loss"] # 損失。回数を重ねるほど損失が小さくなっているのがわかる plt.plot(range(20), loss, marker=".", label="loss") plt.plot(range(20), val_loss, marker=".", label="val_loss") plt.legend(loc="best", fontsize=10) plt.grid() plt.xlabel("epoch") plt.ylabel("loss") plt.show()
  28. 28. コーディング 5 学習結果の評価(損失のグラフ化) # モデルの可視化を行っていく。 import matplotlib.pyplot as plt loss = hist.history["loss"] val_loss = hist.history["val_loss"] # 損失。回数を重ねるほど損失が小さくなっているのがわかる plt.plot(range(20), loss, marker=".", label="loss") plt.plot(range(20), val_loss, marker=".", label="val_loss") plt.legend(loc="best", fontsize=10) plt.grid() plt.xlabel("epoch") plt.ylabel("loss") plt.show()
  29. 29. コーディング acc = hist.history["acc"] val_acc = hist.history["val_acc"] # 正答率。回数を重ねるごとに正答率が上がっている plt.plot(range(20), acc, marker=".", label="acc") plt.plot(range(20), val_acc, marker=".", label="val_acc") plt.legend(loc="best", fontsize=10) plt.grid() plt.xlabel("epoch") plt.ylabel("loss") plt.show() 5 学習結果の評価(正答率のグラフ化)
  30. 30. コーディング acc = hist.history["acc"] val_acc = hist.history["val_acc"] # 正答率。回数を重ねるごとに正答率が上がっている plt.plot(range(20), acc, marker=".", label="acc") plt.plot(range(20), val_acc, marker=".", label="val_acc") plt.legend(loc="best", fontsize=10) plt.grid() plt.xlabel("epoch") plt.ylabel("loss") plt.show() 5 学習結果の評価(正答率のグラフ化)
  31. 31. ここまではネット上にも 記事がたくさんある
  32. 32. でも、ここから拡張していく 記事が全然ない ないから、後発の人のために作ることにした
  33. 33. 自分で集めた画像でやってみる
  34. 34. 集めた画像を学習させ、判別する • リンゴかバナナかを判定するシンプルなプログラムを作る • 自分の理解のため、MNISTプログラムを拡張する方向性で進める banana Who am I ?
  35. 35. 構成 appleフォルダ bananaフォルダ 画像デー タの配列 ラベル データの 配列 Apple とりあえず10枚ずつ手作業で収集 未知のデータ 予測結果
  36. 36. 必要なもの • 複数の画像を一気に読み込む仕組み 画像の読み込み • 読み込んだ画像に1:1対応させる仕組み ラベル付け • ここは、ひとまずMNISTチュートリアルのものを流用する 学習モデルの構築 • 学習に使っていない新たな画像を見せて、リンゴかバナナか答え させる仕組み 未知の画像への予測
  37. 37. 画像の読み込み Pillow PILの後継。画像処理用のライブラリ。OpenCVよりも単純な処理向き 処理が速くて簡単。画像生成に向いている glob 引数に指定したパターンに一致するファイル名を取得できる グロブ 出典: フリー百科事典『ウィキペディア(Wikipedia)』 グロブ(英: glob)とは主にUnix系環境において、ワイルドカードでファイル名のセットを指定するパタ ーンのことである。例えば、UNIXのコマンドmv *.txt textfiles/はカレントディレクトリからtextfilesディレ クトリへと.txtで終わる全てのファイルを移動 (mv) する。ここで、*は「任意の文字列」を表すワイルド カードであり、*.txtはグロブである。*以外に一般的なワイルドカードは疑問符 (?) であり、これは任意の 1文字を表す。 ワイルドカード が使える!
  38. 38. ラベル付け folder = [“apple”, “banana”, “orange”] for index, name in enumerate(folder): print(name, “のインデックスは”, index) <実行結果> appleのインデックスは0 bananaのインデックスは1 orangeのインデックスは2 これを使えば、画像データと1:1対応するラベルデータが作れる <プログラム例> enumurate関数 要素とインデックスを同時に取得できる関数
  39. 39. Kerasでのモデル構築 model = Sequential(Dense(units, input_shape(batch_size, input_dim)), Activation(“softmax”)) model = Sequential() model.add(Dense(units, input_shape(batch_size,input_dim))) model.add(Activation(“softmax”)) あとからつぎ足す書き方も可能。 hoge = Sequential(各パラメータ) fuga = hoge.fit(各パラメータ) でモデル構築 で学習実行。基本はこれだけ 例えば全結合NN一層のみ、活性化関数ソフトマックスのモデルならこのように書く
  40. 40. Kerasでの画像判定 今回は、クラス分けした結果だけ返してもらえれば良いので「predict_classes」を使う ・予測用のデータは学習に使ったデータと同じ形に整形してやらないといけない ・モデルに放り込む予測用データはたとえ1枚でも2次元配列になってないといけない 〇 test = X[[a,b,…,x]] × test = X[a,b,…,x] predict_classes() 指定された配列のクラスを予測して返す 注意点
  41. 41. 実際にコーディング # numpy import numpy as np # 画像ファイル処理用 from PIL import Image import glob # 読み込むフォルダ名 folder = ["apple", "banana"] # 画像とラベルを格納するための配列を準備 X = [] Y = [] # ファイルオープン~配列生成までを関数化 # 画像サイズは50×50に強制的に圧縮 def img(x): y = Image.open(x) y = y.convert(“RGB”) y = y.resize((50, 50)) y = np.asarray(y) return y 準備部分。ファイルオープン~配列化までは トレーニングとテストで2度出てくるので関数化。 Kerasにぶちこむ配列の長さは 統一されていないといけないので 画像のサイズは強制的に50×50にする。
  42. 42. 実際にコーディング # 画像の読み込み処理。インデックスを取得するためにenumerateを使用 # folder名に一致するフォルダの中身を1次元配列化しながらXに格納 # 同時に、Yにはインデックス(今回はappleフォルダが0、bananaフォルダが1)がXと1:1対応で格納される for index, name in enumerate(folder): dir = "./" + name files = glob.glob( dir + "/*.jpg") for i, file in enumerate(files): image = img(file) X.append(image.flatten()) Y.append(index) X = np.array(X)/255 Y = np.array(Y) 画像読み込み部分
  43. 43. 実際にコーディング from keras.utils import np_utils # Kerasで使うためにYの値をバイナリに変換 Y = np_utils.to_categorical(Y, 2) from keras.models import Sequential from keras.layers.core import Dense,Activation # モデルの構築 # とりあえず全結合層だけのやつを作ってみる。一層目出力ノード数は適当 model = Sequential( [ Dense(512, input_dim=7500), Activation("relu"), Dense(2), Activation("softmax") ] ) # モデルのコンパイル # 損失関数:交差エントロピー、最適化関数:sgd、評価関数:正解率(acc) model.compile(loss="categorical_crossentropy", optimizer="sgd", metrics=["accuracy"]) # 学習。バッチサイズ:5、ログ出力:プログレスバー、反復数:20、検証データの割合:0.3 hist = model.fit(X, Y, batch_size=5, verbose=1, epochs=20, validation_split=0.3) モデル構築~学習部分 今回はMNISTチュートリアルの流用なので全結合層のみ
  44. 44. 実際にコーディング ringo.jpg # 学習完了したモデルで画像判別を試してみる Xt = [] testimg = img("ringo.jpg") Xt.append(testimg.flatten()) Xt = np.array(Xt)/255 # 判定 # predict_classは予測結果のクラスを返す result = model.predict_classes(Xt) # 判定結果。リンゴじゃなければバナナ if result == 0: print("apple") else: print("banana") 予測部分 学習に使わなかった画像を見せて、リンゴかバナナか答えさせる apple
  45. 45. 実際にコーディング ringo.jpg # 学習完了したモデルで画像判別を試してみる Xt = [] testimg = img("ringo.jpg") Xt.append(testimg.flatten()) Xt = np.array(Xt)/255 # 判定 # predict_classは予測結果のクラスを返す result = model.predict_classes(Xt) # 判定結果。リンゴじゃなければバナナ if result == 0: print("apple") else: print("banana") 予測部分 学習に使わなかった画像を見せて、リンゴかバナナか答えさせる apple banana.jpg apple
  46. 46. 実際にコーディング ringo.jpg # 学習完了したモデルで画像判別を試してみる Xt = [] testimg = img("ringo.jpg") Xt.append(testimg.flatten()) Xt = np.array(Xt)/255 # 判定 # predict_classは予測結果のクラスを返す result = model.predict_classes(Xt) # 判定結果。リンゴじゃなければバナナ if result == 0: print("apple") else: print("banana") 予測部分 学習に使わなかった画像を見せて、リンゴかバナナか答えさせる apple banana.jpg apple
  47. 47. 10枚ずつくらい集めてやってみた結果 • 問答無用でリンゴと答える。全然ダメ • 全結合層だけだからダメ? • 枚数が圧倒的に足りない? • じゃあ両方100枚ずつくらい集める?手動で?
  48. 48. 画像をたくさん集める
  49. 49. スクレイピングツールを使おう google-images-download Flexible Renamer ・Pythonのターミナル上で実行できる画像収集ツール ・デフォルトではselenium連携(~100枚まで取得可能) ・chromedriverと連携させれば大量に画像取得可能(パスを指定する必要有) ・プログラムに組み込むことももちろん可能 ・今回は画像を集められれば良いのでターミナルで実行 ・正規表現にも対応しているフリーのファイルリネーマー ・ファイル名の一部だけ変えたり連番を付けることもできる。超便利 ・今回は本当は不要だけど、ファイル名は統一していないと個人的に気持ち悪いので利用 ダウンロードしてきたファイルはツールでリネーム 参考URL:https://co.bsnws.net/article/295 参考URL:https://www.vector.co.jp/soft/winnt/util/se131133.html
  50. 50. スクレイピングツールを使おう リンゴ、バナナともに200枚ずつ集めた。 ゴミデータや使えなさそうな画像を間引いて、各130枚、計260枚を用意。 ターミナル上で↓のように稼働する
  51. 51. 学習過程 • コードは変えず、画像の枚数だけ増やして実行 • val_accがブレッブレだけどひとまずOK Train on 182 samples, validate on 78 samples Epoch 1/20 182/182 [==============================] - 2s 12ms/step - loss: 0.8935 - acc: 0.6923 - val_loss: 0.5634 - val_acc: 0.9615 Epoch 2/20 182/182 [==============================] - 1s 8ms/step - loss: 0.5603 - acc: 0.7033 - val_loss: 1.6869 - val_acc: 0.0128 Epoch 3/20 182/182 [==============================] - 1s 8ms/step - loss: 0.3921 - acc: 0.8242 - val_loss: 0.2069 - val_acc: 0.9872 Epoch 4/20 182/182 [==============================] - 1s 8ms/step - loss: 0.3962 - acc: 0.8352 - val_loss: 2.0077 - val_acc: 0.0385 Epoch 5/20 182/182 [==============================] - 2s 8ms/step - loss: 0.4474 - acc: 0.8132 - val_loss: 0.6219 - val_acc: 0.6410 ・ ・ ・ Epoch 16/20 182/182 [==============================] - 2s 9ms/step - loss: 0.1540 - acc: 0.9396 - val_loss: 0.9699 - val_acc: 0.5128 Epoch 17/20 182/182 [==============================] - 1s 8ms/step - loss: 0.0645 - acc: 0.9945 - val_loss: 0.5640 - val_acc: 0.7949 Epoch 18/20 182/182 [==============================] - 1s 8ms/step - loss: 0.0733 - acc: 0.9670 - val_loss: 0.5799 - val_acc: 0.7949 Epoch 19/20 182/182 [==============================] - 1s 8ms/step - loss: 0.0283 - acc: 1.0000 - val_loss: 0.3535 - val_acc: 0.8718 Epoch 20/20 182/182 [==============================] - 1s 8ms/step - loss: 0.0454 - acc: 0.9945 - val_loss: 0.2554 - val_acc: 0.9103
  52. 52. 実行結果 ringo.jpg banana.jpg apple banana
  53. 53. 実行結果 ringo.jpg banana.jpg apple banana
  54. 54. 実行結果の評価 • ほぼ色だけで判別しているっぽいけど、想定していた結果が得られた (赤っぽければapple、それ以外ならbanana) • ちなみに青りんごはbanana、赤バナナはappleと答えた • 今回は画像が200程度、ネットワークも全結合層しかなかったなんちゃっ てDLだったが、一応ちゃんと機能する • 食わせるデータを増やしたり、畳み込み層をちゃんと作ったりすれば、汎 用性が上がっていく。はず
  55. 55. まとめ • 初心者でも(一応)実装できました • 「りんご」「バナナ」「それ以外」という風に分けたらもう少し遊べそう • アドバンスとして、画像を増やす(最低でも各1,000枚くらい)、中間層を 増やす、判別する種類を増やす etc. • スクレイピングツールを組み込んで、ユーザが指定したキーワードで画像 を収集して学習、ユーザが任意の画像をアップロードしてそれを判定、み たいなことも割と簡単にできそう
  56. 56. 結論 • Kerasオススメ • Keras楽しい
  57. 57. 宣伝 • 大分でイベントやります グループ参加もお願いします! URL:https://tech-cafe.connpass.com/ AR編とデータ分析編の2本立て 片方のみでももちろんOKです

×