模型就是获取设备,以方便后面的模型与变量进行内存迁移,设备名只有两种:'cuda'和'cpu'。通常是在你有GPU的情况下需要这样显式进行设备的设置,从而在需要时,你可以将变量从主存迁移到显存中。如果没有GPU,不获取也没事,pytorch会默认将参数都保存在主存中。
实现代码如下:
# 模型的层定义中,使用Sequential来统一管理的层集中表示为一层
import torch
import numpy as np
import matplotlib.pyplot as plt
# 引入nn与optim优化模块
from torch import nn,optim
from torchsummary import summary
from keras.datasets import import mnist
from keras.utils import to_categorical
# 自定义类,并引入nn.Module模块
class TorchModelTest(nn.Module):
def _init_(self,device):
super()._init__()
# Sequential管理所有层
self.layer1 = nn.Sequential(nn.Flatten(), nn.Linear(28*28, 512), nn.ReLU())
self.layer2 = nn.Sequential(nn.Linear(512, 512), nn.ReLU())
self.layer3 = nn.Sequential(nn.Linear(512, 512), nn.ReLU())
self.layer4 = nn.Sequential(nn.Linear(512, 10),nn.Softmax(dim=-1))
定义设备:
device = torch.device('cpu')
若是GPU版本的使用的语句则是:
device = torch.device('cuda')
和TensorFlow不同,pytorch需要在定义时就将需要梯度下降的参数传入,也就是其中的self.parameters(),表示当前模型的所有参数。不用担心定义优化器和模型参数的顺序问题,因为self.parameters()的输出并不是模型参数的实例,而是整个模型参数对象的指针,所以即使你在定义优化器之后又定义了一个层,它依然能优化到。当然优化器你也可以在外部定义,传入model.parameters()也可。这里定义了一个随机梯度下降。
self.opt = optim.SGD(self.parameters(),lr=0.01)
与tensorflow的call类似,定义的model就执行的就是此函数
def forward(self, inputs):
x = self.layer1(inputs)
x = self.layer2(x)
x = self.layer3(x)
x = self.layer4(x)
return x
想要获取的loss 函数集成在模型中,计算预测函数与真实标签之间的交叉熵
def get_loss(self, true_labels, predicts)
loss = -true_lables * torch.log(predicts)
loss = tprch.mean(loss)
在pytorch中,参数梯度集成在各自的对应的参数当中,使用tensor.grad来查看。每次对loss执行的backward(),pytorch都会将之前loss执行的可训练参数关于loss的梯度叠加进去。若不想进行叠加,则要删除 梯度,但待训练参数已经传入优化器,所以对优化器使用zero_gard(),将训练的梯度进行删除。梯度叠加在内存不足以计算整个梯度时,需要将其分成一部分一部分的来计算,每计算一部分得到的loss与backward()一次,从而得到整个批量的梯度。计算好后,在执行优化器的setp(),优化器根据可训练参数的梯度对其执行 一步的优化。
def train(self, imgs, labels):
predicts = model(imgs)
loss = self.get_loss(labels, predicts)
self.opt.zero_grad
loss.backward()
self.opt.step()
model = TorchModelTest(device)
summary(model, (1, 28, 28), 3,, device = 'cpu')
定义好的模型后,就要对其进行训练,pytorch自带的MNIST数据集并不好用,所以使用Keras自带的,定义一个获取数据的生成器。100次迭代后显示一次准确率。
def get_data(device, is_train = True, batch = 1024, num = 10000):
train_data,test_data = mnist.load_data()
if is_train:
imgs,labels = train_data
else:
imgs,labels = test_data
imgs = (imgs/255*2-1)[:, np.newaxis,...]
labels = to_categorical(labels,10)
imgs = torch.tensor(imgs, dtype=torch.float32).to(device)
labels = torch.tensor(labels,dtype=torch.float32).to(device)
i = 0
while(True):
i +=batch
if i > num:
i = batch
yield imgs[i - batch : i],labels[i - batch : i]
train_dg = get_data(device, True,batch=4096, num=60000)
test_dg = get_data(device, False,batch=5000, num=10000)
model = TorchModelTest(device)
summary(model, (1,28,28), 3,device='cpu')
ACCs = []
import time
start = time.time()
for j in range(20000):
# 训练
imgs, labels = next(train_dg)
model.train(imgs, labels)
# 验证
img, label = next(test_dg)
predicts = model(img)
acc = 1 - torch.count_nonzero(torch.argmax(predicts, axis=1) - torch.argmax(label, axis=1)) / label.shape[0]
if j % 50 == 0:
t = time.time() - start
start = time.time()
ACCs.append(acc.cpu().numpy())
print(j, t, 'ACC: ', acc)
# 绘图
x = np.linspace(0, len(ACCs), len(ACCs))
plt.plot(x, ACCs)