建立一个keras模型

时间:2018-07-05 21:52:35

标签: python neural-network keras deep-learning keras-layer

我不明白这段代码中发生了什么:

def construct_model(use_imagenet=True):
    # line 1: how do we keep all layers of this model ?
    model = keras.applications.InceptionV3(include_top=False, input_shape=(IMG_SIZE, IMG_SIZE, 3),
                                          weights='imagenet' if use_imagenet else None) # line 1: how do we keep all layers of this model ?

    new_output = keras.layers.GlobalAveragePooling2D()(model.output)

    new_output = keras.layers.Dense(N_CLASSES, activation='softmax')(new_output)
    model = keras.engine.training.Model(model.inputs, new_output)
    return model

具体地说,我的困惑是,当我们调用最后一个构造函数时

model = keras.engine.training.Model(model.inputs, new_output)

我们指定输入层和输出层,但是怎么知道我们希望所有其他层都保留?

换句话说,我们将new_output层附加到第1行中加载的预训练模型上,即new_output层,然后在最终的构造函数(最后一行)中,我们创建并返回一个带有指定的输入和输出层,但是它如何知道我们还需要其他哪些层?

侧面问题1):keras.engine.training.Model和keras.models.Model有什么区别?

问题2):当我们进行new_layer = keras.layers.Dense(...)(prev_layer)时,会发生什么? ()操作会返回新层吗?它到底是做什么的?

2 个答案:

答案 0 :(得分:5)

此模型是使用Functional API Model

创建的

基本上它是这样工作的(也许如果在阅读本文之前进入下面的“附带问题2”,它可能会变得更加清晰):

  • 您有一个输入张量(您也可以将其视为“输入数据”)
  • 您创建(或重复使用)层
  • 您将输入张量传递到一个图层(您通过输入“调用”一个图层)
  • 您得到一个输出张量

在创建整个图形之前,您将继续使用这些张量。

但是,这还没有创建一个“模型”。 (您可以训练和使用其他东西的人。)
您所拥有的只是一张图,告诉您哪些张量到达哪里。

要创建模型,请定义它的开始终点。


在示例中。

  • 他们采用现有模型:model = keras.applications.InceptionV3(...)
  • 他们想扩展此模型,以便获得其输出张量model.output
  • 他们将这个张量作为GlobalAveragePooling2D层的输入
  • 他们获得该层的输出张量为new_output
  • 他们将其作为输入传递到另一层:Dense(N_CLASSES, ....)
  • 并以new_output的形式获取其输出(此var被替换,因为他们对保持其旧值不感兴趣...)

但是,由于它与功能API兼容,因此我们还没有模型,只有图。为了创建模型,我们使用Model定义输入张量和输出张量:

new_model = Model(old_model.inputs, new_output)    

现在您有了模型。
如果像我(new_model)一样在另一个变量中使用它,则旧模型仍将存在于model中。而且这些模型共享相同的层,以这种方式,每当您训练其中一个时,另一个也会更新。


问题:它如何知道我们还希望在其他哪些层?

当您这样做:

outputTensor = SomeLayer(...)(inputTensor)    

您在输入和输出之间建立了连接。 (Keras将使用内部张量流机制并将这些张量和节点添加到图中)。没有输入就不能存在输出张量。整个InceptionV3模型是从头到尾连接的。它的输入张量遍历所有层以产生输出张量。数据遵循的只有一种可能的方式,而图形就是这种方式。

当您获得该模型的输出并使用它来获取更多输出时,所有新的输出都将与此连接,从而与模型的第一个输入连接。

添加到张量的属性_keras_history可能与其跟踪图形的方式密切相关。

因此,Model(old_model.inputs, new_output)自然会遵循唯一可能的方法:图形。

如果您尝试使用未连接的张量执行此操作,则会出现错误。


旁题1

首选从“ keras.models”导入。基本上,该模块将从其他模块导入:

请注意,文件keras/models.pyModel导入了keras.engine.training。所以,这是同一回事。

问题2

不是new_layer = keras.layers.Dense(...)(prev_layer)

它是output_tensor = keras.layers.Dense(...)(input_tensor)

您正在同一行中做两件事:

  • 创建图层-使用keras.layers.Dense(...)
  • 调用具有输入张量的图层以获得输出张量

如果您想将同一图层用于不同的输入:

denseLayer = keras.layers.Dense(...) #creating a layer

output1 = denseLayer(input1)  #calling a layer with an input and getting an output
output2 = denseLayer(input2)  #calling the same layer on another input
output3 = denseLayer(input3)  #again   

奖金-创建与顺序模型相同的功能模型

如果您创建此顺序模型:

model = Sequential()
model.add(Layer1(...., input_shape=some_shape))   
model.add(Layer2(...))
model.add(Layer3(...))

您所做的与以下操作完全相同:

inputTensor = Input(some_shape)
outputTensor = Layer1(...)(inputTensor)
outputTensor = Layer2(...)(outputTensor)    
outputTensor = Layer3(...)(outputTensor)

model = Model(inputTensor,outputTensor)

有什么区别?

无论如何,功能性API模型都是完全免费的。您可以创建分支:

out1 = Layer1(..)(inputTensor)    
out2 = Layer2(..)(inputTensor)

您可以加入张量:

joinedOut = Concatenate()([out1,out2])   

以此,您可以使用各种精美的东西,分支,门,串联,添加等来创建任何内容,而这是顺序模型无法做到的。

实际上,Sequential模型也是Model,但是创建时是为了在没有分支的模型中快速使用。

答案 1 :(得分:0)

有一种方法可以从您可能会建立的预训练模型中构建模型。

请参见https://keras.io/applications/#fine-tune-inceptionv3-on-a-new-set-of-classes

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)
model = Model(inputs=base_model.input, outputs=predictions)
for layer in base_model.layers:
    layer.trainable = False
model.compile(optimizer='rmsprop', loss='categorical_crossentropy')

每次通过“ x = Dense(...”)之类的操作添加图层时,有关计算图的信息都会更新。您可以交互地键入此内容以查看其包含的内容:

x.graph.__dict__

您可以看到各种各样的属性,包括关于上一层和下一层的属性。这些是内部实施细节,并且可能会随着时间的推移而变化。