构建keras模型
Constructing a keras model
我不明白这段代码中发生了什么:
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层,然后在最后的构造函数中(最后一行) ,我们只是创建并 return 一个具有指定输入和输出层的模型,但它如何知道我们想要介于两者之间的其他层?
附带问题 1):keras.engine.training.Model 和 keras.models.Model 有什么区别?
附带问题 2:当我们执行 new_layer = keras.layers.Dense(...)(prev_layer) 时究竟发生了什么? ()操作returnnew layer,具体是做什么的?
有这种方法可以从您可以构建的预训练模型构建模型。
参见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__
你可以看到各种属性,包括关于上一层和下一层的。这些是内部实施细节,可能会随着时间的推移而改变。
此模型是使用 Functional API Model
创建的
基本上它是这样工作的(也许如果你在阅读这篇文章之前转到下面的"side question 2"它可能会更清楚):
- 你有一个输入张量(你也可以把它看成"input data")
- 您创建(或重复使用)图层
- 你将输入张量传递给一个层(你"call"一个带有输入的层)
- 你得到一个输出张量
您继续使用这些张量,直到您创建了整个 图。
但这还没有创建 "model"。 (一个你可以训练和使用其他东西)。
您所拥有的只是一张图表,告诉您哪些张量去哪里。
要创建模型,您需要定义它的起点终点。
在例子中。
- 他们采用现有模型:
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)
现在你有了你的模型。
如果你像我一样在另一个 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
,只是为了在没有分支的模型中快速使用而创建。
我不明白这段代码中发生了什么:
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层,然后在最后的构造函数中(最后一行) ,我们只是创建并 return 一个具有指定输入和输出层的模型,但它如何知道我们想要介于两者之间的其他层?
附带问题 1):keras.engine.training.Model 和 keras.models.Model 有什么区别?
附带问题 2:当我们执行 new_layer = keras.layers.Dense(...)(prev_layer) 时究竟发生了什么? ()操作returnnew layer,具体是做什么的?
有这种方法可以从您可以构建的预训练模型构建模型。
参见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__
你可以看到各种属性,包括关于上一层和下一层的。这些是内部实施细节,可能会随着时间的推移而改变。
此模型是使用 Functional API Model
创建的基本上它是这样工作的(也许如果你在阅读这篇文章之前转到下面的"side question 2"它可能会更清楚):
- 你有一个输入张量(你也可以把它看成"input data")
- 您创建(或重复使用)图层
- 你将输入张量传递给一个层(你"call"一个带有输入的层)
- 你得到一个输出张量
您继续使用这些张量,直到您创建了整个 图。
但这还没有创建 "model"。 (一个你可以训练和使用其他东西)。
您所拥有的只是一张图表,告诉您哪些张量去哪里。
要创建模型,您需要定义它的起点终点。
在例子中。
- 他们采用现有模型:
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)
现在你有了你的模型。
如果你像我一样在另一个 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
,只是为了在没有分支的模型中快速使用而创建。