深度学习3 使用keras进行迁移学习(重新修订)

修改说明:为了能使迁移学习所训练出的模型能适应后续的知识蒸馏,因此对迁移的代码做了细节上的修订。后续红色标明字样,皆为修改后的内容

采用模型分离的方式构造迁移学习,可以降低反向传播时卷积运算的工作量。

1、卷积基的提取

首先选定迁移的目标并提取其卷积基  可按照不同的需求提取迁移特征。keras除此外还有  DenseNet121、MobileNet、Xception等网络可以用于迁移

注意:1、要按照个人需求和电脑配置调整 shape,batch_size, 和models数组内的模型名称

           2、要从tensorflow.kreas中引入application库,这样子才能支持更多的模型库(如EfficientNet系列)

            3、新增os环境设置,避免价值tensorflow时输出太多不必要的信息

import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'  # or any {'0', '1', '2'}
from keras.preprocessing.image import ImageDataGenerator
from keras.utils import np_utils
#from tensorflow.python.keras.utils import np_utils  #上面语句报错可以改成这个
from tensorflow.keras import applications,Model
import numpy as np
import os,gc
batch_size=32#ResNet50,VGG16,InceptionV3 EfficientNetB7 NASNetLarge
shape=(226, 226)  
# DenseNet169 DenseNet201  #DenseNet121 ResNet152V2 ,"InceptionV3","MobileNetV3Small","ResNet50V2","VGG19"
models=["EfficientNetB0"]#
for modelname in models:
    mstr="applications.%s(include_top=False,input_shape=(114,114,3), weights='imagenet')"%modelname
    base = eval(mstr)
    print(modelname)
    print(modelname)
    model= Model(input=base.input, output=base.layers[-1].output) 
可用于迁移的对象

2、数据集的划分

数据集的划分可以查看python工具方法 4 依据随机种子将图片文件划分为训练集、测试集、验证集_a486259的博客-CSDN博客,代码复制后即可运行

文件夹:flower   通过该代码可得到:flower-训练,flower-验证,flower-测试三个文件夹

3、特征的提取与保存

所提取的特征保存在features文件夹中,命名方式为:
modelname_data_训练、modelname_data_验证、modelname_data_测试

modelname_labels_训练、modelname_labels_验证、modelname_labels_测试

#代码复制过来不想调整缩进,所以使用了if True来控制
if True:
    datagen = ImageDataGenerator()#(rescale=1.0 / 255)
    root_path='./features/'
    if not os.path.exists(root_path):
        os.makedirs(root_path)
    dirList=['训练','验证','测试']
    data_path='flower//'
    for path in dirList:
        generator = datagen.flow_from_directory(data_path+'-'+path,
                                                target_size=shape,
                                                batch_size=batch_size,
                                                class_mode='categorical',
                                                shuffle=False)
        print(generator.class_indices)#输出数据的labels
        labels= np_utils.to_categorical(generator.classes)
        np.save(open(root_path+'label.npy', 'wb'), generator.class_indices)
        features= model.predict_generator(generator, len(generator.classes)/generator.batch_size)
        print('result.shape: ',features.shape)
        #import sys;sys.exit()
        print(len(generator.classes))
        print(path,'集-卷积池化数据固化成功!')
        np.save(open('%s%s_data_%s.npy'%(root_path,modelname,path), 'wb'), features)
        np.save(open('%s%s_labels_%s.npy'%(root_path,modelname,path), 'wb'), labels)
        np.save(open('%s%s_fileName_%s.npy'%(root_path,modelname,path), 'wb'), generator.filenames)
        gc.collect()

4、读取特征

import numpy as np
root_path='./features/VGG16_'
train_data = np.load(root_path+'data_训练.npy')
train_data=train_data.reshape(train_data.shape[0],-1)
train_label = np.load(root_path+'labels_训练.npy')
shuffle=True
if shuffle:
    import random
    randnum = random.randint(0,100)
    random.seed(randnum)
    random.shuffle(train_data)
    random.seed(randnum)
    random.shuffle(train_label)

