赞
踩
2018 年,谷歌发布基于双向 Transformer 的大规模预训练语言模型 BERT,而后一系列基于 BERT 的研究工作如春笋般涌现,预训练模型也成为了业内解决 NLP 问题的标配。
2019年,谷歌又提出预训练模型 T5(Text-to-Text Transfer Transformer),T5模型本质上来说是一个基于Transformer架构的encoder-decoder模型。T5模型将各种NLP任务都视为Text-to-Text任务,也就是输入为Text,输出也为Text的任务。
我们知道BERT相关的预训练语言模型,在下游任务微调过程中都需要添加非线性层,将模型的输出转化为任务指定的输出格式。但是,T5不需要对模型做任何改动,不需要添加任何非线性层,唯一需要做的就是在输入数据前加上任务声明前缀。
T5模型刚发布时,刷新了 Glue 榜单和 SuperGLUE 榜单,直至今日还是这两个榜单的前10名。
今天,我们来了解下T5这个经典的模型。
如下图所示,T5(Text-to-Text Transfer Transformer
)模型将翻译、分类、回归、摘要生成等任务都统一转成Text-to-Text任务,从而使得这些任务在训练(pre-train和fine-tune)时能够使用相同的目标函数,在测试时也能使用相同的解码过程。
T5模型在NLU和NLG上都具有出色表现,能够完成翻译任务、文本分类、阅读理解、摘要生成任务等多种下游任务。
然而,T5刚出来的时候,我们可能没有什么存在感,原因很简单:没有中文版T5可用。
不过Google后面放出了多国语言版的T5(mT5),里边包含了中文语言。
另外,国内还有一些公司,利用T5模型使用了大量中文数据进行训练。
孟子T5预训练生成模型与T5结构相同,但是不包含下游任务,需要在特定任务上 Finetune 后使用。孟子T5预训练生成模型-中文-base
iic在mt5模型基础上使用了大量中文数据进行训练,并引入了零样本分类增强的技术。全任务零样本学习-mT5分类增强版-中文-base
把一个句子看作一个整体,再拆成片段,而没有保留天然的词语的概念。
SentencePiece不将空格视为分隔符,而是将字符串作为其原始格式的输入,使用BPE或ULM作为其分词器来构建词汇表。
from transformers import T5Tokenizer
model_dir = r'D:\\python\\models\\model-download\\iic\\nlp_mt5_zero-shot-augment_chinese-base'
tokenizer = T5Tokenizer.from_pretrained(model_dir, legacy=False)
print(tokenizer.tokenize("Don't make the user feel stupid"))
# ['▁Don', "'", 't', '▁make', '▁the', '▁user', '▁feel', '▁stupid']
print(tokenizer.tokenize("笔画最多的汉字是龘(da)字"))
# 可以看到"龘"字经过tokenize变为:'<0xE9>', '<0xBE>', '<0x98>'
# ['▁', '笔', '画', '最多', '的', '汉', '字', '是', '<0xE9>', '<0xBE>', '<0x98>', '(', 'da', ')', '字']
不同于RNN、CNN等模型,对于Transformer模型来说,位置编码的加入是必不可少的,因为纯粹的Attention模块是无法捕捉输入顺序的,即无法区分不同位置的Token。为此我们大体有两个选择:
微调一下Attention结构,使得它有能力分辨不同位置的Token
,这构成了相对位置编码的一般做法。Transformer中有两种常用的位置编码,分别为绝对位置编码和相对位置编码。
我们先看常规相对位置编码的思路:
论文链接:https://arxiv.org/pdf/1803.02155
视频解释:Self-Attention with Relative Position Representations – Paper explained
因此需要dz=da
,得到(seq_length, B×h, seq_length)后reshape下得到(seq_length, B, h, seq_length),转置后shape为(B, h, seq_length, seq_length)这样就跟第一项对应起来了。我们先看下苏神博客中的内容,分析下T5模型中相对位置编码公式的由来:
近的分割线(对于双向attention是8,对单向attention是16)
# transformers/models/t5/modeling_t5.py中的T5Attention类 def compute_bias(self, query_length, key_length, device=None): """Compute binned relative position bias""" if device is None: device = self.relative_attention_bias.weight.device context_position = torch.arange(query_length, dtype=torch.long, device=device)[:, None] memory_position = torch.arange(key_length, dtype=torch.long, device=device)[None, :] # 计算相对位置 relative_position = memory_position - context_position # shape (query_length, key_length) # 分桶处理 relative_position_bucket = self._relative_position_bucket( relative_position, # shape (query_length, key_length) bidirectional=(not self.is_decoder), num_buckets=self.relative_attention_num_buckets, max_distance=self.relative_attention_max_distance, ) # Embedding矩阵为:self.relative_attention_bias = nn.Embedding(self.relative_attention_num_buckets, self.n_heads) # look-up查找,并进行维度转换 values = self.relative_attention_bias(relative_position_bucket) # shape (query_length, key_length, num_heads) values = values.permute([2, 0, 1]).unsqueeze(0) # shape (1, num_heads, query_length, key_length) return values
# 这里我们假设query_length=key_length=128 # 那么相对位置矩阵为 >>> relative_position tensor([[ 0, 1, 2, ..., 125, 126, 127], [ -1, 0, 1, ..., 124, 125, 126], [ -2, -1, 0, ..., 123, 124, 125], ..., [-125, -124, -123, ..., 0, 1, 2], [-126, -125, -124, ..., -1, 0, 1], [-127, -126, -125, ..., -2, -1, 0]]) # 分桶后 >>> relative_position_bucket tensor([[ 0, 17, 18, ..., 31, 31, 31], [ 1, 0, 17, ..., 31, 31, 31], [ 2, 1, 0, ..., 31, 31, 31], ..., [15, 15, 15, ..., 0, 17, 18], [15, 15, 15, ..., 1, 0, 17], [15, 15, 15, ..., 2, 1, 0]]) >>> relative_position_bucket[0] # 查看第一个,双向attention近的分割线为8 tensor([ 0, 17, 18, 19, 20, 21, 22, 23, 24, 24, 24, 24, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31]) >>> relative_position_bucket[-1] # 查看最后一个,双向attention近的分割线为8 # 就是比较邻近的位置(0~7),我们需要比较得精细一些,所以给它们都分配一个独立的位置编码 # 至于稍远的位置(比如8~11),我们不用区分得太清楚,所以它们可以共用一个位置编码。距离越远,共用的范围就可以越大 tensor([15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 8, 8, 8, 8, 7, 6, 5, 4, 3, 2, 1, 0]) # look-up查找后 values shape=(128, 128, 12) # 维度转换后 values shape=(1, 12, 128, 128)
# transformers/models/t5/modeling_t5.py中的T5Attention类 def forward( self, hidden_states, mask=None, key_value_states=None, position_bias=None, past_key_value=None, layer_head_mask=None, query_length=None, use_cache=False, output_attentions=False, ): ...... # 计算注意力分数 scores = torch.matmul( query_states, key_states.transpose(3, 2) ) # equivalent of torch.einsum("bnqd,bnkd->bnqk", query_states, key_states), compatible with onnx op>9 if position_bias is None: if not self.has_relative_attention_bias: ...... else: # 计算相对位置编码 shape = (1, num_heads, seq_length, key_length) position_bias = self.compute_bias(real_seq_length, key_length, device=scores.device) if mask is not None: # seq_length = key_length # 加上mask信息 mask shape = (batch_size, 1, 1, seq_length) # position_bias shape = (batch_size, n_heads, seq_length, seq_length) position_bias = position_bias + mask if self.pruned_heads: mask = torch.ones(position_bias.shape[1]) mask[list(self.pruned_heads)] = 0 position_bias_masked = position_bias[:, mask.bool()] else: position_bias_masked = position_bias # Note: 位置编码加在了注意力分数scores上 scores += position_bias_masked attn_weights = nn.functional.softmax(scores.float(), dim=-1).type_as( scores ) # (batch_size, n_heads, seq_length, key_length) ......
总结一下:
作者对公开爬取的网页数据集Common Crawl进行了过滤:
从上图实验结果可以看出:
(1) C4比unfiltered C4效果好,说明数据清洗的重要性;
(2) Wikipedia+TBC在SGLUE上的效果比C4好,主要是因为在SGLUE中的MultiRC任务得分很高,MultiRC是一个阅读理解数据集,其中的数据主要是小说书籍,和TBC属于同一领域数据。由此说明预训练的数据集中包含一定的领域数据对下游该领域任务的性能提升有效;
从上图中可以看出,随着数据集不断缩小,模型的性能逐渐下降,说明大的模型很可能在小的数据集上发生了过拟合,因此建议预训练模型还是尽可能使用大数据集。
论文对无监督目标过程中所做的选择进行了探索,从下面四个方面进行实验:
如上图所示,给定句子“Thank you for inviting me to your party last week .”,图中展示了针对不同的预训练目标,模型的Input和Target样本的形式。
其中Replace corrupted spans就是上上图中的noise replace spans目标
Drop corrupted tokens就是上上图中的noise, drop tokens目标。
结果表明,这几种BERT-style预训练目标的变种效果差不多,但是后两种方法不需要预测整个输入序列,而仅需要预测被污染的部分,因此预测的序列长度更短,训练速度也更快。
因此,经过上述实验,确定了T5模型的预训练方式如下:
微调模型的所有参数可能会导致结果欠佳,尤其是在资源匮乏的情况下。论文专注于两种替代的微调方法,这些方法仅更新编码器-解码器模型的参数的子集。
如下图所示,所有参数一起更新效果是最好的,但是缺点就是慢。
adapter layers可能是一种在较少参数上进行微调的有前途的技术,只要将维度适当地缩放到任务大小即可,假如任务数据量小的话,d取小一些,任务数据量大的话,d取大一些。
Gradual unfreezing尽管在微调过程中确实提供了一定的加速,但全局解冻会在所有任务中造成轻微的性能下降。因此通过更仔细地调整解冻时间表,可以获得更好的结果。
大多数将多任务学习应用于NLP的应用都会添加特定于任务的分类网络,或者为每个任务使用不同的损失函数。本论文的多任务学习仅将不同任务的数据集混合在一起。
若现在有无监督任务、有监督任务1、有监督任务2、有监督任务3,一起训练时如何采样数据?
作者设置了三种采样方法:
多任务学习+微调:先用多个任务进行预训练,再对具体任务进行微调
如上图所示,我们发现Multi-task pretraining+fine-tuning的效果和Unsupervised pre-training + fine-tuning的效果差不多,但是前者在预训练过程还能够监控下游任务的性能,因此作者最后采用Multi-task pre-training。
通过对各种对比实验的结果进行分析,作者最终确定了训练T5模型的较优方案:
即无监督任务和有监督任务一起预训练
)。模型 | Layers | Hidden Size | Attention Head | 参数量 |
---|---|---|---|---|
Small | 6 | 512 | 8 | 60M |
Base | 12 | 768 | 12 | 220M |
Large | 24 | 1024 | 16 | 770M |
3B | 24 | 1024 | 32 | 3B |
11B | 24 | 2028 | 128 | 11B |
mT5仍是T5数据构造方式(C4数据集),但语料不再只限于英语,而是扩大到101种语言,其中就包括了中文、俄语等。模型结构是使用的T5.1.1版本,相比于原始T5版本主要有如下升级:
提出一套多任务的微调方案(Flan),来极大提升语言模型的泛化性
。Flan微调的过程:
第一步是收集一系列监督的数据;
第二步将任务都转换成相同的“输入格式”喂给模型训练,同时这些任务的输出也需要是统一的“输出格式”,这样是为了使用单个语言模型来完成超过1800+种不同的任务;
第三步就是微调过程。
例如下面文章中的例子,模型训练好之后,可直接让模型做问答:
「模型输入」是:"Geoffrey Hinton和George Washington这两个人有没有交谈过?在回答之前想一想原因。“
「模型返回」是:Geoffrey Hinton是一个计算机科学家,出生在1947年;而George Washington在1799年去世。所以这两个不可能有过交谈。所以答案时“没有”。
孟子T5与T5结构相同,但是不包含下游任务,需要在特定任务上 finetune 后使用。
我们看一条数据集:
{
'title': '组图:黑河边防军人零下30℃户外训练,冰霜沾满眉毛和睫毛,防寒服上满是冰霜。',
'content': '中国军网2014-12-1709:08:0412月16日,黑龙江省军区驻黑河某边防团机动步兵连官兵,冒着-30℃严寒气温进行体能训练,挑战极寒,锻造钢筋铁骨。该连素有“世界冠军的摇篮”之称,曾有5人24人次登上世界军事五项冠军的领奖台。(魏建顺摄)黑龙江省军区驻黑河某边防团机动步兵连官兵冒着-30℃严寒气温进行体能训练驻黑河某边防团机动步兵连官兵严寒中户外训练,防寒服上满是冰霜驻黑河某边防团机动步兵连官兵严寒中户外训练,防寒服上满是冰霜官兵睫毛上都被冻上了冰霜官兵们睫毛上都被冻上了冰霜驻黑河某边防团机动步兵连官兵严寒中进行户外体能训练驻黑河某边防团机动步兵连官兵严寒中进行户外体能训练驻黑河某边防团机动步兵连官兵严寒中进行户外体能训练'
}
我们可以通过num参数控制数据集的数量进行训练。
""" 微调澜舟科技开源的mengzi-t5-base做摘要生成 数据集(只取5000条):nlpcc_2017: https://huggingface.co/datasets/supremezxc/nlpcc_2017 model link:https://modelscope.cn/models/langboat/mengzi-t5-base link: https://huggingface.co/Langboat/mengzi-t5-base 孟子中文T5预训练生成模型与T5结构相同,只有无监督数据训练,不包含下游任务,需要在特定任务上finetune后使用 """ import os import platform import torch import torch.nn as nn from torch.utils.data import Dataset, DataLoader from datasets import load_from_disk from transformers import AdamW from transformers import T5Tokenizer, T5ForConditionalGeneration from logging_util import get_logger from rouge import Rouge device = 'cuda' if torch.cuda.is_available() else 'cpu' # 获取当前操作系统的名称 os_name = platform.system() logger = get_logger(model_name='mengzi-t5-base') # 设置模型路径及数据集路径 if os_name == "Windows": model_dir = r'D:\python\models\langboat\meng_zi_t5' data_dir = r'D:\python\datas\nlp_seq2seq\nlpcc_2017' logger.info("当前执行环境是 Windows...") elif os_name == "Linux": model_dir = r'/root/autodl-fs/models/meng_zi_t5' data_dir = r'/root/autodl-fs/data/nlp_ai/nlp_seq2seq/nlpcc_2017' logger.info("当前执行环境是 Linux...") else: raise ValueError("当前执行环境不是 Windows 也不是 Linux") class Dataset(Dataset): def __init__(self, split, num=None): # 在线加载数据集(需外网环境) # dataset = load_dataset(path='nlpcc_2017', split=split) # 我们可以将数据保存到本地磁盘,下次利用load_from_disk直接从本地加载即可 # dataset.save_to_disk("./nlpcc_2017") # 划分数据集为:训练集和测试集 dataset = load_from_disk(dataset_path=data_dir) # 选取4900条训练集、100条测试集 split_dataset = dataset.train_test_split(100, seed=42) if num: # 离线加载数据集,cpu环境取少量数据用来训练、测试模型 dataset = split_dataset[split].select(range(num)) else: # 离线加载数据集 dataset = split_dataset[split] # 过滤掉太长的句子,需要去掉CLS、SEP def f(data): return len(data['content']) <= 512 - 2 dataset = dataset.filter(f) self.dataset = dataset def __len__(self): return len(self.dataset) def __getitem__(self, i): content = self.dataset[i]['content'] title = self.dataset[i]['title'] return content, title
def get_collate_fn(tokenizer):
def collate_fn(batch):
contents = ["摘要生成: \n" + tup2[0] for tup2 in batch]
original_labels = [tup2[1] for tup2 in batch]
# 特殊字符
# 0 -> <pad>
# 1 -> </s>
# 2 -> <unk>
inputs = tokenizer(contents, max_length=384, truncation=True, return_tensors='pt', padding=True)
labels = tokenizer(text_target=original_labels, max_length=64, truncation=True, return_tensors='pt', padding=True)
return inputs, labels
return collate_fn
利用transformers库中的T5ForConditionalGeneration加载摘要生成的预训练模型
T5ForConditionalGeneration源码中实现了KV-cache,有兴趣的可以阅读源码(主要是T5Attention中实现相对位置编码、KV-cache、以及门结构的前馈神经网络T5DenseGatedActDense的实现)。
T5模型中可以调用generate函数(transformers\generation\utils.py),这个函数中实现了8种采样的方法(如下代码所示),每种采样都有不同的配置参数,具体可以看transformers\generation\configuration_utils.py中GenerationConfig类的参数解释。
# transformers\generation\configuration_utils.py
class GenerationMode(ExplicitEnum):
"""
Possible generation modes, downstream of the [`~generation.GenerationMixin.generate`] method.
"""
# Non-beam methods
CONTRASTIVE_SEARCH = "contrastive_search"
GREEDY_SEARCH = "greedy_search"
SAMPLE = "sample"
ASSISTED_GENERATION = "assisted_generation"
# Beam methods
BEAM_SEARCH = "beam_search"
BEAM_SAMPLE = "beam_sample"
CONSTRAINED_BEAM_SEARCH = "constrained_beam_search"
GROUP_BEAM_SEARCH = "group_beam_search"
class MengZiT5Model(nn.Module): def __init__(self): super().__init__() # 加载预训练模型 self.model = T5ForConditionalGeneration.from_pretrained(model_dir) def forward(self, inputs, labels=None): # 1、encoder的input_ids和attention_mask input_ids = inputs['input_ids'] attention_mask = inputs['attention_mask'] if labels is not None: # 2、decoder 的labels train_labels = labels['input_ids'].contiguous() train_labels_mask = labels['attention_mask'] # 3、decoder 的input_ids和attention_mask decoder_input_ids = train_labels.new_zeros(train_labels.shape) decoder_input_ids[..., 1:] = train_labels[..., :-1].clone() decoder_attention_mask = train_labels_mask.new_zeros(train_labels_mask.shape) decoder_attention_mask[..., 1:] = train_labels_mask[..., :-1].clone() decoder_attention_mask[..., 0] = 1 # 4、送入模型进行预测 outputs = self.model(input_ids=input_ids , attention_mask=attention_mask , decoder_input_ids=decoder_input_ids , decoder_attention_mask=decoder_attention_mask , labels=train_labels) # 5、返回训练时候的Loss值 return outputs.loss else: # 模型生成 summary_ids = self.model.generate(input_ids , num_beams=4 # 束搜索法 , no_repeat_ngram_size=2 # 确保不重复 , min_length=10 # 长度限制 , max_length=64 , early_stopping=True ) # 将id转换为输出 summary_ids.shape = [bs, length] outputs = tokenizer.batch_decode(summary_ids, skip_special_tokens=True) return outputs
# 模型训练 def train(epochs, model, loader): model.to(device) lr = 2e-5 # 训练 optimizer = AdamW(model.parameters(), lr=lr) model.train() for epoch in range(epochs): for step, (inputs, labels) in enumerate(loader): inputs = inputs.to(device) labels = labels.to(device) # 模型计算 # [b, lens] -> [b, lens, 8] loss = model(inputs, labels) # 梯度下降 loss.backward() optimizer.step() optimizer.zero_grad() if step % 10 == 0: print(f'epoch = {epoch}, step = {step}, loss = {loss:.4f}') os.makedirs('./output', exist_ok=True) torch.save(model, './output/meng_zi_t5_sft.pt') # 模型评估 def test(): # 1、加载模型 model_load = torch.load('output/meng_zi_t5_sft.pt').to(device) model_load.eval() rouge = Rouge() # 2、加载测试集 test_loader = DataLoader(dataset=Dataset('test'), batch_size=32, collate_fn=get_collate_fn(tokenizer=tokenizer), shuffle=False, drop_last=True) for step, (inputs, labels) in enumerate(test_loader): if step == 2: break with torch.no_grad(): # [b, lens] -> [b, lens, 8] decode_preds = model_load(inputs.to(device)) decode_labels = tokenizer.batch_decode(labels['input_ids'].to(device), skip_special_tokens=True) decode_preds = [" ".join(p) for p in decode_preds] decode_labels = [" ".join(l) for l in decode_labels] scores = rouge.get_scores(decode_preds, decode_labels, avg=True) r = { "rouge-1": scores["rouge-1"]["f"], "rouge-2": scores["rouge-2"]["f"], "rouge-l": scores["rouge-l"]["f"], } logger.info(f'setp = {step}, 评估结果:\n{r}') return r if __name__ == '__main__': # 1、加载分词器 tokenizer = T5Tokenizer.from_pretrained(model_dir, legacy=False) # 2、加载训练数据 train_loader = DataLoader(dataset=Dataset('train'), batch_size=16, collate_fn=get_collate_fn(tokenizer=tokenizer), shuffle=True, drop_last=True) # 3、创建模型 model = MengZiT5Model() # 4、模型训练及评估 train(epochs=1, model=model, loader=train_loader) test() # 模型评估 # 5、对模型进行预测 text = """摘要生成: \n在经历了那段惊心动魄但又充满人情味的艰难时刻后,32岁的埃里克森时隔1100天再次为国征战欧洲杯,而且奉献了进球。 丹麦队对垒斯洛文尼亚,这场热度并不算高的小组赛首轮争夺因为一个人的出现得到了外界的关注,他就是埃里克森。 曼联中场在在第17分钟的进球帮助祖国球队取得了领先,他也在经历上届欧洲杯的心脏骤停的遭遇之后,实现了“王者归来”。 尽管这次破门遗憾没能帮助丹麦队最终获得胜利,但绰号“爱神”的埃里克森依然得到了全场乃至全世界球迷的祝福。 """ inputs = tokenizer(text, return_tensors='pt') model_load = torch.load('output/meng_zi_t5_sft.pt') model_load.eval() print('摘要内容:\n', model_load(inputs))
# 训练好的模型可以进行摘要生成
摘要内容:
['曼联32岁埃里克森时隔1100天再次为国征战欧洲杯,并奉献了进球。']
""" model: iic/nlp_mt5_zero-shot-augment_chinese-base link: https://modelscope.cn/models/iic/nlp_mt5_zero-shot-augment_chinese-base 该模型在mt5模型基础上使用了大量中文数据进行训练,并引入了零样本分类增强的技术,使模型输出稳定性大幅提升。 支持任务包含: 文本分类:给定一段文本和候选标签,模型可输出文本所属的标签。 自然语言推理:给定两段文本,判断两者关系。 阅读理解:给定问题和参考文本,输出问题的答案。 问题生成:给定答案和参考文本,生成该答案对应的问题。 摘要生成:给定一段文本,生成该文本的摘要。 标题生成:给定一段文本,为其生成标题。 评价对象抽取:给定一段文本,抽取该段文本的评价对象。 翻译:给定一段文本,将其翻译成另一种语言。 """ import torch import platform from transformers import T5Tokenizer, T5ForConditionalGeneration, T5Config # 获取当前操作系统的名称 os_name = platform.system() device = 'cuda:0' if torch.cuda.is_available() else 'cpu' # 设置模型路径及数据集路径 if os_name == "Windows": model_dir = r'D:\\python\\models\\model-download\\iic\\nlp_mt5_zero-shot-augment_chinese-base' print("当前执行环境是 Windows...") elif os_name == "Linux": model_dir = r'/root/autodl-fs/models/nlp_mt5_zero-shot-augment_chinese-base' print("当前执行环境是 Linux...") else: raise ValueError("当前执行环境不是 Windows 也不是 Linux") # 1、加载tokenizer及预训练模型 tokenizer = T5Tokenizer.from_pretrained(model_dir, legacy=False) model = T5ForConditionalGeneration.from_pretrained(model_dir) model.to(device) def t5inference(text, task_prefix, max_length=None, min_length=1): """ :param text: 要生成摘要的文本 :param task_prefix: 执行的任务 :param max_length: 摘要的最大长度 :return: """ # 准备前缀+文本 t5_prepared_text = f'{task_prefix}: ' + text print("input text: \n", t5_prepared_text) # 分词 tokenized_text = tokenizer.encode(t5_prepared_text, return_tensors="pt").to(device) # 进行文本摘要 # prepare_inputs_for_generation summary_ids = model.generate(tokenized_text, num_beams=4, # 束搜索法 no_repeat_ngram_size=2, # 确保不重复 min_length=min_length, # 长度限制 max_length=max_length, early_stopping=True # 提前停止 ) # 将id转换为输出 summary_ids.shape = [1, length] output = tokenizer.decode(summary_ids[0], skip_special_tokens=True) return output def t0(): text = """ “足球从未高于生死”,这是3年前欧洲杯赛场上丹麦球员埃里克森心脏骤停时,各路媒体报道该事件用的最多的表达。 而在经历了那段惊心动魄但又充满人情味的艰难时刻后,32岁的埃里克森时隔1100天再次为国征战欧洲杯,而且奉献了进球。 17日凌晨的欧洲杯小组赛,埃里克森进球的那一刻,感动和欣慰扑面而来。最终丹麦和斯洛文尼亚队1比1战平,各取1分。 丹麦队对垒斯洛文尼亚,这场热度并不算高的小组赛首轮争夺因为一个人的出现得到了外界的关注,他就是埃里克森。 曼联中场在在第17分钟的进球帮助祖国球队取得了领先,他也在经历上届欧洲杯的心脏骤停的遭遇之后,实现了“王者归来”。 尽管这次破门遗憾没能帮助丹麦队最终获得胜利,但绰号“爱神”的埃里克森依然得到了全场乃至全世界球迷的祝福。 """ output = t5inference(text, task_prefix='文本摘要', min_length=20, max_length=64) print('模型结果:\n', output) text = """ 候选标签:故事,房产,娱乐,文化,游戏,国际,股票,科技,军事,教育。 文本内容:他们的故事平静而闪光,一代人奠定沉默的基石,让中国走向繁荣。 """ output = t5inference(text, task_prefix='文本分类', max_length=64) print('模型结果:\n', output) text = """ 如果日本沉没,中国会接收日本难民吗? """ output = t5inference(text, task_prefix='翻译成英文', max_length=512) print('模型结果:\n', output) if __name__ == '__main__': # print(model.config) # print(model) t0()
input text: 文本摘要: “足球从未高于生死”,这是3年前欧洲杯赛场上丹麦球员埃里克森心脏骤停时,各路媒体报道该事件用的最多的表达。 而在经历了那段惊心动魄但又充满人情味的艰难时刻后,32岁的埃里克森时隔1100天再次为国征战欧洲杯,而且奉献了进球。 17日凌晨的欧洲杯小组赛,埃里克森进球的那一刻,感动和欣慰扑面而来。最终丹麦和斯洛文尼亚队1比1战平,各取1分。 丹麦队对垒斯洛文尼亚,这场热度并不算高的小组赛首轮争夺因为一个人的出现得到了外界的关注,他就是埃里克森。 曼联中场在在第17分钟的进球帮助祖国球队取得了领先,他也在经历上届欧洲杯的心脏骤停的遭遇之后,实现了“王者归来”。 尽管这次破门遗憾没能帮助丹麦队最终获得胜利,但绰号“爱神”的埃里克森依然得到了全场乃至全世界球迷的祝福。 模型结果: 埃里克森:足球从未高于生死,爱神归来,为国征战 input text: 文本分类: 候选标签:故事,房产,娱乐,文化,游戏,国际,股票,科技,军事,教育。 文本内容:他们的故事平静而闪光,一代人奠定沉默的基石,让中国走向繁荣。 模型结果: 文化 input text: 翻译成英文: 如果日本沉没,中国会接收日本难民吗? 模型结果: will China accept Japanese refugees if Japan sinks?
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。