Tensorflow2——使用预训练网络进行迁移学习(Vgg16)

想要将深度学习应用于小型图像数据集,使用预训练网络就是一种常用且高效的方法。预训练网络就是一个保存好的网络,之前已在大型数据集上训练(通常是大规模图像分类任务)。如果训练的原始数据集足够大且足够通用(如imagenet数据集),那么预训练网络学到的特征的空间层次结构可以有效的作为视觉世界的通用模型,因此这些特征可用于不同的计算机视觉问题。这种学习到的特征在不同问题之间的可移植性,也是深度学习与其他浅层方法相比的重要优势。使用预训练网络有两种方法,特征提取和微调模型。

微调模型是用于特征提取的冻结的卷积基,将其顶部的几层“解冻”,并将这几层和新增加的Dence层一起联合训练。
之所以叫微调,是因为它只是略微调整了所复用模型中更加抽象的表示,以便让这些表示与新的任务更加相关。

微调模型的步骤如下:

1)在已经训练好的基网络上添加自定义网络;

2)冻结基网络;

3)训练所添加的部分;

4)解冻基网络的一些层;

5)联合训练解冻的这些层和添加的部分。

微调层数需要考虑以下两点:

1.卷积基中靠近底部的层编码是更加通用的可复用特征,而靠近顶部的层编码是更加专业化的特征。微调这些更专业化的特征更加有用。微调越靠近底部的层,得到的回报越少。

2.训练的参数越多,过拟合的风险越大。

一个好策略是仅微调卷积基的最后两三层。
Tensorflow2——使用预训练网络进行迁移学习(Vgg16)_第1张图片
比如上述:训练好的卷积基可以说我们训练好的Vgg网络,我们丢掉后面的分类器,接上我们自己想要的分类器,比如说添加一个Dense层等等,然后再重新训练的时候,不让我们的vgg网络的变量参加训练,只训练我们的分类器,也就是简单的迁移训练。

weights:指定模型初始化权重检查点
include_top:指定模型最后是否包含密集连接分类器。默认情况下,这个密集连接分类器对应于ImageNet的1000个类别。因为我们打算使用自己的分类器(只有两个类别:cat和dog),所以不用包含。
input_shape:输入到网络中的图像张量(可选参数),如果不传入这个参数,那么网络可以处理任意形状的输入

import tensorflow as tf
from tensorflow import keras
import numpy as np
import matplotlib.pyplot as plt
import os
import glob
%matplotlib inline
from tensorflow.compat.v1 import ConfigProto
from tensorflow.compat.v1 import InteractiveSession
config = ConfigProto()
config.gpu_options.allow_growth = True
session = InteractiveSession(config=config)


train_image_path=glob.glob("./dc/train/*/*.jpg" ) #全部提取出来,表示任意文件名称的下面图片)
train_image_label=[int(p.split("\\")[1]=="cat") for p in train_image_path]
#此时的train_image_label是一个一维的列表,需要将它reshape成一个二维的形状
# [1,2,3]>[[1],[2],[3]]


#图像预处理,包括图像增强
def load_process_image(path,label):
    #读取路径
    image=tf.io.read_file(path)
    #解码图片
    image=tf.image.decode_jpeg(image,channels=3)
    #统一图片大小
    image=tf.image.resize(image,[360,360])
    #随机的裁剪成256x256
    image=tf.image.random_crop(image,[256,256,3])
    #随机的翻转
    image=tf.image.random_flip_left_right(image)
    image=tf.image.random_flip_up_down(image)
    #增加亮度50%
    image=tf.image.random_brightness(image,0.5)
    #增强对比度
    image=tf.image.random_contrast(image,0,1)
    #转换图片的数据类型
    image=tf.cast(image,tf.float32)   #tf默认读取图像是uint8,八位无符号整数,取值范围(0-255)
    #图像归一化
    image=image/255
    #label做二维转换
    label=tf.reshape(label,[1])
    return image,label   #返回的image和label都是一个batch形状的,一个批次的很多张的形式
    
#图像预处理,包括图像增强
def load_process_image_test(path,label):
    #读取路径
    image=tf.io.read_file(path)
    #解码图片
    image=tf.image.decode_jpeg(image,channels=3)
    #统一图片大小
    image=tf.image.resize(image,[256,256])
    #转换图片的数据类型
    image=tf.cast(image,tf.float32)   #tf默认读取图像是uint8,八位无符号整数,取值范围(0-255)
    #图像归一化
    image=image/255
    #label做二维转换
    label=tf.reshape(label,[1])
    return image,label   #返回的image和label都是一个batch形状的,一个批次的很多张的形式

#创建数据集(包含了一个路径和它对应的label)
train_image_dataset=tf.data.Dataset.from_tensor_slices((train_image_path,train_image_label))
AUTOTUNE=tf.data.experimental.AUTOTUNE#根据你的计算机CPU的个数自动的进行并行运算
train_image_dataset=train_image_dataset.map(load_process_image,num_parallel_calls=AUTOTUNE)  #做了图像预处理

BATCH_SIZE=16
train_count=len(train_image_path)
train_image_dataset=train_image_dataset.shuffle(train_count).repeat().batch(BATCH_SIZE)
train_image_dataset=train_image_dataset.prefetch(AUTOTUNE)
#一部分数据在训练的过程中,去读取另一部分的数据,这样的话加速训练过程

test_image_path=glob.glob("./dc/test/*/*.jpg" )
test_image_label=[int(p.split("\\")[1]=="cat") for p in test_image_path]
test_image_dataset=tf.data.Dataset.from_tensor_slices((test_image_path,test_image_label))
test_image_dataset=test_image_dataset.map(load_process_image_test,num_parallel_calls=AUTOTUNE)
test_image_dataset=test_image_dataset.batch(BATCH_SIZE).repeat()
test_image_dataset=test_image_dataset.prefetch(AUTOTUNE)
test_count=len(test_image_path)  
    
#使用keras的内置神经网络
covn_base = tf.keras.applications.VGG16(weights="imagenet",include_top=False)   #weights:是否采用他雨荨你来弄好的权重
#include_top:是否包含后面的全连接层

#开始使用卷积基
model=tf.keras.Sequential()
model.add(covn_base)   #在另一个网络中去调用这个网络
model.add(tf.keras.layers.GlobalAveragePooling2D())
model.add(tf.keras.layers.Dense(512,activation="relu"))
model.add(tf.keras.layers.Dense(1,activation="sigmoid"))

Tensorflow2——使用预训练网络进行迁移学习(Vgg16)_第2张图片

covn_base.trainable=False  #不要动已经训练好了的权重

Tensorflow2——使用预训练网络进行迁移学习(Vgg16)_第3张图片
开始编译和训练:

model.compile(optimizer=tf.keras.optimizers.Adam(lr=0.001),loss="binary_crossentropy",metrics=["acc"])
history=model.fit(train_image_dataset,steps_per_epoch=train_count//BATCH_SIZE,epochs=15,validation_data=test_image_dataset,validation_steps=test_count//BATCH_SIZE)

你可能感兴趣的:(Tensorflow2)