機械学習/樹木写真判定

Python
from PIL import Image
import os, glob
import numpy as np
import random, math

#画像が保存されているルートディレクトリのパス
root_dir = "images/"
#フォルダ名
categories = ["アセビ", "サンシュユ", "ハナミズキ", "マンサク", "金木犀",
              "桜", "椿", "南天", "梅", "白木蓮"]

# 画像データ用配列
X = []
# ラベルデータ用配列
Y = []

#画像データごとにadd_sample()を呼び出し、X,Yの配列を返す関数
def make_sample(files):
    global X, Y
    X = []
    Y = []
    for cat, fname in files:
        add_sample(cat, fname)
    return np.array(X), np.array(Y)

#渡された画像データを読み込んでXに格納し、
#画像データに対応するcategoriesのidxをYに格納する関数
def add_sample(cat, fname):
    img = Image.open(fname)
    img = img.convert("RGB")
    img = img.resize((150, 150))
    data = np.asarray(img)
    X.append(data)
    Y.append(cat)

#全データ格納用配列
allfiles = []

#カテゴリ配列の各値と、それに対応するidxを認識し、全データをallfilesにまとめる
for idx, cat in enumerate(categories):
    image_dir = root_dir + "/" + cat
    files = glob.glob(image_dir + "/*.jpg")
    for f in files:
        allfiles.append((idx, f))

#シャッフル後、学習データと検証データに分ける
random.shuffle(allfiles)
th = math.floor(len(allfiles) * 0.8)
train = allfiles[0:th]
test  = allfiles[th:]
X_train, y_train = make_sample(train)
X_test, y_test = make_sample(test)
xy = (X_train, X_test, y_train, y_test)

#データを保存する(データの名前を「tea_data.npy」としている)
np.save("tea_data.npy", xy)


モデルは畳み込みニューラルネットワーク(CNN)

#モデルの構築①

from keras import layers, models

model = models.Sequential()
model.add(layers.Conv2D(32,(3,3),activation="relu",input_shape=(150,150,3)))
model.add(layers.MaxPooling2D((2,2)))
model.add(layers.Conv2D(64,(3,3),activation="relu"))
model.add(layers.MaxPooling2D((2,2)))
model.add(layers.Conv2D(128,(3,3),activation="relu"))
model.add(layers.MaxPooling2D((2,2)))
model.add(layers.Conv2D(128,(3,3),activation="relu"))
model.add(layers.MaxPooling2D((2,2)))
model.add(layers.Flatten())
model.add(layers.Dense(512,activation="relu"))
model.add(layers.Dense(10,activation="sigmoid")) #分類先の種類分設定

#モデル構成の確認
model.summary()



#モデルのコンパイル
from keras import optimizers

model.compile(loss="binary_crossentropy",
              optimizer=optimizers.RMSprop(lr=1e-4),
              metrics=["acc"])


#データの準備

from keras.utils import np_utils
import numpy as np

categories = ["アセビ", "サンシュユ", "ハナミズキ", "マンサク", "金木犀",
              "桜", "椿", "南天", "梅", "白木蓮"]
nb_classes = len(categories)

X_train, X_test, y_train, y_test = np.load("tea_data.npy")

#データの正規化
X_train = X_train.astype("float") / 255
X_test  = X_test.astype("float")  / 255

#kerasで扱えるようにcategoriesをベクトルに変換
y_train = np_utils.to_categorical(y_train, nb_classes)
y_test  = np_utils.to_categorical(y_test, nb_classes)



#モデルの学習

model = model.fit(X_train,
                  y_train,
                  epochs=10,
                  batch_size=6,
                  validation_data=(X_test,y_test))


epochごとに学習結果が表示








#学習結果を表示

import matplotlib.pyplot as plt

acc = model.history['acc']
val_acc = model.history['val_acc']
loss = model.history['loss']
val_loss = model.history['val_loss']

epochs = range(len(acc))

#精度を示すグラフ
plt.plot(epochs, acc, 'bo', label='Training acc')
plt.plot(epochs, val_acc, 'b', label='Validation acc')
plt.title('Training and validation accuracy')
plt.legend()
plt.savefig('seido.png')

plt.figure()


#損失値を示すグラフ
plt.plot(epochs, loss, 'bo', label='Training loss')
plt.plot(epochs, val_loss, 'b', label='Validation loss')
plt.title('Training and validation loss')
plt.legend()
plt.savefig('sonshitu.png')



#学習結果を保存

#モデルの保存

json_string = model.model.to_json()
open('tea_predict.json', 'w').write(json_string)

#重みの保存

hdf5_file = "tea_predict.hdf5"
model.model.save_weights(hdf5_file)




#未知のデータでテスト
from PIL import Image
import os, glob
import numpy as np
import random, math

