word2vec

논문

 

아티클

프로젝트

유용한 자료

 

 

gunicorn에서의 공유 메모리(heroku)

heroku에 doc2vec으로 학습한 데이터를 올려서 조회해보는 아주 간단한 앱을 만들어서 올렸다. django를 이용했으니, view.py에 golobal model 변수에 대해서 ‘if model =  None이면 모델을 읽어라.’ 라고 코딩했다. 완벽하다. 그런데, 분명히 모델을 읽었음에도 불구하고, global model변수가 None이라고 하면서 다시 읽어들인다.

얼추 검색해보니, wsgi인지 gunicorn인지 뭔지 모르겠으나, 이놈들이 python 웹을 멀티 프로세스(또는 쓰레드?)로 띄워주기 때문에, worker 가 달라지면 global변수가 공유가 안된단다. 아유 골치아파…

그래서 프로세스간 메모리 공유에 대해서 알아봐야한다.

worker를 1개로 줄인다.(O)

worker가 2개 이상이 되면, 새로운 work가 초기화될때마다 전역변수를 새롭게 설정해주어야한다. 따라서 워커를 하나로 줄이면 서비스의 scalability는 낮아지지만, 메모리는 최소화하여 사용할 수 있다. heroku에서 아래와 같이 하면 워커를 1개로 설정할 수 있다.

 

캐싱 방법을 찾아본다.(사이즈 제한이 있음)

https://devcenter.heroku.com/articles/memcachier#django

단, 수MB이하의 데이터를 캐싱하는 것만 허락한다. 그리고 또한 redis등으로 캐싱할 경우 사이즈당 요금이 비싸다. 이건 포기…

 

 

Doc2Vec 시작하기

Doc2Vec은(일명 paragraph2vec 또는 문장 임메딩)에 word2vec 알고리즘을 문장, 단락 또는 전체 문서와 같이 더 큰 텍스트 블록에 대한 연속 표현을 비지도학습하도록 수정되었습니다.

시작하기

비교하고 훈련할 문서가 있는 폴더를 준비하자.  모델이 얼마나 정확한지 결정하는 요소들이 있다.

  • 코퍼스의 크기, 문서의 개수, 문서가 많을 수록 좋다.
  • 문서의 유사성, 비슷할수록 좋다.

Doc2Vec은 모델을 훈련할때 주가지를 사용한다. 라벨과 실제 데이터. 라벨은 아무것이어도 상관 없다. 문서의 파일명을 라벨로 하면 편리하다.

입력

doc2vec은 word2vec의 확장이기 때문에 사용 패턴이 유사하다.  표현의 크기, 슬라이딩 윈도우의 크기, 작업자 수 또는 word2vec 모델로 변경할 수 있는 거의 모든 다른 매개변수를 쉽게 조정할 수 있다.

이 규칙의 한가지 예외는 모델에서 사용한 교육방법과 관련된 매개변수이다.  word2vec 아키텍쳐에서는 두개의 중요 알고리즘이 있는데 “continuous bag of words”(CBOW)와 “skip-gram”(sg) 입니다. doc2vec 아키텍처에서는 “distributed memory”(dm)과 “distributed bag of words”(dbow)이다. 분산메모리 모델이 논문에서 훨씬 좋은 수행을 보였기에 이를 기본으로 사용한다. 원한다면 dm=0 플래그를 설정하여 dbow모델을 강제 실행할 수 있다.

doc2vec의 입력은 LabeledSentence 객체의 iterator이다. 각 객체는 하나의 문장을 나타내며 단어 목록과 레이블 목록으로 구성된다.

sentence = LabeledSentence(words=[u'some', u'words', u'here'], labels=[u'SENT_1'])

그런다음 알고리즘은 sentence iterator를 두번 수행한다.: 한번은 vocab를 빌드하고, 한번은 입력 데이터에서 모델을 학습하고, 각 단어 및 데이터 세트의 각 레이블에 대한 벡터 표현을 학습한다. 이 아키텍처에서는 문장당 둘 이상의 레이블을 사용할 수 있지만 가장 많이 사용되는 경우는 문장의 고유 식별자인 문장당 하나의 레이블을 갖는 것이다. 트레이닝 데이터로 다음의 클래스를 사용하여 한 줄에 한 문장의 파일에 대해 이러한 종류의 사용 사례를 구현할 수 있다.

 

 

