文章目录
- 网络结构
- 输出图像尺寸
- 网络代码
- 预处理代码
- 训练代码
- 结果评定
网络结构
文章图片
按顺序对每个层的参数设置
Conv1
Conv2d:in_channels=1, out_channels=16, kernel_size=3, stride=1Conv2
BatchNorm2d:16
ReLU
MaxPool2d:kernel_size=2, stride=1
Conv2d:in_channels=16, out_channels=32, kernel_size=3, stride=1Conv3
BatchNorm2d:32
ReLU
MaxPool2d:kernel_size=2, stride=1
Conv2d:in_channels=32, out_channels=64, kernel_size=3, stride=1Conv4
BatchNorm2d:64
ReLU
AvgPool2d:kernel_size=2, stride=1
Conv2d:in_channels=64, out_channels=128, kernel_size=3, stride=1MLP
BatchNorm2d:128
ReLU
AvgPool2d:kernel_size=2, stride=1
Linear(128 * 16 * 16, 1000)输出图像尺寸
Linear(1000, 1000)
Linear(1000, 100)
Linear(100, 10)
文章图片
计算公式(lambda函数化)
func = lambda size, kernel=3, stride=1, padding=0: ((size - kernel + 2 * padding) / stride + 1)
代码通过显式获取图片长宽,并且结合网络层的构造可以自动计算图像尺寸的变换
func = lambda size, kernel=3, stride=1, padding=0: ((size - kernel + 2 * padding) / stride + 1)
x = func(func(self.options[1]), kernel=2)
x = func(func(x), kernel=2)
x = func(func(x), kernel=2)
x = func(func(x), kernel=2)y = func(func(self.options[2]), kernel=2)
y = func(func(y), kernel=2)
y = func(func(y), kernel=2)
y = func(func(y), kernel=2)x = int(x)
y = int(y)
网络代码
class CNN(nn.Module):
def __init__(self, channels, width, height, classes, device='cpu'):
super().__init__()self.options = [channels, width, height, classes, device]self.conv1 = nn.Sequential(
nn.Conv2d(in_channels=channels, out_channels=16, kernel_size=3, stride=1),
nn.BatchNorm2d(16),
nn.ReLU(),
nn.MaxPool2d(kernel_size=2, stride=1)
)self.conv2 = nn.Sequential(
nn.Conv2d(in_channels=16, out_channels=32, kernel_size=3, stride=1),
nn.BatchNorm2d(32),
nn.ReLU(),
nn.MaxPool2d(kernel_size=2, stride=1)
)self.conv3 = nn.Sequential(
nn.Conv2d(in_channels=32, out_channels=64, kernel_size=3, stride=1),
nn.BatchNorm2d(64),
nn.ReLU(),
nn.AvgPool2d(kernel_size=2, stride=1)
)self.conv4 = nn.Sequential(
nn.Conv2d(in_channels=64, out_channels=128, kernel_size=3, stride=1),
nn.BatchNorm2d(128),
nn.ReLU(),
nn.AvgPool2d(kernel_size=2, stride=1)
)func = lambda size, kernel=3, stride=1, padding=0: ((size - kernel + 2 * padding) / stride + 1)
x = func(func(self.options[1]), kernel=2)
x = func(func(x), kernel=2)
x = func(func(x), kernel=2)
x = func(func(x), kernel=2)y = func(func(self.options[2]), kernel=2)
y = func(func(y), kernel=2)
y = func(func(y), kernel=2)
y = func(func(y), kernel=2)x = int(x)
y = int(y)self.mlp = nn.Sequential(
nn.Linear(128 * x * y, 1000),
nn.Linear(1000, 1000),
nn.Linear(1000, 100),
nn.Linear(100, self.options[3])
)self = self.to(self.options[4])def forward(self, data):
data = https://www.it610.com/article/data.to(self.options[4])# 将向量转移到设备上
data = self.conv1(data)
data = self.conv2(data)
data = self.conv3(data)
data = self.conv4(data)
data = data.view(data.size(0), -1)
data = self.mlp(data)
return data
预处理代码
data_tf = torchvision.transforms.Compose(
[
torchvision.transforms.ToTensor(),
torchvision.transforms.Normalize([0.5], [0.5])
]
)data_path = r'data/minist'# minist数据集的下载路径
# 获取数据集
train_data = https://www.it610.com/article/mnist.MNIST(data_path, train=True, transform=data_tf, download=False)
test_data = mnist.MNIST(data_path, train=False, transform=data_tf, download=False)
train_loader = data.DataLoader(train_data, batch_size=128, shuffle=True)
test_loader = data.DataLoader(test_data, batch_size=128, shuffle=True)
训练代码
device = 'cuda:0'
model = CNN(channels=1, width=28, height=28, classes=10, device=device)
loss_func = torch.nn.CrossEntropyLoss()
opt = torch.optim.Adam(model.parameters(), lr=0.001)
loss_count = []for epoch in range(50):
for i, (x, y) in enumerate(train_loader):batch_x = Variable(x)
batch_y = Variable(y).to(device)
out = model(batch_x)loss = loss_func(out, batch_y)opt.zero_grad()
loss.backward()
opt.step()if i % 20 == 0:
loss = loss.cpu()
loss_count.append(loss)for a, b in test_loader:
test_x = Variable(a)
test_y = Variable(b).to(device)
out = model(test_x)
test_y = test_y.cpu()
out = out.cpu()
accuracy = max(out, 1)[1].numpy() == test_y.numpy()
print('accuracy:\t', accuracy.mean())
breakdatas = []
for i in loss_count:
if i.data < 0.5:
datas.append(i.data)
plt.figure('LOSS')
plt.plot(datas, label='Loss')
plt.legend()
plt.show()
因为交叉熵损失会出现大于1的值,所以显示的时候删除掉损失大于0.5的值,会更好的显示损失图
结果评定 【学习日志|Python MINIST手写集的识别,卷积神经网络,CNN(最简单PyTorch的使用)】
文章图片
文章图片
推荐阅读
- 机器学习图像处理|从零开始实现一个简单的CycleGAN项目
- python|遗传算法基本思路与0-1决策背包问题
- 数学建模|2022年第十二届MathorCup高校数学建模挑战赛
- 聚类|2022年MathorCup数学建模竞赛(基站聚类思路)
- matlab|2022年MathorCup建模赛D题(MATLAB代码与若干问题)
- matlab|2022 MathorCup 数学建模B题思路解析
- 算法|魔改YOLOv5!一种实时多尺度交通标志检测网络
- 神经网络|YOLO7 姿势识别实例
- 如何用 Python 自动化监控文件夹完成服务部署!