레이블이 doc2vec인 게시물을 표시합니다. 모든 게시물 표시
레이블이 doc2vec인 게시물을 표시합니다. 모든 게시물 표시

2020년 2월 17일 월요일

doc2vec 예제 분석(4)




이전 내용

https://swlock.blogspot.com/2020/01/doc2vec.html


학습 방법

이번에 논의할 주제는 학습 방법에 대한 내용입니다.
doc2vec예제를 많이 찾다보면 가장 일반적인 예제가 아래와 같은 예제입니다.

기존에 사용한 예제
model = Doc2Vec(size=vec_size,
                alpha=alpha, 
                min_alpha=0.00025,
                min_count=1,
                dm =1)
  
model.build_vocab(tagged_data)

for epoch in range(max_epochs):
    print('iteration {0}'.format(epoch))
    model.train(tagged_data,
                total_examples=model.corpus_count,
                epochs=model.iter)
    # decrease the learning rate
    model.alpha -= 0.0002
    # fix the learning rate, no decay
    model.min_alpha = model.alpha


train함수를 이용해 반복적으로 학습 시키는 형태입니다. 하지만 Doc2Vec는 기본적으로 반복적으로 호출 안하고도 한번에 학습 할 수 있는 함수입니다.
따라서 이번에는 기존에 사용한 학습을 변경해서 한번에 학습 하는 형태로 변경해보고, 두개의 효율을 비교해 보겠습니다.

위 코드는 아래와 같이 epochs=max_epochs 라고 만 추가로 넣어주면 됩니다.
변경된 코드
model = Doc2Vec(tagged_data,size=vec_size,
                alpha=alpha, 
                min_alpha=0.00025,
                min_count=1,
                dm =1,epochs=max_epochs)

그럼 효율은 어떨까요?
테스트 해본결과 처음 코드 보다 결과도 좋고 속도도 더 빠릅니다.
이유를 고민해봤는데 처음 코드에 train시 epochs=model.iter 이 부분은 실제 출력해보면 model.iter는 5가 들어있습니다. 즉 100회 train을 했을때 100*5 회 train이 됩니다. 많은 예제들이 왜 이렇게 되어있는지는 모르겠지만, 나중에 train을 하는 방식이 아니라면 처음부터 epochs에 값을 넣어서 train하는것을 추천 합니다.

테스트 해봤을때 결론은 epochs 100회는 작아서 값이 흔들리지만 epochs 1000회로 했을때 항상 같은 값이 나오며 기존 예제보다 빠릅니다.

예제 소스
#Import all the dependencies
from gensim.models.doc2vec import Doc2Vec, TaggedDocument
from nltk.tokenize import word_tokenize

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

data = ["I love machine learning. Its awesome.",
        "I love coding in python",
        "I love building chatbots",
        "they chat amagingly well"]

tagged_data = []

for i, _d in enumerate(data):
 tagged_data.append(TaggedDocument(words=word_tokenize(_d.lower()), tags=[str(i)]))

print(tagged_data)

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

max_epochs = 1000
vec_size = 20
alpha = 0.025

model = Doc2Vec(tagged_data,size=vec_size,
                alpha=alpha, 
                min_alpha=0.00025,
                min_count=1,
                dm =1,epochs=max_epochs)
"""
model.build_vocab(tagged_data)

for epoch in range(max_epochs):
    print('iteration {0}'.format(epoch))
    model.train(tagged_data,
                total_examples=model.corpus_count,
                epochs=model.iter)
    # decrease the learning rate
    model.alpha -= 0.0002
    # fix the learning rate, no decay
    model.min_alpha = model.alpha
"""

model.save("d2v.model")
print("Model Saved")

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

from gensim.models.doc2vec import Doc2Vec

model= Doc2Vec.load("d2v.model")
#to find the vector of a document which is not in training data
test_data = word_tokenize("I love chatbots".lower())
v1 = model.infer_vector(test_data)
print("V1_infer", v1)

# to find most similar doc using tags
similar_doc = model.docvecs.most_similar('1')
print(similar_doc)
# to find vector of doc in training data using tags or in other words, printing the vector of document at index 1 in training data
print(model.docvecs['1'])
print(model.docvecs.most_similar(positive=[model.infer_vector(test_data)],topn=5))


결과
C:\Users\USER\Documents\python\doc2vec>python 2.py
[TaggedDocument(words=['i', 'love', 'machine', 'learning', '.', 'its', 'awesome', '.'], tags=['0']), TaggedDocument(words=['i', 'love', 'coding', 'in', 'python'], tags=['1']), TaggedDocument(words=['i', 'love', 'building', 'chatbots'], tags=['2']), TaggedDocument(words=['they', 'chat', 'amagingly', 'well'], tags=['3'])]
C:\Users\USER\AppData\Local\Programs\Python\Python37\lib\site-packages\gensim\models\doc2vec.py:574: UserWarning: The parameter `size` is deprecated, will be removed in 4.0.0, use `vector_size` instead.
  warnings.warn("The parameter `size` is deprecated, will be removed in 4.0.0, use `vector_size` instead.")
