캠프 생활은 여러 모로 즐겁다. 단순히 새로운 지식을 습득하는 것도 재미있고, 여러 사람들과 그 날 배운 것과 서로 모르는 것들을 공유하는 것도 재미있고, 근처 여러 식당들을 탐방하는 것도 재미있다(최근엔 근처 구내 식당들밖에 이용하지 않았지만 구내 식당도 그 나름대로 매일 바뀌는 메뉴를 즐기게 된다). 이번 주에는 컴퓨터 주변 기기들에 대해 여러 학우님들이 모여 얘기를 나눌 기회가 있었다. 모니터, 키보드, 마우스부터 서브모니터, 팜레스트 등 여러 이야기를 나누었다. 나는 키보드에 관심이 있는 편인데, 키보드 배열에 대한 얘기부터, 여러 스위치들에 대한 이야기를 들을 수 있어서 흥미로웠다. 내가 캠프에서 사용하고 있는 키보드는 75배열 적축(low profile) 키보드인데, 강의실에서 타건음을 들어보면 적축인데도 소리가 다소 큰 편이다. 나중에 금전적인 여유가 생긴다면, 소리가 더 작은 스위치로 교체해주고 싶다.
💻 What?
이번 주로 NLP의 기본적인 부분들에 대한 수업이 끝났다. 저번 주에 배운 RNN에 이어서 LSTM(Long-short-term Memory), GRU(Gated Recurrent Unit)라는 응용 RNN을 배웠다. 또한 Seq2Seq의 기본 구조에 대해 학습했다. Encoder - Decoder로 이루어진 구조, Encoder가 뱉어내는 Context Vector, Decoder에서 사용되는 Teacher Forcing, 기존 Seq2Seq가 지니는 bottleneck problem을 해결할 Attention mechanism 및 Transformer 구조에 대해 배웠다.
화요일에는 2회차 코딩 테스트 스터디가 있었다. 이번 주의 키워드는 정렬이었다. 수요일에는 수업이 끝난 뒤 PCCE에 응시했다.
😮 So What?
이론 폭탄💣
이번 주를 기점으로 NLP의 기본적인 굵직한 이론들은 거의 다 훑어본 것 같다. 지난주 RNN이 등장하면서부터 본격적으로 복잡한 이론 설명이 시작되나 싶었는데, 이번 주에는 그 응용 버전들과 너무나도 어려운 개념들이 연이어 등장해서 정신을 바짝 차려야 했다
LSTM & GRU
기본 RNN이 시퀀스가 길어지면 앞쪽 정보를 까먹는 Long-term Dependency Problem가 있다는 걸 배운 뒤에 바로 상위 호환 격인 LSTM(Long-Short Term Memory)과 GRU(Gated Recurrent Unit)에 대해 배웠다.
LSTM은 이름 그대로 장기 기억과 단기 기억을 모두 다루는 RNN이다. Hidden State 이외에 Cell State라는 컨베이어 벨트 같은 긴 기억 장치를 통해 장기 기억을 관리한다. 그리고 각각의 기억 속에서 보존할 정보의 양을 Gate System을 통해 보정한다. Forget Gate는 Cell State에서 보존할 정보의 비율을 정하고, Input Gate는 현재 time step에서 주어진 정보($X_t$, $H_{t-1}$)에서 보존할 정보의 비율을 정하고, Output Gate는 update된 Cell State($C_t$)에서 어떤 정보를 $H_t$로 내보낼 지에 대한 비율을 정한다. Cell State라는 별도의 정보 흐름 통로가 있어서, 정보가 이 게이트들을 통해 마치 컨베이어 벨트처럼 흐르면서 신중하게 추가되거나 제거될 수 있기 때문에 장기 기억을 효과적으로 관리할 수 있다는 점이 LSTM의 특장점이다.
GRU는 LSTM보다 구조와 연산이 가벼워진 버전이라고 볼 수 있겠다. 게이트가 하나 줄면서 연산량이 감소했지만, LSTM에 버금가는 성능을 보여준 다는 점에서 매력적인 것 같다. GRU는 Reset Gate와 Update Gate, 총 두 개의 게이트로 구성된다. Reset Gate가 Forget Gate, Update Gate가 Input Gate & Output Gate의 역할을 수행하는데, $H_{t_1}$과 내적하는 값은 Update Gate를 빠져나온 sigmoid값, Candidate of $H_t$와 내적하는 값은 1 - sigmoid값이 된다. Update Gate가 과거 정보와 현재 후보 정보를 어떤 비율로 섞을지를 통합적으로 결정하는 방식이 LSTM의 아이디어를 잘 계승하면서도 간결하게 만든 것 같았다.
Seq2Seq(Sequence-to-Sequence)
단순히 감성 분석처럼 분류만 하는 게 아니라, 하나의 문장을 다른 문장으로 바꾸는 작업, 예를 들면 번역이나 챗봇 같은 걸 하려면 어떻게 해야 할까? 여기서 Seq2Seq 모델이 등장한다. 이름 그대로 Input Sequence를 받아 Output Sequence를 뱉어내는 구조인데, 크게 Encoder와 Decoder 두 부분으로 나뉜다는 점이 핵심이었다.
Encoder는 Input Sequence의 모든 정보를 쭉 읽어서 하나의 압축된 정보 덩어리, 즉 Context Vector로 만든다. 보통 Encoder RNN의 마지막 time step의 Hidden State가 이 역할을 한다. Decoder는 이 Context Vector를 받아서, 마치 작가가 주제를 바탕으로 글을 써 내려가듯, Output Sequence를 한 단어 한 단어 생성해낸다. Decoder에서의 $X_t$는 Decoder가 이전 time step에서 만들어낸 $H_{t-1}$이 된다. 즉 현재 예측한 단어를 다음 단어를 예측할 때의 Input으로 사용하는 것이다.
그런데 이런 구조에서는 Encoder가 문장의 모든 정보를 고정된 크기의 Context Vector 하나에 다 우겨 넣으려니, 문장이 길어지면 정보가 손실되는 Bottleneck Problem이 발생할 수 있다.
또한 Decoder 학습 시에는 Teacher Forcing라는 기법을 사용할 수 있다. 학습 초기에는 모델이 엉뚱한 단어를 예측할 수 있으니, 이전 time step에서의 예측값 대신 실제 정답 단어를 다음 입력으로 넣어줘서 학습을 안정화시키는 방법이라고 한다. 모든 time step에서 적용하는 건 아니고, 모델 내부에서 우리가 설정한 확률에 기반하여 독립시행된다. 물론 해당 기법 때문에 실제 예측 환경과의 Exposure Bias가 생길 수도 있다는 점도 주의해야한다. Data Preprocessing에서 Encoding, Labeling, Scaling 등을 수행할 때 test data도 fit할 시 발생하는 Data Leakage와 비슷한 맥락이다.
Attention Mechanism
Attention Mechanism은 Seq2Seq에서 소개한 Bottleneck Problem를 해결하기 위한 방법론이다. Decoder가 매번 Output Sequence를 생성할 때마다, Encoder가 만들었던 Input Sequence의 모든 부분(hidden states of every time steps)을 참고하되, 현재 time step에서의 예측과 관련 높은 부분에 더 가중치를 줘서 집중적으로 보겠다는 아이디어다.
우리는 여러 mechanism 중 Dot-Product Attention(a.k.a. Luong Attention)을 살펴봤는데, Decoder의 현재 상태(Query: $X_t$ = $H_{t-1}$)와 Encoer의 각 상태(Key: hidden states of every time steps)들 간의 유사도(dot-product)를 계산하고, 이 유사도를 Softmax 함수에 통과시켜 Attention Weight를 얻는다. 그리고 이 weight vector를 Encoder의 상태(Value: hidden states of every time steps)들에 곱해서 합치면, 현재 예측에 가장 필요한 정보만 쏙 뽑아낸 새로운 Context Vector를 만드는 식이었다. 이 Attention 덕분에 문장이 길어져도 중요한 정보를 놓치지 않고, 번역 품질이나 챗봇의 답변 품질이 훨씬 좋아졌다고 한다.
cf. 왜 dot-product of $Q$ and $K$를 유사도로 볼 수 있을까?
Cosine Similarity에 대해 알아볼 필요가 있겠다. Count Vectorization에서도 잠깐 다루었던 Cosine Similarity는 두 vector 간 Cosine 각도를 이용하여 구할 수 있는 유사도를 의미한다. 즉 두 vector를 각각 공간 속 하나의 점에 대한 좌표라고 할 때, 공간의 원점과 각 좌표를 통과하는 직선 두 개를 그린 다음, 두 직선의 각도를 기준으로 유사도를 측정하는 방법이다. Cosine 각도를 이용하기 때문에 각도가 0이면 1, 각도가 90이면 0, 180이면 -1을 출력한다. 여기서 각도가 0이라면 두 직선이 서로 완전히 같은 방향을 향하기 때문에 매우 유사하고, 180이라면 서로 아예 다른 방향을 바라보기 때문에 매우 유사하지 않고, 90이라면 서로 독립적인 방향을 바라보고 있어 서로 유사도를 설명할 수 없는 관계라고 볼 수 있다. 이렇게 방향의 개념으로 유사도를 설명하는 것이 Cosine Similarity이다.
$\text{Cosine Similarity}(Q, K) = \cfrac{Q \cdot K^T}{|Q| |K^T|}$
만약 $Q$ 행렬과, $K$ 행렬이 있고, 각 행이 하나의 vector를 나타낸다고 할 때, 특정 $Q$ vector인 q(행 하나)와 $K$ vector인 k(마찬가지로 한 행) 간 유사도를 나타내기 위해 $K$를 transpose하여 $K^T$로 표현하고, dot-product를 사용하는 경우가 있다. 해당 경우, q와 k 간의 Cosine Similarity는 위와 동일한 형태로 표현된다.
Attention Mechanism에서 $QK^T$ 연산은 모든 $Q$ vector와 모든 $K$ vector를 한 번에 계산하는 과정이며, Cosine Similarity 공식의 분자에 해당한다. 즉 -1 ~ 1 사이의 값으로 정규화되지 않은 Cosine Similarity로 간주할 수 있는 것이다.
Transformer 찍먹
Transformer는 Attention Is All You Need 논문에서 등장한 Seq2Seq mechanism without RNN이다. 핵심 키워드는 문장 '자기 자신' 내에서 단어들 간의 관계를 파악하는 Self-Attention과, 이를 여러 관점에서 동시에 수행하는 Multi-Head Attention이다. 또, 순서 정보를 알려주기 위한 Positional Encoding, 학습을 안정화시키는 Add & Norm 같은 장치들도 설계되어 있다.
Transformer의 기본 컨셉과 의미론적인 흐름은 대략 이해했지만, 아직 각 내부 구조에서의 세부적인 연산 과정들이 한 번에 와닿지 않는다. 여러개의 Attention이 여러 개 겹쳐있고, 계산도 복잡해 보여서, 강사님이 해주신 설명과 강의안, 그리고 논문 원문을 꼼꼼히 읽어보는 시간을 따로 가져야 할 것 같다.
알고리즘: 목표 달성.

