Keras 利用資料擴增法訓練貓狗分類器

先從 Kaggle 下載資料集,這裡需要註冊 Kaggle 的帳號,並且取得 API Key,記得置換為自己的 API Token 才能下載資料。


In [1]:
#!pip install kaggle
api_token = {"username":"your_username","key":"your_token"}
import json
import zipfile
import os

if not os.path.exists("/root/.kaggle"):
    os.makedirs("/root/.kaggle")

with open('/root/.kaggle/kaggle.json', 'w') as file:
    json.dump(api_token, file)
!chmod 600 /root/.kaggle/kaggle.json

if not os.path.exists("/kaggle"):
    os.makedirs("/kaggle")
os.chdir('/kaggle')
!kaggle datasets download -d chetankv/dogs-cats-images

!unzip 'dogs-cats-images.zip' > /dev/null


dogs-cats-images.zip: Skipping, found more recently modified local copy (use --force to force download)
replace dataset/test_set/cats/cat.4001.jpg? [y]es, [n]o, [A]ll, [N]one, [r]ename: A

看看資料的基本結構,貓與狗訓練資料夾各有 4000 張,測試資料夾各有 1000 張影像


In [2]:
!echo "training_set cats: "
!echo `ls -alh '/kaggle/dataset/training_set/cats' | grep cat | wc -l`
!echo "training_set dogs: "
!echo `ls -alh '/kaggle/dataset/training_set/dogs' | grep dog | wc -l`
!echo "test_set cats: "
!echo `ls -alh '/kaggle/dataset/test_set/cats' | grep cat | wc -l`
!echo "test_set dogs: "
!echo `ls -alh '/kaggle/dataset/test_set/dogs' | grep dog | wc -l`


training_set cats: 
4000
training_set dogs: 
4000
test_set cats: 
1000
test_set dogs: 
1000

資料處理

我們上面從 Kaggle 下載的檔案全部都是圖片,由於我們想要從頭訓練一個可以分辨貓或狗的 CNN 網路,開始以前需要先將影像資料進行處理,轉換為可以送進 Keras 網路進行訓練的「張量」。並且依據我們選用的損失函數方法,處理對應標準答案的格式。

由於我們今天不會用到全部的資料,我們只會在兩種類別取用 1000 張進行訓練,500 張進行測試。接著利用「資料擴增工法」來提高正確率。


In [0]:
import os, shutil

# The path to the directory where the original
# dataset was uncompressed
original_dataset_dir = '/kaggle/dataset'

# The directory where we will
# store our smaller dataset
base_dir = '/play'
if not os.path.exists(base_dir):
    os.mkdir(base_dir)

# Directories for our training,
# validation and test splits
train_dir = os.path.join(base_dir, 'train')
if not os.path.exists(train_dir):
    os.mkdir(train_dir)
validation_dir = os.path.join(base_dir, 'validation')
if not os.path.exists(validation_dir):
    os.mkdir(validation_dir)
test_dir = os.path.join(base_dir, 'test')
if not os.path.exists(test_dir):
    os.mkdir(test_dir)

# Directory with our training cat pictures
train_cats_dir = os.path.join(train_dir, 'cats')
if not os.path.exists(train_cats_dir):
    os.mkdir(train_cats_dir)

# Directory with our training dog pictures
train_dogs_dir = os.path.join(train_dir, 'dogs')
if not os.path.exists(train_dogs_dir):
    os.mkdir(train_dogs_dir)

# Directory with our validation cat pictures
validation_cats_dir = os.path.join(validation_dir, 'cats')
if not os.path.exists(validation_cats_dir):
    os.mkdir(validation_cats_dir)

# Directory with our validation dog pictures
validation_dogs_dir = os.path.join(validation_dir, 'dogs')
if not os.path.exists(validation_dogs_dir):
    os.mkdir(validation_dogs_dir)

# Directory with our validation cat pictures
test_cats_dir = os.path.join(test_dir, 'cats')
if not os.path.exists(test_cats_dir):
    os.mkdir(test_cats_dir)

# Directory with our validation dog pictures
test_dogs_dir = os.path.join(test_dir, 'dogs')
if not os.path.exists(test_dogs_dir):
    os.mkdir(test_dogs_dir)

# Copy first 1000 cat images to train_cats_dir
fnames = ['cat.{}.jpg'.format(i) for i in range(1, 1001)]
for fname in fnames:
    src = os.path.join(original_dataset_dir, 'training_set', 'cats', fname)
    dst = os.path.join(train_cats_dir, fname)
    shutil.copyfile(src, dst)

# Copy next 500 cat images to validation_cats_dir
fnames = ['cat.{}.jpg'.format(i) for i in range(4001, 4501)]
for fname in fnames:
    src = os.path.join(original_dataset_dir, 'test_set', 'cats', fname)
    dst = os.path.join(validation_cats_dir, fname)
    shutil.copyfile(src, dst)
    
