张量流模型不更新权重

Posted

技术标签:

【中文标题】张量流模型不更新权重【英文标题】:tensorflow model not updating weights 【发布时间】:2019-05-08 22:02:45 【问题描述】:

我有一个正在训练的模型(它经过步骤和时期并评估损失),但权重没有训练。

我试图训练一个鉴别器来区分图像是合成的还是真实的。它是 GAN 模型的一部分,我正在尝试构建。

基本结构如下:

我有两个输入: 1. 图像(可以是真实的或合成的) 2. 标签(0 表示真实,1 表示合成)

Source Estimator 是我从图像中提取特征的地方。我已经训练了模型并恢复了权重和偏差。这些层被冻结(不可训练)。

def SourceEstimator(eye, name, trainable = True):
  # source estimator and target representer shares the same structure.
  # SE is not trainable, while TR is.
  net = tf.layers.conv2d(eye, 32, 3, (1,1), padding='same', activation=tf.nn.leaky_relu, trainable=trainable, name=name+'_conv2d_1')
  net = tf.layers.conv2d(net, 32, 3, (1,1), padding='same', activation=tf.nn.leaky_relu, trainable=trainable, name=name+'_conv2d_2')
  net = tf.layers.conv2d(net, 64, 3, (1,1), padding='same', activation=tf.nn.leaky_relu, trainable=trainable, name=name+'_conv2d_3')
  c3 = net
  net = tf.layers.max_pooling2d(net, 3, (2,2), padding='same', name=name+'_maxpool_4')
  net = tf.layers.conv2d(net, 80, 3, (1,1), padding='same', activation=tf.nn.leaky_relu, trainable=trainable, name=name+'_conv2d_5')
  net = tf.layers.conv2d(net, 192, 3, (1,1), padding='same', activation=tf.nn.leaky_relu, trainable=trainable, name=name+'_conv2d_6')
  c5 = net
  return (c3, c5)

判别器如下:

def DiscriminatorModel(features, reuse=False):
  with tf.variable_scope('discriminator', reuse=tf.AUTO_REUSE):
    net = tf.layers.conv2d(features, 64, 3, 2, padding='same', kernel_initializer='truncated_normal', activation=tf.nn.leaky_relu, trainable=True, name='discriminator_c1')
    net = tf.layers.conv2d(net, 128, 3, 2, padding='same', kernel_initializer='truncated_normal', activation=tf.nn.leaky_relu, trainable=True, name='discriminator_c2')
    net = tf.layers.conv2d(net, 256, 3, 2, padding='same', kernel_initializer='truncated_normal', activation=tf.nn.leaky_relu, trainable=True, name='discriminator_c3')

    net = tf.contrib.layers.flatten(net)
    net = tf.layers.dense(net, units=1, activation=tf.nn.softmax, name='descriminator_out', trainable=True)
    return net

输入进入 SourceEstimator 模型并提取特征 (c3,c5)。

然后将 c3 和 c5 沿通道轴连接并传递给判别器模型。

c3, c5 = CommonModel(self.left_eye, 'el', trainable=False)
c5 = tf.image.resize_images(c5, size=(self.config.img_size,self.config.img_size))
features = tf.concat([c3, c5], axis=3)
##---------------------------------------- DISCRIMINATOR ------------------------------------------##
with tf.variable_scope('discriminator'):
    logit = DiscriminatorModel(features)

最终损失和训练操作

##---------------------------------------- LOSSES ------------------------------------------##
with tf.variable_scope("discriminator_losses"):
  self.loss = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits=logit, labels=self.label))

##---------------------------------------- TRAIN ------------------------------------------##
# optimizers
update_ops = tf.get_collection(tf.GraphKeys.UPDATE_OPS)
with tf.control_dependencies(update_ops):
    disc_optimizer = tf.train.AdamOptimizer(learning_rate = learning_rate)
    self.disc_op = disc_optimizer.minimize(self.loss, global_step=self.global_step_tensor, name='disc_op')

训练步骤和时期。我正在使用 32 批量大小。和数据生成器类来获取每一步的图像。

def train_epoch(self):
    num_iter_per_epoch = self.train_data.get_size() // self.config.get('batch_size')
    loop = tqdm(range(num_iter_per_epoch))
    for i in loop:
        dloss = self.train_step(i)
        loop.set_postfix(loss=':05.3f'.format(dloss))

