数据集介绍
手写数字识别数据集(MNIST)是机器学习领域的标准数据集,也是很多人在学习机器学习和深度学习常用来练手的数据集,MNIST 内的每个样本都是二维的灰度图像,如下图所示。
在 MNIST 中,模型的输入是一副图像,模型的输出就是一个与图像中对应的数字(0 至 9 之间的一个整数,不是独热编码)。
在这种多分类问题中,神经网络的输出层需要一个 softmax 激活函数, 它可以把输出层的数据归一化到 0~1 范围内,且加起来为 1,这样就可以表示概率。
环境介绍
编辑器为Pycharm,深度学习框架为Pytorch,需要用到的库有torch,torchvision,matplotlib.
自己提前配置好环境那么上面这些就没什么问题,运行过程中缺少什么库就补什么库。
代码实现
1、数据集预处理
MNIST数据集是torchvision内置的库,写完代码直接运行就能下载,速度很快不用担心。
在 torchvision 库中分别下载训练集与测试集, 因此需要从torchvision 库中导入 datasets 以下载数据集,下载前需要借助 torchvision 库中的 transforms 进行图像转换,将数据集变为tensor张量,并调整数据集的统计分布。
import matplotlib.pyplot as plt
import torch
import torch.nn as nn
from torch.utils.data import DataLoader
from torchvision import datasets, transforms
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
transform = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize(mean=0.1307,std=0.3081)])
train_data = datasets.MNIST(root='Dataset',
train=True,
transform=transform,
download=False)
test_data = datasets.MNIST(root='Dataset',
train=False,
transform=transform,
download=False)
train_dataloader = DataLoader(dataset=train_data,
batch_size=64,
shuffle=True)
test_dataloader = DataLoader(dataset=test_data,
batch_size=64,
shuffle=False)
在下载数据集之前,要设定转换参数: transform,该参数里解决两个问题:
ToTensor:将图像数据转为张量,且调整三个维度的顺序为 C*W*H; C表示通道数,二维灰度图像的通道数为 1,三维 RGB 彩图的通道数为 3。
Normalize:将神经网络的输入数据转化为标准正态分布,训练更好;根据统计计算, MNIST 训练集所有像素的均值是 0.1307、标准差是 0.3081。
2、搭建神经网络
每个样本的输入都是形状为28*28 的二维数组,那么对于 DNN 来说,输入层的神经元参数就要有28*28=784 个;
输出层使用独热编码,需要 10 个参数。
class DNN(nn.Module):
def __init__(self):
super(DNN,self).__init__()
self.net = nn.Sequential( # 按顺序搭建各层
nn.Flatten(), # 把图像铺平成一维
nn.Linear(784, 512), nn.ReLU(), # 第 1 层:全连接层
nn.Linear(512, 256), nn.ReLU(), # 第 2 层:全连接层
nn.Linear(256, 128), nn.ReLU(), # 第 3 层:全连接层
nn.Linear(128, 64), nn.ReLU(), # 第 4 层:全连接层
nn.Linear(64, 10) # 第 5 层:全连接层
)
def forward(self, x):
y = self.net(x)
return y
# 模型实例化
model = DNN()
3、定义损失函数和优化器
# 损失函数的选择
loss_fn = nn.CrossEntropyLoss() # 自带 softmax 激活函数
# 优化算法的选择
learning_rate = 0.01 # 设置学习率
optimizer = torch.optim.SGD(params=model.parameters(),lr=learning_rate,momentum = 0.5)
4、定义训练函数
# 训练
def train(train_dataloader,model,num_epoch):
model = model.to(device)
loss_list = []
for epoch in range(num_epoch):
for (x,y) in train_dataloader:
x,y = x.to(device),y.to(device)
pred = model(x)
loss = loss_fn(pred,y)
loss_list.append(loss.item())
optimizer.zero_grad()
loss.backward()
optimizer.step()
fig1 = plt.figure()
plt.plot(range(len(loss_list)),loss_list)
plt.show()
train(train_dataloader=train_dataloader,model=model,num_epoch=10)
5、定义测试函数
# 测试
def test(test_dataloader,model):
correct = 0
total = 0
with torch.no_grad():
for (x,y) in test_dataloader:
x, y = x.to(device), y.to(device)
pred = model(x)
_,pred = torch.max(pred.data,dim=1)
correct += torch.sum((pred == y))
total += y.size(0)
print(f'测试集精准度: {100 * correct / total} %')
全部代码
import matplotlib.pyplot as plt
import torch
import torch.nn as nn
from torch.utils.data import DataLoader
from torchvision import datasets, transforms
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
transform = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize(mean=0.1307,std=0.3081)])
train_data = datasets.MNIST(root='Dataset',
train=True,
transform=transform,
download=False)
test_data = datasets.MNIST(root='Dataset',
train=False,
transform=transform,
download=False)
train_dataloader = DataLoader(dataset=train_data,
batch_size=64,
shuffle=True)
test_dataloader = DataLoader(dataset=test_data,
batch_size=64,
shuffle=False)
class DNN(nn.Module):
def __init__(self):
super(DNN,self).__init__()
self.net = nn.Sequential( # 按顺序搭建各层
nn.Flatten(), # 把图像铺平成一维
nn.Linear(784, 512), nn.ReLU(), # 第 1 层:全连接层
nn.Linear(512, 256), nn.ReLU(), # 第 2 层:全连接层
nn.Linear(256, 128), nn.ReLU(), # 第 3 层:全连接层
nn.Linear(128, 64), nn.ReLU(), # 第 4 层:全连接层
nn.Linear(64, 10) # 第 5 层:全连接层
)
def forward(self, x):
y = self.net(x)
return y
# 模型实例化
model = DNN()
# 损失函数的选择
loss_fn = nn.CrossEntropyLoss() # 自带 softmax 激活函数
# 优化算法的选择
learning_rate = 0.01 # 设置学习率
optimizer = torch.optim.SGD(params=model.parameters(),lr=learning_rate,momentum = 0.5)
# 训练
def train(train_dataloader,model,num_epoch):
model = model.to(device)
loss_list = []
for epoch in range(num_epoch):
for (x,y) in train_dataloader:
x,y = x.to(device),y.to(device)
pred = model(x)
loss = loss_fn(pred,y)
loss_list.append(loss.item())
optimizer.zero_grad()
loss.backward()
optimizer.step()
fig1 = plt.figure()
plt.plot(range(len(loss_list)),loss_list)
plt.show()
train(train_dataloader=train_dataloader,model=model,num_epoch=10)
# 测试
def test(test_dataloader,model):
correct = 0
total = 0
with torch.no_grad():
for (x,y) in test_dataloader:
x, y = x.to(device), y.to(device)
pred = model(x)
_,pred = torch.max(pred.data,dim=1)
correct += torch.sum((pred == y))
total += y.size(0)
print(f'测试集精准度: {100 * correct / total} %')
总结
DNN(深度神经网络)是学习深度学习的基础,它都是由线性层(全连接层组成的),这种情况下网络的参数很多,训练效率低下,并且容易造成过拟合,因此后面才会出现CNN,RNN,LSTM,TRANSFORMER等等优秀的网络和机制,不过学习好DNN后面学习才会更快上手。
本人能力有限,不足之处请指出,如果对你有帮助请点赞关注!