Tensorflow重用变量在训练之前和之后不同

时间:2016-11-22 20:59:58

标签: python python-3.x tensorflow

在尝试学习Tensorflow时,我一直在构建一个可变的自动编码器,但是我注意到,在训练之后,我得到了来自共享相同变量的解码器的不同结果。

我创建了两个解码器,因为第一个我训练我的数据集,第二个我想最终提供一个新的Z编码,以产生新的值。

我的检查是,我应该能够将编码过程中生成的Z值发送到两个解码器并获得相同的结果。

我有2个解码器(D,D_new)。 D_new与D共享变量范围。

在训练之前,我可以将值发送到编码器(E)中以生成输出值以及它生成的Z值(Z_gen)。

如果我在训练之前使用Z_gen作为D_new的输入,那么它的输出与D的输出相同,这是预期的。

然而,经过几次训练后,D与D_new相比的输出开始发散(尽管它们非常相似)。

我已经将它与我的代码的更简单版本配对,仍然会重现错误。我想知道其他人是否已经发现了这种情况,以及我可能能够纠正它。

以下代码可以在jupyter笔记本中运行。我正在使用Tensorflow r0.11和Python 3.5.0



    import numpy as np
    import tensorflow as tf
    import matplotlib
    import matplotlib.pyplot as plt
    import os
    import pylab as pl
    mgc = get_ipython().magic
    mgc(u'matplotlib inline')
    pl.rcParams['figure.figsize'] = (8.0, 5.0)



    ##-- Helper function Just for visualizing the data
    def plot_values(values, file=None):
        t = np.linspace(1.0,len(values[0]),len(values[0]))
        for i in range(len(values)):
            plt.plot(t,values[i])
        if file is None:
            plt.show()
        else:
            plt.savefig(file)
        plt.close()



    def encoder(input, n_hidden, n_z):
        with tf.variable_scope("ENCODER"):
            with tf.name_scope("Hidden"):
                n_layer_inputs = input.get_shape()[1].value
                n_layer_outputs = n_hidden
                with tf.name_scope("Weights"):
                    w = tf.get_variable(name="E_Hidden", shape=[n_layer_inputs, n_layer_outputs], dtype=tf.float32)
                with tf.name_scope("Activation"):
                    a = tf.tanh(tf.matmul(input,w))
                prevLayer = a

            with tf.name_scope("Z"):
                n_layer_inputs = prevLayer.get_shape()[1].value
                n_layer_outputs = n_z
                with tf.name_scope("Weights"):
                    w = tf.get_variable(name="E_Z", shape=[n_layer_inputs, n_layer_outputs], dtype=tf.float32)
                with tf.name_scope("Activation"):
                    Z_gen = tf.matmul(prevLayer,w)
        return Z_gen

    def decoder(input, n_hidden, n_outputs, reuse=False):
        with tf.variable_scope("DECODER", reuse=reuse):
            with tf.name_scope("Hidden"):
                n_layer_inputs = input.get_shape()[1].value
                n_layer_outputs = n_hidden
                with tf.name_scope("Weights"):
                    w = tf.get_variable(name="D_Hidden", shape=[n_layer_inputs, n_layer_outputs], dtype=tf.float32)
                with tf.name_scope("Activation"):
                    a = tf.tanh(tf.matmul(input,w))
                prevLayer = a

            with tf.name_scope("OUTPUT"):
                n_layer_inputs = prevLayer.get_shape()[1].value
                n_layer_outputs = n_outputs
                with tf.name_scope("Weights"):
                    w = tf.get_variable(name="D_Output", shape=[n_layer_inputs, n_layer_outputs], dtype=tf.float32)
                with tf.name_scope("Activation"):
                    out = tf.sigmoid(tf.matmul(prevLayer,w))
        return out

