针对特定用例微调较小的NLP模型

2023年12月05日 由 alex 发表 334 0

本文将帮助你了解如何开始使用较小的开源自然语言处理(NLP)模型来处理特定用例,并解释为什么这样做可能更有效,以及如何自行微调基本模型。


介绍


封闭与开源模型


人们很容易认为使用最大、最先进的模型(例如 GPT-4)是处理 NLP 任务的最有效方法。我想我们都同意GPT-4和事件 GPT-3在许多任务上都表现出色。我经常使用它,并且可以很好地将它用于任何事情,例如情感分析、文档分类和翻译。


尽管很了不起,GPT-4——甚至GPT-3——都是相当大的模型。


12


同样值得一提的是,GPT是一个文本生成模型,主要用于内容生成,这对于创意写作或市场营销内容的创造、开发聊天机器人等非常惊人。因此,尽管它目前高度先进,能够执行任何任务,但技术上并不是为所有自然语言处理(NLP)任务而设计的。


请参见下表,了解三个开源模型的架构和它们训练用途的具体例子。


13


假设我们正在做一些平凡的事情,比如分析情感或总结内容。我们正在抓取特定的社交媒体网站或许是客服对话,然后使用AI来分析其内容,总结并给我们一个报告。


我们来看看使用一个较大的闭源模型,如GPT-4 Turbo、GPT-3.5 Turbo或Claude 2,如果我们每天分析多达3000段文本,每段输入400个标记,输出200个标记,那么成本会是多少。


14


显然我们可以尝试将文本批量放入相同的API调用中,但这样我们的代币数量会增加。然而,想法是,对于这样简单的任务使用这些大型模型是杀鸡用牛刀。每月支付多达1000美元对于这样简单的事情来说是不划算的。


那么,我们有哪些选择呢?让我们看看在Hugging Face中有几个针对情感分析和摘要提取进行了微调的开源模型,这里和这里。这些是针对特定任务执行的微调模型。


这是使用 T5 作为基本模型的更一般的总结。下面也是另一个基于 RoBERTa(编码器模型)构建的情感分析模型。


15


这些只是例子。


用例:关键词提取


请参阅下面我尝试使用NLTK、spaCy和KeyBERT从文本中提取关键词的例子。


sample_text = """So, I want to make a dashboard in [Bubble.io](https://Bubble.io). In said Dashboard, I want the "Analytics" of my Shopify-Store to be displayed nicely to the user.  Since I haven't used Bubble yet, what do I need to do, what do I need (to set up)?"""
# NLTK 
print("NLTK Keywords:")
print(extract_keywords_nltk(sample_text))
# NLTK Keywords:
# [('want', 2), ('dashboard', 2), ('need', 2), ('make', 1), ('https', 1), ('said', 1), ('analytics', 1), ('displayed', 1), ('nicely', 1), ('user', 1)]
# spaCy
print("\nspaCy Keywords:")
print(extract_keywords_spacy(sample_text))
# spaCy Keywords:
# [('want', 2), ('need', 2), ('dashboard', 1), ('said', 1), ('Dashboard', 1), ('Analytics', 1), ('Shopify', 1), ('Store', 1), ('displayed', 1), ('nicely', 1)]
# KeyBERT (provided by Hugging Face also)
print("\nKeyBERT Keywords:")
print(extract_keywords_keybert(sample_text))
# KeyBERT Keywords:
# [('analytics shopify', 0.7067), ('dashboard bubble', 0.6169), ('make dashboard', 0.5868), ('dashboard', 0.5715), ('dashboard want', 0.5541), ('shopify', 0.4827), ('shopify store', 0.4775), ('said dashboard', 0.4369), ('want analytics', 0.43), ('analytics', 0.4256)]


这些库都没有做我需要它们做的事情。如果我要汇总成千上万的文本,排在最前面的词将会是‘想要’‘制作’和‘说’。


这里是对于我提供的文本,我会寻找的关键词。


Bubble.io, Shopify, Analytics


