22.02.09 윈도우에서 pf-afn 환경설정 + 인공지능 가상 옷 피팅 (Virtual Try On) demo 돌려보기

2022. 2. 9. 18:00작업/ComputerVision

프로젝트 계기 : 

모델 소개 : pf-afn이란 Parser Free Virtual Try on Via Distilling Appearance Flows 라는 약자의 오픈소스 인공지능 모델로 유명한 대회인 CVPR 2021 대회에 올라왔던 모델이다. 원작자는 geyuying님이다.

기존의 가상피팅으로 유명한 WUTON 모델과 PF-AFN 모델과의 비교사진이다. GAN이라는 게 같은 팀원분이신 서린님의 말씀으로 이해해보자면 Teacher와 Student가 싸우면서 세상 어딘가 존재하는 것 같지만 실제로는 존재하지 않는 가짜 이미지 Fake Image를 점수를 매겨가면서 더 진짜같이 만드는 것이라고 들었다.

GAN이라는 것은 쉽게 말해서 요즘 유명한 DeepFake같이 실제로는 없는 얼굴(이미지)를 생성하는 인공지능 기법이라고 생각하면 된다.

이것이 PF-AFN의 training pipeline이다. 일단 input으로 옷을 입을 사람 이미지 I와 입고 싶은 옷 이미지 Ic_가 주어진다.

일단 몸 input 이미지 I에 segmentation과 edge parse를 적용하여서 목이 어딨고 팔이 어딨고 어디가 배고.. 이런 옷을 입혀야 하는 몸 구조를 알아내고, 저기 보이는 것처럼 관절포인트? 도 잡아내어 사람의 자세를 파악한다.

그리고 PB-AFWM, warping모델을 거쳐서 옷 input Ic를 그 몸 구조에 맞게 휘게 만든다. 그 warping 결과물이 저기 보이는 uw_인것 같다.

그리고 그걸 generate 모델(PB-GM)에 넣어서 Tutor 이미지 uI를 만든다. 이 uI를 만드는 데 필요한 방식(필요한 공식, weight들을 잘 기억해둔다.)

그 tutor uI 이미지를 PB-AFWM과 PF-AFWM을 distillation 시켜서 원래 입고 있던 옷 이미지 Ic를 참고해서 기억해둔 같은 weight(같은 방식)으로 원본인 I을 다시 만든다. 그것이 student SI이다

그리고 나서 최종적으로 student SI와 teacher I가 서로 싸워서(비교해서) 점점 더 적절한 방식(weight)를 찾아가는 모델이 바로 pf-afn인 것 같다.

 

즉 간단히 말하면, 이 pf-afn는 크게 2가지 구조로 이루어져 있고 warping 모델과 generate 모델이 그 2가지 기능을 각각 한다.

 

정리를 하자면 최종적으로 필요한 준비물과 만들고 싶은 것은 실제로 존재하는듯한 그럴듯한 tutor uI이다.

준비물(input) : I, Ic_    를 가지고

최종적으로 만들고 싶은 결과물(output) : Tutor uI

 

 

이제 이 pf-afn을 돌리기 위해 원작자의 GitHub를 참조한다.

https://github.com/geyuying/PF-AFN

 

GitHub - geyuying/PF-AFN: Official code for "Parser-Free Virtual Try-on via Distilling Appearance Flows", CVPR 2021.

Official code for "Parser-Free Virtual Try-on via Distilling Appearance Flows", CVPR 2021. - GitHub - geyuying/PF-AFN: Official code for "Parser-Free Virtual Try-on via Distilling A...

github.com

 

이 분이 사용하신 구현환경이다. 우분투에서 하셨고, training을 위해서는 GTX1080 GPU 무려 8개나 쓰셨고..

test할 때는 GTX1080 GPU 1개를 쓰셨다고 한다. 그런데 뭐 training하지 않고 checkpoints만 가져다 쓸 거면 굳이 GPU까진 필요없을 것 같기도 하다. 그리고 우리가 배포해야할 VM과 개발환경때 사용할 팀원분이 만들어주시는 docker image에도 GPU는 존재하지 않는다.

