AI入门教程03.02:LeNet卷积神经网络

本文介绍如何写一个LeNet卷积神经网络。网络结构为

cnn

使用MNIST数据集,内容为手写数字,1通道灰度图。

模型流程为

  • 将1通道32x32图片卷积为6通道28x28图片
  • 使用池化缩小图片
  • 将6通道14x14图片卷积为16通道10x10图片
  • 使用池化缩小图片
  • 将16通道5x5图片缩小为1通道宽1高120图片
  • 将120图片限制为1通道宽1高84图片
  • 将84图片输出对应0-9这10个结果

模型开发

将神经网络模型转换为对应代码的基本流程。

硬件选择

根据硬件情况选择加速方式

1
2
3
4
if torch.cuda.is_available():
device = torch.device("cuda") # 如果GPU可用,则使用CUDA
else:
device = torch.device("cpu") # 如果GPU不可用,则使用CPU

加载数据集并进行预处理

缩放、裁剪、归一化数据集中的数据。

MNIST数据集图片大小相同,这一步跳过。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 加载MNIST数据集的训练集
training_data = datasets.FashionMNIST(
root="data",
train=True,
download=True,
transform=transforms.ToTensor(),
)
# 加载MNIST数据集的测试集
test_data = datasets.FashionMNIST(
root="data",
train=False,
download=True,
transform=transforms.ToTensor(),
)

# batch大小
batch_size = 64

# 创建dataloader
train_dataloader = torch.utils.data.DataLoader(training_data, batch_size=batch_size)
test_dataloader = torch.utils.data.DataLoader(test_data, batch_size=batch_size)

如果指定位置没有数据集就自动下载。

定义模型

根据神经网络模型定义编写代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 定义神经网络模型
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
# 输入1通道,输出6通道,卷积核为5x5
self.conv1 = nn.Conv2d(1,6,5)
self.conv2 = nn.Conv2d(6,16,5)
self.conv3 = nn.Conv2d(16,120,4)
self.fc2 = nn.Linear(120, 84)
self.fc3 = nn.Linear(84,10)

def forward(self, x):
x = self.conv1(x)
x = F.relu(x)
x = F.max_pool2d(x,(2,2))

# 精简代码
x = F.max_pool2d(F.relu(self.conv2(x)),2)
x = F.relu(self.conv3(x))

x = torch.flatten(x,1) #扁平化
x = F.relu(self.fc2(x))
x = self.fc3(x)
return x

全连接使用Linear函数,只要是784->256->10

使用view函数将二维图片转换为一维数组。

全连接后使用激活函数获得数据。

conv2d 输出通道一般为32 64 128 256

初始化模型、损失函数和优化器

1
2
3
4
5
# 实例化模型并定义损失函数和优化器
net = Net().to(device)
criterion = nn.CrossEntropyLoss() # 交叉熵损失函数适合分类任务
optimizer = torch.optim.SGD(net.parameters(), lr=0.01)
#optimizer = optim.Adam(model.parameters(), lr=learning_rate)

训练

1
2
3
4
5
6
7
8
9
10
11
12
# 加载数据并训练
for epoch in range(100):
index=0
for inputs, labels in train_dataloader:
inputs, labels = inputs.to(device), labels.to(device)
optimizer.zero_grad()
outputs = net(inputs)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
index+=1
print(f'Epoch [{epoch}], Setp [{index}/{len(train_dataloader)}],Loss: {loss.item():.4f}')

预测

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 加载模型并测试
correct = 0
total = 0
net.eval()
with torch.no_grad():
for inputs, labels in test_dataloader:
inputs, labels = inputs.to(device), labels.to(device)
outputs = net(inputs)
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()

# 结果评估
print('Accuracy: %d %%' % (100 * correct / total))

运行

