☰
transform库-自动模型
2026/10/14 3:26:31 网站建设 项目流程

"""

案例:

通过自动模型的方式 完成 NLP常见的6个需求.

我们具体要讲解的6个NLP任务:

1. 文本分类 -> 情感分析

2. 特征抽取

3. 完形填空

4. 阅读理解

5. 文本摘要

6. NER命名实体识别

"""

import warnings

warnings.filterwarnings("ignore") # 忽略警告.

# 导包

import torch # Pytorch深度学习框架, 包括: 张量计算, 自动求导...

# AutoConfig: 自动配置模型参数.

# AutoModel: 自动加载模型 -> 通用的模型加载类.

# AutoTokenizer: 自动加载 (和模型匹配的) 分词器

from transformers import AutoConfig, AutoModel, AutoTokenizer

# AutoModelForSequenceClassification: 用于文本分类的模型.

# AutoModelForMaskedLM: 用于掩码语言建模的模型.

# AutoModelForQuestionAnswering: 用于阅读理解(问答)的模型.

from transformers import AutoModelForSequenceClassification, AutoModelForMaskedLM, AutoModelForQuestionAnswering

# AutoModelForSeq2SeqLM: 用于文本摘要的模型.

# AutoModelForTokenClassification: 用于命名实体识别(token级别分类)的模型.

from transformers import AutoModelForSeq2SeqLM, AutoModelForTokenClassification

from rich import print # 美化输出. 需要额外安装. 例如: pip install rich==15.0.0


# todo 1. 情感分类任务.

# 情绪分类 -> '今天开心极了...' 积极的情绪

# 商品分类 -> '手机壳' -> 数码配件, '连衣裙' -> 服饰

def dm01_text_classification():

# 1. 加载Tokenizer.

# my_tokenizer: 分词器对象, 把文本 -> 转换成 模型可接受的输入格式.

my_tokenizer = AutoTokenizer.from_pretrained(r'C:\Software\CentOS_All\PretrainedModel\chinese_sentiment')

# 2. 加载模型.

my_model = AutoModelForSequenceClassification.from_pretrained(r'C:\Software\CentOS_All\PretrainedModel\chinese_sentiment')

# 3. 文本转张量.

message = '人生该如何起头'

# 思路1: return_tensors = 'pt', 返回的是: 二维张量(tensor)

# 参1 text: 待编码的文本.

# 参2 return_tensors: 返回张量类型, 默认为None, 可选: pt / tf / np

# 参3 padding: 填充方式(是否填充)

# 参4 truncation: 截断方式(是否截断)

# 参5 max_length: (指定输入的)最大长度

msg_tensor1 = my_tokenizer.encode(text=message, return_tensors='pt', padding='max_length', truncation=True, max_length=5)

print(f'msg_tensor1: {msg_tensor1}') # msg_tensor1: tensor([[ 101, 782, 4495, 6421, 102]])

# 思路2: 不用return_tensors = 'pt', 返回的是: 1维列表, 需要手动转成张量.

msg_list2 = my_tokenizer.encode(text=message, padding='max_length', truncation=True, max_length=5)

# print(f'msg_list2: {msg_list2}') # [ 101, 782, 4495, 6421, 102]

# 手动把上述的列表转成 二维张量.

msg_tensor2 = torch.tensor([msg_list2])

# print(f'msg_tensor2: {msg_tensor2}') # tensor([[ 101, 782, 4495, 6421, 102]])

# 4. 将数据输入模型进行推理.

# 4.1 设置模型为: 推理模式(评估模式) -> 会关闭dropout等训练特有的层.

my_model.eval()

# 4.2 直接调用模型(模型推理)

# 结果格式: SequenceClassifierOutput(loss=None, logits=tensor([[-2.6553, -1.7053, 0.0367, 1.9910, 1.4494]], grad_fn=<AddmmBackward0>), hidden_states=None, attentions=None)

result = my_model(msg_tensor2)

print(f'result(包含模型输出的字典): {result}')

# 4.3 使用 return_dict=False 可以返回元组.

# 结果格式: (tensor([[-2.6553, -1.7053, 0.0367, 1.9910, 1.4494]], grad_fn=<AddmmBackward0>),)

