Python-貓狗數據集兩階段分類 原始數據直接訓練;數據增強後訓練

本博客運行環境爲Jupyter Notebook-Python3.7。
由於我使用的是Anaconda3配置的jupyter環境,我也將直接在anaconda下搭建keras環境。

由於我電腦性能不是很好,又是AMD顯卡的,本博客是燒cpu版本的,運行過程會比較慢。

下載tensorflow、keras

直接找到Anaconda Powershell右鍵管理員身份運行。
在這裏插入圖片描述
輸入下列兩條命令

conda install tensorflow
conda install keras

安裝好後,可以進入jupyter來試一試了。
可以查看keras版本。

import keras
keras.__version__

輸出如下:

Using TensorFlow backend.

'2.3.1'

下載數據集並重新劃分

可以從這裏下載貓狗數據集:https://www.kaggle.com/c/dogs-vs-cats/data
原始數據集包含25000張狗和貓的圖片(每個類12500張),543MB。下載並解壓後,我們將創建一個包含三個子集的新數據集:1000個樣本的訓練集(train),500個樣本的驗證集(validation),500個樣本的測試集(test)。

代碼如下:

D://jupyterwork//AI//data//kaggle_original_data是存放原始數據集的位置,kaggle_original_data是原始數據集的名字。
D://jupyterwork//AI//data//cats_and_dogs_small是創建的新數據集的位置,cats_and_dogs_small是新數據集的名字。

import os, shutil
# 原始數據集路徑
original_dataset_dir = 'D://jupyterwork//AI//data//kaggle_original_data'

# 新的數據集
base_dir = 'D://jupyterwork//AI//data//cats_and_dogs_small'
os.mkdir(base_dir)

# 訓練圖像、驗證圖像、測試圖像的目錄
train_dir = os.path.join(base_dir, 'train')
os.mkdir(train_dir)
validation_dir = os.path.join(base_dir, 'validation')
os.mkdir(validation_dir)
test_dir = os.path.join(base_dir, 'test')
os.mkdir(test_dir)

# 訓練集-貓的圖片
train_cats_dir = os.path.join(train_dir, 'cats')
os.mkdir(train_cats_dir)

#訓練集-狗的圖片
train_dogs_dir = os.path.join(train_dir, 'dogs')
os.mkdir(train_dogs_dir)

# 驗證集-貓的圖片
validation_cats_dir = os.path.join(validation_dir, 'cats')
os.mkdir(validation_cats_dir)

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

# 測試集-貓的圖片
test_cats_dir = os.path.join(test_dir, 'cats')
os.mkdir(test_cats_dir)

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

# 複製1000張貓的圖片到train_cats_dir
fnames = ['cat.{}.jpg'.format(i) for i in range(1000)]
for fname in fnames:
    src = os.path.join(original_dataset_dir, fname)
    dst = os.path.join(train_cats_dir, fname)
    shutil.copyfile(src, dst)

#複製接着的500張貓的圖片到validation_cats_dir
fnames = ['cat.{}.jpg'.format(i) for i in range(1000, 1500)]
for fname in fnames:
    src = os.path.join(original_dataset_dir, 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(1500, 2000)]
for fname in fnames:
    src = os.path.join(original_dataset_dir, 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(1000)]
for fname in fnames:
    src = os.path.join(original_dataset_dir, 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(1000, 1500)]
for fname in fnames:
    src = os.path.join(original_dataset_dir, 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(1500, 2000)]
for fname in fnames:
    src = os.path.join(original_dataset_dir, fname)
    dst = os.path.join(test_dogs_dir, fname)
    shutil.copyfile(src, dst)

編譯成功後,我們可以看到對應位置生成了新的數據集。
在這裏插入圖片描述

我們可以驗證一下剛剛的訓練分割的數據集中有多少圖片(訓練/驗證/測試)

print('total training cat images:', len(os.listdir(train_cats_dir)))

total training cat images: 1000

print('total training dog images:', len(os.listdir(train_dogs_dir)))

total training dog images: 1000

print('total validation cat images:', len(os.listdir(validation_cats_dir)))

total validation cat images: 500

print('total validation dog images:', len(os.listdir(validation_dogs_dir)))

total validation dog images: 500

print('total test cat images:', len(os.listdir(test_cats_dir)))

total test cat images: 500

print('total test dog images:', len(os.listdir(test_dogs_dir)))

total test dog images: 500

我們訓練集中確實有2000個圖像,驗證集中有1000個驗證圖像,測試集中1000個圖像。

卷積網絡(ConvNet)將是一組交替的Conv2D(具有relu激活)和MaxPooling2D層。從大小150x150的輸入開始,最終得到尺寸爲7x7的Flatten層之前的特徵圖。

