赞
踩
第1步,导入相关的python包,并且下载训练集,其中训练集可以提前下载放到相应的目录下面。如果真的通过下面代码进行,将会相当耗时。
- from torchvision import datasets, transforms
- import torch
- import torch.nn as nn
- import torch.nn.functional as F
- import torch.optim as optim
-
-
- train_set = datasets.FashionMNIST('D:\\temp\\fashion_mnist',
- train=True,
- download=True,
- transform=transforms.Compose([
- transforms.ToTensor()
- ])
- )
当加载完图片数据,我们可以查看其中一张图片以验证加载是否正确。
- import matplotlib.pyplot as plt
- sample = next(iter(train_set))
- plt.imshow(sample[0].squeeze())
- plt.show()
sample的shape大小为[1,28,28],而imshow显示则只能有[heigth, width]信息,所以通过squeeze()方法减小一个大小为1的轴。运行后显示如下:
第2步,以同样的方式,再加载测试集的数据。
- test_set = datasets.FashionMNIST('D:\\temp\\fashion_mnist',
- train=False,
- download=True,
- transform=transforms.Compose([
- transforms.ToTensor()
- ])
- )
-
- print('train_set size:', len(train_set), ' ,test_test size:', len(test_set))
打印训练集和测试集的数据,我们可以看到训练集有6万张图片,而测试集有1万张图片。
第3步,将训练集和测试集数据加载到loader中。loader可以提供批量加载、图片预处理,shuffle数据等功能。我们设定每一批的大小为100张,因为总共有6万张图片,所以总共有60000/100=60个批次。
- train_loader = torch.utils.data.DataLoader(train_set, batch_size=100)
- test_loader = torch.utils.data.DataLoader(test_set, batch_size=100)
-
- batch = next(iter(train_loader))
- images, labels = batch
- print(images.shape)
查看每一批图片的shape为[100, 1, 28, 28],分别对应[batch_size, channel_size, height, weight]的信息。
最简单的数据加载流程到此为止,下面我们将设计神经网络进行训练,并测试分类的效果。
第4步,设计全连接的网络结构
- class FCNetwork(nn.Module):
- def __init__(self):
- super(FCNetwork, self).__init__()
- self.fc1 = nn.Linear(784, 200)
- self.fc2 = nn.Linear(200, 50)
- self.fc3 = nn.Linear(50, 10)
-
- def forward(self, x):
- x = F.relu(self.fc1(x))
- x = F.relu(self.fc2(x))
- x = self.fc3(x)
- return x
-
- def predict(self, x):
- logits = self.forward(x)
- return F.softmax(logits, dim=1)

以上是一个相对比较简单的全连接网络结构。
(1)nn.Linear要求输入的数据必须是二维的,需要将输入图像(28*28)展平后得到784列数据,输出为200列的数据,通过nn.Linear实现了两个不同维度(假如batch信息,比如之前是[100,784]的shape,后面是[100,200]的shape)的欧几里得空间数据的映射。
(2)因为fashion-mnist的分类结果是10个,所以最后一层需要输出10列的数据,每一列上的数据代表该分类的预测值。
(3)在预测环节,将测试值通过F.softmax()函数转化为概率值,此时10个分类的概率值之和为1.0
第5步,使用全连接网络训练模型,并且在测试集上验证模型的准确性。
- fcNetwork = FCNetwork()
- criterion = nn.CrossEntropyLoss()
- optimizer = optim.Adam(fcNetwork.parameters(), lr=0.01)
-
- epochs = 5
- steps = 0
- running_loss = 0
- print_every = 60
-
- for epoch in range(epochs):
- for images, labels in iter(train_loader):
- steps += 1
- input = images.view(-1, 784)
-
- optimizer.zero_grad()
- output = fcNetwork(input)
- loss = criterion(output, labels)
- loss.backward()
- optimizer.step()
-
- running_loss += loss.item()
-
- if steps % print_every == 0:
- accuracy = 0
- for ii, (images, labels) in enumerate(test_loader):
- inputs = images.view(-1, 784)
- preds = fcNetwork(inputs)
- accuracy += preds.argmax(dim=1).eq(labels).type_as(torch.FloatTensor()).mean()
- print("Epoch: {}/{}".format(epoch + 1, epochs),
- "Loss: {:.4f}".format(running_loss / print_every),
- "Test accuracy: {:.4f}".format(accuracy / (ii + 1)))
- running_loss = 0

