[ML Practice] pix2pix(2)

김현우
None
Published in
9 min readOct 19, 2020

휴먼스케이프 Software engineer Covy입니다.

이전 포스트에서는 pix2pix에서 제시한 layer과 model을 PyTorch를 이용해서 직접 구현해보는 시간을 가졌습니다. 본 포스트에서는 pix2pix에서 제시한 model을 가지고 training을 구현해보는 시간을 가지려고 합니다. 이전 포스트가 궁금하신 분들은 이곳을 참고하시면 좋습니다.

Objective

본 포스트에서는 PyTorch를 이용해 pix2pix 논문에 적혀있는 network의 구조를 학습하는 방법에 대해서 서술합니다. 이는 앞선 포스트에서 소개드렸던 layer과 model의 구현을 바탕으로 구현한 것입니다.

Preparing Data & Preprocessing

가장 먼저 진행해야 할 단계는 데이터를 준비하고 전처리하는 단계입니다. 이 단계에서는 1. 데이터의 transformation(전처리로 사용할 변화들)을 정의하고, 2. 이들과 준비한 데이터를 이용해 dataset을 정의하며, 3. DataLoader 를 이용해 minibatch, shuffle을 활용할 수 있게 합니다.

첫 과정의 transforms.Compose는 내부에 있는 array에 transform에 대한 정보를 담은 배열을 인자로 받습니다. 이 경우 Resize, RandomCrop, 그리고 Normalization을 진행하는 것으로 볼 수 있는데 각각 이미지를 286x286으로 변환하고 랜덤하게 256x256으로 잘라낸 후, 각 값에 0.5를 뺀 뒤에 0.5로 나누는 작업을 실시하는 것입니다. (이 normalization 과정은 0~1까지인 tensor의 범위를 -1~1까지로 바꾸어 줍니다.)

이후, Dataset 에서는 주어진 transforms와 실제 데이터 디렉토리, 그리고 task(이 경우 pix2pix입니다.), opts(다양한 option이 들어갈 수 있는데, 이 경우 학습의 direction입니다.)를 바탕으로 실제 데이터를 transforms, task, opts를 적용하여 최종적으로 tensor 형태로 반환하게 됩니다.

마지막으로 DataLoader의 경우 mini-batch를 이용한 학습을 하기 용이한 형태로 데이터를 반환해 줍니다. 자세한 내용은 아래에서 설명을 이어가겠습니다. 여기서는 데이터를 여러개의 batch로 나눌 batch-size와, 데이터의 shuffle여부, 데이터 로딩에 얼마나 많은 subprocesses를 사용할지에 대해 지정하는 num_workers를 지정한다고 보시면 되겠습니다.

Network

다음으로 진행한 단계는 앞선 pix2pix (1)에서 구현했던 네트워크를 정의하는 것입니다. 이 단계는 간단해서 코드로 간단하게 보여드리고 넘어가려고 합니다.

코드에 적혀 있는 . to(device)는 모델의 연산을 담당할 디바이스를 지정하는 부분입니다. 보통의 경우 다음과 같이 device를 선언하여 cuda, 혹은 cpu를 지정합니다.

device = torch.device(‘cuda’ if torch.cuda.is_available() else ‘cpu’)

코드 아래쪽의 init_weights()는 선언한 네트워크의 weight를 initialize하는 부분입니다. init_type은 weight initialize를 하는 다양한 방법 중 어느 것을 선택할 것인지에 대한 것이고 normal의 경우 normal distribution을 이용한 initialization입니다. init_gain은 이 때 normal distribution의 standard deviation입니다.

Cost function & Optimizer

다음으로 진행한 단계는 cost function 과 optimizer를 설정한 것입니다. 논문에서는 cost function으로 L1 loss와 Binary Cross-Entropy loss를 조합한 형태를 사용하기 때문에 아래와 같이 설정해 주었습니다.

Optimizer의 경우 learning rate와 network parameter, 그리고, Adam optimizer의 경우 연산에 사용할 coefficient beta1, beta2의 값을 parameter로 받습니다. 이후에 설명을 더 드리겠지만, optimizer는 실제로 network의 weight를 업데이트하는 역할을 진행합니다. 여기서 지정한 Adam optimizer의 선택과 beta1, beta2 모두 논문에서 제시한 내용을 따라서 구현해 주었습니다.

Train

