由于深度学习网络的训练复杂,耗时,并且对硬件要求较高,因此对于目标相似的任务,并且自己的数据集数目较小的时候,比如分类任务,不同的分类任务之间的对象具有较为相似的特征,我们就可以使用已经预训练的模型来应用到自己的项目任务中,当然对于已经预训练的模型,需要经过微调才能应用到自己的分类任务中来。
微调主要包括训练参数的变动,全连接层神经元个数,当我们自己的数据集很少时,我们可以仅仅改变最后一层全连接层的神经元的个数即可,当我们的数据量大的时候,我们可以选择训练模型的后几层参数。
这里我们采用VGG16来实现简单的迁移学习案例
VGG16的网络结构如下:
这里我们仅仅通过重新训练最后一层全连接层的参数将预训练好的VGG16模型应用到猫狗大战的数据集上。
VGG16预备训练模型:https://pan.baidu.com/s/1FfNiUAigFBRknftXCXcThw
提取码:cfs1
kaggle猫狗数据集:
链接:https://pan.baidu.com/s/1ohg-q2WWcYSNG7SC-C74cQ
提取码:a4xj
首先我们需要定义网络的结构,定义一个vgg类
class vgg16:
def __init__(self, imgs):
#加入全局列表,把所需参数加载进类里
self.parameters=[]
#初始化
self.imgs=imgs
self.convlayers()
self.fc_layers()
#输出类别的概率
self.probs=tf.nn.softmax(self.fc8)
def saver(self):
return tf.train.Saver()
#定义卷积层
def conv(self,name,input_data,out_channel,trainable=False):
#获取通道数
in_channel=input_data.get_shape()[-1]
with tf.variable_scope(name):
#初始化
kernel=tf.get_variable('weights',[3,3,in_channel,out_channel],dtype=tf.float32,trainable=False)
biases=tf.get_variable('baises',[out_channel],dtype=tf.float32,trainable=False)
conv_res=tf.nn.conv2d(input_data,kernel,[1,1,1,1],padding='SAME')
res=tf.nn.bias_add(conv_res,biases)
out=tf.nn.relu(res,name=name)
self.parameters+=[kernel,biases]
return out
#定义全连接层
def fc(self,name,input_data,out_channel,trainable=True):
#获取维度
shape=input_data.get_shape().as_list()
if len(shape)==4:
size=shape[-1]*shape[-2]*shape[-3]
else :size=shape[1]
#数据展开
input_data_flat=tf.reshape(input_data,[-1,size])
with tf.variable_scope(name):
#初始化
weights=tf.get_variable('weights',shape=[size,out_channel],dtype=tf.float32,trainable=trainable)
biases=tf.get_variable('baises',shape=[out_channel],dtype=tf.float32,trainable=trainable)
res=tf.matmul(input_data_flat,weights)
out=tf.nn.relu(tf.nn.bias_add(res,biases))
self.parameters+=[weights,biases]
return out
#定义池化
def maxpool(self,name,input_data):
out=tf.nn.max_pool(input_data,[1,2,2,1],[1,2,2,1],padding='SAME',name=name)
return out
#卷积堆叠
def convlayers(self):
#cov1
self.conv1_1=self.conv('conv1_1',self.imgs,64,trainable=False)
self.conv1_2=self.conv('conv1_2',self.conv1_1,64,trainable=False)
self.pool1=self.maxpool('poolre1',self.conv1_2)
#cov2
self.conv2_1=self.conv('conv2_1',self.pool1,128,trainable=False)
self.conv2_2=self.conv('conv2_2',self.conv2_1,128,trainable=False)
self.pool2=self.maxpool('pool1',self.conv2_2)
#cov3
self.conv3_1=self.conv('conv3_1',self.pool2,256,trainable=False)
self.conv3_2=self.conv('conv3_2',self.conv3_1,256,trainable=False)
self.conv3_3=self.conv('conv3_3',self.conv3_2,256,trainable=False)
self.pool3=self.maxpool('pool3',self.conv3_3)
#cov4
self.conv4_1=self.conv('conv4_1',self.pool3,512,trainable=False)
self.conv4_2=self.conv('conv4_2',self.conv4_1,512,trainable=False)
self.conv4_3=self.conv('conv4_3',self.conv4_2,512,trainable=False)
self.pool4=self.maxpool('pool4',self.conv4_3)
#cov5
self.conv5_1=self.conv('conv5_1',self.pool4,512,trainable=False)
self.conv5_2=self.conv('conv5_2',self.conv5_1,512,trainable=False)
self.conv5_3=self.conv('conv5_3',self.conv5_2,512,trainable=False)
self.pool5=self.maxpool('pool5',self.conv5_3)
#全连接层
def fc_layers(self):
self.fc6=self.fc('fc1',self.pool5,4096,trainable=False)
self.fc7=self.fc('fc2',self.fc6,4096,trainable=False)
#要进行微调,trainable为true
self.fc8=self.fc('fc3',self.fc7,2,trainable=True)
#载入权重
def load_weights(self,weight_file,sess):
weights=np.load(weight_file)
keys=sorted(weights.keys())
for i,k in enumerate(keys):
if i not in[30,31]:
sess.run(self.parameters[i].assign(weights[k]))
print("weights loading......")
定义提取训练数据集图片的地址和标签,并使用独热编码形式
import tensorflow.compat.v1 as tf
tf.disable_v2_behavior()
import numpy as np
import os
from time import time
import utils
#数据输入
def get_file(file_dir):
images=[]
labels=[]
for fs in os.listdir(file_dir):
images.append(os.path.join(file_dir,fs))
if fs.split('.')[0]=='cat':
labels.append(1)
else:
labels.append(0)
temp=np.array([images,labels])
temp=temp.transpose()
np.random.shuffle(temp)
image_list=list(temp[:,0])
label_list=list(temp[:,1])
label_list=[int(float(i)) for i in label_list]
return image_list,label_list
def get_batch(image_list,label_list,img_width,img_height,batch_size,capacity):
image=tf.cast(image_list,tf.string)
label=tf.cast(label_list,tf.int32)
input_queue=tf.train.slice_input_producer([image,label])
label=input_queue[1]
image_contents=tf.read_file(input_queue[0])
image=tf.image.decode_jpeg(image_contents,channels=3)
image= tf.image.resize_images(image, [224, 224], method=tf.image.ResizeMethod.NEAREST_NEIGHBOR)
image_batch,label_batch=tf.train.batch([image,label],batch_size=batch_size,num_threads=64,capacity=capacity)
label_batch=tf.reshape(label_batch,[batch_size])
return image_batch,label_batch
#转换独热编码
def onehot(labels):
n_sample=len(labels)
n_class=max(labels)+1
onehot_labels=np.zeros((n_sample,n_class))
onehot_labels[np.arange(n_sample),labels]=1
return onehot_labels
下面我们进行模型的训练
batch_size=10
capacity=256#存储容量
#VGG预训练是减掉的均值
means=[123.68,116.779,103.939]
img_width=224
img_height=224
start_time=time()
xs,ys =get_file(r'D:/study/MOOC/deeplearning/dataset_kaggledogvscat/dataset_kaggledogvscat/train')
image_batch,label_batch=get_batch(xs,ys,img_width,img_height,batch_size,capacity)
print(len(xs),len(ys))
x=tf.placeholder(tf.float32,[None,224,224,3])
y=tf.placeholder(tf.int32,[None,2])
vgg=vgg16(x)
fc8_finetuining=vgg.probs
loss_function=tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=fc8_finetuining,labels=y))
optimizer=tf.train.GradientDescentOptimizer(learning_rate=0.001).minimize(loss_function)
sess=tf.Session()
sess.run(tf.global_variables_initializer())
vgg.load_weights(r'D:\study\MOOC\deeplearning\dataset_kaggledogvscat\dataset_kaggledogvscat/vgg16_weights.npz',sess)
saver=tf.train.Saver()
coord= tf.train.Coordinator()
threads=tf.train.start_queue_runners(coord=coord,sess=sess)
epoch_start_time=time()
for i in range (100):
print('开始训练......')
images,labels=sess.run([image_batch,label_batch])
labels=onehot(labels)
sess.run(optimizer,feed_dict={x:images,y:labels})
loss=sess.run(loss_function,feed_dict={x:images,y:labels})
print("loss:%f"%loss)
epoch_end_time=time()
print('time:',(epoch_end_time-epoch_start_time))
epoch_start_time=epoch_end_time
if(i+1)%20==0:
saver.save(sess,os.path.join('./model/','epoch{:06d}.ckpt'.format(i+1)))
print("____epoch%d finish"%(i+1))
saver.save(sess,'./model/')
coord.request_stop()
coord.join(threads)
输出训练的结果,训练的次数,loss
下面我们来进行验证
tf.reset_default_graph()
means=[123.68,116.779,103.939]
x=tf.placeholder(tf.float32,[None,224,224,3])
with tf.Session() as sess:
vgg=vgg16(x)
fc8_finetuining=vgg.probs
saver=tf.train.Saver()
print('restoring...')
saver.restore(sess,'./model/')
filepath=r'D:\study\MOOC\deeplearning\dataset_kaggledogvscat\dataset_kaggledogvscat\test1\test1\11160.jpg'
image_raw_data = tf.gfile.FastGFile(filepath,'rb').read()
img_data = tf.image.decode_jpeg(image_raw_data)
# plt.imshow(img_data.eval())
# plt.show()
image = tf.image.resize_images(img_data, [224, 224], method=tf.image.ResizeMethod.NEAREST_NEIGHBOR)
img = image.eval()
print(img.shape)
image = tf.expand_dims(image,0)
print(image.shape)
#for c in range(3):
# image[:,:,c] -= means[c]
prob=sess.run(fc8_finetuining,feed_dict={x:[img]})
max_index=np.argmax(prob)
if max_index==1:
print('The result: cat %.6f'%prob[:,0])
else:
print('The result: dog %.6f'%prob[:,1])
输出某类分类结果的概率