Bootstrap

神经网络——tensorflow_hub迁移学习,EfficientNet的使用

## 迁移学习简述

迁移学习(Transfer Learning)是一种机器学习方法,就是把为任务 A 开发的已经训练好的模型参数作为初始点,重新迁移使用在为任务 B 开发模型中,来帮助新模型的训练。

TensorFlow Hub是一个用于促进机器学习模型中可复用部分再次进行探索与发布的库,主要将预训练过的TensorFlow模型片段再次利用到新的任务上。迁移学习的经典做法,即首先使用transfer learning对数据集进行训练,经过一定的Epoch批次之后,再改用fine tuning的方法,接着刚才训练过的模型即训练权重集继续进行训练,可以得到较好的效果。
EfficientNet是Google公司开发的全新的神经网络模型。原码看我

## 利用Efficientnet进行猫狗识别实战

  1. 数据准备
    使用Kaggle比赛猫狗大战的数据集Kaggle Cats and Dogs Dataset。点击下载
    猫狗图片在文件夹PetImages中,共有图片25000张,为了节约时间,我们选取每类900张图片用于训练,100张用于测试。

  2. 训练数据
    首先需要导入Efficientnet:import efficientnet.keras as efk(安装:pip install efficientnet)
    训练参数设置:

batch_size = 30
width = 300
height = 300
epochs = 10
NUM_TRAIN = 900
NUM_TEST = 100
dropout_rate = 0.2
input_shape = (height, width, 3)

图像尺寸根据选择模型相应变化:
在这里插入图片描述
本次实验设置训练轮数为10,共900张图片作为训练数据,100张图片作为测试数据。

  1. 使用Efficientnet迁移学习:
#使用EfficientNet进行迁移学习,B0~7可选(首先需要下载)
base_model = efk.EfficientNetB3(weights='imagenet', include_top=False, input_shape=input_shape)
top_model = tf.keras.models.Sequential()
model=base_model
#构建model
top_model.add(tf.keras.layers.GlobalMaxPooling2D(name="gap"))
if dropout_rate > 0:
    top_model.add(tf.keras.layers.Dropout(dropout_rate, name="dropout_out"))
top_model.add(tf.keras.layers.Dense(2, activation='softmax', name="fc_out"))
model = tf.keras.models.Model(inputs = model.input,outputs = top_model(model.output))
# 输出网络模型参数
#model.summary()
# 冻结卷积层不参与训练
base_model.trainable = False
#模型编译
model.compile(loss='categorical_crossentropy', optimizer=tf.keras.optimizers.RMSprop(lr=2e-5),
	          metrics=['acc'])

使用model.summary()查看网络模型参数:
在这里插入图片描述
4. 训练模型
训练网络模型,并将训练好后的网络模型文件保存,函数fit和fit_generator均可以使用,此处使用fit。

#模型训练model.fit_generator tf.keras.Model.fit
history_tl = model.fit(       
      train_data,
      train_label,
      steps_per_epoch= NUM_TRAIN//batch_size,
      epochs=epochs,
      validation_data=(valid_data,valid_label),
      validation_steps= NUM_TEST//batch_size,
      shuffle=True,
      verbose=1)
  1. 结果可视化
    输出Training和Validation的accuracy及loss图:
def plot_training(history):
	acc = history.history['acc']
	val_acc = history.history['val_acc']
	loss = history.history['loss']
	val_loss = history.history['val_loss']
	epochs_x = range(len(acc))

	plt.plot(epochs_x, acc, 'bo', label='Training acc')
	plt.plot(epochs_x, val_acc, 'b', label='Validation acc')
	plt.title('Training and validation accuracy')
	plt.legend()
	plt.figure()
	plt.plot(epochs_x, loss, 'bo', label='Training loss')
	plt.plot(epochs_x, val_loss, 'b', label='Validation loss')
	plt.title('Training and validation loss')
	plt.legend()
	plt.show()
  1. 训练结果
    对数据集进行训练,总共训练10轮。训练数据共900张图片,其中猫和狗各450张,测试数据共100张图片,其中猫和狗各50张。以下是EfficientnetB0和EfficientnetB1的训练结果,大家可以看看3~7的结果,此处不再展示。
    使用EfficientnetB0训练结果:
    第一轮结束准确率到达74%,第二轮达到82%,第10轮达到100%。在这里插入图片描述
    Training和Validation的accuracy及loss图:
    ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200430230907322.png在这里插入图片描述在这里插入图片描述

使用EfficientnetB1训练结果:
第一轮结束准确率到达20%,第二轮达到27%,第10轮达到94%。
在这里插入图片描述
Training和Validation的accuracy及loss图:
在这里插入图片描述在这里插入图片描述
7. 模型载入
训练中利用save函数将模型保存为h5文件:
再次使用时不需要重新训练数据,导入load_model函数,然后在对应路径下使用函数导出保存的模型。

