本次使用minist数据集学习多分类任务
minist数据集是多分类常用数据集,经常用作测试模型是否有效。数据集如下:
还得二分类任务时,分类目标是0,1,我们只需计算一种结果得概率就行,但是在多分类任务中,还采用传统方法就有些不合适了。这里我们得要求是使输出满足分布,即单个概率大于0,概率和为1。
softmax函数可以很好地解决这个问题,所以我们要引入softmax函数作为最后一层的激活函数。激活函数如下:
这里理解原理,在实际使用的时候,softmax被封装在了CrossEntropyLoss(交叉熵损失)这个函数中,我们只需注意网络的最后一层不加激活函数,并且在配置损失函数时调用即可。
本节要做图像的训练,所以还需要了解一点图像的处理步骤。
图像是由像素点组成的矩阵,每个像素点的值都不同。在最简单的黑白图像中,每个像素点的值是0-255,根据值的大小,像素点的颜色深度有所变化,由像素点构成的举证就构成了图像。
图像:
像素矩阵:
彩色图像的构成大同小异,是根据三颜色原理,由红绿蓝三张矩阵叠加在一起,可以看作一个三维矩阵,在本节不在详述。
所以我们处理图像时需要进行图像转换,才能交给网络进行学习。其中最简单的一种方法是将像素点拍成一行,看作一个一维矩阵,这里我们也采用了这种方法,但是这样有一个缺点,就是会丢失结构信息,并且由于像素点多,全连接网络的训练需要特别漫长的时间,所以才引入了cnn这一经典模型,这点我们后话再说。
首先,我们将图像矩阵转置,图像矩阵是[w, h, c],即宽,高,通道。我们需要将其转置为[c, w, h],将其变为张量,便于pytorch运算,同时对于神经网络而言,希望数值在-1——1之间,所以还要对图像进行标准化。
这些步骤说来麻烦,用起来也就两个函数,理解原理总是好的。
import torch
from torchvision import transforms
from torchvision import datasets
from torch.utils.data import DataLoader
import torch.nn.functional as F
import torch.optim as optim
batch_size = 64
transform = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.1307, ), (0.3081, ))
])
train_dataset = datasets.MNIST(root='data/MNIST/',
train=True,
download=True,
transform=transform)
train_loader = DataLoader(train_dataset,
shuffle=True,
batch_size=batch_size)
test_dataset = datasets.MNIST(root='data/MNIST/',
train=False,
download=True,
transform=transform)
test_loader = DataLoader(test_dataset,
shuffle=False,
batch_size=batch_size)
class Net(torch.nn.Module):
def __init__(self):
super(Net, self).__init__()
self.l1 = torch.nn.Linear(784, 512)
self.l2 = torch.nn.Linear(512, 256)
self.l3 = torch.nn.Linear(256, 128)
self.l4 = torch.nn.Linear(128, 64)
self.l5 = torch.nn.Linear(64, 10)
def forward(self, x):
x = x.view(-1, 784)
x = F.relu(self.l1(x))
x = F.relu(self.l2(x))
x = F.relu(self.l3(x))
x = F.relu(self.l4(x))
return self.l5(x)
model = Net()
criterion = torch.nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.5)
def train(epoch):
running_loss = 0.0
for batch_idx, data in enumerate(train_loader, 0):
inputs, target = data
optimizer.zero_grad()
# forward + backward + update
outputs = model(inputs)
loss = criterion(outputs, target)
loss.backward()
optimizer.step()
running_loss += loss.item()
if batch_idx % 300 == 299:
print('[%d, %5d] loss: %.3f' % (epoch + 1, batch_idx + 1, running_loss / 300))
running_loss = 0.0
def test():
correct = 0
total = 0
with torch.no_grad():
for data in test_loader:
images, labels = data
outputs = model(images)
_, predicted = torch.max(outputs.data, dim=1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
print('Accuracy on test set: %d %%' % (100 * correct / total))
if __name__ == '__main__':
for epoch in range(10):
train(epoch)
test()
输出:
[1, 300] loss: 2.209
[1, 600] loss: 0.844
[1, 900] loss: 0.395
Accuracy on test set: 89 %
[2, 300] loss: 0.308
[2, 600] loss: 0.263
[2, 900] loss: 0.234
Accuracy on test set: 93 %
[3, 300] loss: 0.189
[3, 600] loss: 0.174
[3, 900] loss: 0.154
Accuracy on test set: 95 %
[4, 300] loss: 0.133
[4, 600] loss: 0.128
[4, 900] loss: 0.121
Accuracy on test set: 96 %
[5, 300] loss: 0.104
[5, 600] loss: 0.098
[5, 900] loss: 0.093
Accuracy on test set: 96 %
[6, 300] loss: 0.080
[6, 600] loss: 0.078
[6, 900] loss: 0.073
Accuracy on test set: 96 %
[7, 300] loss: 0.063
[7, 600] loss: 0.062
[7, 900] loss: 0.061
Accuracy on test set: 97 %
[8, 300] loss: 0.049
[8, 600] loss: 0.049
[8, 900] loss: 0.051
Accuracy on test set: 97 %
[9, 300] loss: 0.040
[9, 600] loss: 0.037
[9, 900] loss: 0.043
Accuracy on test set: 97 %
[10, 300] loss: 0.031
[10, 600] loss: 0.031
[10, 900] loss: 0.035
Accuracy on test set: 97 %