styleGAN ver1 vs. styleGAN ver2

styleGAN

styleGAN2

 

<주요 특징>

styleGAN : mapping network, AdaIN, Noise

styleGAN2 : AdaIN 연산 수정, progressive 대신에 G output skips, D residual nets

 

styleGAN 의 mapping network는 networks_stylegan.py의 G_style 함수로, synthesis network는 G_synthesis 함수로 정의된다 (보다 정확히 말하자면, Style-based generator는 G_mapping과 G_synthesis라는 두 서브 네트워크로 이루어진다.)

 

G_synthesis에서 이미지를 합성하는 부분(해상도 2x 하며 images_out 업데이트)은 PGGAN과 거의 동일하다.

  • Early layers ( 4 * 4 해상도 )
    • 합성 네트워크로 바로 입력되는 상수 벡터라면 곧바로 layer_epilogue 함수로 들어가서 노이즈 추가, bias, 활성화함수, pixel/instance 정규화, AdaIN 적용
    • 잠재코드 w 라면, dense 통과 후 layer_epilogue 함수로 들어가서 노이즈 추가, bias, 활성화함수, pixel/instance 정규화, AdaIN 적용
    • 그 다음 conv 레이어를 통과하고, layer_epilogue로 다시 들어간다 .. 노이즈 추가, bias, 활성화함수, pixel/instance 정규화, AdaIN 적용
    # Early layers.
    with tf.variable_scope('4x4'):
        if const_input_layer:
            with tf.variable_scope('Const'):
                x = tf.get_variable('const', shape=[1, nf(1), 4, 4], initializer=tf.initializers.ones())
                x = layer_epilogue(tf.tile(tf.cast(x, dtype), [tf.shape(dlatents_in)[0], 1, 1, 1]), 0)
        else:
            with tf.variable_scope('Dense'):
                x = dense(dlatents_in[:, 0], fmaps=nf(1)*16, gain=gain/4, use_wscale=use_wscale) # tweak gain to match the official implementation of Progressing GAN
                x = layer_epilogue(tf.reshape(x, [-1, nf(1), 4, 4]), 0)
        with tf.variable_scope('Conv'):
            x = layer_epilogue(conv2d(x, fmaps=nf(1), kernel=3, gain=gain, use_wscale=use_wscale), 1)

####################################################################################################################################################################

    # Linear structure: simple but inefficient.
    if structure == 'linear':
        images_out = torgb(2, x)
        for res in range(3, resolution_log2 + 1):
            lod = resolution_log2 - res
            x = block(res, x)
            img = torgb(res, x)
            images_out = upscale2d(images_out)
            with tf.variable_scope('Grow_lod%d' % lod):
                images_out = tflib.lerp_clip(img, images_out, lod_in - lod)

layer_epilogue: noise 적용, instance normalization, Style modulation

*해상도마다 block 함수를 통과하므로 해상도 레이어마다 noise, style modulation 적용됨

style modulation = AdaIN !!!

Ys, Yb 주목 ..

content input인 x와 style input인 y를 평균과 분산으로 정규화

dense를 통과해서 나온 style 에 ys, yb 가 있음

def style_mod(x, dlatent, **kwargs):
    with tf.variable_scope('StyleMod'):
        style = apply_bias(dense(dlatent, fmaps=x.shape[1]*2, gain=1, **kwargs))
        style = tf.reshape(style, [-1, 2, x.shape[1]] + [1] * (len(x.shape) - 2))
        return x * (style[:,0] + 1) + style[:,1]

 

(코세라) AdaIN은 각 conv 레이어 다음에 있고, dlatent w도 AdaIN으로 들어간다.
step1. Instance Normalization : batch 단위로 정규화하지 않고 instance 단위로 정규화.
step2. apply adaptive styles : dlatent w는 학습된 dense 레이어를 통과해 ys(scale), yb(bias)로 나온다. 이 statistics가 AdaIN layers에 적용된다. ys는 rescale 하고, yb는 reshift 함.
→ instance씩 0~1 사이로 정규화된 값을 스케일링하고 shift 하기 = content에 style 적용하기

 

