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)