from tensorflow.keras.models import load_model
model = load_model('./transdata/my_model.h5')

使用该模型预测分类结果

def predict_image(img_path):
	img = Image.open(img_path)# image resize
	img = img.resize((height, width))
	x=np.array(img)
	# 将图像转化为Numpy数组格式
	x = x.reshape((1,) + x.shape)
	#x /= 255.0
	result = model.predict([x])[0][0]
	if result > 0.5:
		animal = "cat"
	else:
		animal = "dog"
		result = 1 - result
	return animal, result

输入图像路径,使用model.predict函数就可以预测对应类别,如果需要批量预测的话可以自己修改代码实现。

全部代码

import tensorflow as tf
import efficientnet.tfkeras as efk
from keras.utils import to_categorical
import os
import numpy as np
from PIL import Image
import matplotlib.pyplot as plt

# Hyper parameters 超参数
# 模型对应的图片尺寸:efficientnetb0:224 efficientnetb1:240 efficientnetb2:260 efficientnetb3:300
batch_size = 30
width = 300
height = 300
epochs = 10
NUM_TRAIN = 900
NUM_TEST = 100
dropout_rate = 0.2
input_shape = (height, width, 3)
#训练文件地址
path_cat='./transdata/PetImages/Cat/'
path_dog='./transdata/PetImages/Dog/'

#用于图片数据载入,返回图像的numpy数组格式和标签
def load_data():
	data=np.empty((1000,width,height,3),dtype="float32")
	label=np.empty((1000,))
	imgcat=os.listdir(path_cat)
	imgdog=os.listdir(path_dog)
	cnt=0
	for i in range(0,500):
		img=Image.open(path_cat+str(i)+".jpg")
		#猫和狗各导入一张,以达到打乱数据的目的
		arr=np.array(img)
		#修改尺寸
		arr.resize((width,height,3))
		data[cnt,:,:,:]=arr
		#0表示猫
		label[cnt]=0
		cnt+=1
		img=Image.open(path_dog+str(i)+".jpg")
		arr=np.array(img)
		arr.resize((width,height,3))
		data[cnt,:,:,:]=arr
		#1表示狗
		label[cnt]=1
		cnt+=1
	return data,label
#调用函数得到数据和标签
data,label=load_data()
#转换成二值形式
label = to_categorical(label)
#前900张训练,后100张测试
train_data=data[:900]
train_label=label[:900]
valid_data=data[900:1000]
valid_label=label[900:1000]
train_label = to_categorical(train_label)
valid_label = to_categorical(valid_label)

#使用EfficientNet进行迁移学习,B0~7可选(首先需要下载)
base_model = efk.EfficientNetB3(weights='imagenet', include_top=False, input_shape=input_shape)
top_model = tf.keras.models.Sequential()
model=base_model
#构建model
top_model.add(tf.keras.layers.GlobalMaxPooling2D(name="gap"))
if dropout_rate > 0:
    top_model.add(tf.keras.layers.Dropout(dropout_rate, name="dropout_out"))
top_model.add(tf.keras.layers.Dense(2, activation='softmax', name="fc_out"))
model = tf.keras.models.Model(inputs = model.input,outputs = top_model(model.output))
# 输出网络模型参数
#model.summary()
# 冻结卷积层不参与训练
base_model.trainable = False
#模型编译
model.compile(loss='categorical_crossentropy', optimizer=tf.keras.optimizers.RMSprop(lr=2e-5),
	          metrics=['acc'])

#模型训练model.fit_generator tf.keras.Model.fit
history_tl = model.fit(       
      train_data,
      train_label,
      steps_per_epoch= NUM_TRAIN//batch_size,
      epochs=epochs,
      validation_data=(valid_data,valid_label),
      validation_steps= NUM_TEST//batch_size,
      shuffle=True,
      verbose=1)
# 训练后的模型文件保存目录
model.save('./transdata/my_model3.h5')
#accuracy及loss画图函数
def plot_training(history):
	acc = history.history['acc']
	val_acc = history.history['val_acc']
	loss = history.history['loss']
	val_loss = history.history['val_loss']
	epochs_x = range(len(acc))

	plt.plot(epochs_x, acc, 'bo', label='Training acc')
	plt.plot(epochs_x, val_acc, 'b', label='Validation acc')
	plt.title('Training and validation accuracy')
	plt.legend()
	plt.figure()
	plt.plot(epochs_x, loss, 'bo', label='Training loss')
	plt.plot(epochs_x, val_loss, 'b', label='Validation loss')
	plt.title('Training and validation loss')
	plt.legend()

	plt.show()
# 用于训练后输出Training和Validation的accuracy及loss图
plot_training(history_tl)

因为本人也是刚开始学习,使用难免有理解不到位的地方,欢迎各位大佬指正,也欢迎大家交流讨论。
部分内容参考此博客

;