MNIST数据集
MNIST数据集是分类任务中最简单、最常用的数据集。人为的手写了0-9数字的图片
MNIST大概有7w张
torchvision是pytorch中处理视觉和图像的包
nn是神经网络相关包
步骤
Load data
Build model
Train
Test
加载数据
import torch from torch import nn from torch.nn import functional as F from torch import optim import torchvision from matplotlib import pyplot as plt from utils import plot_image,plot_curve,one_hot #utils库是自己写的 #plot_curve是画曲线 #plot_image是画图片 #one_hot编码工具 batch_size = 512 #一次处理的图片的数量 #gpu一次可以处理并行多张图片 #第一步,加载数据集 load dataset train_loader = torch.utils.data.DataLoader( torchvision.datasets.MNIST('dataset/', train=True, download=True, transform=torchvision.transforms.Compose([ torchvision.transforms.ToTensor(), torchvision.transforms.Normalize( (0.1307,), (0.3081,)) ])), batch_size=batch_size, shuffle=True) #train=True表示是训练数据,train=False是测试数据 #download=True的话,如果当前指定的文件夹中没有mnist数据集,就会自动去网上下载 #一般下载以后得到的文件是numpy格式,torchvision.transforms.ToTensor()将numpy转成tensor #torch中的数据载体都是tensor #Normalize做正则化,归一化,方便神经网络优化。也可以注释掉,性能会稍差一点,70%多,带着的话80%多 #shuffle=True表示在加载的时候将图片随机打散 test_loader = torch.utils.data.DataLoader( torchvision.datasets.MNIST('dataset/', train=False, download=True, transform=torchvision.transforms.Compose([ torchvision.transforms.ToTensor(), torchvision.transforms.Normalize( (0.1307,), (0.3081,)) ])), batch_size=batch_size, shuffle=False) #x是图片,y是label x, y = next(iter(train_loader)) print(x.shape, y.shape, x.min(), x.max()) plot_image(x, y, 'image sample')
在DataLoader中
train=True表示是训练数据,train=False是测试数据
download=True的话,如果当前指定的文件夹中没有mnist数据集,就会自动去网上下载
一般下载以后得到的文件是numpy格式,torchvision.transforms.ToTensor()将numpy转成tensor
torch中的数据载体都是tensor
Normalize做正则化,归一化,方便神经网络优化。也可以注释掉,性能会稍差一点,70%多,带着的话80%多
shuffle=True表示在加载的时候将图片随机打散
512张图片,1个通道,28行,28列
创建网络
训练
三层
训练就是每次求导,然后更新
批训练:把数据分为一小批一小批进行训练
Dataloader就是用来包装使用的数据,比如说该程序中把数据5个5个的打包,每一次抛出一组数据进行操作
import torch from torch import nn from torch.nn import functional as F from torch import optim import torchvision from matplotlib import pyplot as plt from utils import plot_image,plot_curve,one_hot #plot_curve是画曲线 #plot_image是画图片 #one_hot编码工具 batch_size = 512 #一次处理的图片的数量 #gpu一次可以处理并行多张图片 #第一步,加载数据集 load dataset train_loader = torch.utils.data.DataLoader( torchvision.datasets.MNIST('mnist_data', train=True, download=True, transform=torchvision.transforms.Compose([ torchvision.transforms.ToTensor(), torchvision.transforms.Normalize( (0.1307,), (0.3081,)) ])), batch_size=batch_size, shuffle=True) #train=True表示是训练数据,train=False是测试数据 #download=True的话,如果当前指定的文件夹中没有mnist数据集,就会自动去网上下载 #一般下载以后得到的文件是numpy格式,torchvision.transforms.ToTensor()将numpy转成tensor #torch中的数据载体都是tensor #Normalize做正则化,归一化,方便神经网络优化。也可以注释掉,性能会稍差一点,70%多,带着的话80%多 #shuffle=True表示在加载的时候将图片随机打散 test_loader = torch.utils.data.DataLoader( torchvision.datasets.MNIST('mnist_data/', train=False, download=True, transform=torchvision.transforms.Compose([ torchvision.transforms.ToTensor(), torchvision.transforms.Normalize( (0.1307,), (0.3081,)) ])), batch_size=batch_size, shuffle=False) x, y = next(iter(train_loader)) print(x.shape, y.shape, x.min(), x.max()) plot_image(x, y, 'image sample') class Net(nn.Module): def __init__(self): super(Net, self).__init__() # xw+b self.fc1 = nn.Linear(28*28, 256) self.fc2 = nn.Linear(256, 64) self.fc3 = nn.Linear(64, 10) def forward(self, x): # x: [b, 1, 28, 28] # h1 = relu(xw1+b1) x = F.relu(self.fc1(x)) # h2 = relu(h1w2+b2) x = F.relu(self.fc2(x)) # h3 = h2w3+b3 x = self.fc3(x) return x net = Net() #创建网络对象 #打印模型的参数直观地看一下 #k,v就分别是w和b for k, v in net.named_parameters(): print(k,v) # [w1, b1, w2, b2, w3, b3] optimizer = optim.SGD(net.parameters(), lr=0.01, momentum=0.9) for epoch in range(3): for batch_idx, (x, y) in enumerate(train_loader): # x: [b, 1, 28, 28], y: [512] # [b, 1, 28, 28] => [b, 784] x = x.view(x.size(0), 28*28) #x.size(0)就是batch_size # => [b, 10] out = net(x) #我们的目的是希望我们的output能够更好得接近我们y的label # [b, 10] y_onehot = one_hot(y) #就是将y转成onehot #y是512个label值,是一个512*1的tensor数组 #y_onehot是512个10维的,即512*10的tensor数组 #例如y的label是2,那么对应的y_onehot就是0,1,2,第三个位置为1,其余位置为0这样 # loss = mse(out, y_onehot) loss = F.mse_loss(out, y_onehot) #计算均方差 optimizer.zero_grad() #清零梯度 loss.backward() #计算梯度 # w' = w - lr*grad optimizer.step() #更新梯度 train_loss.append(loss.item()) if batch_idx % 10==0: #每隔10个batch打印一下 print(epoch, batch_idx, loss.item())
可以看到loss是在稳定下降的
加上一句绘制图形的代码
import torch from torch import nn from torch.nn import functional as F from torch import optim import torchvision from matplotlib import pyplot as plt from utils import plot_image,plot_curve,one_hot #plot_curve是画曲线 #plot_image是画图片 #one_hot编码工具 batch_size = 512 #一次处理的图片的数量 #gpu一次可以处理并行多张图片 #第一步,加载数据集 load dataset train_loader = torch.utils.data.DataLoader( torchvision.datasets.MNIST('mnist_data', train=True, download=True, transform=torchvision.transforms.Compose([ torchvision.transforms.ToTensor(), torchvision.transforms.Normalize( (0.1307,), (0.3081,)) ])), batch_size=batch_size, shuffle=True) #train=True表示是训练数据,train=False是测试数据 #download=True的话,如果当前指定的文件夹中没有mnist数据集,就会自动去网上下载 #一般下载以后得到的文件是numpy格式,torchvision.transforms.ToTensor()将numpy转成tensor #torch中的数据载体都是tensor #Normalize做正则化,归一化,方便神经网络优化。也可以注释掉,性能会稍差一点,70%多,带着的话80%多 #shuffle=True表示在加载的时候将图片随机打散 test_loader = torch.utils.data.DataLoader( torchvision.datasets.MNIST('mnist_data/', train=False, download=True, transform=torchvision.transforms.Compose([ torchvision.transforms.ToTensor(), torchvision.transforms.Normalize( (0.1307,), (0.3081,)) ])), batch_size=batch_size, shuffle=False) x, y = next(iter(train_loader)) print(x.shape, y.shape, x.min(), x.max()) plot_image(x, y, 'image sample') class Net(nn.Module): def __init__(self): super(Net, self).__init__() # xw+b self.fc1 = nn.Linear(28*28, 256) self.fc2 = nn.Linear(256, 64) self.fc3 = nn.Linear(64, 10) def forward(self, x): # x: [b, 1, 28, 28] # h1 = relu(xw1+b1) x = F.relu(self.fc1(x)) # h2 = relu(h1w2+b2) x = F.relu(self.fc2(x)) # h3 = h2w3+b3 x = self.fc3(x) return x net = Net() #创建网络对象 # [w1, b1, w2, b2, w3, b3] optimizer = optim.SGD(net.parameters(), lr=0.01, momentum=0.9) train_loss = [] for epoch in range(3): for batch_idx, (x, y) in enumerate(train_loader): # x: [b, 1, 28, 28], y: [512] # [b, 1, 28, 28] => [b, 784] x = x.view(x.size(0), 28*28) # => [b, 10] out = net(x) #我们的目的是希望我们的output能够更好得接近我们y的label # [b, 10] y_onehot = one_hot(y) # loss = mse(out, y_onehot) loss = F.mse_loss(out, y_onehot) #计算均方差 optimizer.zero_grad() #清零梯度 loss.backward() #计算梯度 # w' = w - lr*grad optimizer.step() #更新梯度 train_loss.append(loss.item()) if batch_idx % 10==0: #每隔10个batch打印一下 print(epoch, batch_idx, loss.item()) plot_curve(train_loss)
测试
import torch from torch import nn from torch.nn import functional as F from torch import optim import torchvision from matplotlib import pyplot as plt from utils import plot_image,plot_curve,one_hot #plot_curve是画曲线 #plot_image是画图片 #one_hot编码工具 batch_size = 512 #一次处理的图片的数量 #gpu一次可以处理并行多张图片 #第一步,加载数据集 load dataset train_loader = torch.utils.data.DataLoader( torchvision.datasets.MNIST('mnist_data', train=True, download=True, transform=torchvision.transforms.Compose([ torchvision.transforms.ToTensor(), torchvision.transforms.Normalize( (0.1307,), (0.3081,)) ])), batch_size=batch_size, shuffle=True) #train=True表示是训练数据,train=False是测试数据 #download=True的话,如果当前指定的文件夹中没有mnist数据集,就会自动去网上下载 #一般下载以后得到的文件是numpy格式,torchvision.transforms.ToTensor()将numpy转成tensor #torch中的数据载体都是tensor #Normalize做正则化,归一化,方便神经网络优化。也可以注释掉,性能会稍差一点,70%多,带着的话80%多 #shuffle=True表示在加载的时候将图片随机打散 test_loader = torch.utils.data.DataLoader( torchvision.datasets.MNIST('mnist_data/', train=False, download=True, transform=torchvision.transforms.Compose([ torchvision.transforms.ToTensor(), torchvision.transforms.Normalize( (0.1307,), (0.3081,)) ])), batch_size=batch_size, shuffle=False) x, y = next(iter(train_loader)) print(x.shape, y.shape, x.min(), x.max()) plot_image(x, y, 'image sample') class Net(nn.Module): def __init__(self): super(Net, self).__init__() # xw+b self.fc1 = nn.Linear(28*28, 256) self.fc2 = nn.Linear(256, 64) self.fc3 = nn.Linear(64, 10) def forward(self, x): # x: [b, 1, 28, 28] # h1 = relu(xw1+b1) x = F.relu(self.fc1(x)) # h2 = relu(h1w2+b2) x = F.relu(self.fc2(x)) # h3 = h2w3+b3 x = self.fc3(x) return x net = Net() #创建网络对象 # [w1, b1, w2, b2, w3, b3] optimizer = optim.SGD(net.parameters(), lr=0.01, momentum=0.9) train_loss = [] for epoch in range(3): for batch_idx, (x, y) in enumerate(train_loader): # x: [b, 1, 28, 28], y: [512] # [b, 1, 28, 28] => [b, 784] x = x.view(x.size(0), 28*28) # => [b, 10] out = net(x) #我们的目的是希望我们的output能够更好得接近我们y的label # [b, 10] y_onehot = one_hot(y) # loss = mse(out, y_onehot) loss = F.mse_loss(out, y_onehot) #计算均方差 optimizer.zero_grad() #清零梯度 loss.backward() #计算梯度 # w' = w - lr*grad optimizer.step() #更新梯度 train_loss.append(loss.item()) if batch_idx % 10==0: #每隔10个batch打印一下 print(epoch, batch_idx, loss.item()) plot_curve(train_loss) # we get optimal [w1, b1, w2, b2, w3, b3] total_correct = 0 for x,y in test_loader: x = x.view(x.size(0), 28*28) out = net(x) #网络的输出 # out: [b, 10] => pred: [b] pred = out.argmax(dim=1) correct = pred.eq(y).sum().float().item() #当前batch预测正确的数量 total_correct += correct total_num = len(test_loader.dataset) acc = total_correct / total_num print('test accurancy:', acc)
总体的准确度是88%
在这里还不够直观,因为我们希望拿到每一个具体图片的预测结果,看一下到底是不是真的预测对了
import torch from torch import nn from torch.nn import functional as F from torch import optim import torchvision from matplotlib import pyplot as plt from utils import plot_image,plot_curve,one_hot #plot_curve是画曲线 #plot_image是画图片 #one_hot编码工具 batch_size = 512 #一次处理的图片的数量 #gpu一次可以处理并行多张图片 #第一步,加载数据集 load dataset train_loader = torch.utils.data.DataLoader( torchvision.datasets.MNIST('mnist_data', train=True, download=True, transform=torchvision.transforms.Compose([ torchvision.transforms.ToTensor(), torchvision.transforms.Normalize( (0.1307,), (0.3081,)) ])), batch_size=batch_size, shuffle=True) #train=True表示是训练数据,train=False是测试数据 #download=True的话,如果当前指定的文件夹中没有mnist数据集,就会自动去网上下载 #一般下载以后得到的文件是numpy格式,torchvision.transforms.ToTensor()将numpy转成tensor #torch中的数据载体都是tensor #Normalize做正则化,归一化,方便神经网络优化。也可以注释掉,性能会稍差一点,70%多,带着的话80%多 #shuffle=True表示在加载的时候将图片随机打散 test_loader = torch.utils.data.DataLoader( torchvision.datasets.MNIST('mnist_data/', train=False, download=True, transform=torchvision.transforms.Compose([ torchvision.transforms.ToTensor(), torchvision.transforms.Normalize( (0.1307,), (0.3081,)) ])), batch_size=batch_size, shuffle=False) x, y = next(iter(train_loader)) print(x.shape, y.shape, x.min(), x.max()) plot_image(x, y, 'image sample') class Net(nn.Module): def __init__(self): super(Net, self).__init__() # xw+b self.fc1 = nn.Linear(28*28, 256) self.fc2 = nn.Linear(256, 64) self.fc3 = nn.Linear(64, 10) def forward(self, x): # x: [b, 1, 28, 28] # h1 = relu(xw1+b1) x = F.relu(self.fc1(x)) # h2 = relu(h1w2+b2) x = F.relu(self.fc2(x)) # h3 = h2w3+b3 x = self.fc3(x) return x net = Net() #创建网络对象 # [w1, b1, w2, b2, w3, b3] optimizer = optim.SGD(net.parameters(), lr=0.01, momentum=0.9) train_loss = [] for epoch in range(3): for batch_idx, (x, y) in enumerate(train_loader): # x: [b, 1, 28, 28], y: [512] # [b, 1, 28, 28] => [b, 784] x = x.view(x.size(0), 28*28) # => [b, 10] out = net(x) #我们的目的是希望我们的output能够更好得接近我们y的label # [b, 10] y_onehot = one_hot(y) # loss = mse(out, y_onehot) loss = F.mse_loss(out, y_onehot) #计算均方差 optimizer.zero_grad() #清零梯度 loss.backward() #计算梯度 # w' = w - lr*grad optimizer.step() #更新梯度 train_loss.append(loss.item()) if batch_idx % 10==0: #每隔10个batch打印一下 print(epoch, batch_idx, loss.item()) plot_curve(train_loss) # we get optimal [w1, b1, w2, b2, w3, b3] total_correct = 0 for x,y in test_loader: x = x.view(x.size(0), 28*28) out = net(x) #网络的输出 # out: [b, 10] => pred: [b] pred = out.argmax(dim=1) correct = pred.eq(y).sum().float().item() #当前batch预测正确的数量 total_correct += correct total_num = len(test_loader.dataset) acc = total_correct / total_num print('test accurancy:', acc) x, y = next(iter(test_loader)) out = net(x.view(x.size(0), 28*28)) pred = out.argmax(dim=1) #得到预测值 plot_image(x, pred, 'test')
这里我们拿到的就是test的图片,上面的文字是我们训练了三遍的神经网络预测的结果
全预测对了
utils.py
import torch from matplotlib import pyplot as plt def plot_curve(data): fig = plt.figure() plt.plot(range(len(data)), data, color='blue') plt.legend(['value'], loc='upper right') plt.xlabel('step') plt.ylabel('value') plt.show() def plot_image(img, label, name): fig = plt.figure() for i in range(6): plt.subplot(2, 3, i + 1) plt.tight_layout() plt.imshow(img[i][0]*0.3081+0.1307, cmap='gray', interpolation='none') plt.title("{}: {}".format(name, label[i].item())) plt.xticks([]) plt.yticks([]) plt.show() def one_hot(label, depth=10): out = torch.zeros(label.size(0), depth) idx = torch.LongTensor(label).view(-1, 1) out.scatter_(dim=1, index=idx, value=1) return out