【深度学习图像识别课程】keras实现CNN系列:(8)keras迁移学习实战-狗类品种分类

时间:2021-03-14 18:35:54

1、实战分析

背景:数据集8351张图,每张都是狗狗照片,共133种。

目标:用CNN实现狗类品种分类

方法:使用ImageNet上预先训练好的VGG16

分析场景:狗类数据集较小,与ImageNet相似度较高

【深度学习图像识别课程】keras实现CNN系列:(8)keras迁移学习实战-狗类品种分类

将最后的全连接层删除,换成新的连接层。冻结前面模型的权重,只训练最后一个连接层的权重。

【深度学习图像识别课程】keras实现CNN系列:(8)keras迁移学习实战-狗类品种分类


我们将所有的图片,都直接穿过之前的网络一直到红色的最大池化层,做为新的输入。则我们需要训练的网络只剩下2层。

【深度学习图像识别课程】keras实现CNN系列:(8)keras迁移学习实战-狗类品种分类

【深度学习图像识别课程】keras实现CNN系列:(8)keras迁移学习实战-狗类品种分类


二、实战

2.1 模型1
1、加载数据库
from sklearn.datasets import load_files       
from keras.utils import np_utils
import numpy as np
from glob import glob

# define function to load train, test, and validation datasets
def load_dataset(path):
    data = load_files(path)
    dog_files = np.array(data['filenames'])
    dog_targets = np_utils.to_categorical(np.array(data['target']), 133)
    return dog_files, dog_targets

# load train, test, and validation datasets
train_files, train_targets = load_dataset('dogImages/train')
valid_files, valid_targets = load_dataset('dogImages/valid')
test_files, test_targets = load_dataset('dogImages/test')

# load ordered list of dog names
dog_names = [item[25:-1] for item in glob('dogImages/train/*/')]

# print statistics about the dataset
print('There are %d total dog categories.' % len(dog_names))
print('There are %s total dog images.\n' % str(len(train_files) + len(valid_files) + len(test_files)))
print('There are %d training dog images.' % len(train_files))
print('There are %d validation dog images.' % len(valid_files))
print('There are %d test dog images.'% len(test_files))

【深度学习图像识别课程】keras实现CNN系列:(8)keras迁移学习实战-狗类品种分类

2、可视化部分图片
import cv2
import matplotlib.pyplot as plt
%matplotlib inline

def visualize_img(img_path, ax):
    img = cv2.imread(img_path)
    ax.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
    
fig = plt.figure(figsize=(20, 10))
for i in range(12):
    ax = fig.add_subplot(3, 4, i + 1, xticks=[], yticks=[])
    visualize_img(train_files[i], ax)

【深度学习图像识别课程】keras实现CNN系列:(8)keras迁移学习实战-狗类品种分类

3、读入VGG16瓶颈特征
bottleneck_features = np.load('bottleneck_features/DogVGG16Data.npz')
train_vgg16 = bottleneck_features['train']
valid_vgg16 = bottleneck_features['valid']
test_vgg16 = bottleneck_features['test']
4、模型1
from keras.layers import Dense, Flatten
from keras.models import Sequential

model = Sequential()
model.add(Flatten(input_shape=(7, 7, 512)))
model.add(Dense(133, activation='softmax'))
model.compile(loss='categorical_crossentropy', optimizer='rmsprop', 
                  metrics=['accuracy'])
model.summary()

【深度学习图像识别课程】keras实现CNN系列:(8)keras迁移学习实战-狗类品种分类

5、模型编译
model.compile(loss='categorical_crossentropy', optimizer='rmsprop', 
                  metrics=['accuracy'])
6、模型训练
from keras.callbacks import ModelCheckpoint   

# train the model
checkpointer = ModelCheckpoint(filepath='dogvgg16.weights.best.hdf5', verbose=1, 
                               save_best_only=True)
model.fit(train_vgg16, train_targets, epochs=20, validation_data=(valid_vgg16, valid_targets), 
          callbacks=[checkpointer], verbose=1, shuffle=True)

【深度学习图像识别课程】keras实现CNN系列:(8)keras迁移学习实战-狗类品种分类

【深度学习图像识别课程】keras实现CNN系列:(8)keras迁移学习实战-狗类品种分类

7、加载最优模型
# load the weights that yielded the best validation accuracy
model.load_weights('dogvgg16.weights.best.hdf5')
8、测试
# get index of predicted dog breed for each image in test set
vgg16_predictions = [np.argmax(model.predict(np.expand_dims(feature, axis=0))) 
                     for feature in test_vgg16]

# report test accuracy
test_accuracy = 100*np.sum(np.array(vgg16_predictions)==
                           np.argmax(test_targets, axis=1))/len(vgg16_predictions)
print('\nTest accuracy: %.4f%%' % test_accuracy)
【深度学习图像识别课程】keras实现CNN系列:(8)keras迁移学习实战-狗类品种分类
2.2 模型2

