本网站可以出售:只需60000元直接拥有。QQ:939804642
您当前的位置:首页 > IT编程 > Keras
| C语言 | Java | VB | VC | python | Android | TensorFlow | C++ | oracle | 学术与代码 | cnn卷积神经网络 | gnn | 图像修复 | Keras | 数据集 | Neo4j | 自然语言处理 | 深度学习 | 医学CAD | 医学影像 | 超参数 | pointnet | pytorch | 异常检测 | Transformers | 情感分类 | 知识图谱 |

自学教程:深度学习—Keras迁移学习(升级版)+模型融合实现详解

51自学网 2020-11-08 09:36:26
  Keras
这篇教程深度学习—Keras迁移学习(升级版)+模型融合实现详解写得很实用,希望能帮到您。

深度学习—Keras迁移学习(升级版)+模型融合实现详解

最近时间充裕在学习深度学习,用博客记录一下自己的理解,毕竟好记性不如烂笔头。如果有错误的地方,希望大家指正,一起进步。如果这篇博客对你有帮助,点赞支持一下,码字不易。。。。。
迁移学习是深度学习中常用的一个手段,从头开始训练一个模型需要耗费大量的资源,在训练好的权重(预训练)的基础上训练自己的模型是迁移学习的重要思想。Keras 的应用模块(keras.applications)提供了带有预训练权值的深度学习模型,这些模型可以用来进行预测、特征提取和微调(fine-tuning)。关于keras.applications的详细应用可以参考博客,详细介绍了keras.applications的用法和一些具体的例子。

 

 

1、迁移学习用于图像分类(基础版)

迁移学习通俗来讲就是把预训练权重当作模型的初始化权重,使得模型站在巨人的肩膀上训练。
我们通过一个例子来了解Keras中迁移学习用于图像分类的基础版实现,在预训练模型InceptionV3上微调训练出自己的模型。
首先来介绍一下调用keras.applications中InceptionV3模型时各参数的意义:

keras.applications.inception_v3.InceptionV3(include_top=False,
                                            weights='imagenet',
                                            input_tensor=None,
                                            input_shape=None,
                                            pooling=None,
                                            classes=1000)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

各参数的意义:
include_top:是否保留顶层的全连接网络
weights:None代表随机初始化,即不加载预训练权重。'imagenet’代表加载预训练权重
input_tensor:可填入Keras tensor作为模型的图像输出tensor
input_shape:可选,仅当include_top=False有效,应为长为3的tuple,指明输入图片的shape,图片的宽高必须大于197,如(200,200,3)
pooling:当include_top=False时,该参数指定了池化方式。None代表不池化,最后一个卷积层的输出为4D张量。‘avg’代表全局平均池化,‘max’代表全局最大值池化。
classes:可选,图片分类的类别数,仅当include_top=True并且不加载预训练权重时可用。
返回值:Keras 模型对象
更多不同模型加载时的参数意义可参考Keras中文文档
迁移学习实现代码如下,在代码中详细介绍了每一步的实现

#首先导入相关的包,导入applications模块中的InceptionV3预训练模型
from keras.applications.inception_v3 import InceptionV3
from keras.preprocessing import image
from keras.models import Model
from keras.layers import Dense, GlobalAveragePooling2D
from keras import backend as K
#
# 第二步:构建完整模型
#include_top这个参数可以控制的是,到底要不要最后的这些全连接层。构建不带分类器的预训练模型
base_model = InceptionV3(weights='imagenet', include_top=False) 

x = base_model.output
x = GlobalAveragePooling2D()(x)# 添加全局平均池化层
x = Dense(1024, activation='relu')(x)# 添加一个全连接层
predictions = Dense(200, activation='softmax')(x)# 自定义自己的分类器,这是一个200分类的分类器
model = Model(inputs=base_model.input, outputs=predictions)# 构建我们需要训练的完整模型

#第三步:在构建好的完整模型上用预训练权重开始训练,我们对模型进行两个训练

# 第一次训练:我们只训练随机初始化的层
# 锁住所有 InceptionV3 的卷积层
for layer in base_model.layers:
    layer.trainable = False
# 编译模型(一定要在锁层以后操作)
model.compile(optimizer='rmsprop', loss='categorical_crossentropy')
# 在新的数据集上训练几代
model.fit_generator(...)

#第二次训练:开始微调Inception V3的卷积层,我们会锁住 Inception V3 中底下的几层,然后训练其余的顶层。

# 让我们看看每一层的名字和层号,看看我们应该锁多少层呢:
for i, layer in enumerate(base_model.layers):
   print(i, layer.name)

# 我们选择训练最上面的两个 Inception block。也就是说锁住前面249层,然后放开之后的层。
for layer in model.layers[:249]:
   layer.trainable = False
for layer in model.layers[249:]:
   layer.trainable = True

# 我们需要重新编译模型,才能使上面的修改生效
# 让我们设置一个很低的学习率,使用 SGD 来微调
from keras.optimizers import SGD
model.compile(optimizer=SGD(lr=0.0001, momentum=0.9), loss='categorical_crossentropy')

# 我们继续训练模型,这次我们训练最后两个 Inception block
# 和两个全连接层
model.fit_generator(...)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48

至此,就可以实现在InceptionV3预训练权重上训练一个符合自己数据特征的200分类的分类模型。

2、迁移学习高级实现(升级版)

我们已经实现了迁移学习,将整个InceptionV3的网络用于特征提取网络,但有时根据任务的需要,我们不需要将整个网络用特征提取,只需要迁移部分模型。有的时候还需要进行不同模型的融合。