Model Saved
V1_infer [-0.1478307  -0.12874664  0.37128845 -0.03459457  0.57580817  0.04165906
 -0.161333    0.27196127 -0.21677573  0.01032528  0.25623006  0.5556566
  0.12414648 -0.54218525 -0.208055   -0.52243584  0.3771771   0.5290485
 -0.4843504  -0.17298844]
[('2', 0.9900819063186646), ('3', 0.9708542823791504), ('0', 0.970792293548584)]
[-0.0752231  -0.35064244  0.34328702  0.08152835  0.6884224  -0.03017065
 -0.29200274  0.27554145 -0.22331765  0.09528319  0.25715432  0.72438854
  0.03624368 -0.6178097  -0.2795767  -0.76473147  0.44413832  0.69012666
 -0.66727465 -0.21889076]
[('2', 0.9923702478408813), ('1', 0.9780316352844238), ('3', 0.9494951963424683), ('0', 0.9215951561927795)]

C:\Users\USER\Documents\python\doc2vec>python 2.py
[TaggedDocument(words=['i', 'love', 'machine', 'learning', '.', 'its', 'awesome', '.'], tags=['0']), TaggedDocument(words=['i', 'love', 'coding', 'in', 'python'], tags=['1']), TaggedDocument(words=['i', 'love', 'building', 'chatbots'], tags=['2']), TaggedDocument(words=['they', 'chat', 'amagingly', 'well'], tags=['3'])]
C:\Users\USER\AppData\Local\Programs\Python\Python37\lib\site-packages\gensim\models\doc2vec.py:574: UserWarning: The parameter `size` is deprecated, will be removed in 4.0.0, use `vector_size` instead.
  warnings.warn("The parameter `size` is deprecated, will be removed in 4.0.0, use `vector_size` instead.")
Model Saved
V1_infer [ 0.11019158  0.51370174 -0.26823092  0.65347505  0.4890385  -0.22247577
 -0.23286937  0.05573504  0.18244551  0.66818357  0.35685948 -0.4554677
 -0.2638483   0.3127647   0.165362    0.10424155  0.04493263 -0.06063128
  0.26513922 -0.1957828 ]
[('2', 0.9853891730308533), ('3', 0.9765698909759521), ('0', 0.9650870561599731)]
[ 0.01700659  0.5642358  -0.4336092   0.8316983   0.5487111  -0.33020684
 -0.35978654  0.00089785  0.08480686  0.790529    0.3226167  -0.69981
 -0.31057844  0.5498898   0.11522991  0.2883605   0.09612332 -0.07747563
  0.44214472 -0.16630754]
[('2', 0.9960660338401794), ('1', 0.978064775466919), ('3', 0.961208164691925), ('0', 0.9451479315757751)]

C:\Users\USER\Documents\python\doc2vec>python 2.py
[TaggedDocument(words=['i', 'love', 'machine', 'learning', '.', 'its', 'awesome', '.'], tags=['0']), TaggedDocument(words=['i', 'love', 'coding', 'in', 'python'], tags=['1']), TaggedDocument(words=['i', 'love', 'building', 'chatbots'], tags=['2']), TaggedDocument(words=['they', 'chat', 'amagingly', 'well'], tags=['3'])]
C:\Users\USER\AppData\Local\Programs\Python\Python37\lib\site-packages\gensim\models\doc2vec.py:574: UserWarning: The parameter `size` is deprecated, will be removed in 4.0.0, use `vector_size` instead.
  warnings.warn("The parameter `size` is deprecated, will be removed in 4.0.0, use `vector_size` instead.")
Model Saved
V1_infer [-0.12817842  0.15201263 -0.35161802  0.06387527  0.09849352  0.4477839
  0.05868901 -0.7434576  -0.41151583  0.22117768 -0.19870114  0.45456207
  0.29246542  0.27406123 -0.4315686   0.37656972 -0.5473998   0.05305056
  0.2825684   0.16648887]
[('2', 0.9858678579330444), ('0', 0.9623578786849976), ('3', 0.9542171955108643)]
[-0.20036705  0.13212322 -0.47465435  0.12010227  0.23122686  0.504441
 -0.01674547 -1.1015012  -0.4765742   0.24642535 -0.39708486  0.5127476
  0.3206394   0.3630215  -0.4660666   0.30893013 -0.6207208   0.03018731
  0.28201237  0.3812475 ]
[('2', 0.9939821362495422), ('1', 0.979041337966919), ('3', 0.9386898875236511), ('0', 0.9325041770935059)]

epochs 1000일때 여러번 시험시에도 모두 같은 결과를 얻었습니다.




2020년 2월 9일 일요일

doc2vec 예제 분석(3)


이전 내용


https://swlock.blogspot.com/2020/01/doc2vec.html

앞에서 기본 예제에 대해서 살펴 보았습니다.

이번에 다룰 주제는 '비슷한 문장인 경우 어떻게 찾을까?' 입니다.
이전 예제는 이미 존재하는 label과 가장 비슷한 문장을 찾는 예제였습니다.

