基于MindSpore的GPT2文本摘要 --AI代码解析
数据集加载与处理
- 数据集加载 本次实验使用的是nlpcc2017摘要数据,内容为新闻正文及其摘要,总计50000个样本。
from mindnlp.utils import http_get # 导入http_get模块,用于下载数据集# download dataset
url = 'https://download.mindspore.cn/toolkits/mindnlp/dataset/text_generation/nlpcc2017/train_with_summ.txt' # 数据集的URL
path = http_get(url, './') # 使用http_get函数下载数据集并保存到当前目录from mindspore.dataset import TextFileDataset # 导入TextFileDataset模块,用于加载文本文件数据集# load dataset
dataset = TextFileDataset(str(path), shuffle=False) # 加载下载的数据集,shuffle设置为False表示不打乱数据顺序
dataset.get_dataset_size() # 获取数据集的大小# split into training and testing dataset
train_dataset, test_dataset = dataset.split([0.9, 0.1], randomize=False) # 将数据集按比例分割为训练集(90%)和测试集(10%),randomize设置为False表示不随机打乱
代码解析:
- 导入模块:
from mindnlp.utils import http_get
:导入http_get
函数,用于从指定的URL下载数据。
- 下载数据集:
url = '...'
:定义数据集的下载链接。path = http_get(url, './')
:调用http_get
函数,将数据集下载到当前目录,并返回文件路径。
- 加载数据集:
from mindspore.dataset import TextFileDataset
:导入TextFileDataset
类,用于处理文本文件类型的数据集。dataset = TextFileDataset(str(path), shuffle=False)
:创建一个TextFileDataset
对象,加载之前下载的数据,shuffle=False
表示保持原始顺序。
- 获取数据集大小:
dataset.get_dataset_size()
:调用该方法获取数据集的大小(即样本数量)。
- 分割数据集:
train_dataset, test_dataset = dataset.split([0.9, 0.1], randomize=False)
:将数据集按90%和10%的比例分割为训练集和测试集,randomize=False
表明不打乱顺序。
API 解析:
http_get(url, path)
:该函数用于从url
指定的地址下载数据,并将其保存到path
指定的路径。下载完成后返回文件的路径。TextFileDataset
:这是一个用于处理文本数据集的类,支持从文件中读取文本数据并进行后续处理。get_dataset_size()
:该方法用于获取数据集的总样本数量,方便后续的数据处理和分析。split(ratios, randomize)
:此方法用于将数据集按照指定的比例分割成多个子集,ratios
为比例列表,randomize
表示是否打乱数据顺序。
- 数据预处理 原始数据格式:
article: [CLS] article_context [SEP]
summary: [CLS] summary_context [SEP]
预处理后的数据格式:
[CLS] article_context [SEP] summary_context [SEP]
import json # 导入json模块,用于处理JSON格式的数据
import numpy as np # 导入numpy库,用于数值计算和数组处理# preprocess dataset
def process_dataset(dataset, tokenizer, batch_size=6, max_seq_len=1024, shuffle=False):# 定义数据预处理函数def read_map(text):data = json.loads(text.tobytes()) # 将文本数据解析为字典格式return np.array(data['article']), np.array(data['summarization']) # 返回文章和摘要作为numpy数组def merge_and_pad(article, summary):# 对文章和摘要进行标记化处理# 对于最大序列长度进行填充,只截断文章tokenized = tokenizer(text=article, text_pair=summary,padding='max_length', truncation='only_first', max_length=max_seq_len)return tokenized['input_ids'], tokenized['input_ids'] # 返回标记化的输入IDdataset = dataset.map(read_map, 'text', ['article', 'summary']) # 使用read_map函数将文本数据映射为文章和摘要# 将列名更改为input_ids和labels以用于后续训练dataset = dataset.map(merge_and_pad, ['article', 'summary'], ['input_ids', 'labels']) # 使用merge_and_pad处理数据dataset = dataset.batch(batch_size) # 按照batch_size对数据集进行分批处理if shuffle:dataset = dataset.shuffle(batch_size) # 如果shuffle为True,则对数据集进行洗牌return dataset # 返回经过处理的数据集
代码解析:
- 导入模块:
import json
:导入JSON模块,用于处理JSON格式的数据。import numpy as np
:导入NumPy库,以便进行数值计算和数组操作。
- 定义数据预处理函数:
def process_dataset(dataset, tokenizer, batch_size=6, max_seq_len=1024, shuffle=False)
:定义一个函数来预处理数据集,包含数据集、分词器、批量大小、最大序列长度和是否打乱的参数。
- **内部函数 **
read_map
:def read_map(text)
:定义一个内部函数,用于处理输入的文本数据。data = json.loads(text.tobytes())
:将文本数据转换为字典格式。return np.array(data['article']), np.array(data['summarization'])
:返回文章和摘要的NumPy数组。
- **内部函数 **
merge_and_pad
:def merge_and_pad(article, summary)
:定义一个函数,用于对文章和摘要进行标记化处理。tokenized = tokenizer(...)
:使用分词器对文章和摘要进行标记化,设置填充和截断的选项。return tokenized['input_ids'], tokenized['input_ids']
:返回标记化后的输入ID。
- 映射和处理数据集:
dataset = dataset.map(read_map, 'text', ['article', 'summary'])
:使用read_map
函数将文本数据映射为文章和摘要。dataset = dataset.map(merge_and_pad, ['article', 'summary'], ['input_ids', 'labels'])
:使用merge_and_pad
函数处理数据并重命名列。
- 分批和洗牌:
dataset = dataset.batch(batch_size)
:将数据集按指定的批量大小进行分批。if shuffle: dataset = dataset.shuffle(batch_size)
:如果shuffle
为真,则对数据集进行洗牌。
- 返回处理后的数据集:
return dataset
:返回经过预处理的数据集。
API 解析:
json.loads()
:该函数用于将JSON格式的字符串解析为Python字典或列表。tokenizer()
:这是一个用于文本标记化的函数,通常将原始文本转换为模型可接受的输入格式,包括输入ID和其他必要的信息。参数中包含填充、截断策略以及最大长度等设置。dataset.map(func, input_columns, output_columns)
:该方法应用指定的函数到数据集的指定列,返回新的数据集。dataset.batch(batch_size)
:将数据集按指定的batch_size
进行分批处理,方便后续训练。dataset.shuffle(buffer_size)
:该方法用于随机打乱数据集的顺序,buffer_size
指代在打乱过程中使用的缓冲区大小。
因GPT2无中文的tokenizer,我们使用BertTokenizer替代。
from mindnlp.transformers import BertTokenizer # 导入BertTokenizer,用于中文文本的标记化# We use BertTokenizer for tokenizing chinese context.
tokenizer = BertTokenizer.from_pretrained('bert-base-chinese') # 从预训练模型加载BERT分词器len(tokenizer) # 获取分词器的词汇表大小# 处理训练数据集
train_dataset = process_dataset(train_dataset, tokenizer, batch_size=4) # 使用process_dataset函数处理训练集,设置batch_size为4next(train_dataset.create_tuple_iterator()) # 创建一个元组迭代器并获取下一个批次的数据
代码解析:
- 导入BertTokenizer:
from mindnlp.transformers import BertTokenizer
:导入BertTokenizer
类,该类用于处理中文文本的标记化。
- 初始化分词器:
tokenizer = BertTokenizer.from_pretrained('bert-base-chinese')
:从预训练的BERT模型加载中文分词器,'bert-base-chinese'
是BERT的中文基础版。
- 获取词汇表大小:
len(tokenizer)
:获取分词器的词汇表大小,以便了解可以处理的词汇数量。
- 处理训练数据集:
train_dataset = process_dataset(train_dataset, tokenizer, batch_size=4)
:调用process_dataset
函数处理训练数据集,设置每个批次的大小为4。
- 创建迭代器并获取数据:
next(train_dataset.create_tuple_iterator())
:使用create_tuple_iterator()
方法创建一个元组迭代器,并获取下一个批次的数据。这通常用于迭代训练数据集中的样本。
API 解析:
BertTokenizer.from_pretrained()
:该方法用于加载指定预训练BERT模型的分词器,可以处理特定语言的文本,如中文。len(tokenizer)
:用于获取分词器的词汇表大小,返回值为一个整数,表示分词器可以识别的词语数量。process_dataset(dataset, tokenizer, batch_size)
:自定义函数,用于处理数据集并返回一个批量处理过的数据集。create_tuple_iterator()
:该方法用于创建一个元组形式的迭代器,可以迭代数据集中的样本,适合于模型训练过程中的数据输入。next(iterator)
:用于获取迭代器中的下一个元素,通常在处理批量数据时使用。
模型构建
- 构建GPT2ForSummarization模型,注意_shift right_的操作。
from mindspore import ops # 导入MindSpore的操作模块
from mindnlp.transformers import GPT2LMHeadModel # 导入GPT2LMHeadModel类,用于文本生成任务class GPT2ForSummarization(GPT2LMHeadModel): # 定义一个新的类,继承自GPT2LMHeadModeldef construct(self,input_ids=None, # 输入的token IDattention_mask=None, # 注意力掩码labels=None, # 真实标签):# 调用父类的construct方法,获取模型输出outputs = super().construct(input_ids=input_ids, attention_mask=attention_mask)# 对logits进行偏移处理,移除最后一个token的输出shift_logits = outputs.logits[..., :-1, :] # 将labels进行偏移,移除第一个token的标签shift_labels = labels[..., 1:] # 计算交叉熵损失loss = ops.cross_entropy(shift_logits.view(-1, shift_logits.shape[-1]), shift_labels.view(-1), ignore_index=tokenizer.pad_token_id)return loss # 返回计算得到的损失
代码解析:
- 导入模块:
from mindspore import ops
:导入MindSpore的操作模块,提供各种张量操作和计算功能。from mindnlp.transformers import GPT2LMHeadModel
:导入GPT2的语言模型头类,用于文本生成和相关任务。
- **定义类 **
GPT2ForSummarization
:class GPT2ForSummarization(GPT2LMHeadModel)
:定义一个名为GPT2ForSummarization
的类,继承自GPT2LMHeadModel
,目的是用于文本摘要生成。
- 构造方法:
def construct(self, input_ids=None, attention_mask=None, labels=None)
:定义构造方法,接受输入的token ID、注意力掩码和真实标签。
- 调用父类方法:
outputs = super().construct(input_ids=input_ids, attention_mask=attention_mask)
:调用父类的方法,以获取模型的输出,包括logits(预测结果)。
- 处理logits和labels:
shift_logits = outputs.logits[..., :-1, :]
:从logits中移除最后一个token的输出,便于后续计算。shift_labels = labels[..., 1:]
:从labels中移除第一个token的标签,以对齐logits。
- 计算损失:
loss = ops.cross_entropy(...)
:使用交叉熵函数计算损失。shift_logits
被展平,并与shift_labels
进行比较,ignore_index
参数用于忽略填充的token。
- 返回损失:
return loss
:返回计算得到的损失值。
API 解析:
ops.cross_entropy()
:用于计算交叉熵损失的函数。输入包括预测的logits和真实标签,常用于分类任务的损失计算。super().construct()
:调用父类(GPT2LMHeadModel
)的构造函数,以便获取标准的输出,包括logits。.view()
:这是一个张量操作,用于改变张量的形状,通常用于将多维张量展平为一维或改变其维度,便于后续处理。tokenizer.pad_token_id
:这是分词器中定义的填充token的ID,常用于在计算损失时忽略填充部分的影响。
- 动态学习率
from mindspore import ops # 导入MindSpore的操作模块
from mindspore.nn.learning_rate_schedule import LearningRateSchedule # 导入学习率调度类class LinearWithWarmUp(LearningRateSchedule): # 定义一个线性带热身的学习率调度类"""Warmup-decay learning rate."""def __init__(self, learning_rate, num_warmup_steps, num_training_steps):super().__init__() # 调用父类的构造函数self.learning_rate = learning_rate # 初始化学习率self.num_warmup_steps = num_warmup_steps # 初始化热身步骤数self.num_training_steps = num_training_steps # 初始化训练总步骤数def construct(self, global_step): # 定义构造方法,接收当前的全局步骤数if global_step < self.num_warmup_steps: # 如果当前步骤小于热身步骤数# 计算线性热身学习率return global_step / float(max(1, self.num_warmup_steps)) * self.learning_rate# 计算衰减后的学习率return ops.maximum(0.0, (self.num_training_steps - global_step) / float(max(1, self.num_training_steps - self.num_warmup_steps))) * self.learning_rate # 返回学习率
代码解析:
- 导入模块:
from mindspore import ops
:导入MindSpore的操作模块,提供数值计算功能。from mindspore.nn.learning_rate_schedule import LearningRateSchedule
:导入学习率调度类,允许创建自定义的学习率调度策略。
- **定义类 **
LinearWithWarmUp
:class LinearWithWarmUp(LearningRateSchedule)
:定义一个新的类,继承自LearningRateSchedule
,用于实现带热身的线性学习率调度。
- 构造方法:
def __init__(self, learning_rate, num_warmup_steps, num_training_steps)
:定义构造方法,接受学习率、热身步骤数和训练总步骤数。super().__init__()
:调用父类的构造函数进行初始化。self.learning_rate = learning_rate
:保存学习率。self.num_warmup_steps = num_warmup_steps
:保存热身步骤数。self.num_training_steps = num_training_steps
:保存训练总步骤数。
- 构造学习率:
def construct(self, global_step)
:定义构造方法,根据当前全局步骤计算学习率。if global_step < self.num_warmup_steps
:检查当前步骤是否在热身阶段。return global_step / float(max(1, self.num_warmup_steps)) * self.learning_rate
:如果在热身阶段,计算线性增长的学习率。
- 计算衰减学习率:
return ops.maximum(...) * self.learning_rate
:在热身结束后,计算衰减学习率,并确保学习率不会为负。
API 解析:
LearningRateSchedule
:一个基类,用于实现自定义的学习率调度策略,允许用户定义如何根据训练进度调整学习率。ops.maximum()
:用于计算输入张量的最大值,通常用于确保学习率的非负性。max(1, value)
:返回value
和1之间的较大值,避免在计算中出现除以零的情况。global_step
:当前的全局训练步骤,通常用于动态调整学习率。construct(...)
:这是一个方法,用于根据当前的训练状态(如全局步骤)动态计算所需的学习率。
模型训练
num_epochs = 1 # 设置训练的轮数为1
warmup_steps = 2000 # 设置热身步骤数为2000
learning_rate = 1.5e-4 # 设置初始学习率为1.5e-4num_training_steps = num_epochs * train_dataset.get_dataset_size() # 计算总训练步骤数from mindspore import nn # 导入MindSpore的神经网络模块
from mindnlp.transformers import GPT2Config, GPT2LMHeadModel # 导入GPT2的配置和模型类config = GPT2Config(vocab_size=len(tokenizer)) # 创建GPT2模型配置,设置词汇表大小
model = GPT2ForSummarization(config) # 实例化模型# 创建学习率调度器
lr_scheduler = LinearWithWarmUp(learning_rate=learning_rate, num_warmup_steps=warmup_steps, num_training_steps=num_training_steps)# 定义优化器
optimizer = nn.AdamWeightDecay(model.trainable_params(), learning_rate=lr_scheduler)# 记录模型参数数量
print('number of model parameters: {}'.format(model.num_parameters())) # 输出模型的参数数量
代码解析:
- 设置超参数:
num_epochs = 1
:设置训练的轮数为1。warmup_steps = 2000
:设置热身步骤数为2000,以在训练初期逐渐增加学习率。learning_rate = 1.5e-4
:设置初始学习率为1.5e-4,控制模型学习的速度。
- 计算训练步骤:
num_training_steps = num_epochs * train_dataset.get_dataset_size()
:计算总的训练步骤数,乘以训练数据集的大小。
- 导入必要模块:
from mindspore import nn
:导入MindSpore的神经网络模块,以便使用神经网络相关的类和函数。from mindnlp.transformers import GPT2Config, GPT2LMHeadModel
:导入用于配置和创建GPT2模型的类。
- 创建模型配置:
config = GPT2Config(vocab_size=len(tokenizer))
:使用分词器的词汇表大小创建GPT2模型的配置。
- 实例化模型:
model = GPT2ForSummarization(config)
:根据配置实例化文本摘要生成模型。
- 创建学习率调度器:
lr_scheduler = LinearWithWarmUp(...)
:使用先前定义的LinearWithWarmUp
类创建学习率调度器,传入学习率、热身步骤数和总训练步骤数。
- 定义优化器:
optimizer = nn.AdamWeightDecay(...)
:使用Adam优化器及权重衰减,对模型的可训练参数进行优化,学习率由学习率调度器提供。
- 记录并输出模型参数数量:
print('number of model parameters: {}'.format(model.num_parameters()))
:输出模型的参数总数,以便了解模型的复杂性。
API 解析:
train_dataset.get_dataset_size()
:获取训练数据集的大小,通常返回样本数量,用于计算总训练步骤。GPT2Config(vocab_size=len(tokenizer))
:用于初始化GPT2模型的配置对象,包括设置词汇表大小等参数。GPT2ForSummarization(config)
:创建模型实例,使用之前定义的模型配置。LinearWithWarmUp(...)
:创建一个线性带热身的学习率调度器对象,使学习率在训练初期逐渐增加,随后再进行衰减。nn.AdamWeightDecay(...)
:Adam优化器的一个变种,支持权重衰减功能,用于正则化以防止过拟合。model.num_parameters()
:返回模型中可训练参数的数量,帮助用户理解模型的规模。
from mindnlp._legacy.engine import Trainer # 导入Trainer类,用于训练模型
from mindnlp._legacy.engine.callbacks import CheckpointCallback # 导入CheckpointCallback类,用于保存训练模型的检查点# 创建检查点回调对象
ckpoint_cb = CheckpointCallback(save_path='checkpoint', # 指定保存路径ckpt_name='gpt2_summarization', # 指定检查点的名称epochs=1, # 设置每个epoch保存一次检查点keep_checkpoint_max=2 # 最大保留2个检查点
)# 创建Trainer对象,用于训练模型
trainer = Trainer(network=model, # 训练的模型train_dataset=train_dataset, # 训练数据集epochs=1, # 设置训练轮数optimizer=optimizer, # 使用的优化器callbacks=ckpoint_cb # 添加回调函数
)# 设置混合精度
trainer.set_amp(level='O1') # 开启混合精度训练,O1级别表示混合精度的使用# 开始训练,指定目标列
trainer.run(tgt_columns="labels") # 开始训练,"labels"为目标列
代码解析:
- 导入模块:
from mindnlp._legacy.engine import Trainer
:导入Trainer类,用于管理和执行模型的训练流程。from mindnlp._legacy.engine.callbacks import CheckpointCallback
:导入CheckpointCallback类,用于在训练过程中保存模型的检查点。
- 创建检查点回调对象:
ckpoint_cb = CheckpointCallback(...)
:创建一个检查点回调对象,允许在训练过程中定期保存模型状态。save_path='checkpoint'
:指定保存检查点的文件夹名称。ckpt_name='gpt2_summarization'
:指定保存的检查点文件名。epochs=1
:设置每个epoch结束时保存一次检查点。keep_checkpoint_max=2
:最多保留2个检查点文件,旧的检查点将会被覆盖。
- 创建Trainer对象:
trainer = Trainer(...)
:实例化Trainer对象,控制训练进程。network=model
:指定要训练的模型。train_dataset=train_dataset
:传入训练数据集。epochs=1
:设置训练轮数为1。optimizer=optimizer
:指定优化器。callbacks=ckpoint_cb
:添加回调函数(检查点回调)。
- 设置混合精度:
trainer.set_amp(level='O1')
:启用混合精度训练,使用O1级别的配置,O1表示大部分操作使用FP16(半精度浮点),而少数关键操作使用FP32(单精度浮点),以提高计算效率并减少内存使用。
- 开始训练:
trainer.run(tgt_columns="labels")
:开始模型的训练过程,tgt_columns="labels"
指定用于训练的目标列。
API 解析:
Trainer
:一个训练管理类,提供训练过程中所需的功能,如训练循环、优化器管理和回调函数管理。CheckpointCallback(...)
:用于设置训练过程中的检查点保存策略,使得每次训练完成一个epoch后可以保存模型状态,以便后续恢复和继续训练。trainer.set_amp(level='O1')
:配置混合精度训练,旨在提高训练性能,降低内存使用。trainer.run(tgt_columns="labels")
:执行训练过程,tgt_columns
指定模型训练所需的目标输出列,通常用于处理标签。
模型推理
数据处理,将向量数据变为中文数据
def process_test_dataset(dataset, tokenizer, batch_size=1, max_seq_len=1024, max_summary_len=100):# 定义处理测试数据集的函数def read_map(text):# 解析文本数据为文章和摘要data = json.loads(text.tobytes()) # 将字节文本加载为JSONreturn np.array(data['article']), np.array(data['summarization']) # 返回文章和摘要def pad(article):# 对文章进行分词和填充tokenized = tokenizer(text=article, truncation=True, max_length=max_seq_len - max_summary_len) # 分词并截断return tokenized['input_ids'] # 返回输入ID# 使用map函数对数据集进行处理dataset = dataset.map(read_map, 'text', ['article', 'summary']) # 解析数据集dataset = dataset.map(pad, 'article', ['input_ids']) # 填充分词后的文章# 将数据集按批次处理dataset = dataset.batch(batch_size)return dataset # 返回处理后的数据集# 处理测试数据集
test_dataset = process_test_dataset(test_dataset, tokenizer, batch_size=1)
print(next(test_dataset.create_tuple_iterator(output_numpy=True))) # 打印测试数据集中的一项# 加载预训练模型
model = GPT2LMHeadModel.from_pretrained('./checkpoint/gpt2_summarization_epoch_0.ckpt', config=config)
model.set_train(False) # 设置模型为评估模式# 设置模型的结束标记ID
model.config.eos_token_id = model.config.sep_token_id i = 0
# 迭代测试数据集
for (input_ids, raw_summary) in test_dataset.create_tuple_iterator():# 使用模型生成总结output_ids = model.generate(input_ids, max_new_tokens=50, num_beams=5, no_repeat_ngram_size=2) output_text = tokenizer.decode(output_ids[0].tolist()) # 解码生成的ID为文本print(output_text) # 输出生成的总结i += 1if i == 1: # 只处理一个样本break
代码解析:
- **定义函数 **
process_test_dataset
:def process_test_dataset(dataset, tokenizer, batch_size=1, max_seq_len=1024, max_summary_len=100)
:定义一个函数,用于处理测试数据集。read_map(text)
:定义内部函数,用于将输入文本转换为文章和摘要。data = json.loads(text.tobytes())
:将字节文本解析为JSON格式。return np.array(data['article']), np.array(data['summarization'])
:返回文章和摘要内容。
pad(article)
:定义另一个内部函数,用于对文章进行分词处理。tokenized = tokenizer(...)
:使用分词器对文章进行分词和截断,确保长度不超过max_seq_len - max_summary_len
。return tokenized['input_ids']
:返回分词后的输入ID。
- 处理数据集:
dataset = dataset.map(read_map, 'text', ['article', 'summary'])
:对数据集应用read_map
函数,解析输入文本。dataset = dataset.map(pad, 'article', ['input_ids'])
:对文章进行分词填充。dataset = dataset.batch(batch_size)
:将数据集按批次进行处理。
- 返回处理后的数据集:
return dataset
:返回处理后的测试数据集。
- 处理测试数据集:
test_dataset = process_test_dataset(...)
:调用函数处理测试集。print(next(test_dataset.create_tuple_iterator(output_numpy=True)))
:打印处理后的测试数据集中的一项。
- 加载预训练模型:
model = GPT2LMHeadModel.from_pretrained(...)
:从指定路径加载预训练的GPT2模型。model.set_train(False)
:设置模型为评估模式,不进行训练。
- 设置结束标记ID:
model.config.eos_token_id = model.config.sep_token_id
:将结束标记ID设置为分隔标记ID。
- 生成摘要:
for (input_ids, raw_summary) in test_dataset.create_tuple_iterator():
:迭代处理后的测试数据集。output_ids = model.generate(...)
:使用模型生成摘要,设置最大生成长度、束搜索数量和不重复n-gram的大小。output_text = tokenizer.decode(output_ids[0].tolist())
:解码生成的ID,转换为可读文本。print(output_text)
:输出生成的摘要。i += 1
:累加处理的样本数量。if i == 1: break
:仅处理一个样本,之后退出循环。
API 解析:
json.loads(...)
:用于将JSON字符串解析为Python对象,适合处理动态数据。tokenizer(...)
:分词器对象的方法,用于将文本转换为模型输入所需的ID。dataset.map(...)
:数据集的映射函数,允许用户将自定义函数应用于数据集的每个元素。dataset.batch(batch_size)
:将数据集划分为指定大小的批次,以便于训练或推理。GPT2LMHeadModel.from_pretrained(...)
:从指定路径加载预训练的GPT2模型,便于进行推理或再训练。model.generate(...)
:使用模型生成文本,支持多种生成策略,如束搜索、最大生成长度等。tokenizer.decode(...)
:用于将生成的ID序列转换回可读的文本格式。