【深度学习】经典的深度学习模型-01 开山之作:CNN卷积神经网络LeNet-5
Note: 草稿状态,持续更新中,如果有感兴趣,欢迎关注。。。
0. 论文信息
@article{lecun1998gradient,
title={Gradient-based learning applied to document recognition},
author={LeCun, Yann and Bottou, L{'e}on and Bengio, Yoshua and Haffner, Patrick},
journal={Proceedings of the IEEE},
volume={86},
number={11},
pages={2278–2324},
year={1998},
publisher={Ieee}
}
基于梯度的学习在文档识别中的应用
LeNet-5 是一个经典的卷积神经网络(CNN)架构,由 Yann LeCun 等人在 1998 年提出,主要用于手写数字识别任务,特别是在 MNIST 数据集上。
LeNet-5 的设计对后来的卷积神经网络研究产生了深远影响,该模型具有以下几个特点:
- 卷积层:LeNet-5 包含多个卷积层,每个卷积层后面通常会跟一个池化层(Pooling Layer),用于提取图像特征并降低特征图的空间维度。
- 池化层:在卷积层之后,LeNet-5 使用池化层来降低特征图的空间分辨率,减少计算量,并增加模型的抽象能力。
- 全连接层:在卷积和池化层之后,LeNet-5 包含几个全连接层,用于学习特征之间的复杂关系。
- 激活函数:LeNet-5 使用了 Sigmoid 激活函数,这是一种早期的非线性激活函数,用于引入非线性,使得网络可以学习复杂的模式。
- Dropout:尽管原始的 LeNet-5 并没有使用 Dropout,但后来的研究者在改进模型时加入了 Dropout 技术,以减少过拟合。
- 输出层:LeNet-5 的输出层通常使用 Softmax 激活函数,用于进行多分类任务,输出每个类别的概率。
虽然站在2024年看LeNet-5 的模型结构相对简单,但是时间回拨到1998年,彼时SVM这类算法为主的时代,LeNet-5的出现,不仅证明了卷积神经网络在图像识别任务中的有效性,而且为后续深度神经网络研究的发展带来重要启迪作用,使得我们有幸看到诸如 AlexNet、VGGNet、ResNet 等模型的不断推成出新。
2. 论文摘要
3. 研究背景
4. 算法模型
5. 实验效果
6. 代码实现
以MNIST手写字图像识别问题为例子,采用LeNet5模型进行分类,代码如下:
import torch import torch.nn as nn import torch.nn.functional as F import torch.optim as optim from torchvision import datasets, transforms device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") print(f"Using device: {device}") # Define the LeNet-5 model class LeNet5(nn.Module): def __init__(self): super(LeNet5, self).__init__() self.conv1 = nn.Conv2d(1, 6, 5) # 1 input image channel, 6 output channels, 5x5 kernel self.pool = nn.MaxPool2d(2, 2) # pool with window 2x2, stride 2 self.conv2 = nn.Conv2d(6, 16, 5) self.fc1 = nn.Linear(16 * 4 * 4, 120) # 16*4*4 = 256 self.fc2 = nn.Linear(120, 84) self.fc3 = nn.Linear(84, 10) def forward(self, x): x = self.pool(F.relu(self.conv1(x))) x = self.pool(F.relu(self.conv2(x))) x = x.view(-1, 16 * 4 * 4) # flatten the tensor x = F.relu(self.fc1(x)) x = F.relu(self.fc2(x)) x = self.fc3(x) return x # # Initialize the network # net = LeNet5() # Initialize the network on GPU net = LeNet5().to(device) # Define loss function and optimizer criterion = nn.CrossEntropyLoss() optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9) # Data loading transform = transforms.Compose([ transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,)) ]) train_dataset = datasets.MNIST(root='./data', train=True, download=True, transform=transform) test_dataset = datasets.MNIST(root='./data', train=False, download=True, transform=transform) train_loader = torch.utils.data.DataLoader(dataset=train_dataset, batch_size=64, shuffle=True) test_loader = torch.utils.data.DataLoader(dataset=test_dataset, batch_size=1000, shuffle=False) # Train the network for epoch in range(10): # loop over the dataset multiple times running_loss = 0.0 for i, data in enumerate(train_loader, 0): # for cpu # inputs, labels = data # for gpu inputs, labels = data[0].to(device), data[1].to(device) optimizer.zero_grad() outputs = net(inputs) loss = criterion(outputs, labels) loss.backward() optimizer.step() running_loss += loss.item() if i % 2000 == 1999: # print every 2000 mini-batches print(f'[{epoch + 1}, {i + 1}] loss: {running_loss / 2000:.3f}') running_loss = 0.0 print('Finished Training') # Test the network on the test data correct = 0 total = 0 with torch.no_grad(): for data in test_loader: # # for cpu # images, labels = data # for gpu images, labels = data[0].to(device), data[1].to(device) outputs = net(images) _, predicted = torch.max(outputs.data, 1) total += labels.size(0) correct += (predicted == labels).sum().item() print(f'Accuracy of the network on the 10000 test images: {100 * correct / total:.2f}%')
注意:这里使用GPU做简单加速。如果没有GPU,可以关闭对应代码,替换为相应的CPU代码即可。
程序运行后结果如下:
可以看到,在测试数据上的准确率为98.33%!