result = my_model(msg_tensor2, return_dict=False)

print(f'result(包含模型输出的元组): {result}')

# 5. 上述获取的是 5个分类的概率, 我们需要获取 最大概率对应的索引.

# result_index = torch.argmax(result.logits) # 针对于字典(返回值写法)

result_index = torch.argmax(result[0]) # 针对于元组(返回值写法)

# 最终分类结果, 这里的3(索引)表示: 第4个分类.

print(f'result_index: {result_index}')

print(f'最终分类: star {result_index + 1}')


# todo 2. 特征抽取任务.

def dm02_feature_extraction():

# 1. 加载Tokenizer.

my_tokenizer = AutoTokenizer.from_pretrained(r'C:\Software\CentOS_All\PretrainedModel\bert-base-chinese')

# 2. 加载模型.

my_model = AutoModel.from_pretrained(r'C:\Software\CentOS_All\PretrainedModel\bert-base-chinese')

# 3. 文本转张量.

# 3.1 定义变量, 记录: 待处理的文本.

message = ['你是谁', '人生该如何起头']

# 3.2 把上述的文本 转成 模型可接受的输入张量.

# 返回值是字典形式, 其中各个键的意思是:

# input_ids: 文本的id序列 -> 对应模型的 vocab.txt 文件.

# token_type_ids: 文本的token序列.

# attention_mask: 注意力掩码, 1(真实), 0(填充)

msg_tensor = my_tokenizer.encode_plus(

text = message, # 待处理的文本.

return_tensors='pt', # 返回张量类型, 默认: None, 可选: pt / tf / np

padding='max_length', # 填充方式(是否填充)

truncation=True, # 截断方式(是否截断)

max_length=30, # (指定输入的)最大长度, 一会儿得到句子内容: [CLS] + 句子1 + [SEP] + 句子2 + [SEP] + 填充

)

# msg_tensor: {'input_ids': tensor([[101, 872, 102, 782, 102]]), 'token_type_ids': tensor([[0, 0, 0, 1, 1]]),

# 'attention_mask': tensor([[1, 1, 1, 1, 1]])}

print(f'msg_tensor: {msg_tensor}')

# 4. 给模型喂数据, 提取特征.

my_model.eval()

result = my_model(**msg_tensor)

# 5. 打印结果.

print(f'result: \n{result}')

# 最后1个(隐藏状态)层输出 -> [batch_size 批次大小, seq_len 序列长度, hidden_size 隐藏层的维度]

print(f'result.last_hidden_state: \n{result.last_hidden_state.shape}') # [1, 30, 768]

# 池化层输出 -> [batch_size 批次大小, hidden_size 隐藏层的维度]

print(f'result.pooler_output: \n{result.pooler_output.shape}') # [1, 768]


# todo 3. 完形填空任务.

def dm03_fill_mask():

# 1. 定义变量, 记录: 模型名.

model_name = r'C:\Software\CentOS_All\PretrainedModel\chinese-bert-wwm'

# 2. 加载Tokenizer.

my_tokenizer = AutoTokenizer.from_pretrained(model_name)

# 3. 加载模型.

my_model = AutoModelForMaskedLM.from_pretrained(model_name)

# 4. 文本转张量.

input = my_tokenizer.encode_plus(

text = '我想明天去[MASK]家吃饭', # 待处理的文本

return_tensors='pt', # 返回张量类型, 默认: None, 可选: pt / tf / np

)

# print(f'input: {input}')

# 5. 给模型喂数据.

my_model.eval()

output = my_model(**input)

# 6. 获取预测结果.

# print(f'output: {output}')

# print(f'output.logits: {output.logits.shape}') # [1, 11, 21128]

print(f'output.logits: {output.logits[0][6].shape}') # [21128]

# 7. 获取概率最高的预测结果 -> 即: [MASK]位置的.

mask_predict_idx = torch.argmax(output.logits[0][6]).item()

print(f'mask_predict_idx: {mask_predict_idx}') # 872

# 8. 打印概率最高的字 -> '你'

# print(f'概率最高的字: {my_tokenizer.convert_ids_to_tokens(mask_predict_idx)}') # 你, 接收1个索引.