我确实找到了一个已经在Hugging Face上经过微调的模型,并且这个模型的表现还不错。


查看下面来自这个模型的结果。


16


更好了,但还不够好。


如果我用这个h2-keywordextractor模型再测试一些文本,我会得到下面的结果。


from transformers import pipeline
pipe = pipeline("summarization", model="transformer3/H2-keywordextractor")
print(pipe("Simplifying Docker Multiplatform Builds with Buildx"))
# Keywords generated: Docker Multiplatform Builds, Buildx, Docker Multiplatform, Multiplatform Building, Installability, Container Store, Security, Transaction Support
print(pipe("Dissecting ByteByteGo’s Notification System Design Solution"))
# Keywords generated: ByteByteByteGo, Notification System Design Solution, ByteByteByte
print(pipe("Utilizing the Lease Pattern on AWS Using DDB and DDB Lock Client Library"))
# Keywords generated: lease pattern, DDB and DDB Lock Client Library, Lease Pattern, AWS, leases, amr research, integration middleware, security, transaction support


我需要的是比这更干净的东西。回复的词汇并不总是独立的、正确的或相关的。


查看使用上述相同文本的细调BART模型。


from transformers import pipeline
pipe = pipeline("text2text-generation", model="ilsilfverskiold/tech-keywords-extractor")
print(pipe("Simplifying Docker Multiplatform Builds with Buildx"))
# Keywords generated: Docker, Buildx, Multiplatform Builds
print(pipe("Dissecting ByteByteGo’s Notification System Design Solution"))
# Keywords generated: ByteByteGo, Notification System Design
print(pipe("Utilizing the Lease Pattern on AWS Using DDB and DDB Lock Client Library"))
# Keywords generated: Lease Pattern, AWS, DDB, Lock Client Library


看到它只返回了几个相关的关键词吗,确保像Docker这样的名字是分开的?这正是我需要的。通过能够提取正确的关键词,我可以对成千上万的文本进行分析。


在这里分享了我处理过的 8,500 行数据集,因此请查看或自己使用它。它有几个字段,但我用 GPT-4 生成的字段是关键字、主题和摘要。

如果你想构建一个不同的模型,就用那个模型吧。


17


训练


模型和任务


我确定BART是一个很好的基础模型,并将使用摘要作为任务,用于提取文本中的技术术语、公司名称、流程、平台和工具的模型。也许这是一个奇怪的选择,因为编码器模型似乎是使用文本分类作为任务的理想之选。


如果你对不同的变压器模型类型感到困惑,下面的表格展示了一些。


18


获取数据集


下一步是获取一个足够大的数据集来产生影响。也许3000篇文本就足够好了,但理想情况下,至少需要7000个例子。你可以创建自己的数据集,也可以使用别人分享的现成数据集。


我的数据集已经设置好了,不需要调整。


寻找基础模型


我看到很多人在决定采用哪个之前会“逛逛”基础模型。你可以直接微调一个基础模型,也可以微调已经被微调的模型,进一步进行微调。不过需要是一个变压器模型。


处理数据集


首先,我们将开始导入我们需要的所有依赖项。


# install dependencies
!pip install -U datasets
!pip install -U accelerate
!pip install -U transformers
!pip install -U huggingface_hub


接下来,我们将导入我们将要使用的数据集。在这里,你可以自行选择要导入的数据集。


from datasets import load_dataset
# import dataset from hugging face
dataset = load_dataset("ilsilfverskiold/tech-keywords-topics-summary")
# check the dataset
dataset


这个模型已经为你设置好了训练集、验证集和测试集。如果你运行它,它应该会记录这个过程。


DatasetDict({
    train: Dataset({
        features: ['id', 'source', 'text', 'timestamp', 'reactions', 'engagement', 'url', 'text_length', 'keywords', 'topic', 'summary', '__index_level_0__'],
        num_rows: 7196
    })
    validation: Dataset({
        features: ['id', 'source', 'text', 'timestamp', 'reactions', 'engagement', 'url', 'text_length', 'keywords', 'topic', 'summary', '__index_level_0__'],
        num_rows: 635
    })
    test: Dataset({
        features: ['id', 'source', 'text', 'timestamp', 'reactions', 'engagement', 'url', 'text_length', 'keywords', 'topic', 'summary', '__index_level_0__'],
        num_rows: 635
    })
})


