9주차 - 19장 세상에 없는 얼굴 GAN, 오토인코더

김영기·2024년 1월 14일
0

생성적 적대 신경망 줄여서 GAN(간)이라고 부르는 알고리즘을 이용해 위와 같은 가상의 얼굴을 만들었다.

GAN 딥러닝의 원리를 활용해 가상 이미지를 생성하는 알고리즘
GAN은 적대적 경합을 통해 진짜 같은 가짜를 생성하는 원리

가짜를 만들어 내는 파트를 '생성자' 진위를 가려내는 파트를 '판별자'라고 한다.

1. 가짜 제조 공장, 생성자

생성자는 가상의 이미지를 만들어 내는 공장

DCGAN

생성자가 가짜 이미지를 만들 때 컨벌루션 신경망(CNN)을 이용한다.
풀링과정이 없는 대신 패딩과정이 포함된다.

패딩과정이 필요한 이유는 입력 크기와 출력 크기를 똑같이 맞춰주기 위해서
패딩을 사용하면 자동으로 크기를 확장해 주고, 확장된 공간에 0을 채워 넣는다

DCGAN에 필요한 옵션
배치 정규화 : 입력 데이터의 평균이 0 분산이 1이 되도록 재배치 하는 것
다음 층으로 입력될 값을 일정하게 재배치하는 역할을 한다.
케라스는 이를 위해 BatchNormalization()함수를 제공

생성자의 활성화 함수로는 ReLU()함수를 쓰고 판별자로 넘겨주기 전에 tanh()함수
tanh()함수를 쓰면 출력되는 값을 -1~1 사이로 맞출 수 있음.

코드

generator = Sequential() # 모델 이름을 generator로 정하고 Sequential() 함수를 호출
generator.add(Dense(12877, input_dim=100, activation=LeakyReLU(0.2))) ----- ➊
generator.add(BatchNormalization() ----- ➋
generator.add(Reshape((7, 7, 128))) ----- ➌
generator.add(UpSampling2D()) ----- ➍
generator.add(Conv2D(64, kernel_size=5, padding='same')) ----- ➎
generator.add(BatchNormalization()) ----- ➏
generator.add(Activation(LeakyReLU(0.2))) ----- ➐
generator.add(UpSampling2D()) ----- ➑
generator.add(Conv2D(1, kernel_size=5, padding='same', activation='tanh')) ----- ➒

1번 코드
generator.add(Dense(12877, input_dim=100, activation=LeakyReLU(0.2)))
128은 임의로 정한 노드의 수 충분한 노드면 ok
input_dim=100은 100차원 크기의 랜덤 벡터를 준비해 집어 넣으라는 의미

7X7을 사용한 이유
UpSampling2D()를 사용했다. 이미지의 크기를 2배로 늘려준다. 4와 8번 코드

DCGAN의 특징
작은 크기의 이미지를 점점 늘려 가면서 컨볼루션 층(5,9)을 지나치게 하는 것이 특징

3번 코드
generator.add(Reshape((7, 7, 128))) ----- ➌
컨벌루션 레이어가 받아들일 수 있는 형태로 바꾸어 주는 코드

4,5 8,9는 두 배씩 업(up)샘플링을 한 후 컨볼루션 과정을 처리합니다.
1과 7번 코드에서 LeakyReLU(리키렐루) 사용
2, 6에서는 데이터의 배치를 정규 분포로 만드는 배치 정규화
9에서는 한 번 더 컨볼루션 과정을 거친 후 판별자로 값을 넘길 준비를 끝냄.

2. 진위를 가려내는 장치, 판별자

판별자를 만들어보자
생성자에서 넘어온 이미지가 가짜인지 진짜인지 판별해주는 장치

판별자가 얻은 가중치는 판별자 자신이 학습하는데 쓰이는 것이 아닌 생성자로 넘겨주어 생성자가 업데이트된 이미지를 만들도록 해야한다.

판별자를 만들 때는 가중치를 저장하는 학습 기능을 꺼줘야한다.

코드

#모델 이름을 discriminator로 정하고 Sequential() 함수를 호출합니다.
discriminator = Sequential()
discriminator.add(Conv2D(64, kernel_size=5, strides=2, input_shape=(28,28,1), padding="same")) ----- ➊
discriminator.add(Activation(LeakyReLU(0.2))) ----- ➋
discriminator.add(Dropout(0.3)) ----- ➌
discriminator.add(Conv2D(128, kernel_size=5, strides=2, padding="same")) ----- ➍
discriminator.add(Activation(LeakyReLU(0.2))) ----- ➎
discriminator.add(Dropout(0.3)) ----- ➏
discriminator.add(Flatten()) ----- ➐
discriminator.add(Dense(1, activation='sigmoid')) ----- ➑
discriminator.compile(loss='binary_crossentropy', optimizer='adam') ----- ➒
discriminator.trainable = False ----- ➓

1,4를 보면 노드의 수는 각각 64개 128개로 정했고, 커널의 크기는 5로 설정해 5X5 커널이 사용됨

strides는 커널 윈도를 몇 칸씩 이동시킬지 정하는 옵션
새로운 필터를 적용한 효과가 생기는 것과 같음.

strides나 드롭아웃(3,6) 등 차원을 줄여주는 기능을 적극적으로 사용하면서 컨볼루션 신경망 본래의 목적을 달성하자

2,5는 LeakyReLU() 사용
7,8은 2차원 과정을 1차원으로 바꿔주는 Flatten()함수와 sigmoid()함수를 사용하는 과정
9에서는 이진 로스 함수, 최적화 함수(adam)
10에서는 판별자 자신이 학습되지 않게끔 학습기능을 꺼 줍니다.

3. 적대적 신경망 실행하기

profile
안녕하세요

0개의 댓글