다음으로 진행할 단계는 training입니다. Training 단계는 앞서 설명드린 mini-batch를 이용해 전체 데이터셋을 batch 크기로 나눈 뒤에 그 batch에 해당하는 cost function으로 학습을 시켜나가는 방법입니다.

위 코드는 pix2pix training을 위해 작성한 코드입니다. 먼저, epoch 만큼의 루프를 돌고, 그 내부에서는 mini-batch 형태로 데이터를 나누어 루프를 돌기 위해 앞선 dataLoader에서 불러온 데이터를 enumerate 하면서 시작하게 됩니다.

enumerate 루프 내에선 크게 3가지로 나누어지는데 그것이 1. forward netG, 2. backward netD, 3. backward netD 입니다. 이는 앞서 논문 리뷰에서 설명했던 것 처럼, generator를 이용해 이미지를 생성해 내고, netD는 그 이미지를 이용해 진위여부를 수행한 뒤 back propagation을 진행하여 gradient descent 방향으로 학습하고, 이후에 netG가 back propagation을 진행하여 gradient descent 방향으로 학습이 진행되는 것입니다.

여기서 일괄적으로 볼 수 있는 것이, output=netG(input) 와 같은 형태로 forward propagation을 진행한다는 점과, discriminatorLoss.backward(), optimD.step()의 형태로 back propagation을 진행한다는 점입니다. 부연설명을 하자면 netG(input)은 network의 현재 weight를 기반으로 output을 산출해내는 것이고, .backward()는 각 weight의 위치에서의 gradient를 back propagtion 으로 연산을 진행한다는 것이고, optimizer.step()의 경우 연산한 gradient를 weight parameter의 .grad property에서 가져와서 최종적으로 weight를 업데이트해주는 과정입니다.

backward netD에서만 fake.detach()를 해준 이유는 discriminator를 back propagtion 할 때 원하지 않는 generator의 back propagation을 막기 위함입니다. 자세한 내용은 이곳을 참고하시면 좋습니다.

Image save

마지막이자, 부가적으로 소개해드릴 것은 이미지 저장에 관한 내용입니다. 학습된 데이터를 확인할 수 있도록 batchsize 의 절반 간격으로 이미지를 저장한 코드는 아래와 같습니다.

denormalize의 경우 앞서 -1~1 사이의 범위로 normalize 해 주었던 데이터를 다시 denormalize해주는 과정이고 changeToNumpy의 경우 tensor를 numpy data로 변환하고 차원의 순서를 변화시키는 과정을 진행한 것입니다.

이렇게 변환한 데이터를 0~1 사이의 범위로 맞춰주기 위해 다시 np.clip()을 사용했고, plt.imsave()를 이용해 이미지를 저장하게 됩니다.

Result

학습에는 pix2pix 학습 용도로 제공하는 dataset을 사용했고, map to photo의 방향으로 학습을 진행했습니다. 그 결과를 간단히 나타내면 다음과 같습니다.

Batch 20
Batch 11980

첫 번째 그림은 학습 초기의 학습 데이터와 generator로 생성된 이미지이고, 두 번째 그림은 학습 후기의 학습 데이터와 generator로 생성된 이미지입니다. 초기에는 확실히 map의 형태만을 blurry하게 따라하던 반면, 후기에는 input photo와 상당히 닮아 있는 모습을 확인할 수 있었습니다.

Conclusion

이것으로 간단하게 pix2pix 논문에서 제시한 network를 가지고 training을 진행하고 결과를 확인해보는 시간을 가졌습니다. 저는 cpu를 가지고 training을 하여 꽤 시간이 걸렸는데, 관심 있으신 분들은 google colab을 이용해보시는 것을 추천드립니다. Google colab 관한 내용은 이곳에서 확인하실 수 있습니다. 이후에는 다양한 dataset을 사용해보거나, 설정을 바꿔보는 시간을 가지는 것도 좋을 것 같습니다.

Get to know us better!
Join our official channels below.

Telegram(EN) : t.me/Humanscape
KakaoTalk(KR) : open.kakao.com/o/gqbUQEM
Website : humanscape.io
Medium : medium.com/humanscape-ico
Facebook : www.facebook.com/humanscape
Twitter : twitter.com/Humanscape_io
Reddit : https://www.reddit.com/r/Humanscape_official
Bitcointalk announcement : https://bit.ly/2rVsP4T
Email : support@humanscape.io

--

--