TensorFlow Specialization Course 2 學習筆記

TensorFlow Specialization Course 2

Week1主要講了在數據集比較小的情況下很容易過擬合的問題。

Week2給出解決過擬合問題的一種解決方法:數據增強。

Week3主要講遷移學習,同時使用數據增強,另外介紹了另一種解決過擬合問題的方法:Dropout。

Week4主要講多分類問題,從二分類擴展到多分類。
多分類和二分類不同的地方有:
設置class_mode=‘categorical’。
tf.keras.layers.Dense(3, activation=‘softmax’) # 此處的3表示3種類別
設置loss=‘categorical_crossentropy’

每一週的內容都比較少,所以放在一起總結。

我們下面使用前三週所講的知識(遷移學習+數據增強+Dropout)來完成Kaggle比賽的狗貓分類。

下面代碼全部運行在Colab上。

導入必要的包

import os
import zipfile
import random
import tensorflow as tf
from tensorflow.keras.optimizers import RMSprop
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from shutil import copyfile

下載數據集

!wget --no-check-certificate \
    "https://download.microsoft.com/download/3/E/1/3E1C3F21-ECDB-4869-8368-6DEBA77B919F/kagglecatsanddogs_3367a.zip" \
    -O "/tmp/cats-and-dogs.zip"

local_zip = '/tmp/cats-and-dogs.zip'
zip_ref   = zipfile.ZipFile(local_zip, 'r')
zip_ref.extractall('/tmp')
zip_ref.close()

print(len(os.listdir('/tmp/PetImages/Cat/')))
print(len(os.listdir('/tmp/PetImages/Dog/')))

# Expected Output:
# 12501
# 12501
try:
    os.mkdir('/tmp/cats-v-dogs')
    os.mkdir('/tmp/cats-v-dogs/training')
    os.mkdir('/tmp/cats-v-dogs/testing')
    os.mkdir('/tmp/cats-v-dogs/training/cats')
    os.mkdir('/tmp/cats-v-dogs/training/dogs')
    os.mkdir('/tmp/cats-v-dogs/testing/cats')
    os.mkdir('/tmp/cats-v-dogs/testing/dogs')
except OSError:
    pass

創建數據集目錄,下一步將圖像複製到對應文件夾中。需要注意的是,公開數據集中的數據並不是完美的,例如本次使用的數據集中存在文件大小爲空的圖像,需要把他們去除。

def split_data(SOURCE, TRAINING, TESTING, SPLIT_SIZE):
    files = []
    for filename in os.listdir(SOURCE):
        file = SOURCE + filename
        if os.path.getsize(file) > 0:
            files.append(filename)
        else:
            print(filename + " is zero length, so ignoring.")

    training_length = int(len(files) * SPLIT_SIZE)
    testing_length = int(len(files) - training_length)
    shuffled_set = random.sample(files, len(files))
    training_set = shuffled_set[0:training_length]
    testing_set = shuffled_set[-testing_length:]

    for filename in training_set:
        this_file = SOURCE + filename
        destination = TRAINING + filename
        copyfile(this_file, destination)

    for filename in testing_set:
        this_file = SOURCE + filename
        destination = TESTING + filename
        copyfile(this_file, destination)

CAT_SOURCE_DIR = "/tmp/PetImages/Cat/"
TRAINING_CATS_DIR = "/tmp/cats-v-dogs/training/cats/"
TESTING_CATS_DIR = "/tmp/cats-v-dogs/testing/cats/"
DOG_SOURCE_DIR = "/tmp/PetImages/Dog/"
TRAINING_DOGS_DIR = "/tmp/cats-v-dogs/training/dogs/"
TESTING_DOGS_DIR = "/tmp/cats-v-dogs/testing/dogs/"

split_size = .9
split_data(CAT_SOURCE_DIR, TRAINING_CATS_DIR, TESTING_CATS_DIR, split_size)
split_data(DOG_SOURCE_DIR, TRAINING_DOGS_DIR, TESTING_DOGS_DIR, split_size)

# Expected output
# 666.jpg is zero length, so ignoring
# 11702.jpg is zero length, so ignoring

使用遷移學習。

from tensorflow.keras import layers
from tensorflow.keras import Model
from tensorflow.keras.optimizers import RMSprop


!wget --no-check-certificate \
    https://storage.googleapis.com/mledu-datasets/inception_v3_weights_tf_dim_ordering_tf_kernels_notop.h5 \
    -O /tmp/inception_v3_weights_tf_dim_ordering_tf_kernels_notop.h5

from tensorflow.keras.applications.inception_v3 import InceptionV3

local_weights_file = '/tmp/inception_v3_weights_tf_dim_ordering_tf_kernels_notop.h5'

