개요

Zookiz 캐릭터 이미지를 이용해 styleGAN 모델을 학습시켰다. 선, 색감, 표정 등 Zookiz 캐릭터의 표현방식을 모델이 (얼마나) 잘 학습할 수 있는지 살펴봤다. 구글 Colab GPU를 사용하여 효율적인 학습은 어려웠다.

 

 

전처리

# resize images
def resize_image(src_img, size=(64,64), bg_color="white"): 
    src_img.thumbnail(size, PIL.Image.ANTIALIAS)
    new_image = PIL.Image.new("RGB", size, bg_color)
    new_image.paste(src_img, (int((size[0] - src_img.size[0]) / 2), int((size[1] - src_img.size[1]) / 2)))
    return new_image

test_folder = '/content/drive/MyDrive/zookiz_dataset'
test_image_files = os.listdir(test_folder)

image_arrays = []
size = (256, 256)
background_color="white"

for file_idx in range(len(test_image_files)):
    img = PIL.Image.open(os.path.join(test_folder, test_image_files[file_idx]))
    resized_img = np.array(resize_image(img, size, background_color))
    image_arrays.append(resized_img)

 

초상화 styleGAN

모델

styleGAN art

stylegan-art/styleganportraits.ipynb at master · ak9250/stylegan-art

 

 

시행착오

InvalidArgumentError: 2 root error(s) found.
  (0) Invalid argument: Input to reshape is a tensor with 16384 values, but the requested shape requires a multiple of 32768
	 [[{{node GPU0/D_loss/D/4x4/MinibatchStddev/Reshape}}]]
	 [[TrainD/ApplyGrads0/UpdateWeights/cond/pred_id/_2051]]
  (1) Invalid argument: Input to reshape is a tensor with 16384 values, but the requested shape requires a multiple of 32768
	 [[{{node GPU0/D_loss/D/4x4/MinibatchStddev/Reshape}}]]
0 successful operations.
0 derived errors ignored.

During handling of the above exception, another exception occurred:

InvalidArgumentError                      Traceback (most recent call last)
/tensorflow-1.15.2/python3.7/tensorflow_core/python/client/session.py in _do_call(self, fn, *args)
   1382                     '\nsession_config.graph_options.rewrite_options.'
   1383                     'disable_meta_optimizer = True')
-> 1384       raise type(e)(node_def, op, message)
   1385 
   1386   def _extend_graph(self):

InvalidArgumentError: 2 root error(s) found.
  (0) Invalid argument: Input to reshape is a tensor with 16384 values, but the requested shape requires a multiple of 32768
	 [[node GPU0/D_loss/D/4x4/MinibatchStddev/Reshape (defined at /tensorflow-1.15.2/python3.7/tensorflow_core/python/framework/ops.py:1748) ]]
	 [[TrainD/ApplyGrads0/UpdateWeights/cond/pred_id/_2051]]
  (1) Invalid argument: Input to reshape is a tensor with 16384 values, but the requested shape requires a multiple of 32768
	 [[node GPU0/D_loss/D/4x4/MinibatchStddev/Reshape (defined at /tensorflow-1.15.2/python3.7/tensorflow_core/python/framework/ops.py:1748) ]]
0 successful operations.
0 derived errors ignored.

 

(2) total_kimg를 잘못 설정한 것도 문제였다. 학습은 while cur_nimg < total_kimg * 1000: 아래서 반복되는데, total_kimg를 충분히 크게 설정하지 않으면 학습이 실행되지 않고 종료된다.

처음 cur_nimg는 resume_kimg * 1000로 시작해 Discriminator가 학습할 때마다 minibatch만큼 값이 추가된다. 사전학습된 모델의 resume_kimg = 11125 이므로, total_kimg가 11125보다 작게 세팅되면 학습 loop가 아예 돌지 않는다. 처음 total_kimg를 단순 데이터 개수로 오인해 작은 값을 입력한 것이 문제였다.

total_kimg 의 의미는 “Total length of the training, measured in thousands of real images”로 이미지를 1000(1k)개 단위로 계산해 학습 횟수를 설정하겠다는 것이다.

 

(3) 또다른 가능성은 should_stop() 함수다. 학습 loop 바로 아래 if ctx.should_stop(): break 조건문이 있다. 이 조건문에서 ctx(학습 loop를 관리하는 RunContext 클래스의 helper object)가 학습할 때마다 while문을 종료할지 체크한다. ctx.should_stop()은 실행 폴더에 abort.txt가 존재할 때 True를 반환한다.

