该模型是使用功能性API模型 https://keras.io/getting-started/functional-api-guide/
基本上它的工作原理是这样的(也许如果你在阅读本文之前转到下面的“附带问题2”,它可能会变得更清楚):
- 你有一个输入张量(您也可以将其视为“输入数据”)
- 您创建(或重用)图层
- 您将输入张量传递给一个层(您用输入“调用”一个层)
- 你得到一个输出张量
您继续使用这些张量,直到创建了整个张量graph.
但这还没有创建一个“模型”。 (你可以训练和使用其他东西)。
你所拥有的只是一张图表,告诉你哪些张量去哪里。
要创建模型,您需要定义其起点和终点。
在例子中。
- 他们采用现有模型:
model = keras.applications.InceptionV3(...)
- 他们想要扩展这个模型,所以他们得到了它输出张量:
model.output
- 他们将此张量作为输入
GlobalAveragePooling2D
层
- 他们得到该层的输出张量为
new_output
- 他们将其作为输入传递给另一层:
Dense(N_CLASSES, ....)
- 并得到它的输出
new_output
(这个变量被替换,因为他们对保留其旧值不感兴趣......)
但是,由于它与函数式 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”导入。基本上,该模块将从其他模块导入:
- https://github.com/keras-team/keras/blob/master/keras/models.py https://github.com/keras-team/keras/blob/master/keras/models.py
请注意该文件keras/models.py
进口Model
from keras.engine.training
。所以,这是同样的事情。
附带问题2
它不是new_layer = keras.layers.Dense(...)(prev_layer)
.
It is 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])
有了这个,您可以创建anything你想要各种奇特的东西,分支,门,串联,添加等等,这是顺序模型无法做到的。
事实上,一个Sequential
模型也是一个Model
,但创建它是为了在没有分支的模型中快速使用。