【问题标题】:Keras Functional API Multiple Input ModelKeras 函数式 API 多输入模型
【发布时间】:2019-05-17 12:12:02
【问题描述】:

我正在尝试使用 Keras 中的功能 API 创建一个具有以下结构的多输入模型:

共有三个输入:Team_1_InTeam_2_InHome_In。其中Team_1_InTeam_2_In 经过Embedding 层,然后是BatchNormalizationFlatten 层。问题是当我尝试在BatchNormalization 之后添加Flatten 层时出现此错误:

---------------------------------------------------------------------------

ValueError                                Traceback (most recent call last) <ipython-input-46-8354b255cfd1> in <module>
     15 batch_normalization_2 = BatchNormalization()(team_2_strength)
     16 
---> 17 flatten_1 = Flatten()(batch_normalization_1)
     18 flatten_2 = Flatten()(batch_normalization_2)
     19 

~/conda/lib/python3.6/site-packages/keras/engine/topology.py in
__call__(self, inputs, **kwargs)
    573                 # Raise exceptions in case the input is not compatible
    574                 # with the input_spec specified in the layer constructor.
--> 575                 self.assert_input_compatibility(inputs)
    576 
    577                 # Collect input shapes to build layer.

~/conda/lib/python3.6/site-packages/keras/engine/topology.py in assert_input_compatibility(self, inputs)
    488                                      self.name + ': expected min_ndim=' +
    489                                      str(spec.min_ndim) + ', found ndim=' +
--> 490                                      str(K.ndim(x)))
    491             # Check dtype.
    492             if spec.dtype is not None:

ValueError: Input 0 is incompatible with layer flatten_10: expected min_ndim=3, found ndim=2 

我尝试使用BatchNormalization 层的轴参数,但没有帮助。这是我的代码:

# create embedding layer
from keras.layers import Embedding
from keras.layers import BatchNormalization, Flatten, Dense
from numpy import unique

# Create an embedding layer
team_lookup = Embedding(input_dim=n_teams,
                        output_dim=1,
                        input_length=1,
                        name='Team-Strength')

# create model with embedding layer
from keras.layers import Input, Embedding, Flatten
from keras.models import Model

# Create an input layer for the team ID
teamid_in = Input(shape=(1,))

# Lookup the input in the team strength embedding layer
strength_lookup = team_lookup(teamid_in)

# Flatten the output
strength_lookup_flat = Flatten()(strength_lookup)

# Combine the operations into a single, re-usable model
team_strength_model = Model(teamid_in, strength_lookup_flat, name='Team-Strength-Model')



# Create an Input for each team
team_in_1 = Input(shape=(1,), name='Team-1-In')
team_in_2 = Input(shape=(1,), name='Team-2-In')

# Create an input for home vs away
home_in = Input(shape=(1,), name='Home-In')

# Lookup the team inputs in the team strength model
team_1_strength = team_strength_model(team_in_1)
team_2_strength = team_strength_model(team_in_2)

batch_normalization_1 = BatchNormalization()(team_1_strength)
batch_normalization_2 = BatchNormalization()(team_2_strength)

flatten_1 = Flatten()(batch_normalization_1)
flatten_2 = Flatten()(batch_normalization_2)

# Combine the team strengths with the home input using a Concatenate layer, then add a Dense layer
out = Concatenate()([flatten_1, flatten_2, home_in])
out = Dense(1)(out)