print(f'概率最高的字: {my_tokenizer.convert_ids_to_tokens([mask_predict_idx])}') # 你, 接收1个索引列表


# todo 4. 阅读理解 -> 也叫:抽取式问答, 即输入一段文本和一个问题, 让模型输出结果.

def dm04_question_answering():

# 1. 定义变量, 记录: 模型名.

model_name = r'C:\Software\CentOS_All\PretrainedModel\chinese_pretrain_mrc_roberta_wwm_ext_large'

# 2. 加载Tokenizer.

my_tokenizer = AutoTokenizer.from_pretrained(model_name)

# 3. 加载模型.

my_model = AutoModelForQuestionAnswering.from_pretrained(model_name)

# 4. 准备文本, 细节: 上下文最好不要加空格, 会影响模型定位, 空格会被删除, 可以换成标点符号.

context = '我叫张三 我是一个程序员 我的喜好是打篮球'

questions = ['我是谁?', '我是做什么的?', '我的爱好是什么?']

# 5. 该模型是针对于每个问题进行问答推理的, 即: 逐个问题生成, 此处要用for循环.

for question in questions:

# 5.1 把上述的问题 转成 ids(模型可接受的输入张量)

# 参1: 当前的问题. 参2: 包含答案的上下文文本. 参3: 返回张量形式.

input = my_tokenizer.encode_plus(question, context, return_tensors='pt')

# input_ids: [CLS] + 问题 + [SEP] + 上下文 + [SEP] 细节: 空格不统计.

# token_type_ids: 0 -> 问题, 1 -> 上下文

# attention_mask: 1 -> 真实, 0 -> 填充

# print(f'input: {input}\n\n\n')

# 5.2 给模型喂数据, 获取结果.

my_model.eval()

output = my_model(**input)

# 5.3 获取结果.

print(f'output: {output}')

print(f'output: {output.start_logits.shape}') # 第1句话: [1, 26], 即: [CLS] + 问题 + [SEP] + 上下文 + [SEP] 第2句话:[1,29], 第3句话: [1, 30]

print(f'output: {output.end_logits.shape}') # 第1句话: [1, 26], 第2句话:[1,29], 第3句话: [1, 30]

# 5.4 计算模型预测的答案(开头的位置索引, 结束的位置索引.)

start, end = torch.argmax(output.start_logits), torch.argmax(output.end_logits) + 1

print(f'start: {start}, end: {end}') # 针对于第1个句子, 这里是: 8, 10

# 5.5 获取模型预测的答案.

answer = my_tokenizer.convert_ids_to_tokens(input.input_ids[0][start:end])

print(f'问题: {question}, 模型预测的答案: {answer}')

print('\n' * 2)


# todo 5. 文本摘要 -> 输入一段文本, 提取其重要信息.

def dm05_summarization():

# 1. 定义输入文本 -> 一段关于BERT模型预训练方法的英文介绍.

text = "BERT is a transformers model pretrained on a large corpus of English data " \

"in a self-supervised fashion. This means it was pretrained on the raw texts " \

"only, with no humans labelling them in any way (which is why it can use lots " \

"of publicly available data) with an automatic process to generate inputs and " \

"labels from those texts. More precisely, it was pretrained with two objectives:Masked " \

"language modeling (MLM): taking a sentence, the model randomly masks 15% of the " \

"words in the input then run the entire masked sentence through the model and has " \

"to predict the masked words. This is different from traditional recurrent neural " \

"networks (RNNs) that usually see the words one after the other, or from autoregressive " \

"models like GPT which internally mask the future tokens. It allows the model to learn " \

"a bidirectional representation of the sentence.Next sentence prediction (NSP): the models" \

" concatenates two masked sentences as inputs during pretraining. Sometimes they correspond to " \

"sentences that were next to each other in the original text, sometimes not. The model then " \

"has to predict if the two sentences were following each other or not."

# 2. 定义变量, 记录: 模型名.

model_name = r'C:\Software\CentOS_All\PretrainedModel\distilbart-cnn-12-6'

# 3. 加载分词器 和 模型.

