2025.03.08
Chapter 7. Autoencoders, Image Augmentation
- 50. 오토 인코더
인코더와 디코더, 잠재변수
- 오토인코더는 입력과 출력이 동일하다.
- 자기 자신을 재생성하는 네트워크
- Latent Vector : 잠재변수. Encoder : 입력쪽, Decoder : 출력쪽.
- 인코더는 일종의 특징추출기 같은 역할
- 디코더는 압축된 데이터를 다시 복원하는 역할
MNIST 데이터
Tensorflow.datasets에 저장되어 있는 MNIST 데이터셋 호출
import tensorflow as tf
import numpy as np
(train_X, train_y), (test_X, test_y) = tf.keras.datasets.mnist.load_data()
train_X = train_X/255.0
test_X = test_X/255.0
print(train_X.shape, train_y.shape)
--------------------------------------------------------------------------
>>(60000, 28, 28) (60000,)
무슨 데이터인가 다시 확인해 보면..
import matplotlib.pyplot as plt
plt.imshow(train_X[0], cmap='gray')
plt.colorbar()
plt.title(f'label : {train_y[0]}')
plt.show()
인코더, 디코더, 잠재변수?
# layer 구성
# 모델 내에서 Flatten() layer 와와 동일한 역할할
train_X = train_X.reshape(-1, 28*28)
test_X = test_X.reshape(-1, 28*28)
model = tf.keras.Sequential([
tf.keras.layers.Dense(784, activation='relu', input_shape=(784,)),
tf.keras.layers.Dense(64, activation='relu'),
tf.keras.layers.Dense(784, activation='sigmoid')
])
model.compile(
optimizer = tf.keras.optimizers.Adam(),
loss = 'mse'
)
model.summary()
784 layer에서 64 layer로 갈 때, 64는 임의로 지정한 것.
학습진행
## 학습
model.fit(train_X, train_X, epochs=10, batch_size=256)
train_X 가 두 번 들어간다. 오토인코더는 자기 자신을 입력과 출력으로 가진다. 결국 잠재 vector는 입력을 대표하는 vector가 된다.
예측값 확인
import random
plt.figure(figsize=(4, 8))
for c in range(4):
plt.subplot(4, 2, c*2 + 1) # 홀수
rand_index = random.randint(0, test_X.shape[0]) # test_X.shape[0] = 10000
plt.imshow(test_X[rand_index].reshape(28, 28), cmap='gray')
plt.axis('off')
plt.subplot(4, 2, c*2 + 2) # 짝수
img = model.predict(np.expand_dims(test_X[rand_index], axis=0)) #batch 사이즈 추가
plt.imshow(img.reshape(28, 28), cmap='gray')
plt.axis('off')
print(f'rand_index : {rand_index}')
plt.show()
비슷한게 나오는 것 같다.
CNN으로 다시 진행
train_X = train_X.reshape(-1, 28, 28, 1)
test_X = test_X.reshape(-1, 28, 28, 1)
model = tf.keras.Sequential([
tf.keras.layers.Conv2D(filters=32, kernel_size=2, strides=(2,2), activation='relu', input_shape=(28, 28,1)),
tf.keras.layers.Conv2D(filters=64, kernel_size=2, strides=(2,2), activation='relu'),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(64, activation='relu'), #특성벡터가 되는 자리!!
tf.keras.layers.Dense(7*7*64, activation='relu'),
tf.keras.layers.Reshape(target_shape=(7, 7, 64)),
tf.keras.layers.Conv2DTranspose(filters=32, kernel_size=2, strides=(2,2), padding='same', activation='relu'),
tf.keras.layers.Conv2DTranspose(filters=1, kernel_size=2, strides=(2,2), padding='same', activation='sigmoid')
])
model.compile(optimizer=tf.optimizers.Adam(), loss='mse')
model.summary()
다시 학습 진행 (FIT)
model.fit(train_X, train_X, epochs=20, batch_size=256)
아까와 같이 예측한 후, 다시 사진으로 확인해 보면
plt.figure(figsize=(4, 8))
for c in range(4):
plt.subplot(4, 2, c*2 + 1) # 홀수
rand_index = random.randint(0, test_X.shape[0]) # test_X.shape[0] = 10000
plt.imshow(test_X[rand_index].reshape(28, 28), cmap='gray')
plt.axis('off')
plt.subplot(4, 2, c*2 + 2) # 짝수
img = model.predict(np.expand_dims(test_X[rand_index], axis=0)) #batch 사이즈 추가
plt.imshow(img.reshape(28, 28), cmap='gray')
plt.axis('off')
print(f'rand_index : {rand_index}')
plt.show()
비슷한 거 같다.. 사실
ReLu 말고 ELU 적용
ReLU : 음수 이하 값은 모두 0이다. 계산이 빠르나 음수 구간에서 뉴런이 죽는 문제(Vanishing Gradient) 발생 가능
ELU : 음수 값도 -1 이내의 범위에서 존재한다. ReLU 비해 계산이 느리나, 음수 구간에서도 뉴런이 죽지 않는다.
import math
x = np.arange(-5, 5, 0.01)
relu = [0 if z < 0 else z for z in x]
elu = [1.0 * (np.exp(z) - 1) if z < 0 else z for z in x]
plt.axvline(0, color='gray')
plt.plot(x, relu, 'r--', label='relu')
plt.plot(x, elu, 'g-', label='elu')
plt.legend()
plt.show()
위 모델(CNN)에 활성화 함수를 ReLU 대신 ELU 적용. 학습 및 예측 재진행
train_X = train_X.reshape(-1, 28, 28, 1)
test_X = test_X.reshape(-1, 28, 28, 1)
model = tf.keras.Sequential([
tf.keras.layers.Conv2D(filters=32, kernel_size=2, strides=(2,2), activation='elu', input_shape=(28, 28,1)),
tf.keras.layers.Conv2D(filters=64, kernel_size=2, strides=(2,2), activation='elu'),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(64, activation='relu'), #특성벡터가 되는 자리!!
tf.keras.layers.Dense(7*7*64, activation='relu'),
tf.keras.layers.Reshape(target_shape=(7, 7, 64)),
tf.keras.layers.Conv2DTranspose(filters=32, kernel_size=2, strides=(2,2), padding='same', activation='elu'),
tf.keras.layers.Conv2DTranspose(filters=1, kernel_size=2, strides=(2,2), padding='same', activation='sigmoid')
])
model.compile(optimizer=tf.optimizers.Adam(), loss='mse')
model.fit(train_X, train_X, epochs=20, batch_size=256)
plt.figure(figsize=(4, 8))
for c in range(4):
plt.subplot(4, 2, c*2 + 1) # 홀수
rand_index = random.randint(0, test_X.shape[0]) # test_X.shape[0] = 10000
plt.imshow(test_X[rand_index].reshape(28, 28), cmap='gray')
plt.axis('off')
plt.subplot(4, 2, c*2 + 2) # 짝수
img = model.predict(np.expand_dims(test_X[rand_index], axis=0)) #batch 사이즈 추가
plt.imshow(img.reshape(28, 28), cmap='gray')
plt.axis('off')
print(f'rand_index : {rand_index}')
plt.show()
뭐 큰 차이는 안 보인다. 조금 더 동일하게 보인다고 해야 하나?..
잠재변수 벡터 확보
latent_vector_model = tf.keras.Model(inputs=model.input, outputs=model.layers[3].output)
latent_vector = latent_vector_model.predict(train_X)
print(latent_vector.shape)
print(latent_vector[0])
from sklearn.cluster import KMeans
kmeans = KMeans(n_clusters=10, n_init=10, random_state=42)
kmeans.fit(latent_vector)
plt.figure(figsize=(12, 12))
for i in range(10):
images = train_X[kmeans.labels_ == i]
for c in range(10):
plt.subplot(10, 10, i*10+c+1)
plt.imshow(images[c].reshape(28,28), cmap='gray')
plt.axis('off')
plt.show()
t-SNE
- 고차원 벡터를 저차원으로 옮겨서 시각화에 도움을 주는 방법
- t - Stochastic Nearest Neighbor
- k-Means가 각 클러스터를 계산하기 위한 단위로 중심과 각 데이터의 거리를 측정한다면,
- t-SNE는 각 데이터의 유사도를 정의하고, 원래 공간에서의 유사도와 저차원 공간에서의 유사도가 비슷해지도록 학습
- 여기서 유사도가 수학적으로 확률로 표현됨
## t- SNE 수행
from sklearn.manifold import TSNE
tsne = TSNE(n_components=2, learning_rate=100, perplexity=15, random_state=0)
tsne_vector = tsne.fit_transform(latent_vector[:5000])
cmap = plt.get_cmap('rainbow', 10)
fig = plt.scatter(tsne_vector[:, 0], tsne_vector[:, 1], marker='.', c=train_y[:5000], cmap=cmap)
cb = plt.colorbar(fig, ticks=range(10))
n_clusters=10
tick_locs = (np.arange(n_clusters) + 0.5) * (n_clusters-1) / n_clusters
cb.set_ticks(tick_locs)
cb.set_ticklabels(range(10))
plt.show()
- manifold 모듈은 데이터의 비선형 구조를 보존하는 차원 축소 기법들을 제공. (여기선 64 채널 → 2 채널 축소)
- TSNE(n_components=2, ...) → 64차원 특징 벡터(latent_vector)를 2차원으로 축소
- n_components=2 → 최종적으로 2차원으로 변환하여 시각화
- learning_rate = 100 → t-SNE가 좌표를 조정하는 속도
- perplexity = 15 → 데이터 샘플 개수와 관련된 거리 기준 설정
- 값이 크면 전역적(전체적인) 구조를 고려
- 값이 작으면 국소적(근처 이웃 관계) 구조를 고려
- fit_transform() → latent_vector(64차원 벡터)를 2차원으로 변환
- latent_vector[:5000] → 메모리 부담을 줄이기 위해 처음 5000개 샘플만 사용
- 결과 tsne_vector의 크기는 (5000, 2)
- 즉, 5000개의 샘플이 각각 2차원 좌표로 변환됨
- plt.get_cmap('rainbow', 10)
- rainbow → 무지개 색상을 사용하여 0~9까지의 라벨을 구별할 수 있도록 설정
- 10 → 총 10개의 클래스를 표현하기 위한 색상 개수 지정
- plt.scatter(x, y, marker='.', c=라벨, cmap=색상맵)
- x=tsne_vector[:, 0] → 2차원으로 변환된 첫 번째 축 값
- y=tsne_vector[:, 1] → 2차원으로 변환된 두 번째 축 값
- marker='.' → 점 형태로 표시
- c=train_y[:5000] → 각 데이터의 실제 라벨 (0~9)을 색상으로 구분
- cmap=cmap → 미리 지정한 rainbow 색상 맵 사용
- plt.colorbar(fig, ticks=range(10))
- fig → scatter 그래프에 대해 색상 막대를 추가
- ticks=range(10) → 0~9까지의 숫자를 눈금(tick)으로 추가
- n_clusters=10 → 총 10개의 클러스터 (0~9 숫자)
- tick_locs → 눈금 위치를 균등하게 분포하도록 설정
- cb.set_ticks(tick_locs) → 색상 막대의 눈금 위치 조정
- cb.set_ticklabels(range(10)) → 눈금에 0~9까지의 숫자 표시
제일 큰 특징은 label 값을 사용하지 않았다.
'Bootcamp_zerobase > Image Augmentation' 카테고리의 다른 글
Image Augmentation #1 (0) | 2025.03.11 |
---|