BRICKSTUDY

RNN, Sequence-to-Sequence model 본문

AI

RNN, Sequence-to-Sequence model

c-park-2 2024. 11. 4. 00:38

0. 개요

안녕하십니까 브릭스터디 박찬영입니다. 이번 포스팅에서는 이제는 인공지능 기본 개념이 된 Attention, Transformer에 대한 공부를 하기 전에 필요한 RNN, Sequence-to-Sequence에 대해서 알아보려고 합니다. 한참 인공지능 공부할 때에도 잘 안 보고 넘어갔던 내용들이었는데, 이제는 그 영향력이 너무 커진 것 같아서 최근 듣고 있는 강의를 통해서 공부를 해봤습니다. 그래서 제가 이해한 내용을 바탕으로 공유하려고 합니다. 

 

참고 강의 링크 : https://cs182sp21.github.io/

 

CS 182: Deep Learning

Head uGSI Brandon Trabucco btrabucco@berkeley.edu Office Hours: Th 10:00am-12:00pm Discussion(s): Fr 1:00pm-2:00pm

cs182sp21.github.io

 

1. Recurrent Neural Network(RNN)

우리가 먼저 알아야 할 것은 RNN으로 잘 알려진 Recurrent Neural Network입니다. RNN을 알기 위해서 RNN이 어쩌다가 등장했는지부터 알아보려고 합니다. 

 

1) 등장 배경

fixed size input -> model -> output

우리가 기존에 알고 있는 Neural Network를 생각해 보면, input의 size를 고정시켜 놓고 model을 생각했습니다. 즉 input layer에서 input의 size는 정해져 있고, input data의 size를 조정해서 고정을 시키는 방법을 이어왔습니다. 

 

 

만약 input의 길이가 다양하면 어떤 식으로 처리를 해야 할까?

 

이전 고정 size input에서 이제는 다음과 같은 걸 생각해 보자는 것입니다. 

이런 경우에 모델은 다양한 길이의 input을 처리할 줄 알아야 합니다. 

그렇다면 어떻게 해결할 수 있을까요?

 

2) Simple idea : Variable size -> fixed size

가장 간단하게 생각해 볼 수 있는 방법으로는 각기 다른 길이의 input을 통일하는 것입니다. zero-pad를 진행해서 서로 다른 길이를 똑같이 맞춰주는 작업으로 길이를 맞춰줄 수 있습니다. 

 

이렇게 zero-padding을 통해서 길이를 맞추는 방법은 매우 간단하다는 장점이 있고, 우리가 짧고 간단한 sequence에서는 좋은 방법이 될 수 있지만, 길고 복잡한 sequence에서는 좋은 방법이지는 않습니다. (input의 최대 길이만큼 모두 padding을 해야 하기 때문)

 

3) Idea 2 : One input per layer

왜 지금까지 하나의 input layer에 고집을 했을까? 는 생각입니다. 그래서 이번에는 layer 마다 input을 받는 구조로 생각을 해봅시다.

input의 개수(time step = t)마다 input layer를 두어서 처리를 하면, 한 번에 받는 방법보다 computation 적으로 가볍게 처리를 할 수 있습니다. 이런 경우에 각 레이어 연산은 다음과 같습니다. 

 

그런데, 이렇게 구조를 두면, 문제가 발생합니다. "우리가 "t"가 달라지는 input 즉, variable length input에 대해서 처리를 하는데, 실시간으로 레이어를 변경할 수도 없고, input이 없는 layer도 생길 수 있는 거 아니야?"라는 생각이 듭니다. 

 

 

3-1) Variable layer count?

위와 같은 문제를 해결하기 위해서 어떤 방법을 취하는지 한 번 살펴보면 다음과 같이 이전 layer의 activation을 0으로 간주를 하는 것입니다. 

이렇게 이전 layer의 activation 값을 0으로 처리를 해주면서, missing layer에 대해서 처리를 할 수가 있습니다. 길이가 달라져도 전혀 그다음 step에 영향을 끼치지 않도록 만들 수 있는 것입니다. 

 

