Python AI 画像

kerasを用いて機械学習(ニューラルネットワーク)を行います。ここでは、Kerasで画像処理を行います

データには、kaggleからダウンロードした果物の画像を用います。https://www.kaggle.com/moltean/fruits kerasはGoogleで開発され、GoogleのTensorFlowをバックエンドで用いるAPIラッパーで、コーディングが簡単になります。https://ymgsapo.com/2019/08/22/fruits-deep-learning/ Anacondaの場合、conda install numpy、conda install matplotlib、conda install pandas、conda install keras-gpu等でインストールしてください。condaでインストールできない場合は、pip install ternsorflow kerasのようにpipでインストールしてください。

In [1]:
from keras import layers
from keras import models
from keras import optimizers
from keras.preprocessing.image import ImageDataGenerator
from keras.models import Sequential
#from keras.layers import Activation, Dense
#from keras.utils.np_utils import to_categorical
import numpy as np
import matplotlib.pyplot as plt
import os
Using TensorFlow backend.

1.データを用意する

In [2]:
train_path = './image_fruits/fruits-360/Training/' # 訓練画像の存在するローカルディレクトリ
test_path  = './image_fruits/fruits-360/Test/' # 試験画像の存在するローカルディレクトリ

TARGET = ["Apple Golden 1",
          "Avocado",
#          "Banana",
#          "Blueberry",
          "Cherry 1",
          "Clementine",
          "Grape Pink",
#          "Kaki",
          "Kiwi",
#          "Lemon",
#          "Mango",
          "Nectarine",
#          "Onion Red",
          "Orange",
          "Peach",
          "Strawberry",
          "Tamarillo"]
#          "Tomato 1"]

train_images = []
test_images = []
for i in TARGET:
    subdir = '{}'.format(i)
#    print("train images:{}".format(len(os.listdir(train_path + "/" + subdir +"/"))))
#    print("test  images:{}".format(len(os.listdir(test_path + "/" + subdir + "/"))))
    train_images.append(len(os.listdir(train_path + "/" + subdir +"/")))
    test_images.append(len(os.listdir(test_path + "/" + subdir + "/")))
print("train images:", train_images )
print("test images: ", test_images )

IMG_WIDTH = 40 # 統一する画像の横幅
IMG_HEIGHT = 40 # 統一する画像の縦幅
CHANNELS = 3
TRAIN_BATCH_SIZE = 48 # ミニバッチ学習に使われるバッチサイズ、[重要]データの枚数を割り切れるように
VALID_BATCH_SIZE = 50 # ミニバッチ学習に使われるバッチサイズ、[重要]データの枚数を割り切れるように

train_datagen = ImageDataGenerator(rescale = 1./255) # 画素数のリスケーリング係数
 
train_generator = train_datagen.flow_from_directory(
    train_path,
    target_size = (IMG_WIDTH, IMG_HEIGHT), #自動的に指定サイズにリサイズ default256,256
    batch_size = TRAIN_BATCH_SIZE, # 一度に処理する画像の枚数
    classes = TARGET, # サブディレクトリリスト
    class_mode = "categorical" #複数クラスの分類、カテゴリごとに正解フラグ、binary 二値のラベル
)

validation_datagen = ImageDataGenerator(rescale = 1./255)
 
validation_generator = validation_datagen.flow_from_directory(
    test_path,
    target_size = (IMG_WIDTH, IMG_HEIGHT),
    batch_size = VALID_BATCH_SIZE,
    classes = TARGET,
    class_mode = "categorical"
) 
train images: [492, 427, 492, 490, 492, 466, 492, 479, 492, 492, 490]
test images:  [164, 143, 164, 166, 164, 156, 164, 160, 164, 164, 166]
Found 5304 images belonging to 11 classes.
Found 1775 images belonging to 11 classes.

2.ニューラルネットワークの作成

In [3]:
model = models.Sequential()
model.add(layers.Conv2D(32, # 2次元の畳み込みレイヤー、出力フィルター数32
                        (3, 3), # カーネルサイズ 畳み込みウインドウの幅と高さ
                        activation = "relu", # 活性化関数 ランプ関数、正規化線形関数
                        input_shape = (IMG_WIDTH, IMG_HEIGHT, CHANNELS)))
