Обучение существующему конвейеру Spacy Ner забывает предыдущие примеры - PullRequest
0 голосов
/ 10 февраля 2020

Я создаю новую модель для распознавания именованных объектов. У меня есть тренировочный набор данных, который выглядит следующим образом:

[[
"world leading global energy trading company has an exciting 
opportunity for a senior csharp application platform developer to 
join its systematic trading division developing new trading 
applications tools and solutions for its successful front office 
trading team", 
{"entities": [[80, 86, "RNK"]]}
]]

Поэтому я запускаю следующую функцию для обучения модели.

@plac.annotations(
model=("Model name. Defaults to blank 'en' model.", "option", "m", 
str),
new_model_name=("New model name for model meta.", "option", "nm", 
str),
output_dir=("Optional output directory", "option", "o", Path),
n_iter=("Number of training iterations", "option", "n", int), 
entity=("Name of the entity to be trained", "option", "e", str),
label=("The label to be given to the trained entity", "option", "l", 
str),
)
def main(model = None, new_model_name=("ner%s" % str(datetime.now)), 
output_dir= None, n_iter=20, entity=None, label=None):

if entity is None or label is None:
    log.info("Entity and Label must both be supplied")
    log.info("Bailing out as nothing to do ...... :-(")
    return

log.info("Fetching training data for entity [%s] to be trained with 
label [%s]" % (entity, label))

log.info("Training data retrieved and the first row is : ")
log.info(TRAIN_DATA[0])
log.info("There are %d rows to be trained" % len(TRAIN_DATA))

if model is not None:
    nlp = spacy.load(output_dir)  # load existing spaCy model
    print("Loaded model '%s'" % model)
else:
    nlp = spacy.blank("en")  # create blank Language class
    print("Created blank 'en' model")

if "ner" not in nlp.pipe_names:
    log.info("ner not in pipe names, adding it in now ....")
    ner = nlp.create_pipe("ner")
    nlp.add_pipe(ner)
# otherwise, get it, so we can add labels to it
else:
    log.info("retrieving previous ner pipe now ....")
    ner = nlp.get_pipe("ner")

# add labels
for _, annotations in TRAIN_DATA:
     for ent in annotations.get('entities'):
        ner.add_label(ent[2])

move_names = list(ner.move_names)

# get names of other pipes to disable them during training
pipe_exceptions = ["ner", "trf_wordpiecer", "trf_tok2vec"]
other_pipes = [pipe for pipe in nlp.pipe_names if pipe not in 
pipe_exceptions]
with nlp.disable_pipes(*other_pipes):  # only train NER
    # reset and initialize the weights randomly – but only if we're
    # training a new model
    if model is None:
        optimizer=nlp.begin_training()
    else:
        optimizer=nlp.resume_training()
    for itn in range(n_iter):
        random.shuffle(TRAIN_DATA)
        losses = {}
        # batch up the examples using spaCy's minibatch
        batches = minibatch(TRAIN_DATA, size=compounding(4.0, 32.0, 

1.001)) для партий в пакетах: тексты, аннотации = zip (* batch) nlp.update (тексты, # пакет аннотаций текстов, # пакет аннотаций drop = 0.5, # dropout - затруднить запоминание данных sgd = оптимизатор, loss = loss,) print ("Потери", потери)

# test the trained model
for text, _ in TRAIN_DATA:
    doc = nlp(text)
    print("Entities", [(ent.text, ent.label_) for ent in doc.ents])
    print("Tokens", [(t.text, t.ent_type_, t.ent_iob) for t in doc])

if output_dir is not None:
    output_dir = Path(output_dir)
    if not output_dir.exists():
        output_dir.mkdir()
    nlp.meta["name"] = new_model_name  # rename model
    nlp.to_disk(output_dir)
    print("Saved model to", output_dir)

    # test the saved model
    print("Loading from", output_dir)
    nlp2 = spacy.load(output_dir)
    # Check the classes have loaded back consistently
    assert nlp2.get_pipe("ner").move_names == move_names

return

if __name__ == "__main__":
    log = logging.getLogger(__name__)
    log.setLevel(logging.DEBUG)

    consoleHandler = logging.StreamHandler()
    consoleHandler.setLevel(logging.DEBUG)

    log.addHandler(consoleHandler)
    plac.call(main)

Это работает хорошо, и я могу затем успешно протестировать модель, используя следующую функцию

@plac.annotations(
model_dir=("Optional output directory", "option", "o", Path),
test_text=("The test text to be used to test the model","option", 
"t", str),
entity=("Name of the entity to be trained", "option", "e", str),
label=("The label to be given to the trained entity", "option", "l", 
str),
)
def main(model_dir= None,test_text=None, entity=None, label=None):

if entity is None or label is None:
    log.info("Entity and Label must both be supplied")
    log.info("Bailing out as nothing to do ...... :-(")
    return

if test_text is None:
    test_text = ("Using default test string which is not optimal to 
look for %s" % entity)

nlp = spacy.load(model_dir)
log.info("Loaded model %s" % nlp.meta["name"])
log.info("Testing the string %s" % test_text)

ner = nlp.get_pipe("ner")
for label in ner.labels:
    log.info("NER Label : %s found in model" % label)

doc = nlp(test_text)
print("Entities", [(ent.text, ent.label_) for ent in doc.ents])
print("Tokens", [(t.text, t.ent_type_, t.ent_iob) for t in doc])

if __name__ == "__main__":
log = logging.getLogger(__name__)
log.setLevel(logging.DEBUG)

consoleHandler = logging.StreamHandler()
consoleHandler.setLevel(logging.DEBUG)

log.addHandler(consoleHandler)
plac.call(main)

Однако, если я снова запустил код, чтобы тренироваться против нового пометить, сказать «SKILL» и предоставить новые обучающие данные, он успешно загружает старую модель, извлекает конвейер Ner и настраивает возобновление работы оптимизатора, но когда я проверяю его снова, он забывает все свои тренировки по метке RNK.

Я предполагаю, что резюме каким-то образом подхватит предыдущее состояние модели и сохранит ранее изученные аннотации. Это, безусловно, сохраняет метку NER.

Почему это происходит?

Думая, что это, возможно, связано с катастрофой c Забывая проблему, я создал один большой набор обучающих данных с примерами из обеих категорий , так что это:

'TOKEN'  >>> 'NER Annotation'
-----------------------------
'senior' >>> 'RNK'
'csharp' >>> 'SKILL'
'sql'    >>> 'SKILL'

Это потери

Losses {'ner': 721.8737016180717}
Losses {'ner': 5.999976082008388}
Losses {'ner': 5.970323057037423}
Losses {'ner': 5.996330579093365}
Losses {'ner': 6.028536462566022}
Losses {'ner': 12.043830573641666}
Losses {'ner': 10.001897952651317}
Losses {'ner': 6.016950026187274}
Losses {'ner': 6.624311646328313} 
Losses {'ner': 10.602919933949224}
Losses {'ner': 6.1062697231067995}
Losses {'ner': 8.792055106010444}
Losses {'ner': 13.302123281119345}
Losses {'ner': 6.068028368915684}
Losses {'ner': 8.026694430880903}
Losses {'ner': 8.961434860193798}
Losses {'ner': 6.02721516249698}
Losses {'ner': 9.714660156853073}
Losses {'ner': 4.108544494319015}
Losses {'ner': 6.023105974059858}
Losses {'ner': 7.357760648981275}
Losses {'ner': 6.295292869532734}
Losses {'ner': 3.8088561052881995}
Losses {'ner': 6.059279332644757}
Losses {'ner': 7.024559462190113}
Losses {'ner': 4.784358718788942}
Losses {'ner': 5.935101364429172}
Losses {'ner': 4.027772727507415}
Losses {'ner': 2.1748163004265884}
Losses {'ner': 5.993975825343896}

Я включил свои тренировочные данные по пастбину, которые можно найти здесь:

https://pastebin.com/JmQv7HRS

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