# Copy next 500 cat images to test_cats_dir
fnames = ['cat.{}.jpg'.format(i) for i in range(4501, 5001)]
for fname in fnames:
    src = os.path.join(original_dataset_dir, 'test_set', 'cats', fname)
    dst = os.path.join(test_cats_dir, fname)
    shutil.copyfile(src, dst)
    
# Copy first 1000 dog images to train_dogs_dir
fnames = ['dog.{}.jpg'.format(i) for i in range(1, 1001)]
for fname in fnames:
    src = os.path.join(original_dataset_dir, 'training_set', 'dogs', fname)
    dst = os.path.join(train_dogs_dir, fname)
    shutil.copyfile(src, dst)
    
# Copy next 500 dog images to validation_dogs_dir
fnames = ['dog.{}.jpg'.format(i) for i in range(4001, 4501)]
for fname in fnames:
    src = os.path.join(original_dataset_dir, 'test_set', 'dogs', fname)
    dst = os.path.join(validation_dogs_dir, fname)
    shutil.copyfile(src, dst)
    
# Copy next 500 dog images to test_dogs_dir
fnames = ['dog.{}.jpg'.format(i) for i in range(4501, 5001)]
for fname in fnames:
    src = os.path.join(original_dataset_dir, 'test_set', 'dogs', fname)
    dst = os.path.join(test_dogs_dir, fname)
    shutil.copyfile(src, dst)

In [4]:
print('total training cat images:', len(os.listdir(train_cats_dir)))
print('total training dog images:', len(os.listdir(train_dogs_dir)))
print('total validation cat images:', len(os.listdir(validation_cats_dir)))
print('total validation dog images:', len(os.listdir(validation_dogs_dir)))
print('total test cat images:', len(os.listdir(test_cats_dir)))
print('total test dog images:', len(os.listdir(test_dogs_dir)))


total training cat images: 1000
total training dog images: 1000
total validation cat images: 500
total validation dog images: 500
total test cat images: 500
total test dog images: 500

接著建構我們需要的網路,使用四層網路組合 CNN,最後的 Full Connection Layer 使用 512 個神經元,Keras 建立 CNN 網路的方法如下:


In [5]:
from keras import layers
from keras import 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(1, activation='sigmoid'))


Using TensorFlow backend.

顯示網路的組成架構,整個網路有 3,453,121 個參數需要訓練,這樣的運算量非常需要高速的 GPU 來協助運算。


In [6]:
model.summary()