similar_doc = model.docvecs.most_similar('1')




들어가기 앞서

먼저 공식 link를 살펴 보도록 하겠습니다. 이중에 wv, docvecs 라는것이 있습니다.
https://radimrehurek.com/gensim/models/doc2vec.html


class gensim.models.doc2vec.Doc2Vec(documents=Nonecorpus_file=Nonedm_mean=Nonedm=1dbow_words=0dm_concat=0dm_tag_count=1docvecs=Nonedocvecs_mapfile=Nonecomment=Nonetrim_rule=Nonecallbacks=()**kwargs)
Bases: gensim.models.base_any2vec.BaseWordEmbeddingsModel
Class for training, using and evaluating neural networks described in Distributed Representations of Sentences and Documents.
Some important internal attributes are the following:
wv
This object essentially contains the mapping between words and embeddings. After training, it can be used directly to query those embeddings in various ways. See the module level docstring for examples.
Type
Word2VecKeyedVectors
docvecs
This object contains the paragraph vectors learned from the training data. There will be one such vector for each unique document tag supplied during training. They may be individually accessed using the tag as an indexed-access key. For example, if one of the training documents used a tag of ‘doc003’:
>>> model.docvecs['doc003']
Type
Doc2VecKeyedVectors


WordVector

document 관련된 기능이지만 내부적으로word vector도 관리를 합니다. 그래서 word도 처리가 가능합니다. wv는 wordvector라서 아래 와 같이 단어를 넣어서 비슷한 값을 구할 수 있습니다.

print(doc_vectorizer.wv.most_similar(positive=['영화', '남자배우'], negative=['여배우']))

사용법은 아래 블로그 참고 하시면 됩니다.
http://hero4earth.com/blog/projects/2018/01/21/naver_movie_review/



docvecs.most_similar 이용

docvecs.most_similar 이용하더다도 뒤쪽에 인자를 어떻게 사용하는지 궁금합니다. 간단합니다. positive에 token화된 vector를 넣으면 됩니다. model.infer_vector 이것이 vector로 변환하는것입니다.

Document Similarity using doc2vec 

# find most similar doc 
test_doc = word_tokenize("That is a good device".lower())
model.docvecs.most_similar(positive=[model.infer_vector(test_doc)],topn=5)
출처는 아래 링크입니다.
https://www.thinkinfi.com/2019/10/doc2vec-implementation-in-python-gensim.html



소스 작업

지난번에 작업한 소스를 수정해 보도록 하겠습니다.

소스
from gensim.models.doc2vec import Doc2Vec, TaggedDocument
from nltk.tokenize import word_tokenize

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

data = ["I love machine learning. Its awesome.",
        "I love coding in python",
        "I love building chatbots",
        "they chat amagingly well"]

tagged_data = []

for i, _d in enumerate(data):
 tagged_data.append(TaggedDocument(words=word_tokenize(_d.lower()), tags=[str(i)]))

print(tagged_data)

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

max_epochs = 1000
vec_size = 20
alpha = 0.025

model = Doc2Vec(size=vec_size,
                alpha=alpha, 
                min_alpha=0.00025,
                min_count=1,
                dm =1)
  
model.build_vocab(tagged_data)

for epoch in range(max_epochs):
    #print('iteration {0}'.format(epoch))
    model.train(tagged_data,
                total_examples=model.corpus_count,
                epochs=model.iter)
    # decrease the learning rate
    model.alpha -= 0.0002
    # fix the learning rate, no decay
    model.min_alpha = model.alpha

model.save("d2v.model")
print("Model Saved")

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


from gensim.models.doc2vec import Doc2Vec

model= Doc2Vec.load("d2v.model")
#to find the vector of a document which is not in training data
test_data = word_tokenize("I love chatbots".lower())

print(model.docvecs.most_similar(positive=[model.infer_vector(test_data)],topn=5))

결과 화면
[TaggedDocument(words=['i', 'love', 'machine', 'learning', '.', 'its', 'awesome', '.'], tags=['0']), TaggedDocument(words=['i', 'love', 'coding', 'in', 'python'], tags=['1']), TaggedDocument(words=['i', 'love', 'building', 'chatbots'], tags=['2']), TaggedDocument(words=['they', 'chat', 'amagingly', 'well'], tags=['3'])]
C:\Users\USER\AppData\Local\Programs\Python\Python37\lib\site-packages\gensim\models\doc2vec.py:574: UserWarning: The parameter `size` is deprecated, will be removed in 4.0.0, use `vector_size` instead.
  warnings.warn("The parameter `size` is deprecated, will be removed in 4.0.0, use `vector_size` instead.")
29.py:37: DeprecationWarning: Call to deprecated `iter` (Attribute will be removed in 4.0.0, use self.epochs instead).
  epochs=model.iter)
Model Saved
[('2', 0.999824047088623), ('1', 0.9997918009757996), ('0', 0.9997824430465698), ('3', 0.9994299411773682)]
결론을 살펴보면 'I love chatbots'과 가장 비슷한 문장은 '2'번 "I love building chatbots"문