验证集和测试集的数据量很小。我发现它做的还可以,但理想情况下你需要数据都更多一些。


我们可以从数据集中绘制一些示例来看看它是什么样子。


# map out some examples from the dataset
def show_samples(dataset, num_samples=3, seed=42):
    sample = dataset["train"].shuffle(seed=seed).select(range(num_samples))
    for example in sample:
        print(f"\n'>> Text: {example['text']}'")
        print(f"'>> Keywords: {example['keywords']}'")

show_samples(dataset)


结果:


'>> Text: Driverless car users will not be prosecuted for fatal crashes in UK'
'>> Keywords: Driverless Cars, Legal Issues, UK'
'>> Text: Google is embedding inaudible watermarks right into its AI generated music -'
'>> Keywords: Google, AI Music, Watermarks, Audio Technology'
'>> Text: What are your thoughts on Nextjs performance? Do you agree with this chart? - ( by 10up where Nextjs appears lower than WordPress on core vitals. Couldn’t post the image here due to community rules. But appreciate any other studies and thought you have on this matter.'
'>> Keywords: Next.js, Performance, 10up, WordPress'


在这里,我使用文本和关键字作为字段。你可以选择使用其他字段。


接下来,我们将获取基模型的分词器,以便我们可以检查文本的长度。BART有1024个令牌的限制。


from transformers import AutoModelForSeq2SeqLM, AutoTokenizer
# set the correct model you'll be fine-tuning 
model_name = 'facebook/bart-large'
# get the tokenizer for the model
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForSeq2SeqLM.from_pretrained(model_name)
# check the token length of the text field - you can do this for both fields
texts = dataset['train']['text']
# Tokenize all texts and find the maximum length (max for BART is 1024 tokens)
max_token_length = max(len(tokenizer.encode(text, truncation=True)) for text in texts)
print(f"The longest text is {max_token_length} tokens long.")


现在我们将对这些数据进行预处理,并将输入文本和目标(即关键词)转换为适合训练序列到序列模型的格式。


# preprocessing function - sequence to sequence model
def get_feature(batch):
  encodings = tokenizer(batch['text'], text_target=batch['keywords'],
                        max_length=1024, truncation=True)
  encodings = {'input_ids': encodings['input_ids'],
               'attention_mask': encodings['attention_mask'],
               'labels': encodings['labels']}
  return encodings
dataset_pt = dataset.map(get_feature, batched=True)
dataset_pt


现在,这个dataset_pt将记录一些新的字段,包括input_ids、attention_mask和labels。


DatasetDict({
    train: Dataset({
        features: ['id', 'source', 'text', 'timestamp', 'reactions', 'engagement', 'url', 'text_length', 'keywords', 'topic', 'summary', '__index_level_0__', 'input_ids', 'attention_mask', 'labels'],
        num_rows: 7196
    })
    validation: Dataset({
        features: ['id', 'source', 'text', 'timestamp', 'reactions', 'engagement', 'url', 'text_length', 'keywords', 'topic', 'summary', '__index_level_0__', 'input_ids', 'attention_mask', 'labels'],
        num_rows: 635
    })
    test: Dataset({
        features: ['id', 'source', 'text', 'timestamp', 'reactions', 'engagement', 'url', 'text_length', 'keywords', 'topic', 'summary', '__index_level_0__', 'input_ids', 'attention_mask', 'labels'],
        num_rows: 635
    })
})


我们将指定这些新字段是应该被返回的字段。


columns = ['input_ids', 'labels', 'attention_mask']'input_ids', 'labels', 'attention_mask']
dataset_pt.set_format(type='torch', columns=columns)


我们开始训练模型之前要做的最后一件事是获取序列到序列模型的数据整理器。