pre_trained_model = InceptionV3(input_shape=(150, 150, 3),
                               	input_top=False,		# False則表示只使用卷積層,去掉InceptionV3的全連接層
                               	weights=None)		# None爲隨機初始化 如選'imagenet'表示在ImageNet上預訓練的權重

# 載入我們下載好的預訓練權重
pre_trained_model.load_weights(local_weights_file)

# 先讓所有的卷積層凍結(參數不可訓練),因爲前面的卷積層的參數已經訓練好,我們不希望他們變化
for layer in pre_trained_model.layers:
    layer.trainable = False
    
# pre_trained_model.summary()

# 可能最後幾層卷積層學習檢測的特徵也比較專門化,我們可以多棄幾層。比如下面我們直接使用mixed7層的輸出接我們的全連接層
last_layer = pre_trained_model.get_layer('mixed7')
print('last layer output shape: ', last_layer.output_shape)
last_output = last_layer.output

x = layers.Flatten()(last_output)

x = layers.Dense(1024, activation='relu')(x)
# 使用Dropout來防止過擬合。Dropout作用於上面的的層。
x = layers.Dropout(0.2)(x)

x = layers.Dense(1, activation='sigmoid')(x)

# Model這裏接受兩個參數 模型的輸入和輸出
model = Model(pre_trained_model.input, x)

model.compile(optimizer=RMSprop(lr=0.0001), loss='binary_crossentropy', metrics=['acc'])

和之前一樣使用ImageDataGenerator訓練數據預處理,不同的是,我們在訓練集上使用數據增強來擴充數據集從而防止過擬合。在ImageDataGenerator方法中添加數據增強的參數。

TRAINING_DIR = "/tmp/cats-v-dogs/training/"

# train_datagen = ImageDataGenerator(rescale=1./255.)
# 數據增強
train_datagen = ImageDataGenerator(
    rescale=1./255.,
    # 隨機旋轉圖像,角度取值範圍(0-180),
    rotation_range=40,
    # 上下或左右平移的範圍,0.2爲圖像大小的20%。
    width_shift_range=0.2,
    height_shift_range=0.2,
    # 水平或垂直投影變換
    shear_range=0.2,
    # Randomly zooming inside pictures.
    zoom_range=0.2,
    # 水平翻轉
    horizontal_flip=True,
    # 用於填充旋轉或水平/垂直移動後填補像素 (什麼時候用?什麼時候不用?)
    fill_mode='nearest')
train_generator = train_datagen.flow_from_directory(
    TRAINING_DIR,
 	batch_size=100,
 	class_mode='binary',
 	target_size=(150, 150))

# 數據增強需要根據數據集特點來調整
# 例如之前的人-馬數據集中 人和馬都是直立着的。如果使用了圖像旋轉的方法,則驗證集的準確率比較低且波動很大。因爲驗證集中並沒有平躺的人或馬。
VALIDATION_DIR = "/tmp/cats-v-dogs/testing/"
validation_datagen = ImageDataGenerator(rescale=1.0/255.)
validation_generator = validation_datagen.flow_from_directory(VALIDATION_DIR,
                                                              batch_size=100,
                                                              class_mode='binary',
                                                              target_size=(150, 150))
# Expected Output:
# Found 22498 images belonging to 2 classes.
# Found 2500 images belonging to 2 classes.

開始訓練,將訓練的數據存入history。

history = model.fit_generator(train_generator,
                              epochs=50,
                              verbose=1,
                              validation_data=validation_generator)

可視化訓練過程中的loss和accuracy變化。

%matplotlib inline

import matplotlib.image  as mpimg
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)) # Get number of epochs

# 展示每一次迭代訓練集和驗證集的accuracy
plt.plot(epochs, acc, 'r', "Training Accuracy")
plt.plot(epochs, val_acc, 'b', "Validation Accuracy")
plt.title('Training and validation accuracy')
plt.figure()

# 展示每一次迭代訓練集和驗證集的loss
plt.plot(epochs, loss, 'r', "Training Loss")
plt.plot(epochs, val_loss, 'b', "Validation Loss")
plt.figure()

查看如何在colab上使用Kaggle API向Kaggle提交答案:https://blog.csdn.net/JSerenity/article/details/89713458

Kaggle鏈接:https://www.kaggle.com/c/dogs-vs-cats

參考:

https://github.com/lmoroney/dlaicourse/blob/master/Course 2 - Part 4 - Lesson 2 - Notebook (Cats v Dogs Augmentation).ipynb

<https://github.com/lmoroney/dlaicourse/blob/master/Course 2 - Part 6 - Lesson 3 - Notebook.ipynb

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