문제는 아직도 있습니다. 우리가 길이가 비슷한 sequence만을 처리하면 상관이 없는데, 길이가 가장 긴 sequence 만큼 layer가 생기는데, 길이가 긴 데이터는 흔하지 않습니다. 이렇게 되면 input이 잘 안 들어오는 layer의 경우 학습이 다른 layer에 비해서 고르게 되지 않을 가능성이 큽니다. 

 

3-2) Can we share weights matrices?

위와 같은 문제가 발생하는 근본적인 이유는 layer마다 weight matrix가 다르기 때문입니다. 그래서 이런 생각을 해봅시다. "우리가 만약 layer마다 weight를 다 똑같이 만들면 어떨까?"

weight sharing을 이용해서 이제는 긴 sequence에 대해서도 weight를 공유하기 때문에 이전에 언급한 문제를 해결할 수 있습니다. 

지금까지 살펴본 내용이 RNN의 기본적인 구조입니다. RNN의 기본 디자인은 sequence 최대 길이랑 같은 깊이의 매우 깊은 네트워크를 가지고 있고, 각 레이어는 다른 input을 받습니다.(각 layer는 이전 layer의 activation을 해당 timestep의 input과 concat) 

 

그래서 RNN을 "Variable-depth network"라고 표현하기도 합니다. 

 

지금까지 variable-size input에 대해서 알아봤는데, 만약 variable-size output은 어떨까요? output의 경우도 똑같이 처리를 해준다고 보면 됩니다. 

 

4) An output at every layer

이런 경우 생각해봐야 할 점은 "loss를 어떻게 계산할 것인가?"에 대한 것입니다. 해당 경우에는 각 output에 대한 loss를 계산하고, total loss를 sum으로 계산합니다. 

간단하게 computation graph로 살펴보면 다음과 같습니다. 

 


2. Sequence-to-Sequence model

지금까지 input이 여러 길이일 때, output이 여러 길이 일 때, 즉 input도 sequence, output도 sequence를 알아봤습니다. 둘이 합치면 뭔가요? sequence에서 sequence를 출력하는 모델... 

Sequence-to-Sequence model입니다. 

예시로 번역 문제를 생각해 봅시다(Eng -> KR)

"I love AI" -> "나는 인공지능을 사랑한다"

그러면 다음과 같은 그림을 생각할 수 있습니다. 

우선은 <START>는 sequence가 여기서부터 시작한다"는 것을 알리기 위한 하나의 토큰이라고 볼 수 있고, 이전에 우리가 봤었던 내용 중에 이전 layer의 activation 값을 0으로 두어서, 가변 길이 input에 대한 대처를 했던 것과 같은 맥락이라고 볼 수 있습니다. 

 

각 단어들이 그대로 입력으로 들어가진 않고 one-hot encoding과 같은 방법으로 vector 형태로 변환되어서 들어갑니다. 

 

그렇게 encoder를 거치고 나면, 생성된 activation이 decoder로 들어가는데, decoder도 마찬가지로 <START> 토큰을 기반으로 sequence의 시작을 알리고 번역 작업을 시작하게 됩니다. 

 

마지막 우리가 sequence 예측이 끝났음을 모델이 정해야 하므로 예측할 수 있는 값 중에 <EOS> "End of Sequence" 토큰을 두어서, sequence가 끝났음을 정할 수 있습니다. 

 

1) In practical

실제로는 이렇게 layer를 더 많이 쌓아서 사용할 수 있고, 굉장히 다양한 타입(하나의 언어를 다른 언어로, 긴 글을 짧은 글로 요약, 질문에 답을 하거나, text를 code)으로 사용할 수 있습니다. 

 

2) Decoding with Beam search

하나의 예시를 생각해 봅시다. 프랑스어를 영어로 번역하는 task를 생각해 볼 건데, 문장은 다음과 같습니다. 

- Fn : "Un chiot mignon"

- Eng : "A cute puppy"

만약에 decoder 첫 step에서 "A" 대신에 "One"이라는 단어의 확률이 더 높게 나왔다고 해봅시다. 그림으로 살펴보면 다음과 같습니다. 

