Почему тренировка моего наивного байесовского классификатора занимает столько памяти? - PullRequest
1 голос
/ 16 февраля 2020

В последнее время я работаю над проектом, который требует анализа настроений в Твиттере. Я использую наивный байесовский классификатор из библиотеки Textblob и пытаюсь обучить его 1,6 миллионам твитов (их можно найти здесь, если кому-то интересно: https://www.kaggle.com/kazanova/sentiment140). Простая передача 1,6 миллиона твитов вызывает ошибку памяти, поэтому я решил разделить ее на части, чтобы одновременно обучалось только 1000 твитов. Это имеет небольшой успех, так как я могу получить только около 10 000 твитов на своем локальном компьютере, пока мой компьютер не зависнет, потому что я использую слишком много оперативной памяти. Затем я попробовал это на Google colab, чтобы я мог запустить свой код в облаке. Как с TPU, так и с GPU, максимум, который я получил, составляет 28 000 твитов, прежде чем сеанс потерпел крах, и мне пришлось перезапустить среду выполнения. Вот мой код:

with open("shuffledlist.pickle", 'rb') as f: #Loading in my list of 1.6 million tweets
    full_data = pickle.load(f)

training_data = (tweet for tweet in full_data[:1500000]) 

try:
    with open("sentimentclassifier.pickle", "rb") as file: #makes a new classifier if one doesnt exist
        classifier = pickle.load(file)
        print("Got existing classifier")
except EOFError:
    classifier = NaiveBayesClassifier(full_data[:1000])
    print("Made new classifier")
del full_data

feeding_size = 1000
left_splice = 0
right_splice = feeding_size + left_splice

count = 0
new_start_time = time.time()
past_times = 0

while right_splice < 1500000:
    loop_time = time.time()
    data = itertools.islice(training_data,left_splice,right_splice)
    try:
        classifier.update(data)
    except Exception:
        print("Houston we got a problem")
        with open("sentimentclassifier.pickle", "wb") as sentiment:
             pickle.dump(classifier, sentiment, protocol = -1)
        sys.exit("Yo it ended at {} and {}".format(left_splice, right_splice))
    past_times += time.time() - loop_time
    count += 1
    string = "Left: {} Right: {}. Took {} seconds. Total Time Elapsed: {}. Average Time for each: {}. Count: {}."\
        .format(left_splice, right_splice, time.time()-loop_time, time.time() - new_start_time, past_times/count, count)
    sys.stdout.write('\r' + string)
    left_splice += feeding_size
    right_splice += feeding_size
    with open("sentimentclassifier.pickle", "wb") as sentiment:
        pickle.dump(classifier, sentiment, protocol = -1)
        print("Done dumping cycle {}!".format(count))

print("Done! Right: {}, Left: {}!".format(left_splice, right_splice))

with open("sentimentclassifier.pickle", "wb") as sentiment:
    pickle.dump(classifier, sentiment, protocol = -1)


print("Training took {} seconds!".format(time.time()-new_start_time))

Некоторые примечания:

  • Поскольку моя основная проблема заключается в размере моего файла sentimentclassifier.pickle, я попытался использовать gzip, но это просто слишком долго, чтобы открыть и закрыть файл, и это особенно плохо, потому что мне нужно открывать файл каждые l oop, так как я не хочу потерять какой-либо прогресс в случае сбоя программы.

  • Я перешел от использования списков к использованию генераторов, что значительно улучшило скорость.

  • В google colab я пытался передавать по 10 000 за раз, что было из последних усилий, и неудивительно, что это не сработало к лучшему.

  • Я не уверен, является ли наивный байесовский классификатор nltk более эффективным, но я действительно хочу, чтобы это было последнее средство, поскольку переформатирование моего списка твитов может занять несколько часов. Но если это действительно будет более эффективно, я с радостью переделаю свой код, если это будет означать, что я смогу заставить это работать.

Спасибо, и любые советы будут высоко оценены!

1 Ответ

0 голосов
/ 16 февраля 2020

Я бы попробовал разбить данные обучения на управляемые куски в отдельных файлах обучения. Вместо открытия файла с 1,5 миллионами твитов, разбейте этот файл на несколько тысяч твитов на файл. Сделайте так, чтобы al oop тренировался на одном файле, закройте этот файл, затем тренируйтесь на следующем. Таким образом, вы не загружаете столько памяти сразу. Он должен хранить в памяти все 1,5 миллиона твитов так, как вы это делаете. Это затормозит вашу оперативную память.

Для ясности:

Это:

с открытым ("shuffledlist.pickle", 'rb') как f: # Загрузка в моем списке 1,6 миллиона твитов full_data = pickle.load (f)

    >training_data = (tweet for tweet in full_data[:1500000]) 

загружает весь файл в оперативную память. Таким образом, разбиение на фрагменты после этой строки не уменьшает количество оперативной памяти, которую вы используете, хотя это уменьшает количество ядер GPU, которые вы используете, потому что вы загружаете только количество GPU x за одну итерацию. Если вы сначала загрузите файл меньшего размера, вы уменьшите объем используемой оперативной памяти с get- go.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...