3. 첫 번째 GAN
GAN 구조를 만드려면 세 가지 핵심 클래스를 작성해야 한다. 첫째, 판별기 discriminator 가 필요하다. 판별기는 입력이 특정 계급에 속하는지 아닌지를 결정하는 데 중점을 둔 아키텍처다.
Discriminator 기저 클래스
Discriminator 클래스의 핵심 구조는 다음과 같다.
class Discriminator(object):
# 변수 초기화
def __init__ (self, width=28, height=28, channels=1, latent_size=100):
# 이진 분류기를 만들어 반환한다.
def model (self):
return model
# 모델을 요약한 내용을 화면에 인쇄한다.
def summary (self):
# 모델 구조를 데이터 폴더의 파일로 저장한다.
def save_model (self):
판별기, 생성기 및 GAN 구조 자체는 동일한 네 가지 공통 메서드를 공유한다.
- init : 개체를 사용하는 동안에도 사용할 수 있어야 하는 변수를 초기화한다. 또한 기본 기능을 실행해 내부 메서드를 초기화할 수 있다.
- model : 특정 계급을 표현하는 심층 신경망을 만든다. 판별기의 경우 단순한 이진 분류 유형의 신경망이다.
- summary : 모델을 요약한 내용을 인쇄하기 위한 간단한 래퍼
- save_model : 모델 구조의 사진을 저장한다.
Generator 기저 클래스
class Generator(object):
# 변수를 초기화한다.
def __init__(self, width=28, height=28, channels=1, latent_size=100):
# 생성기 모델을 구축해 반환
def model (self):
return model
# 모델을 요약한 내용을 화면에 인쇄한다.
def summary (self):
# 모델 구조를 데이터 폴더의 파일로 저장한다.
def save_model (self):
주요 차이점은 init 문과 model 문, 생성기는 간단한 순차 모델 sequential model 이다. 순차 모델이란 단지 신경망에서 계층들을 순서대로 함께 구성하고 연결하는 방법을 나타낸다.
GAN 기저 클래스
마지막으로 생성기과 판별기를 하나의 모델로 연결한다.
class GAN(object):
# 변수를 초기화한다.
def __init__ (self, discriminator_model, generator_model):
# 적대 모델을 구축하고 반환한다.
def model (self):
return model
# 모델을 요약한 내용을 화면에 인쇄한다.
def summary (self):
# 모델 구조를 데이터 폴더의 파일로 저장한다.
def save_model (self):
위 스켈레톤 클래스는 각 모델 유형의 유사한 구조가 서로 상대적으로 알기 위한 것
첫 번째 GAN 구성요소 판별기
초기화 변수 (판별기 클래스 내의 init)
init에서 초기화되는 변수 및 수량을 선택하는 과정이 중요하다. 다음과 같이 모델의 용량, 입력 모양, 최적화기 초기화 및 모델 구축이 필요하다.
#너비, 높이, 채널 및 잠재 공간 크기가 있는 클래스의 초기화
class Discriminator(obejct):
def __init__(self, width=28, height=28, channels=1, latent_size=100:
# 입력 인수들을 클래스의 내부 변수로 추가한다.
self.CAPACITY = width*height*channels
self.SHAPE = (width,height,channels)
self.OPTIMIZER = Adam(lr=0.0002, decay=8e-9)
# 이 레시피의 뒷부분에서 정의할 메서드에 따라 모델을 초기화한다.
self.Discriminator = self.model()
# binary_crossentropy 손실과 지정된 최적화기를 사용해 모델을 컴파일한다.
self.Discriminator.compile(loss='binary_crossentropy', optimizer=self.OPTIMIZER, metrics=['accuracy'] )
# 터미널에 모델의 텍스트 요약을 표시한다.
self.save_model()
self.summary()
여기선 내장된 손실 함수를 사용했지만, 향후 사용자 정의 손실 함수 등을 사용할 수 있다.
판별기에 대한 모델 정의
판별기 모델을 이진 분류기 구조로 정의
# 이 메서드는 순차적 모델로 시작된다. 이렇게 하면 계층들을 서로 쉽게 접합할 수 있다.
# 케라스는 처리 도중에 몇 가지 가정을 하는데, 예를 들면 이전 계층의 크기가 처리 진행 중인 계층의 입려고가 같다는 식이다.
def model(self):
model = Sequential()
# 데이터를 단일 데이터 스트림으로 전개한다.
model.add(Flatten(input_shape=self.SHAPE))
#
model.add(Dense(self.CAPACITY, input_shape=self.SHAPE))
model.add(LeakyReLU(alpha=0.2))
#
model.add(Dense(int(self.CAPACITY/2)))
model.add(LeakyReLU(alpha=0.2))
# 마지마긍로 확률을 출력
model.add(Dense(1, activation='sigmoid'))
return model
dense layer 란 각 뉴런들이 이전 계층의 뉴런들과 서로 모두 완전히 연결된 계층을 말한다.
모델을 구축하고 나면 메서드가 모델을 반환한다.
판별기 클래스의 도우미 메서드
구조에 대한 주요 정볼르 이해할 수 있는 메서드가 있다.
# 모델을 출력한다.
def summary(self):
return self.Discriminator.summary()
# 모델 구조를 이미지로 출력한다.
def save_model(self):
plot_model(self.Discriminator.model, to_file='/data/Discriminator_Model.png')
두 번째 GAN 구성요소인 생성기 설명
생성기 generator 는 잠재 공간에서 입력 내요을 가져 와서 사실적으로 보이는 데이터를 생성한다. 생성기는 또한 훈련 시 적대적인 부분에 추가될 것이다.
생성기 초기화
Generator 클래스에는 입력 데이터의 너비, 높이 및 채널과 같은 몇 가지 입력 변수가 있어야 한다. 잠재 공간은 또한 우리가 표본추출을 할 분포의 크기와 신경망의 측면을 정의하는 데 도움이 되므로 중요하다.
class Generator(object):
def __init__(self, width = 28, height= 28, channels = 1, latent_size=100):
self.W = width
self.H = height
self.C = channels
self.OPTIMIZER = Adam(lr=0.0002, decay=8e-9)
self.LATENT_SPACE_SIZE = latent_size
self.latent_space = np.random.normal(0,1,(self.LATENT_SPACE_SIZE,))
self.Generator = self.model()
self.Generator.compile(loss='binary_crossentropy', optimizer=self.OPTIMIZER)
self.save_model()
self.summary()
변수 중 몇 가지는 같은 클래스 내에서 정의된다. 최적화기들이 인스턴스화되고 잠재 공간이 정의된다. 마지막으로 object가 호출될 때마다 자체적으로 구축되고 컴파일되기를 바란다. object가 완성되면, object는 이 단계들을 거치면서 구축한 모델을 요약해 표시해 줄 것이다.
생성기의 모델 정의
모델은 이러한 각 클래스의 핵심이다. 우리는 잠재 공간에서 표본을 입력으로 사용해 원본 이미지와 동일한 모양의 이미지를 생성하는 모델을 정의하고 있다. 이 모델을 나타내는 코드를 확인
# 먼저 모델을 정의하고 기본 Sequential 구조로 시작
def model(self, block_starting_size=128,num_blocks=4):
model = Sequential()
# 신경망의 첫 블록을 시작한다.
block_size = block_starting_size
model.add(Dense(block_size, input_shape=(self.LATENT_SPACE_SIZE,)))
model.add(LeakyReLU(alpha=0.2))
model.add(BatchNormalization(momentum=0.8))
# 가장 까다로운 부분
for i in range(num_blocks-1):
block_size = block_size * 2
model.add(Dense(block_size))
model.add(LeakyReLU(alpha=0.2))
model.add(BatchNormalization(momentum=0.8))
#출력을 입력 이미지와 동일한 모양으로 재구성해 모델을 반환한다.
model.add(Dense(self.W * self.H * self.C, activation='tanh'))
model.add(Reshape((self.W, self.H, self.C)))
return model
2. 잠재 표본의 입력 모양이자 초기 블록 크기의 시작 크기에 맞춰 신경망에 조밀 계층을 추가한다. 이 경우 128개의 뉴런으로 시작한다.
3. 이전 블록과 같은 추가 블록을 추가할 수 있지만 조밀 계층 크기를 두 배로 만든다.
4. 출력을 입력 이미지와 동일한 모양으로 재구성해 모델을 반환한다.
생성기의 메서드
def summary(self):
return self.Generator.summary()
def save_model(self):
plot_model(self.Generator.model, to_file='/data/Generator_Model.png')
GAN의 모든 부분을 종합하기
생성기와 판별기를 지니고 난 후 적대 모델까지 만들어야 한다. 또한 더 복잡한 모델을 다뤄야 할 경우 손실 함수를 직접 정의해야 한다. 지금은 기본 GAN에 대해서만 집중
작동 방식
생성적 적대 모델은 이 Discrimimnator 와 Generator를 입력으로 두 모델을 가지고 잠재 사례를 입력으로 삼아 훈련할 수 있게 결함이 된 모델이다.
1단계 : GAN 클래스 초기화
def __init__(self,discriminator,generator):
self.OPTIMIZER = Adam(lr=0.0002, decay=8e-9)
self.Generator = generator
self.Discriminator = discriminator
self.Discriminator.trainable = False
self.gan_model = self.model()
self.gan_model.compile(loss='binary_crossentropy', optimizer=self.OPTIMIZER)
self.save_model()
self.summary()
이 코드를 살펴보면 판별기 모델과 생성기 모델을 모두 포함하고 있다. 그런 다음에 판별기의 훈련 가능성을 False로 설정하는데, 이는 적대 훈련을 하는 중에는 판별기가 훈련이 되지 않게 하겠다는 뜻이다. 이에 따라 생성기는 지속적으로 개선되지만 판별기는 원래대로 유지된다.
2단계: 모델 정의
def model(self):
model = Sequential()
model.add(self.Generator)
model.add(self.Discriminator)
return model
생성기를 첫 번째 부분으로 삼고 판별기를 두 번째 부분으로 삼은 순차 모델을 구성해 사용한다. 그런 다음 GAN 모델은 잠재 표본을 채취하여 해당 계급에 속하는지 여부에 관한 확률을 산출한다.
첫 GAN의 훈련
클래스의 init 메서드