(checkpoints란 epoch마다 머신러닝 모델을 training 시키는 데 너무 많은 자원과 시간이 드므로 학습될 때마다 개선된, 또는 모든 weight들과 model 파일들을 일정 간격, 또는 원할 때마다 저장하는 것이다. 우리는 그냥 저 원작자분인 geyuying 님이 학습 다 해놓으신 weight들(checkpoints)를 가져와서 쓸 것이다.)

 

 

그리고 내 환경이다 이 아래 글은 내가 예전에 tensorflow 환경설정 하며 썼던 글이다. 

https://scalar.tistory.com/116?category=1255257 

 

22.01.30 윈도우에 tensorflow GPU까지 연결해서 환경설정하기(cuDNN, CUDA, tensorflow, 1050Ti)

tensorflow깔라고 보니까 문제점.. 내 컴퓨터는 python3.10.0으로 깔려있었다 tensorflow는 python3.9이하를 지원함.. 그래서 conda로 python 다운그레이드를 실행함. 아나콘다가 있었었다.. 엥... (python 버..

scalar.tistory.com

내 로컬환경 :

window 10

gpu GTX 1050 Ti

python 3.10 

이므로 저 pfafn 원작자분이 사용하신 환경과 전혀 맞지 않고 에러 폭탄일 것이 분명했다.

그러므로 로컬말고 conda 가상환경에서 모든 설치 및 demo 과정을 진행해보자.

저번 머신러닝때 사용한 conda 가상환경 seoyoonenv

저번 머신러닝때는 tensorflow를 사용했어서 이런 버전 표를 보고 설치했었다

그런데 지금은 tensorflow가 아니라 pytorch이므로 저 원작자분이 까신대로 cuda 9.0 cupy 6.0.0 등을 깔아줘야 할 것 같다.

일단 저번에(https://scalar.tistory.com/116?category=1255257 ) 한 것 처럼 conda의 가상환경을 만들어서 원작자분이 알려주신 install guideline으로 한번 해보자.

 


+ 수정부분 원글 부분 먼저 실행하고 밑에서 참고하라고 할 때 그때 보셔도 됩니다.

# + 수정 cmd에서 하면 무조건 되고, 
> conda create -n tryon python=3.6


# bash shell에서 하려면
# /c/Users/user/anaconda3/etc/profile.d 이 위치까지 들어간 다음 ls로 무슨 파일들이 있는지 확인하고
$ source conda.sh 를 해야 bash shell에서도 conda를 사용할 수 있다.

# 그 다음 아까 cmd에서 만든 가상환경 잘 있는지 확인
$ pip list

 


 

원글

 

tryon이라는 이름의 가상환경 생성
나는 윈도우임. 그래서 리눅스식 activate가 안됨. conda.bat 하고 실행해야됨

근데 gitbash 터미널은 지금 가상환경인지 아닌지 잘 보이지 않는다.. 그래서 저번에도 cmd 에서 했었다.

# 윈도우시면 cmd에서 실행하세용

conda activate tryon

오.. cmd에서는 그냥 conda activate tryon해도 되네 ㅎㅎ gitbash만 conda.bat activate해야되나보다.

cmd에서는 가상환경에 들어와지면 C:\어쩌구 경로 앞에 (가상환경이름)이 표시됩니다.

앞으로 윈도우에서 conda 가상환경가지고 설치할 때는 cmd에서 하고 개발은 gitbash에서 하는걸루..해보자 ㅋㅋ

# python 3.6으로 가상환경 잘 생성됐나 확인하기

python -V

 

굳굳

# 필요한 pytorch, cudatoolkit, torchvision 깔기

conda install pytorch=1.1.0 torchvision=0.3.0 cudatoolkit=9.0 -c pytorch

# cupy 6.0.0 버전 설치하기

pip install cupy==6.0.0 -> # 이거는 에러떴음

conda install cupy=6.0.0 # 이걸로 해보자

에러 WOW..

음.. 내생각엔 pip3로 하면 될 것 같긴 함.. 근데 conda install 로 해볼까

오.. 완료됨!!

# 지금까지 사용할 파이썬 라이브러리들이 잘 깔렸나 확인해보자
pip list

굳굳

 

# opencv-python 설치
pip3 install opencv-python -> # 아 근데 생각해보니 원작자분은 4.5.1로 까심 이대로 깔면 최신버전이 깔림
pip3 install opencv-python==4.5.1 # 나도 4.5.1로 한다음 거기에 나오는 버전으로 깔자.
pip3 install opencv-python==4.5.1.어쩌구

굳굳 다시한번 pip list 확인

왼: 내가 깐 라이브러리, 오: 원작자님의 필요한 라이브러리

지금까지 깐 필요한 라이브러리들이 잘 깔렸다.

(conda 진짜 편하구나... 너가 좀 무겁다고 널 배척하고 pip venv를 더 좋아했었는데 미안하다)

# 드디어 pf-afn GitHub 코드 clone해오기
git clone https://github.com/geyuying/PF-AFN.git

C:\Users\user\PF-AFN 폴더가 잘 받아와졌다.
윈도우에서 리눅스 'ls'명령 사용하기 -> dir

# 본격적으로 작업 폴더에 들어가기
cd PF-AFN # PF-AFN이 git clone된 작업폴더를 파일탐색기 등으로 확인하고 그냥 거기로 드가시면 됩니당

그냥 VScode를 새로 켜자 ㅋㅋ

그리고 꼭!! conda.bat activate tryon이나 conda activate tryon으로 가상환경 들어가서 작업하기!!

 

 

cmd 버전

 

+ 위에 수정된 부분을 보고 와주시기를 바란다!

여긴 Git Bash 창이지만 cmd에서 했던 설치과정들이 tryon 가상환경에 잘 있다

참고로 bash 창에서는 dir 대신 ls도 가능하고 $로 끝나서 > 등의 문제도 해결된다! 리눅스처럼 사용가능 그러나 위치는 내 컴퓨터이므로 gpu도 사용이 가능할 것이다.

# 내 컴퓨터에 있는 GPU 잘 연결되있나 확인
dxdiag

잘 된다

이제 demo를 돌려보자 아 그 이전에 Training 과정도 있다.

(일단은 첫번째 sprint를 끝내야 하고.. 성능개선은 나중에 하면 되므로.. 그리고 내 컴퓨터에 지금 용량이 별로 없기 떄문에 일단 training은 생략하고 demo running으로 넘어갔다.)

 

이 과정은 추후에 우리가 원하는 한국 쇼핑몰에 (무신사..에이블리 등 실제 한국 유저들이 사용하는 의류구매사이트들) 더 최적화된 모델을 만들고 싶으면 우리가 원하는 이미지들로 데이터셋을 구성한 다음 training 시켜보면 될 거 같다.

git clone을 아예 새로 해서..! PF-AFN2라는 폴더를 만들어서 추후에 한번 해보자!

 

일단은 현재 저 training 과정을 생략한다면, 원작자분이 사용하신 VITON 데이터셋의 14221 개로 train된 모델을 사용하게 되는 것이고, 한국 유행의 옷..이라기 보다는 어떤 외국 쇼핑몰의.. 좀 구린 여성 의류 사진들에 더 최적화되어있다.

 

Running Demo

1. 

cd PF-AFN_test

2. 미리 학습된 weight들 가져오기(chekcpoints들 적절한 폴더에 위치시키기)

머신러닝 학습 시키고 나면 생기는 파일들인 .pth 확장자의 파일들을 위치시킨다.

지금 이 pf-afn 모델은 크게 warping과 generate 모델이 있다.

먼저 필요한 checkpoints를 다운받았다

압축을 풀면 이런 폴더들이 있다. 우리가 사용할 건 .pth로 끝나는 놈들

이게 바로 원작자님이 미리 학습시켜놓은 pth 이다!

압축을 풀고 나서 저 checkpoints 폴더 안에 있는 PFAFN이라는 폴더를 PF-AFN_test/checkpoints 안에 위치하도록 한다.

3. 이제 데이터셋 폴더 안에 있는 간단한 test image들을 가지고 demo를 돌리기 위한 준비를 하자

PF-AFN 파일구조

PF-AFN 폴더 안에 dataset 폴더안에는 test를 위한 데모 이미지들이 들어있다.

test_img안에는 사람이미지 I가 들어있고, test_clothes안에는 입고싶은 옷 이미지들 Ic_가 들어있고, test_edge 안에는 파이썬 내장함수를 이용해 Ic_에서 뽑아낸(extract) edge 가 들어있다.

(참고 , 이 때 Ic_와 Ic_의 edge의 사진명이 같다.(0175375_1.jpg))

그리고 각 옷과 사람을 matching 시킬 때는 (사람) (입을옷) demo.txt에 test pairs를 적어주면 된다.

지금 예시로 5 pairs가 적혀있는데 성능이 딸리면.. 그리고 우리 서비스는 몸 1개+옷 1개를 합성할 것이므로 pair 한 개만 적어줘도 된다.

demo.txt

000066_0.jpg 017575_1.jpg
016962_0.jpg 003434_1.jpg
004912_0.jpg 014396_1.jpg
005510_0.jpg 006026_1.jpg
014834_0.jpg 019119_1.jpg
015794_0.jpg 010567_1.jpg

일단 한 pair만 해보기로 하고 혹시모르니 복사해놨다.

일단 pair 한 개만 해보자

 

dataset/test_clothes 즉 Ic_
dataset/test_edge 즉 Ic_의 edge
dataset/test_img 즉 옷을 입을 사람 I

여기서 이 pf-afn의 장점이 또 드러나는데, test를 할 때 edge가 pf-afn 모델의 네트워크단에 주어지기 떄문에(fed 먹이를 준다고 표현되있음 ㅋㅋ) 최종 output인 가상피팅사진을 generate할 때 human parsing(목,팔,배,가슴나누기)이나 human pose estimation(관절포인트잡기) 결과를 위한 모델이 따로 필요 없다고 한다! 정말 대단하네

 

5. 이제 checkpoint를 불러와서 또는 training된 모델을 가지고 진짜 demo를 돌려보는 시간

bash test.sh

test.sh를 run하면 된다고 한다. 그러면 그 가상피팅된 output은 results라는 폴더에 저장된다.

test.sh

# test.sh 파일 원본내용 나는 좀 수정할거라 일단 복사해놨다.

python test.py --name demo --resize_or_crop None --batchSize 1 --gpu_ids 0

근데 test.sh파일을 보니 이거 실행 안하고 저 명령어 그대로 terminal창에 쳐도 된다.

 

저 test.sh를 한번 분석해보자

python test.py (test.py를 파이썬으로 실행시켜라)

--name demo (리눅스터미널에서 - 하나만 붙으면 한글자옵션, --붙으면 두글자이상 옵션 name은 demo로 해라)

이런식으로 변수에다가 값을 넣어주는 것 같다
?? 이런뜻인가?

--resize_or_crop None(resize_or_crop는 None으로 해라)

--batchSize 1 (batchSize는 1로 해라)

--gpu_ids 0 (gpu_ids 는 0으로 해라)

 

 

음.. test.sh가 이해가 잘 안된다. 구글링 해보자

아하.. 이거보니까 pytorch로 된 파일을 실행시킬 때 있는 옵션인 것 같다.

name은 그냥 내맘대로 seoyoon으로 해도되고 그 뒤에 것들도 옵션인 듯 하다.

 

그리고 우리가 또 중요한 것은 저 gpu_ids를 없애고 시켜봐야도 될 것 같다. 왜냐면 docker image에는 gpu가 없을테니까

난 추후에 이렇게 바꾸고 한번 실행해볼 것이다.

그럼 간다!!

 

++ 오류 발생..

# 오류 로그
RuntimeError:
        An attempt has been made to start a new process before the
        current process has finished its bootstrapping phase.

        This probably means that you are not using fork to start your
        child processes and you have forgotten to use the proper idiom
        in the main module:

            if __name__ == '__main__':
                freeze_support()
                ...

        The "freeze_support()" line can be omitted if the program
        is not going to be frozen to produce an executable.
        
        
Traceback (most recent call last):
  File "test.py", line 40, in <module>
    for i, data in enumerate(dataset, start=epoch_iter):
  File "C:\Users\user\anaconda3\envs\tryon\lib\site-packages\torch\utils\data\dataloader.py", line 576, in __next__
    idx, batch = self._get_batch()
  File "C:\Users\user\anaconda3\envs\tryon\lib\site-packages\torch\utils\data\dataloader.py", line 553, in _get_batch
    success, data = self._try_get_batch()
  File "C:\Users\user\anaconda3\envs\tryon\lib\site-packages\torch\utils\data\dataloader.py", line 519, in _try_get_batch
    raise RuntimeError('DataLoader worker (pid(s) {}) exited unexpectedly'.format(pids_str))
RuntimeError: DataLoader worker (pid(s) 20364) exited unexpectedly

 

원본 test.py 코드

import time
from options.test_options import TestOptions
from data.data_loader_test import CreateDataLoader
from models.networks import ResUnetGenerator, load_checkpoint
from models.afwm import AFWM
import torch.nn as nn
import os
import numpy as np
import torch
import cv2
import torch.nn.functional as F

opt = TestOptions().parse()

start_epoch, epoch_iter = 1, 0

data_loader = CreateDataLoader(opt)
dataset = data_loader.load_data()
dataset_size = len(data_loader)
print(dataset_size)

warp_model = AFWM(opt, 3)
print(warp_model)
warp_model.eval()
warp_model.cuda()
load_checkpoint(warp_model, opt.warp_checkpoint)

gen_model = ResUnetGenerator(7, 4, 5, ngf=64, norm_layer=nn.BatchNorm2d)
print(gen_model)
gen_model.eval()
gen_model.cuda()
load_checkpoint(gen_model, opt.gen_checkpoint)

total_steps = (start_epoch-1) * dataset_size + epoch_iter
step = 0
step_per_batch = dataset_size / opt.batchSize

for epoch in range(1,2):

    for i, data in enumerate(dataset, start=epoch_iter):
        iter_start_time = time.time()
        total_steps += opt.batchSize
        epoch_iter += opt.batchSize

        real_image = data['image']
        clothes = data['clothes']
        ##edge is extracted from the clothes image with the built-in function in python
        edge = data['edge']
        edge = torch.FloatTensor((edge.detach().numpy() > 0.5).astype(np.int))
        clothes = clothes * edge        

        flow_out = warp_model(real_image.cuda(), clothes.cuda())
        warped_cloth, last_flow, = flow_out
        warped_edge = F.grid_sample(edge.cuda(), last_flow.permute(0, 2, 3, 1),
                          mode='bilinear', padding_mode='zeros')

        gen_inputs = torch.cat([real_image.cuda(), warped_cloth, warped_edge], 1)
        gen_outputs = gen_model(gen_inputs)
        p_rendered, m_composite = torch.split(gen_outputs, [3, 1], 1)
        p_rendered = torch.tanh(p_rendered)
        m_composite = torch.sigmoid(m_composite)
        m_composite = m_composite * warped_edge
        p_tryon = warped_cloth * m_composite + p_rendered * (1 - m_composite)

        path = 'results/' + opt.name
        os.makedirs(path, exist_ok=True)
        sub_path = path + '/PFAFN'
        os.makedirs(sub_path,exist_ok=True)

        if step % 1 == 0:
            a = real_image.float().cuda()
            b= clothes.cuda()
            c = p_tryon
            combine = torch.cat([a[0],b[0],c[0]], 2).squeeze()
            cv_img=(combine.permute(1,2,0).detach().cpu().numpy()+1)/2
            rgb=(cv_img*255).astype(np.uint8)
            bgr=cv2.cvtColor(rgb,cv2.COLOR_RGB2BGR)
            cv2.imwrite(sub_path+'/'+str(step)+'.jpg',bgr)

        step += 1
        if epoch_iter >= dataset_size:
            break

data/custom_dataset_loader_test.py

찾았다! torch의 내장함수 DataLoaoder의 num_workers!

opt의 nTheareds를 0으로..해보자

opt
TestOptions의
BaseOptions까지 확인

++ 해결

저기 --nThreads 의 default를 1 에서 0으로 바꿔라

 

그리고 잘 되는지 수정한 test.sh

demo.txt

results 결과 (demo 폴더는 아까 --name 을 demo 로 하고, demo.txt에 다섯 개 이미지 넣었을 떄 결과이다.)

(seoyoon 폴더는 --name을 seoyoon으로 하고, demo.txt에 한 개 이미지 넣었을 떄 결과이다.)

드디어 첫 데모 성공!!

 

++수정 

CPU로도 돌려봤다

test.sh
results

CPU로도 잘 된다!(test는 CPU가 오히려 더 빠른 거 같은데..?)

 

+ Dataloaders의 num_workers 관련 설명자료