abort.txt가 어떤 시점에 생성되는지는 모르겠지만, 세션을 초기화하지 않고 곧바로 메인 학습 코드를 다시 돌렸을 때 ctx.should_stop()가 이전 학습 과정에서 생성된 abort.txt를 인지했을 가능성이 있다.

 

포켓몬 styleGAN

초기 세팅

아예 다른 모델을 사용해 다시 시도해보기로 했다. 사전 학습된 모델을 정리해둔 깃허브 페이지가 있어

GitHub - justinpinkney/awesome-pretrained-stylegan: A collection of pre-trained StyleGAN models to download 참고하기 좋았다. 모델 중에서 해상도가 적당히 낮고 (512*512 미만) Zookiz 일러스트와 비슷한 특성의 이미지로 학습한 모델을 찾기로 했다. 결과적으로 256*256 포켓몬 이미지 데이터로 학습한 모델을 선택했다.

 

 

사용할 모델에 맞춰 resume_kimg를 새로 맞춰줘야 했는데, 모델 pickle 파일명에 명시되어 있지 않았다. 다음 깃허브에서 total_kimg가 7991로 설정되어 있는 것에서 유추해 resume_kimg를 7991로 설정했다.

stylegan-pokemon/training_loop.py at f2b4334ce665432b8792f50ac027ddbe75dbfc71 · t04glovern/stylegan-pokemon

 

모델에 맞게 이미지를 256*256으로 설정하고, total_kimg를 적당히 큰 숫자로 설정했다. 아래는 3 ticks까지 성공한 모습이다.

 

Creating the run dir root: results
Creating the run dir: results/00000-sgan-custom-1gpu
Copying files to the run dir
dnnlib: Running training.training_loop.training_loop() on localhost...

Streaming data using training.dataset.TFRecordDataset...

Instructions for updating:
Use eager execution and: 
`tf.data.TFRecordDataset(path)`

Dataset shape = [3, 256, 256]
Dynamic range = [0, 255]
Label size    = 0
Loading networks from "/content/drive/MyDrive/Colab Notebooks/pokemon.pkl"...