2.1 迁移部分模型

我们已经实现了迁移学习,将整个InceptionV3的网络用于特征提取网络,但有时根据任务的需要,我们不需要将整个网络用特征提取,从网络的任意中间层中抽取特征用于迁移学习;这时候就只需要迁移部分模型。
首先,我们要先了解如何获得指定层的输出。有两种方法可以获得指定层的输出
第一种:自定义用于输出中间层的model

from keras.models import Model

base_model = InceptionV3(weights='imagenet', include_top=False) 
layer_name = 'my_layer' # 给定待输出的层的名字
#自定义用于输出中间层的model
model = Model(inputs=base_model.input, outputs=base_model.get_layer(layer_name).output)
#获得指定层的输出
layer_name_features = model.predict(input_data)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

第二中:通过定义Keras函数实现,用于输出指定层的输出

from keras import backend as K
# with a Sequential model
get_3rd_layer_output = K.function([model.layers[0].input],
                                  [model.layers[3].output])
layer_output = get_3rd_layer_output([x])[0]
  • 1
  • 2
  • 3
  • 4
  • 5

了解了如何获得指定层输出,下面看迁移部分模型用来训练的代码:与基础版相比只更改了第二步的代码。

# 第二步:构建完整模型
#include_top这个参数可以控制的是,到底要不要最后的这些全连接层。构建不带分类器的预训练模型
Inp = Input((224,224,3)) #定义一个输入层,输入图片尺寸为224x224
base_model = InceptionV3(weights='imagenet', include_top=False) 
intermediate_layer_model = Model(inputs=base_model.input,outputs=base_model.get_layer('Layer_Name').output)

x = intermediate_layer_model(Inp)
x = GlobalAveragePooling2D()(x)# 添加全局平均池化层
x = Dense(1024, activation='relu')(x)# 添加一个全连接层
predictions = Dense(200, activation='softmax')(x)# 自定义自己的分类器,这是一个200分类的分类器
model = Model(inputs=base_model.input, outputs=predictions)# 构建我们需要训练的完整模型
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

Layer_Name可以根据自己的需要指定任意中间层,将代码与基础版的第二步换一下,就可以实现模型部分的迁移训练,灵活运用预训练模型。

2.2 实现模型融合(多输入单输出,单输入单输出)

不同的模型对同一张图片提取到的特征是不同的,在单独一个模型不能满足任务需求时,不妨试试模型融合,因为迁移训练不会增加太多的训练量,所以多个模型融合的训练量也在可以接受的范围内。
这里一共介绍3中模型融合方式,如下图所示。

 
 
 
Input1
模型1特征提取器
模型2特征提取器
分类器

第一种融合方式的实现和2.1迁移部分模型类似,将平均池化层和全连接层看作模型2特征提取器,最后的一层(Softmax层)看作分类器就可以实现了。

 
 
 
 
 
Input
模型1特征提取器
模型2特征提取器
x
分类器

第二种为单输入单输出的模型融合,我们依然使用Keras的applications模块来实现,这里我们将VGG16和Resnet50两个模型的特征提取网络融合。模型1为Resnet50并加载预训练权重。

def model1():
    base_model1 = choice_model(weights='imagenet',
                              include_top=False,
                              input_shape=(norm_size, norm_size, 3))
    model = Model(inputs=base_model1.input, outputs=base_model1.get_layer('activation_43').output)
    return model
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

模型2为VGG16并加载预训练权重。

def model2():
    base_model2 = VGG16(weights='imagenet',
                              include_top=False,
                              input_shape=(norm_size, norm_size, 3))
    model = Model(inputs=base_model2.input, outputs=base_model2.get_layer('block5_pool').output)
    return model
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

将模型1和模型2提取到的特征进行融合,输入为224x224大小的图片,得到的model即为融合后的模型。

def merge_model( ):
    inp = Input((224,224,3))

    model_2 = model2()
    model_1 = model1()

    r1 = model_1(inp)
    r2 = model_2(inp)

    x = concatenate([r1,r2], axis=-1)

    model = Model(inputs=inp, outputs=x)
    return model
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

融合后的特征提取网络结构如图:
merge_model

 
 
 
 
 
Input1
模型1特征提取器
x
Input2
模型2特征提取器
分类器

第三种为多输入单输出的模型融合,首先也是定义两个加载预训练权重的模型,不同的是在merge_model( )函数中定义了两个输入

##多输入单输出
def merge_model_2( ):
    inp1 = Input((224,224,3))
    inp2 = Input((224, 224, 3))

    model_2 = model2()
    model_1 = model1()

    r1 = model_1(inp1)
    r2 = model_2(inp2)

    x = concatenate([r1,r2], axis=-1)

    model = Model(inputs=[inp1,inp2], outputs=x)
    return model
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

融合后的特征提取网络结构如图:
在这里插入图片描述

3、总结

(1)Keras内置的applications模块可以实现迁移学习,该模块的详细介绍见博客
(2)Keras有两种方法可以输出指定层的特征图,
第一种:自定义用于输出中间层的model
第二种:通过定义Keras函数实现,用于输出指定层的输出(我没用过。。。)
(3)Keras利用applications模块中自带的权重可以实现模型融合。


keras查看网络结构
深度学习用函数建立模型-Keras框架建立模型方法:函数API
51自学网自学EXCEL、自学PS、自学CAD、自学C语言、自学css3实例,是一个通过网络自主学习工作技能的自学平台,网友喜欢的软件自学网站。
京ICP备13026421号-1