G_mapping

    # Normalize latents.
    if normalize_latents:
        x = pixel_norm(x)

    # Mapping layers.
    for layer_idx in range(mapping_layers):
        with tf.variable_scope('Dense%d' % layer_idx):
            fmaps = dlatent_size if layer_idx == mapping_layers - 1 else mapping_fmaps
            x = dense(x, fmaps=fmaps, gain=gain, use_wscale=use_wscale, lrmul=mapping_lrmul)
            x = apply_bias(x, lrmul=mapping_lrmul)
            x = act(x)

Latent vectors Z를 pixel normalization하고, 8개의 mapping layer로 이루어진 MLP 를 통과한다.

 

G_style 아래 서브 네트워크인 G_mapping과 G_synthesis 를 세팅하는 부분

# Setup components.
    if 'synthesis' not in components:
        components.synthesis = tflib.Network('G_synthesis', func_name=G_synthesis, **kwargs)
    num_layers = components.synthesis.input_shape[1]
    dlatent_size = components.synthesis.input_shape[2]
    if 'mapping' not in components:
        components.mapping = tflib.Network('G_mapping', func_name=G_mapping, dlatent_broadcast=num_layers, **kwargs)

 

G_mapping → G_synthesis

 

  1. latents_in (z) 가 mapping 네트워크를 통과해 disentangled latents (w) 로 나온다
    dlatents = components.mapping.get_output_for(latents_in, labels_in, **kwargs)
 

2. dlatent_avg_beta만큼 (이동평균을 구할 때 오래된 데이터의 영향을 감쇠시키는 정도), 이동평균 업데이트. style_mixing_prob만큼 mixing regularization. truncation_psi 만큼 truncation trick.

    # Update moving average of W.
    if dlatent_avg_beta is not None:
        with tf.variable_scope('DlatentAvg'):
            batch_avg = tf.reduce_mean(dlatents[:, 0], axis=0)
            update_op = tf.assign(dlatent_avg, tflib.lerp(batch_avg, dlatent_avg, dlatent_avg_beta))
            with tf.control_dependencies([update_op]):
                dlatents = tf.identity(dlatents)
    
    if style_mixing_prob is not None:
        with tf.name_scope('StyleMix'):
            latents2 = tf.random_normal(tf.shape(latents_in))
            dlatents2 = components.mapping.get_output_for(latents2, labels_in, **kwargs)
            layer_idx = np.arange(num_layers)[np.newaxis, :, np.newaxis]
            cur_layers = num_layers - tf.cast(lod_in, tf.int32) * 2
            mixing_cutoff = tf.cond(
                tf.random_uniform([], 0.0, 1.0) < style_mixing_prob,
                lambda: tf.random_uniform([], 1, cur_layers, dtype=tf.int32),
                lambda: cur_layers)
            dlatents = tf.where(tf.broadcast_to(layer_idx < mixing_cutoff, tf.shape(dlatents)), dlatents, dlatents2)    
            
    # Apply truncation trick.
    if truncation_psi is not None and truncation_cutoff is not None:
        with tf.variable_scope('Truncation'):
            layer_idx = np.arange(num_layers)[np.newaxis, :, np.newaxis]
            ones = np.ones(layer_idx.shape, dtype=np.float32)
            coefs = tf.where(layer_idx < truncation_cutoff, truncation_psi * ones, ones)
            dlatents = tflib.lerp(dlatent_avg, dlatents, coefs)

3. 잠재코드 dlatents를 G_synthesis에 입력해 이미지를 생성한다

    # Evaluate synthesis network.
    with tf.control_dependencies([tf.assign(components.synthesis.find_var('lod'), lod_in)]):
        images_out = components.synthesis.get_output_for(dlatents, force_clean_graph=is_template_graph, **kwargs)
    return tf.identity(images_out, name='images_out')

'인공지능 > computer vision' 카테고리의 다른 글

styleGAN3 이해하기  (0) 2022.08.01
styleGAN2 이해하기  (0) 2022.05.31
styleGAN 이해하기  (0) 2022.05.31
PGGAN의 공식 코드 살펴보기  (0) 2022.05.31
PGGAN 이해하기  (0) 2022.05.31
복사했습니다!