【问题讨论】:

    标签: python keras keras-layer flatten batch-normalization


    【解决方案1】:

    如报错所示,Flatten层需要一个3D张量:

    ValueError: Input 0 is incompatible with layer flatten_10: expected min_ndim=3, found ndim=2
    

    在代码的第一部分,您将输入传递给嵌入层,一切正常,编译成功:

    team_lookup = Embedding(input_dim=1,
                            output_dim=1,
                            input_length=1,
                            name='Team-Strength')
    
    strength_lookup = team_lookup(teamid_in)
    
    batch_normalization_1 = BatchNormalization()(strength_lookup)
    
    strength_lookup_flat = Flatten()(batch_normalization_1)
    
    team_strength_model = Model(teamid_in, strength_lookup_flat, name='Team-Strength-Model')
    team_strength_model.compile(optimizer='adam', loss='categorical_crossentropy')
    

    但在第二部分代码中,您将输入传递给team_strength_model,它会将形状转换为(batch, flatten) 的张量展平。当您将此 2D 张量传递给 BatchNormalization 时,它会引发这样的异常。

    解决问题

    1) 将输入传递给Embedding

    2) 做BatchNormalization

    3) 展平BatchNormalization 的输出

    【讨论】:

      【解决方案2】:

      这是一个关于Datacamp练习的问题:https://campus.datacamp.com/courses/advanced-deep-learning-with-keras-in-python/multiple-inputs-3-inputs-and-beyond?ex=11

      我在这里复制它不是为了侵犯他们的IP,而是为了更清楚地解释它。我在使用 Datacamp 之类的网站(我经常使用它)时遇到的问题之一是,如果您不了解发生了什么,除了在 SO 上发布之外,没有真正的追索权。

      Datacamp 中没有明确表述该问题。练习介绍了集成模型;在这里,一个模型根据常规赛数据预测两支篮球队之间的得分差异,另一个模型根据早先的预测和新数据预测得分差异。

      不幸的是,在练习中,这两个模型都只是称为model,它们是乱序呈现的,练习中使用的实际模型从未明确地与学生分享。哎呀。

      这是第一个模型。并不是说这与 OP 的模型不同,因为它使用嵌入 layer,而不是嵌入 model。同样,Datacamp 练习对此并不清楚,Embedding 的性质在没有通知学生的情况下被更改。它根据整数 id(哑)以及哪支球队是主队或客队来预测两队之间的得分差异。

      # Create an Input for each team
      team_in_1 = Input(shape=(1,), name='Team-1-In')
      team_in_2 = Input(shape=(1,), name='Team-2-In')
      
      # Create an input for home vs away
      home_in = Input(shape=(1,), name='Home-In')
      
      # Create an embedding layer
      team_lookup = Embedding(input_dim=n_teams,
                              output_dim=1,
                              input_length=1,
                              name='Team-Strength')
      
      team_1_strength = team_lookup(team_in_1)
      team_2_strength = team_lookup(team_in_2)
      
      batch_normalization_1 = BatchNormalization(axis=1)(team_1_strength)
      batch_normalization_2 = BatchNormalization(axis=1)(team_2_strength)
      
      # flatten batch_normalization_1
      flatten_1 = Flatten()(batch_normalization_1)
      
      # flatten batch_normalization_2
      flatten_2 = Flatten()(batch_normalization_2)
      
      out = Concatenate()([flatten_1, flatten_2, home_in])
      out = Dense(1)(out)
      
      model = Model([team_in_1, team_in_2, home_in], out)
      model.compile(optimizer="adam", loss="mean_absolute_error")
      

      然后,此模型适用于常规赛数据:

      model.fit([games_season["team_1"], games_season["team_2"], games_season["home"]],
                games_season["score_diff"],
                epochs=1,
                verbose=True,
                validation_split=0.1,
                batch_size=2048)
      

      ...并用于预测不同数据集的分数差异:

      # Predict
      games_tourney['pred'] = model.predict(
          [games_tourney["team_1"], 
           games_tourney["team_2"], 
           games_tourney["home"]])
      

      现在将此数据集拆分为训练和测试。

      games_tourney_train = games_tourney.loc[games_tourney["season"] < 2010]
      games_tourney_test = games_tourney.loc[games_tourney["season"] >= 2010]
      

      这是第二个模型,我无缘无故地称之为preds_model

      # Create an input layer with 3 columns
      input_tensor = Input((3, ))
      
      # Pass it to a Dense layer with 1 unit
      output_tensor = Dense(1)(input_tensor)
      
      # Create a model
      preds_model = Model(input_tensor, output_tensor)
      
      # Compile the model
      preds_model.compile(optimizer="adam", loss="mean_absolute_error")
      
      preds_model.fit(games_tourney_train[['home', 'seed_diff', 'pred']],
                games_tourney_train['score_diff'],
                epochs=1,
                verbose=True)
      

      最后,评估您的(第一个)集成模型:

      # Evaluate the model on the games_tourney_test dataset
      print(preds_model.evaluate(games_tourney_test[["home", "seed_diff", "pred"]],
                     games_tourney_test["score_diff"], verbose=False))
      

      你的输出:

      11.94
      

      我怀疑那里有更直接的集成模型介绍。

      【讨论】:

      • 后来对该模型的检查表明,应该使用更高的学习率来使模型更快地收敛。损失大约 9 分(每场比赛得分)是合理的。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-12-26
      • 2020-03-21
      • 2021-06-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多