validation_data = np.load(root_path+'data_验证.npy')
validation_data=validation_data.reshape(validation_data.shape[0],-1)
validation_label =np.load(root_path+'labels_验证.npy')

test_data = np.load(root_path+'data_测试.npy')
test_data=test_data.reshape(test_data.shape[0],-1)
test_label =np.load(root_path+'labels_测试.npy')

#数据的扁平化
inputShape=np.array(train_data.shape[1:]).prod()
train_data=train_data.reshape(-1,inputShape)
test_data=test_data.reshape(-1,inputShape)
validation_data=validation_data.reshape(-1,inputShape)

5、重新训练分类器

在这里修改了两行代码,移除了最后一个Dense中的激活函数,并为每一个dense设置了name,通过这种操作,可以已另一种方式实现模型拼接。需要进行更高级的知识蒸馏(实现kl loss,softmax升温)的朋友,请不要使用后续的模型拼接代码。

output = Dense(class_types,name='dense_out')(x)
output = Activation(tf.nn.softmax,name='Activation_out')(output)

import tensorflow as tf
from keras.models import Model
from keras.layers import Dense,Input,Dropout,Activation

inputs = Input(shape=(inputShape,))
x = Dense(100, activation='relu',name='dense1')(inputs)
x = Dense(50, activation='relu',name='dense2')(x)
x = Dropout(0.2)(x)
output = Dense(class_types,name='dense_out')(x)
output = Activation(tf.nn.softmax,name='Activation_out')(output)
model = Model(inputs=inputs, outputs=output)
model.compile(optimizer='adam',loss='categorical_crossentropy',metrics=['acc'])

from keras.callbacks import History,ModelCheckpoint,EarlyStopping
#最佳模型保存
ModelCheckpoint=ModelCheckpoint('best_model.h5', monitor='acc', verbose=0, save_best_only=True, save_weights_only=False, mode='auto', period=1)
#提前终止
EarlyStopping=EarlyStopping(monitor='val_loss', patience=2, verbose=2, mode='auto')
#历史数据记录
loss_history = History()
#模型训练
model.fit(train_data,train_label,epochs=100,batch_size=32,
          callbacks=[ModelCheckpoint,EarlyStopping,loss_history]
          validation_data=(validation_data, validation_label),
          verbose=2)
#模型评估
loss,acc=model.evaluate(test_data, test_label )
print('loss:',loss,'acc:',acc)
#历史数据绘图
import pandas as pd
d=pd.DataFrame(data=loss_history.history)
d.to_csv('history.csv')

6、全部代码

01.feature_save.py   复制代码保存为01.feature_save.py,然后执行,完成迁移特征的提取与保存

import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'  # or any {'0', '1', '2'}
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.python.keras.utils.np_utils import to_categorical
from tensorflow.keras import applications,Model
import numpy as np
import os,gc
batch_size=32#ResNet50,VGG16,InceptionV3 EfficientNetB7 NASNetLarge
shape=(56, 56)
# DenseNet169 DenseNet201  #DenseNet121 ResNet152V2 ,"InceptionV3","MobileNetV3Small","ResNet50V2","VGG19"
models=["EfficientNetB0"]#
for modelname in models:
    mstr="applications.%s(include_top=False,input_shape=(114,114,3), weights='imagenet')"%modelname
    base = eval(mstr)
    print(modelname)
    print(modelname)
    model= Model(inputs=base.input, outputs=base.layers[-1].output)
    datagen = ImageDataGenerator()#(rescale=1.0 / 255)
    root_path='./features/'
    if not os.path.exists(root_path):
        os.makedirs(root_path)
    dirList=['训练','验证','测试']
    data_path = r"./flower"
    for path in dirList:
        generator = datagen.flow_from_directory(data_path+'-'+path,
                                                target_size=shape,
                                                batch_size=batch_size,
                                                class_mode='categorical',
                                                shuffle=False)
        print(generator.class_indices)#输出数据的labels
        labels= to_categorical(generator.classes)
        np.save(open(root_path+'label.npy', 'wb'), generator.class_indices)
        features= model.predict_generator(generator, len(generator.classes)/generator.batch_size)
        print('result.shape: ',features.shape)
        #import sys;sys.exit()
        print(len(generator.classes))
        print(path,'集-卷积池化数据固化成功!')
        np.save(open('%s%s_data_%s.npy'%(root_path,modelname,path), 'wb'), features)
        np.save(open('%s%s_labels_%s.npy'%(root_path,modelname,path), 'wb'), labels)
        np.save(open('%s%s_fileName_%s.npy'%(root_path,modelname,path), 'wb'), generator.filenames)
        gc.collect()

