: U-Net은 오토인코더와 같은 인코더-디코더 기반 모델
오토인코더란?
💡 오토인코더? : 입력을 출력으로 복사하는 신경망 (딥러닝에서의 비지도 학습) → 네트워크에 여러가지 방법으로 제약을 줌으로써 어려운 신경망으로 만든다.오토인코더는 잠재 표현의 크기를 제한하거나(은닉층 뉴런의 수를 입력층 뉴런 수보다 작게 하는 방법) 입력값에 잡음을 추가하고 원본 입력값을 복원하도록 하는 등의 네트워크 훈련 방법을 사용해 데이터를 효율적으로 표현하는 방법(패턴이 있는 데이터)을 배운다. (어려운 신경망으로 만든다.)
→ 그 중 차원을 줄이는 방법
: 입력층보다 적은 수의 뉴런을 가진 은닉층을 중간에 넣어 줌으로써 차원을 줄인다. 이때 학습을 톻해 소실된 데이터를 복원하는데 이 과정을 통해 입력 데이터의 특징을 효율적으로 응축한 새로운 출력이 나오는 원리를 따른다.
⇒ 입력보다 훨씬 더 낮은 차원을 갖기 때문에 차원 축소와 시각화에 유용하게 사용된다. 입력이 저차원으로 표현되는 인코더구조를 Undercomplete Autoencoder라고 한다.
인코더-디코더 기반 모델의 문제
➡️ U-Net은 인코더-디코터 구조의 이런 정보 손실 회복 불가 문제를 해결하기 위해 고안된 모델
Details
Encoder
Decoder
# U-Net model
# coded by st.watermelon
import tensorflow as tf
from tensorflow.keras.layers import Conv2D, MaxPooling2D, Conv2DTranspose
from tensorflow.keras.layers import Activation, BatchNormalization, Concatenate
""" Conv Block """
class ConvBlock(tf.keras.layers.Layer):
def __init__(self, n_filters):
super(ConvBlock, self).__init__()
self.conv1 = Conv2D(n_filters, 3, padding='same')
self.conv2 = Conv2D(n_filters, 3, padding='same')
self.bn1 = BatchNormalization()
self.bn2 = BatchNormalization()
self.activation = Activation('relu')
def call(self, inputs):
x = self.conv1(inputs)
x = self.bn1(x)
x = self.activation(x)
x = self.conv2(x)
x = self.bn2(x)
x = self.activation(x)
return x
""" Encoder Block """
class EncoderBlock(tf.keras.layers.Layer):
def __init__(self, n_filters):
super(EncoderBlock, self).__init__()
self.conv_blk = ConvBlock(n_filters)
self.pool = MaxPooling2D((2,2))
def call(self, inputs):
x = self.conv_blk(inputs)
p = self.pool(x)
return x, p
""" Decoder Block """
class DecoderBlock(tf.keras.layers.Layer):
def __init__(self, n_filters):
super(DecoderBlock, self).__init__()
self.up = Conv2DTranspose(n_filters, (2,2), strides=2, padding='same')
self.conv_blk = ConvBlock(n_filters)
def call(self, inputs, skip):
x = self.up(inputs)
x = Concatenate()([x, skip])
x = self.conv_blk(x)
return x
""" U-Net Model """
class UNET(tf.keras.Model):
def __init__(self, n_classes):
super(UNET, self).__init__()
# Encoder
self.e1 = EncoderBlock(64)
self.e2 = EncoderBlock(128)
self.e3 = EncoderBlock(256)
self.e4 = EncoderBlock(512)
# Bridge
self.b = ConvBlock(1024)
# Decoder
self.d1 = DecoderBlock(512)
self.d2 = DecoderBlock(256)
self.d3 = DecoderBlock(128)
self.d4 = DecoderBlock(64)
# Outputs
if n_classes == 1:
activation = 'sigmoid'
else:
activation = 'softmax'
self.outputs = Conv2D(n_classes, 1, padding='same', activation=activation)
def call(self, inputs):
s1, p1 = self.e1(inputs)
s2, p2 = self.e2(p1)
s3, p3 = self.e3(p2)
s4, p4 = self.e4(p3)
b = self.b(p4)
d1 = self.d1(b, s4)
d2 = self.d2(d1, s3)
d3 = self.d3(d2, s2)
d4 = self.d4(d3, s1)
outputs = self.outputs(d4)
return outputs