代码之家  ›  专栏  ›  技术社区  ›  Baron Yugovich

构建路缘石模型

  •  2
  • Baron Yugovich  · 技术社区  · 6 年前

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

    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)
    

    我们指定了输入层和输出层,但是它怎么知道我们希望所有其他层都保持不变呢?

    换言之,我们将新的_输出层附加到我们在第1行加载的预先训练的模型(即新的_输出层),然后在最终构造函数(最后一行)中,我们只创建并返回一个具有指定输入和输出层的模型,但它如何知道我们希望在这两个层之间包含哪些其他层?

    附带问题1):keras.engine.training.model和keras.models.model有什么区别?

    附带问题2:当我们执行new_layer=keras.layers.dense(…)(prev_layer)时,到底会发生什么?()操作是否返回新层,它具体做什么?

    2 回复  |  直到 6 年前
        1
  •  5
  •   Daniel Möller    6 年前

    此模型是使用 Functional API Model

    基本上它是这样工作的(如果你在阅读之前进入下面的“次要问题2”,它可能会更清晰):

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

    你继续使用这些张量,直到你创造出 图表 是的。

    但这还没有创造出一个“模型”。(你可以训练和使用其他东西)。
    你所拥有的只是一个图表,它告诉我们哪些张量去了哪里。

    要创建模型,需要定义它的起点和终点。


    在这个例子中。

    • 他们采取了现有的模式: model = keras.applications.InceptionV3(...)
    • 他们想扩展这个模型,所以他们得到了 输出张量 以下内容: model.output
    • 他们把这个张量作为 GlobalAveragePooling2D
    • 他们得到这个层的输出张量为 new_output
    • 它们将此作为输入传递到另一层: Dense(N_CLASSES, ....)
    • 输出为 新的输出 (此var已被替换,因为它们不想保留其旧值…)

    但是,由于它与函数式api一起工作,我们还没有一个模型,只有一个图。为了创建一个模型,我们使用 Model 定义输入张量和输出张量:

    new_model = Model(old_model.inputs, new_output)    
    

    现在你有了你的模型。
    如果你像我一样在另一个变量中使用它( 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 是的。所以,这是一样的。

    附带问题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 模型也是 模型 ,但创建的目的是在没有分支的模型中快速使用。

        2
  •  0
  •   swiftg    6 年前

    有一种方法可以从一个预先训练过的模型中建立一个模型,你可以建立在这个模型上。

    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__
    

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