Потери при обучении не уменьшаются (Word2Vec, Gensim)

Что может вызвать потери от model.get_latest_training_loss() увеличения в каждую эпоху?

Код, используемый для обучения:

class EpochSaver(CallbackAny2Vec):
    '''Callback to save model after each epoch and show training parameters '''

    def __init__(self, savedir):
        self.savedir = savedir
        self.epoch = 0

        os.makedirs(self.savedir, exist_ok=True)

    def on_epoch_end(self, model):
        savepath = os.path.join(self.savedir, "model_neg{}_epoch.gz".format(self.epoch))
        model.save(savepath)
        print(
            "Epoch saved: {}".format(self.epoch + 1),
            "Start next epoch ... ", sep="\n"
            )
        if os.path.isfile(os.path.join(self.savedir, "model_neg{}_epoch.gz".format(self.epoch - 1))):
            print("Previous model deleted ")
            os.remove(os.path.join(self.savedir, "model_neg{}_epoch.gz".format(self.epoch - 1))) 
        self.epoch += 1
        print("Model loss:", model.get_latest_training_loss())

    def train():

        ### Initialize model ###
        print("Start training Word2Vec model")

        workers = multiprocessing.cpu_count()/2

        model = Word2Vec(
            DocIter(),
            size=300, alpha=0.03, min_alpha=0.00025, iter=20,
            min_count=10, hs=0, negative=10, workers=workers,
            window=10, callbacks=[EpochSaver("./checkpoints")], 
            compute_loss=True
    )     

Выход:

Убытки от эпох (с 1 по 20):

Model loss: 745896.8125
Model loss: 1403872.0
Model loss: 2022238.875
Model loss: 2552509.0
Model loss: 3065454.0
Model loss: 3549122.0
Model loss: 4096209.75
Model loss: 4615430.0
Model loss: 5103492.5
Model loss: 5570137.5
Model loss: 5955891.0
Model loss: 6395258.0
Model loss: 6845765.0
Model loss: 7260698.5
Model loss: 7712688.0
Model loss: 8144109.5
Model loss: 8542560.0
Model loss: 8903244.0
Model loss: 9280568.0
Model loss: 9676936.0

Что я делаю неправильно?

Язык арабский. На входе DocIter - список с токенами.


person Dasha    schedule 27.08.2018    source источник
comment
Прокомментируйте, пожалуйста, ваше голосование против!   -  person Dasha    schedule 28.08.2018


Ответы (2)


Вплоть до gensim 3.6.0 сообщаемое значение потерь может быть не очень разумным, только сбрасывая счетчик каждого вызова на train(), а не для каждой внутренней эпохи. В этой проблеме есть несколько исправлений:

https://github.com/RaRe-Technologies/gensim/pull/2135

Между тем, разница между предыдущим и последним значением может быть более значимой. В этом случае ваши данные предполагают, что в 1-ю эпоху общие потери составили 745896, а в последней (9676936-9280568 =) 396,368, что может указывать на ожидаемый прогресс.

person gojomo    schedule 29.08.2018
comment
Спасибо за ваш ответ! Но на последнем этапе потери больше, и, насколько я понял, я принимаю во внимание только разницу и должен интерпретировать ее как прогресс, не так ли? И могу ли я получить более подходящую потерю, если вызову train () вместо того, чтобы просто передать iter = smth моей модели? - person Dasha; 29.08.2018
comment
Вызов train() несколько раз, если вы еще не очень хорошо знакомы с внутренними операциями кода, часто дает сбой ... поэтому я не рекомендую это делать. (Это хрупкий и подверженный ошибкам, и большинство онлайн-примеров, которые я вижу, неверны.) Модель обычно пытается снизить свои потери после каждого обучающего примера, но она может никогда не стать объективно очень хорошей в своем внутренние предсказания слов, и это не обязательно, чтобы слова-векторы по-прежнему были полезны для последующих задач. (Модель с меньшими потерями не обязательно дает лучшие слова-векторы, чем модель с более высокими!) - person gojomo; 29.08.2018
comment
И вполне естественно, что для эпохи потерь за всю эпоху на какое-то время они подпрыгивают все выше и ниже, а затем, в конце концов, перестают улучшаться после сходимости модели. Это означает, что она примерно настолько хороша, насколько хороша модель такой сложности для определенного корпуса обучения, и последующие эпохи будут просто немного подергивать общие потери вверх и вниз, но больше не будут надежно снижать их. Так что не стоит особо беспокоиться о последней межпериодной дельте. Почему потеря интереса к вам? - person gojomo; 29.08.2018
comment
(Отдельно, изменение значения по умолчанию _1 _ / _ 2_ - это не то, с чем я обычно возился, если не уверен в причинах, по которым и не могу проверить, что изменения улучшают результаты последующих задач.) - person gojomo; 29.08.2018
comment
@DashaOrgunova, вы пробовали использовать механизм ранней остановки в callback-функции? - person gaurav1207; 04.10.2018
comment
@ gaurav1207 нет, я не делал! - person Dasha; 04.10.2018
comment
@gojomo, я прошил gensim-версию, если не возражаете. (Не удалось отредактировать номер версии на месте) - person DimG; 24.12.2018

Согласно предложению gojomo, вы можете рассчитать разницу потерь в функции обратного вызова:

from gensim.models.callbacks import CallbackAny2Vec
from gensim.models import Word2Vec

# init callback class
class callback(CallbackAny2Vec):
    """
    Callback to print loss after each epoch
    """
    def __init__(self):
        self.epoch = 0

    def on_epoch_end(self, model):
        loss = model.get_latest_training_loss()
        if self.epoch == 0:
            print('Loss after epoch {}: {}'.format(self.epoch, loss))
        else:
            print('Loss after epoch {}: {}'.format(self.epoch, loss- self.loss_previous_step))
        self.epoch += 1
        self.loss_previous_step = loss

Для обучения вашей модели добавьте computer_loss = True и callbacks=[callback()] в метод поезда word2vec:

# init word2vec class
w2v_model = Word2Vec(min_count=20, 
                     window=12 
                     size=100, 
                     workers=2)
# build vovab
w2v_model.build_vocab(sentences)
  
# train the w2v model
w2v_model.train(senteces, 
                total_examples=w2v_model.corpus_count, 
                epochs=10, 
                report_delay=1,
                compute_loss = True, # set compute_loss = True
                callbacks=[callback()]) # add the callback class

# save the word2vec model
w2v_model.save('word2vec.model')

Это выведет что-то вроде этого:

Убыток после эпохи 0: 4448638,5

Убыток после эпохи 1: 3283735,5

Убыток после эпохи 2: 2826198.0

Убыток после эпохи 3: 2680974.0

Убыток после эпохи 4: 2601113.0

Убыток после эпохи 5: 2271333.0

Убыток после эпохи 6: 2052050,0

Убыток после 7-й эпохи: 2011 768,0

Убыток после эпохи 8: 1927 454,0

Убыток после эпохи 9: 1887798.0

person lux7    schedule 18.12.2019