Boostcamp AI Tech (Day 008)
1. assignment #2 풀이
입력층, 하나의 은닉층(hidden layer), 그리고 출력층으로 구성된다.
1. 클래스 초기화 및 파라미터 초기화
클래스 TwoLayerNN
는 초기화 메서드 __init__
와 파라미터 초기화 메서드 initialize_parameters
를 가지고 있다.
-
__init__
메서드: 신경망의 입력 차원(input_dim
), 은닉 유닛의 수(num_hiddens
), 그리고 클래스의 수(num_classes
)를 초기화하고, 이들을 바탕으로 신경망의 가중치와 bias를 초기화한다. -
initialize_parameters
메서드: Xavier Initialization 방법을 이용해 가중치와 바이어스를 초기화한다. Xavier 초기화는 각 가중치가 정규분포를 따르도록 초기화하여 학습이 잘 진행되도록 돕는다.
2. Forward Pass
Forward pass는 입력 데이터를 신경망에 통과시켜 예측값을 생성하는 과정이다.
forward
메서드에서는 입력 데이터X
를 은닉층과 출력층에 통과시켜 최종 예측y
를 계산한다.- 입력 데이터
X
는 첫 번째 가중치(W1
)와 바이어스(b1
)에 의해 변환된 후, 시그모이드(sigmoid) 활성화 함수를 거쳐 은닉층의 출력을 생성한다. - 이 출력은 다시 두 번째 가중치(
W2
)와 바이어스(b2
)에 의해 변환되고, 마지막으로 소프트맥스(softmax) 함수를 통해 최종 예측 확률이 계산된다. - 이 과정에서
ff_dict
라는 딕셔너리에 중간 값들을 저장하여 나중에 역전파(backpropagation) 과정에서 사용할 수 있도록 한다.
3. Backward Pass (Backpropagation)
Backward pass는 예측값과 실제값의 차이를 기반으로 가중치와 바이어스를 업데이트하는 과정이다.
backward
메서드는 신경망의 각 파라미터에 대한 그라디언트(gradient)를 계산합니다. 이 그라디언트를 사용해 파라미터를 업데이트하면 신경망이 예측을 점점 더 정확하게 하도록 학습한다.- 그라디언트는 체인 룰(chain rule)을 사용하여 출력층부터 역순으로 계산된다. 이 과정에서 앞서 저장한
ff_dict
의 값들이 사용된다.
4. 파라미터 업데이트 (Gradient Descent)
Gradient Descent는 가중치와 바이어스를 업데이트하는 최적화 기법이다.
train_step
메서드는 학습률(lr
)을 사용해 계산된 그라디언트를 바탕으로 가중치와 바이어스를 업데이트한다. 신경망이 점차적으로 더 나은 예측을 하게 된다.
5. 손실 함수 및 정확도 평가
신경망의 성능을 평가하기 위해 손실 함수와 정확도를 계산한다.
-
compute_loss
메서드는 예측값과 실제값 간의 엔트로피 손실(cross-entropy loss)을 계산한다. 이 값은 모델이 얼마나 잘 예측하고 있는지 나타낸다. -
evaluate
메서드는 신경망의 분류 정확도를 계산합니다. 이는 모델이 얼마나 정확하게 클래스를 예측하고 있는지를 퍼센트로 나타낸다.
6. 모델 학습
Training은 신경망이 주어진 데이터를 학습하도록 만드는 과정이다.
train
메서드는 주어진 학습 데이터와 검증 데이터에 대해 여러 번의 반복(에포크)을 통해 모델을 학습시킨다. 이 과정에서 미니 배치 경사 하강법(mini-batch gradient descent)을 사용하여 성능을 개선해 나간다.
코드의 주요 개념
- Xavier 초기화: 학습을 원활히 하기 위한 가중치 초기화 방법.
- Forward Pass: 입력 데이터를 신경망에 통과시켜 예측값을 계산하는 과정.
- Backward Pass (Backpropagation): 예측값의 오류를 기반으로 가중치와 바이어스를 업데이트하는 과정.
- Gradient Descent: 파라미터를 업데이트하여 모델을 학습시키는 방법.
- 손실 함수: 모델의 예측 성능을 평가하는 지표.
- 정확도: 모델이 얼마나 정확하게 예측하는지를 나타내는 지표.
2. 마스터클래스
김수경 마스터님 Q&A 요약 정리
질의응답
Q1: 인공지능은 앞으로 어떻게 발전할 것이라고 생각하시나요? 긍정적인 부분과 부정적인 부분에 대해 알고 싶고, 부정적인 부분을 개선하기 위해 수료생이 어떤 마음가짐과 자세로 이 기술을 활용하면 좋을지 궁금합니다.
- A: 높은 수준의 관리 스킬이 요구될 것이며, 특정 분야의 도메인을 설정하는 것이 중요해질 것입니다.
Q2: 전자공학 석사 취득 후 재료 시뮬레이션에서 머신러닝으로 전향하신 이유가 궁금합니다.
- A: 현실적인 부분들을 고민해서 전향했습니다.
Q3: 환경이나 기상 분석 분야에 관심이 있는데, 기상 분야에서 GIS 외에도 어떤 연구가 이루어지는지 궁금합니다. 에너지, 환경 도메인 쪽 취업을 목표로 하고 있는데 실무에서는 어떤 업무를 하는지도 알고 싶습니다.
- A: 실무에서는 여전히 GIS를 많이 이용하며, 연구 분야에서는 다양하게 활용되고 있습니다.
Q4: 미국 대학원 진학을 준비 중인데 어떤 것을 준비하면 좋을까요? 한국에서 학교를 다니다가 미국으로 가서 어려움이 있었는지, 그리고 미국 대학원 진학 스토리가 궁금합니다.
- A: 고등학생 때부터 유학의 꿈을 가지고 준비했습니다. 머신러닝 분야에서 Second 티어 정도의 논문이 1~2개는 있어야 한다고 생각합니다. 영어만 잘 한다면 한국 대학보다 크게 어렵지 않을 것입니다.
Q5: 주변의 AI 연구자나 AI 엔지니어 중 본받을만한 사람의 예시가 있을까요?
- A: 사람마다 다릅니다. 유학이 아니더라도 국내에서 연구하고 성공한 분들도 많습니다.
Q6: 도메인마다 XAI 평가 방법이 상이할 것 같은데, 도메인에 따라 XAI 평가 방법 사례를 듣고 싶습니다.
- A: 도메인이 아니라 모델에 따라 다릅니다.
Q7: XAI 연구 분야가 활발히 적용되는 산업과 사례가 궁금합니다. XAI의 전반적인 전망은 어떤가요?
- A: 리스크가 큰 분야에서 XAI가 중요합니다.
Q8: XAI를 통해 모델의 설명 가능성을 판단하고 해석할 때, 사용자에게 제공되는 형식과 사례가 궁금합니다.
- A: 수학식이나 그래프 등과 같은 시각화 도구로 제공됩니다.
Q9: 함수들의 수식을 보는 것이 어렵습니다. 개발 경험이 없는데, 라이브러리를 통해 어려움을 넘기고 나중에 수식을 공부해도 괜찮을까요?
- A: 직군에 따라 다릅니다. 과학 관련 직군에서는 수학이 중요하지만, 엔지니어 및 프로그래밍 직군에서는 비교적 덜 중요합니다.
Q10: 대학원을 준비 중인 대학생인데, 논문을 처음 읽어보려면 어떻게 시작해야 할까요? 기초적인 논문부터 읽어야 할지, 최신 논문부터 읽어야 할지 궁금합니다.
- A: 블로그에서 제대로 다루고 있는 경우가 많으니 블로그를 참고하는 것을 추천합니다. AI tech 과정을 성실히 따라가고 이해하는 것이 우선입니다.
Q11: 기후를 결정하는 변수들이 복잡한데, 네트워크가 이러한 feature를 학습하기 쉽지 않을 것 같습니다. 얼마나 많은 데이터와 복잡한 모델이 필요할까요?
- A: 생각보다 복잡한 모델은 요구되지 않으며, 데이터 사이즈가 중요합니다.
Q12: 할루시네이션이 보통 부정적으로 인식되는데, 예술 분야에서 창의적 생각의 근거가 될 가능성이 있을까요?
- A: 예술적인 분야에서는 근거가 될 가능성이 있다고 봅니다.
Q13: 현재 비디오 데이터 분야는 어떻게 발전되고 있나요?
- A: 모든 모델들이 Transformer로 통합 중입니다. 비디오 데이터 분야에서는 ViT가 발전하고 있습니다.
Q14: 여러 XAI 기법 중 어떤 것을 적용할지 정성적으로 평가하는 사례가 있나요?
- A: 정성적인 평가는 User Study를 많이 진행합니다. Ground Truth가 명확하지 않기 때문입니다.
캠퍼들에게 한 마디
네이버 AI Tech 커리큘럼은 석사과정에서 요구하는 것 이상으로 퀄리티가 높습니다. 성실히 따라가고 역량을 갖춘다면 굉장히 큰 기회가 올 것이라고 생각합니다.
3.assignment#3 풀이
Multi-head Self-attention Model 구현
1) Self-attention: \(\text{Attention}(Q,K,V)=\text{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right)V\) 2) Multi-head Self-attention의 개념 3) 알고리즘 구현
CustomMultiHeadAttention
클래스를 정의
이 클래스는 MLP(Multi-Head Attention)를 구현한다. 이는 Transformer 모델의 핵심 구성 요소 중 하나로, 다양한 헤드로 정보를 나누어 병렬적으로 처리하는 방법을 제공한다.
클래스 초기화 (__init__
메서드)
def __init__(self, num_heads, model_dim):
super().__init__()
self.num_heads = num_heads
self.head_dim = model_dim // num_heads
self.all_heads_dim = self.head_dim * num_heads
self.query_proj = nn.Linear(model_dim, self.all_heads_dim)
self.key_proj = nn.Linear(model_dim, self.all_heads_dim)
self.value_proj = nn.Linear(model_dim, self.all_heads_dim)
# Output projection layer
self.out_proj = nn.Linear(self.all_heads_dim, model_dim)
num_heads
: 어텐션에서 몇 개의 헤드를 사용할지 정하는 변수이다. 보통 8 또는 16으로 설정된다.model_dim
: 입력 벡터의 차원 수이다. 이 값은 모델의 전체 차원을 의미한다.head_dim
: 각 헤드가 처리할 차원 수를 나타낸다.model_dim
을num_heads
로 나눈 값이다.query_proj
,key_proj
,value_proj
: 각각 쿼리, 키, 값에 대해 선형 변환을 적용하는 레이어다. 이들은 입력 데이터를 각 헤드로 나누기 전에 변환하기 위해 사용된다.out_proj
: 모든 헤드의 출력을 결합한 후, 다시 원래 모델 차원으로 투영하는 선형 변환 레이어이다.
split_heads
메서드
def split_heads(self, tensor):
batch_size, seq_len, _ = tensor.size()
tensor = tensor.view(batch_size, seq_len, self.num_heads, self.head_dim)
return tensor.permute(0, 2, 1, 3)
- 이 메서드는 입력 텐서를 여러 헤드로 분리한다.
tensor.view(batch_size, seq_len, self.num_heads, self.head_dim)
: 입력 텐서를batch_size
,seq_len
,num_heads
,head_dim
의 형태로 변환한다. 각 헤드가 처리할 차원으로 나누는 것이다.tensor.permute(0, 2, 1, 3)
: 텐서의 차원을 재배열하여 헤드를 첫 번째 차원으로 이동시킨다. 배열은 이후 행렬 연산을 효율적으로 수행하기 위함이다.
forward
메서드
def forward(self, x):
Q = self.split_heads(self.query_proj(x))
K = self.split_heads(self.key_proj(x))
V = self.split_heads(self.value_proj(x))
attn_weights = torch.matmul(Q, K.transpose(-1, -2)) / math.sqrt(self.head_dim)
attn_weights = nn.Softmax(dim=-1)(attn_weights)
attn_output = torch.matmul(attn_weights, V)
# Concatenate all heads
attn_output = attn_output.permute(0, 2, 1, 3).contiguous()
concat_output = attn_output.view(attn_output.size(0), attn_output.size(1), -1)
final_output = self.out_proj(concat_output)
return final_output
- 쿼리(Q), 키(K), 값(V) 계산
Q = self.split_heads(self.query_proj(x))
K = self.split_heads(self.key_proj(x))
V = self.split_heads(self.value_proj(x))
- 입력
x
에 대해 각각의 선형 변환(query_proj
,key_proj
,value_proj
)을 통해 쿼리, 키, 값을 계산한다. 그런 다음,split_heads
메서드를 통해 각 텐서를 여러 헤드로 분리한다.
- 어텐션 가중치 계산
attn_weights = torch.matmul(Q, K.transpose(-1, -2)) / math.sqrt(self.head_dim)
- 쿼리 Q와 키 K의 내적(dot product)을 통해 어텐션 가중치(스코어)를 계산합니다. 이때, 내적 결과는
head_dim
의 제곱근으로 나누어 스케일링합니다. 이는 수치 안정성을 높이기 위한 방법이다. attn_weights = nn.Softmax(dim=-1)(attn_weights)
- 소프트맥스 함수를 적용하여 어텐션 가중치를 확률로 변환한다. 각 가중치는 0과 1 사이의 값이 되며, 합은 1이 된다.
- 어텐션 출력 계산
attn_output = torch.matmul(attn_weights, V)
- 계산된 어텐션 가중치와 값 V의 곱을 통해 어텐션 출력을 계산한다. 이는 각 헤드에 대한 출력이다.
- 헤드 결합 및 최종 출력 계산:
attn_output = attn_output.permute(0, 2, 1, 3).contiguous()
concat_output = attn_output.view(attn_output.size(0), attn_output.size(1), -1)
- 여러 헤드의 출력을 하나의 텐서로 결합하기 위해 차원을 다시 정렬하고, 이어서
view
메서드를 사용하여 원래의 형태로 재배열한다. final_output = self.out_proj(concat_output)
- 결합된 출력을 다시 원래 모델 차원으로 변환하여 최종 출력을 생성한다.
알고리즘
- 쿼리, 키, 값 계산: 입력 데이터를 쿼리(Q), 키(K), 값(V)로 변환한다.
- 헤드 분할: Q, K, V를 다중 헤드로 분리한다.
- 어텐션 가중치 계산: Q와 K를 내적하여 어텐션 가중치를 계산하고, 소프트맥스 함수를 통해 확률 분포로 변환한다.
- 어텐션 출력 계산: 가중치와 V를 곱하여 각 헤드의 어텐션 출력을 생성한다.
- 헤드 결합: 각 헤드의 출력을 결합하여 하나의 텐서로 만들고, 최종 선형 변환을 통해 모델 차원으로 복원한다.