저번 달 봤던 PCCE에서 Lv. 2를 받은 뒤 세운 목표는 다음 시험에서 Lv. 3를 달성하고 PCCE를 졸업하는 것이었다. 바로 다음 시험을 지난 수요일에 치뤘는데, 목표를 달성할 수 있었다. 전체적인 문제 풀이 시간도 단축할 수 있었고, 디버깅 및 빈칸 채우기 실력도 어느 정도 성장한 것 같다. 10번 문제를 풀지 못해 아쉬웠다. 사실 10번도 다 풀었는데 OMR 카드 밀려 쓴 느낌이라고 봐야겠다. 로직은 맞았는데 한 문장을 안 읽어서 일어난 일이었다.
시험 전 날 했었던 코딩테스트 스터디의 주제는 정렬이었다. PCCE 수준에서 가장 빈번하게 활용되는 스킬이라고 생각해서 정렬 관련 문제들을 풀어보고, Python built-in sorting인 list.sort()와 sorted()에 대해 살펴볼 수 있는 자료를 준비했다. 그런데 당일에는 정렬이 메인인 문제가 하나도 나오지 않았던 것 같아서 조금 아쉬웠다.
어쨌든 이번 시험 결과에서 지난 날 열심히 기초를 다진 보람이 느껴져서 기분이 좋다. 다음 시험부터는 PCCP를 응시해봐야겠다.
🎈 Now What?
다음 주에는 블로그에 처음으로 회고 이외의 포스팅을 남겨보려 한다. 위에서 언급한 Transformer 복습 결과를 블로그에 남겨야겠다. 수업일보다 휴일이 많은 주니까 휴일을 적극적으로 활용해보자. 그리고 주말 동안 3회차 코딩 테스트 스터디 문제를 풀어보려 한다. 문제 난이도가 높으니 일부 문제들은 슬슬 최적화를 요구하고 있다. 지금 한 문제가 로직은 맞는데 시간초과에서 걸리는데, 이를 해결할 방법을 생각해봐야겠다.
두 번째 월간 회고를 쓰고 있는 현 시점, 데이터베이스, 정형 데이터 분석, 비정형 데이터 분석 등 많은 것들을 배웠다. 하나 하나 새롭게 배울 때마다 하고 싶은 것들이 많아진다. 막연하게 하고싶다고 생각하는 것들에 대해 '내가 정말로 흥미를 느끼고 하고싶어 하는 일인지' 생각해보고, 다음 월간 회고 전에는 잘 추려볼 수 있었으면 하는 바람이다.
여담