运行输出为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Epoch [99], Setp [917/938],Loss: 0.1260
Epoch [99], Setp [918/938],Loss: 0.1750
Epoch [99], Setp [919/938],Loss: 0.1906
Epoch [99], Setp [920/938],Loss: 0.1170
Epoch [99], Setp [921/938],Loss: 0.1094
Epoch [99], Setp [922/938],Loss: 0.1026
Epoch [99], Setp [923/938],Loss: 0.0564
Epoch [99], Setp [924/938],Loss: 0.0766
Epoch [99], Setp [925/938],Loss: 0.1219
Epoch [99], Setp [926/938],Loss: 0.1193
Epoch [99], Setp [927/938],Loss: 0.1568
Epoch [99], Setp [928/938],Loss: 0.1768
Epoch [99], Setp [929/938],Loss: 0.1075
Epoch [99], Setp [930/938],Loss: 0.2160
Epoch [99], Setp [931/938],Loss: 0.1079
Epoch [99], Setp [932/938],Loss: 0.1955
Epoch [99], Setp [933/938],Loss: 0.2639
Epoch [99], Setp [934/938],Loss: 0.1002
Epoch [99], Setp [935/938],Loss: 0.0420
Epoch [99], Setp [936/938],Loss: 0.0846
Epoch [99], Setp [937/938],Loss: 0.0923
Epoch [99], Setp [938/938],Loss: 0.1290
Accuracy: 89 %

源码

完整代码为

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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torchvision import datasets, transforms

if torch.cuda.is_available():
device = torch.device("cuda") # 如果GPU可用,则使用CUDA
else:
device = torch.device("cpu") # 如果GPU不可用,则使用CPU

# 定义神经网络模型
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
# 输入1通道,输出6通道,卷积核为5x5
self.conv1 = nn.Conv2d(1,6,5)
self.conv2 = nn.Conv2d(6,16,5)
self.conv3 = nn.Conv2d(16,120,4)
self.fc2 = nn.Linear(120, 84)
self.fc3 = nn.Linear(84,10)

def forward(self, x):
x = self.conv1(x)
x = F.relu(x)
x = F.max_pool2d(x,(2,2))

# 精简代码
x = F.max_pool2d(F.relu(self.conv2(x)),2)
x = F.relu(self.conv3(x))

x = torch.flatten(x,1) #扁平化
x = F.relu(self.fc2(x))
x = self.fc3(x)
return x


# 加载MNIST数据集的训练集
training_data = datasets.FashionMNIST(
root="data",
train=True,
download=True,
transform=transforms.ToTensor(),
)
# 加载MNIST数据集的测试集
test_data = datasets.FashionMNIST(
root="data",
train=False,
download=True,
transform=transforms.ToTensor(),
)

# batch大小
batch_size = 64

# 创建dataloader
train_dataloader = torch.utils.data.DataLoader(training_data, batch_size=batch_size)
test_dataloader = torch.utils.data.DataLoader(test_data, batch_size=batch_size)

# 实例化模型并定义损失函数和优化器
net = Net().to(device)
#print(net)
#params = list(net.parameters())
#print(len(params))
#print(params[0].size())#conv1的权重参数
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(net.parameters(), lr=0.01)

# 加载数据并训练
for epoch in range(100):
index=0
for inputs, labels in train_dataloader:
inputs, labels = inputs.to(device), labels.to(device)
optimizer.zero_grad()
outputs = net(inputs)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
index+=1
print(f'Epoch [{epoch}], Setp [{index}/{len(train_dataloader)}],Loss: {loss.item():.4f}')

# 加载模型并测试
net.eval()
correct = 0
total = 0
with torch.no_grad():
for inputs, labels in test_dataloader:
inputs, labels = inputs.to(device), labels.to(device)
outputs = net(inputs)
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()

# 结果评估
print('Accuracy: %d %%' % (100 * correct / total))

AI入门教程03.02:LeNet卷积神经网络
https://feater.top/ai/how-to-build-a-lenet-nn/
作者
JackeyLea
发布于
2024年6月24日
许可协议