模型组合时未遵循批量大小维度

我在训练过程中定义了一个Keras模型,如下所示:

   img = keras.Input(shape=[65, 65, 2])   bnorm = keras.layers.BatchNormalization()(img)   ...   model = keras.Model(img, outputprob)

然而,在服务过程中,我的输入有所不同。因此,我定义了一个输入层(验证to_img的形状也为(65, 65, 2)),并尝试使用以下代码进行模型组合:

  to_img = keras.layers.Lambda(...)(json_input)  model_output = model(to_img)  serving_model = keras.Model(json_input, model_output)

然而,我得到了以下错误:

tensorflow.python.framework.errors_impl.InvalidArgumentError: Shape must be rank 4 but is rank 3 for 'model/batch_normalization/cond/FusedBatchNorm' (op: 'FusedBatchNorm') with input shapes: [65,65,2], [2], [2], [0], [0].

这似乎表明批量维度未能通过。为什么会这样?

编辑:我尝试过的方法包括:

(1) 在所有层中明确设置trainable=False,但这似乎没有任何效果:

  model_core = model  for layer in model_core.layers:    layer.trainable = False  model_output = model_core(to_img)

(2) 尝试扩展预处理的结果:

   to_img = keras.layers.Lambda(      lambda x : preproc(x))(json_input)   to_img = keras.layers.Lambda(       lambda x : tf.expand_dims(x, axis=0) )(to_img)

这导致了一个错误:AttributeError: 'Model' object has no attribute '_name',发生在serving_model = keras.Model(json_input, model_output)这行。

(3) 将Lambda层更改为使用map_fn来逐个处理数据:

to_img = keras.layers.Lambda(    lambda items: K.map_fn(lambda x: preproc, items))(json_input)

这导致了一个形状错误,表明预处理函数接收到的是[65,2]的项目,而不是[65,65,2]。这表明Lambda层一次处理一个示例。

(4) 以下是模型的完整代码:

  img = keras.Input(shape=[height, width, 2])  # 模型的卷积部分  cnn = keras.layers.BatchNormalization()(img)  for layer in range(nlayers):    nfilters = nfil * (layer + 1)    cnn = keras.layers.Conv2D(nfilters, (ksize, ksize), padding='same')(cnn)    cnn = keras.layers.Activation('elu')(cnn)    cnn = keras.layers.BatchNormalization()(cnn)    cnn = keras.layers.MaxPooling2D(pool_size=(2, 2))(cnn)  cnn = keras.layers.Flatten()(cnn)  cnn = keras.layers.Dropout(dprob)(cnn)  cnn = keras.layers.Dense(10, activation='relu')(cnn)  # 模型的特征工程部分  engfeat = keras.layers.Lambda(    lambda x: engineered_features(x, height//2))(img)  # 连接两个部分  both = keras.layers.concatenate([cnn, engfeat])  ltgprob = keras.layers.Dense(1, activation='sigmoid')(both)  # 创建模型  model = keras.Model(img, ltgprob)  def rmse(y_true, y_pred):    import tensorflow.keras.backend as K    return K.sqrt(K.mean(K.square(y_pred - y_true), axis=-1))  optimizer = tf.keras.optimizers.Adam(lr=params['learning_rate'],                                       clipnorm=1.)  model.compile(optimizer=optimizer,                loss='binary_crossentropy',                metrics=['accuracy', 'mse', rmse])

以及预处理函数的代码:

def reshape_into_image(features, params):  # 堆叠输入形成2通道输入  # features['ref'] 是 [-1, height*width]  # 堆叠图像是 [-1, height*width, n_channels]  n_channels = 2  stacked = tf.concat([features['ref'], features['ltg']], axis=1)  height = width = PATCH_SIZE(params)  return tf.reshape(stacked, [height, width, n_channels])

以及服务层:

  # 1. 从JSON中提取多个输入的层  height = width = PATCH_SIZE(hparams)  json_input = keras.layers.concatenate([    keras.layers.Input(name='ref', dtype=tf.float32, shape=(height * width,)),    keras.layers.Input(name='ltg', dtype=tf.float32, shape=(height * width,)),  ], axis=0)  # 2. 将json_input转换为图像(模型所需的格式)  to_img = keras.layers.Lambda(    lambda x: reshape_into_image(features={      'ref': tf.reshape(x[0], [height * width, 1]),      'ltg': tf.reshape(x[1], [height * width, 1])    }, params=hparams),    name='serving_reshape')(json_input)  # 3. 现在,使用训练好的模型进行预测  model_output = model(to_img)  # 4. 创建服务模型  serving_model = keras.Model(json_input, model_output)

回答:

考虑到样本轴,您的模型输入形状是(?, 65, 65, 2),其中?可以是一个或多个。因此,您需要修改Lambda层(实际上是其中的包装函数),使得其输出也为(?, 65, 65, 2)。一种方法是在包装函数中使用K.expand_dims(out, axis=0),这样输出形状将为(1, 65, 65, 2)

顺便提一下,K指的是后端:from keras import backend as K

此外,请注意,您必须定义Lambda包装的函数以保留批量轴;否则,很可能在定义该函数时出了问题。

更新:

错误AttributeError: 'Model' object has no attribute '_name'是因为您将json_input作为模型的输入传递。然而,它不是输入层,而是concatenation层的输出。为了解决这个问题,首先定义输入层,然后将它们传递给concatenation层和Model类,像这样:

inputs = [keras.layers.Input(name='ref', dtype=tf.float32, shape=(height * width,)),           keras.layers.Input(name='ltg', dtype=tf.float32, shape=(height * width,))]json_input = keras.layers.concatenate(inputs, axis=0)# ...serving_model = keras.Model(inputs, model_output)

更新2:我认为您可以写得更简单一些,不必陷入这么多不必要的麻烦。您想从形状为(?, h*w)的两个张量转换到形状为(?, h, w, 2)的张量。您可以使用Reshape层,这样做的话会是:

from keras.layers import Reshapeinputs = [keras.layers.Input(name='ref', dtype=tf.float32, shape=(height * width,)),           keras.layers.Input(name='ltg', dtype=tf.float32, shape=(height * width,))]reshape_layer = Reshape((height, width, 1))r_in1 = reshape_layer(inputs[0])r_in2 = reshape_layer(inputs[1])img = concatenate([r_in1, r_in2])output = model(img)serving_model = keras.Model(inputs, output)

不需要任何自定义函数或Lambda层。

顺便说一句,如果您有兴趣知道,批量轴移除的问题是由以下这行代码引起的:

return tf.reshape(stacked, [height, width, n_channels])

在重塑时,您没有考虑批量轴。

Related Posts

使用LSTM在Python中预测未来值

这段代码可以预测指定股票的当前日期之前的值,但不能预测…

如何在gensim的word2vec模型中查找双词组的相似性

我有一个word2vec模型,假设我使用的是googl…

dask_xgboost.predict 可以工作但无法显示 – 数据必须是一维的

我试图使用 XGBoost 创建模型。 看起来我成功地…

ML Tuning – Cross Validation in Spark

我在https://spark.apache.org/…

如何在React JS中使用fetch从REST API获取预测

我正在开发一个应用程序,其中Flask REST AP…

如何分析ML.NET中多类分类预测得分数组?

我在ML.NET中创建了一个多类分类项目。该项目可以对…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注