赞
踩
在使用过keras和pytorch后发现确实各有各的优点,keras能够以极少的代码量快速搭建出一个神经网络,并且在各种功能上都进行了封装,可以说用keras就只需要关注调参就可以了,但缺点也是很明显的,就是不够灵活,这一点在使用了pytorch后更加有体会。而pytorch我个人认为是结合了tensorflow和keras的一些优点,比如在pytorch中也有像keras的Sequential模型,搭建网络也很方便,而且用pytorch搭建网络更加结构化,可以更加方便获取中间层的参数数据等等,因此pytorch也是十分得好用。
下面以RNN为例写一下pytorch搭建神经网络的一般套路。
import torch
import torch.nn as nn
import torch.optim as optim
import torch.nn.functional as F
from torch.utils.data import RandomSampler,DataLoader,TensorDataset,SequentialSampler
from tensorflow.keras.preprocessing.sequence import pad_sequences
from tensorflow.keras.datasets import imdb
这里以imdb文本情感分析为例
MAX_WORDS = 10000
MAX_LEN = 200
BATCH_SIZE = 256
EMB_SIZE = 300
HID_SIZE = 300 //rnn隐藏层数量
DROPOUT = 0.2
DEVICE = torch.device('cuda')
这里使用keras加载数据,因为pytorch本身不自带imdb。
(x_train,y_train),(x_test,y_test) = imdb.load_data(num_words=MAX_WORDS)
x_train = pad_sequences(x_train,maxlen=MAX_LEN,padding='post',truncating='post')
x_test = pad_sequences(x_test,maxlen=MAX_LEN,padding='post',truncating='post')
# 将数据转为tensorDataset
train_data = TensorDataset(torch.LongTensor(x_train),torch.LongTensor(y_train))
test_data = TensorDataset(torch.LongTensor(x_test),torch.LongTensor(y_test))
# 将数据放入dataloader
train_sampler = RandomSampler(train_data)
train_loader = DataLoader(train_data,sampler=train_sampler,batch_size=BATCH_SIZE)
test_sampler = SequentialSampler(test_data)
test_loader = DataLoader(test_data,sampler=test_sampler,batch_size=BATCH_SIZE)
pytorch不会自动转换类型,因此我们需要手动将numpy转为tensor数据才能为神经网络所用。DataLoader是将数据转换为可迭代的类型,后面训练时候会用到。
由于是文本,因此一般都需要词嵌入,即Embedding层处理,将以300位的向量代表每个单词,除了将embedding层放进主网络之外,也可以额外定义一个只包含Embedding层和Linear层的网络将数据处理成词向量的形式保存下来。
class Model(nn.Module): def __init__(self,max_words,emb_size,hid_size,dropout): super(Model,self).__init__() self.max_words = max_words self.emb_size = emb_size self.hid_size = hid_size self.dropout = dropout self.Embedding = nn.Embedding(self.max_words,self.emb_size) self.fc2 = nn.Linear(self.hid_size,2) self.RNN = nn.RNN(self.emb_size,self.hid_size,num_layers=1,batch_first=True) def forward(self,x): x = self.Embedding(x) # [bs,seq_len,emb_size] x,_ = self.RNN(x) # [bs,seq_len,hid_size,] #[bs,1,hid_size]将第二维转成1,再用squeeze()去掉维度为1的维[bs,hid_size] x = F.avg_pool2d(x,(x.shape[1],1)).squeeze() out = self.fc2(x) # [bs,2]与标签数据匹配(其实不能说完全匹配,后面说) return out
由于经过RNN处理后的数据维度是(batch_size,300,2),因此需要用F.avg_pool2d(x,(x.shape[1],1)).squeeze()
将第二维数据去掉才能和标签数据计算误差值。
由于标签维度是[64,],而训练后的预测维度是[64,2],在pytorch里面进行分类任务时候只有部分函数支持这种维度不匹配的误差计算的,而CrossEntropyLoss,因此这里要用这个。
而且可能你发现了在我们网络的最后没有用softmax层,这是因为nn.CrossEntropyLoss()中集成了softmax的功能,因此不需要额外定义softmax了(这里和keras有所不同)。
def train(model,device,train_loader,optimizer,epoch): model.train() # 将模型设置为训练模式 loss_func = nn.CrossEntropyLoss() for step,(x,y) in enumerate(train_loader): x,y = x.to(DEVICE),y.to(DEVICE) optimizer.zero_grad() y_ = model(x) loss = loss_func(y_,y) loss.backward() optimizer.step()#这一步一定要有,用于更新参数,之前由于漏写了括号导致参数没有更新,排BUG排了半天 if(step+1)%10==0: print('Train Epoch:{} [{}/{} ({:.0f}%)]\tLoss:{:.6f}'.format( epoch, step*len(x),len(train_loader.dataset), 100.*step/len(train_loader),loss.item() ))
def test(model,device,test_loader): model.eval() loss_func = nn.CrossEntropyLoss(reduction='sum') test_loss = 0.0 acc = 0 for step,(x,y) in enumerate(test_loader): x, y = x.to(DEVICE), y.to(DEVICE) with torch.no_grad(): y_ = model(x) test_loss += loss_func(y_,y) pred = y_.max(-1,keepdim=True)[1] acc += pred.eq(y.view_as(pred)).sum().item() test_loss /= len(test_loader.dataset) print('\nTest set:Average loss:{:.4f},Accuracy:{}/{} ({:.0f}%)'.format( test_loss,acc,len(test_loader.dataset), 100*acc/len(test_loader.dataset) )) return acc / len(test_loader.dataset)
model = Model(MAX_WORDS,EMB_SIZE,HID_SIZE,DROPOUT).to(DEVICE)
print(model)
optimizer = optim.Adam(model.parameters())
best_acc = 0.0
for epoch in range(1,11):
train(model,DEVICE,train_loader,optimizer,epoch)
acc = test(model,DEVICE,test_loader)
if best_acc < acc:
best_acc = acc
print("acc is:{:.4f},best acc is {:.4f}\n".format(acc,best_acc))
整个过程到此结束,总的来说pytorch确实没有keras容易上手,keras的简洁性真的爱了,但pytorch搭建网络的结构化也是挺香的。不过用pytorch经常会遇到内存溢出的问题,而在keras从来没遇到过,可能是底层优化pytorch没有keras好吧?也有可能是我自己写代码不规范而导致的,因此还需要继续学习才能用好这个框架。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。