- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
本文通过ChnSentiCorp数据集介绍了文本分类任务过程,主要使用预训练语言模型bert-base-chinese直接在测试集上进行测试,也简要介绍了模型训练流程,不过最后没有保存训练好的模型. 一.任务和数据集介绍 1.任务 中文情感分类本质还是一个文本分类问题。 2.数据集 本文使用ChnSentiCorp情感分类数据集,每条数据中包括一句购物评价,以及一个标识,表明这条评价是一条好评还是一条差评。被评价的商品主要是书籍、酒店、计算机配件等。一些例子如下所示: 二.模型架构 基本思路是先特征抽取,然后进行下游任务。前者主要是RNN、LSTM、GRU、BERT、GPT、Transformers等模型,后者本质就是分类模型,比如全连接神经网络等. 三.实现代码 1.准备数据集 (1)使用编码工具 。 输出结果如下所示: 其中,vocab_size=21128表示bert-base-chinese模型的字典中有21128个词,特殊token主要是UNK、SEP、PAD、CLS、MASK。需要说明的是model_max_length,定义为 self.model_max_length = model_max_length if model_max_length is not None else VERY_LARGE_INTEGER 。因为从本地加载模型,不满足如下条件,所以给model_max_length赋了一个很大的数值,如下所示: 返回值token总的数据结构如下所示: 接下来测试编码工具如下所示: 输出结果如下所示: 其中,out数据结构如下所示: 因此, out['input_ids'][0] 表示第一个句子, token.decode(out['input_ids'][0]) 表示对第一个句子进行解码。 input_ids 、 token_type_ids 和 attention_mask 编码结果示意图如下所示: 说明:bert-base-chinese编码工具是以字为词,即把每个字都作为一个词进行处理。如果对 input_ids 、 token_type_ids 和 attention_mask 物理意义不清楚的,那么参考 使用编码工具 . (2)定义数据集 。 输出结果如下所示: (3)定义计算设备 通常做深度学习都会有个N卡,设置CUDA如下所示: (4)定义数据整理函数 主要对输入data进行batch_encode_plus(),然后返回input_ids、attention_mask、token_type_ids和labels: 结果输出如下所示: (5)定义数据集加载器 定义数据集加载器使用数据整理函数批量处理数据集中的数据如下所示: 2.定义模型 (1)加载预训练模型 。 输出结果如下所示: 其中,out是BaseModelOutputWithPoolingAndCrossAttentions对象,包括last_hidden_state和pooler_output两个字段。数据结构如下所示: (2)定义下游任务模型 该模型是权重为768×2的全连接神经网络,本质就是把768维向量转换为2维。计算过程就是通过模型提取特征矩阵(16×500×768),然后取第1个字[CLS]代表整个文本语义特征,用于下游分类任务等。如下所示: 3.训练和测试 (1)训练 。 (2)测试 。 在PyTorch中,model.train()和model.eval()是用于切换模型训练和评估模式的方法: 参考文献: [1]HuggingFace自然语言处理详解:基于BERT中文模型的任务实战 [2]https://huggingface.co/bert-base-chinese/tree/main 。
def load_encode_tool(pretrained_model_name_or_path):
# 加载编码工具bert-base-chinese
token = BertTokenizer.from_pretrained(Path(f
'{pretrained_model_name_or_path}'
))
# print(token)
return
token
if
__name__ ==
'__main__'
:
# 测试编码工具
pretrained_model_name_or_path = r
'L:\20230713_HuggingFaceModel\bert-base-chinese'
token = load_encode_tool(pretrained_model_name_or_path)
print
(token)
BertTokenizer(name_or_path=
'L:\20230713_HuggingFaceModel\bert-base-chinese'
, vocab_size=21128, model_max_length=1000000000000000019884624838656, is_fast=False, padding_side=
'right'
, truncation_side=
'right'
, special_tokens={
'unk_token'
:
'[UNK]'
,
'sep_token'
:
'[SEP]'
,
'pad_token'
:
'[PAD]'
,
'cls_token'
:
'[CLS]'
,
'mask_token'
:
'[MASK]'
}, clean_up_tokenization_spaces=True)
if
__name__ ==
'__main__'
:
# 测试编码工具
pretrained_model_name_or_path = r
'L:\20230713_HuggingFaceModel\bert-base-chinese'
token = load_encode_tool(pretrained_model_name_or_path)
out = token.batch_encode_plus(
batch_text_or_text_pairs=[
'从明天起,做一个幸福的人。'
,
'喂马,劈柴,周游世界。'
],
truncation=True,
# 是否截断
padding=
'max_length'
,
# 是否填充
max_length=17,
# 最大长度,如果不足,那么填充,如果超过,那么截断
return_tensors=
'pt'
,
# 返回的类型
return_length=True
# 返回长度
)
# 查看编码输出
for
key, value
in
out.items():
print
(key, value.shape)
# 把编码还原成文本
print
(token.decode(out[
'input_ids'
][0]))
input_ids torch.Size([2, 17])
[CLS] 从 明 天 起 , 做 一 个 幸 福 的 人 。 [SEP] [PAD] [PAD]
token_type_ids torch.Size([2, 17])
[CLS] 从 明 天 起 , 做 一 个 幸 福 的 人 。 [SEP] [PAD] [PAD]
length torch.Size([2])
[CLS] 从 明 天 起 , 做 一 个 幸 福 的 人 。 [SEP] [PAD] [PAD]
attention_mask torch.Size([2, 17])
[CLS] 从 明 天 起 , 做 一 个 幸 福 的 人 。 [SEP] [PAD] [PAD]
class Dataset(torch.utils.data.Dataset):
def __init__(self, split):
mode_name_or_path = r
'L:\20230713_HuggingFaceModel\ChnSentiCorp'
self.dataset = load_from_disk(mode_name_or_path)[split]
def __len__(self):
return
len(self.dataset)
def __getitem__(self, i):
text = self.dataset[i][
'text'
]
label = self.dataset[i][
'label'
]
return
text, label
if
__name__ ==
'__main__'
:
# 加载训练数据集
dataset = Dataset(
'train'
)
print
(len(dataset), dataset[20])
9600 (
'非常不错,服务很好,位于市中心区,交通方便,不过价格也高!'
, 1)
device =
'cpu'
if
torch.cuda.is_available():
device =
'cuda'
# 数据整理函数
def collate_fn(data):
sents = [i[0]
for
i
in
data]
labels = [i[1]
for
i
in
data]
# 编码
data = token.batch_encode_plus(batch_text_or_text_pairs=sents, truncation=True, padding=
'max_length'
, max_length=500, return_tensors=
'pt'
, return_length=True)
# input_ids:编码之后的数字
# attention_mask:补零的位置是0, 其他位置是1
input_ids = data[
'input_ids'
]
attention_mask = data[
'attention_mask'
]
token_type_ids = data[
'token_type_ids'
]
labels = torch.LongTensor(labels)
# 把数据移动到计算设备上
input_ids = input_ids.to(device)
attention_mask = attention_mask.to(device)
token_type_ids = token_type_ids.to(device)
labels = labels.to(device)
return
input_ids, attention_mask, token_type_ids, labels
if
__name__ ==
'__main__'
:
# 测试编码工具
pretrained_model_name_or_path = r
'L:\20230713_HuggingFaceModel\bert-base-chinese'
token = load_encode_tool(pretrained_model_name_or_path)
# 定义计算设备
device =
'cpu'
if
torch.cuda.is_available():
device =
'cuda'
# 测试数据整理函数
data = [
(
'你站在桥上看风景'
, 1),
(
'看风景的人在楼上看你'
, 0),
(
'明月装饰了你的窗子'
, 1),
(
'你装饰了别人的梦'
, 0),
]
input_ids, attention_mask, token_type_ids, labels = collate_fn(data)
print
(input_ids.shape, attention_mask.shape, token_type_ids.shape, labels)
torch.Size([4, 500]) torch.Size([4, 500]) torch.Size([4, 500]) tensor([1, 0, 1, 0], device=
'cuda:0'
)
loader = torch.utils.data.DataLoader(dataset=dataset, batch_size=16, collate_fn=collate_fn, shuffle=True, drop_last=True)
# 查看数据样例
for
i, (input_ids, attention_mask, token_type_ids, labels)
in
enumerate(loader):
break
print
(input_ids.shape, attention_mask.shape, token_type_ids.shape, labels)
pretrained_model_name_or_path = r
'L:\20230713_HuggingFaceModel\bert-base-chinese'
pretrained = BertModel.from_pretrained(Path(f
'{pretrained_model_name_or_path}'
))
# 不训练预训练模型,不需要计算梯度
for
param
in
pretrained.parameters():
param.requires_grad_(False)
pretrained.to(device)
out = pretrained(input_ids=input_ids, attention_mask=attention_mask, token_type_ids=token_type_ids)
print
(out.last_hidden_state.shape)
torch.Size([16, 500]) torch.Size([16, 500]) torch.Size([16, 500]) tensor([1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0], device=
'cuda:0'
)
#数据整理函数计算结果
torch.Size([16, 500, 768])
#16表示batch size,500表示句子包含词数,768表示向量维度
class Model(torch.nn.Module):
def __init__(self):
super().__init__()
self.fc = torch.nn.Linear(768, 2)
def forward(self, input_ids, attention_mask, token_type_ids):
# 使用预训练模型抽取数据特征
with torch.no_grad():
out = pretrained(input_ids=input_ids, attention_mask=attention_mask, token_type_ids=token_type_ids)
# 对抽取的特征只取第1个字的结果做分类即可
out = self.fc(out.last_hidden_state[:, 0])
out = out.softmax(dim=1)
return
out
def train():
# 定义优化器
optimizer = AdamW(model.parameters(), lr=5e-4)
# 定义1oss函数
criterion = torch.nn.CrossEntropyLoss()
# 定义学习率调节器
scheduler = get_scheduler(name=
'linear'
, num_warmup_steps=0, num_training_steps=len(loader), optimizer=optimizer)
# 将模型切换到训练模式
model.train()
# 按批次遍历训练集中的数据
for
i, (input_ids, attention_mask, token_type_ids, labels)
in
enumerate(loader):
# 模型计算
out = model(input_ids=input_ids, attention_mask=attention_mask, token_type_ids=token_type_ids)
# 计算loss并使用梯度下降法优化模型参数
loss = criterion(out, labels)
loss.backward()
optimizer.step()
scheduler.step()
optimizer.zero_grad()
# 输出各项数据的情况,便于观察
if
i % 10 == 0:
out = out.argmax(dim=1)
accuracy = (out == labels).sum().item() / len(labels)
lr = optimizer.state_dict()[
'param_groups'
][0][
'lr'
]
print
(i, loss.item(), lr, accuracy)
def
test
():
# 定义测试数据集加载器
loader_test = torch.utils.data.DataLoader(dataset=Dataset(
'test'
), batch_size=32, collate_fn=collate_fn, shuffle=True, drop_last=True)
# 将下游任务模型切换到运行模式
model.eval()
correct = 0
total = 0
# 按批次遍历测试集中的数据
for
i, (input_ids, attention_mask, token_type_ids, labels)
in
enumerate(loader_test):
# 计算5个批次即可,不需要全部遍历
if
i == 5:
break
print
(i)
# 计算
with torch.no_grad():
out = model(input_ids=input_ids, attention_mask=attention_mask, token_type_ids=token_type_ids)
# 统计正确率
out = out.argmax(dim=1)
correct += (out == labels).sum().item()
total += len(labels)
print
(correct / total)
最后此篇关于中文情感分类的文章就讲到这里了,如果你想了解更多关于中文情感分类的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我正在尝试使用 Pandas 和 scikit-learn 在 Python 中执行分类。我的数据集包含文本变量、数值变量和分类变量的混合。 假设我的数据集如下所示: Project Cost
我想要一种图形化且有吸引力的方式来表示二进制数据的列总和,而不是表格格式。我似乎无法让它发挥作用,尽管有人会认为这将是一次上篮。 数据看起来像这样(我尝试创建一个可重现的示例,但无法让代码填充 0 和
我有一个简单的类别模型: class Category(models.Model): name = models.CharField(max_length=200) slug = mo
我正在开发一个知识系统,当用户进入一道菜时,该系统可以返回酒。我的想法是根据用户的输入为每个葡萄酒类别添加分数,然后显示最适合的葡萄酒类别的前 3 个。例如,如果有人输入鱼,那么知识库中的所有红葡萄酒
我目前正在研究流失问题的预测模型。 每当我尝试运行以下模型时,都会收到此错误:至少一个类级别不是有效的 R 变量名称。这将在生成类概率时导致错误,因为变量名称将转换为 X0、X1。请使用可用作有效 R
如何对栅格重新分类(子集)r1 (与 r2 具有相同的尺寸和范围)基于 r2 中的以下条件在给定的示例中。 条件: 如果网格单元格值为 r2是 >0.5 ,保留>0.5中对应的值以及紧邻0.5个值的相
我想知道在 java 中进行以下分类的最佳方法是什么。例如,我们有一个简单的应用程序,其分类如下: 空气 -----电机类型 -----------平面对象 -----非电机型 -----------
这是一个非常基本的示例。但我正在做一些数据分析,并且不断发现自己编写非常类似的 SQL 计数查询来生成概率表。 我的表被定义为值 0 表示事件未发生,而值 1 表示事件确实发生。 > sqldf(
假设我有一组护照图像。我正在开展一个项目,我必须识别每本护照上的姓名,并最终将该对象转换为文本。 对于标签(或分类(我认为是初学者))的第一部分,每本护照上都有姓名,我该怎么做? 我可以使用哪些技术/
我有这张图片: 我想做的是在花和树之间对这张图片进行分类,这样我就可以找到图片中被树木覆盖的区域,以及被那些花覆盖的区域。 我在想这可能是某种 FFT 问题,但我不确定它是如何工作的。单个花的 FFT
我的数据集有 32 个分类变量和一个数值连续变量(sales_volume) 首先,我使用单热编码 (pd.get_dummies) 将分类变量转换为二进制,现在我有 1294 列,因为每一列都有多个
我正在尝试学习一些神经网络来获得乐趣。我决定尝试从 kaggle 的数据集中对一些神奇宝贝传奇卡进行分类。我阅读了文档并遵循了机器学习掌握指南,同时阅读了媒体以尝试理解该过程。 我的问题/疑问:我尝试
我目前正在进行推文情绪分析,并且有几个关于步骤的正确顺序的问题。请假设数据已经过相应的预处理和准备。所以这就是我将如何进行: 使用 train_test_split(80:20 比例)停止测试数据集。
一些上下文:Working with text classification and big sparse matrices in R 我一直在研究 text2vec 的文本多类分类问题。包装和 ca
数据 我有以下(简化的)数据集,我们称之为 df从现在开始: species rank value 1
我一直在尝试创建一个 RNN。我总共有一个包含 1661 个单独“条目”的数据集,每个条目中有 158 个时间序列坐标。 以下是一个条目的一小部分: 0.00000000e+00 1.9260968
我有一个关于机器学习的分类和回归问题。第一个问题,以下数据集 http://it.tinypic.com/view.php?pic=oh3gj7&s=8#.VIjhRDGG_lF 我们可以说,数据集是
我用1~200个数据作为训练数据,201~220个作为测试数据格式如下:3 个类(类 1、类 2、类 3)和 20 个特征 2 1:100 2:96 3:88 4:94 5:96 6:94 7:72
我有 2 个基于多个数字特征(例如 v1….v20)的输出类别(好和差)。 如果 v1、v2、v3 和 v4 为“高”,则该类别为“差”。如果 v1、v2、v3 和 v4 为“低”,则该类别为“好”
我遇到了使用朴素贝叶斯将文档分类为各种类别问题的问题。 实际上我想知道 P(C) 或我们最初掌握的类别的先验概率会随着时间的推移而不断变化。例如,对于类(class) - [音乐、体育、新闻] 初始概
我是一名优秀的程序员,十分优秀!