TensorFlow 实现

我们现在拥有了使用 TensorFlow 实现稀疏自编码器所需的全部功能:

  1. def kl_divergence(p, q):
  2. return p * tf.log(p / q) + (1 - p) * tf.log((1 - p) / (1 - q))
  3. learning_rate = 0.01
  4. sparsity_target = 0.1
  5. sparsity_weight = 0.2
  6. [...] # Build a normal autoencoder (in this example the coding layer is hidden1)
  7. optimizer = tf.train.AdamOptimizer(learning_rate)
  8. hidden1_mean = tf.reduce_mean(hidden1, axis=0) # batch mean
  9. sparsity_loss = tf.reduce_sum(kl_divergence(sparsity_target, hidden1_mean))
  10. reconstruction_loss = tf.reduce_mean(tf.square(outputs - X)) # MSE
  11. loss = reconstruction_loss + sparsity_weight * sparsity_loss
  12. training_op = optimizer.minimize(loss)

一个重要的细节是编码层的激活必须介于 0 和 1 之间(但不等于 0 或 1),否则 KL 散度将返回NaN(非数字)。 一个简单的解决方案是对编码层使用逻辑激活功能:

  1. hidden1 = tf.nn.sigmoid(tf.matmul(X, weights1) + biases1)

一个简单的技巧可以加速收敛:不是使用 MSE,我们可以选择一个具有较大梯度的重建损失。 交叉熵通常是一个不错的选择。 要使用它,我们必须对输入进行规范化处理,使它们的取值范围为 0 到 1,并在输出层中使用逻辑激活函数,以便输出也取值为 0 到 1。TensorFlow 的sigmoid_cross_entropy_with_logits()函数负责 有效地将 logistic(sigmoid)激活函数应用于输出并计算交叉熵:

  1. [...]
  2. logits = tf.matmul(hidden1, weights2) + biases2)
  3. outputs = tf.nn.sigmoid(logits)
  4. reconstruction_loss = tf.reduce_sum(
  5. tf.nn.sigmoid_cross_entropy_with_logits(labels=X, logits=logits))

请注意,训练期间不需要输出操作(我们仅在我们想要查看重建时才使用它)。