以下是设置Tensorflow图的地方:



    batch_size = 3
    n_inputs = 100
    n_hidden_nodes = 12
    n_z = 2

    with tf.variable_scope("INPUT_VARS"):
        with tf.name_scope("X"):
            X = tf.placeholder(tf.float32, shape=(None, n_inputs))
        with tf.name_scope("Z"):
            Z = tf.placeholder(tf.float32, shape=(None, n_z))

    Z_gen = encoder(X,n_hidden_nodes,n_z)

    D = decoder(Z_gen, n_hidden_nodes, n_inputs)
    D_new = decoder(Z, n_hidden_nodes, n_inputs, reuse=True)

    with tf.name_scope("COST"):
        loss = -tf.reduce_mean(X * tf.log(1e-6 + D) + (1-X) * tf.log(1e-6 + 1 - D))
        train_step = tf.train.AdamOptimizer(0.001, beta1=0.5).minimize(loss)

我正在生成一组3个正态分布噪声样本的训练集,包含100个数据点,然后对其进行排序,以便更容易想象:



    train_data = (np.random.normal(0,1,(batch_size,n_inputs)) + 3) / 6.0
    train_data.sort()
    plot_values(train_data)

enter image description here

启动会话:



    sess = tf.InteractiveSession()
    sess.run(tf.group(tf.initialize_all_variables(), tf.initialize_local_variables()))

让我们看看网络在培训之前最初生成的内容......



    resultA, Z_vals = sess.run([D, Z_gen], feed_dict={X:train_data})
    plot_values(resultA)

enter image description here

拉出Z生成的值并将它们提供给D_new,这将重用D:

中的变量


    resultB = sess.run(D_new, feed_dict={Z:Z_vals})
    plot_values(resultB)

enter image description here

为了理智,我会描绘两者之间的差异,以确保它们是相同的...... enter image description here

现在运行1000个训练时期并绘制结果......



    for i in range(1000):
        _, resultA, Z_vals = sess.run([train_step, D, Z_gen], feed_dict={X:train_data})
    plot_values(resultA)

enter image description here

现在让我们将相同的Z值提供给D_new并绘制这些结果......



    resultB = sess.run(D_new, feed_dict={Z:Z_vals})
    plot_values(resultB)

enter image description here

他们看起来非常相似。但是(我认为)它们应该完全相同。让我们看看差异......



    plot_values(resultA - resultB)

enter image description here

你现在可以看到有一些变化。在更复杂的数据上使用更大的网络会变得更加戏剧化,但仍然会在这个简单的示例中显示出来。 关于发生了什么的任何线索?

2 个答案:

答案 0 :(得分:0)

有一些方法(不知道哪一个具体)可以提供种子值。除此之外,我甚至不确定训练过程是否完全确定,特别是在GPU is involved时,仅仅是因为并行化的性质。

请参阅this question

答案 1 :(得分:0)

虽然我没有完整解释原因,但我可以通过更改来解决我的问题:

for i in range(1000):
    _, resultA, Z_vals = sess.run([train_step, D, Z_gen], feed_dict={X:train_data})
plot_values(resultA)

resultB = sess.run(D_new, feed_dict={Z:Z_vals})
plot_values(resultB)
plot_values(resultA - resultB)

为...

for i in range(1000):
    _, resultA, Z_vals = sess.run([train_step, D, Z_gen], feed_dict={X:train_data})

resultA, Z_vals = sess.run([D, Z_gen], feed_dict={X:train_data})

plot_values(resultA)

resultB = sess.run(D_new, feed_dict={Z:Z_vals})
plot_values(resultB)
plot_values(resultA - resultB)

注意,我最后一次只运行并提取结果和Z_vals,没有train_step

我在更复杂的设置中仍然遇到问题的原因是我有使用...生成的偏差变量(即使它们被设置为0.0)

b = tf.Variable(tf.constant(self.bias_k, shape=[n_layer_outputs], dtype=tf.float32))

使用reusetf.variable_scope时,不会考虑这一点。所以在技术上有些变量没有被重用。设置为0.0时为什么会出现这样的问题我不确定。