# 画像が保存されているディレクトリのパス
root_dir = "test/images/"
# 画像が保存されているフォルダ名
categories = ["アセビ", "サンシュユ", "ハナミズキ", "マンサク", "金木犀",
              "桜", "椿", "南天", "梅", "白木蓮"]

X = [] # 画像データ
Y = [] # ラベルデータ

# フォルダごとに分けられたファイルを収集
#(categoriesのidxと、画像のファイルパスが紐づいたリストを生成)
allfiles = []
for idx, cat in enumerate(categories):
    image_dir = root_dir + "/" + cat
    files = glob.glob(image_dir + "/*.jpg")
    for f in files:
        allfiles.append((idx, f))

for cat, fname in allfiles:
    img = Image.open(fname)
    img = img.convert("RGB")
    img = img.resize((150, 150))
    data = np.asarray(img)
    X.append(data)
    Y.append(cat)

x = np.array(X)
y = np.array(Y)

np.save("test/tea_data_test_X_150.npy", x)
np.save("test/tea_data_test_Y_150.npy", y)




# モデルの精度を測る

#評価用のデータの読み込み
eval_X = np.load("test/tea_data_test_X_150.npy")
eval_Y = np.load("test/tea_data_test_Y_150.npy")

#Yのデータをone-hotに変換
from keras.utils import np_utils

eval_Y = np_utils.to_categorical(eval_Y, 10)

score = model.model.evaluate(x=eval_X,y=eval_Y)

print('loss=', score[0])
print('accuracy=', score[1])





#データを拡張して精度をあげる②

#KerasのImageDataGeneratorを使って画像を水増し

import os
import glob
import numpy as np
from keras.preprocessing.image import ImageDataGenerator, load_img, img_to_array, array_to_img

# 画像を拡張する関数
def draw_images(generator, x, dir_name, index):
    save_name = 'extened-' + str(index)
    g = generator.flow(x, batch_size=1, save_to_dir=output_dir,
                       save_prefix=save_name, save_format='jpeg')

    # 1つの入力画像から何枚拡張するかを指定(今回は50枚)
    for i in range(50):
        bach = g.next()

# 出力先ディレクトリの設定
output_dir = "test/"

if not(os.path.exists(output_dir)):
    os.mkdir(output_dir)

# 拡張する画像の読み込み
images = glob.glob(os.path.join("test/", "*.jpg"))

# ImageDataGeneratorを定義
datagen = ImageDataGenerator(rotation_range=30,
                            width_shift_range=20,
                            height_shift_range=0.,
                            zoom_range=0.1,
                            horizontal_flip=True,
                            vertical_flip=True)

# 読み込んだ画像を順に拡張
#「img.resize((250, 250))」に変更
for i in range(len(images)):
    img = load_img(images[i])
    img = img.resize((250, 250))
    x = img_to_array(img)
    x = np.expand_dims(x, axis=0)
    draw_images(datagen, x, output_dir, i)



#各種パスの修正、モデルのinput sizeを250, 250, 3に修正する必要
############①で学習させる






#過学習を抑制するdropoutをモデルに追加
from keras import layers, models

model = models.Sequential()
model.add(layers.Conv2D(32,(3,3),activation="relu",input_shape=(250,250,3)))
model.add(layers.MaxPooling2D((2,2)))
model.add(layers.Conv2D(64,(3,3),activation="relu"))
model.add(layers.MaxPooling2D((2,2)))
model.add(layers.Conv2D(128,(3,3),activation="relu"))
model.add(layers.MaxPooling2D((2,2)))
model.add(layers.Conv2D(128,(3,3),activation="relu"))
model.add(layers.MaxPooling2D((2,2)))
model.add(layers.Flatten())
model.add(layers.Dropout(0.5)) #損失率を調整しつつ
model.add(layers.Dense(512,activation="relu"))
model.add(layers.Dense(10,activation="sigmoid"))



#各種パスの修正、モデルのinput sizeを250, 250, 3に修正する必要
###########①で学習させる




#答え合わせプログラム

from keras import models
from keras.models import model_from_json
from keras.preprocessing import image
import numpy as np

#保存したモデルの読み込み
model = model_from_json(open('tea_predict.json').read())
#保存した重みの読み込み
model.load_weights('tea_predict.hdf5')

categories = ["アセビ", "サンシュユ", "ハナミズキ", "マンサク", "金木犀",
              "桜", "椿", "南天", "梅", "白木蓮"]

#画像を読み込む
#input
img_path = str(input())
#指定
img_path = str("sazanka.jpg")

img = image.load_img(img_path,target_size=(150, 150, 3))#調整しつつ
x = image.img_to_array(img)
x = np.expand_dims(x, axis=0)

#予測
features = model.predict(x)

#予測結果によって処理を分ける
for i in range(0,10):
      if features[0,i] == 1:
          cat = categories[i]
print(cat)