숫자 생성 인공지능 만들기 : https://www.youtube.com/watch?v=PLIMEa5wkeA
GAN(Generative adversarial network, “갠” 또는 “간”이라고 읽음) – 적대적(대립적) 생성 신경망
숫자를 학습한 인공지능은 – 숫자 하나 써봐 – 숫자를 만들어 냄 : 첨에는 노이즈 값이 점점 숫자화 됨
생성자와 판별자는 서로 이기기 위해 학습 – 진짜 같은 그림 만들게 됨
from keras.models import Model, Sequential # GAN은 서로 다른 신경망(생성자, 판별자)이 필요하며 둘 다 시퀀셜 형태로 만듬 from keras.layers import Dense, Input, LeakyReLU # 레이어 도구 / 활성화(액티베이션) 함수 - LeakyReLU from keras.optimizers import Adam # 오차 줄이기 위해 경사하강법 from keras.datasets import mnist # 데이터셋 도구 중 mnist 데이터셋 불러오기 from tqdm import tqdm # 모델 학습을 시각적으로 보여주는 라이브러리 ex> 프로그레스바 import numpy as np import matplotlib.pyplot as plt
(x_train, y_train), (x_test, y_test) = mnist.load_data() # 데이터 불러오기 - 케라스에서 제공하는 mnist 데이터셋은 크게 4부분(1.2 : 훈련데이터 / 3.4 : 검증데이터) x_test = (x_test.astype(np.float32) - 127.5) / 127.5 # 레이블인 y_train은 이번엔 사용X / 정규화 # mnist 그림은 0 ~ 255 숫자로 되어 있어서 127.5를 뺀 후 127.5로 나누면 0은 -1로 / 255는 1로 바뀜 mnist_data = x_test.reshape(10000, 784) # 28x28을 한 줄(reshape)로 = 1열 784개로 늘여서 사용 print(mnist_data.shape) len(mnist_data)
생성자 신경망에 노이즈(아무런 의미 없는 수자)값 넣으면 -> 그럴듯한 숫자 이미지로 생성
def create_generator(): generator = Sequential() generator.add(Dense(units=256, input_dim=100)) # 입력 값 100 = 100(10x10)개의 픽셀은 노이즈 값 / 이 신경망의 첫 번째 층은 256개 노드로 구성되어 있음 generator.add(LeakyReLU(0.2)) # 첫번째 활성화 함수 사용. 음수 값의 기울기 0.2 generator.add(Dense(units=512)) # 두번째 층 512개 노드로 구성 generator.add(LeakyReLU(0.2)) generator.add(Dense(units=784, activation='tanh')) # 마지막 층 tanh 함수(다른 함수 사용 가능) 사용 # mnist 데이터가 28x28 픽셀로 되어 있으니 = 마지막 값은 784(1x784)가 되어야 함 return generator g = create_generator() g.summary()
판별자 신경망은 이미지를 만들어 내는 신경망이 아니라 생성자 신경망이 만든 이미지가 가짜인지 판별하는 신경망으로 훈련되지 않은 신경망
적대적 생성 신경망(GAN)을 통해 생성자 신경망과 지금 만드는 판별자 신경망을 학습시켜 나갈 예정
def create_discriminator(): discriminator = Sequential() discriminator.add(Dense(units=512, input_dim=784)) # 생성자가 만든 손글씨가 784개 픽셀로 구성되어 있기에 입력 값 784(28x28) / 첫 번째 층 512 노드(임의) discriminator.add(LeakyReLU(0.2)) discriminator.add(Dense(units=256)) discriminator.add(LeakyReLU(0.2)) discriminator.add(Dense(units=1, activation ='sigmoid')) # 최종 출력 값 1 = 진위 여부(진짜 1 or 가짜 0) discriminator.compile(loss='binary_crossentropy', optimizer = Adam(learning_rate=0.0002, beta_1=0.5)) # 오차(loss)는 이항 교차 엔트로피(binary_crossentropy = 2개 중에 1개) 사용 # GAN 만들려면 이전보다 조금 더 정교하게 옵티마이저 사용해야 함(학습 속도=학습률=0.0002 / 베타 최적 값 0.5) return discriminator d = create_discriminator() d.summary()
생성자 신경망과 판별자 신경망을 적절하게 학습시키기
def create_gan(discriminator, generator): # 재료(discriminator, generator) = 판별자, 생성자 둘 다 필요 discriminator.trainable = False # 판별자가 학습하지 못하도록 막아둠 gan_input = Input(shape=(100,)) # gan에 입력 데이터 모습 정하는 코드 = 입력 값 100개 # 콤마 뒤는 총 데이터 개수 넣기 위함 =비워두면 실제 데이터 개수(여기 선 10000개) 자동 넣어줌 x = generator(gan_input) # 생성자 신경망(generator)에게 바로 윗 줄에 작성한 픽셀 100개 값과 데이터의 전체 수(10000)만큼 데이터 넣음 gan_output = discriminator(x) # 생성자가 만든 X를 판별자 보고 판단해 보라고 시킴 gan = Model(inputs=gan_input, outputs=gan_output) # 모델 만들기 - 입력값(gan_inpu)은 노이즈 값 / 출력값(gan_output)은 판별자가 판단 결과 gan.compile(loss='binary_crossentropy', optimizer = 'Adam') # 신경망 오차 줄이기 return gan gan = create_gan(d, g) # 판별자 신경망 d, 생성자 신경망 g를 넣기 gan.summary()
분류나 예측은 정확도를 수치로 확인 가능 했으나, 적대적 생성 신경망에서는 판단을 사람이 할 수 있음 = 직접 눈으로 볼 수 있는 장치
def plot_generated_images(generator): # 그림을 그릴 때 어떤 생성자로 그릴지 알아야 해서 파라미터(generator) 1개 필요 noise = np.random.normal(loc=0, scale=1, size=[100, 100]) # 생성자에 넣어줄 노이즈 값 만들어주며, 규일한 값 생성할 수 있도록 넘파이 랜덤 값 생성. 정규 분포 함수 사용 # loc = 평균 0 / scale = 1는 평균에서 1만큼 씩 떨어진 값(-1 ~ 1) / [100, 100]는 노이즈 100개 생성 = 100개 그림 generated_images = generator.predict(noise) # generator도 신경망 모델이기에 predict 함수 사용 - 노이즈 값을 신경망에 넣어 값 예측하라 명령어 generated_images = generated_images.reshape(100, 28, 28) # generator가 예측값이 1x784기에 28x28의 그림 형태로 바꿔줌 plt.figure(figsize=(10, 10)) # 10x10 사이즈로 그림 그리기 for i in range(generated_images.shape[0]): # 100개 그림 그려주는 반복문 - 어떻게 화면에 표시할 것 인가 plt.subplot(10, 10, i+1) # 위치 정해줌 - 가로 10. 세로 10에 위치를 지정 plt.imshow(generated_images[i], interpolation='nearest') # imshow 함수는 이미지 출력하는 함수로 각 위치에 어떤 그림 넣을지 결정. plt.axis('off') # 그림 이름 넣지 않는다는 의미 plt.tight_layout()
batch_size = 128 # 한 번에 몇 개의 그림을 학습 시킬 것인지 128개 epochs = 5000 # 몇 번 반복 - 5천번 반복 for e in tqdm(range(epochs)): # 반복문과 tqdm 라이브러리를 사용해서 반복 학습 진행 / tqdm(range(epochs)) = 반복 횟수는 에포크 noise = np.random.normal(0, 1, [batch_size, 100]) # 생성자에게 노이즈 값 만듦 - 정규 분포 함수(균일값) # 평균 0 / 평균에서 1만큼 떨어진 값(-1 ~ 1) / batch_size 개수 만큼 생성(생성 데이터는 각각 숫자 100개씩 구성) generated_images = g.predict(noise) # 생성자 모델에 노이즈 입력하여 생성자 신경망이 그림 그린 후 결과 저장 image_batch = mnist_data[np.random.randint(low=0, high=mnist_data.shape[0], size=batch_size)] # 실제 데이터를 위해 범위 0개(low) ~ 10000개(mnist_data 데이터 수) 중에 배치 사이즈(128개)만큼 랜덤 뽑기 X = np.concatenate([image_batch, generated_images]) # 진짜 그림과 생성 그림 합치는 모습 - 한 줄 세우기 - (784 x 128) 2개를 한 줄로 = 784 x 256 y_dis = np.zeros(2*batch_size) # 판별자에게 전달할 결괏갑. 0이란 값 가진 배열 만들기(2*128) y_dis[:batch_size] = 1 # 이 값 중 앞에 128에는 실제 값 1을 넣어줌 = 앞 128은 진짜 1 / 뒤 128은 가짜 0 = 정답 알려줌 = 지도 학습 d.trainable = True # 판별자 학습 시키기 d.train_on_batch(X, y_dis) # 입력 데이터는 X고 출력 데이터는 y_dis임 noise = np.random.normal(0, 1, [batch_size, 100]) # 새롭게 노이즈 값 만들기 y_gen = np.ones(batch_size) # 새로운 노이즈 값은 다 1로 설정 d.trainable = False # 판별자가 더 이상 학습 못하게 함 = 생성자가 만든 게 진짜 인지 판별하는 역할만 함 gan.train_on_batch(noise, y_gen) # gan에게 노이즈 값 입력으로 넣고 출력값은 다 진짜(1)를 넣어서 학습 시킴 # 목표 값은 1인데 너무 가짜 같으면 판별자가 오류로 하고 그럼 생성자가 다시 학습함 = 최종 1 될 때 까지 if e == 0 or e % 1000 == 0 : # 에포크 별로 훈련을 잘 하는지 살펴보기 plot_generated_images(g)
판별자에게 입력데이터(X)를 주고 판별자를 통해 나온 출력값과 정답 데이터(y_dis)의 결과값을 비교하며 오차를 줄이는 방식으로 판별자 학습 시킴
[모두의 인공지능 with 파이썬] 첫째마당. 인공지능 개념 이해하기
[모두의 인공지능 with 파이썬] 둘째마당. 딥러닝 이해하기
[모두의 인공지능 with 파이썬] 셋째마당 인공지능 개발을 위한 파이썬 첫걸음
[모두의 인공지능 with 파이썬] 넷째마당 딥러닝 프로그래밍 시작하기 1
[모두의 인공지능 with 파이썬] 넷째마당 딥러닝 프로그래밍 시작하기 2 – 숫자 인식 인공지능 만들기