在尝试学习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)
启动会话:
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)
拉出Z生成的值并将它们提供给D_new,这将重用D:
中的变量
resultB = sess.run(D_new, feed_dict={Z:Z_vals})
plot_values(resultB)
为了理智,我会描绘两者之间的差异,以确保它们是相同的......
现在运行1000个训练时期并绘制结果......
for i in range(1000):
_, resultA, Z_vals = sess.run([train_step, D, Z_gen], feed_dict={X:train_data})
plot_values(resultA)
现在让我们将相同的Z值提供给D_new并绘制这些结果......
resultB = sess.run(D_new, feed_dict={Z:Z_vals})
plot_values(resultB)
他们看起来非常相似。但是(我认为)它们应该完全相同。让我们看看差异......
plot_values(resultA - resultB)
你现在可以看到有一些变化。在更复杂的数据上使用更大的网络会变得更加戏剧化,但仍然会在这个简单的示例中显示出来。 关于发生了什么的任何线索?
答案 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))
使用reuse
和tf.variable_scope
时,不会考虑这一点。所以在技术上有些变量没有被重用。设置为0.0时为什么会出现这样的问题我不确定。