02.new_cls.py  复制代码保存为02.new_cls.py,然后执行,完成分类器训练

#------------------------------特征数据读取---------------------------------------
import numpy as np
class_types=2
root_path='./features/VGG16_'
train_data = np.load(root_path+'data_训练.npy')
train_label = np.load(root_path+'labels_训练.npy')
shuffle=True
if shuffle:
    import random
    randnum = random.randint(0,100)
    random.seed(randnum)
    random.shuffle(train_data)
    random.seed(randnum)
    random.shuffle(train_label)
 
validation_data = np.load(root_path+'data_验证.npy')
validation_label =np.load(root_path+'labels_验证.npy')
 
test_data = np.load(root_path+'data_测试.npy')
test_label =np.load(root_path+'labels_测试.npy')
#-----------------------------------重新训练全连接分类器--------------------------
 
from keras.models import Model
from keras.layers import Dense,Input,Dropout,GlobalAveragePooling2D
 
inputs = Input(shape=test_data[0].shape)
x = GlobalAveragePooling2D()(inputs)#GlobalAveragePooling2D 为了减少对数据的形变操作,和降低模型参数量
x = Dense(100, activation='relu')(x)
x = Dense(50, activation='relu')(x)
x = Dropout(0.2)(x)
output = Dense(class_types, activation='softmax')(x)
model = Model(inputs=inputs, outputs=output)
model.compile(optimizer='adam',loss='categorical_crossentropy',metrics=['acc'])
 
from keras.callbacks import History,ModelCheckpoint,EarlyStopping
#最佳模型保存
ModelCheckpoint=ModelCheckpoint('gap_best_model.h5', monitor='acc', verbose=0, save_best_only=True, save_weights_only=False, mode='auto', period=1)
#提前终止
EarlyStopping=EarlyStopping(monitor='val_loss', patience=15, verbose=2, mode='auto')
#历史数据记录
loss_history = History()
#模型训练
model.fit(train_data,train_label,epochs=100,batch_size=32,
          callbacks=[ModelCheckpoint,EarlyStopping,loss_history],
          validation_data=(validation_data, validation_label),
          verbose=2)
#模型评估
loss,acc=model.evaluate(test_data, test_label)
print('test loss:',loss,'acc:',acc)
loss,acc=model.evaluate(train_data, train_label)
print('train loss:',loss,'acc:',acc)
loss,acc=model.evaluate(validation_data, validation_label)
print('valid loss:',loss,'acc:',acc)
#历史数据绘图
import pandas as pd
d=pd.DataFrame(data=loss_history.history)
d.to_csv(root_path+'history.csv')

7、模型拼接

复制代码既可用       深度学习 11 keras迁移学习模型拼接_a486259的博客-CSDN博客

8、迁移模型知识蒸馏

迁移后的模型体量太大,复制该代码既可

深度学习12 基于keras的知识蒸馏_a486259的博客-CSDN博客

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

万里鹏程转瞬至

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值