有时,你需要对预先训练的模型进行微调,以添加新标签或纠正某些特定错误。这可能会出现“灾难性遗忘”的问题。而伪排练是一个很好的解决方案:使用原始模型标签实例,并通过微调更新进行混合。
import spacy
nlp = spacy.load('en_core_web_sm')
doc = nlp(u'search for pictures of playful rodents')
spacy.displacy.serve(doc)
Doc
实例和一个GoldParse
实例传递给nlp.update()
方法:from spacy.gold import GoldParse
new_tags = [None] * len(doc)
new_tags[0] = 'VBP'
gold = GoldParse(doc, tags=new_tags)
nlp.update(doc, gold, update_shared=True)
None
值表示没有对这些标签的监督,所以预测的梯度为零。依赖性解析或实体识别器没有标签,因此这些模型的权重将不会被更新。然而,所有模型共享相同的输入表示法,因此如果这种表示法更新,所有模型都可能受到影响。为了解决这个问题,spaCy v2.0.0a10引入了一个新的标志:update_shared
。此标志默认设置为False
。VBP
?这句话的第一个词是什么?是否搜索了所有实例?我们需要向模型提供更多有关我们正在寻找的解决方案的信息,学习问题将不受约束,我们也不可能获得我们想要的解决方案。nlp.update()时
,我们要求模型产生对当前权重的分析。然后为每个子任务计算误差梯度,并通过反向传播更新权重。从本质上讲,我们增加权重直到我们得到一组产生误差梯度接近于零的分析的权重。任何一组零损失的权重都是稳定的。revision_data = []
# Apply the initial model to raw examples. You'll want to experiment
# with finding a good number of revision texts. It can also help to
# filter out some data.
for doc in nlp.pipe(revision_texts):
tags = [w.tag_ for w in doc]
heads = [w.head.i for w in doc]
deps = [w.dep_ for w in doc]
entities = [(e.start_char, e.end_char, e.label_) for e in doc.ents]
revision_data.append((doc, GoldParse(doc, tags=doc_tags, heads=heads,
deps=deps, entities=entities)))
# Now shuffle the previous behaviour into the new fine-tuning data, and
# update with them together. You might want to upsample the fine-tuning
# examples (e.g. include 5 copies of it). This lets you use a better
# variety of revision data without changing the ratio of revision : tuning
# data.
n_epoch = 5
batch_size = 32
for i in range(n_epoch):
examples = revision_data + fine_tune_data
losses = {}
random.shuffle(examples)
for batch in partition_all(batch_size, examples):
docs, golds = zip(*batch)
nlp.update(docs, golds, losses=losses)