학습하기

doc2vec은 단어와 레이블에 대한 표현을 동시에 학습한다. 단어에 대한 표현만을 학습하려면, doc2vec 클래스에서 train_lbls=False 플래그를 사용할 수 있다. 마찬가지로 레이블에 대한 표현을 배우고 단어 표현을 고정된 상태로 유지하려면 train_words= False 플래그를 사용한다.

이 알고리즘에 대한 한가지 주의사항은 데이터를 반복하는 과정에서 학습 속도가 감소하기 때문에 교육중 단일 LabeledSentence에서만 관측되는 레이블은 고정학습 속도로만 학습된다. 데이터를 여러 번 반복하여 더 좋은 결과를 얻을 수 있다.

예를 들어, 10 epoch동안 학습속도를 수동으로 제어하려는 경우 다음과 같이 사용할 수 있다.

코드는 원본 word2vec과 마찬가지로 최적화된 C(Cython)에서 실행되므로 매우 빠르다.

라벨과 데이터 읽기

먼저 문서파일의 경로를 배열에 저장한다. 이 또한 우리의 라벨로 활용될 것이다. :

docLabels 변수에는 문서의 전체 파일 이름을 저장하고 있고 이 파일의 컨텐츠를 이용하여 트레이닝을 할 것이다.

 

파일이 너무 크면 메모리 부족 오류가 발생할 수도 있겠지만… 웬만해선 괜찮을것 같다.

 

I/O

doc2vec의 사용은 word2vec의 사용법과 같다. 일반적인 방식으로 doc2vec 인스턴스를 저장하고 로드할 수 있다. : 직접 파이썬 피클을 사용하거나 Doc2Vec.save() 및 Doc2Vec.load() 메쏘드 사용 :

model.most_similar() ,  model.doesnt_match() ,  model.similarity()  도 모두 존재한다. 생(raw) 단어와 라벨 벡터들은   model['word'] 를 통해 개별적으로 접근할 수 있고  model.syn0 을 통해 전체를 접근할 수 있다.

요점은 라벨은 doc2vec에서의 단어와 같은 방식으로 동작한다. 따라서 가장 비슷한 단어/문장을 첫번째 문장 (예: SENT_0 라벨)에 표시하려면,

또는 해당 문장에 대한 raw embedding 을 가져 오려면,

 

Doc2Vec을 위한 데이터 준비하기

Doc2Vec은 LabeledSentence 에 있는 데이터를 이용하여 트레이닝한다. 앞에서 보여줬던 클래스를 다음과 같이 수정하여 사용한다.

먼저, raw 데이터와 레이블 목록을 모두 제공할 수 있도록 생성자를 변경한다.

다음으로 iter를 모든 docs에 반복하도록 변경하고 각 document의 레이블로 문서 filename을 넣는다.

gensim에서는 모델을 작성할 때 문장 또는 전체 문서를 iter-object로 사용하더라도 모델은 항상 단어단위로 학습하게 된다. 따라서 문서를 단어 배열로 분할한다.

NLTK 토크나이저를 사용하면 더 나은 결과를 얻을 수 있겠지만 큰 차이가 나지 않을 것이다.

모델 훈련하기

위의 dociterator의 수정된 버전을 사용하여 먼저 iter객체를 만든다. 그리고 데이터와 레이블을 전달한다.

다음으로  이제 모델을 훈련하자 :

그다음으로 모델을 저장한다. 모델을 저장하는 것은 대부분의 경우 옳다. 교육에는 시간이 많이 소요되기 때문이다.

 

모델 테스트하기

모델을 사용해보자. gensim의 내장 함수로 쉽게 테스트 해볼수 있다.

되었다. 이제 훈련된 벡터를 이용하여 이들사이의 거리를 계싼하거나 SVM에서 분류의 용도로 사용할 수 있다. 각 세트의 raw 고정 크기 벡터를 얻으려면

끝.

 

참조

  • https://medium.com/@klintcho/doc2vec-tutorial-using-gensim-ab3ac03d3a1
  • https://rare-technologies.com/doc2vec-tutorial/