그림과 같이 단순히 스텝마다 확률이 높은 값을 취하면, 이상한 결과가 나올 수 있습니다. (Sequence 문제이기 때문임) 

 

만약 확률이 조금 낮은 "A"를 선택했다면 다음과 같이 흘러갔을 것입니다. 

왜 이런 일이 발생하는 것일까요? 

 

우리가 원하는 것은 전체 확률의 곱을 최대화하는 것입니다. 모든 확률의 곱을 최대로 하려면, 첫 번째 단계에서 가장 높은 확률을 가진 선택지를 단순 greedy 하게 선택하는 것은 좋은 방법이 아닐 수 있습니다. 

결국에는 전체 sequence의 확률곱이 최대가 되는 것을 찾아야 한다는 것입니다. 그렇기 때문에, 각 step에서 단순 greedy 방법은 좋지 않을 수 있습니다. 

 

2-1) How many possible decodings are there? 

https://cs182sp21.github.io/ [lecture11]

많은 경우 중에 하나는 optimal 일 것입니다. 그래서 decoding을 일종의 search problem으로 보고 문제를 해결하려고 합니다. 



어떤 tree search algorithm을 사용할 수 있지만, 사실상 매우 비싸기 때문에, 간단한 approximate search method를 사용합니다. 

 

2-2) Decoding with approximate search

기본적인 아이디어는 다음과 같습니다. 

가장 높은 확률을 처음에 고르는 것은 optimal이 아닐 수 있는데, 엄청 낮은 확률을 고르는 것은 대부분 좋은 결과로 이어지지 못한다.

 

그래서 K best sequence를 저장해 놓고 search를 진행하자, 즉 step 마다 single best word를 찾는 것이 아니라 k개의 best word를 찾는다는 것입니다. 

 

예를 들어서 살펴보도록 하겠습니다. 

처음 log 확률 계산 결과가 he, i 각각 -0.7, -0.9가 나왔고 나머지는 낮은 확률을 가지고 있어서 2개를 선택합니다. 그래서 <START> he sequence와 <START> I sequence가 생겼고, 그다음으로 올 값을 계산했을 때, 그림과 같이 나왔다면, 계산된 확률값에 따라서 best 2개씩 남겨가면서 search를 진행하는 것입니다. 

이전의 확률의 곱으로 표현된 식을 계산의 편의를 위해서 log를 취해주어 확률 덧셈으로 바꿔주었기 때문에 log 함수로 계산을 한다. 
log 함수는 덜 음수(음수 값이 작을수록) 확률이 큰 값이다. log(1) = 0

search는 최종적으로 <EOS> token의 확률이 가장 높게 나오면, 해당 sequence를 저장하는 방식으로 종료가 됩니다.

그렇게 종료가 되면, 그림에서 예를 들면 다음 계산으로 <EOS>가 가장 높은 확률이 나왔다고 한다면 해당하는 sequence가 최종 예측이 되는 방식입니다. 

 

그런데, 잘 보면, 확률값을 계속해서 더하는 과정이기 때문에, sequence가 길면 길수록 유리한 입장입니다. 따라서 간단하게 단순히 더하는 것이 아니라 sequence 길이로 나누어주면서 최종적으로는 일종의 평균으로 계산을 하게 됩니다. 

 

그래서 그 평균 점수가 가장 높은 sequence를 선택하는 것으로 이전에 언급했던 문제를 해결하는 것입니다. 

 

3. 마치며

이번 포스팅에서는 Attention, Transformer에 대한 개념을 보기 전에 필요한 개념인 RNN, Seq2Seq에 대해서 간단하게 살펴봤습니다. 다음 포스팅에는 Attention과 Transformer에 대해서 공유하도록 하겠습니다. 

감사합니다. 

 

'AI' 카테고리의 다른 글

Attention, Transformer를 알아보자  (0) 2024.11.05
인공지능 기초 Optimization  (0) 2024.10.26
Supervised Learning 기초  (6) 2024.10.11
Embodied AI : Vision-Language Navigation Challenges  (3) 2024.09.28
Embodied AI : Survey(2)  (3) 2024.09.01