注意特徵圖的深度在網絡中逐漸增加(從32到128),而特徵圖的大小正在減少(從148x148到7x7)。這是一個幾乎在所有的卷積網絡(ConvNet)結構中會看到的模式。

由於我們正在處理二元分類問題,所以我們用一個神經元(一個大小爲1的密集層(Dense))和一個sigmoid激活函數來結束網絡。該神經元將會被用來查看圖像歸屬於那一類或另一類的概率。

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'))

輸出模型各層參數狀況:

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
_________________________________________________________________

使用“RMSprop”優化器:

from keras import optimizers

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

數據預處理

1、讀入圖片文件。
2、將JPEG內容解碼爲RBG像素網格。
3、把它們轉換成浮點張量。
4、將像素值(介於0和255之間)重新縮放到[0,1]間隔。

Keras有一個帶有圖像處理輔助工具的模塊,位於keras.preprocessing.image文件。它包含ImageDataGenerator類,該類可以快速設置Python生成器,該生成器可以自動將磁盤上的圖像文件轉換成批預處理的張量。

代碼如下:

from keras.preprocessing.image import ImageDataGenerator

# 所有的圖像將重新進行歸一化處理 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,
        # 所有圖像大小會被轉換成150x150
        target_size=(150, 150),
        batch_size=20,
        # 由於這是一個二元分類問題,y的label值也會被轉換成二元的標籤
        class_mode='binary')
# 直接從目錄讀取圖像數據
validation_generator = test_datagen.flow_from_directory(
        validation_dir,
        target_size=(150, 150),
        batch_size=20,
        class_mode='binary')

運行結果如下:
Found 2000 images belonging to 2 classes.
Found 1000 images belonging to 2 classes.

可以看一下其中一個生成器的輸出:它生成150x150的RGB圖像(shape(20,150,150,3))和二進制標籤(shape(20,))。
20是每批樣品的數量(批量大小)。ps:生成器無限期地生成這些批:它只是在目標文件夾中的圖像上無休止地循環。因此,我們需要在某個點上中斷迭代循環。

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

運行結果如下:
data batch shape: (20, 150, 150, 3)
labels batch shape: (20,)

訓練

我們使用生成器將模型與數據擬合。我們使用fit_generator來實現,它希望第一個參數是Python生成器,將無限期地生成一批輸入和目標。由於數據是無休止地生成的,生成器需要知道在聲明一個紀元結束之前要從生成器中抽取多少樣本。這是steps_per_epoch參數的作用:從生成器中繪製steps_per_epoch批後,即在運行steps_per_epoch梯度下降步驟後,擬合過程將轉到下一個epoch。也就是說我們將訓練數據的總數除以批量大小的結果作爲steps_per_epoch的值。一旦Keras到達這一步,它就會知道這是一個新的epoch。
在我們的例子中,批次是20個大樣本,因此它將需要100個批次,直到我們看到2000個樣本的目標。

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

運行結果如下:
電腦性能不太好就會跑的有點慢,快一些的每個epoch大概8s左右。