2020년 2월 3일 월요일

doc2vec 예제 분석(2)


https://swlock.blogspot.com/2020/01/doc2vec.html

앞에서 두가지 해야할 일을 남겨두었습니다.
이글은 그중에서 첫번째 이야기 입니다.

지난번 게시글에서 sample 코드로 해본것이 할때마다 다른값을 가지는것 같다고 하였습니다. 원하는 결과가 나오는것 같지도 않고요, 결론부터 얘기하자면 학습 횟수가 작아서 그렇습니다.
예제 코드를 만든 사람이 잘못 만들었다고 보는게 좋을것 같습니다. 그러면 1000, 2000 올려서 어떻게 되는지 같은 예제를 가지고 시험 해보겠습니다.

warning 제거

시작하기 전에 기존 코드에 waring이 많아서 제거하는 작업이 필요합니다.

1. iter 제거

아래와 같은 경고가 발생합니다.
doc2vectut.py:37: DeprecationWarning: Call to deprecated `iter` (Attribute will be removed in 4.0.0, use self.epochs instead).
  epochs=model.iter)

To avoid common mistakes around the model’s ability to do multiple training passes itself, an explicit epochs argument MUST be provided. In the common and recommended case where train() is only called once, you can set epochs=self.iter.

이렇게 되어있음에도 iter사용하면 안된다고 합니다. epochs로 사용하면 warning 사라집니다.

2. size 제거

C:\Users\USER\AppData\Local\Programs\Python\Python37\lib\site-packages\gensim\models\doc2vec.py:574: UserWarning: The parameter `size` is deprecated, will be removed in 4.0.0, use `vector_size` instead.
  warnings.warn("The parameter `size` is deprecated, will be removed in 4.0.0, use `vector_size` instead.")
iteration 0
이 부분을 size=vec_size => vec_size=vec_size 이렇게 조정하면 됩니다.

변경된 예제

epochs 100,1000,2000번 하도록 수정함
#Import all the dependencies
from gensim.models.doc2vec import Doc2Vec, TaggedDocument
from nltk.tokenize import word_tokenize

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

data = ["I love machine learning. Its awesome.",
        "I love coding in python",
        "I love building chatbots",
        "they chat amagingly well"]

tagged_data = []

for i, _d in enumerate(data):
 tagged_data.append(TaggedDocument(words=word_tokenize(_d.lower()), tags=[str(i)]))

print(tagged_data)

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

epochs = [100,1000,2000]

for max_epochs in epochs:
 vec_size = 20
 alpha = 0.025

 model = Doc2Vec(vec_size=vec_size,
     alpha=alpha, 
     min_alpha=0.00025,
     min_count=1,
     dm =1)
 

 
 model.build_vocab(tagged_data)
 #model.init_sims(replace=False)
 print("epoch count : ",max_epochs)

 for epoch in range(max_epochs):
  #print('iteration {0}'.format(epoch))
  model.train(tagged_data,
     total_examples=model.corpus_count,
     epochs=model.epochs)
  # decrease the learning rate
  model.alpha -= 0.0002
  # fix the learning rate, no decay
  model.min_alpha = model.alpha

 model.save("d2v.model")
 #model.clear_sims()
 
 print("Model Saved")

 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


 from gensim.models.doc2vec import Doc2Vec

 model= Doc2Vec.load("d2v.model")
 #to find the vector of a document which is not in training data
 test_data = word_tokenize("I love chatbots".lower())
 #v1 = model.infer_vector(test_data)
 #print("V1_infer", v1)

 # to find most similar doc using tags
 similar_doc = model.docvecs.most_similar('1')
 print(similar_doc)

여러번 시험한 결과

C:\Users\USER\Documents\python\doc2vec>python 23.py
[TaggedDocument(words=['i', 'love', 'machine', 'learning', '.', 'its', 'awesome', '.'], tags=['0']), TaggedDocument(words=['i', 'love', 'coding', 'in', 'python'], tags=['1']), TaggedDocument(words=['i', 'love', 'building', 'chatbots'], tags=['2']), TaggedDocument(words=['they', 'chat', 'amagingly', 'well'], tags=['3'])]
epoch count :  100
Model Saved
[('0', 0.9945449829101562), ('2', 0.9924600124359131), ('3', 0.9910708665847778)]
epoch count :  1000
Model Saved
[('0', 0.9999822378158569), ('2', 0.9999727010726929), ('3', 0.9998421669006348)]
epoch count :  2000
Model Saved
[('0', 0.9999822378158569), ('2', 0.9999727010726929), ('3', 0.9998533725738525)]

