[AI/Hands-on ML] - [핸즈온 머신러닝] 17장 - 오토인코더와 GAN을 사용한 표현 학습과 생성적 학습
17. 4 합성곱 오토인코더, Convolutional AutoEncoder
이미지를 다룰 때는, 합성곱 신경망이 밀집 네트워크보다 잘 맞음
-> 이미지에 대한 오토인코더를 위한 합성곱 오토인코더
인코더는 합성곱 층과 풀링 층으로 구성된 일반적인 CNN
- 입력에서 공간 방향의 차원(높이, 너비)를 줄이고, 특성 맵의 개수(깊이)를 늘림
디코더는 반대로 동작
- 이미지의 스케일을 늘리고, 깊이를 원본 차원으로 되돌림
-> 전치 합성곱 층 사용
패션 MNIST 데이터셋에 대한 합성곱 오토인코더
conv_encoder = keras.models.Sequential([
keras.layers.Reshape([28, 28, 1], input_shape=[28, 28]),
keras.layers.Conv2D(16, kernel_size=3, padding="SAME", activation="selu"),
keras.layers.MaxPool2D(pool_size=2),
keras.layers.Conv2D(32, kernel_size=3, padding="SAME", activation="selu"),
keras.layers.MaxPool2D(pool_size=2),
keras.layers.Conv2D(64, kernel_size=3, padding="SAME", activation="selu"),
keras.layers.MaxPool2D(pool_size=2)
])
conv_decoder = keras.models.Sequential([
keras.layers.Conv2DTranspose(32, kernel_size=3, strides=2, padding="VALID", activation="selu",
input_shape=[3, 3, 64]),
keras.layers.Conv2DTranspose(16, kernel_size=3, strides=2, padding="SAME", activation="selu"),
keras.layers.Conv2DTranspose(1, kernel_size=3, strides=2, padding="SAME", activation="sigmoid"),
keras.layers.Reshape([28, 28])
])
conv_ae = keras.models.Sequential([conv_encoder, conv_decoder])
17. 5 순환 오토인코더, Recurrent AutoEncoder
비지도 학습이나 차원 축소를 위해, 시계열이나 텍스트와 같은 시퀀스에 대한 오토인코더를 만들때는 순환 신경망 사용
인코더는 일반적으로 입력 시퀀스를 하나의 벡터로 압축하는 시퀀스-투-벡터 RNN
디코더는 반대로 벡터-투-시퀀스 RNN
순환 오토인코더
recurrent_encoder = keras.models.Sequential([
keras.layers.LSTM(100, return_sequences=True, input_shape=[28, 28]),
keras.layers.LSTM(30)
])
recurrent_decoder = keras.models.Sequential([
keras.layers.RepeatVector(28, input_shape=[30]),
keras.layers.LSTM(100, return_sequences=True),
keras.layers.TimeDistributed(keras.layers.Dense(28, activation="sigmoid"))
])
recurrent_ae = keras.models.Sequential([recurrent_encoder, recurrent_decoder])
recurrent_ae.compile(loss="binary_crossentropy", optimizer=keras.optimizers.SGD(0.1),
metrics=[rounded_accuracy])
- 타임 스텝마다 28차원을 갖는 어떤 길이의 시퀀스로 처리 가능
=> 각 이미지를 행의 시퀀스로 간주해, 패션 MNIST 이미지를 처리할 수 있음
- 각 타임 스텝에서 이 RNN은 28픽셀의 행 하나를 처리
- 타임 스텝마다 입력 벡터를 주입하기 위해, 디코더의 첫 번째 층에 RepeatVector 층 사용
지금까지 오토인코더가 흥미로운 특성을 학습하도록 하기 위해 코딩 층의 크기를 제한하여 과소완전으로 만듦
-> 입력 크기 또는 입력보다 큰 코딩 층을 두어 과대완전 오토인코더를 만들 수 있음
17. 6 잡음 제거 오토인코더, Stacked Denoising AutoEncoder
오토인코더가 유용한 특성을 학습하도록 강제하는 방법으로, 입력에 잡음을 추가하고 잡음이 없는 원본 입력을 복원하도록 훈련할 수 있음
- 1980년대부터 있었던 아이디어로, 2010년 파스칼 빈센트의 논문에서 적층 잡음 제거 오토인코더가 소개
잡음은 입력에 추가된 순수한 가우시안 잡음이거나, 드롭아웃처럼 무작위로 입력을 꺼서 발생시킬 수 있음
인코더의 입력에 적용한 Dropout 층이 있는 (또는 GaussianNoise층 사용) 적층 오토인코더
denoising_encoder = keras.models.Sequential([
keras.layers.Flatten(input_shape=[28, 28]),
keras.layers.GaussianNoise(0.2), # Dropout 층 사용시 keras.layers.Dropout(0.5)
keras.layers.Dense(100, activation="selu"),
keras.layers.Dense(30, activation="selu")
])
denoising_decoder = keras.models.Sequential([
keras.layers.Dense(100, activation="selu", input_shape=[30]),
keras.layers.Dense(28 * 28, activation="sigmoid"),
keras.layers.Reshape([28, 28])
])
denoising_ae = keras.models.Sequential([denoising_encoder, denoising_decoder])
- Dropout 층 또는 GaussianNoise 층은 훈련하는 동안에만 활성화됨
잡음 섞인 이미지와 드롭아웃 기반의 잡음 제거 오토인코더로 재구성한 이미지
- 네 번째 이미지의 목 부분 같이 실제 입력에 없는 정보를 추측하는 모습
- 다른 오토인코더처럼 잡음 제거 오토인코더를 데이터 시각화나 비지도 사전훈련을 위해 사용할 뿐만 아니라, 이미지에서 잡음을 제거하는 데 사용할 수 있음
- Denoising Autoencoder로 학습했을때의 필터가 좀더 edge detector의 모습을 보임
- 반면에 기존의 Autoencoder는 아직 노이즈에 가까운 모습
-> 성능이 향상된 모습
17. 7 희소 오토인코더, Sparse AutoEncoder
좋은 특성을 추출하도록 만드는 다른 제약의 방식, 희소
- 비용 함수에 적절한 항을 추가해, 오토인코더가 코딩 층에서 활성화되는 뉴런 수를 감소시키도록 만듦
- ex. 코딩 층에서 평균 5% 뉴런만 활성화되도록 강제
-> 이렇게 하면, 오토인코더가 적은 수의 활성화된 뉴런을 조합해 입력을 표현해야 함
- 따라서 코딩 층의 각 뉴런은 유용한 특성을 표현하게 됨
희소를 구현하는 간단한 방법
- 코딩을 0~1 사이 값으로 제한하기 위해 시그모이드 활성화 함수 사용
- 300개 유닛을 가진 층 같이 큰 코딩 층 사용
- 코딩 층의 활성화 값에 l1 규제 추가
sparse_l1_encoder = keras.models.Sequential([
keras.layers.Flatten(input_shape=[28, 28]),
keras.layers.Dense(100, activation="selu"),
keras.layers.Dense(300, activation="sigmoid"),
keras.layers.ActivityRegularization(l1=1e-3) # Alternatively, you could add
# activity_regularizer=keras.regularizers.l1(1e-3)
# to the previous layer.
])
sparse_l1_decoder = keras.models.Sequential([
keras.layers.Dense(100, activation="selu", input_shape=[300]),
keras.layers.Dense(28 * 28, activation="sigmoid"),
keras.layers.Reshape([28, 28])
])
sparse_l1_ae = keras.models.Sequential([sparse_l1_encoder, sparse_l1_decoder])
- ActivityRegularization 층은 입력을 그대로 반환하면서 훈련 손실에 입력의 절대값의 합을 더함
-> 이 규제는 신경망이 0에 가까운 코딩을 만들도록 유도하지만, 입력을 올바르게 재구성하지 못하면 벌칙을 받기 때문에 적어도 0이 아닌 값이 조금은 출력되어야 함
- l2노름 대신 l1 노름을 사용해 신경망이 입력 이미지에서 불필요한 것을 제거하고 가장 중요한 코딩을 보전하도록 만듦
희소 손실을 사용하는 방법
훈련마다 코딩 층의 실제 희소 정도를 측정하고, 희소 정도가 타깃 희소 정도와 다르면 모델에 벌칙 부과
- 전체 훈련 배치에 대해 코딩 층에 있는 각 뉴런의 평균적인 활성화를 계산해야함
각 뉴런에 대한 평균 활성화 정도를 알면, 비용 함수에 희소 손실을 추가해 너무 활성화되거나 충분히 활성화되지 않은 뉴런에 벌칙을 가할 수 있음
- ex. 한 뉴런의 평균 활성화가 0.3이고, 목표 희소 정도가 0.1이라면, 이 뉴런은 덜 활성화되도록 규제해야 함
-> 비용 함수에 제곱 오차 (0.3-0.1)^2 추가
-> 더 좋은 방법은, 평균 제곱 오차보다 더 강한 그래디언트를 가진 쿨백-라이블러 발산 사용
쿨백-라이블러 발산
두 개의 이산 확률 분포 P와 Q가 주어졌을 때, 이 두 분산 사이의 KL 발산 DKL(P||Q) 계산
- 여기서는 코딩 층에서 뉴런이 활성화 될 목표 확률 p와 실제 확률 q(훈련 배치에 대한 평균 활성화) 사이의 발산을 측정
코딩 층의 각 뉴런에 대해 희소 손실을 계산하고, 이 손실들을 모두 합해 비용 함수의 결과에 더함
- 희소 손실과 재구성 손실의 상대적 중요도를 제어하기위해 희소 손실에 희소 가중치 하이퍼파라미터를 곱함
-> 이 가중치가 너무 크면, 모델이 목표 희소에 가까워지지만, 입력을 적절히 재구성하지 못할 수 있음
-> 반대로 너무 작으면, 모델이 희소 목표를 무시해 흥미로운 특성을 학습하지 못함
KL 발산 기반의 희소 오토인코더 구현
KL 발산 규제를 적용하기 위한 사용자 정의 규제
K = keras.backend
kl_divergence = keras.losses.kullback_leibler_divergence
class KLDivergenceRegularizer(keras.regularizers.Regularizer):
def __init__(self, weight, target=0.1):
self.weight = weight
self.target = target
def __call__(self, inputs):
mean_activities = K.mean(inputs, axis=0)
return self.weight * (
kl_divergence(self.target, mean_activities) +
kl_divergence(1. - self.target, 1. - mean_activities))
코딩 층의 활성화에 KLDivergenceRegularizer을 적용해 희소 오토인코더 구성
kld_reg = KLDivergenceRegularizer(weight=0.05, target=0.1)
sparse_kl_encoder = keras.models.Sequential([
keras.layers.Flatten(input_shape=[28, 28]),
keras.layers.Dense(100, activation="selu"),
keras.layers.Dense(300, activation="sigmoid", activity_regularizer=kld_reg)
])
sparse_kl_decoder = keras.models.Sequential([
keras.layers.Dense(100, activation="selu", input_shape=[300]),
keras.layers.Dense(28 * 28, activation="sigmoid"),
keras.layers.Reshape([28, 28])
])
sparse_kl_ae = keras.models.Sequential([sparse_kl_encoder, sparse_kl_decoder])
패션 MNIST에 희소 오토인코더를 훈련한 후 코딩 층에 있는 뉴런의 활성화가 거의 0에 가까워짐
- 전체 활성화의 약 70%가 0.1보다 작음
- 전체 뉴런의 약 90%가 0.1~0.2 사이의 평균 활성화를 가짐
[AI/Hands-on ML] - [핸즈온 머신러닝] 17장(3) - 변이형 오토인코더, Variational AutoEncoder
'AI > Hands-on ML' 카테고리의 다른 글
[핸즈온 머신러닝] 17장(3) - 변이형 오토인코더, Variational AutoEncoder (0) | 2021.05.19 |
---|---|
[핸즈온 머신러닝] 17장(1) - 오토인코더와 GAN을 사용한 표현 학습과 생성적 학습 (0) | 2021.05.17 |
[핸즈온 머신러닝] 15장(2) - RNN과 CNN을 사용해 시퀀스 처리하기 (긴 시퀀스) (0) | 2021.04.27 |
[핸즈온 머신러닝] 15장(1) - RNN과 CNN을 사용해 시퀀스 처리하기 (0) | 2021.04.26 |
[핸즈온 머신러닝] 14장(4) - CNN을 통한 위치 추정, 객체 탐지, 시맨틱 분할 (1) | 2021.04.06 |