跟模型1的区别就是步骤4的模型不同,引入全局平均池化层 GAP减少训练参数

1、加载数据库
from sklearn.datasets import load_files       
from keras.utils import np_utils
import numpy as np
from glob import glob

# define function to load train, test, and validation datasets
def load_dataset(path):
    data = load_files(path)
    dog_files = np.array(data['filenames'])
    dog_targets = np_utils.to_categorical(np.array(data['target']), 133)
    return dog_files, dog_targets

# load train, test, and validation datasets
train_files, train_targets = load_dataset('dogImages/train')
valid_files, valid_targets = load_dataset('dogImages/valid')
test_files, test_targets = load_dataset('dogImages/test')

# load ordered list of dog names
dog_names = [item[25:-1] for item in glob('dogImages/train/*/')]

# print statistics about the dataset
print('There are %d total dog categories.' % len(dog_names))
print('There are %s total dog images.\n' % str(len(train_files) + len(valid_files) + len(test_files)))
print('There are %d training dog images.' % len(train_files))
print('There are %d validation dog images.' % len(valid_files))
print('There are %d test dog images.'% len(test_files))

【深度学习图像识别课程】keras实现CNN系列:(8)keras迁移学习实战-狗类品种分类

2、可视化部分图片
import cv2
import matplotlib.pyplot as plt
%matplotlib inline

def visualize_img(img_path, ax):
    img = cv2.imread(img_path)
    ax.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
    
fig = plt.figure(figsize=(20, 10))
for i in range(12):
    ax = fig.add_subplot(3, 4, i + 1, xticks=[], yticks=[])
    visualize_img(train_files[i], ax)

【深度学习图像识别课程】keras实现CNN系列:(8)keras迁移学习实战-狗类品种分类

3、读入VGG16瓶颈特征
bottleneck_features = np.load('bottleneck_features/DogVGG16Data.npz')
train_vgg16 = bottleneck_features['train']
valid_vgg16 = bottleneck_features['valid']
test_vgg16 = bottleneck_features['test']
4、模型2
from keras.layers import Dense, GlobalAveragePooling2D
from keras.models import Sequential

model = Sequential()
model.add(GlobalAveragePooling2D(input_shape=(7, 7, 512)))
model.add(Dense(133, activation='softmax'))
model.summary()

【深度学习图像识别课程】keras实现CNN系列:(8)keras迁移学习实战-狗类品种分类

5、模型编译
model.compile(loss='categorical_crossentropy', optimizer='rmsprop', 
                  metrics=['accuracy'])
6、模型训练
from keras.callbacks import ModelCheckpoint   

# train the model
checkpointer = ModelCheckpoint(filepath='dogvgg16.weights.best.hdf5', verbose=1, 
                               save_best_only=True)
model.fit(train_vgg16, train_targets, epochs=20, validation_data=(valid_vgg16, valid_targets), 
          callbacks=[checkpointer], verbose=1, shuffle=True)

【深度学习图像识别课程】keras实现CNN系列:(8)keras迁移学习实战-狗类品种分类

【深度学习图像识别课程】keras实现CNN系列:(8)keras迁移学习实战-狗类品种分类

7、加载最优模型
# load the weights that yielded the best validation accuracy
model.load_weights('dogvgg16.weights.best.hdf5')
8、测试
# get index of predicted dog breed for each image in test set
vgg16_predictions = [np.argmax(model.predict(np.expand_dims(feature, axis=0))) 
                     for feature in test_vgg16]

# report test accuracy
test_accuracy = 100*np.sum(np.array(vgg16_predictions)==
                           np.argmax(test_targets, axis=1))/len(vgg16_predictions)
print('\nTest accuracy: %.4f%%' % test_accuracy)
【深度学习图像识别课程】keras实现CNN系列:(8)keras迁移学习实战-狗类品种分类


三、优化

引入全局平均池化层GAP进行优化。最近MIT发现,包含GAP的CNN还具有目标定位的功能。

【深度学习图像识别课程】keras实现CNN系列:(8)keras迁移学习实战-狗类品种分类


Gap简单说明:

【深度学习图像识别课程】keras实现CNN系列:(8)keras迁移学习实战-狗类品种分类

全连接层:上面程序中,将(7, 7, 512)展开,得到7*7*512个元素,再softmax成133类

GAP全局平均池化:上面程序中,(7,7,512)中的7*7变成1个点,512个元素直接softmax成133类。


论文:http://cnnlocalization.csail.mit.edu/Zhou_Learning_Deep_Features_CVPR_2016_paper.pdf

         提出用GAP层进行目标定位的第一篇论文

代码:https://github.com/alexisbcook/ResNetCAM-keras

         使用CNN进行目标定位

视频:https://www.youtube.com/watch?v=fZvOy0VXWAI 

         使用CNN进行目标定位

代码:https://github.com/alexisbcook/keras_transfer_cifar10

         用可视化技术更好的理解瓶颈特征