G                             Params    OutputShape         WeightShape     
---                           ---       ---                 ---             
latents_in                    -         (?, 512)            -               
labels_in                     -         (?, 0)              -               
lod                           -         ()                  -               
dlatent_avg                   -         (512,)              -               
G_mapping/latents_in          -         (?, 512)            -               
G_mapping/labels_in           -         (?, 0)              -               
G_mapping/PixelNorm           -         (?, 512)            -               
G_mapping/Dense0              262656    (?, 512)            (512, 512)      
G_mapping/Dense1              262656    (?, 512)            (512, 512)      
G_mapping/Dense2              262656    (?, 512)            (512, 512)      
G_mapping/Dense3              262656    (?, 512)            (512, 512)      
G_mapping/Dense4              262656    (?, 512)            (512, 512)      
G_mapping/Dense5              262656    (?, 512)            (512, 512)      
G_mapping/Dense6              262656    (?, 512)            (512, 512)      
G_mapping/Dense7              262656    (?, 512)            (512, 512)      
G_mapping/Broadcast           -         (?, 14, 512)        -               
G_mapping/dlatents_out        -         (?, 14, 512)        -               
Truncation                    -         (?, 14, 512)        -               
G_synthesis/dlatents_in       -         (?, 14, 512)        -               
G_synthesis/4x4/Const         534528    (?, 512, 4, 4)      (512,)          
G_synthesis/4x4/Conv          2885632   (?, 512, 4, 4)      (3, 3, 512, 512)
G_synthesis/ToRGB_lod6        1539      (?, 3, 4, 4)        (1, 1, 512, 3)  
G_synthesis/8x8/Conv0_up      2885632   (?, 512, 8, 8)      (3, 3, 512, 512)
G_synthesis/8x8/Conv1         2885632   (?, 512, 8, 8)      (3, 3, 512, 512)
G_synthesis/ToRGB_lod5        1539      (?, 3, 8, 8)        (1, 1, 512, 3)  
G_synthesis/Upscale2D         -         (?, 3, 8, 8)        -               
G_synthesis/Grow_lod5         -         (?, 3, 8, 8)        -               
G_synthesis/16x16/Conv0_up    2885632   (?, 512, 16, 16)    (3, 3, 512, 512)
G_synthesis/16x16/Conv1       2885632   (?, 512, 16, 16)    (3, 3, 512, 512)
G_synthesis/ToRGB_lod4        1539      (?, 3, 16, 16)      (1, 1, 512, 3)  
G_synthesis/Upscale2D_1       -         (?, 3, 16, 16)      -               
G_synthesis/Grow_lod4         -         (?, 3, 16, 16)      -               
G_synthesis/32x32/Conv0_up    2885632   (?, 512, 32, 32)    (3, 3, 512, 512)
G_synthesis/32x32/Conv1       2885632   (?, 512, 32, 32)    (3, 3, 512, 512)
G_synthesis/ToRGB_lod3        1539      (?, 3, 32, 32)      (1, 1, 512, 3)  
G_synthesis/Upscale2D_2       -         (?, 3, 32, 32)      -               
G_synthesis/Grow_lod3         -         (?, 3, 32, 32)      -               
G_synthesis/64x64/Conv0_up    1442816   (?, 256, 64, 64)    (3, 3, 512, 256)
G_synthesis/64x64/Conv1       852992    (?, 256, 64, 64)    (3, 3, 256, 256)
G_synthesis/ToRGB_lod2        771       (?, 3, 64, 64)      (1, 1, 256, 3)  
G_synthesis/Upscale2D_3       -         (?, 3, 64, 64)      -               
G_synthesis/Grow_lod2         -         (?, 3, 64, 64)      -               
G_synthesis/128x128/Conv0_up  426496    (?, 128, 128, 128)  (3, 3, 256, 128)
G_synthesis/128x128/Conv1     279040    (?, 128, 128, 128)  (3, 3, 128, 128)
G_synthesis/ToRGB_lod1        387       (?, 3, 128, 128)    (1, 1, 128, 3)  
G_synthesis/Upscale2D_4       -         (?, 3, 128, 128)    -               
G_synthesis/Grow_lod1         -         (?, 3, 128, 128)    -               
G_synthesis/256x256/Conv0_up  139520    (?, 64, 256, 256)   (3, 3, 128, 64) 
G_synthesis/256x256/Conv1     102656    (?, 64, 256, 256)   (3, 3, 64, 64)  
G_synthesis/ToRGB_lod0        195       (?, 3, 256, 256)    (1, 1, 64, 3)   
G_synthesis/Upscale2D_5       -         (?, 3, 256, 256)    -               
G_synthesis/Grow_lod0         -         (?, 3, 256, 256)    -               
G_synthesis/images_out        -         (?, 3, 256, 256)    -               
G_synthesis/lod               -         ()                  -               
G_synthesis/noise0            -         (1, 1, 4, 4)        -               
G_synthesis/noise1            -         (1, 1, 4, 4)        -               
G_synthesis/noise2            -         (1, 1, 8, 8)        -               
G_synthesis/noise3            -         (1, 1, 8, 8)        -               
G_synthesis/noise4            -         (1, 1, 16, 16)      -               
G_synthesis/noise5            -         (1, 1, 16, 16)      -               
G_synthesis/noise6            -         (1, 1, 32, 32)      -               
G_synthesis/noise7            -         (1, 1, 32, 32)      -               
G_synthesis/noise8            -         (1, 1, 64, 64)      -               
G_synthesis/noise9            -         (1, 1, 64, 64)      -               
G_synthesis/noise10           -         (1, 1, 128, 128)    -               
G_synthesis/noise11           -         (1, 1, 128, 128)    -               
G_synthesis/noise12           -         (1, 1, 256, 256)    -               
G_synthesis/noise13           -         (1, 1, 256, 256)    -               
images_out                    -         (?, 3, 256, 256)    -               
---                           ---       ---                 ---             
Total                         26086229                                      