def train_step(self, i):
    el, label = self.train_data.get_batch(i)

    ## ------------------- train discriminator -------------------##
    feed_dict = 
            self.model.left_eye: el,
            self.model.label: label
    
    _, dloss = self.sess.run([self.model.disc_op, self.model.loss], feed_dict=feed_dict)
    return dloss

当模型经历步骤和时期时,权重保持不变。

损失在训练步骤中波动,但每个时期的损失是相同的。例如,如果我不在每个 epoch 打乱数据集,则图上的 loss 将在每个 epoch 遵循相同的模式。

我认为这意味着模型识别了不同的损失,但没有根据损失更新参数。

以下是我尝试过但没有帮助的其他几件事:

    尝试了大大小小的学习率(0.1 和 1e-8) 已尝试使用 SourceEstimator 层 trainable==True 翻转标签(0 == 合成,1 == 真实) 增加了鉴别器中的内核大小和过滤器大小。

我已经被这个问题困扰了一段时间,我真的需要一些见解。提前致谢。

-----编辑1-----

def initialize_uninitialized(sess):
    global_vars = tf.global_variables()
    is_initialized= sess.run([tf.is_variable_initialized(var) for var in global_vars])
    not_initialized_vars = [v for (v, f) in zip(global_vars, is_initialized) if not f]

    # for var in not_initialized_vars: # only for testing
    #    print(var.name)

    if len(not_initialized_vars):
        sess.run(tf.variables_initializer(not_initialized_vars))

self.sess = tf.Session()
## inbetween here I create data generator, model and restore pretrained model.
self.initilize_uninitialized(self.sess) 

for current_epoch in range(self.model.current_epoch_tensor.eval(self.sess), self.config.num_epochs, 1)
    self.train_epoch() # included above
    self.sess.run(self.model.increment_current_epoch_tensor)

【问题讨论】:

【参考方案1】:

我从未设法找出代码有什么问题。

我的同事建议在不同的隔离环境中尝试相同的模型,因此我使用 Keras 库重写了代码。

现在它开始工作了。 :/

我们仍然不知道上面的代码到底出了什么问题——我没有做任何改变。我什至使用相同的代码进行权重传递和变量初始化。

如果有人遇到过类似的问题,我建议在不同的环境中尝试相同的模型。

或者如果有人知道上面的代码有什么问题,请分享!

【讨论】:

您检查过两种环境之间的区别吗? Python、tensorflow的版本以及是否在anaconda下使用以及anaconda的哪个版本? 我必须检查我使用的 python、tensorflow 和 keras 的确切版本,但我确实使用了相同的虚拟环境。 python==3.6.6 / tensorflow==1.10.0 / keras==2.2.4【参考方案2】:

我可以看到您在 session.run() 中调用了最小化和损失函数。您应该只调用 minimize() 函数。即只有 self.model.disc_op 会在内部调用损失函数。 另外,我在任何地方都看不到您的会话初始化调用。确保它只被调用一次。

查看您更新的代码,我可以看到您将 tf.is_variable_initialized() 调用等同于 is_not_initialized。因此,它正在初始化那些已经初始化的变量。

【讨论】:

你说得对,我没有包括会话初始化。因为部分模型是从预训练模型中恢复的。我必须创建自定义初始化函数来仅初始化未初始化的变量。不想被不必要的代码淹没。我还尝试了您仅调用最小化函数的建议。不幸的是没有帮助。我在每个时期都调用损失函数来进行简单的评估,我认为这不是问题:( 在帖子中包含会话初始化! 查看您更新的代码,我可以看到您将 tf.is_variable_initialized() 调用等同于 is_not_initialized。因此,它正在初始化那些已经初始化的变量。 谢谢,我应该解决这个问题,那是糟糕的命名。但是,在下一行中,当得到 not_initialized_vars 时,它已经被补偿了。 not_initialized_vars = [v for (v, f) in zip(global_vars, is_not_initialized) if not f] 您能否也包含获取 logits 的代码?

以上是关于张量流模型不更新权重的主要内容,如果未能解决你的问题,请参考以下文章

如何在张量流中创建集成?

带有张量流的拥抱脸转换器将两个文件保存为模型权重

将张量流权重导出到 hdf5 文件和模型到 keras model.json

张量流不训练(只有偏差改变)

tf2.0 Keras:使用 RNN 的自定义张量流代码时无法保存权重

仅使用线性代数执行训练的张量流模型