代码如下,简单来说就是计算生成器生成的图像对其latent vector的梯度(Jacobian矩阵),
∣
∣
J
w
T
y
∣
∣
2
||J_w^Ty||_2
∣∣JwTy∣∣2就是代码中的pl_lengths,
a
a
a为pl_mean_var的移动平均: pl_mean_var= pl_mean_var + 0.01 * (
m
e
a
n
mean
mean(pl_lengths) - pl_mean_var)。
这种方法"dramatically facilitates projecting images back into the latent space"(让图像得到更加线性的对应latent vector)。
#----------------------------------------------------------------------------# Non-saturating logistic loss with path length regularizer from the paper# "Analyzing and Improving the Image Quality of StyleGAN", Karras et al. 2019defG_logistic_ns_pathreg(G, D, opt, training_set, minibatch_size, pl_minibatch_shrink=2, pl_decay=0.01, pl_weight=2.0):
_ = opt
latents = tf.random_normal([minibatch_size]+ G.input_shapes[0][1:])
labels = training_set.get_random_labels_tf(minibatch_size)
fake_images_out, fake_dlatents_out = G.get_output_for(latents, labels, is_training=True, return_dlatents=True)
fake_scores_out = D.get_output_for(fake_images_out, labels, is_training=True)
loss = tf.nn.softplus(-fake_scores_out)# -log(sigmoid(fake_scores_out))# Path length regularization.with tf.name_scope('PathReg'):# Evaluate the regularization term using a smaller minibatch to conserve memory.if pl_minibatch_shrink >1:
pl_minibatch = minibatch_size // pl_minibatch_shrink
pl_latents = tf.random_normal([pl_minibatch]+ G.input_shapes[0][1:])
pl_labels = training_set.get_random_labels_tf(pl_minibatch)
fake_images_out, fake_dlatents_out = G.get_output_for(pl_latents, pl_labels, is_training=True, return_dlatents=True)# Compute |J*y|.
pl_noise = tf.random_normal(tf.shape(fake_images_out))/ np.sqrt(np.prod(G.output_shape[2:]))
pl_grads = tf.gradients(tf.reduce_sum(fake_images_out * pl_noise),[fake_dlatents_out])[0]
pl_lengths = tf.sqrt(tf.reduce_mean(tf.reduce_sum(tf.square(pl_grads), axis=2), axis=1))
pl_lengths = autosummary('Loss/pl_lengths', pl_lengths)# Track exponential moving average of |J*y|.with tf.control_dependencies(None):
pl_mean_var = tf.Variable(name='pl_mean', trainable=False, initial_value=0.0, dtype=tf.float32)
pl_mean = pl_mean_var + pl_decay *(tf.reduce_mean(pl_lengths)- pl_mean_var)
pl_update = tf.assign(pl_mean_var, pl_mean)# Calculate (|J*y|-a)^2.with tf.control_dependencies([pl_update]):
pl_penalty = tf.square(pl_lengths - pl_mean)
pl_penalty = autosummary('Loss/pl_penalty', pl_penalty)# Apply weight.## Note: The division in pl_noise decreases the weight by num_pixels, and the reduce_mean# in pl_lengths decreases it by num_affine_layers. The effective weight then becomes:## gamma_pl = pl_weight / num_pixels / num_affine_layers# = 2 / (r^2) / (log2(r) * 2 - 2)# = 1 / (r^2 * (log2(r) - 1))# = ln(2) / (r^2 * (ln(r) - ln(2))#
reg = pl_penalty * pl_weight
return loss, reg
#----------------------------------------------------------------------------