C:\Users\USER\Documents\python\doc2vec>python 23.py
[TaggedDocument(words=['i', 'love', 'machine', 'learning', '.', 'its', 'awesome', '.'], tags=['0']), TaggedDocument(words=['i', 'love', 'coding', 'in', 'python'], tags=['1']), TaggedDocument(words=['i', 'love', 'building', 'chatbots'], tags=['2']), TaggedDocument(words=['they', 'chat', 'amagingly', 'well'], tags=['3'])]
epoch count :  100
Model Saved
[('0', 0.9962625503540039), ('3', 0.9957269430160522), ('2', 0.9942873120307922)]
epoch count :  1000
Model Saved
[('0', 0.9999853372573853), ('2', 0.9999737739562988), ('3', 0.999885082244873)]
epoch count :  2000
Model Saved
[('0', 0.9999853372573853), ('2', 0.9999737739562988), ('3', 0.9998925924301147)]

C:\Users\USER\Documents\python\doc2vec>python 23.py
[TaggedDocument(words=['i', 'love', 'machine', 'learning', '.', 'its', 'awesome', '.'], tags=['0']), TaggedDocument(words=['i', 'love', 'coding', 'in', 'python'], tags=['1']), TaggedDocument(words=['i', 'love', 'building', 'chatbots'], tags=['2']), TaggedDocument(words=['they', 'chat', 'amagingly', 'well'], tags=['3'])]
epoch count :  100
Model Saved
[('0', 0.9967427849769592), ('2', 0.9945513606071472), ('3', 0.9939110279083252)]
epoch count :  1000
Model Saved
[('0', 0.999987781047821), ('2', 0.9999759793281555), ('3', 0.9998540878295898)]
epoch count :  2000
Model Saved
[('0', 0.999987781047821), ('2', 0.9999759793281555), ('3', 0.9998698234558105)]

C:\Users\USER\Documents\python\doc2vec>python 23.py
[TaggedDocument(words=['i', 'love', 'machine', 'learning', '.', 'its', 'awesome', '.'], tags=['0']), TaggedDocument(words=['i', 'love', 'coding', 'in', 'python'], tags=['1']), TaggedDocument(words=['i', 'love', 'building', 'chatbots'], tags=['2']), TaggedDocument(words=['they', 'chat', 'amagingly', 'well'], tags=['3'])]
epoch count :  100
Model Saved
[('0', 0.9953392744064331), ('2', 0.9942353367805481), ('3', 0.9917100667953491)]
epoch count :  1000
Model Saved
[('0', 0.999980628490448), ('2', 0.9999741315841675), ('3', 0.9998222589492798)]
epoch count :  2000
Model Saved
[('0', 0.9999832510948181), ('2', 0.9999783635139465), ('3', 0.999845027923584)]

C:\Users\USER\Documents\python\doc2vec>python 23.py
[TaggedDocument(words=['i', 'love', 'machine', 'learning', '.', 'its', 'awesome', '.'], tags=['0']), TaggedDocument(words=['i', 'love', 'coding', 'in', 'python'], tags=['1']), TaggedDocument(words=['i', 'love', 'building', 'chatbots'], tags=['2']), TaggedDocument(words=['they', 'chat', 'amagingly', 'well'], tags=['3'])]
epoch count :  100
Model Saved
[('0', 0.9950520992279053), ('3', 0.992672324180603), ('2', 0.9917551875114441)]
epoch count :  1000
Model Saved
[('0', 0.9999843835830688), ('2', 0.9999716877937317), ('3', 0.9998539686203003)]
epoch count :  2000
Model Saved
[('0', 0.9999843835830688), ('2', 0.9999716877937317), ('3', 0.9998610019683838)]

C:\Users\USER\Documents\python\doc2vec>python 23.py
[TaggedDocument(words=['i', 'love', 'machine', 'learning', '.', 'its', 'awesome', '.'], tags=['0']), TaggedDocument(words=['i', 'love', 'coding', 'in', 'python'], tags=['1']), TaggedDocument(words=['i', 'love', 'building', 'chatbots'], tags=['2']), TaggedDocument(words=['they', 'chat', 'amagingly', 'well'], tags=['3'])]
epoch count :  100
Model Saved
[('2', 0.9950048327445984), ('0', 0.9948043823242188), ('3', 0.9913235306739807)]
epoch count :  1000
Model Saved
[('0', 0.9999803304672241), ('2', 0.9999801516532898), ('3', 0.9998198747634888)]
epoch count :  2000
Model Saved
[('0', 0.9999803304672241), ('2', 0.9999801516532898), ('3', 0.9998342990875244)]

C:\Users\USER\Documents\python\doc2vec>python 23.py
[TaggedDocument(words=['i', 'love', 'machine', 'learning', '.', 'its', 'awesome', '.'], tags=['0']), TaggedDocument(words=['i', 'love', 'coding', 'in', 'python'], tags=['1']), TaggedDocument(words=['i', 'love', 'building', 'chatbots'], tags=['2']), TaggedDocument(words=['they', 'chat', 'amagingly', 'well'], tags=['3'])]
epoch count :  100
Model Saved
[('0', 0.9962822198867798), ('3', 0.994450569152832), ('2', 0.9934964179992676)]
epoch count :  1000
Model Saved
[('0', 0.9999848008155823), ('2', 0.999968409538269), ('3', 0.9998449087142944)]
epoch count :  2000
Model Saved
[('0', 0.9999848008155823), ('2', 0.999968409538269), ('3', 0.9998505115509033)]

