ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [cs224n] 2강 워드 벡터와 워드 센스 (2/5, 최적화 (optimization))
    AI 2021. 1. 17. 15:08

    우리는 어떻게 이 단어 벡터들을 학습했는지에 대해 얘기하기 시작했습니다. 이 수업은 사실 최적화 시간은 아닌데, 최적화에 대해 알고 싶다면, 229에서 더 잘 배울 수 있죠. 스테판 보이드의 최적화 수업을 듣거나요. 이건 베이비 (baby) 최적화이고 우리 모두가 같은 이해를 하고 있다는 걸 확인하기 위한 거죠. 여기 3장의 슬라이드가 있습니다. 우리는 최소화하고 싶은 비용함수를 가지고 있고, 우리의 워드 벡터에 대해서 미분을 해서 비용함수의 경사를 계산했죠. 우리의 변수는 쎄타 (θ)였고, 우리가 하고 싶은 건, 우리가 작은 걸음으로 음의 경사 방향으로 걸어가면서, 이 공간의 언덕을 따라 내려가는 것이었습니다. 그걸 계속해서 우리 공간의 최소값으로 나아가고 싶죠. 물론 높은 차원의 공간에서는 이런 부드러운 곡선이 아니겠죠. 그건 끔찍한 넌컨벡스 (non-convex) 곡선이겠죠. 아무튼 이게 아이디어입니다.

    우리는 예전 (old) 파라미터가 있고, 우리는 목표 함수 (objective function)의 경사에 어떤 작업을 해서, 이런 예전 파라미터에 작은 알파 (α)를 곱합니다. 알파는 우리의 걸음 크기 혹은 학습률 (learning rate)이죠. 우리는 조금씩만 움직이고 싶은데, 너무 크게 걸으면 오버슛 (overshoot)할 수 있기 때문입니다. 그래서 우리는 매번 조금만 움직이고 싶습니다. 작은 알파 학습률이 있고, 예전 파라미터에서 작은 여러 개의 경사를 빼죠. 그럼 우리의 새 (new) 파라미터를 얻죠. 이건 컴포넌트별로 효과적으로 작동합니다. 아래 보이는 것처럼요. 우리는 그냥 각각의 부분 미분을 해서, 우리가 바라는 건 그것이 이 표면에서 우리를 점진적으로 걸어 내려가게 하는 것이죠. 근데 실제로 이걸 해보면, 우리가 만드는 시스템에 대해서는 믿을 수 없을 정도로 나쁩니다.

    최적화에 대한 많은 똑똑한 연구가 있지만, 여러분이 반드시 알아야 할 가장 기본적인 것은 여기 목표 함수는 J(θ)는 우리의 말뭉치 전체에 대한 함수라는 거고, 이게 잘 동작하려면, 제일 먼저 할 건 여러분이 좋아하는 언어의 수십억개의 단어를 모으고, "자! 나를 위해 워드2벡을 만들어"라고 말하는 거죠. 여러분이 10억개의 중심 단어를 평가하고 각각의 100억개의 문맥 단어를 평가하려면, 윈도우 크기가 5일때 경사를 알아내기 위해 100억개의 소프트맥스 계산을 해야 할 겁니다. 그럼 여러분의 컴퓨터는 경사에서 하나의 걸음을 옮기기 위해 매우 오랜 시간동안 계산을 해야 할 겁니다. 매우매우 느리겠죠. 아무도 딥 러닝 시스템에서 그렇게 하지 않습니다. 사람들이 하는건 확률적 경사 하강을 쓰는 건데, 우리는 가장 간단한 경우의 윈도우를 샘플링합니다.

    하나의 윈도우에 대해서 경사를 추정하기 위해서 그걸 파라미터 업데이트로 사용합니다. 이건 엄청나게 잡음이 많은 (noisy) 경사 추정인데, 그래도 괜찮죠. 왜냐면 일단 다 하기만 하면, 우리는 다음 중심 단어를 골라서 반복하니까요. 그래서 점점 더 우리가 얻어야 할 것에 도달합니다. 우리가 모든 중심단어를 보고 다음 단계로 넘어가면요. 우리가 점점 걸음을 걷기 때문에 우리는 함수의 최소값에 몇 배로 빨리 도달합니다. 이건 하나의 윈도우를 샘플링하는 가장 간단한 예를 보여줍니다. 실제에선, 그렇게 하지 않죠. 우리는 작은 번치 (bunch)를 샘플링합니다. 32나 64 크기로요. 그래서 만약 우리가 더 큰 샘플을 가진다면, 그건 일반적으로 미니배치 (minibatch)라고 불리는데, 그 미니배치로부터 경사 하강을 계산합니다. 그건 2개의 장점이 잇는데, 하나는, 잡음이 더 적은 (less noisy) 추정을 얻을 수 있죠. 왜냐면 하나만 쓴게 아니라 몇 묶음의 예제에 대해서 평균을 냈으니까요. 두번째는 우리가 정말 신경쓰는 건데, GPU를 써서 우리의 계산이 빠르려면, 우리는 계속해서 병렬로 같은 작업을 할 필요가 있죠. 그럼 64크기 등으로 미니배치를 사용함으로써 효과를 많이 얻습니다. 꼭 해야 하는건 아니지만, 하드웨어 내부의 디테일을 생각해 보면 Nvdia GPU든 뭐든 2의 제곱으로 되어 있죠. 여러분이 32나 64를 쓴다면 여러분은 더 속도를 낼 수 있죠. 여러분이 고등학교때 좋아하는 숫자가 42라고 그걸 미니배치 크기로 쓰는 것보다는요.

    여기 또 재밌는 최적화의 세부사항이 있는데, 워드벡터로 확률적 경사를 하는 걸 생각해 보죠. 그건 비전 (vision) 딥 러닝 같은 다른 딥 러닝 문제와는 매우 다릅니다. 하나의 윈도우든 상당한 크기의 미니배치에 대해서든, 미니 배치는 비교적 몇개의 단어로 되어 있기 때문에, 만약 32미니배치에 10개의 윈도우로 되어 있다면, 아마도 거기엔 100개나 150개의 단어가 들어 있을 거고, 우리는 25만 단어장에 대한 모델을 만들겠죠. 그래서 이 벡터 안의 모든 원소가 0인 경우에 대해서, 우리는 일종의 매우 성긴 (sparse) 파라미터 업데이트를 가집니다.

    그래서 우리는 아마 나타나는 워드 벡터만 업데이트 하고 싶은 거죠. 이걸 할 수 있을까요? 멍청한 방법은 거의 모두 다 0인 행렬 가지고 두 행렬을 더하는 거죠. 행렬의 어떤 행들만 업데이트하는 성긴 행렬 업데이트를 가질 수 있을까요? 그때 행렬을 여러분이 입력한 단어만 가지고 있어서 더 빨리 동작해야 하는 거죠. 만약 여러분이 더 영리한 뭔가를 하려면, 예를 들어, 여러 컴퓨터에 걸쳐 여러분의 파라미터를 공유하는 분산 컴퓨팅 같은 것 말인데요. 그럼 분명 여러분은 파라미터 추정을 얻을 수 있는 그 워드 벡터만 업데이트하고 싶을 겁니다.

    몇 사람이 질문했었는데, 왜 중심 것과 주변것의 2개의 워드 벡터들이 있을까요? 답은 제가 보여 준 수학을 쉽게 만들었다는 것입니다. 제가 말한 대로 하면, 작업할 때 중앙 단어에 대한 부분미분은 보여준대로 쉬워요. 만약 하나의 워드 벡터의 셋만 사용하면, 문맥 단어들에 대한 소프트맥스 작업을 했을 때 중심 단어도 선택될 것입니다. 그럼 두개의 레퍼런스에 대해서 이 항들을 얻을 수 있고 제곱된 항도 얻을 수 있는데, 같은 단어들을 가리키게 되면 수학이 더 어려워 집니다. 일종의 실용적인 것을 얘기하면, 결국은 그건 큰 차이가 없습니다. 왜냐면 생각해 보면, 모든 포지션 전체를 거치기 때문이죠. 한 지점에서 가운데 단어였던 것이 즉시 후에 문맥 단어가 되고, 문맥 단어였던 것이 중심 단어가 됩니다. 그래서 같은 계산을 하는 겁니다. 왜냐면, 내적은 결국 계속 반복해서 대칭적이니까요. 그들은 꽤 비슷한 벡터 표현을 얻습니다. 일반적으로 여러분은 두 벡터에 대해 나온 것을 평균냄으로써 최선의 결과를 얻을 수 있을 것입니다. 결국은 단어 마다 하나의 벡터를 얻게 되죠.

    워드2벡 (word2vec) 논문으로 가서 보면 워드2벡 이상의 것이 있다는 것을 알게 되죠 . 그것들은 일종의 워드2벡 가족 (family)을 정의합니다. 그 가족의 2개의 메인 파트가 있는데, 첫째는 연속 단어 가방 모델 (continous bag of words model) 과 스킵 그램 모델 (skip-gram model) 중에 선택하는 것입니다. 스킵 그램 모델을 보여줬는데, 스킵 그램 모델에선 여러분이 하나의 중앙 단어를 얻어서, 한번에 문맥 내에서 모든 단어를 예측하려고 합니다. 연속 단어 가방 모델에 대해서는 그게 반대입니다. 여러분은 모든 주변 단어를 얻고 그 모든 단어를 사용하려 할겁니다. 비록 독립적으로 고려되지만, 나이브 베이즈 모델이 중앙 단어를 예측하려고 하는 것 처럼요. 두번째 건 이 학습을 보여준 방식은 나이브 (naive) 소프트맥스를 사용한 방식이라서 이게 동작하려면, 문맥 단어에 대해 확률 추정을 원한다고 말하는 것이죠. 우리는 전체 단어장에 대해 합을 구할 거고 이 확률 추정을 얻을 것입니다. 실제에서는 나쁜 아이디어로 밝혀졌는데, 왜냐면 그건 엄청 느립니다.

    문제는 우리가 미분하기 위해서 사용했던 이 방정식을 사용하면, 이 분모는 전체 단어장에 대한 합을 구하는데, 만약 여러분이 25만 단어가 있다면, 우리는 내적을 25만번해야 하고, 지수연산을 하고 그 다음 다 더해서 분모를 만들죠. 그건 정말 나쁜 아이디어죠. 빠르게 하기 위해 토마스 미코로브 (Thomas Mikolov)와 동료들은 음의 샘플링 (negative sampling)이 충분하게 해결 할 거라고 생각했습니다. 음의 샘플링 아이디어는 그 대신 바이너리 로지스틱 리그레션 (binary logistic regression)을 학습하는 겁니다. 그래서 우리는 분자에 있는 관찰된 실제 단어에 대해서 하나의 바이너리 로지스틱 회귀를 훈련시키는 거죠. 여러분은 실제로 관찰된 단어에 높은 확률을 주고 싶을 겁니다. 그리고 나면, 우리는 다른 단어 묶음을 임의로 샘플링할건데 그것들이 음의 샘플이죠 그들은 실제 보인게 아닙니다. 여러분들은 그 단어들에 가능한한 낮은 확률을 주려고 해야죠.

    논문에서 쓰인 표기인데 제가 쓴것과 좀 다르죠. 그들은 최소화 대신 최대화를 썼죠. 여기 시그모이드 (sigmoid) 함수가 잇는데, 시그모이드는 일반적으로 이렇게 쓰이죠. 1 / (1 + e^(-x))로요. 하지만, 본질적으로 시그모이드 함수는 소프트맥스의 바이너리 케이스입니다. 우리는 예와 아니오의 2개의 가능한 답이 있죠. 그리고 여러분은 일종의 입력이 있는데 그건 모든 실수가 해당됩니다. 그걸 0과 1사이의 바이너리 결과를 나타내는 확률 분포로 매핑합니다. 그 숫자가 양수인 정도에 따라 1까지 올라가고, 음수는 0까지 내려가죠. 우리는 좋은 단어에 대해 내적을 할 건데, 결국 2개의 벡터에 대해 내적을 할거고, 그걸 시그모이드로 밀어넣죠. 그리고 우리는 확률 추정이 가능한 높길 바랍니다.

    이 버전을 보면 약간 다르게 쓰인 건데, 가능한한 지난번에 사용한 표기와 비슷하게 쓰려고 했습니다. 여기 음의 샘플링을 위한 우리의 새로운 목표 함수가 있는데, 2개의 항이 있죠. 첫번째 것은 관찰된 문맥 단어의 시그모이드의 로그죠. 바깥쪽 단어들과 중심단어의 내적이구요. 우리는 이게 크길 바랄겁니다. 다른 한쪽엔 임의로 고를  K개의 단어가 있는데, 그냥 다른 단어들이죠. 그것들과 중심 단어들과 내적을 할 거고 그게 가능한 작길 바랄 겁니다. 이전 식과 달리 마이너스 표시가 추가된 것에 주의해야 합니다. 이게 음의 샘플들이고요. 큰 K에 대해선 그건 합리적인 보통의 숫자일 수 있는데, 10, 15개의 음의 샘플링을 취해보면 그것들은 잘 동작합니다.우리가  음의 샘플이 되도록 몇 단어들을 샘플한다고 했는데, 그것들은 매우 자주 등장하는 단어에 대한 문제를 다루는 걸 부분적으로 약간 도와주는 샘플링 분포를 제안합니다. 어떻게 단어를 샘플링할 것인가에 대해서는 우리는 유니그램 분포 (unigram distribution)라는 것을 쓰죠. 그건 큰 말뭉치에서 단어들을 취해서 독립적인 단어로 각각이 얼마나 나타났는지 세는 거죠. 그게 유니그램 카운트입니다. 그걸로 시작해서, 그걸  3/4제곱하여 키우면 매우 자주 등장한 단어를 샘플링 하는 걸 줄이는 효과가 있죠. 그리고 드문 단어를 샘플링할 빈도를 높이구요. 대문자 Z는 정규화 항으로 쓰입니다. 만약 여러분이 단어의 확률 분포를 원한다면, 단어장의 모든 단어에 대해 센 숫자에 3/4 제곱을 하고, 단어장에 대해 이 숫자를 모두 더하면 총합이 되고, 그걸 Z로 나누면 우리는 확률 분포를 가지게 되죠.

    댓글

Designed by Tistory.