Model: "sequential_1"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_1 (Conv2D)            (None, 148, 148, 32)      896       
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 74, 74, 32)        0         
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 72, 72, 64)        18496     
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 36, 36, 64)        0         
_________________________________________________________________
conv2d_3 (Conv2D)            (None, 34, 34, 128)       73856     
_________________________________________________________________
max_pooling2d_3 (MaxPooling2 (None, 17, 17, 128)       0         
_________________________________________________________________
conv2d_4 (Conv2D)            (None, 15, 15, 128)       147584    
_________________________________________________________________
max_pooling2d_4 (MaxPooling2 (None, 7, 7, 128)         0         
_________________________________________________________________
flatten_1 (Flatten)          (None, 6272)              0         
_________________________________________________________________
dense_1 (Dense)              (None, 512)               3211776   
_________________________________________________________________
dense_2 (Dense)              (None, 1)                 513       
=================================================================
Total params: 3,453,121
Trainable params: 3,453,121
Non-trainable params: 0
_________________________________________________________________

這次要解決的問題屬於「二元分類」,算是 CNN 裡最典型的問題,因此損失函式採用「binary_crossentropy」,優化器選用「RMSprop」


In [0]:
from keras import optimizers

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

再來定義 ImageDataGenerator,ImageDataGenerator 是 Keras 用來讀取影像資料的方法,可以想像為 Dataset Provider 的概念,這樣可以不需要把所有資料都讀進記憶體,如果要訓練的資料影像很多,這會是一個解套的好方。這裡我們只是利用 ImageDataGenerator 來走訪需要訓練的資料,稍後會用來產生更多資料提高模型訓練準確度。


In [8]:
from keras.preprocessing.image import ImageDataGenerator

# All images will be rescaled by 1./255
train_datagen = ImageDataGenerator(rescale=1./255)
test_datagen = ImageDataGenerator(rescale=1./255)

train_generator = train_datagen.flow_from_directory(
        # This is the target directory
        train_dir,
        # All images will be resized to 150x150
        target_size=(150, 150),
        batch_size=20,
        # Since we use binary_crossentropy loss, we need binary labels
        class_mode='binary')

validation_generator = test_datagen.flow_from_directory(
        validation_dir,
        target_size=(150, 150),
        batch_size=20,
        class_mode='binary')

for data_batch, labels_batch in train_generator:
    print('data batch shape:', data_batch.shape)
    print('labels batch shape:', labels_batch.shape)
    break


Found 2000 images belonging to 2 classes.
Found 1000 images belonging to 2 classes.
data batch shape: (20, 150, 150, 3)
labels batch shape: (20,)

剛剛的 batch_size 設定 20,表示每次從 train_generator 抓 20 筆資料送進 Network 進行訓練 我們有 2000 筆資料 (貓與狗各 1000 筆),一共要做 100 次才會做完,這樣訓練一輪就是一個 epoch,訓練如下:


In [9]:
history = model.fit_generator(
      train_generator,
      steps_per_epoch=100,
      epochs=30,
      validation_data=validation_generator,
      validation_steps=50)


Epoch 1/30
100/100 [==============================] - 10s 96ms/step - loss: 0.6904 - acc: 0.5195 - val_loss: 0.7004 - val_acc: 0.5000
Epoch 2/30
100/100 [==============================] - 8s 76ms/step - loss: 0.6632 - acc: 0.5935 - val_loss: 0.6979 - val_acc: 0.5390
Epoch 3/30
100/100 [==============================] - 8s 75ms/step - loss: 0.6216 - acc: 0.6620 - val_loss: 0.7073 - val_acc: 0.5970
Epoch 4/30
100/100 [==============================] - 7s 75ms/step - loss: 0.5794 - acc: 0.7000 - val_loss: 0.6442 - val_acc: 0.6620
Epoch 5/30
100/100 [==============================] - 8s 75ms/step - loss: 0.5495 - acc: 0.7195 - val_loss: 0.4687 - val_acc: 0.7010
Epoch 6/30
100/100 [==============================] - 8s 76ms/step - loss: 0.5140 - acc: 0.7395 - val_loss: 0.5897 - val_acc: 0.7240
Epoch 7/30
100/100 [==============================] - 8s 75ms/step - loss: 0.4917 - acc: 0.7615 - val_loss: 0.5813 - val_acc: 0.7390
Epoch 8/30
100/100 [==============================] - 8s 75ms/step - loss: 0.4570 - acc: 0.7880 - val_loss: 0.5448 - val_acc: 0.7410
Epoch 9/30
100/100 [==============================] - 8s 77ms/step - loss: 0.4373 - acc: 0.7980 - val_loss: 0.4795 - val_acc: 0.7190
Epoch 10/30
100/100 [==============================] - 8s 77ms/step - loss: 0.4179 - acc: 0.8030 - val_loss: 0.3926 - val_acc: 0.7530
Epoch 11/30
100/100 [==============================] - 8s 75ms/step - loss: 0.3904 - acc: 0.8205 - val_loss: 0.3298 - val_acc: 0.7430
Epoch 12/30
100/100 [==============================] - 8s 77ms/step - loss: 0.3688 - acc: 0.8380 - val_loss: 0.3789 - val_acc: 0.7420
Epoch 13/30
100/100 [==============================] - 8s 76ms/step - loss: 0.3488 - acc: 0.8430 - val_loss: 0.4959 - val_acc: 0.7340
Epoch 14/30
100/100 [==============================] - 8s 77ms/step - loss: 0.3225 - acc: 0.8620 - val_loss: 0.3764 - val_acc: 0.7600
Epoch 15/30
100/100 [==============================] - 8s 76ms/step - loss: 0.3042 - acc: 0.8740 - val_loss: 0.6138 - val_acc: 0.7450
Epoch 16/30
100/100 [==============================] - 8s 76ms/step - loss: 0.2920 - acc: 0.8730 - val_loss: 0.3423 - val_acc: 0.7650
Epoch 17/30
100/100 [==============================] - 7s 75ms/step - loss: 0.2668 - acc: 0.8870 - val_loss: 0.5920 - val_acc: 0.7380
Epoch 18/30
100/100 [==============================] - 8s 76ms/step - loss: 0.2367 - acc: 0.9110 - val_loss: 0.7729 - val_acc: 0.7640
Epoch 19/30
100/100 [==============================] - 8s 76ms/step - loss: 0.2212 - acc: 0.9190 - val_loss: 0.4577 - val_acc: 0.7650
Epoch 20/30
100/100 [==============================] - 8s 76ms/step - loss: 0.1945 - acc: 0.9295 - val_loss: 0.3474 - val_acc: 0.7560
Epoch 21/30
100/100 [==============================] - 8s 76ms/step - loss: 0.1790 - acc: 0.9275 - val_loss: 0.5133 - val_acc: 0.7750
Epoch 22/30
100/100 [==============================] - 8s 77ms/step - loss: 0.1581 - acc: 0.9490 - val_loss: 0.4559 - val_acc: 0.7630
Epoch 23/30
100/100 [==============================] - 8s 78ms/step - loss: 0.1453 - acc: 0.9505 - val_loss: 0.5877 - val_acc: 0.7750
Epoch 24/30
100/100 [==============================] - 8s 76ms/step - loss: 0.1299 - acc: 0.9570 - val_loss: 0.4599 - val_acc: 0.7680
Epoch 25/30
100/100 [==============================] - 8s 76ms/step - loss: 0.1123 - acc: 0.9665 - val_loss: 0.8650 - val_acc: 0.7630
Epoch 26/30
100/100 [==============================] - 8s 76ms/step - loss: 0.0968 - acc: 0.9725 - val_loss: 0.4563 - val_acc: 0.7660
Epoch 27/30
100/100 [==============================] - 8s 76ms/step - loss: 0.0832 - acc: 0.9800 - val_loss: 1.0983 - val_acc: 0.7700
Epoch 28/30
100/100 [==============================] - 8s 76ms/step - loss: 0.0777 - acc: 0.9750 - val_loss: 1.7549 - val_acc: 0.7520
Epoch 29/30
100/100 [==============================] - 8s 77ms/step - loss: 0.0671 - acc: 0.9790 - val_loss: 1.1255 - val_acc: 0.7530
Epoch 30/30
100/100 [==============================] - 8s 77ms/step - loss: 0.0537 - acc: 0.9865 - val_loss: 0.5249 - val_acc: 0.7670

觀察圖表分析訓練情況


In [10]:
import matplotlib.pyplot as plt

acc = history.history['acc']
val_acc = history.history['val_acc']
loss = history.history['loss']
val_loss = history.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.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.show()


從上面的圖片可以發現,在 5 Epoch 之後就開始走針了,Model 已經出現 Over Fitting 的現象。接下來透過 ImageDataGenerator 來擴增訓練樣本數量。

Keras 利用資料擴增法提高訓練準確性

由於我們總共只用了 2000 筆資料,假設樣本真的很難取得,那麼我們可以透過資料擴增法,將影像資料做一點「變化」,稍微加工一下這樣就有更多資料可以讓模型進行學習。Keras ImageDataGenerator 可以幫助我們實現影像資料擴增,如下:


In [0]:
datagen = ImageDataGenerator(
      rotation_range=40,             # 隨機旋轉的角度
      width_shift_range=0.2,         # 隨機水平平移的 % 比例
      height_shift_range=0.2,        # 隨機垂直平移的 % 比例
      shear_range=0.2,               # 隨機傾斜的角度
      zoom_range=0.2,                # 隨機縮放的比例
      horizontal_flip=True,          # 隨機左右翻轉
      fill_mode='nearest')           # 邊界像素填補,由於影像調整後周圍會出現缺少的像素,設定 nearest 會以最接近的像素填補

以下我們將每一張影像隨機進行變化,產生四張經過加工的圖片。這樣一來我們的資料集忽然就便多了,如下:


In [12]:
# This is module with image preprocessing utilities
from keras.preprocessing import image

fnames = [os.path.join(train_cats_dir, fname) for fname in os.listdir(train_cats_dir)]

# We pick one image to "augment"
img_path = fnames[3]

# Read the image and resize it
img = image.load_img(img_path, target_size=(150, 150))

# Convert it to a Numpy array with shape (150, 150, 3)
x = image.img_to_array(img)

# Reshape it to (1, 150, 150, 3)
x = x.reshape((1,) + x.shape)

# The .flow() command below generates batches of randomly transformed images.
# It will loop indefinitely, so we need to `break` the loop at some point!
i = 0
for batch in datagen.flow(x, batch_size=1):
    plt.figure(i)
    imgplot = plt.imshow(image.array_to_img(batch[0]))
    i += 1
    if i % 4 == 0:
        break

plt.show()


重新建立模型,這裡我們有動一點手腳,就是在卷積層傳入全連接層 (Full Connection Layer) 的時候加入了 Dropout Layer,這樣會隨機丟棄 50% 的資訊,用意是不要讓網路的學習過於狹隘,不然很容易造成 Over Fitting,如下:


In [13]:
from keras import layers
from keras import 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.Dropout(0.5))                # 加入 Dropout 0.5 隨機丟棄 50%
model.add(layers.Dense(512, activation='relu'))
model.add(layers.Dense(1, activation='sigmoid'))

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

model.summary()


Model: "sequential_2"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_5 (Conv2D)            (None, 148, 148, 32)      896       
_________________________________________________________________
max_pooling2d_5 (MaxPooling2 (None, 74, 74, 32)        0         
_________________________________________________________________
conv2d_6 (Conv2D)            (None, 72, 72, 64)        18496     
_________________________________________________________________
max_pooling2d_6 (MaxPooling2 (None, 36, 36, 64)        0         
_________________________________________________________________
conv2d_7 (Conv2D)            (None, 34, 34, 128)       73856     
_________________________________________________________________
max_pooling2d_7 (MaxPooling2 (None, 17, 17, 128)       0         
_________________________________________________________________
conv2d_8 (Conv2D)            (None, 15, 15, 128)       147584    
_________________________________________________________________
max_pooling2d_8 (MaxPooling2 (None, 7, 7, 128)         0         
_________________________________________________________________
flatten_2 (Flatten)          (None, 6272)              0         
_________________________________________________________________
dropout_1 (Dropout)          (None, 6272)              0         
_________________________________________________________________
dense_3 (Dense)              (None, 512)               3211776   
_________________________________________________________________
dense_4 (Dense)              (None, 1)                 513       
=================================================================
Total params: 3,453,121
Trainable params: 3,453,121
Non-trainable params: 0
_________________________________________________________________

進行模型訓練,這裡設定 batch_size=32, steps_per_epoch=100,相當於透過資料擴增法增加到 3,200 筆訓練資料,運算量很高,需要讓子彈飛一下,如下:


In [14]:
train_datagen = ImageDataGenerator(
    rescale=1./255,
    rotation_range=40,
    width_shift_range=0.2,
    height_shift_range=0.2,
    shear_range=0.2,
    zoom_range=0.2,
    horizontal_flip=True,)

# Note that the validation data should not be augmented!
test_datagen = ImageDataGenerator(rescale=1./255)

train_generator = train_datagen.flow_from_directory(
        # This is the target directory
        train_dir,
        # All images will be resized to 150x150
        target_size=(150, 150),
        batch_size=32,
        # Since we use binary_crossentropy loss, we need binary labels
        class_mode='binary')

validation_generator = test_datagen.flow_from_directory(
        validation_dir,
        target_size=(150, 150),
        batch_size=32,
        class_mode='binary')

history = model.fit_generator(
      train_generator,
      steps_per_epoch=100,
      epochs=100,
      validation_data=validation_generator,
      validation_steps=50)


Found 2000 images belonging to 2 classes.
Found 1000 images belonging to 2 classes.
Epoch 1/100
100/100 [==============================] - 27s 272ms/step - loss: 0.6920 - acc: 0.5196 - val_loss: 0.6840 - val_acc: 0.5298
Epoch 2/100
100/100 [==============================] - 25s 247ms/step - loss: 0.6823 - acc: 0.5543 - val_loss: 0.6955 - val_acc: 0.5580
Epoch 3/100
100/100 [==============================] - 25s 245ms/step - loss: 0.6732 - acc: 0.5833 - val_loss: 0.6556 - val_acc: 0.5971
Epoch 4/100
100/100 [==============================] - 25s 247ms/step - loss: 0.6545 - acc: 0.6083 - val_loss: 0.6424 - val_acc: 0.6050
Epoch 5/100
100/100 [==============================] - 24s 238ms/step - loss: 0.6425 - acc: 0.6206 - val_loss: 0.7481 - val_acc: 0.6643
Epoch 6/100
100/100 [==============================] - 27s 266ms/step - loss: 0.6300 - acc: 0.6426 - val_loss: 0.6284 - val_acc: 0.6727
Epoch 7/100
100/100 [==============================] - 25s 250ms/step - loss: 0.6090 - acc: 0.6638 - val_loss: 0.4832 - val_acc: 0.6916
Epoch 8/100
100/100 [==============================] - 25s 251ms/step - loss: 0.5909 - acc: 0.6891 - val_loss: 0.7031 - val_acc: 0.6637
Epoch 9/100
100/100 [==============================] - 25s 249ms/step - loss: 0.5960 - acc: 0.6809 - val_loss: 0.5904 - val_acc: 0.7068
Epoch 10/100
100/100 [==============================] - 25s 246ms/step - loss: 0.5798 - acc: 0.6963 - val_loss: 0.4710 - val_acc: 0.7227
Epoch 11/100
100/100 [==============================] - 26s 258ms/step - loss: 0.5778 - acc: 0.7023 - val_loss: 0.6274 - val_acc: 0.6733
Epoch 12/100
100/100 [==============================] - 25s 252ms/step - loss: 0.5702 - acc: 0.7061 - val_loss: 0.5703 - val_acc: 0.7367
Epoch 13/100
100/100 [==============================] - 25s 253ms/step - loss: 0.5678 - acc: 0.7038 - val_loss: 0.6989 - val_acc: 0.7062
Epoch 14/100
100/100 [==============================] - 25s 254ms/step - loss: 0.5555 - acc: 0.7175 - val_loss: 0.4782 - val_acc: 0.7221
Epoch 15/100
100/100 [==============================] - 25s 253ms/step - loss: 0.5563 - acc: 0.7083 - val_loss: 0.6167 - val_acc: 0.7307
Epoch 16/100
100/100 [==============================] - 25s 250ms/step - loss: 0.5504 - acc: 0.7121 - val_loss: 0.5567 - val_acc: 0.7416
Epoch 17/100
100/100 [==============================] - 24s 238ms/step - loss: 0.5470 - acc: 0.7208 - val_loss: 0.5159 - val_acc: 0.7640
Epoch 18/100
100/100 [==============================] - 27s 274ms/step - loss: 0.5431 - acc: 0.7178 - val_loss: 0.6084 - val_acc: 0.7216
Epoch 19/100
100/100 [==============================] - 26s 257ms/step - loss: 0.5468 - acc: 0.7167 - val_loss: 0.6070 - val_acc: 0.6910
Epoch 20/100
100/100 [==============================] - 25s 252ms/step - loss: 0.5250 - acc: 0.7339 - val_loss: 0.4600 - val_acc: 0.7500
Epoch 21/100
100/100 [==============================] - 25s 251ms/step - loss: 0.5280 - acc: 0.7293 - val_loss: 0.4701 - val_acc: 0.7386
Epoch 22/100
100/100 [==============================] - 24s 243ms/step - loss: 0.5110 - acc: 0.7500 - val_loss: 0.5716 - val_acc: 0.7571
Epoch 23/100
100/100 [==============================] - 27s 268ms/step - loss: 0.5198 - acc: 0.7434 - val_loss: 0.6187 - val_acc: 0.7443
Epoch 24/100
100/100 [==============================] - 26s 258ms/step - loss: 0.5140 - acc: 0.7500 - val_loss: 0.3970 - val_acc: 0.7526
Epoch 25/100
100/100 [==============================] - 26s 255ms/step - loss: 0.5125 - acc: 0.7472 - val_loss: 0.4816 - val_acc: 0.7455
Epoch 26/100
100/100 [==============================] - 26s 256ms/step - loss: 0.5137 - acc: 0.7513 - val_loss: 0.5930 - val_acc: 0.7557
Epoch 27/100
100/100 [==============================] - 25s 252ms/step - loss: 0.4968 - acc: 0.7563 - val_loss: 0.4939 - val_acc: 0.7603
Epoch 28/100
100/100 [==============================] - 26s 257ms/step - loss: 0.4934 - acc: 0.7541 - val_loss: 0.2958 - val_acc: 0.7900
Epoch 29/100
100/100 [==============================] - 26s 256ms/step - loss: 0.4958 - acc: 0.7503 - val_loss: 0.5735 - val_acc: 0.7738
Epoch 30/100
100/100 [==============================] - 26s 256ms/step - loss: 0.4845 - acc: 0.7648 - val_loss: 0.5950 - val_acc: 0.7557
Epoch 31/100
100/100 [==============================] - 26s 258ms/step - loss: 0.4881 - acc: 0.7566 - val_loss: 0.4371 - val_acc: 0.7719
Epoch 32/100
100/100 [==============================] - 25s 252ms/step - loss: 0.4831 - acc: 0.7688 - val_loss: 0.2949 - val_acc: 0.7848
Epoch 33/100
100/100 [==============================] - 25s 254ms/step - loss: 0.4824 - acc: 0.7655 - val_loss: 0.4044 - val_acc: 0.7392
Epoch 34/100
100/100 [==============================] - 24s 240ms/step - loss: 0.4876 - acc: 0.7601 - val_loss: 0.4135 - val_acc: 0.7829
Epoch 35/100
100/100 [==============================] - 27s 273ms/step - loss: 0.4843 - acc: 0.7579 - val_loss: 0.4373 - val_acc: 0.7690
Epoch 36/100
100/100 [==============================] - 26s 256ms/step - loss: 0.4707 - acc: 0.7827 - val_loss: 0.2799 - val_acc: 0.7899
Epoch 37/100
100/100 [==============================] - 25s 253ms/step - loss: 0.4705 - acc: 0.7816 - val_loss: 0.7514 - val_acc: 0.7107
Epoch 38/100
100/100 [==============================] - 25s 254ms/step - loss: 0.4769 - acc: 0.7711 - val_loss: 0.6266 - val_acc: 0.7229
Epoch 39/100
100/100 [==============================] - 25s 248ms/step - loss: 0.4617 - acc: 0.7814 - val_loss: 0.4762 - val_acc: 0.7881
Epoch 40/100
100/100 [==============================] - 27s 266ms/step - loss: 0.4558 - acc: 0.7842 - val_loss: 0.3156 - val_acc: 0.7945
Epoch 41/100
100/100 [==============================] - 25s 249ms/step - loss: 0.4673 - acc: 0.7721 - val_loss: 0.6127 - val_acc: 0.7803
Epoch 42/100
100/100 [==============================] - 25s 252ms/step - loss: 0.4551 - acc: 0.7858 - val_loss: 0.6685 - val_acc: 0.7570
Epoch 43/100
100/100 [==============================] - 25s 254ms/step - loss: 0.4567 - acc: 0.7839 - val_loss: 0.4393 - val_acc: 0.7796
Epoch 44/100
100/100 [==============================] - 25s 249ms/step - loss: 0.4636 - acc: 0.7808 - val_loss: 0.3811 - val_acc: 0.8084
Epoch 45/100
100/100 [==============================] - 25s 254ms/step - loss: 0.4580 - acc: 0.7839 - val_loss: 0.4175 - val_acc: 0.7835
Epoch 46/100
100/100 [==============================] - 25s 249ms/step - loss: 0.4405 - acc: 0.7901 - val_loss: 0.4507 - val_acc: 0.8014
Epoch 47/100
100/100 [==============================] - 25s 247ms/step - loss: 0.4358 - acc: 0.7898 - val_loss: 0.4543 - val_acc: 0.8138
Epoch 48/100
100/100 [==============================] - 25s 248ms/step - loss: 0.4406 - acc: 0.7965 - val_loss: 0.4704 - val_acc: 0.7977
Epoch 49/100
100/100 [==============================] - 25s 248ms/step - loss: 0.4423 - acc: 0.7961 - val_loss: 0.3871 - val_acc: 0.8122
Epoch 50/100
100/100 [==============================] - 25s 248ms/step - loss: 0.4353 - acc: 0.7905 - val_loss: 0.6303 - val_acc: 0.8189
Epoch 51/100
100/100 [==============================] - 23s 234ms/step - loss: 0.4254 - acc: 0.8027 - val_loss: 0.3503 - val_acc: 0.8299
Epoch 52/100
100/100 [==============================] - 27s 268ms/step - loss: 0.4265 - acc: 0.7993 - val_loss: 0.4712 - val_acc: 0.8106
Epoch 53/100
100/100 [==============================] - 25s 249ms/step - loss: 0.4239 - acc: 0.8052 - val_loss: 0.4240 - val_acc: 0.8052
Epoch 54/100
100/100 [==============================] - 25s 249ms/step - loss: 0.4270 - acc: 0.8068 - val_loss: 0.4997 - val_acc: 0.8164
Epoch 55/100
100/100 [==============================] - 25s 251ms/step - loss: 0.4209 - acc: 0.8003 - val_loss: 0.6326 - val_acc: 0.8039
Epoch 56/100
100/100 [==============================] - 25s 248ms/step - loss: 0.4329 - acc: 0.8018 - val_loss: 0.4907 - val_acc: 0.7642
Epoch 57/100
100/100 [==============================] - 26s 259ms/step - loss: 0.4196 - acc: 0.8065 - val_loss: 0.4612 - val_acc: 0.8318
Epoch 58/100
100/100 [==============================] - 25s 248ms/step - loss: 0.4197 - acc: 0.8090 - val_loss: 0.6534 - val_acc: 0.7957
Epoch 59/100
100/100 [==============================] - 25s 253ms/step - loss: 0.4141 - acc: 0.8125 - val_loss: 0.4440 - val_acc: 0.7693
Epoch 60/100
100/100 [==============================] - 25s 250ms/step - loss: 0.4086 - acc: 0.8068 - val_loss: 0.3602 - val_acc: 0.7944
Epoch 61/100
100/100 [==============================] - 25s 252ms/step - loss: 0.4119 - acc: 0.8160 - val_loss: 0.3499 - val_acc: 0.7964
Epoch 62/100
100/100 [==============================] - 25s 252ms/step - loss: 0.4031 - acc: 0.8134 - val_loss: 0.2722 - val_acc: 0.8147
Epoch 63/100
100/100 [==============================] - 25s 253ms/step - loss: 0.4146 - acc: 0.8087 - val_loss: 0.5688 - val_acc: 0.8067
Epoch 64/100
100/100 [==============================] - 25s 252ms/step - loss: 0.3985 - acc: 0.8122 - val_loss: 0.2003 - val_acc: 0.7951
Epoch 65/100
100/100 [==============================] - 25s 255ms/step - loss: 0.3964 - acc: 0.8122 - val_loss: 0.5255 - val_acc: 0.7843
Epoch 66/100
100/100 [==============================] - 25s 252ms/step - loss: 0.3960 - acc: 0.8210 - val_loss: 0.4698 - val_acc: 0.8035
Epoch 67/100
100/100 [==============================] - 25s 252ms/step - loss: 0.3984 - acc: 0.8194 - val_loss: 0.4008 - val_acc: 0.8122
Epoch 68/100
100/100 [==============================] - 25s 247ms/step - loss: 0.3952 - acc: 0.8235 - val_loss: 0.3911 - val_acc: 0.7854
Epoch 69/100
100/100 [==============================] - 27s 268ms/step - loss: 0.3929 - acc: 0.8229 - val_loss: 0.3712 - val_acc: 0.8039
Epoch 70/100
100/100 [==============================] - 26s 256ms/step - loss: 0.3888 - acc: 0.8260 - val_loss: 0.4618 - val_acc: 0.8183
Epoch 71/100
100/100 [==============================] - 25s 253ms/step - loss: 0.3854 - acc: 0.8242 - val_loss: 0.1919 - val_acc: 0.8141
Epoch 72/100
100/100 [==============================] - 26s 257ms/step - loss: 0.3920 - acc: 0.8254 - val_loss: 0.4077 - val_acc: 0.8048
Epoch 73/100
100/100 [==============================] - 25s 248ms/step - loss: 0.3847 - acc: 0.8194 - val_loss: 0.3354 - val_acc: 0.8215
Epoch 74/100
100/100 [==============================] - 26s 261ms/step - loss: 0.3873 - acc: 0.8204 - val_loss: 0.3557 - val_acc: 0.8319
Epoch 75/100
100/100 [==============================] - 25s 254ms/step - loss: 0.3810 - acc: 0.8280 - val_loss: 0.2042 - val_acc: 0.8209
Epoch 76/100
100/100 [==============================] - 25s 251ms/step - loss: 0.3729 - acc: 0.8308 - val_loss: 0.4523 - val_acc: 0.8173
Epoch 77/100
100/100 [==============================] - 25s 255ms/step - loss: 0.3765 - acc: 0.8348 - val_loss: 0.3507 - val_acc: 0.8363
Epoch 78/100
100/100 [==============================] - 25s 254ms/step - loss: 0.3717 - acc: 0.8273 - val_loss: 0.2907 - val_acc: 0.8115
Epoch 79/100
100/100 [==============================] - 25s 254ms/step - loss: 0.3764 - acc: 0.8284 - val_loss: 0.3448 - val_acc: 0.8331
Epoch 80/100
100/100 [==============================] - 24s 241ms/step - loss: 0.3712 - acc: 0.8354 - val_loss: 0.1281 - val_acc: 0.8215
Epoch 81/100
100/100 [==============================] - 27s 274ms/step - loss: 0.3649 - acc: 0.8286 - val_loss: 0.7544 - val_acc: 0.7874
Epoch 82/100
100/100 [==============================] - 25s 251ms/step - loss: 0.3710 - acc: 0.8371 - val_loss: 0.3130 - val_acc: 0.8241
Epoch 83/100
100/100 [==============================] - 26s 255ms/step - loss: 0.3537 - acc: 0.8417 - val_loss: 0.4078 - val_acc: 0.8312
Epoch 84/100
100/100 [==============================] - 26s 255ms/step - loss: 0.3796 - acc: 0.8277 - val_loss: 0.3538 - val_acc: 0.8254
Epoch 85/100
100/100 [==============================] - 25s 245ms/step - loss: 0.3546 - acc: 0.8477 - val_loss: 0.2819 - val_acc: 0.8388
Epoch 86/100
100/100 [==============================] - 27s 268ms/step - loss: 0.3467 - acc: 0.8510 - val_loss: 0.4794 - val_acc: 0.8428
Epoch 87/100
100/100 [==============================] - 26s 257ms/step - loss: 0.3539 - acc: 0.8467 - val_loss: 0.2452 - val_acc: 0.8274
Epoch 88/100
100/100 [==============================] - 26s 256ms/step - loss: 0.3405 - acc: 0.8510 - val_loss: 0.3204 - val_acc: 0.8247
Epoch 89/100
100/100 [==============================] - 26s 257ms/step - loss: 0.3427 - acc: 0.8543 - val_loss: 0.3466 - val_acc: 0.8138
Epoch 90/100
100/100 [==============================] - 25s 254ms/step - loss: 0.3488 - acc: 0.8455 - val_loss: 0.2954 - val_acc: 0.8319
Epoch 91/100
100/100 [==============================] - 26s 260ms/step - loss: 0.3456 - acc: 0.8434 - val_loss: 0.3080 - val_acc: 0.8144
Epoch 92/100
100/100 [==============================] - 26s 259ms/step - loss: 0.3385 - acc: 0.8523 - val_loss: 0.6150 - val_acc: 0.8439
Epoch 93/100
100/100 [==============================] - 25s 255ms/step - loss: 0.3515 - acc: 0.8472 - val_loss: 0.2326 - val_acc: 0.8363
Epoch 94/100
100/100 [==============================] - 26s 256ms/step - loss: 0.3388 - acc: 0.8536 - val_loss: 0.4098 - val_acc: 0.8388
Epoch 95/100
100/100 [==============================] - 25s 255ms/step - loss: 0.3302 - acc: 0.8576 - val_loss: 0.4681 - val_acc: 0.8286
Epoch 96/100
100/100 [==============================] - 25s 254ms/step - loss: 0.3335 - acc: 0.8549 - val_loss: 0.1140 - val_acc: 0.8280
Epoch 97/100
100/100 [==============================] - 24s 240ms/step - loss: 0.3389 - acc: 0.8434 - val_loss: 0.4625 - val_acc: 0.7982
Epoch 98/100
100/100 [==============================] - 27s 270ms/step - loss: 0.3292 - acc: 0.8518 - val_loss: 0.2730 - val_acc: 0.8479
Epoch 99/100
100/100 [==============================] - 25s 253ms/step - loss: 0.3307 - acc: 0.8554 - val_loss: 0.3123 - val_acc: 0.8293
Epoch 100/100
100/100 [==============================] - 25s 252ms/step - loss: 0.3238 - acc: 0.8576 - val_loss: 0.3500 - val_acc: 0.8428

In [15]:
acc = history.history['acc']
val_acc = history.history['val_acc']
loss = history.history['loss']
val_loss = history.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.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.show()


上圖,將貓與狗的訓練樣本由 2,000 擴增為 3,200,並且在網路最後一層 Dropout 50%,可將正確率由 0.7 提昇至 0.85。