Epoch 1/30
100/100 [==============================] - 54s 543ms/step - loss: 0.6935 - acc: 0.5130 - val_loss: 0.7036 - val_acc: 0.5180
Epoch 2/30
100/100 [==============================] - 56s 559ms/step - loss: 0.6550 - acc: 0.6130 - val_loss: 0.6227 - val_acc: 0.6480
Epoch 3/30
100/100 [==============================] - 54s 545ms/step - loss: 0.6043 - acc: 0.6585 - val_loss: 0.6725 - val_acc: 0.6790
Epoch 4/30
100/100 [==============================] - 54s 542ms/step - loss: 0.5693 - acc: 0.6865 - val_loss: 0.6075 - val_acc: 0.6780
Epoch 5/30
100/100 [==============================] - 54s 536ms/step - loss: 0.5359 - acc: 0.7245 - val_loss: 0.6992 - val_acc: 0.6910
Epoch 6/30
100/100 [==============================] - 54s 542ms/step - loss: 0.5029 - acc: 0.7530 - val_loss: 0.4156 - val_acc: 0.6990
Epoch 7/30
100/100 [==============================] - 58s 575ms/step - loss: 0.4844 - acc: 0.7720 - val_loss: 0.5446 - val_acc: 0.6980
Epoch 8/30
100/100 [==============================] - 55s 545ms/step - loss: 0.4447 - acc: 0.7970 - val_loss: 0.4741 - val_acc: 0.6970
Epoch 9/30
100/100 [==============================] - 54s 542ms/step - loss: 0.4208 - acc: 0.8040 - val_loss: 0.4067 - val_acc: 0.7030
Epoch 10/30
100/100 [==============================] - 54s 541ms/step - loss: 0.3892 - acc: 0.8225 - val_loss: 0.6877 - val_acc: 0.7060
Epoch 11/30
100/100 [==============================] - 55s 551ms/step - loss: 0.3695 - acc: 0.8360 - val_loss: 0.3179 - val_acc: 0.7340
Epoch 12/30
100/100 [==============================] - 55s 547ms/step - loss: 0.3402 - acc: 0.8480 - val_loss: 0.4159 - val_acc: 0.7310
Epoch 13/30
100/100 [==============================] - 56s 559ms/step - loss: 0.3143 - acc: 0.8645 - val_loss: 0.8054 - val_acc: 0.7050
Epoch 14/30
100/100 [==============================] - 57s 567ms/step - loss: 0.2979 - acc: 0.8760 - val_loss: 0.4196 - val_acc: 0.7290
Epoch 15/30
100/100 [==============================] - 54s 545ms/step - loss: 0.2663 - acc: 0.8980 - val_loss: 0.7709 - val_acc: 0.7280
Epoch 16/30
100/100 [==============================] - 54s 545ms/step - loss: 0.2527 - acc: 0.8975 - val_loss: 0.6916 - val_acc: 0.7360
Epoch 17/30
100/100 [==============================] - 55s 550ms/step - loss: 0.2254 - acc: 0.9180 - val_loss: 0.6579 - val_acc: 0.7290
Epoch 18/30
100/100 [==============================] - 54s 541ms/step - loss: 0.1983 - acc: 0.9220 - val_loss: 0.5245 - val_acc: 0.7280
Epoch 19/30
100/100 [==============================] - 57s 569ms/step - loss: 0.1736 - acc: 0.9385 - val_loss: 1.1733 - val_acc: 0.7280
Epoch 20/30
100/100 [==============================] - 54s 536ms/step - loss: 0.1627 - acc: 0.9450 - val_loss: 0.4002 - val_acc: 0.7350
Epoch 21/30
100/100 [==============================] - 55s 554ms/step - loss: 0.1478 - acc: 0.9505 - val_loss: 0.6728 - val_acc: 0.7220
Epoch 22/30
100/100 [==============================] - 55s 549ms/step - loss: 0.1245 - acc: 0.9595 - val_loss: 0.3836 - val_acc: 0.7370
Epoch 23/30
100/100 [==============================] - 54s 539ms/step - loss: 0.1059 - acc: 0.9690 - val_loss: 0.2034 - val_acc: 0.7250
Epoch 24/30
100/100 [==============================] - 55s 547ms/step - loss: 0.0996 - acc: 0.9680 - val_loss: 0.7567 - val_acc: 0.7390
Epoch 25/30
100/100 [==============================] - 55s 547ms/step - loss: 0.0773 - acc: 0.9750 - val_loss: 1.1593 - val_acc: 0.7400
Epoch 26/30
100/100 [==============================] - 55s 545ms/step - loss: 0.0689 - acc: 0.9820 - val_loss: 1.4114 - val_acc: 0.7250
Epoch 27/30
100/100 [==============================] - 57s 567ms/step - loss: 0.0569 - acc: 0.9845 - val_loss: 0.8993 - val_acc: 0.7100
Epoch 28/30
100/100 [==============================] - 56s 558ms/step - loss: 0.0473 - acc: 0.9870 - val_loss: 1.4554 - val_acc: 0.7310
Epoch 29/30
100/100 [==============================] - 57s 567ms/step - loss: 0.0456 - acc: 0.9850 - val_loss: 0.9483 - val_acc: 0.7310
Epoch 30/30
100/100 [==============================] - 57s 565ms/step - loss: 0.0339 - acc: 0.9935 - val_loss: 2.1054 - val_acc: 0.7100

訓練完成後,把保存模型。命名爲cats_and_dogs_small_1.h5,默認保存到對應的編譯文件夾。

model.save('cats_and_dogs_small_1.h5')

訓練過程中模型對訓練和驗證數據的損失(loss)和準確性(accuracy)數據對比圖

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()

如下圖所示:
這些曲線圖具有過度擬合的特點。隨着時間的推移,我們的訓練準確率呈線性增長,直到接近100%,而我們的驗證準確率則停滯在70%多一點。我們的驗證損失在五個階段後達到最小,然後停止,而訓練損失保持線性下降,直到接近0。
在這裏插入圖片描述
因爲我們只有相對較少的訓練樣本(2000張),所以過度擬合將是我們最關心的問題。
過擬合(over-fitting)也稱爲過學習,它的直觀表現是算法在訓練集上表現好,但在測試集上表現不好,泛化性能差。過擬合是在模型參數擬合過程中由於訓練數據包含抽樣誤差,在訓練時複雜的模型將抽樣誤差也進行了擬合導致的。

