stylegan2-flax-tpu / training_steps.py
akhaliq's picture
akhaliq HF staff
add files
81170fd
import jax
import jax.numpy as jnp
import functools
def main_step_G(state_G, state_D, batch, z_latent1, z_latent2, metrics, mixing_prob, rng):
def loss_fn(params):
w_latent1, new_state_G = state_G.apply_mapping({'params': params['mapping'], 'moving_stats': state_G.moving_stats},
z_latent1,
batch['label'],
mutable=['moving_stats'])
w_latent2 = state_G.apply_mapping({'params': params['mapping'], 'moving_stats': state_G.moving_stats},
z_latent2,
batch['label'],
skip_w_avg_update=True)
# style mixing
cutoff_rng, layer_select_rng, synth_rng = jax.random.split(rng, num=3)
num_layers = w_latent1.shape[1]
layer_idx = jnp.arange(num_layers)[jnp.newaxis, :, jnp.newaxis]
mixing_cutoff = jax.lax.cond(jax.random.uniform(cutoff_rng, (), minval=0.0, maxval=1.0) < mixing_prob,
lambda _: jax.random.randint(layer_select_rng, (), 1, num_layers, dtype=jnp.int32),
lambda _: num_layers,
operand=None)
mixing_cond = jnp.broadcast_to(layer_idx < mixing_cutoff, w_latent1.shape)
w_latent = jnp.where(mixing_cond, w_latent1, w_latent2)
image_gen = state_G.apply_synthesis({'params': params['synthesis'], 'noise_consts': state_G.noise_consts},
w_latent,
rng=synth_rng)
fake_logits = state_D.apply_fn(state_D.params, image_gen, batch['label'])
loss = jnp.mean(jax.nn.softplus(-fake_logits))
return loss, (fake_logits, image_gen, new_state_G)
dynamic_scale = state_G.dynamic_scale_main
if dynamic_scale:
grad_fn = dynamic_scale.value_and_grad(loss_fn, has_aux=True, axis_name='batch')
dynamic_scale, is_fin, aux, grads = grad_fn(state_G.params)
else:
grad_fn = jax.value_and_grad(loss_fn, has_aux=True)
aux, grads = grad_fn(state_G.params)
grads = jax.lax.pmean(grads, axis_name='batch')
loss = aux[0]
_, image_gen, new_state = aux[1]
metrics['G_loss'] = loss
metrics['image_gen'] = image_gen
new_state_G = state_G.apply_gradients(grads=grads, moving_stats=new_state['moving_stats'])
if dynamic_scale:
new_state_G = new_state_G.replace(opt_state=jax.tree_multimap(functools.partial(jnp.where, is_fin),
new_state_G.opt_state,
state_G.opt_state),
params=jax.tree_multimap(functools.partial(jnp.where, is_fin),
new_state_G.params,
state_G.params))
metrics['G_scale'] = dynamic_scale.scale
return new_state_G, metrics
def regul_step_G(state_G, batch, z_latent, pl_noise, pl_mean, metrics, config, rng):
def loss_fn(params):
w_latent, new_state_G = state_G.apply_mapping({'params': params['mapping'], 'moving_stats': state_G.moving_stats},
z_latent,
batch['label'],
mutable=['moving_stats'])
pl_grads = jax.grad(lambda *args: jnp.sum(state_G.apply_synthesis(*args) * pl_noise), argnums=1)({'params': params['synthesis'],
'noise_consts': state_G.noise_consts},
w_latent,
'random',
rng)
pl_lengths = jnp.sqrt(jnp.mean(jnp.sum(jnp.square(pl_grads), axis=2), axis=1))
pl_mean_new = pl_mean + config.pl_decay * (jnp.mean(pl_lengths) - pl_mean)
pl_penalty = jnp.square(pl_lengths - pl_mean_new) * config.pl_weight
loss = jnp.mean(pl_penalty) * config.G_reg_interval
return loss, pl_mean_new
dynamic_scale = state_G.dynamic_scale_reg
if dynamic_scale:
grad_fn = dynamic_scale.value_and_grad(loss_fn, has_aux=True)
dynamic_scale, is_fin, aux, grads = grad_fn(state_G.params)
else:
grad_fn = jax.value_and_grad(loss_fn, has_aux=True)
aux, grads = grad_fn(state_G.params)
grads = jax.lax.pmean(grads, axis_name='batch')
loss = aux[0]
pl_mean_new = aux[1]
metrics['G_regul_loss'] = loss
new_state_G = state_G.apply_gradients(grads=grads)
if dynamic_scale:
new_state_G = new_state_G.replace(opt_state=jax.tree_multimap(functools.partial(jnp.where, is_fin),
new_state_G.opt_state,
state_G.opt_state),
params=jax.tree_multimap(functools.partial(jnp.where, is_fin),
new_state_G.params,
state_G.params))
metrics['G_regul_scale'] = dynamic_scale.scale
return new_state_G, metrics, pl_mean_new
def main_step_D(state_G, state_D, batch, z_latent1, z_latent2, metrics, mixing_prob, rng):
def loss_fn(params):
w_latent1 = state_G.apply_mapping({'params': state_G.params['mapping'], 'moving_stats': state_G.moving_stats},
z_latent1,
batch['label'],
train=False)
w_latent2 = state_G.apply_mapping({'params': state_G.params['mapping'], 'moving_stats': state_G.moving_stats},
z_latent2,
batch['label'],
train=False)
# style mixing
cutoff_rng, layer_select_rng, synth_rng = jax.random.split(rng, num=3)
num_layers = w_latent1.shape[1]
layer_idx = jnp.arange(num_layers)[jnp.newaxis, :, jnp.newaxis]
mixing_cutoff = jax.lax.cond(jax.random.uniform(cutoff_rng, (), minval=0.0, maxval=1.0) < mixing_prob,
lambda _: jax.random.randint(layer_select_rng, (), 1, num_layers, dtype=jnp.int32),
lambda _: num_layers,
operand=None)
mixing_cond = jnp.broadcast_to(layer_idx < mixing_cutoff, w_latent1.shape)
w_latent = jnp.where(mixing_cond, w_latent1, w_latent2)
image_gen = state_G.apply_synthesis({'params': state_G.params['synthesis'], 'noise_consts': state_G.noise_consts},
w_latent,
rng=synth_rng)
fake_logits = state_D.apply_fn(params, image_gen, batch['label'])
real_logits = state_D.apply_fn(params, batch['image'], batch['label'])
loss_fake = jax.nn.softplus(fake_logits)
loss_real = jax.nn.softplus(-real_logits)
loss = jnp.mean(loss_fake + loss_real)
return loss, (fake_logits, real_logits)
dynamic_scale = state_D.dynamic_scale_main
if dynamic_scale:
grad_fn = dynamic_scale.value_and_grad(loss_fn, has_aux=True)
dynamic_scale, is_fin, aux, grads = grad_fn(state_D.params)
else:
grad_fn = jax.value_and_grad(loss_fn, has_aux=True)
aux, grads = grad_fn(state_D.params)
grads = jax.lax.pmean(grads, axis_name='batch')
loss = aux[0]
fake_logits, real_logits = aux[1]
metrics['D_loss'] = loss
metrics['fake_logits'] = jnp.mean(fake_logits)
metrics['real_logits'] = jnp.mean(real_logits)
new_state_D = state_D.apply_gradients(grads=grads)
if dynamic_scale:
new_state_D = new_state_D.replace(opt_state=jax.tree_multimap(functools.partial(jnp.where, is_fin),
new_state_D.opt_state,
state_D.opt_state),
params=jax.tree_multimap(functools.partial(jnp.where, is_fin),
new_state_D.params,
state_D.params))
metrics['D_scale'] = dynamic_scale.scale
return new_state_D, metrics
def regul_step_D(state_D, batch, metrics, config):
def loss_fn(params):
r1_grads = jax.grad(lambda *args: jnp.sum(state_D.apply_fn(*args)), argnums=1)(params, batch['image'], batch['label'])
r1_penalty = jnp.sum(jnp.square(r1_grads), axis=(1, 2, 3)) * (config.r1_gamma / 2) * config.D_reg_interval
loss = jnp.mean(r1_penalty)
return loss, None
dynamic_scale = state_D.dynamic_scale_reg
if dynamic_scale:
grad_fn = dynamic_scale.value_and_grad(loss_fn, has_aux=True)
dynamic_scale, is_fin, aux, grads = grad_fn(state_D.params)
else:
grad_fn = jax.value_and_grad(loss_fn, has_aux=True)
aux, grads = grad_fn(state_D.params)
grads = jax.lax.pmean(grads, axis_name='batch')
loss = aux[0]
metrics['D_regul_loss'] = loss
new_state_D = state_D.apply_gradients(grads=grads)
if dynamic_scale:
new_state_D = new_state_D.replace(opt_state=jax.tree_multimap(functools.partial(jnp.where, is_fin),
new_state_D.opt_state,
state_D.opt_state),
params=jax.tree_multimap(functools.partial(jnp.where, is_fin),
new_state_D.params,
state_D.params))
metrics['D_regul_scale'] = dynamic_scale.scale
return new_state_D, metrics
def eval_step_G(generator, params, z_latent, labels, truncation):
image_gen = generator.apply(params, z_latent, labels, truncation_psi=truncation, train=False, noise_mode='const')
return image_gen