JSON 파일에 저장되어있는 의학 저널의 문장에서 gensim을 사용하여 word2vec 모델을 생성하는 클러스터를 사용 중이며 메모리에 문제가 있습니다. 사용량이 너무 많습니다.매우 큰 Python 목록에 대한 과도한 메모리 사용량이 word2vec 용 JSON 90GB에서로드 됨
과제는 모든 문장의 누적 목록을 특정 연도까지 유지 한 다음 해당 연도의 word2vec 모델을 생성하는 것입니다. 그런 다음 내년의 문장을 누적 목록에 추가하고 모든 문장을 기반으로 해당 연도의 다른 모델을 생성하고 저장하십시오.
이 특정 클러스터의 I/O는 충분히 느리고 데이터가 충분히 크고 (메모리에 2/3가 읽는 데는 약 3 일이 걸림), 매년 JSON을 디스크에서 스트리밍하면 영원히 걸릴 수 있으므로 솔루션 90GB의 모든 JSON을 파이썬 목록의 메모리에로드하는 것이 었습니다. 이 작업에는 최대 256GB의 메모리를 사용할 수있는 권한이 있지만 필요한 경우 더 많은 메모리를 확보 할 수 있습니다.
내가 가지고있는 문제는 내가 기억이 부족하다는 것입니다. 파이썬이 메모리를 OS로 반환하지 않는 무료 목록을 구현하는 방식에 관한 다른 글을 읽었으며 문제의 일부가 될 수 있다고 생각하지만 확실하지 않습니다.
무료 목록이 문제가 될 수 있고 numpy가 많은 수의 요소에 대해 더 나은 구현을 가질 수 있다고 생각하여 문장의 누적 목록에서 문장의 누적 배열로 변경했습니다 (gensim은 문장이 단어/문자열 목록). 그러나 문장의 작은 하위 집합에서이 코드를 실행했고 약간 더 많은 메모리를 사용했기 때문에 진행 방법이 확실하지 않습니다.
누구나 이와 관련하여 경험이 있다면 도움을받을 수있어서 기쁩니다. 또한, 변경 될 수있는 것이 있다면 나에게도 알려 주셔서 감사합니다. 전체 코드는 다음과 같습니다 :
import ujson as json
import os
import sys
import logging
from gensim.models import word2vec
import numpy as np
PARAMETERS = {
'numfeatures': 250,
'minwordcount': 10,
'context': 7,
'downsampling': 0.0001,
'workers': 32
}
logger = logging.getLogger()
handler = logging.StreamHandler()
formatter = logging.Formatter('%(asctime)s %(levelname)-8s %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)
logger.setLevel(logging.INFO)
def generate_and_save_model(cumulative_sentences, models_dir, year):
"""
Generates and saves the word2vec model for the given year
:param cumulative_sentences: The list of all sentences up to the current year
:param models_dir: The directory to save the models to
:param year: The current year of interest
:return: Nothing, only saves the model to disk
"""
cumulative_model = word2vec.Word2Vec(
sentences=cumulative_sentences,
workers=PARAMETERS['workers'],
size=PARAMETERS['numfeatures'],
min_count=PARAMETERS['minwordcount'],
window=PARAMETERS['context'],
sample=PARAMETERS['downsampling']
)
cumulative_model.init_sims(replace=True)
cumulative_model.save(models_dir + 'medline_abstract_word2vec_' + year)
def save_year_models(json_list, json_dir, models_dir, min_year, max_year):
"""
:param json_list: The list of json year_sentences file names
:param json_dir: The directory holding the the sentences json files
:param models_dir: The directory to serialize the models to
:param min_year: The minimum value of a year to generate a model for
:param max_year: The maximum value of a year to generate a model for
Goes year by year through each json of sentences, saving a cumulative word2vec
model for each year
"""
cumulative_sentences = np.array([])
for json_file in json_list:
year = json_file[16:20]
# If this year is greater than the maximum, we're done creating models
if int(year) > max_year:
break
with open(json_dir + json_file, 'rb') as current_year_file:
cumulative_sentences = np.concatenate(
(np.array(json.load(current_year_file)['sentences']),
cumulative_sentences)
)
logger.info('COMPLETE: ' + year + ' sentences loaded')
logger.info('Cumulative length: ' + str(len(cumulative_sentences)) + ' sentences loaded')
sys.stdout.flush()
# If this year is less than our minimum, add its sentences to the list and continue
if int(year) < min_year:
continue
generate_and_save_model(cumulative_sentences, models_dir, year)
logger.info('COMPLETE: ' + year + ' model saved')
sys.stdout.flush()
def main():
json_dir = '/projects/chemotext/sentences_by_year/'
models_dir = '/projects/chemotext/medline_year_models/'
# By default, generate models for all years we have sentences for
minimum_year = 0
maximum_year = 9999
# If one command line argument is used
if len(sys.argv) == 2:
# Generate the model for only that year
minimum_year = int(sys.argv[1])
maximum_year = int(sys.argv[1])
# If two CL arguments are used
if len(sys.argv) == 3:
# Generate all models between the two year arguments, inclusive
minimum_year = int(sys.argv[1])
maximum_year = int(sys.argv[2])
# Sorting the list of files so that earlier years are first in the list
json_list = sorted(os.listdir(json_dir))
save_year_models(json_list, json_dir, models_dir, minimum_year, maximum_year)
if __name__ == '__main__':
main()
또한 유니 코드 헛소리와 관련이있을 수 있습니다. JSON 파일의 인코딩, 클러스터에서 사용중인 Python 버전 및 ['sys.maxunicode'] (http://stackoverflow.com/questions/1446347)에서 제공 한 번호를 부여 할 수 있습니까? – user6758673
답변 해 주셔서 감사합니다. 인코딩이 문제가 될 수 있다고 생각하지 않았습니다. 'file -i thefile.json'을 입력하면 파일이 us-ascii로 인코딩되었음을 알 수 있습니다. 이 시스템은 Python 2.6.6을 실행합니다. 'sys.maxunicode'는 114111을 반환합니다. – sfirrin
여러분의 파이썬 유니 코드 문자열이 문자 당 4 바이트를 차지한다는 것을 의미합니다. JSON에서는 주로 문자 당 1 바이트의 문자를 사용하지만 (유니 코드 문자의 공유에 따라 다르지만 유니 코드 문자는 이스케이프 시퀀스 '\ uXXXX'로 저장됩니다.) 적어도 이것이 부분적으로 과도한 메모리 사용을 설명한다고 생각합니다. – user6758673