결과 설명

위 결과를 잘 살펴보면 epoch count 100에서는 '0', '2' 값이 나오는 경우도 있고 뒤의 값들도 1000, 2000번 일때와는 상당히 다른 값입니다.
결론은 epoch 횟수가 늘어남에 따라 오차도 줄어들게 된다는것을 알 수 있습니다. 제대로 하려면 error rate값을 확인하는게 맞을텐데 여기에서는 error 값을 보기가 쉽지 않습니다.

아래글에서 error_rate_for_model 부분 참고하면 학습의 error 값 구현도 가능할것 같습니다.
https://radimrehurek.com/gensim/auto_examples/howtos/run_doc2vec_imdb.html








2020년 1월 27일 월요일

doc2vec 예제 분석


doc2vec 예제 분석


오래전부터 doc2vec 예제를 좀 찾아봤습니다. 적당한 예제도 없고 자세한 설명이 부족한것 같아서 정리해 봅니다.


준비

기본 예제는 아래 링크에서 출발합니다.
python3 로 시작 합니다.

https://medium.com/@mishra.thedeepak/doc2vec-simple-implementation-example-df2afbbfbad5


시작하기전에 import 에러나는 것은 없는지 확인해봅시다.
#Import all the dependencies
from gensim.models.doc2vec import Doc2Vec, TaggedDocument
from nltk.tokenize import word_tokenize


만약 아래와 같은 에러가 난다면 nltk를 설치해 줍니다.

python doc2vectut.py
Traceback (most recent call last):
  File "doc2vectut.py", line 3, in <module>
    from nltk.tokenize import word_tokenize
ModuleNotFoundError: No module named 'nltk'

https://stackoverflow.com/questions/40361488/importerror-no-module-named-nltk-tokenize-nltk-is-not-a-package

pip install nltk


입력 데이터


학습 모델의 기본은 입력 데이터 형태부터 파악 하는것입니다. 여기 train을 위해서 입력하는 데이터를 가공 하는 소스 입니다. word2vec에서는 list의 list형태로 데이터를 넣었다면, 여기에서는 words=['i', 'love', 'machine', 'learning', '.', 'its', 'awesome', '.'], tags=['0'] 이런 형태의 데이터의 list들을 만들어서 입력으로 사용합니다.
여기에서 tags는 label이 되기를 원하는 값=목표값으로 (분류를 원하는 값) 입니다. 예를 들어보자면 영화 평점 리뷰 게시판이 있고 댓글과 평점이 있을때 학습을 하는경우 댓글 내용이 words가 되고 평점은 tags가 됩니다. 학습이 되고 나면 댓글 (words)내용을 가지고 (tags)평점이 얼마나 될지 예측이 가능하게 됩니다.
평점이 높을수록 좋은 의미를 지니므로 이것은 영화뿐 아니라 다른곳에서 사용가능한 데이터에도 응용할 수 있습니다. 영화 평점은 이런면에서 좋은 학습 데이터가 되게 됩니다.
여기 비슷하게 처리한 내용이 있네요, 한번 읽어보는것도 좋을것 같습니다.
http://hero4earth.com/blog/projects/2018/01/21/naver_movie_review/
Let’s prepare data for training our doc2vec model
data = ["I love machine learning. Its awesome.",
        "I love coding in python",
        "I love building chatbots",
        "they chat amagingly well"]

