#第9章/加载编码工具 from transformers import BertTokenizer token = BertTokenizer.from_pretrained('bert-base-chinese') #第9章/定义数据集 import torch from datasets import load_from_disk import random class Dataset(torch.utils.data.Dataset): def __init__(self, split): dataset = load_from_disk('./data/ChnSentiCorp')[split] def f(data): return len(data['text']) > 40 self.dataset = dataset.filter(f) def __len__(self): return len(self.dataset) def __getitem__(self, i): text = self.dataset[i]['text'] #切分一句话为前半句和后半句 sentence1 = text[:20] sentence2 = text[20:40] #随机整数,取值范围为0和1 label = random.randint(0, 1) #有一半的概率把后半句替换为一句无关的话 if label == 1: j = random.randint(0, len(self.dataset) - 1) sentence2 = self.dataset[j]['text'][20:40] return sentence1, sentence2, label dataset = Dataset('train') #第9章/定义计算设备 import torch device = 'cpu' if torch.cuda.is_available(): device = 'cuda' #第9章/数据整理函数 def collate_fn(data): sents = [i[:2] for i in data] labels = [i[2] for i in data] #编码 data = token.batch_encode_plus(batch_text_or_text_pairs=sents, truncation=True, padding='max_length', max_length=45, return_tensors='pt', return_length=True, add_special_tokens=True) #input_ids:编码之后的数字 #attention_mask:是补零的位置是0,其他位置是1 #token_type_ids:第一个句子和特殊符号的位置是0,第二个句子的位置是1 input_ids = data['input_ids'].to(device) attention_mask = data['attention_mask'].to(device) token_type_ids = data['token_type_ids'].to(device) labels = torch.LongTensor(labels).to(device) return input_ids, attention_mask, token_type_ids, labels #第9章/数据加载器 loader = torch.utils.data.DataLoader(dataset=dataset, batch_size=8, collate_fn=collate_fn, shuffle=True, drop_last=True) #第9章/加载预训练模型 from transformers import BertModel pretrained = BertModel.from_pretrained('bert-base-chinese') #第9章/不训练预训练模型,不需要计算梯度 for param in pretrained.parameters(): param.requires_grad_(False) #第9章/定义下游任务模型 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) #对抽取的特征只取第一个字的结果做分类即可 out = self.fc(out.last_hidden_state[:, 0]) out = out.softmax(dim=1) return out model = Model() #设定计算设备 model.to(device) #第9章/训练 from transformers import AdamW from transformers.optimization import get_scheduler def train(): #定义优化器 optimizer = AdamW(model.parameters(), lr=5e-5) #定义loss函数 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 % 20 == 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) train() #第9章/测试 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) pred = out.argmax(dim=1) #统计正确率 correct += (pred == labels).sum().item() total += len(labels) print(correct / total) test()
深度学习#第9章/加载编码工具
最新推荐文章于 2024-07-11 23:31:47 发布