数据整理器负责动态填充批次到每个批次中的最大长度,这对于像BART或T5这样的变换器模型的高效训练至关重要。


from transformers import DataCollatorForSeq2Seq
data_collator = DataCollatorForSeq2Seq(tokenizer, model=model)q(tokenizer, model=model)


根据你使用的模型类型,填充看起来会有所不同。

在查看预处理函数和数据整理器时,请将其视为我们试图将人类可读的文本翻译成计算机可以理解的内容。

每个模型都有自己的流程,这就是为什么如果你使用仅编码器或仅解码器模型,它可能看起来不同。


训练过程


我们应该准备开始训练模型了。我们使用的是训练器API,它抽象了许多复杂性,在这里让我们很容易对变换器模型进行微调。


确保你在Colab上切换你的运行时至少使用T4。如果你在专业计划中,你可以使用V100,但那样的话也要将批处理大小至少增加到8。


from transformers import TrainingArguments, Trainer
# we're using the Trainer API which abstracts away a lot of complexity
training_args = TrainingArguments(
    output_dir = 'bart_tech_keywords', # rename to what you want it to be called
    num_train_epochs=3, # your choice
    warmup_steps = 500,
    per_device_train_batch_size=4, # keep a small batch size when working with a small GPU
    per_device_eval_batch_size=4,
    weight_decay = 0.01, # helps prevent overfitting
    logging_steps = 10,
    evaluation_strategy = 'steps',
    eval_steps=50, # base this on the size of your dataset and number of training epochs
    save_steps=1e6,
    gradient_accumulation_steps=16 # running this on a small GPU
)
trainer = Trainer(model=model, args=training_args, tokenizer=tokenizer, data_collator=data_collator,
                  train_dataset = dataset_pt['train'], eval_dataset = dataset_pt['validation'])
trainer.train()


你可以查看代码中的我的注释来理解我们正在使用的参数。


完成后,保存模型。确保你设置了你想要的名称。


# save the model
trainer.save_model('tech-keywords-extractor') # set the name you want


测试


现在我们可以手动对它进行测试,看看它在我们的测试集上的表现如何。


from transformers import pipeline
# test the model using Hugging Face's pipeline
pipe = pipeline('summarization', model='tech-keywords-extractor')
# test the first item in the test set to see how it does
test_text=dataset['test'][0]['text']
keywords = dataset['test'][0]['keywords']
print("the text: ", text_test)
print("generated keywords: ", pipe(test_text))
print("orginal keywords : ",keywords)


你也可以逐个迭代几个示例,以便一一查看它们的表现情况。


# iterate over the test set to generate 50 examples at once
for i in range(0, 50):
    text_test = dataset['test'][i]['text']
    keywords = dataset['test'][i]['keywords']
    print("text: ", text_test)
    print("generated keywords: ", pipe(text_test)[0]['summary_text'])
    print("original keywords: ", keywords)


推送到Hugging Face


所以如果你准备好了,你可以推送它到Hugging Face中心,以便将来使用。


要登录,你需要导航到Hugging Face并进入你的账户设置,以找到访问令牌。


19


你找到它,创建一个新的写入令牌并复制它。当他们要求你提供你的令牌时,请使用它。


# Log in - they'll ask for your token
!huggingface-cli login


在你登录后,你可以简单地设置你的用户名以及你希望模型被推送到的路径。这将为你创建一个新的模型仓库。


# you would replace your own name here
# you do not need to create a repository beforehand
trainer.push_to_hub("your_hugging_face_username/tech-keywords-extractor")


这样就完成了!

文章来源:https://medium.com/gitconnected/fine-tune-smaller-nlp-models-with-hugging-face-for-specific-use-cases-1745813471dc
欢迎关注ATYUN官方公众号
商务合作及内容投稿请联系邮箱:bd@atyun.com
评论 登录
热门职位
Maluuba
20000~40000/月
Cisco
25000~30000/月 深圳市
PilotAILabs
30000~60000/年 深圳市
写评论取消
回复取消