D                    Params    OutputShape         WeightShape     
---                  ---       ---                 ---             
images_in            -         (?, 3, 256, 256)    -               
labels_in            -         (?, 0)              -               
lod                  -         ()                  -               
FromRGB_lod0         256       (?, 64, 256, 256)   (1, 1, 3, 64)   
256x256/Conv0        36928     (?, 64, 256, 256)   (3, 3, 64, 64)  
256x256/Conv1_down   73856     (?, 128, 128, 128)  (3, 3, 64, 128) 
Downscale2D          -         (?, 3, 128, 128)    -               
FromRGB_lod1         512       (?, 128, 128, 128)  (1, 1, 3, 128)  
Grow_lod0            -         (?, 128, 128, 128)  -               
128x128/Conv0        147584    (?, 128, 128, 128)  (3, 3, 128, 128)
128x128/Conv1_down   295168    (?, 256, 64, 64)    (3, 3, 128, 256)
Downscale2D_1        -         (?, 3, 64, 64)      -               
FromRGB_lod2         1024      (?, 256, 64, 64)    (1, 1, 3, 256)  
Grow_lod1            -         (?, 256, 64, 64)    -               
64x64/Conv0          590080    (?, 256, 64, 64)    (3, 3, 256, 256)
64x64/Conv1_down     1180160   (?, 512, 32, 32)    (3, 3, 256, 512)
Downscale2D_2        -         (?, 3, 32, 32)      -               
FromRGB_lod3         2048      (?, 512, 32, 32)    (1, 1, 3, 512)  
Grow_lod2            -         (?, 512, 32, 32)    -               
32x32/Conv0          2359808   (?, 512, 32, 32)    (3, 3, 512, 512)
32x32/Conv1_down     2359808   (?, 512, 16, 16)    (3, 3, 512, 512)
Downscale2D_3        -         (?, 3, 16, 16)      -               
FromRGB_lod4         2048      (?, 512, 16, 16)    (1, 1, 3, 512)  
Grow_lod3            -         (?, 512, 16, 16)    -               
16x16/Conv0          2359808   (?, 512, 16, 16)    (3, 3, 512, 512)
16x16/Conv1_down     2359808   (?, 512, 8, 8)      (3, 3, 512, 512)
Downscale2D_4        -         (?, 3, 8, 8)        -               
FromRGB_lod5         2048      (?, 512, 8, 8)      (1, 1, 3, 512)  
Grow_lod4            -         (?, 512, 8, 8)      -               
8x8/Conv0            2359808   (?, 512, 8, 8)      (3, 3, 512, 512)
8x8/Conv1_down       2359808   (?, 512, 4, 4)      (3, 3, 512, 512)
Downscale2D_5        -         (?, 3, 4, 4)        -               
FromRGB_lod6         2048      (?, 512, 4, 4)      (1, 1, 3, 512)  
Grow_lod5            -         (?, 512, 4, 4)      -               
4x4/MinibatchStddev  -         (?, 513, 4, 4)      -               
4x4/Conv             2364416   (?, 512, 4, 4)      (3, 3, 513, 512)
4x4/Dense0           4194816   (?, 512)            (8192, 512)     
4x4/Dense1           513       (?, 1)              (512, 1)        
scores_out           -         (?, 1)              -               
---                  ---       ---                 ---             
Total                23052353                                      


Setting up snapshot image grid...
Setting up run dir...

Training...

tick 1     kimg 7992.0   lod 0.00  minibatch 8    time 4m 16s       sec/tick 195.4   sec/kimg 190.79  maintenance 60.4   gpumem 5.1 
tick 2     kimg 7993.0   lod 0.00  minibatch 8    time 7m 37s       sec/tick 187.2   sec/kimg 182.83  maintenance 13.8   gpumem 5.1 
tick 3     kimg 7994.1   lod 0.00  minibatch 8    time 10m 50s      sec/tick 186.8   sec/kimg 182.45  maintenance 6.2    gpumem 5.1 
---------------------------------------------------------------------------
KeyboardInterrupt                         Traceback (most recent call last)

 

이후 아래와 같이 파라미터를 수정했다.

    size = (256, 256)
    
    ...
    
    tick_kimg_dict = {4: 160, 8:140, 16:120, 32:100, 64:80, 128:2, 256:1, 512:1, 1024:1}): # Resolution-specific overrides.
