【问题标题】:Unable to completely separate outputs of model in TensorFlow无法在 TensorFlow 中完全分离模型的输出
【发布时间】:2021-01-14 06:42:55
【问题描述】:

我正在尝试创建一个具有两个回归输出、一个分数和一个置信度的卷积神经网络。我冻结了它们共有的层,希望增加置信度输出不会改变分数,但在我的实验中它有。对于只有分数的模型,我使用 Xception 并添加了一个简单的GlobalAveragePooling2DDense(512) 层,然后输出一个数字。

base_model = Xception(input_shape=(224, 224, 3), weights='imagenet', include_top=False)

x = base_model.output
x = GlobalAveragePooling2D()(x)
x = Dense(512, activation='relu')(x)
predictions = Dense(1, activation='sigmoid')(x)

model = Model(inputs=base_model.input, outputs=predictions)

for layer in base_model.layers:
    layer.trainable = False

optimizer = Adam(learning_rate=learning_rate)
model.compile(loss='mae', optimizer=optimizer, metrics=['mse','mae'], run_eagerly=True)

model.summary() 的结尾是这样的:

当我拟合它时,模型会产生很好的结果。

但是当我尝试添加第二个输出时,第一个输出的结果变得更糟。新模型通过元组进行训练,其中第一个数字与第一个模型相同,第二个数字是置信度值。该模型与上述模型非常相似。

base_model = Xception(input_shape=(224, 224, 3), weights='imagenet', include_top=False)

x = base_model.output
x = GlobalAveragePooling2D()(x)

score_x = Dense(512, activation='relu')(x)
score_out = Dense(1, activation='sigmoid', name='score_model')(score_x)

confidence_x = Dense(512, activation='relu')(x)
confidence_out = Dense(1, name='confidence_model')(confidence_x)

model = Model(inputs=base_model.input, outputs=[score_out, confidence_out])

for layer in base_model.layers:
    layer.trainable = False

losses = {'score_model': 'mae', 'confidence_model': 'mae'}
loss_weights = {'score_model': 1, 'confidence_model': 1} 

model.compile(loss=losses, loss_weights=loss_weights, optimizer=optimizer, metrics=['mse','mae'], run_eagerly=True)

当我查看model.summary() 时,它的可训练参数是之前模型的两倍,这正是我所期望的。到目前为止,一切对我来说都是正确的。

但是当我训练这个模型时,分数的表现要差得多。我在想它会是一样的(在随机变化范围内)。在第一个 epoch 之后,第一个模型的损失约为 0.125。第二个模型的score_model_loss 约为 0.554。显然我并没有完全分离模型。我错过了什么?

【问题讨论】:

  • 你的优化过程没有分离。优化两个目标比优化一个目标更难。
  • 我能想到两件事.. 1) 仔细检查基本模型层是否确实冻结在 model 和 2) 尝试设置 loss_weights['confidence_model'] = 0. 看看这是否会使事情变得更好(如果是这样,请尝试仅缓慢增加它)
  • 如果目标不是一起优化它们,只构建 2 个单独的模型是否有意义?
  • @AkshaySehgal 为了提高效率我想让一个模型同时产生两个输出。
  • 缩小一点,我不知道您的具体应用,但我永远不会尝试将置信度/方差拟合为点估计(MSE、MAE、...)。相反,我会使用像 KL-divergence 这样的目标。联合拟合均值和方差。

标签: python tensorflow keras conv-neural-network


【解决方案1】:

注意:这个答案会很好,只是因为进行特征提取的层被冻结了。正如@Akshay Sehgal 在 cmets 中所述:

同时优化 2 个目标实际上与分别优化 2 个独立目标完全不同

在这种情况下,我们分别针对 2 个目标进行优化。


最简单的解决方案可能是编写一个带有 2 个tf.GradientTape 的自定义训练循环,每个目标一个。让我们考虑这个非常简单的例子:

虚拟数据

让我们创建一些随机数据

import tensorflow as tf

X = tf.random.normal((1000,1))
y1= 3*X + 1
y2 = -2*X +2

ds = tf.data.Dataset.from_tensor_slices((X,y1,y2)).batch(10)

创建具有 2 个输出的模型

在该示例中,我跳过了特征提取步骤,因为简单的线性回归将适用于数据。但由于您的特征提取器网络被冻结,示例类似。

inp = tf.keras.Input((1,))
dense_1 = tf.keras.layers.Dense(1, name="objective1")(inp)
dense_2 = tf.keras.layers.Dense(1, name="objective2")(inp)
model = tf.keras.Model(inputs=inp, outputs=[dense_1, dense_2])

# setting up the loss functions as well as the optimizer
opt = tf.optimizers.SGD()
loss_func1 = tf.losses.mean_squared_error
loss_func2 = tf.losses.mean_absolute_error

注意两个密集层的名称:稍后我将使用它们来检索适当的权重。

获取权重进行优化

我们可以使用之前设置的名称来检索属于每个目标的变量:

var1, var2 = [],[]
for l in model.layers:
    if "objective1" in l.name:
        var1 += l.trainable_variables
    if "objective2" in l.name:
        var2 += l.trainable_variables

训练循环

您只需要磁带,每个目标一个。你也可以使用不同的优化器,如果它能使训练更好的话。

counter = 0
for x, y1, y2 in ds:
    counter += 1
    with tf.GradientTape() as tape1, tf.GradientTape() as tape2:
        pred1, pred2 = model(x)
        loss1 = loss_func1(y1, pred1)
        loss2 = loss_func2(y2, pred2)
    grad1 = tape1.gradient(loss1, var1)
    grad2 = tape2.gradient(loss2, var2)
    opt.apply_gradients(zip(grad1, var1))
    opt.apply_gradients(zip(grad2, var2))
    if counter % 10:
        print(f"Step : {counter}, objective1: {tf.reduce_mean(loss1)}, objective2: {tf.reduce_mean(loss2)}")

如果我们进行训练,我们会得到:

Step : 1, objective1: 4.609124183654785, objective2: 2.6634981632232666
[...]
Step : 99, objective1: 7.176481902227555e-14, objective2: 0.030187154188752174

这种方式训练的主要优势是您只需为两个目标提取一次特征。

【讨论】:

  • 这看起来不错。我仍在测试它,但我会确保在赏金期结束之前做出回应。
猜你喜欢
  • 2019-03-31
  • 2012-01-01
  • 2020-07-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-23
  • 2022-08-19
  • 1970-01-01
相关资源
最近更新 更多