ratsgo / embedding

한국어 임베딩 (Sentence Embeddings Using Korean Corpora)
https://ratsgo.github.io/embedding
MIT License
455 stars 130 forks source link

126쪽 코드 4-4 관련 #106

Closed TransAmRaiser closed 4 years ago

TransAmRaiser commented 4 years ago

안녕하세요. 예전에 이 부분에 대해 질문했던 적이 있는데 문제가 여전히 있어서 다시 글 남깁니다.

  1. GPU 버전 에러 python models/ ... 이 코드를 GPU 버전에서 실행하면 다음과 같은 에러가 발생합니다.

ImportError: No module named 'numpy.core._multiarray_umath' ImportError: No module named 'numpy.core._multiarray_umath' Traceback (most recent call last): File "models/word_utils.py", line 10, in from preprocess import get_tokenizer File "/notebooks/embedding/preprocess/init.py", line 1, in from .supervised_nlputils import get_tokenizer, post_processing File "/notebooks/embedding/preprocess/supervised_nlputils.py", line 3, in from konlpy.tag import Okt, Komoran, Mecab, Hannanum, Kkma File "/usr/local/lib/python3.5/dist-packages/konlpy/init.py", line 12, in from konlpy import ( File "/usr/local/lib/python3.5/dist-packages/konlpy/tag/init.py", line 6, in from konlpy.tag._hannanum import Hannanum File "/usr/local/lib/python3.5/dist-packages/konlpy/tag/_hannanum.py", line 7, in import jpype File "/usr/local/lib/python3.5/dist-packages/jpype/init.py", line 17, in import _jpype ImportError: numpy.core.multiarray failed to import

numpy 버전의 문제인 것 같아 현재 GPU 버전에 깔려 있는 numpy(1.15.4) 를 지우고, pip로 새 버전을 설치하면(별도의 옵션을 안 주니 2020년 8월 22일 기준, 1.18.5으로 설치됨), 일단 작동은 합니다. 근데 CPU 버전에도 1.15.4 버전이 깔려 있는데, 왜 이런 차이가 있는지 모르겠네요.

  1. 메모리 문제 https://github.com/ratsgo/embedding/issues/42 예전에 위 링크에서 '죽었음' 문제에 대해 솔루션을 주셨는데, 지금 해 보니 여전히 '죽었음' 메시지가 뜹니다. max_num_tokens_per_doc 을 줄이고 줄여서 10까지 했는데도 계속 '죽었음'이 뜹니다. 컴퓨터 2대에서 각각 CPU 버전과 GPU 버전으로 다 시도해 봤는데 안 되더라고요. 무슨 문제인지 궁금합니다.
ratsgo commented 4 years ago

안녕하세요 @TransAmRaiser 님! 너무 늦게 답을 드린 건 아닌지요. 죄송합니다ㅠㅠ 1번 GPU 도커를 어떤 환경에서 실행하셨는지 여쭤 봐도 될까요? 문제 체크에 좀 더 도움이 될 것 같습니다.

ratsgo commented 4 years ago

2번 메모리 문제와 관련해서 gensim word2vec 패키지가 초반에 vocabulary를 만들 때 메모리를 상당히 사용하기 때문에 이 문제가 발생하는 것으로 추정됩니다. 혹시 @TransAmRaiser 님의 도커에서 아래 코드를 실행해 보실 수 있을까요?

from gensim.models import Word2Vec

class Word2VecCorpus:

    def __init__(self, corpus_fname):
        self.corpus_fname = corpus_fname

    def __iter__(self):
        with open(self.corpus_fname, 'r') as f:
            for sentence in f:
                tokens = sentence.replace('\n', '').strip().split(" ")
                yield tokens

def make_save_path(full_path):
    if full_path[:4] == "data":
        full_path = os.path.join(os.path.abspath("."), full_path)
    model_path = '/'.join(full_path.split("/")[:-1])
    if not os.path.exists(model_path):
       os.makedirs(model_path)

def train_word2vec(corpus_fname, model_fname):
    make_save_path(model_fname)
    corpus = Word2VecCorpus(corpus_fname)
    model = Word2Vec(corpus, size=100, workers=4, sg=1)
    model.save(model_fname)

corpus_name = "data/tokenized/corpus_mecab.txt"
model_fname = "data/word-embeddings/word2vec/word2vec"
train_word2vec(corpus_fname, model_fname)

기존 코드는 (1) raw corpus (2) token sequence 등을 모두 메모리에 적재해두는 방식인데요, 위 코드는 Word2Vec 클래스가 실제로 데이터를 사용할 때만 yield하여 메모리 사용량을 줄였습니다. max_num_tokens_per_doc으로 줄이는 것이 문제 해결에 전혀 도움이 안되는 것 같아 방식을 바꿔봤는데요. @TransAmRaiser 님 환경에서 테스트해보시고 결과를 공유해주시면 감사하겠습니다.

TransAmRaiser commented 4 years ago

안녕하세요 @TransAmRaiser 님! 너무 늦게 답을 드린 건 아닌지요. 죄송합니다ㅠㅠ 1번 GPU 도커를 어떤 환경에서 실행하셨는지 여쭤 봐도 될까요? 문제 체크에 좀 더 도움이 될 것 같습니다.

저 작업 이후 컴퓨터 포맷을 해서 정확히는 기억이 안 나는데 아는 선에서 말씀드리겠습니다.

OS: Ubuntu 16.04 64bit GPU: RTX 2070 NVIDIA driver: 418 기타: 우분투 내장 터미널을 이용해 실행함.

도커 버전 등은 기억이 안 나네요. 도움이 될지 모르겠습니다.

TransAmRaiser commented 4 years ago

2번 메모리 문제와 관련해서 gensim word2vec 패키지가 초반에 vocabulary를 만들 때 메모리를 상당히 사용하기 때문에 이 문제가 발생하는 것으로 추정됩니다. 혹시 @TransAmRaiser 님의 도커에서 아래 코드를 실행해 보실 수 있을까요?

from gensim.models import Word2Vec

class Word2VecCorpus:

    def __init__(self, corpus_fname):
        self.corpus_fname = corpus_fname

    def __iter__(self):
        with open(self.corpus_fname, 'r') as f:
            for sentence in f:
                tokens = sentence.replace('\n', '').strip().split(" ")
                yield tokens

def make_save_path(full_path):
    if full_path[:4] == "data":
        full_path = os.path.join(os.path.abspath("."), full_path)
    model_path = '/'.join(full_path.split("/")[:-1])
    if not os.path.exists(model_path):
       os.makedirs(model_path)

def train_word2vec(corpus_fname, model_fname):
    make_save_path(model_fname)
    corpus = Word2VecCorpus(corpus_fname)
    model = Word2Vec(corpus, size=100, workers=4, sg=1)
    model.save(model_fname)

corpus_name = "data/tokenized/corpus_mecab.txt"
model_fname = "data/word-embeddings/word2vec/word2vec"
train_word2vec(corpus_fname, model_fname)

기존 코드는 (1) raw corpus (2) token sequence 등을 모두 메모리에 적재해두는 방식인데요, 위 코드는 Word2Vec 클래스가 실제로 데이터를 사용할 때만 yield하여 메모리 사용량을 줄였습니다. max_num_tokens_per_doc으로 줄이는 것이 문제 해결에 전혀 도움이 안되는 것 같아 방식을 바꿔봤는데요. @TransAmRaiser 님 환경에서 테스트해보시고 결과를 공유해주시면 감사하겠습니다.

성공했습니다.

우선 위 코드에서 오류가 있는 부분을 먼저 말씀드립니다. corpus_name 을 corpus_fname으로 수정해야 합니다. 또 import os를 해 줘야 작동합니다.

제 환경은 다음과 같습니다.

훈련에 대략 한 시간쯤 소요되었습니다.

아무튼 이 코드로 바꾸면 메모리 문제가 없는 것 같습니다. 감사합니다.

ratsgo commented 4 years ago

안녕하세요 @TransAmRaiser 님! 너무 늦게 답을 드린 건 아닌지요. 죄송합니다ㅠㅠ 1번 GPU 도커를 어떤 환경에서 실행하셨는지 여쭤 봐도 될까요? 문제 체크에 좀 더 도움이 될 것 같습니다.

저 작업 이후 컴퓨터 포맷을 해서 정확히는 기억이 안 나는데 아는 선에서 말씀드리겠습니다.

OS: Ubuntu 16.04 64bit GPU: RTX 2070 NVIDIA driver: 418 기타: 우분투 내장 터미널을 이용해 실행함.

도커 버전 등은 기억이 안 나네요. 도움이 될지 모르겠습니다.

제가 추적을 시도해보았습니다만 이슈 재현에 실패하였습니다. 이후 비슷한 증상이 반복될 경우 별도 이슈로 남겨주시면 시간 내어서 살펴보겠습니다. Word2Vec을 학습할 때 발생하는 메모리 이슈를 해결한 코드는 마스터에 반영해 두었습니다. 리포 개선에 큰 도움을 주셔서 매우 감사드립니다.