my_tokenizer = AutoTokenizer.from_pretrained(model_name)

my_model = AutoModelForSeq2SeqLM.from_pretrained(model_name)

# 4. 将输入文本转成模型可接受的输入张量.

input = my_tokenizer(text, return_tensors='pt')

# print(f'input: {input}')

# 5. 把输入文本喂给模型, 获取预测结果.

my_model.eval()

output = my_model.generate(input['input_ids'])

print(f'output: {output}')

# 6. 打印预测结果, 即: 把摘要结果 -> 可读文本.

# 扩展: 如下的方式只能将ids还原为tokens, 如果感兴趣, 可以看一下BPE(Byte-Pair Encoding), 字节对编码(切词), GPT底层用的就是它进行切词的.

# print(my_tokenizer.convert_ids_to_tokens(output[0]))

# 可以用 decode() 解码实现.

# skip_special_tokens: 跳过特殊标记 -> 即: 去掉token前后的特殊字符, 例如: [CLS], [SEP]...

# clean_up_tokenization_spaces: 是否保留原始分词的空格.

print([my_tokenizer.decode(g, skip_special_tokens=True, clean_up_tokenization_spaces=True) for g in output])

print()

print([my_tokenizer.decode(g, skip_special_tokens=False, clean_up_tokenization_spaces=False) for g in output])


# todo 6. NER任务 -> 命名实体识别

def dm06_ner():

# 1. 定义变量, 记录: 模型名.

model_name = r'C:\Software\CentOS_All\PretrainedModel\roberta-base-finetuned-cluener2020-chinese'

# 2. 加载分词器, 模型, 配置文件.

my_tokenizer = AutoTokenizer.from_pretrained(model_name)

my_model = AutoModelForTokenClassification.from_pretrained(model_name)

config = AutoConfig.from_pretrained(model_name)

# 3. 数据张量化 -> 把输入文本 转成模型可接受的输入张量.

input = my_tokenizer.encode_plus('我爱北京天安门, 天安门上太阳升', return_tensors='pt')

print(f'input: {input}')

# 4. 把数据喂给模型, 获取结果.

my_model.eval()

logits = my_model(input.input_ids).logits

print(f'logits: {logits.shape}') # [1, 17, 32] -> [批次大小, 句子长度, 类别数量]

# 5. 处理预处理结果, 并显示.

# 5.1 把输入id 转回 token形式(用于可视化.

# ['[CLS]', '我', '爱', '北', '京', '天', '安', '门', ',', '天', '安', '门', '上', '太', '阳', '升', '[SEP]']

input_tokens = my_tokenizer.convert_ids_to_tokens(input.input_ids[0])

# 5.2 用zip()函数, 把 token 和 预测的标签概率分布 组合到一起.

# 定义变量, 记录结果.

outputs = [] # 格式为: [('我', 'O'), ('爱','O'), ('北京', 'LOC')...]

# 遍历: 每个token(17个) 和 预测的概率标签分布 (17, 32)

for token, value in zip(input_tokens, logits[0]): # logits[0]: [17, 32]

# 过滤掉特殊字符.

if token in my_tokenizer.all_special_tokens:

continue

# 走到这里, 说明不是特殊字符, 就获取: 32个标签的概率分布中, 最大概率标签的索引.

idx = torch.argmax(value).item()

print(f'token: {token}, idx: {idx}')

# 构建元组, 即: (token, 预测标签)

outputs.append((token, config.id2label[idx]))

# 6. 输出结果, 即: 格式为: [('我', 'O'), ('爱','O'), ('北京', 'LOC')...]

print(f'outputs: {outputs}')


# todo 7.测试代码

if __name__ == '__main__':

# 1. 测试: 情感分类(文本分类任务)

# dm01_text_classification()

# 2. 测试: 特征抽取(特征抽取任务)

# dm02_feature_extraction()

# 3. 测试: 完形填空(完形填空任务)

# dm03_fill_mask()

# 4. 测试: 阅读理解(阅读理解任务)

# dm04_question_answering()

# 5. 测试: 文本摘要(文本摘要任务)

# dm05_summarization()

# 6. 测试: NER(命名实体识别)

dm06_ner()

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询