这个模型是使用Functional API Model创建的
基本上它是这样工作的(也许如果你在阅读本文之前转到下面的“附带问题2”可能会更清楚):
- 您有一个输入张量(您也可以将其视为“输入数据”)
- 您创建(或重复使用)一个图层
- 您将输入张量传递给层(您“调用”具有输入的层)
- 你得到一个输出张量
您一直使用这些张量,直到您创建了整个图表。
但这还没有创建一个“模型”。 (您可以训练和使用其他东西)。
你所拥有的只是一张图表,告诉你哪些张量去了哪里。
要创建模型,您需要定义它的起点终点。
在示例中。
- 他们采用现有模型:
model = keras.applications.InceptionV3(...)
- 他们想扩展这个模型,所以他们得到了它的输出张量:
model.output
- 他们将此张量作为
GlobalAveragePooling2D 层的输入传递
- 他们得到这一层的输出张量为
new_output
- 他们将此作为输入传递给另一层:
Dense(N_CLASSES, ....)
- 并将其输出为
new_output(此变量已被替换,因为他们对保留其旧值不感兴趣...)
但是,由于它与函数式 API 一起使用,我们还没有模型,只有图表。为了创建模型,我们使用Model 定义输入张量和输出张量:
new_model = Model(old_model.inputs, new_output)
现在你有你的模型了。
如果您像我一样在另一个 var 中使用它 (new_model),那么旧模型仍将存在于 model 中。这些模型共享相同的层,这样每当你训练其中一个时,另一个也会更新。
问题:它如何知道我们想要在其间的其他层?
当你这样做时:
outputTensor = SomeLayer(...)(inputTensor)
您在输入和输出之间建立了联系。 (Keras 将使用内部 tensorflow 机制,并将这些张量和节点添加到图中)。没有输入,输出张量就不能存在。整个InceptionV3 模型从头到尾连接。它的输入张量经过所有层以产生一个输出张量。数据只有一种可能的方式,而图表就是方式。
当您获得此模型的输出并使用它来获得更多输出时,您的所有新输出都会连接到此,从而连接到模型的第一个输入。
可能添加到张量的属性_keras_history 与它如何跟踪图形密切相关。
所以,做Model(old_model.inputs, new_output) 自然会遵循唯一可能的方法:图表。
如果您尝试对未连接的张量执行此操作,则会收到错误消息。
附加问题 1
更喜欢从“keras.models”导入。基本上,这个模块将从另一个模块导入:
请注意,文件 keras/models.py 从 keras.engine.training 导入 Model。所以,是一样的。
附加问题 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,但创建用于在没有分支的模型中快速使用。