数据集 数据集介绍 MNIST是一个手写数字的数据集,专门用于进行深度学习训练,属于是深度学习中的”Hello World”,已经算是经典中的经典。其中有60000个训练集和10000个测试集,每个数据包含了28×28的灰度图像和对应的标签0~9。
获取数据集 1 2 3 4 5 6 7 8 import torchvisionfrom torchvision import transformstrans = transforms.ToTensor() mnist_train = torchvision.datasets.MNIST(root='./' ,train=True ,transform=trans,download=False ) mnist_test = torchvision.datasets.MNIST(root='./' ,train=True ,transform=trans,download=False )
观察数据集 要建立神经网络,必须要了解数据集的格式或者说形状。
1 2 3 4 5 6 import matplotlib.pyplot as pltprint ('type:' ,type (mnist_train[1 ]))mnist_train[1 ][0 ].shape plt.imshow(mnist_train[1 ][0 ].reshape(28 ,-1 ,1 ),cmap='gray' ) plt.show() mnist_train[1 ][1 ]
1 2 3 4 type: <class 'tuple'> torch.Size([1, 28, 28]) <matplotlib.image.AxesImage object at 0x000002A41C7D7B80> 0
根据以上的输出结构,可以确定每个数据都是一个元组,由28×28的图像和整数标签组成。
加载数据 通常,我们会选择创建一个数据加载器,进行小批量数据训练。下面代码中batch_size就是批量大小,一般会设定为2的整数次方,这是为了充分利用GPU的并行计算能力,如果没有用GPU进行计算,那倒是无所谓。不过批量过小和学习率过高可能会导致最后的损失不收敛。
1 2 3 from torch.utils import datatrain_load = data.DataLoader(mnist_train,batch_size=64 ,shuffle=True ) test_load = data.DataLoader(mnist_test,batch_size=64 ,shuffle=True )
建立模型 神经网络类和实例化 一般会选择建立神经网络的类并实例化。这里选用卷积神经网络,因为图像识别领域一般用CNN比较快而且准确。输入内容是28×28的灰度图像,输出结果是一个十维向量(专业术语叫独热编码),每一维对应了图像是0~9的概率。 至于为什么要设定这么多层网络,网络中的参数为什么这么设定,只能说这是一种素养。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 import torchdef try_gpu (i=0 ): if torch.cuda.device_count() >= i + 1 : return torch.device(f'cuda:{i} ' ) return torch.device('cpu' ) device = try_gpu() import torch.nn as nnclass Net (nn.Module): def __init__ (self ): super ().__init__() self.conv1 = nn.Conv2d(in_channels=1 ,out_channels=6 ,kernel_size=5 ,padding=2 ) self.act1 = nn.ReLU() self.pool1 = nn.MaxPool2d(2 ) self.conv2 = nn.Conv2d(in_channels=6 ,out_channels=16 ,kernel_size=5 ,padding=0 ) self.act2 = nn.ReLU() self.pool2 = nn.MaxPool2d(2 ) self.conv3 = nn.Conv2d(in_channels=16 ,out_channels=120 ,kernel_size=5 ,padding=0 ) self.act3 = nn.ReLU() self.fc1 = nn.Linear(in_features=120 ,out_features=84 ) self.act4 = nn.ReLU() self.fc2 = nn.Linear(in_features=84 ,out_features=10 ) def forward (self,x ): out = self.pool1(self.act1(self.conv1(x))) out = self.pool2(self.act2(self.conv2(out))) out = self.act3(self.conv3(out)) out = out.view(-1 ,120 ) out = self.act4(self.fc1(out)) out = self.fc2(out) return out model = Net().to(device=device)
损失函数 对于多分类问题一般选择交叉熵损失函数。需要注意的是,在Pytorch中,神经网络的最后输出层不管有没有再进行一次softmax运算,最后用交叉熵损失函数算出来的结果都是一样的,好像是内部自带了。
1 loss_fn = nn.CrossEntropyLoss()
优化器 SGD是随机梯度下降法优化器,这种简单的问题用简单的优化器就可以。
1 2 import torch.optim as optimoptimizer = optim.SGD(model.parameters(),lr=0.1 )
模型的训练和评价 训练方法 训练过程一般是设定训练轮数,计算模型预测结果与真实标签的损失,用优化器对参数进行调整。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 num_epochs = 10 for epoch in range (1 ,1 +num_epochs): loss_train = 0.0 for X,y in train_load: X = X.to(device=device) y = y.to(device=device) y_hat = model(X) loss = loss_fn(y_hat,y) optimizer.zero_grad() loss.backward() optimizer.step() loss_train += loss.item() print ('epochs: ' ,epoch,' ' ,loss_train/len (train_load))
1 2 3 4 5 6 7 8 9 10 epochs: 1 0.08579787918389328 epochs: 2 0.059785575573163816 epochs: 3 0.04760235151487476 epochs: 4 0.03793407763548837 epochs: 5 0.03081712542800295 epochs: 6 0.026653120353041508 epochs: 7 0.022646719979969705 epochs: 8 0.019911968960397704 epochs: 9 0.017030523287513772 epochs: 10 0.015213624578597575
模型评价和保存模型 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 def accuracy (data_set,model ): correct = 0 total = 0 with torch.no_grad(): for imgs,labels in data_set: imgs = imgs.to(device=device) labels = labels.to(device=device) outputs = model(imgs) _,labels_pre = torch.max (outputs,dim=1 ) total += labels.shape[0 ] correct += int ((labels_pre == labels).sum ()) return correct/total print ('Train_Accuracy: ' ,accuracy(train_load,model))print ('Test_Accuracy: ' ,accuracy(test_load,model))torch.save(model.state_dict(),'./mnist.pth' )
1 2 Train_Accuracy: 0.9960666666666667 Test_Accuracy: 0.9960666666666667
可以看到最终不管是在训练集还是测试集上,准确率都是很高的。