深度学习与Pytorch入门实战(六)定义MLP&GPU加速&测试【数字识别实例】
-
Pytorch定义网络结构识别手写数字,可以对网络中的参数w和b进行手动定义的(参考上一节)
-
也可以直接用
nn.Linear
定义层的方式来定义 -
更加方便的方式是直接继承
nn.Module
来定义自己的网络结构。
1. nn.Linear方式
import torch
import torch.nn as nn
import torch.nn.functional as F
# 模拟 一张 28*28 的图片摊平
x = torch.randn(1, 784) #shape=[1,784]
# 定义三个全连接层
layer1 = nn.Linear(784, 200) # (in, out)
layer2 = nn.Linear(200, 200)
layer3 = nn.Linear(200, 10)
x = layer1(x) # shape=[1,200]
x = F.relu(x, inplace=True) # inplace=True在原对象基础上修改,可以节省内存
print(x.shape)
x = layer2(x) # shape=[1,200]
x = F.relu(x, inplace=True)
x = layer3(x) # shape=[1,10]
x = F.relu(x, inplace=True)
2. 继承nn.Module方式
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torchvision import datasets, transforms
#超参数
batch_size=200
learning_rate=0.01
epochs=10
#获取训练数据
train_loader = torch.utils.data.DataLoader(
datasets.MNIST('../data', train=True, download=True, #train=True则得到的是训练集
transform=transforms.Compose([ #transform进行数据预处理
transforms.ToTensor(), #转成Tensor类型的数据
transforms.Normalize((0.1307,), (0.3081,)) #进行数据标准化(减去均值除以方差)
])),
batch_size=batch_size, shuffle=True) #按batch_size分出一个batch维度在最前面,shuffle=True打乱顺序
#获取测试数据
test_loader = torch.utils.data.DataLoader(
datasets.MNIST('../data', train=False, transform=transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.1307,), (0.3081,))
])),
batch_size=batch_size, shuffle=True)
class MLP(nn.Module):
def __init__(self):
super(MLP, self).__init__()
# 定义网络的每一层,nn.ReLU可以换成其他激活函数,比如nn.LeakyReLU()
self.model = nn.Sequential(
nn.Linear(784, 200),
nn.ReLU(inplace=True),
nn.Linear(200, 200),
nn.ReLU(inplace=True),
nn.Linear(200, 10),
nn.ReLU(inplace=True),
)
def forward(self, x):
x = self.model(x)
return x
net = MLP()
# 定义sgd优化器,指明优化参数、学习率
# net.parameters()得到这个类所定义的网络的参数[[w1,b1,w2,b2,...]
optimizer = optim.SGD(net.parameters(), lr=learning_rate)
criteon = nn.CrossEntropyLoss()
for epoch in range(epochs):
for batch_idx, (data, target) in enumerate(train_loader):
data = data.view(-1, 28*28) # 将二维的图片数据摊平[样本数,784]
logits = net(data) # 前向传播
loss = criteon(logits, target) # nn.CrossEntropyLoss()自带Softmax
optimizer.zero_grad() # 梯度信息清空
loss.backward() # 反向传播获取梯度
optimizer.step() # 优化器更新
if batch_idx % 100 == 0: # 每100个batch输出一次信息
print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
epoch, batch_idx * len(data), len(train_loader.dataset),
100. * batch_idx / len(train_loader), loss.item()))
test_loss = 0
correct = 0 # correct记录正确分类的样本数
for data, target in test_loader:
data = data.view(-1, 28 * 28)
logits = net(data)
test_loss += criteon(logits, target).item() # 其实就是criteon(logits, target)的值,标量
pred = logits.data.max(dim=1)[1] # 也可以写成pred=logits.argmax(dim=1)
correct += pred.eq(target.data).sum()
test_loss /= len(test_loader.dataset)
print('\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format(
test_loss, correct, len(test_loader.dataset),
100. * correct / len(test_loader.dataset)))
view result
Train Epoch: 0 [0/60000 (0%)] Loss: 2.307840
Train Epoch: 0 [20000/60000 (33%)] Loss: 2.022810
Train Epoch: 0 [40000/60000 (67%)] Loss: 1.342542
Test set: Average loss: 0.0038, Accuracy: 8374/10000 (84%)
Train Epoch: 1 [0/60000 (0%)] Loss: 0.802759
Train Epoch: 1 [20000/60000 (33%)] Loss: 0.627895
Train Epoch: 1 [40000/60000 (67%)] Loss: 0.482087
Test set: Average loss: 0.0020, Accuracy: 8926/10000 (89%)
Train Epoch: 2 [0/60000 (0%)] Loss: 0.496279
Train Epoch: 2 [20000/60000 (33%)] Loss: 0.420009
Train Epoch: 2 [40000/60000 (67%)] Loss: 0.429296
Test set: Average loss: 0.0017, Accuracy: 9069/10000 (91%)
Train Epoch: 3 [0/60000 (0%)] Loss: 0.304612
Train Epoch: 3 [20000/60000 (33%)] Loss: 0.356296
Train Epoch: 3 [40000/60000 (67%)] Loss: 0.405541
Test set: Average loss: 0.0015, Accuracy: 9149/10000 (91%)
Train Epoch: 4 [0/60000 (0%)] Loss: 0.304062
Train Epoch: 4 [20000/60000 (33%)] Loss: 0.406027
Train Epoch: 4 [40000/60000 (67%)] Loss: 0.385962
Test set: Average loss: 0.0014, Accuracy: 9201/10000 (92%)
Train Epoch: 5 [0/60000 (0%)] Loss: 0.186269
Train Epoch: 5 [20000/60000 (33%)] Loss: 0.196249
Train Epoch: 5 [40000/60000 (67%)] Loss: 0.228671
Test set: Average loss: 0.0013, Accuracy: 9248/10000 (92%)
Train Epoch: 6 [0/60000 (0%)] Loss: 0.364886
Train Epoch: 6 [20000/60000 (33%)] Loss: 0.295816
Train Epoch: 6 [40000/60000 (67%)] Loss: 0.244240
Test set: Average loss: 0.0012, Accuracy: 9290/10000 (93%)
Train Epoch: 7 [0/60000 (0%)] Loss: 0.228807
Train Epoch: 7 [20000/60000 (33%)] Loss: 0.192547
Train Epoch: 7 [40000/60000 (67%)] Loss: 0.223399
Test set: Average loss: 0.0012, Accuracy: 9329/10000 (93%)
Train Epoch: 8 [0/60000 (0%)] Loss: 0.176273
Train Epoch: 8 [20000/60000 (33%)] Loss: 0.346954
Train Epoch: 8 [40000/60000 (67%)] Loss: 0.253838
Test set: Average loss: 0.0011, Accuracy: 9359/10000 (94%)
Train Epoch: 9 [0/60000 (0%)] Loss: 0.246411
Train Epoch: 9 [20000/60000 (33%)] Loss: 0.201452
Train Epoch: 9 [40000/60000 (67%)] Loss: 0.162228
Test set: Average loss: 0.0011, Accuracy: 9377/10000 (94%)
区别nn.ReLU()
和F.relu()
-
nn.ReLU()是类风格的API(大写开头,必须 先实例化再调用;参数w、b是内部成员,通过
.parameters
来访问) -
F.relu()是函数风格的API(自己管理)
import torch
import torch.nn as nn
import torch.nn.functional as F
x = torch.randn(1,10)
# 方法一
# F.relu: 直接调用函数 并传入参数
print(F.relu(x, inplace=True))
# tensor([[0.2846, 0.6158, 0.0000, 0.0000, 0.0000, 1.7980, 0.6466, 0.4263, 0.0000, 0.0000]])
# 方法二
# nn.Relu: 必须先实例化,如:创建layer,
layer = nn.ReLU(inplace=True)
print(layer(x))
# tensor([[0.2846, 0.6158, 0.0000, 0.0000, 0.0000, 1.7980, 0.6466, 0.4263, 0.0000, 0.0000]])
3. GPU加速
-
Pytorch中使用
torch.device()
选取并返回抽象出的设备 -
然后,在定义的网络模块 或者 Tensor后面加上
.to(device变量)
就可以将它们搬到设备上了。 -
.cuda()
默认用gpu,不推荐.
device = torch.device('cpu:0') #使用第一张显卡
net = MLP().to(device) # 定义的网络
criteon = nn.CrossEntropyLoss().to(device) # 损失函数
- 每次取出的训练集 和 验证集的 batch数据放到GPU上:
data, target = data.to(device), target.cuda() # 两种方式, .cuda()不推荐
- 应用上面的案例 添加GPU加速,完整代码:
view code
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torchvision import datasets, transforms
# 超参数
batch_size=200
learning_rate=0.01
epochs=10
# 获取训练数据
train_loader = torch.utils.data.DataLoader(
datasets.MNIST('../data', train=True, download=True, # train=True则得到的是训练集
transform=transforms.Compose([ # transform进行数据预处理
transforms.ToTensor(), # 转成Tensor类型的数据
transforms.Normalize((0.1307,), (0.3081,)) # 进行数据标准化(减去均值除以方差)
])),
batch_size=batch_size, shuffle=True) # 按batch_size分出一个batch维度在最前面,shuffle=True打乱顺序
#获取测试数据
test_loader = torch.utils.data.DataLoader(
datasets.MNIST('../data', train=False, transform=transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.1307,), (0.3081,))
])),
batch_size=batch_size, shuffle=True)
class MLP(nn.Module):
def __init__(self):
super(MLP, self).__init__()
self.model = nn.Sequential( # 定义网络的每一层,
nn.Linear(784, 200),
nn.ReLU(inplace=True),
nn.Linear(200, 200),
nn.ReLU(inplace=True),
nn.Linear(200, 10),
nn.ReLU(inplace=True),
)
def forward(self, x):
x = self.model(x)
return x
device = torch.device('cuda:0') # 使用第一张显卡
net = MLP().to(device)
# 定义sgd优化器,指明优化参数、学习率,net.parameters()得到这个类所定义的网络的参数[[w1,b1,w2,b2,...]
optimizer = optim.SGD(net.parameters(), lr=learning_rate)
criteon = nn.CrossEntropyLoss().to(device)
for epoch in range(epochs):
for batch_idx, (data, target) in enumerate(train_loader):
data = data.view(-1, 28*28) # 将二维的图片数据摊平[样本数,784]
data, target = data.to(device), target.cuda()
logits = net(data) # 前向传播
loss = criteon(logits, target) # nn.CrossEntropyLoss()自带Softmax
optimizer.zero_grad() # 梯度信息清空
loss.backward() # 反向传播获取梯度
optimizer.step() # 优化器更新
if batch_idx % 100 == 0: # 每100个batch输出一次信息
print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
epoch, batch_idx * len(data), len(train_loader.dataset),
100. * batch_idx / len(train_loader), loss.item()))
test_loss = 0
correct = 0 # correct记录正确分类的样本数
for data, target in test_loader:
data = data.view(-1, 28 * 28)
data, target = data.to(device), target.cuda()
logits = net(data)
test_loss += criteon(logits, target).item() # 其实就是criteon(logits, target)的值,标量
pred = logits.data.max(dim=1)[1] # 也可以写成pred=logits.argmax(dim=1)
correct += pred.eq(target.data).sum()
test_loss /= len(test_loader.dataset)
print('\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format(
test_loss, correct, len(test_loader.dataset),
100. * correct / len(test_loader.dataset)))
4. 多分类测试
-
下面的例子中logits是一个 4*10 的Tensor
-
可以理解成4张图片,每张图片有10维向量的预测
-
然后对每一张照片的输出值执行
softmax
和argmax(dim=1)
,得出预测标签,与真实标签比较,得出准确率。
-
import torch
import torch.nn.functional as F
logits = torch.rand(4, 10)
pred = F.softmax(logits, dim=1)
print(pred.shape) # torch.Size([4, 10])
pred_label = pred.argmax(dim=1) # 每行最大值的下标
print(pred_label)
# tensor([8, 0, 7, 2]) 和 logits.argmax(dim=1)结果一样
# 定义标签(真实值)
label = torch.tensor([5, 0, 2, 7])
# 与真实标签比较
correct = torch.eq(pred_label, label)
print(correct)
# tensor([False, True, False, False]) 和 pred_label.eq(label)结果一样
# 准确率
print(correct.sum().float().item() / len(logits)) # 0.25