用神经网络实现手写数字识别
用神经网络实现手写数字识别
神经网络:是一种模仿生物神经网络结构和功能的人工智能模型,具有强大的信息处理能力。
小鱼书里这样说:神经网络的重要性质是它可以自动地从数据中学习到合适的权重参数。
以我的理解来看,神经网络是对已经经过预处理的数据进行拟合的工具,通过训练可以使它学习到权重参数,让其拥有识别能力。
神经网络如何实现手写数字识别呢?
我们需要设计一个三层的神经网络,它包括最基本的输入层中间层(隐藏层,用于特征提取)和输出层,这个神经网络以数字图像(28*28的灰色通道图像)作为输入 ,经过神经网络的计算识别出图像中的数字是几。
1.定义两个线性层
class Network(nn.Module):
def __init__(self):
super().__init__()
# 线性层1,输入层和隐藏层之间的线性层
self.layer1 = nn.Linear(784, 256)
# 线性层2,隐藏层和输出层之间的线性层
self.layer2 = nn.Linear(256, 10)
2.向前传播forward函数中,输入图像x
def forward(self, x):
x = x.view(-1, 28 * 28) # 使用view函数,将x展平变为1*784的矩阵
x = self.layer1(x) # 将x输入至layer1
x = torch.relu(x) # 使用relu激活
return self.layer2(x) # 输入至layer2计算结果
这里用到激活函数,如果没有激活函数,则数据一直进行线性运算,用图像来说它将保持为一个直线,而要进行非线性化,就要用到激活函数,常见的激活函数有sigmoid,relu等,relu会有更好的效果,而sigmoid由于导数最大值是0.25,会使得反向传播时出现梯度消失的可能。
那什么又是反向传播呢,我的理解是,神经网络最开始的权重参数是随机的,并不一定会有好的拟合效果,由第一次的损失函数进行梯度下降从而更新权重和偏置,使其逐渐收敛到一个好的值,使得神经网络不仅能够更好的拟合训练数据,而且提高它的泛化能力。
3.获取数据集(MNIST)并对图像预处理
if __name__ == '__main__':
transform = transforms.Compose([
transforms.Grayscale(num_output_channels=1),#转换为单通道灰度图
transforms.ToTensor()#转换为张量
])
# 读入并构造数据集
train_dataset = datasets.ImageFolder(root='./mnist_images/train', transform=transform)
print("train_dataset length: ", len(train_dataset))
# 小批量的数据读入
train_loader = DataLoader(train_dataset, batch_size=64, shuffle=True)
print("train_loader length: ", len(train_loader))
model = Network() # 模型本身,它就是我们设计的神经网络
optimizer = optim.Adam(model.parameters()) # 优化模型中的参数
criterion = nn.CrossEntropyLoss() # 分类问题,使用交叉熵损失误差
4.训练
# 进入模型的迭代循环
for epoch in range(10): # 外层循环,代表了整个训练数据集的遍历次数
# 整个训练集要循环多少轮,是10次、20次或者100次都是可能的,
# 内存循环使用train_loader,进行小批量的数据读取
for batch_idx, (data, label) in enumerate(train_loader):
# 内层每循环一次,就会进行一次梯度下降算法
# 包括了5个步骤:
output = model(data) # 1.计算神经网络的前向传播结果
loss = criterion(output, label) # 2.计算output和标签label之间的损失loss
loss.backward() # 3.使用backward计算梯度
optimizer.step() # 4.使用optimizer.step更新参数
optimizer.zero_grad() # 5.将梯度清零
# 这5个步骤,是使用pytorch框架训练模型的定式,记住即可
# 每迭代100个小批量,就打印一次模型的损失,观察训练的过程
if batch_idx % 100 == 0:
print(f"Epoch {epoch + 1}/10 "
f"| Batch {batch_idx}/{len(train_loader)} "
f"| Loss: {loss.item():.4f}")
这一步就运用了前面提到的反向传播,最后打印loss可以发现损失逐渐变小
5.可以进行测试
总结
这页内容里,我用简单的个人理解描述了神经网络的组成与工作原理,并用一部分代码写了手写数字识别的部分功能实现,以便随时重温神经网络的内容。
浙公网安备 33010602011771号