數據增強

數據增強(data augmentation),意思是讓有限的數據通過某種變換操作產生更多的等價數據的過程。數據增強主要用來防止過擬合,用於數據較小的時候。

過擬合使得我們無法訓練一個能夠推廣到新數據的模型。給定無限的數據,我們的模型將暴露在手頭數據分佈的所有可能方面:我們永遠不會過度擬合。數據增強採用的方法是從現有的訓練樣本中生成更多的訓練數據,通過一些隨機變換“增強”樣本,從而生成可信的圖像。我們的目標是在訓練的時候,我們的模特永遠不會看到完全一樣的畫面兩次。這有助於模型暴露於數據的更多方面,並更好地進行泛化。
在Keras中,這可以通過配置要對ImageDataGenerator實例讀取的圖像執行的一些隨機轉換來完成。

參數詳解
1、rotation_range是以度(0-180)爲單位的值,它是隨機旋轉圖片的範圍。
2、width_shift和height_shift是範圍(佔總寬度或高度的一小部分),用於縱向或橫向隨機轉換圖片。
3、shear_range用於隨機剪切變換。
4、zoom_range用於隨機放大圖片內容。
5、horizontal_flip用於在沒有水平不對稱假設(例如真實世界圖片)的情況下水平地隨機翻轉一半圖像。
6、fill_mode是用於填充新創建的像素的策略,可以在旋轉或寬/高移位後顯示。

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')

看看增強後的圖像:

# 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()

如下圖所示:
在這裏插入圖片描述

我們使用這種數據增強配置訓練一個新的網絡,將永遠不會看到兩次相同的輸入。然而,它看到的輸入仍然是高度相關的,因爲它們來自於少量的原始圖像——我們不能產生新的信息,我們只能重新混合現有的信息。因此,這可能還不足以完全擺脫過度裝修。爲了進一步克服過擬合,我們還將在模型中的密接分類器(densely-connected)前添加一個Dropout:

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))
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'])

使用數據增強(data augmentation)和dropout來訓練我們的網絡

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,
        #所有的圖像大小會被轉換成150x150
        target_size=(150, 150),
        batch_size=32,
        #由於這是一個二元分類問題,y的label值也會被轉換成二元的標籤
        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 [==============================] - 86s 858ms/step - loss: 0.6924 - acc: 0.5091 - val_loss: 0.6648 - val_acc: 0.5584
Epoch 2/100
100/100 [==============================] - 82s 824ms/step - loss: 0.6809 - acc: 0.5628 - val_loss: 0.6982 - val_acc: 0.6031
Epoch 3/100
100/100 [==============================] - 87s 869ms/step - loss: 0.6648 - acc: 0.6010 - val_loss: 0.6746 - val_acc: 0.6085
Epoch 4/100
100/100 [==============================] - 84s 839ms/step - loss: 0.6451 - acc: 0.6168 - val_loss: 0.6111 - val_acc: 0.6244
 ……
Epoch 98/100
100/100 [==============================] - 92s 925ms/step - loss: 0.3324 - acc: 0.8520 - val_loss: 0.4216 - val_acc: 0.8202
Epoch 99/100
100/100 [==============================] - 92s 920ms/step - loss: 0.3470 - acc: 0.8489 - val_loss: 0.3072 - val_acc: 0.8261
Epoch 100/100
100/100 [==============================] - 92s 921ms/step - loss: 0.3450 - acc: 0.8460 - val_loss: 0.4872 - val_acc: 0.8338

訓練完成後,把保存模型。命名爲cats_and_dogs_small_2.h5,默認保存到對應的編譯文件夾。

model.save('cats_and_dogs_small_2.h5')

訓練過程中模型對訓練和驗證數據的損失(loss)和準確性(accuracy)數據對比圖

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()

運行結果如下:
在這裏插入圖片描述

由於數據增加和Dropout,不再過擬合:訓練曲線非常接近於驗證曲線。我們現在能夠達到83%的精度,比非正則模型相對提高了15%。
通過進一步利用正則化技術並通過調整網絡參數(例如每個卷積層的濾波器數量或網絡層數量),我們可能獲得更好的精度,可能高達86-87%。

參考教程:https://github.com/fchollet/deep-learning-with-python-notebooks/blob/master/5.2-using-convnets-with-small-datasets.ipynb

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章