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

猜你喜欢

转载自blog.csdn.net/JSerenity/article/details/89520334