인공신경망 중 이미지생성 모델, VAE을 GPT만 의존하면서 코딩해 볼 수 있는지 시도해 봄.
학습시키느라 시간은 오래 걸렸지만 정말 혼자 다 해줌.
3. VAE 모델 구성
VAE는 인코더와 디코더로 구성됩니다. 인코더는 입력 이미지를 잠재 벡터의 평균과 로그 분산으로 변환하고, 디코더는 이 잠재 벡터를 사용하여 이미지를 재구성합니다.
3.1 인코더 모델
from tensorflow.keras.layers import Input, Conv2D, Flatten, Dense, Lambda
from tensorflow.keras.models import Model
import tensorflow as tf
latent_dim = 2 # 잠재 공간의 차원
encoder_inputs = Input(shape=(28, 28, 1))
x = Conv2D(32, 3, activation="relu", strides=2, padding="same")(encoder_inputs)
x = Conv2D(64, 3, activation="relu", strides=2, padding="same")(x)
x = Flatten()(x)
x = Dense(16, activation="relu")(x)
z_mean = Dense(latent_dim)(x)
z_log_var = Dense(latent_dim)(x)
def sampling(args):
z_mean, z_log_var = args
batch = tf.shape(z_mean)[0]
dim = tf.shape(z_mean)[1]
epsilon = tf.keras.backend.random_normal(shape=(batch, dim))
return z_mean + tf.exp(0.5 z_log_var) epsilon
z = Lambda(sampling)([z_mean, z_log_var])
encoder = Model(encoder_inputs, [z_mean, z_log_var, z], name="encoder")
encoder.summary()
3.2 디코더 모델
from tensorflow.keras.layers import Reshape, Conv2DTranspose
latent_inputs = Input(shape=(latent_dim,))
x = Dense(7 7 64, activation="relu")(latent_inputs)
x = Reshape((7, 7, 64))(x)
x = Conv2DTranspose(64, 3, activation="relu", strides=2, padding="same")(x)
x = Conv2DTranspose(32, 3, activation="relu", strides=2, padding="same")(x)
decoder_outputs = Conv2DTranspose(1, 3, activation="sigmoid", padding="same")(x)
decoder = Model(latent_inputs, decoder_outputs, name="decoder")
decoder.summary()
4. VAE 모델 훈련
VAE의 손실 함수는 재구성 손실과 KL 발산을 포함해야 합니다.
class VAE(Model):
def init(self, encoder, decoder, **kwargs):
super(VAE, self).__init__(**kwargs)
self.encoder = encoder
self.decoder = decoder
def call(self, inputs):
z_mean, z_log_var, z = self.encoder(inputs)
reconstructed = self.decoder(z)
kl_loss = -0.5 * tf.reduce_mean(
z_log_var - tf.square(z_mean) - tf.exp(z_log_var) + 1)
self.add_loss(kl_loss)
return reconstructed
vae = VAE(encoder, decoder)
vae.compile(optimizer='adam', loss=tf.keras.losses.MeanSquaredError())
vae.fit(x_train, x_train, epochs=30, batch_size=128)
5. 이미지 생성 및 잠재 공간 시각화
훈련된 모델을 사용하여 새로운 이미지를 생성하고, 잠재 공간을 시각화하여 모델의 학습을 평가합니다.
이 과정을 따라하면 VAE를 이해하고 실제로 MNIST 데이터셋을 사용하여 손글씨 숫자 생성 모델을 실험해 볼 수 있습니다.
5번 단계에서는 훈련된 VAE 모델을 사용하여 새로운 이미지를 생성하고, 잠재 공간을 시각화하는 작업을 진행할 수 있습니다. 이를 위해 다음과 같은 세부 작업을 수행할 수 있습니다:
1. 이미지 생성
훈련된 VAE 모델의 디코더를 사용하여 임의의 잠재 벡터에서 이미지를 생성합니다. 잠재 공간에서 무작위로 포인트를 샘플링하여 디코더에 입력하고, 결과 이미지를 관찰합니다.
import matplotlib.pyplot as plt
def plot_images(images, title):
fig, axes = plt.subplots(1, len(images), figsize=(20, 4))
for img, ax in zip(images, axes):
ax.imshow(img.squeeze(), cmap='gray')
ax.axis('off')
plt.suptitle(title, size=16)
plt.show()
n = 10 # 이미지를 생성할 샘플 수
random_latent_vectors = tf.random.normal(shape=(n, latent_dim))
generated_images = decoder(random_latent_vectors)
plot_images(generated_images.numpy(), "Generated Images")
결과
=========
2. 잠재 공간 시각화
TensorFlow와 Keras라는 라이브러리를 사용하여 구현, MNIST 데이터셋 사용
TensorFlow: 구글에서 개발한 오픈 소스 머신 러닝 라이브러리로, 데이터 플로우와 다양한 수학적 연산을 위한 그래프를 구성하여 복잡한 연산을 쉽고 효율적으로 처리.
Keras: TensorFlow 위에서 동작하는 고수준 신경망 API로, 사용자가 쉽게 신경망 모델을 구축하고 실험할 수 있게 해주는 도구.
MNIST: 'Modified National Institute of Standards and Technology'의 약자로, 손으로 쓴 숫자들의 큰 데이터베이스. 주로 이미지 처리 시스템을 훈련시키는 데 사용
from tensorflow.keras.datasets import mnist
import numpy as np
import matplotlib.pyplot as plt
from tensorflow.keras.layers import Input, Conv2D, Flatten, Dense, Lambda, Reshape, Conv2DTranspose
from tensorflow.keras.models import Model
import tensorflow as tf
# 데이터셋 로드 시 y_test도 함께 로드합니다.
(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train = np.expand_dims(x_train, -1).astype("float32") / 255
x_test = np.expand_dims(x_test, -1).astype("float32") / 255
latent_dim = 2 # 잠재 공간의 차원
# 인코더 모델 구성
encoder_inputs = Input(shape=(28, 28, 1))
x = Conv2D(32, 3, activation="relu", strides=2, padding="same")(encoder_inputs)
x = Conv2D(64, 3, activation="relu", strides=2, padding="same")(x)
x = Flatten()(x)
x = Dense(16, activation="relu")(x)
z_mean = Dense(latent_dim)(x)
z_log_var = Dense(latent_dim)(x)
def sampling(args):
z_mean, z_log_var = args
batch = tf.shape(z_mean)[0]
dim = tf.shape(z_mean)[1]
epsilon = tf.keras.backend.random_normal(shape=(batch, dim))
return z_mean + tf.exp(0.5 z_log_var) epsilon
z = Lambda(sampling)([z_mean, z_log_var])
encoder = Model(encoder_inputs, [z_mean, z_log_var, z], name="encoder")
encoder.summary()
# 디코더 모델 구성
latent_inputs = Input(shape=(latent_dim,))
x = Dense(7 7 64, activation="relu")(latent_inputs)
x = Reshape((7, 7, 64))(x)
x = Conv2DTranspose(64, 3, activation="relu", strides=2, padding="same")(x)
x = Conv2DTranspose(32, 3, activation="relu", strides=2, padding="same")(x)
decoder_outputs = Conv2DTranspose(1, 3, activation="sigmoid", padding="same")(x)
decoder = Model(latent_inputs, decoder_outputs, name="decoder")
decoder.summary()
# VAE 모델 구성 및 훈련
class VAE(Model):
def init(self, encoder, decoder, **kwargs):
super(VAE, self).__init__(**kwargs)
self.encoder = encoder
self.decoder = decoder
def call(self, inputs):
z_mean, z_log_var, z = self.encoder(inputs)
reconstructed = self.decoder(z)
kl_loss = -0.5 * tf.reduce_mean(
z_log_var - tf.square(z_mean) - tf.exp(z_log_var) + 1)
self.add_loss(kl_loss)
return reconstructed
vae = VAE(encoder, decoder)
vae.compile(optimizer='adam', loss=tf.keras.losses.MeanSquaredError())
vae.fit(x_train, x_train, epochs=30, batch_size=128)
# 이미지 생성 및 플롯
def plot_images(images, title):
fig, axes = plt.subplots(1, len(images), figsize=(20, 4))
for img, ax in zip(images, axes):
ax.imshow(img.squeeze(), cmap='gray')
ax.axis('off')
plt.suptitle(title, size=16)
plt.show()
n = 10 # 이미지를 생성할 샘플 수
random_latent_vectors = tf.random.normal(shape=(n, latent_dim))
generated_images = decoder(random_latent_vectors)
plot_images(generated_images.numpy(), "Generated Images")
# 잠재 공간의 시각화
z_mean, , = encoder.predict(x_test, batch_size=128)
# y_test를 범주형 색상 레이블로 사용할 수 있도록 처리합니다.
y_test_categorical = np.argmax(y_test, axis=1)
plt.figure(figsize=(12, 10))
plt.scatter(z_mean[:, 0], z_mean[:, 1], c=y_test_categorical, cmap='viridis')
plt.colorbar()
plt.xlabel("z[0]")
plt.ylabel("z[1]")
plt.title("Latent Space Representation")
plt.show()
결과 : 방법을 변경했는데 유사한 결과가 나옴. 기대와 다른데 데이터 요소가 3차원을 가져오지 못할 수 있다는 생각이 듦.
—