6.5 卷积神经网络迁移学习
6.5.1 迁移学习介绍
下标给出了从2012年到2015年ILSVRC(Large Scale Visual Recognition Challenge)第一名模型的层数以及前五个答案的错误率
随着模型层数以及复杂度的增加,模型在ImageNet上的错误率也随之降低。然而,训练复杂的卷积神经网络需要非常多的标注数据。ImageNet图像分类数据集中有120万标注图片,所以才能将152层的ResNet的模型训练到大约96.5%的正确率。为了解决标注数据和训练时间的问题,本届将要介绍迁移学习的方式。
所谓迁移学习,就是讲一个问题上训练好的模型通过简单的调整使其适用于一个新的问题。本节将介绍图和利用ImageNet数据集上训练好的Inception-v3模型来解决一个新的图像分类问题。
根据论文DeCAF:A Deep Convolutional Activation Feature for Generic Visual Recognition中的结论,可以保留训练好的Inception-v3模型中所有卷积层的参数,只是替换最后一层全连接层。在最后这一层全连接之前的网络层称之为瓶颈层(bottleneck)。
将新的图像通过训练好的卷积神经网络直到瓶颈处的过程可以看成事对图像进行特征提取的过程。在训练好的Inception-v3模型中,因为将瓶颈处的输出再通过一个单层的全连接层神经网络可以很好地区分1000种类别的图像,所以有理由认为瓶颈处输出的节点向量可以被作为任何图像的一个更加精简且表达能力更强的特征向量。
于是,在新数据集上,可以直接利用这个训练好的神经网络对图像进行特征提取,然后再将提取得到的特征向量作为输入来训练一个新的单层全连接神经网络处理新的分类问题。
一般来说,迁移学习所需要的训练时间和训练样本书远远小于训练完整的模型。
6.5.2 TensorFlow实现迁移学习
本节将给出一个完整的TensorFlow程序来介绍如何通过TensorFlow实现迁移学习。一下大妈给出了如何下载这一节中将要用到的数据集。
wget http://download.tensorflow.org/example_images/flower_photos.tgz
tar xzf flower_photos.tgz
解压之后的文件夹包含了5个子文件夹,每一个子文件的名称为一种花的名称,代表不同的类别。平均每一种花有734张图片,每一张图片都是RGB色彩模式的,大小也不相同。和之前的样例不同,在这一节中给出的程序将直接处理没有整理过的图像数据。
以下代码给出了如何将原始的图像数据整理成模型需要的输入数据。
# -*- coding: utf-8 -*-
# @Time : 2019/3/28 16:59
# @Author : Chord
import glob;
import os.path;
import numpy as np;
import tensorflow as tf;
from tensorflow.python.platform import gfile;
# 原始输入数据的目录,这个目录下有5个子目录,每个子目录底下保存属于该类别的所有图片
INPUT_DATA = 'C:\Documents\workspace\Resource\\flower_photos'
# 输出文件地址,将整理后的图片数据通过numpy格式保存。
OUTPUT_FILE = 'C:\Documents\workspace\Resource\\flower_processed_data.npy'
# 测试数据和验证数据比例
VALIDATION_PERCENTAGE = 10
TEST_PERCENTAGE = 10
# 读取数据并将数据分割成训练数据、验证数据和测试数据
def create_image_lists(sess, testing_percentage, validation_percentage):
sub_dirs = [x[0] for x in os.walk(INPUT_DATA)] # 读取数据数据目录的root
is_root_dir = True
# 初始化各个数据集
training_images = []
training_labels = []
testing_images = []
testing_labels= []
validation_images = []
validation_labels = []
current_label = 0
# 读取所有的子目录
for sub_dir in sub_dirs:
if (is_root_dir):
is_root_dir = False
continue
# 获取一个子目录中所有的图片文件
extensions = ['jpg', 'jpeg', 'JPG', 'JPEG']
file_list = []
dir_name = os.path.basename(sub_dir)
for extension in extensions:
file_glob = os.path.join(INPUT_DATA, dir_name, '*.' + extension)
print(file_glob)
file_list.extend(glob.glob(file_glob))
if not file_list: continue
# 处理图片数据
for file_name in file_list:
# 读取并解析图片,将图片转化为299×299以便inception-v3模型来处理
image_raw_d