# 空間データのマックスプーリング演算 
model.add(layers.MaxPooling2D((2, 2))) # ダウンスケール係数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),
                              padding = "SAME")) # valid or same
model.add(layers.Flatten()) # 入力を平滑化する
model.add(layers.Dropout(0.5)) # 過学習防止
model.add(layers.Dense(512, # 通常の全結合NN
                       activation = "relu"))
model.add(layers.Dense(len(TARGET),
                       activation = "sigmoid"))
model.summary()
WARNING:tensorflow:From d:\ProgramData\Anaconda3\envs\keras-gpu\lib\site-packages\tensorflow\python\framework\op_def_library.py:263: colocate_with (from tensorflow.python.framework.ops) is deprecated and will be removed in a future version.
Instructions for updating:
Colocations handled automatically by placer.
WARNING:tensorflow:From d:\ProgramData\Anaconda3\envs\keras-gpu\lib\site-packages\keras\backend\tensorflow_backend.py:3445: calling dropout (from tensorflow.python.ops.nn_ops) with keep_prob is deprecated and will be removed in a future version.
Instructions for updating:
Please use `rate` instead of `keep_prob`. Rate should be set to `rate = 1 - keep_prob`.
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_1 (Conv2D)            (None, 38, 38, 32)        896       
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 19, 19, 32)        0         
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 17, 17, 64)        18496     
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 8, 8, 64)          0         
_________________________________________________________________
conv2d_3 (Conv2D)            (None, 6, 6, 128)         73856     
_________________________________________________________________
max_pooling2d_3 (MaxPooling2 (None, 3, 3, 128)         0         
_________________________________________________________________
conv2d_4 (Conv2D)            (None, 1, 1, 128)         147584    
_________________________________________________________________
max_pooling2d_4 (MaxPooling2 (None, 1, 1, 128)         0         
_________________________________________________________________
flatten_1 (Flatten)          (None, 128)               0         
_________________________________________________________________
dropout_1 (Dropout)          (None, 128)               0         
_________________________________________________________________
dense_1 (Dense)              (None, 512)               66048     
_________________________________________________________________
dense_2 (Dense)              (None, 11)                5643      
=================================================================
Total params: 312,523
Trainable params: 312,523
Non-trainable params: 0
_________________________________________________________________

3.学習

In [4]:
#model.compile(loss = keras.losses.categorical_crossentropy,
model.compile(loss = "categorical_crossentropy",
#              optimizer = keras.optimizers.RMSprop(lr = 1e-4, decay = 1e-6),
              optimizer = optimizers.RMSprop(lr = 1e-4, decay = 1e-6),
              metrics = ['accuracy'])
 
STEP_SIZE_TRAIN = train_generator.n//train_generator.batch_size # 切り捨て除算
STEP_SIZE_VALID = validation_generator.n//validation_generator.batch_size
print("train_generator.n:", train_generator.n)
print("valid_generator.n:", validation_generator.n)
print("STEP_SIZE_TRAIN:", STEP_SIZE_TRAIN) 
print("STEP_SIZE_VALID:", STEP_SIZE_VALID) 

history = model.fit_generator(train_generator,
                             steps_per_epoch = STEP_SIZE_TRAIN,
                             epochs = 20,
                             validation_data = validation_generator,
                             validation_steps = STEP_SIZE_VALID)
train_generator.n: 5304
valid_generator.n: 1775
STEP_SIZE_TRAIN: 110
STEP_SIZE_VALID: 35
WARNING:tensorflow:From d:\ProgramData\Anaconda3\envs\keras-gpu\lib\site-packages\tensorflow\python\ops\math_ops.py:3066: to_int32 (from tensorflow.python.ops.math_ops) is deprecated and will be removed in a future version.
Instructions for updating:
Use tf.cast instead.
Epoch 1/20
110/110 [==============================] - 13s 116ms/step - loss: 2.1956 - acc: 0.2731 - val_loss: 1.7018 - val_acc: 0.3137
Epoch 2/20
110/110 [==============================] - 10s 94ms/step - loss: 1.5340 - acc: 0.3947 - val_loss: 1.1551 - val_acc: 0.6278
Epoch 3/20
110/110 [==============================] - 10s 93ms/step - loss: 1.1183 - acc: 0.5794 - val_loss: 0.7545 - val_acc: 0.7200
Epoch 4/20
110/110 [==============================] - 10s 90ms/step - loss: 0.7547 - acc: 0.7299 - val_loss: 0.4987 - val_acc: 0.8551
Epoch 5/20
110/110 [==============================] - 10s 90ms/step - loss: 0.5332 - acc: 0.8252 - val_loss: 0.3554 - val_acc: 0.8759
Epoch 6/20
110/110 [==============================] - 10s 91ms/step - loss: 0.3582 - acc: 0.8890 - val_loss: 0.4171 - val_acc: 0.8678
Epoch 7/20
110/110 [==============================] - 10s 91ms/step - loss: 0.2703 - acc: 0.9189 - val_loss: 0.1948 - val_acc: 0.9316
Epoch 8/20
110/110 [==============================] - 10s 90ms/step - loss: 0.1930 - acc: 0.9428 - val_loss: 0.1404 - val_acc: 0.9548
Epoch 9/20
110/110 [==============================] - 10s 92ms/step - loss: 0.1556 - acc: 0.9517 - val_loss: 0.1038 - val_acc: 0.9646
Epoch 10/20
110/110 [==============================] - 10s 89ms/step - loss: 0.1112 - acc: 0.9674 - val_loss: 0.0630 - val_acc: 0.9832
Epoch 11/20
110/110 [==============================] - 10s 90ms/step - loss: 0.0949 - acc: 0.9722 - val_loss: 0.0633 - val_acc: 0.9774
Epoch 12/20
110/110 [==============================] - 10s 90ms/step - loss: 0.0722 - acc: 0.9786 - val_loss: 0.0236 - val_acc: 1.0000
Epoch 13/20
110/110 [==============================] - 10s 87ms/step - loss: 0.0615 - acc: 0.9811 - val_loss: 0.0206 - val_acc: 1.0000
Epoch 14/20
110/110 [==============================] - 10s 89ms/step - loss: 0.0559 - acc: 0.9837 - val_loss: 0.0378 - val_acc: 0.9884
Epoch 15/20
110/110 [==============================] - 10s 87ms/step - loss: 0.0418 - acc: 0.9881 - val_loss: 0.0217 - val_acc: 0.9901
Epoch 16/20
110/110 [==============================] - 10s 87ms/step - loss: 0.0402 - acc: 0.9886 - val_loss: 0.0341 - val_acc: 0.9809
Epoch 17/20
110/110 [==============================] - 10s 87ms/step - loss: 0.0351 - acc: 0.9915 - val_loss: 0.0439 - val_acc: 0.9751
Epoch 18/20
110/110 [==============================] - 10s 87ms/step - loss: 0.0329 - acc: 0.9894 - val_loss: 0.0149 - val_acc: 1.0000
Epoch 19/20
110/110 [==============================] - 10s 89ms/step - loss: 0.0298 - acc: 0.9913 - val_loss: 0.0045 - val_acc: 1.0000
Epoch 20/20
110/110 [==============================] - 9s 85ms/step - loss: 0.0316 - acc: 0.9894 - val_loss: 0.0100 - val_acc: 1.0000

4.可視化

In [5]:
acc = history.history["acc"]
val_acc = history.history["val_acc"]
loss = history.history["loss"]
val_loss = history.history["val_loss"]
 
epochs = range(1, len(acc) + 1)
 
plt.figure(figsize=(8, 8))
#plt.style.use('fivethirtyeight')
plt.subplot(211)
plt.plot(epochs, acc, "bo", label = "Training Acc")
plt.plot(epochs, val_acc, "r", label = "Validation Acc")
plt.title("model accuracy")
plt.legend()

plt.subplot(212)
plt.plot(epochs, loss, "ko", label = "Training Loss")
plt.plot(epochs, val_loss, "g", label = "Validation Loss")
plt.legend()
plt.title("model loss") 
plt.xlabel("epochs")
plt.show()
In [ ]: