ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [cs231n] 10강 순환 신경망 (Recurrent Neural Network) (2/4, 계산 그래프 (computational graph))
    AI 2021. 4. 13. 11:50

    구체적인 예로, 우리가 순환 신경망을 자주 사용하는 대상은 언어 모델링 (language modeling)이라고 부르는 문제입니다. 언어 모델링 문제에서는, 어떤 순열을 읽는 건데, 망이 어떻게 자연어 (natural language)를 만들어 내는 지를 이해하는 거죠. 그래서 이건 문자 단위로 (character level) 벌어지는 일이라서, 우리의 모델은 한번에 하나씩 문자를 만들어 냅니다. 이건 또 단어 수준으로 (word level) 할 수 있죠. 모델이 한번에 하나씩 단어를 만들어 내는 겁니다. 그러나, 매우 간단한 예에서, 여러분은 이 문자 단위 언어 모델을 상상해 볼 수있고, 거기서는 망이 어떤 순서의 문자들을 읽고 텍스트의 흐름에서 다음 문자가 어떤 것이 될 지를 예측할 필요가 있는거죠. 그래서 이 예에서, 우리는 이 매우 작은 어휘를 가지는데, 4개의 글자죠. h, e, l, o입니다. 단어 hello, h, e, l, l, o의 순열을 훈련하는 예가 있습니다.

    이 언어 모델을 훈련시킬 때, 우리는 이 훈련 순열을 입력, x_t들로 넣는 거죠. 순환 신경망에 대한 입력으로 넣는 겁니다. 그리고 이 입력 각각은 그건 글자인데요. 우리는 망에서 문자들을 표현할 방법을 알아내야죠. 전형적으로는 전체 어휘가 무엇인지를 알아냅니다. 이 경우 우리의 어휘는 4개의 요소로 되어 있죠. 각각의 글자는 벡터 (vector)로 표현이 될텐데 모든 슬롯 (slot)에 0을 가지고 있지만, 그 문자에 해당하는 어휘의 슬롯에 대해서만 1을 가지고 있는 벡터로 표현됩니다. 이 작은 예에서, 어휘는 4개의 글자 , h, e, l, o를 가지고 있으므로, 우리의 입력 순열 h는 4개의 원소로 된 벡터로 표현이 됩니다. 첫번째 슬롯에는 1이고 나머지 3개 슬롯에는 0이있는 거죠. 우리는 같은 종류의 패턴을 사용해서 입력 순열 속의 모든 여러 글자들을 표현하죠.

    순방향 전달에서 이 망은 첫번째 시점에서, 입력 글자 h를 받죠. 그건 첫번째 RNN 셀로 들어갑니다. 그리고 나서 우리는 이 출력 y_t를 만들어 낼거고, 망이 어휘에 있는 각 단어에 대해 예측을 하는 겁니다. 어떤 글자가 다음에 올 것이라고 생각하느냐는 거죠. 이 예에서는 정확한 출력 글자는 e 인데, 왜냐면 훈련 순열이 hello였으니까요. 그런데 모델은 사실 o를 가장 나올 것 같은 글자로 예측하고 있죠. 그래서 이 경우에, 이 예측은 틀린거고, 우리는 소프트맥스 손실 (softmax loss)을 사용해서 이 예측에 만족하지 않음을 정량화할 겁니다. 다음 단계로, 우리는 훈련 순열에서 두번째 글자인 e를 넣을 건데 이 과정이 반복됩니다. e를 벡터로 표현하는 거죠. 그 입력 벡터를 이전 숨겨진 상태와 같이 사용해서 새로운 숨겨진 상태를 만들고 그 두번째 숨겨진 상태를 사용해서 어휘의 모든 글자들에 대해 예측을 하는 겁니다. 이 경우는, 훈련 순열이 hello였으니까, 'e' 다음에, 모델이 'l'을 예측하길 바라고 있는 거죠. 이 경우, 모델은 아마 'l'에 대해 매우 낮은 예측을 하고 있죠. 그래서 매우 높은 손실을 초래할 겁니다. 이런 절차를 계속 반복하고, 많은 다양한 순열로 이 모델을 훈련시키면, 결국, 그건 앞서서 본 모든 이전 문자들의 문맥에 근거하여 어떤 순열에서 다음 문자를 예측하는 방법을 학습할 겁니다.

    이제 테스트 시에 어떤 일이 벌어지는 생각해 보면, 이 모델을 훈련시킨 다음, 모델로부터 샘플링하고 이 훈련된 신경망을 사용해서 훈련된 텍스트와 정신적으로 (in spirit) 유사해 보이는 새로운 텍스트를 합성하는 것입니다.이것이 동작하는 방식을 얘기해 보죠. 일반적으로 어떤 텍스트의 전치사가 모델에 있는 것을 보게 될 겁니다. 이 경우 전치사는 그냥 하나의 문자인 h죠. 그리고 그 문자를 순환 신경망의 첫번째 시점을 통해서 h를 입력합니다. 그건 어휘 내의 모든 문자들에 대한 이 점수 분포를 만들 겁니다. 이제 훈련시에, 우리는 이 점수들을 사용해서 그것들로부터 사실상 샘플링할 겁니다. 그래서 우리는 소프트맥스 함수를 사용해서 그 점수들을 확률 분포로 변화하고 그 확률 분포로부터 샘플링해서 사실 순열에서의 두번째 문자를 합성하는 거죠. 이 경우는, 점수가 꽤 나쁘지만, 아마도 운이 좋아서 확률 분포로부터 글자 e를 샘플링했네요.

    그리고 이제, 이 분포로부터 샘플링한 글자 e를 가지고 다음 시점에서 망에 입력으로 넣습니다. 이제 이 e를 가지고 위에서부터 끌어내린다음 망에 이런 원핫벡터 (one-hot vector) 표현으로 넣습니다.

    그리고 출력에서 두번째 글자를 합성하기 위해 그 과정을 반복합니다.

    그리고 이 과정을 계속 반복하고 이 훈련된 모델을 사용해서 새로운 순열을 합성합니다. 매 시점 마다 이 예측된 확률 분포를 사용해서 한번에 한 글자씩 이 순열을 합성하는 겁니다.

    순열을 가지고 순열의 매 시점 (time step)마다 출력을 만들어 내고 최종적으로 어떤 손실을 계산하는 이 아이디어는 종종 시간에 따른 역전파라고 불립니다. ( backpropagation through time) 왜냐면, 순방향 전달 (forward pass)에서, 여러분은 일종의 시간을 통과하면서 한걸음씩 전진하고 있는 거니까요. 그리고 역방향 전달 (backward pass) 동안에는 시간을 거치면서 거꾸로 가면서 경사를 계산하는 거죠. 매우 매우 긴 순열을 훈련시키려고 한다면, 사실 문제가 많을 수 있습니다. 만약 우리가 신경망 언어 모델을 훈련시키려는 것을 상상해 보죠. 위키피디아 전체 텍스트에 대해서요. 그런데 이건 사람들이 꽤 자주 하는 일이죠. 이건 매우 느리고, 경사 걸음을 걸을 때마다, 위키피디아의 전체 텍스트를 통과하는 순방향 전달을 해야 합니다. 그 이후에 모든 위키파디아를 통과해서 역방향 전달도 해야합니다. 그리고 나서야 하나의 경사 업데이트를 할 수 있죠. 그건 슈퍼 느릴거고, 모델은 절대 수렴하지 않을 겁니다. 또한 말도 안되는 양의 메모리를 필요로 하니까 이건 그냥 너무 나쁜 겁니다.

    실제에서 사람들은 일종의 이런 추정을 하는데, truncated backpropagation through time이라고 부릅니다. 여기 그 아이디어가 있는데, 입력 순열이 매우 매우 길고, 심지어 잠재적으로는 무한하다고 하더라도, 모델을 훈련시키는 동안, 우리는 어떤 숫자만큼의 걸음동안 앞으로 전진하는 겁니다. 아마도 100정도가 사람들이 자주 사용하는 대략적인 숫자죠. 그리고 우리는 아마도 100 걸음 전진할거고, 데이타의 하위 순열에 대해서만 손실을 계산할 겁니다. 그리고 이 하위 순열에 걸쳐서 역전파를 하는 거죠. 그리고 나서 경사 걸음을 걷습니다. (make a gradient step).

    이제 반복할 때, 우리는 여전히 첫번째 배치 (batch)로부터 계산한 이 숨겨진 상태 (hidden)를 가질 거고, 이제 데이타의 이 다음 배치를 계산할 때, 우리는 그 숨겨진 상태를 시간상 앞으로 옮겨 놓습니다. 그래서 순방향 전달은 정확하게 같은 것이 되는 거죠. 그러나 이제 우리가 데이타의 이 다음 배치에 대해 경사 걸음을 계산할 때, 우리는 이 두번째 배치를 통해서 다시 역전파만 할 겁니다. 이제 우리는 이 시간에 따른 잘려진 역전파에 근거해서 경사 걸음을 걸을 겁니다.

    이 과정은 계속될 거고, 이제 다음 배치를 만들 때, 우리는 이 숨겨진 상태를 앞에 다시 복사하지만, 이후 전진하고 다시 뒤로 갈겁니다. 그러나 단지 어떤 작은 숫자의 시점에 대해서만 그렇게 하는 거죠. 이걸 순열의 경우의 확률적 경사 하강 (stochastic gradient descent)과 비슷한 것이라고 생각할 수 있습니다. 기억하듯이, 우리가 큰 데이타 셋에 대해 모델을 훈련시키는 것을 얘기했을 때, 이 데이타 셋 (data set)은, 데이타 셋에 있는 모든 항목에 대해서 경사를 계산하는 것이 슈퍼 비싸겠죠. 그래서 그 대신에, 작은 샘플들, 즉 작은 미니 배치를 취합니다. 어떤 이미지 분류의 경우이든지 데이타의 미니 배치를 사용해서 경사 스텝을 계산하죠.

    안드레이 (Andrej)는 min-char-rnn이라고 부르는 이 예제를 갖고 있는데, 그건 이 모든 것을 112줄의 파이썬 코드로 하고 있습니다. 그건 어휘를 만들고, 시간에 따른 잘려진 역전파로 모델을 훈련하고, 그리고 나서 그런 사실 모델로부터 샘플링도 할 수 있죠. 별로 많지도 않은 코드로요. 이게 크고 무서운 과정처럼 보이지만, 사실 그건 그렇게 어렵지 않습니다. 만약 잘 이해가 안된다면, 이걸 한번 확인해 보고 시간을 내서 코드를 거쳐가 보고 코드에서 벌어지는 이 구체적인 단계들을 보길 바랍니다. 이건 모두 하나의 파일에 있고, 넘파이를 사용하고 의존성 (dependency)이 없습니다. 비교적 읽기도 쉽구요.

    gist.github.com/karpathy/d4dee566867f8291f086

     

    Minimal character-level language model with a Vanilla Recurrent Neural Network, in Python/numpy

    Minimal character-level language model with a Vanilla Recurrent Neural Network, in Python/numpy - min-char-rnn.py

    gist.github.com

    일단 우리가 이 순환 신경망 언어 모델을 훈련시키는 아이디어를 가지면, 우리는 사실 이걸로 이것저것 해 볼 수 있습니다. 우린 원하는 어떤 텍스트든지 받아 들일 수 있죠. 생각해 볼 수 있는 임의의 인터넷으로부터의 어떤 텍스트든지, 순환 신경망 언어 모델을 이 텍스트에 대해 훈련시키고, 새로운 텍스트를 만들어 내는 거죠. 이 예제에서, 우리는 셰익스피어어의 작품의 전체 텍스트를 가지고 그걸 사용해서 순환 신경망 언어 모델을 모든 셰익스피어에 대해서 훈련시킵니다.

    보다시피, 훈련의 초기에, 그건 일종의 임의의 횡설수설하는 쓰레기를 만들어 내는 것 같지만, 훈련과정을 거치면, 결국 비교적 그럴만 해 보이는 것들을 만들어 내죠. 이 모델이 꽤 잘 훈련된 후에는, 그건 저에게는 셰익스피어처럼 보이는 문장들을 만들어 냅니다. "Why do what that day," replied. 이런 것들이죠. 이런 것을 읽을 수 있는데, 이건 셰익스피어 같아 보입니다.

    만약 이 모델을 훨씬 더 많이 훈련시키고 더 나아가서 수렴하게 하고 훨씬 더 긴 이 순열들을 샘플링하면, 정말로 셰익스피어 연극처럼 보이는 모든 종류의 미친 멋진 것들을 학습할 수 있다는 것을 알게 되죠. 그건 누가 말하는지 얘기하기 위한 이런 헤딩들 (headings)도 사용할 줄 알게 되죠. 그리고 나면 그건 셰익스피어처럼 들리는 미친 대화들을 가진 이런 텍스트 조각들을 만들어 냅니다. 그건 이런 다른 것들 사이에서 줄바꿈도 할 줄 알죠. 이건 모두 정말 멋지고, 데이타의 구조로부터 모두 학습한 거죠.

    이것보다 더 미친 것들도 얻을 수 있는데요. 이건 제가 제일 좋아하는 것 중의 하나였는데요. 온라인에서 찾았습니다. 이방에 수학자 있나요? 혹시 대수적 위상수학 (algebraic topology) 과정 들은 사람 있나요? 와 2명있네요. 인상적이네요. 여러분이 어쩌면 대수적 위상에 대해서 저보다 더 많이 알 수 도 있지만, 저는 이 오픈소스 대수적 위상 수학 교과서를 온라인에서 찾았죠. 그건 이런 슈퍼 빽빽한 수학 같은 많은 테크 파일들이었습니다. 그리고 레이텍스 (LaTex)은 일종의 방정식, 다이어그램 같은 것들을 그냥 텍스트로 그릴 수 있게 해주는 것이죠. 우리는 사실 순환 신경망 언어 모델을 이 대수적 위상 수학 교과서의 레이텍스 소스 코드에 대해 훈련시킬 수 있습니다.

    그걸 하면, 모델로부터 샘플링을 한 다음, 우리는 이런 것을 얻을 수 있죠. 대수적 위상 수학 같죠. 그건 방정식도 넣을 줄 알고 모든 종류의 미친 것들을 넣습니다. 연구를 증명하기 위해 우리는 F 서브 U는 소수 x 를 커버하는 것 블라, 블라, 블라 블라, 블라. 어디에 합집합을 넣을 지도 알고 증명 끝에 사각형을 넣을 줄도 알죠. 그건 보조정리 (lemma)도 만들고, 앞선 보조정리를 참조합니다. 그건 즉, 바이레마 (bi-lemma) 질문이죠. R은 기하학적인 무언가입니다. 이건 사실 꽤 미친거죠.

    그건 또한 가끔씩 다이어그램 (diagram)을 만들려고 합니다. 대수적 위상 수학을 들은 사람들은 이런 의사전달을 위한 다이어그램으로 작업을 많이 했겠죠. 그래서 그건 그런 다이어그램들을 어떻게 만드는지에 대한 전체적인 요점은 이해했지만, 다이어그램들이 의미가 있는 것은 아닙니다. 사실 여기서 제가 좋아하는 예제중의 하나는 그건 가끔 증명을 생략합니다. 그래서 가끔 그건 정리는 블라 , 블라, 블라, 블라, 블라, 증명 생략이라고 하죠. 이건 이런 수학 교과서가 어떻게 생겼는지 요점을 이해한 것 같아요.

    우리는 이걸로 정말 재밌게 시간을 보낼 수 있어요. 그래서 또한 리눅스 커널의 전체 소스코드에 대해서 이 모델들을 중의 하나를 훈련시켜보려고 했죠. 우리가 훈련시킬 수 있는 것은 이 문자 수준의 것들이죠.

    그리고 나서 이걸 샘플링했을 때, 그건 사실 C 소스 코드처럼 보입니다. 그건 if문을 작성할 줄 알고, 꽤 좋은 코드 형식을 만드는 기술도 갖고 있죠. 그건 if 문뒤에 들여쓰기를 할 줄도 알고 괄호도 넣을 줄 알죠. 그건 심지어 어떤 것에 대해서 주석도 달 줄 아는데, 보통 말이 안되는 거긴 합니다. 이 모델에서 문제점 하나는 그게 변수를 선언 할 줄은 아는데, 항상 선언한 변수를 사용하지 않습니다. 그리고 가끔 선언하지 않은 변수를 사용하려고 하죠. 이건 컴파일 되지 않습니다. 리눅스에 풀 리퀘스트 (pull request)로 이걸 보내는 건 권장하지 않습니다.

    이건 또한 GNU를 나열하는 것을 알죠. 이 GNU 라이센스를 글자 마다요. GNU 라이센스를 나열해야 한다는 걸 알고 라이센스 뒤엔 include들이 오고,

    그리고 또 다른 include들이 오고 그다음 소스 코드가 오죠. 이건 사실상 일반적인 데이타 구조에 대해서 많이 학습했습니다. 다시 얘기하지만, 훈련 중에, 우리는 이 모델이 순열에서 다음 글자가 무엇인지를 예측하도록 한 것이죠. 우리는 이 구조의 어떤 것도 모델에 얘기하지 않았죠. 그러나 어떻든, 훈련 과정을 통해서, 그것은 순차적인 데이타에서 잠재적인 구조에 대해 많이 배웠습니다. 네! 그건 코드를 작성할 줄 알죠. 그건 멋진 것들을 많이 합니다.

    댓글

Designed by Tistory.