赞
踩
这是个简单的分类任务,我会写出我使用的代码,按照我的习惯,我会添加很多注释,这些注释是我认为的精髓所在,最后我还会顺着数据的转变过程进行一次梳理,毕竟数据的变换就是整个模型的核心任务。
数据是很多评论的句子,要求输出评价是正面还是负面,所以是个二分类任务。
- #! pip install transformers datasets
- #from google.colab import drive
- #drive.mount('/content/drive')
- import torch
- from datasets import load_dataset
-
-
- #定义数据集
- class Dataset(torch.utils.data.Dataset):
- def __init__(self, split):
- self.dataset = load_dataset(path='seamew/ChnSentiCorp', split=split)#self.dataset是Dataset类
-
-
- def __len__(self):
- return len(self.dataset)
-
- def __getitem__(self, i):
- text = self.dataset[i]['text']
- #print(self.dataset[2])后是{'text': '房间太小。其他的都一般。。。。。。。。。', 'label': 0}是字典
- label = self.dataset[i]['label']#dataset[i]是字典列表
-
- return text, label
-
-
- dataset = Dataset('train')#dataset是Dataset类,好像是我定义的那个
-
- print(len(dataset), dataset[0])
-
- from transformers import BertTokenizer
-
- #加载字典和分词工具
- token = BertTokenizer.from_pretrained('bert-base-chinese')
-
- token
-

- def collate_fn(data):
- sents = [i[0] for i in data]
- labels = [i[1] for i in data]
- #print(len(data))后是16=batch_size
- #print(data)后是[('环境还不错,在西街头上,又有相当的一段距离与吵闹的西街隔离,非常安静. 但是: 1.不能上网,与四星水准不符; 2.同去旅伴抱怨房内有霉味', 1), ('其实我也是曾经在官网上追文看的一员,心急如焚地等待过。当
-
- #编码
- 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)
- #print(data)后data是字典里面的键分别包括'input_ids','attention_mask','token_type_ids','length'值是tensor
-
- #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)#转成长整形暂时不知道为何
- #print(input_ids.shape)是torch.Size([16, 500])
- #print(data['length'], data['length'].max())
-
- return input_ids, attention_mask, token_type_ids, labels
-
-
- #数据加载器
- 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(len(loader))
- input_ids.shape, attention_mask.shape, token_type_ids.shape, labels#前三个都是16*500的tensor,labels是1*16的tensor
-

- from transformers import BertModel
-
- #加载预训练模型
- pretrained = BertModel.from_pretrained('bert-base-chinese')
-
- #不训练,不需要计算梯度
- for param in pretrained.parameters():
- param.requires_grad_(False)
-
- #模型试算
- out = pretrained(input_ids=input_ids,
- attention_mask=attention_mask,
- token_type_ids=token_type_ids)
-
- out.last_hidden_state.shape#是torch.Size([16, 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)
- #print(out.last_hidden_state[:, 0].shape)是torch.Size([16, 768])
-
- out = self.fc(out.last_hidden_state[:, 0])
- #print(out.shape)是torch.Size([16, 2])
-
- out = out.softmax(dim=1)
-
- return out
-
-
- model = Model()
-
- model(input_ids=input_ids,
- attention_mask=attention_mask,
- token_type_ids=token_type_ids).shape#是torch.Size([16, 2])

- from transformers import AdamW
-
- #训练
- optimizer = AdamW(model.parameters(), lr=5e-4)
- criterion = torch.nn.CrossEntropyLoss()
-
- 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)
- #print(out.shape,labels.shape)是torch.Size([16, 2]) torch.Size([16])
-
- loss = criterion(out, labels)
- loss.backward()
- optimizer.step()
- optimizer.zero_grad()
-
- if i % 5 == 0:
- out = out.argmax(dim=1)
- accuracy = (out == labels).sum().item() / len(labels)
-
- print(i, loss.item(), accuracy)
-
- if i == 25:
- break

- #测试
- def test():
- model.eval()
- correct = 0
- total = 0
-
- loader_test = torch.utils.data.DataLoader(dataset=Dataset('validation'),
- batch_size=32,
- collate_fn=collate_fn,
- shuffle=True,
- drop_last=True)
-
- for i, (input_ids, attention_mask, token_type_ids,
- labels) in enumerate(loader_test):
-
- 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)
-
-
- test()

下面开始总结使用bert需要哪些步骤,以及数据的具体变化
最开始就是将数据从数据集中读出
self.dataset = load_dataset(path='seamew/ChnSentiCorp', split=split)#self.dataset是Dataset类
这个dataset是一个列表,里面是一个个字典,包含了所有数据
然后把这个dataset放入数据加载器中,分成批次,比如batch_szie=16,就是16个数据为一组
然后使用tokenizer分词编码形成一个字典
字典里面的键分别包括'input_ids','attention_mask','token_type_ids','length'值是tensor
print(input_ids.shape)是torch.Size([16, 500])
然后将三个torch.Size([16, 500])放入model中得到一个torch.Size([16, 500, 768])
16代表16句话,500是代表每句话分成500个词,不够的就padding补充,768就是一个词的向量
print(out.last_hidden_state[:, 0].shape)是torch.Size([16, 768])
print(out.shape)是torch.Size([16, 2])
在经过softmax后得到两种评价的概率,最后取最大就行了。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。