#   tick_kimg_dict = {4: 160, 8:140, 16:120, 32:100, 64:80, 128:60, 256:40, 512:30, 1024:20}): # Resolution-specific overrides.

    ...
      
    resume_run_id           = "/content/drive/MyDrive/Colab Notebooks/network-snapshot-007994.pkl",     # Run ID or network pkl to resume training from, None = start from scratch.
    resume_kimg             = 7994,      # Assumed training progress at the beginning. Affects reporting and training schedule.
    
    ...    
        
    # Dataset.
    desc += '-custom';     dataset = EasyDict(tfrecord_dir='smalls', resolution=256);              train.mirror_augment = True

    # Number of GPUs.
    desc += '-1gpu'; submit_config.num_gpus = 1; sched.minibatch_base = 4; sched.minibatch_dict = {4: 128, 8: 128, 16: 128, 32: 64, 64: 32, 128: 16, 256: 8, 512: 4}
    
    # Default options.
    train.total_kimg = 25000
    sched.lod_initial_resolution = 8
    sched.G_lrate_dict = {128: 0.0015, 256: 0.002, 512: 0.003, 1024: 0.003}
    sched.D_lrate_dict = EasyDict(sched.G_lrate_dict)

 

  • size : 이미지 크기를 전처리
  • tick_kimg_dict : 해상도에 따라 tick에서 처리할 kimg 개수 설정 - 해상도 128 이상일 때 값을 매우 작게 만들어서 tick이 돌아가는 속도를 빠르게 만들었음.
  • resume_run_id : 위에서 3 tick만큼 더 학습한 (가장 최근) 모델 사용
  • resume_kimg : 7991에서 3 tick 진행된 상태이므로 7994로 설정
  • resolution=256 : custom dataset에 해상도에 대한 정보 추가
  • train.total_kimg : 학습이 계속 이뤄지도록 충분히 큰 값(25000) 설정
  • lod_initial_resolution : 초기 Level of detail 설정 (그런데 막상 tick 돌 때는 0.0부터 시작함. 확인 필요.)

 

학습

Colab 환경에서 학습을 진행하기 때문에 제약 사항이 많았다. 사용자당 GPU 사용량도 제한되어 있고, 런타임도 최대 12시간이었다. 따라서 한번 학습할 때 가능한 한 오래 학습을 시킨 후에, 세션을 초기화하고 가장 최근에 저장된 모델로 학습을 재개하기로 했다.

 

런타임 끊김 방지

런타임 끊김 방지를 위해 아래 코드를 개발자도구 페이지 콘솔에 추가했다.

function ClickConnect(){
    console.log("1분마다 코랩 연결 끊김 방지"); 
    document.querySelector("#top-toolbar > colab-connect-button").shadowRoot.querySelector("#connect-icon")
.click();
}
setInterval(ClickConnect, 1000 * 60);

 

모델 저장

본 코드는 학습을 진행하면서 tick마다 이미지와 모델의 snapshot을 저장하도록 한다. 여기에 코드를 추가해서 나의 개인 드라이브에도 이미지와 모델을 저장하도록 했다. 처음에는 모델 snapshot만 저장해서, 초반 50~60 tick의 이미지 snapshot이 없다. (매우 아쉬운 점임.)

학습을 진행하다가 중간에 network_snapshot_ticks = 2로 수정해서 tick 두 번에 모델 snapshot 하나를 저장하게 했다. 모델 파일 하나에 300MB 정도 해서, tick마다 저장하는 것이 부담스러웠기 때문이다.

(내 개인 드라이브에 공간이 없는 게 문제였다. 용량이 부족할 것 같아 학습 중간중간 개인 드라이브에서 지난 모델 snapshot들을 직접 삭제해야 했다.)

    image_snapshot_ticks    = 1,        # How often to export image snapshots?
    network_snapshot_ticks  = 2,       # How often to export network snapshots?
    
    ...
    
    misc.save_image_grid(grid_fakes, os.path.join('/content/drive/MyDrive/Colab Notebooks', 'fakes%06d.png' % resume_kimg), drange=drange_net, grid_size=grid_size)    
    pkl_my = os.path.join('/content/drive/MyDrive/Colab Notebooks', 'network-snapshot-%06d.pkl' % (cur_nimg // 1000))
    misc.save_pkl((G, D, Gs), pkl_my)

 

 

결과

총 8시간을 학습시킨 모델로 임의 이미지를 생성해보았다.

 

아래는 학습 중 저장한 image snapshot을 gif로 생성한 결과이다. image snapshot을 드라이브에 저장하는 코드를 학습 중간에 추가해서, 학습 초반의 snapshot이 없다.

 

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

GAN 실험(3) - styleGAN2 + pixel2style2pixel  (0) 2022.08.10
GAN 실험(2) - layer swapping  (0) 2022.08.10
few-shot GAN ada 이해하기  (0) 2022.08.01
ReStyle 이해하기  (0) 2022.08.01
p2S2p 이해하기  (0) 2022.08.01
복사했습니다!