tagged_data = [TaggedDocument(words=word_tokenize(_d.lower()), tags=[str(i)]) for i, _d in enumerate(data

위 코드를 실행했을때 nltk 아래와 같은 오류가 난다면 데이터를 다운로드 받도록 합니다.

LookupError:
**********************************************************************
  Resource  [93mpunkt [0m not found.
  Please use the NLTK Downloader to obtain the resource:

   [31m>>> import nltk
  >>> nltk.download('punkt')
   [0m
  For more information see: https://www.nltk.org/data.html

  Attempted to load  [93mtokenizers/punkt/english.pickle [0m

  Searched in:
    - 'C:\\Users\\USER/nltk_data'
    - 'C:\\Users\\USER\\AppData\\Local\\Programs\\Python\\Python37\\nltk_data'
    - 'C:\\Users\\USER\\AppData\\Local\\Programs\\Python\\Python37\\share\\nltk_data'
    - 'C:\\Users\\USER\\AppData\\Local\\Programs\\Python\\Python37\\lib\\nltk_data'
    - 'C:\\Users\\USER\\AppData\\Roaming\\nltk_data'
    - 'C:\\nltk_data'
    - 'D:\\nltk_data'
    - 'E:\\nltk_data'
    - ''
**********************************************************************


nltk 데이터 다운로드 받기

http://www.nltk.org/nltk_data/

Punkt Tokenizer Models

python 실행 후 아래와 같이 실행합니다.
>>> import nltk
>>> nltk.download('punkt')


지금까지 소스와 실행한 결과입니다.

#Import all the dependencies
from gensim.models.doc2vec import Doc2Vec, TaggedDocument
from nltk.tokenize import word_tokenize

data = ["I love machine learning. Its awesome.",
        "I love coding in python",
        "I love building chatbots",
        "they chat amagingly well"]

tagged_data = [TaggedDocument(words=word_tokenize(_d.lower()), tags=[str(i)]) for i, _d in enumerate(data)]

print(tagged_data)

실행 결과
C:\Users\USER\Documents\python\doc2vec>python doc2vectut.py
[TaggedDocument(words=['i', 'love', 'machine', 'learning', '.', 'its', 'awesome', '.'], tags=['0']), TaggedDocument(words=['i', 'love', 'coding', 'in', 'python'], tags=['1']), TaggedDocument(words=['i', 'love', 'building', 'chatbots'], tags=['2']), TaggedDocument(words=['they', 'chat', 'amagingly', 'well'], tags=['3'])]


코드가 복잡한데 좀 더 쉽게 풀어서 구현한 코드는 아래와 같습니다.

tagged_data = []

for i, _d in enumerate(data):
 tagged_data.append(TaggedDocument(words=word_tokenize(_d.lower()), tags=[str(i)]))

python enumerate 는 index와 data를 분리하게 됩니다. 아래 링크 참조
https://dpdpwl.tistory.com/43


학습시키기

학습하는 데이터의 parameter는 데이터들마다 다르기 때문에 값을 바꿔가면서 이것저것 변경해봐야 합니다. 이것을 hyper parameter라고 하는데 여기 원본 문서를 참고해 가면서 의미를 파악 하시면 됩니다.
https://radimrehurek.com/gensim/models/doc2vec.html

학습의 기본은 epoch과 learning rate입니다. 여기 예제에서 max_epochs로 나온 부분이 학습을 얼마나 할것인지 결정합니다. 전체 데이터를 이용해서 1번 학습하는것을 1 epoch라고합니다.
여기 예제에서는 model.alpha -= 0.0002 를 이용하여 learning rate를 조절 하고 있습니다. 학습을 거듭할수록 error값이 줄어드는데 learning rate가 올라가면 발진할 수 있으므로 학습 할수록 작아지도록 예제를 만들어 놓은것으로 판단됩니다.
max_epochs = 100
vec_size = 20
alpha = 0.025

model = Doc2Vec(size=vec_size,
                alpha=alpha, 
                min_alpha=0.00025,
                min_count=1,
                dm =1)
  
model.build_vocab(tagged_data)

for epoch in range(max_epochs):
    print('iteration {0}'.format(epoch))
    model.train(tagged_data,
                total_examples=model.corpus_count,
                epochs=model.iter)
    # decrease the learning rate
    model.alpha -= 0.0002
    # fix the learning rate, no decay
    model.min_alpha = model.alpha

model.save("d2v.model")
print("Model Saved")

지금까지 소스외에 model save / load하는 소스까지 하여 실행 시켜 봤습니다.

전체 소스
#Import all the dependencies
from gensim.models.doc2vec import Doc2Vec, TaggedDocument
from nltk.tokenize import word_tokenize

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

data = ["I love machine learning. Its awesome.",
        "I love coding in python",
        "I love building chatbots",
        "they chat amagingly well"]

tagged_data = []

for i, _d in enumerate(data):
 tagged_data.append(TaggedDocument(words=word_tokenize(_d.lower()), tags=[str(i)]))

print(tagged_data)

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

max_epochs = 100
vec_size = 20
alpha = 0.025

model = Doc2Vec(size=vec_size,
                alpha=alpha, 
                min_alpha=0.00025,
                min_count=1,
                dm =1)
  
model.build_vocab(tagged_data)

for epoch in range(max_epochs):
    print('iteration {0}'.format(epoch))
    model.train(tagged_data,
                total_examples=model.corpus_count,
                epochs=model.iter)
    # decrease the learning rate
    model.alpha -= 0.0002
    # fix the learning rate, no decay
    model.min_alpha = model.alpha

model.save("d2v.model")
print("Model Saved")

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


from gensim.models.doc2vec import Doc2Vec

model= Doc2Vec.load("d2v.model")
#to find the vector of a document which is not in training data
test_data = word_tokenize("I love chatbots".lower())
v1 = model.infer_vector(test_data)
print("V1_infer", v1)

# to find most similar doc using tags
similar_doc = model.docvecs.most_similar('1')
print(similar_doc)

결과
C:\Users\USER\Documents\python\doc2vec>python doc2vectut.py
[TaggedDocument(words=['i', 'love', 'machine', 'learning', '.', 'its', 'awesome', '.'], tags=['0']), TaggedDocument(words=['i', 'love', 'coding', 'in', 'python'], tags=['1']), TaggedDocument(words=['i', 'love', 'building', 'chatbots'], tags=['2']), TaggedDocument(words=['they', 'chat', 'amagingly', 'well'], tags=['3'])]
C:\Users\USER\AppData\Local\Programs\Python\Python37\lib\site-packages\gensim\models\doc2vec.py:574: UserWarning: The parameter `size` is deprecated, will be removed in 4.0.0, use `vector_size` instead.
  warnings.warn("The parameter `size` is deprecated, will be removed in 4.0.0, use `vector_size` instead.")
iteration 0
doc2vectut.py:37: DeprecationWarning: Call to deprecated `iter` (Attribute will be removed in 4.0.0, use self.epochs instead).
  epochs=model.iter)
iteration 1
iteration 2
iteration 3
iteration 4
iteration 5
iteration 6
iteration 7
iteration 8
iteration 9
iteration 10
iteration 11
iteration 12
iteration 13
iteration 14
iteration 15
iteration 16
iteration 17
iteration 18
iteration 19
iteration 20
iteration 21
iteration 22
iteration 23
iteration 24
iteration 25
iteration 26
iteration 27
iteration 28
iteration 29
iteration 30
iteration 31
iteration 32
iteration 33
iteration 34
iteration 35
iteration 36
iteration 37
iteration 38
iteration 39
iteration 40
iteration 41
iteration 42
iteration 43
iteration 44
iteration 45
iteration 46
iteration 47
iteration 48
iteration 49
iteration 50
iteration 51
iteration 52
iteration 53
iteration 54
iteration 55
iteration 56
iteration 57
iteration 58
iteration 59
iteration 60
iteration 61
iteration 62
iteration 63
iteration 64
iteration 65
iteration 66
iteration 67
iteration 68
iteration 69
iteration 70
iteration 71
iteration 72
iteration 73
iteration 74
iteration 75
iteration 76
iteration 77
iteration 78
iteration 79
iteration 80
iteration 81
iteration 82
iteration 83
iteration 84
iteration 85
iteration 86
iteration 87
iteration 88
iteration 89
iteration 90
iteration 91
iteration 92
iteration 93
iteration 94
iteration 95
iteration 96
iteration 97
iteration 98
iteration 99
Model Saved
V1_infer [-0.0109304   0.01453446 -0.02796343  0.01905919  0.0186462   0.01566897
  0.01792961  0.00705164  0.01424597  0.00248461  0.02653115  0.02868732
 -0.01172108  0.00585754 -0.01540187 -0.01015471  0.0146137   0.00021682
  0.01906102 -0.01555774]
[('0', 0.9923108816146851), ('3', 0.9911640882492065), ('2', 0.9911146759986877)]

소스 분석


test_data = word_tokenize("I love chatbots".lower())
v1 = model.infer_vector(test_data)
위 코드는 test_data를 토큰화 해서 vector를 만드는 과정입니다.
위 예제에서는 결과로서 아래와 같은 vector가 출력되었습니다. 위에서 vector size를 20으로 했기 때문에 20개가 되는것 입니다. 크기가 클수록 더 정확해질 수 있으나 더 많은 메모리와 더많은 데이터로 더 많은 훈련이 필요합니다.
 [-0.0109304   0.01453446 -0.02796343  0.01905919  0.0186462   0.01566897
  0.01792961  0.00705164  0.01424597  0.00248461  0.02653115  0.02868732
 -0.01172108  0.00585754 -0.01540187 -0.01015471  0.0146137   0.00021682
  0.01906102 -0.01555774]

similar_doc = model.docvecs.most_similar('1')
이 예제는 "1" 번 문장과 가장 비슷한 문장이 어떤것인지 나타납니다. 결과를 보자면 "0"이 0.9923% 수준으로 제일 근접 합니다. "0" 번 문장인데 전혀 비슷하지 않지만....
[('0', 0.9923108816146851), ('3', 0.9911640882492065), ('2', 0.9911146759986877)]

문제점

여러번 실행시키면 아래와 같이 값이 다릅니다. 이때 결과가 "2" 두번째 문장인 경우도 나옵니다.

Model Saved
V1_infer [-0.02121443 -0.00848201 -0.00763245  0.00745193  0.00415829 -0.01217643
  0.01441886  0.01548216 -0.00765178 -0.02253398 -0.0081254  -0.00448609
 -0.0034246  -0.01841096  0.02063655 -0.01921302  0.01506925  0.0162458
  0.01329079 -0.0103074 ]
[('2', 0.9906354546546936), ('0', 0.9863607883453369), ('3', 0.9810261726379395)]


Model Saved
V1_infer [ 0.00368929  0.00579063 -0.00694244 -0.01026715 -0.00822515  0.01120392
 -0.00292197  0.00318307 -0.00821392  0.003614   -0.02230442 -0.01828359
  0.01888582  0.01448112  0.00215786  0.00533434  0.01083726 -0.00696347
 -0.00343927 -0.02374181]
[('0', 0.9902483224868774), ('3', 0.9879346489906311), ('2', 0.9857644438743591)]

앞으로 해결할 주제

위 문제점은 어디에서 잘못되었을까?
원하는 문장이 있을때 어떤 문장과 비슷한가?