캠프 라운지에 협업을 위한 테이블, 모니터와 HDMI 케이블, 여러 기술 스택 관련 서적 등 여러 시설들이 준비되어 있다. 이번 주에 그 중 화이트 보드를 사용해봤다. 수업이 끝난 금요일 저녁, 다들 금요일을 만끽하러 갔는지 남아있는 사람들이 얼마 없었다. 라운지에는 스터디를 하는 JH님, MI님, JH님, HY님 네 분만 계셨고, 나는 그 옆 테이블에서 화이트보드를 펼쳐 이번 주에 배운 내용들을 머릿속에서 끌어내어 보드에 끄적여봤다. 고요한 라운지에 자연어 처리를 복습하는 열의에 찬 학우님들의 목소리와, 화이트보드를 채웠다 지웠다 반복하며 중얼거린 내 혼잣말 소리만이 남았다.
'SKN_13th' 카테고리의 다른 글
| [플레이데이터 SK네트웍스 Family AI 캠프 13기] 12주차 회고 (6) | 2025.06.14 |
|---|---|
| [플레이데이터 SK네트웍스 Family AI 캠프 13기] 11주차 회고 (7) | 2025.06.08 |
| [플레이데이터 SK네트웍스 Family AI 캠프 13기] 9주차 회고 (0) | 2025.05.25 |
| [플레이데이터 SK네트웍스 Family AI 캠프 13기] 8주차 회고 (0) | 2025.05.18 |
| [플레이데이터 SK네트웍스 Family AI 캠프 13기] 7주차 후기 (0) | 2025.05.11 |