개요
케창딥 11장에 나오는 Transformer Encoder 코드 학습 내용을 정리 합니다.
TransformerEncoder 클래스 개요
TransformerEncoder 는 다음과 같은 주요 단계들로 구성되어 있습니다:
- MultiHeadAttention
- Residual Connection 및 LayerNormalization
- Position-wise Feedforward Network
- 다시 Residual Connection 과 LayerNormalization
Transformer Encoder 의 하나의 블록을 구현하는 방식으로, 입력 시퀀스의 각 위치 간의 관계를 학습하는 데 사용됩니다.
__init__ 메서드
이 메서드는 클래스의 초기화 단계에서 필요한 하위 모듈들을 설정합니다.
- embed_dim: 입력의 임베딩 차원.
- dense_dim: 피드포워드 네트워크의 내부 레이어의 차원.
- num_heads: 멀티 헤드 어텐션의 헤드 수.
주요 하위 레이어 정의
- Multi-Head Attention (MultiHeadAttention)
- 입력 텐서의 다양한 부분 간의 관계를 동시에 모델링하기 위해 멀티 헤드 어텐션을 사용합니다.
- key_dim은 각 어텐션 헤드의 차원을 나타내며, 입력의 embed_dim과 동일합니다.
- Position-wise Feedforward Network (dense_proj)
- 첫 번째 Dense 레이어는 dense_dim 크기를 가지며, 비선형 활성화 함수 ReLU를 사용합니다.
- 두 번째 Dense 레이어는 다시 임베딩 차원 (embed_dim)으로 줄어듭니다.
- 이 네트워크는 시퀀스의 각 위치에 대해 독립적으로 작용합니다.
- Layer Normalization (layernorm_1과 layernorm_2)
- Normalization 를 통해 학습이 더 안정적으로 진행되도록 합니다.
- 각각 잔차 연결 후의 출력에 적용됩니다.
class TransformerEncoder(layers.Layer):
def __init__(self, embed_dim, dense_dim, num_heads, **kwargs):
super().__init__(**kwargs)
# 임베딩 차원, 피드포워드 네트워크 차원, 멀티 헤드 수 초기화
self.embed_dim = embed_dim
self.dense_dim = dense_dim
self.num_heads = num_heads
# 멀티 헤드 어텐션 레이어 생성
self.attention = layers.MultiHeadAttention(
num_heads=num_heads, key_dim=embed_dim)
# 피드포워드 네트워크로 구성된 Dense 레이어 시퀀스 생성
self.dense_proj = keras.Sequential(
[layers.Dense(dense_dim, activation="relu"), # 첫 번째 Dense 레이어 (ReLU 활성화 함수 사용)
layers.Dense(embed_dim),] # 두 번째 Dense 레이어 (출력 크기는 embed_dim)
)
# 두 개의 Layer Normalization 레이어 생성
self.layernorm_1 = layers.LayerNormalization()
self.layernorm_2 = layers.LayerNormalization()
def call(self, inputs, mask=None):
# 마스크가 주어진 경우 차원을 확장하여 어텐션 레이어에 맞게 변환
if mask is not None:
mask = mask[:, tf.newaxis, :]
# 멀티 헤드 어텐션 적용 (쿼리, 키, 값은 모두 입력으로 사용)
attention_output = self.attention(
inputs, inputs, attention_mask=mask)
# 어텐션 출력과 입력의 잔차 연결 후 Layer Normalization 적용
proj_input = self.layernorm_1(inputs + attention_output)
# 피드포워드 네트워크 적용
proj_output = self.dense_proj(proj_input)
# 피드포워드 출력과 이전 결과의 잔차 연결 후 Layer Normalization 적용
return self.layernorm_2(proj_input + proj_output)
def get_config(self):
# 객체를 직렬화하기 위해 필요한 구성 정보 반환
config = super().get_config()
config.update({
"embed_dim": self.embed_dim,
"num_heads": self.num_heads,
"dense_dim": self.dense_dim,
})
return config
TransformerEncoder 시각화
┌──────────┐
│ Output │
└─────▲────┘
│
┌─────┴────┐
│ Add & │
│ LayerNorm│ (Layer Normalization 2)
└─────▲────┘
│
┌─────┴────────────┐
│ Feedforward │
│ Dense Network │
│ [Dense (embed_dim)] │
│ [Dense (ReLU)] │
└─────▲────────────┘
│
┌─────┴────┐
│ Add & │
│ LayerNorm│ (Layer Normalization 1)
└─────▲────┘
│
┌─────┴──────────────┐
│ Multi-Head Attention│
│ [inputs -> Q, K, V] │
│ (Attention Weights) │
└─────▲──────────────┘
│
┌─────┴────┐
│ Input │
│ Tensor │
└──────────┘
각 블록의 설명
- Input Tensor
- Transformer 인코더 블록의 시작점입니다. 입력 데이터는 시퀀스 길이 N과 임베딩 차원 D를 가지는 텐서 형태로 들어옵니다.
- Multi-Head Attention
- 입력 텐서가 쿼리(Q), 키(K), 값(V)로 분리되어 멀티 헤드 어텐션 연산이 수행됩니다.
- 여러 헤드를 사용하여 서로 다른 관계를 학습하고, 어텐션 가중치를 통해 시퀀스 내 다른 위치 간의 연관성을 모델링합니다.
- Add & Layer Normalization 1
- 어텐션 출력에 원래 입력을 더한 뒤, 레이어 정규화를 수행합니다.
- 잔차 연결을 통해 정보가 보존되며 학습 안정성이 높아지고, Layer Normalization은 모델의 학습 효율성을 높입니다.
- Feedforward Dense Network
- 정규화된 출력은 포지션-와이즈 피드포워드 네트워크로 전달됩니다.
- 이 네트워크는 두 개의 Dense 레이어로 구성되며:
- 첫 번째 Dense 레이어에서 dense_dim 차원으로 확장한 뒤 ReLU 활성화 함수가 적용됩니다.
- 두 번째 Dense 레이어에서 다시 임베딩 차원 (embed_dim)으로 축소합니다.
- Add & Layer Normalization 2
- 피드포워드 네트워크의 출력에 이전 단계의 입력을 더한 뒤, 다시 한 번 레이어 정규화를 수행합니다.
- 잔차 연결과 Layer Normalization은 학습의 안정성을 보장하고, 더 깊이 있는 특징을 효과적으로 학습할 수 있도록 합니다.
- Output
- 최종 출력입니다. 이 출력은 다음 레이어로 전달될 수 있거나, 여러 인코더 블록이 쌓여 있을 경우 다음 인코더 블록의 입력으로 사용됩니다.
'AI > 아이펠_리서치' 카테고리의 다른 글
Transformer 를 사용한 seq2seq 모델 실습 (4) | 2024.11.27 |
---|---|
Transformer Decoder 구현 및 학습 (1) | 2024.11.26 |
KerasTuner 와 Tensorboard 로 HyperParameter 시각화하기 (1) | 2024.11.23 |
TensorFlow 사용자 정의 metric 만들기 (1) | 2024.11.17 |
CNN 과 RNN 대표 모델 (3) | 2024.11.09 |