(1)images的shape为[100, 1, 28, 28],而nn.Linear()需要输入的格式为[batch_size, 784],所以通过images.view(-1, 784)进行了转化,得到[100, 784]维度的数据。
(2)optimizer中的梯度信息是不断累加(链式求导)的,需要在每批数据训练前清空一下上次得到的梯度信息,避免不同批次间的grad相互干扰。
(3)loss.backward()是计算grad信息。
(4)optimizer.step()是根据第(3)的grad信息计算weight信息。
(5)preds.argmax(dim=1)可以获得预测值属于哪一类的信息。
(6)执行结果如下:
- Epoch: 1/5 Loss: 5.1928 Test accuracy: 0.8200
- Epoch: 2/5 Loss: 4.0105 Test accuracy: 0.8487
- Epoch: 3/5 Loss: 3.7100 Test accuracy: 0.8498
- Epoch: 4/5 Loss: 3.5857 Test accuracy: 0.8528
- Epoch: 5/5 Loss: 3.4329 Test accuracy: 0.8570
第6步, 使用CNN网络构建神经网络
- class CNNNetwork(nn.Module):
- def __init__(self):
- super(CNNNetwork, self).__init__()
- self.conv1 = nn.Conv2d(1, 6, 5)
- self.conv2 = nn.Conv2d(6, 16, 5)
- self.fc1 = nn.Linear(16*4*4, 120)
- self.fc2 = nn.Linear(120, 84)
- self.fc3 = nn.Linear(84, 10)
-
- def forward(self, x):
- x = F.max_pool2d(F.relu(self.conv1(x)), (2,2))
- x = F.max_pool2d(F.relu(self.conv2(x)), 2)
- x = torch.flatten(x, start_dim=1)
- x = F.relu(self.fc1(x))
- x = F.relu(self.fc2(x))
- x = self.fc3(x)
- return x
-
- def predict(self, x):
- logits = self.forward(x)
- return F.softmax(logits, dim=1)

(1)nn.Conv2d(1, 6, 5),卷积的输入需要是[batch, channel, heigth, width]格式的。其中1指的是输入图像是1通道的。6指的是有6个卷积核,每个卷积核都是(5,5)维度的。
(2)只有卷积网络需要有F.max_pool2d()池化操作,而全连接是不需要用池化操作的。
第7步,使用cnn网络训练模型
- cnnNetwork = CNNNetwork()
- criterion = nn.CrossEntropyLoss()
- optimizer = optim.Adam(cnnNetwork.parameters(), lr=0.01)
-
- epochs = 5
- steps = 0
- running_loss = 0
- print_every = 60
-
- for epoch in range(epochs):
- for images, labels in iter(train_loader):
- steps += 1
-
- optimizer.zero_grad()
- output = cnnNetwork(images)
- loss = criterion(output, labels)
- loss.backward()
- optimizer.step()
-
- running_loss += loss.item()
-
- if steps % print_every == 0:
- accuracy = 0
- for ii, (images, labels) in enumerate(test_loader):
- preds = cnnNetwork(images)
- accuracy += preds.argmax(dim=1).eq(labels).type_as(torch.FloatTensor()).mean()
- print("Epoch: {}/{}".format(epoch + 1, epochs),
- "Loss: {:.4f}".format(running_loss / print_every),
- "Test accuracy: {:.4f}".format(accuracy / (ii + 1)))
- running_loss = 0

运行后输出如下,可以看到使用cnn网络的准确率稍微高一点点。
- Epoch: 1/5 Loss: 5.0865 Test accuracy: 0.8457
- Epoch: 2/5 Loss: 3.6299 Test accuracy: 0.8417
- Epoch: 3/5 Loss: 3.3446 Test accuracy: 0.8495
- Epoch: 4/5 Loss: 3.2233 Test accuracy: 0.8719
- Epoch: 5/5 Loss: 3.1051 Test accuracy: 0.8697
第8步,使用混淆矩阵查看预测结果
- (images, labels) = next(iter(test_loader))
- preds = cnnNetwork(images).argmax(dim=1)
-
- from sklearn.metrics import confusion_matrix
- cm = confusion_matrix(labels, preds)
- print(cm)
取一批测试集数据校验结果,结果如下,可以看到每行的最大值基本上是沿着对角线走的,说明预测值基本上等于实际值。
- [[ 8 0 0 0 0 0 0 0 0 0]
- [ 0 13 0 0 0 0 0 0 0 0]
- [ 0 0 13 1 0 0 0 0 0 0]
- [ 0 1 0 6 1 0 1 0 0 0]
- [ 0 0 2 0 6 0 2 0 0 0]
- [ 0 0 0 0 0 8 0 1 0 0]
- [ 1 0 1 0 0 0 6 0 0 0]
- [ 0 0 0 0 0 1 0 10 0 0]
- [ 0 0 0 0 0 0 0 0 12 0]
- [ 0 0 0 0 0 1 0 1 0 4]]
第9步,使用tensorboard跟踪训练结果
(1)安装tensorboard:
pip install tensorboardX
(2)在算法脚本下新建runs目录,后面tensorboard的日志都指定放到该目录之下
(3)日志插桩
from tensorboardX import SummaryWriter
writer = SummaryWriter('runs/scalar_example')
具体插桩示例如下:
- loss_value = running_loss / print_every
- accuracy_value = accuracy / (ii + 1)
- print("Epoch: {}/{}".format(epoch + 1, epochs),
- "Loss: {:.4f}".format(loss_value),
- "Test accuracy: {:.4f}".format(accuracy_value))
- writer.add_scalar("loss", loss_value, epoch)
- writer.add_scalar("accuracy", accuracy_value, epoch)
- running_loss = 0
(4)运行tensorboard:
在runs的上一级目录下运行如下程序:
tensorboard --logdir "./runs" --host=127.0.0.1
得到结果:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。