26备战秋招day12——基于Wikitext-2数据集的gpt2文本生成

自然语言处理中的文本生成:从基础到实践

自然语言处理(NLP)中的文本生成任务是指让模型根据一些输入内容,自动生成自然语言文本。这种技术在很多应用中都有用武之地,比如聊天机器人、自动写作、内容创作等。

比如,当你输入“今天的天气是”时,NLP模型可能生成类似“晴天”的文本。本文将带你了解文本生成的基本概念、常用的数据集和模型,并用代码演示如何使用GPT-2模型生成文本,同时避免训练过程中的过拟合现象。

基础知识

文本生成的原理

文本生成的关键是语言模型,它根据给定的上下文来预测接下来的词。例如,你输入 “明天我想去”,模型可能生成 “公园”、“购物”等合理的接续。

常见的文本生成模型
  1. GPT-2:OpenAI的一个强大的文本生成模型,能够根据上下文生成流畅的段落。
  2. BARTT5:这类模型除了生成文本,还能处理翻译和摘要等任务。
  3. Transformer 架构:这些模型依赖强大的Transformer架构,它们能够捕捉长距离的文本依赖关系,生成连贯的文本。

数据集

为了让模型学会生成文本,我们需要数据。常用的文本生成数据集有:

  • Wikitext-2:一个较小的语言建模数据集,来自维基百科的文章,适合简单的文本生成任务。
  • OpenWebText:这是一个大型的数据集,来源于互联网上的开放内容,适合训练更大规模的模型。
  • CNN/DailyMail:主要用于新闻摘要生成任务,包含新闻和摘要对。

评价指标

生成的文本如何评价呢?常用的评价指标包括:

  • Perplexity(困惑度):衡量模型生成文本的自然程度,越低的Perplexity代表生成的文本越符合语言习惯。
  • BLEU/ROUGE:比较生成文本与参考文本之间的相似度,通常用于机器翻译和摘要任务。

实践:使用GPT-2进行文本生成并避免过拟合

我们将使用transformers库中的GPT-2模型进行文本生成。通过微调模型生成合适的文本,同时避免在训练过程中出现过拟合的问题。

环境准备

首先,确保安装必要的Python库:

!pip install transformers datasets torch
加载和预处理数据

我们使用Wikitext-2数据集,并将其分词和处理。接着,我们为训练和验证集分别进行标注处理。

from datasets import load_dataset
from transformers import GPT2Tokenizer, GPT2LMHeadModel, Trainer, TrainingArguments
import torch

# 加载Wikitext-2数据集
dataset = load_dataset("wikitext", "wikitext-2-raw-v1")

# 加载GPT-2的分词器和模型
tokenizer = GPT2Tokenizer.from_pretrained("gpt2")
model = GPT2LMHeadModel.from_pretrained("gpt2")

# 添加 padding token,因为 GPT-2 默认没有设置它
tokenizer.pad_token = tokenizer.eos_token

# 预处理函数,tokenize文本并创建labels
def tokenize_function(examples):
    tokenized = tokenizer(examples['text'], padding='max_length', truncation=True, max_length=128)
    tokenized['labels'] = tokenized['input_ids'].copy()
    return tokenized

# 对训练和验证集进行分词处理
tokenized_datasets = dataset.map(tokenize_function, batched=True, remove_columns=["text"])

train_dataset = tokenized_datasets["train"].shuffle(seed=42).select(range(1000))  # 选择1000条作为训练集
eval_dataset = tokenized_datasets["validation"].shuffle(seed=42).select(range(1000))  # 选择1000条作为验证集
训练时避免过拟合

为了防止训练时过拟合,我们将做以下几点调整:

  1. 减小学习率:学习率过高可能导致训练发散或过拟合,故我们设置一个较小的学习率。
  2. 增加正则化:通过增加 weight_decay 参数,限制模型的过度学习。
  3. 使用Early Stopping:在验证集上监控模型表现,当验证集性能不再提升时提前停止训练。
代码示例:训练与评估
# 使用Early Stopping防止过拟合
from transformers import TrainerCallback

class EarlyStoppingCallback(TrainerCallback):
    def __init__(self, patience=3, min_delta=0.0):
        self.patience = patience
        self.min_delta = min_delta
        self.best_loss = float('inf')
        self.counter = 0

    def on_evaluate(self, args, state, control, **kwargs):
        current_loss = kwargs["metrics"]["eval_loss"]
        if current_loss < self.best_loss - self.min_delta:
            self.best_loss = current_loss
            self.counter = 0
        else:
            self.counter += 1
            if self.counter >= self.patience:
                print(f"Early stopping triggered. Best eval loss: {self.best_loss}")
                control.should_training_stop = True

# 设置训练参数,避免过拟合
training_args = TrainingArguments(
    output_dir="./gpt2-wikitext2",
    evaluation_strategy="epoch",
    learning_rate=1e-5,  # 较低的学习率
    per_device_train_batch_size=2,
    per_device_eval_batch_size=2,
    num_train_epochs=20,  # 我们设置20个epoch,但使用Early Stopping
    weight_decay=0.1,  # 增加正则化
    save_steps=10_000,
    save_total_limit=2,
    logging_dir='./logs',
    report_to=[],  # 禁用 wandb 等监控工具
)

# 创建Trainer实例
trainer = Trainer(
    model=model,
    args=training_args,
    train_dataset=train_dataset,
    eval_dataset=eval_dataset,
    callbacks=[EarlyStoppingCallback(patience=3)]  # 使用Early Stopping
)

# 开始训练
trainer.train()
文本生成

在模型训练结束后,可以使用它生成文本。比如,我们可以输入一句话,然后让GPT-2自动生成后续的句子。

# 检查是否有可用的GPU
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model.to(device)

# 生成文本
model.eval()

input_text = "The future of AI is"
inputs = tokenizer(input_text, return_tensors="pt", padding=True)
input_ids = inputs['input_ids'].to(device)
attention_mask = inputs['attention_mask'].to(device)

# 设置 pad_token_id 为 eos_token_id(如果没有明确设置)
if model.config.pad_token_id is None:
    model.config.pad_token_id = model.config.eos_token_id

# 生成文本
generated_ids = model.generate(input_ids, attention_mask=attention_mask, max_length=50, num_return_sequences=1)
generated_text = tokenizer.decode(generated_ids[0], skip_special_tokens=True)
print("Generated text:", generated_text)
评价模型质量:计算Perplexity

最后,我们可以用Perplexity来衡量生成文本的质量。Perplexity越低,说明模型生成的文本越符合语言习惯。

from math import exp
import torch

def calculate_perplexity(model, tokenizer, text):
    # 检查是否有可用的GPU
    device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

    model.to(device)
    
    inputs = tokenizer(text, return_tensors="pt").to(device)
    
    with torch.no_grad():
        outputs = model(**inputs, labels=inputs["input_ids"])
    
    loss = outputs.loss
    perplexity = exp(loss.item())
    return perplexity

# 测试文本的Perplexity
test_text = "The future of AI is"
print(f"Perplexity: {calculate_perplexity(model, tokenizer, test_text)}")

结论

通过调整学习率、增加正则化、以及使用Early Stopping策略,我们可以有效避免模型的过拟合问题。本文演示了如何从头开始加载数据、微调GPT-2模型、生成文本,并使用Perplexity来评价模型的生成效果。

如果有更多问题,欢迎关注公众号【算法最TOP】进一步讨论!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值