【问题标题】:how to merge classification models horizontally如何水平合并分类模型
【发布时间】:2021-06-18 14:15:50
【问题描述】:

我已经训练了许多模型,每个模型都回答一个简单的是/否问题。伪代码:

model_dog = keras.load('is_dog')
model_cat = keras.load('is_cat')
model_rat = keras.load('is_rat')

image = load_photo_as_numpy_array('photo.jpg')

multi_class = [ m.predict(image) for m in (model_dog,model_cat,model_rat) ]

这很好用,但是 a> 很慢,因为推理是按顺序而不是并行进行的(我有数百个这样的模型,而不仅仅是 3 个),而且 b> 使用起来比我有 ONE 模型要复杂得多进行多分类。

我想要的是:

model = keras.concat_horizontal([ model_dog, model_cat, model_rat ])
model.save('combined_model')

那么每当我想使用组合模型时,就这么简单:

model = keras.load('combined_model')
multi_class = m.predict(image)

这样,我可以通过训练一个简单的模型(例如识别鱼的模型)向组合模型添加新的分类。

【问题讨论】:

  • 我知道图层有一个 concat_horizo​​ntal,但模型没有。此外,我在发布之前查看了 Stackoverflow 上的几个类似问题 - 对他们的任何答案都不满意。
  • 我意识到这可能被称为“合奏”,但我认为合奏是关于投票并将选票合并为一个最终答案。我在这里谈论的是一种不同的合奏。每个模型都是回答自己的 Y/N 问题的专家;我想像运行这些模型一样运行这些模型,并最终得到 Y/N 答案的串联。
  • 你能链接到关于 Keras 中这个 concat_horizo​​ntal 函数的文档吗?
  • @freeideas 没有这样的库。您应该定义一个新的输入层。然后将其链接到您的所有模型。并收集所有模型的输出层。然后用这些输入和输出定义一个新模型。然后你可以保存并加载它。
  • @Kaveh:这听起来正是我想要做的。这可能会给我带来我正在寻找的大部分或全部好处:)

标签: keras tensorflow2.0


【解决方案1】:

正如我在 cmets 中建议的那样,您可以将多个模型合并到一个新模型中并使用这个新模型进行预测。

首先,我编写一个函数来合并模型并返回一个新的组合模型。这就是你想要的:

def concat_horizontal(models, input_shape):
  models_count = len(models)
  hidden = []
  input = tf.keras.layers.Input(shape=input_shape)
  for i in range(models_count):
    hidden.append(models[i](input))
  output = tf.keras.layers.concatenate(hidden)
  model = tf.keras.Model(inputs=input, outputs=output)
  return model

让我们来看看一个例子。假设我们想像这样合并两个顺序模型:

def model_1():
  model = tf.keras.models.Sequential([
                      tf.keras.layers.Flatten(input_shape=(28,28,1)),
                      tf.keras.layers.Dense(150, activation='relu'),
                      tf.keras.layers.Dense(200, activation='relu'),
                      tf.keras.layers.Dense(150, activation='relu'),
                      tf.keras.layers.Dense(10, activation='softmax')], name="model1")
  model.compile(optimizer=tf.keras.optimizers.Adam(), loss=tf.keras.losses.sparse_categorical_crossentropy, metrics=['accuracy'])
  return model

def model_2():
  model = tf.keras.models.Sequential([
                      tf.keras.layers.Flatten(input_shape=(28,28,1)),
                      tf.keras.layers.Dense(150, activation='relu'),
                      tf.keras.layers.Dense(150, activation='relu'),
                      tf.keras.layers.Dense(10, activation='softmax')], name="model2")
  model.compile(optimizer=tf.keras.optimizers.Adam(), loss=tf.keras.losses.sparse_categorical_crossentropy, metrics=['accuracy'])
  return model

model1 = model_1()
model2 = model_2()

让我们使用 MNIST 作为我们两个模型的训练数据集:

import tensorflow_datasets as tfds
ds_1 = tfds.load('mnist', split='train', as_supervised=True)
ds_2 = tfds.load('mnist', split='test', as_supervised=True)

def map_fn(image, label):
  image = image / 255
  return image, label

ds_1 = ds_1.map(map_fn).shuffle(1024).batch(32)
ds_2 = ds_2.map(map_fn).shuffle(1024).batch(32)

现在,我们可以训练模型,保存它们,然后像​​这样加载它们:

model1.fit(ds_1, epochs=2, validation_data=ds_1)
model2.fit(ds_2, epochs=2, validation_data=ds_2)

model1.save('model1.h5')
model2.save('model2.h5')

model3 = tf.keras.models.load_model('model1.h5')
model4 = tf.keras.models.load_model('model2.h5')

所以我们有 2 个单独的模型 (model3,model4) 并希望将它们合并为一个新模型。将它们沿着输入形状(在本例中为 MNIST 数据形状)传递给我们上面编写的函数:

new_model = concat_horizontal([model3,model4],(28,28,1))

现在,如果我们绘制这个新模型:

tf.keras.utils.plot_model(new_model)

是时候得到模型的预测了:

sample = ds_1.unbatch().take(1)
for i,j in sample:
  img = i
  lbl = j
img = tf.expand_dims(img,axis=0)
pred = new_model.predict(img)
pred = np.reshape(pred,(2,10))
results = np.argmax(pred,axis=1)
print(results)

import matplotlib.pyplot as plt
plt.imshow(np.array(img).squeeze())
plt.show

在我的情况下,我将两个预测都归类为 4:

输出:

【讨论】:

  • 实施了这个建议,它完全有效!非常高兴和感谢@Kaveh
猜你喜欢
  • 1970-01-01
  • 2018-02-18
  • 2022-12-18
  • 1970-01-01
  • 2013-12-03
  • 1970-01-01
  • 2014-01-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多