• LeNet-5


    目录

    一、知识点

    二、代码

    三、查看卷积层的feature map

    1. 查看每层信息

    ​2. show_featureMap.py


    背景:LeNet-5是一个经典的CNN,由Yann LeCun在1998年提出,旨在解决手写数字识别问题。

    一、知识点

    1. iter()+next()

    iter():返回迭代器

    next():使用next()来获取下一条数据

    1. data = [1, 2, 3]
    2. data_iter = iter(data)
    3. print(next(data_iter)) # 1
    4. print(next(data_iter)) # 2
    5. print(next(data_iter)) # 3

    2. enumerate

    enumerate(sequence,[start=0]) 函数用于将一个可遍历的数据对象组合为一个索引序列,同时列出数据和数据下标,一般用在 for 循环当中。

    start--下标起始位置的值。 

    1. data = ['zs', 'ls', 'ww']
    2. print(list(enumerate(data)))
    3. # [(0, 'zs'), (1, 'ls'), (2, 'ww')]

    3. torch.no_grad()

    在该模块下,所有计算得出的tensor的requires_grad都自动设置为False。

    当requires_grad设置为False时,在反向传播时就不会自动求导了,可以节约存储空间。

    4. torch.max(input,dim)

    input -- tensor类型

    dim=0 -- 行比较

    dim=1 -- 列比较

    1. import torch
    2. data = torch.Tensor([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
    3. x = torch.max(data, dim=0)
    4. print(x)
    5. # values=tensor([7., 8., 9.]),
    6. # indices=tensor([2, 2, 2])
    7. x = torch.max(data, dim=1)
    8. print(x)
    9. # values=tensor([3., 6., 9.]),
    10. # indices=tensor([2, 2, 2])

    5. torch.eq:对两个张量Tensor进行逐个元素的比较,若相同位置的两个元素相同,则返回True;若不同,返回False。

    注意:item返回一个数。

    1. import torch
    2. data1 = torch.tensor([1, 2, 3, 4, 5])
    3. data2 = torch.tensor([2, 3, 3, 9, 5])
    4. x = torch.eq(data1, data2)
    5. print(x) # tensor([False, False, True, False, True])
    6. sum = torch.eq(data1, data2).sum()
    7. print(sum) # tensor(2)
    8. sum_item = torch.eq(data1, data2).sum().item()
    9. print(sum_item) # 2

    6. squeeze(input,dim)函数

    squeeze(0):若第一维度值为1,则去除第一维度

    squeeze(1):若第二维度值为2,则去除第二维度

    squeeze(-1):去除最后维度值为1的维度

    7. unsqueeze(input,dim)

    增加大小为1的维度,即返回一个新的张量,对输入的指定位置插入维度 1且必须指明维度。

    二、代码

    model.py

    1. import torch.nn as nn
    2. import torch.nn.functional as F
    3. class LeNet(nn.Module):
    4. def __init__(self):
    5. super(LeNet, self).__init__()
    6. self.conv1 = nn.Conv2d(3, 16, 5) # output(16,28,28)
    7. self.pool1 = nn.MaxPool2d(2, 2) # output(16,14,14)
    8. self.conv2 = nn.Conv2d(16, 32, 5) # output(32,10,10)
    9. self.pool2 = nn.MaxPool2d(2, 2) # output(32,5,5)
    10. self.fc1 = nn.Linear(32 * 5 * 5, 120) # output:120
    11. self.fc2 = nn.Linear(120, 84) # output:84
    12. self.fc3 = nn.Linear(84, 10) # output:10
    13. def forward(self, x):
    14. x = F.relu(self.conv1(x))
    15. x = self.pool1(x)
    16. x = F.relu(self.conv2(x))
    17. x = self.pool2(x)
    18. x = x.view(-1, 32 * 5 * 5)
    19. x = F.relu(self.fc1(x))
    20. x = F.relu(self.fc2(x))
    21. x = self.fc3(x)
    22. return x

    train.py

    1. import torch
    2. import torchvision
    3. import torch.nn as nn
    4. import torch.optim as optim
    5. import torchvision.transforms as transforms
    6. from model import LeNet
    7. def main():
    8. # preprocess data
    9. transform = transforms.Compose([
    10. # Converts a PIL Image or numpy.ndarray (H x W x C) in the range [0, 255] to a torch.FloatTensor of shape (C x H x W) in the range [0.0, 1.0]
    11. transforms.ToTensor(),
    12. # (mean[1],...,mean[n])`` and std: ``(std[1],..,std[n])
    13. transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))
    14. ])
    15. # 训练集 如果数据集已经下载了,则download=False
    16. train_data = torchvision.datasets.CIFAR10('./data', train=True, transform=transform, download=False)
    17. train_loader = torch.utils.data.DataLoader(train_data, batch_size=36, shuffle=True, num_workers=0)
    18. # 验证集
    19. val_data = torchvision.datasets.CIFAR10('./data', train=False, download=False, transform=transform)
    20. val_loader = torch.utils.data.DataLoader(val_data, batch_size=10000, shuffle=False, num_workers=0)
    21. # 返回迭代器
    22. val_data_iter = iter(val_loader)
    23. val_image, val_label = next(val_data_iter)
    24. net = LeNet()
    25. loss_function = nn.CrossEntropyLoss()
    26. optimizer = optim.Adam(net.parameters(), lr=0.001)
    27. # loop over the dataset multiple times
    28. for epoch in range(5):
    29. epoch_loss = 0
    30. for step, data in enumerate(train_loader, start=0):
    31. # get the inputs from train_loader;data is a list of[inputs,labels]
    32. inputs, labels = data
    33. # 在处理每一个batch时并不需要与其他batch的梯度混合起来累积计算,因此需要对每个batch调用一遍zero_grad()将参数梯度设置为0
    34. optimizer.zero_grad()
    35. # 1.forward
    36. outputs = net(inputs)
    37. # 2.loss
    38. loss = loss_function(outputs, labels)
    39. # 3.backpropagation
    40. loss.backward()
    41. # 4.update x by optimizer
    42. optimizer.step()
    43. # print statistics
    44. # 使用item()取出的元素值的精度更高
    45. epoch_loss += loss.item()
    46. # print every 500 mini-batches
    47. if step % 500 == 499:
    48. with torch.no_grad():
    49. outputs = net(val_image)
    50. predict_y = torch.max(outputs, dim=1)[1] # [0]取每行最大值,[1]取每行最大值的索引
    51. val_accuracy = torch.eq(predict_y, val_label).sum().item() / val_label.size(0)
    52. print('[epoch:%d step:%5d] train_loss:%.3f test_accuracy:%.3f' % (
    53. epoch + 1, step + 1, epoch_loss / 500, val_accuracy))
    54. epoch_loss = 0
    55. print('Train finished!')
    56. sava_path = './model/LeNet.pth'
    57. torch.save(net.state_dict(), sava_path)
    58. if __name__ == '__main__':
    59. main()

    predict.py

    1. import torch
    2. import torchvision.transforms as transforms
    3. from PIL import Image
    4. from model import LeNet
    5. def main():
    6. transform = transforms.Compose([
    7. transforms.Resize((32, 32)),
    8. transforms.ToTensor(), # CHW格式
    9. transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))
    10. ])
    11. classes = ['plane', 'car', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck']
    12. net = LeNet()
    13. net.load_state_dict(torch.load('./model/LeNet.pth'))
    14. image = Image.open('./predict/2.png') # HWC格式
    15. image = transform(image)
    16. image = torch.unsqueeze(image, dim=0) # 在第0维加一个维度 #[N,C,H,W] N:Batch批处理大小
    17. with torch.no_grad():
    18. outputs = net(image)
    19. predict = torch.max(outputs, dim=1)[1]
    20. print(classes[predict])
    21. if __name__ == '__main__':
    22. main()

    2.png

     

    三、查看卷积层的feature map

    1. 查看每层信息

    1. for i in net.children():
    2. print(i)

    2. show_featureMap.py

    1. import torch
    2. import torch.nn as nn
    3. from model import LeNet
    4. import torchvision
    5. import torchvision.transforms as transforms
    6. from PIL import Image
    7. import matplotlib.pyplot as plt
    8. def main():
    9. transform = transforms.Compose([
    10. transforms.Resize((32, 32)),
    11. transforms.ToTensor(), # CHW格式
    12. transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))
    13. ])
    14. image = Image.open('./predict/2.png') # HWC格式
    15. image = transform(image)
    16. image = torch.unsqueeze(image, dim=0) # 在第0维加一个维度 #[N,C,H,W] N:Batch批处理大小
    17. net = LeNet()
    18. net.load_state_dict(torch.load('./model/LeNet.pth'))
    19. conv_weights = [] # 模型权重
    20. conv_layers = [] # 模型卷积层
    21. counter = 0 # 模型里有多少个卷积层
    22. # 1.将卷积层以及对应权重放入列表中
    23. model_children = list(net.children())
    24. for i in range(len(model_children)):
    25. if type(model_children[i]) == nn.Conv2d:
    26. counter += 1
    27. conv_weights.append(model_children[i].weight)
    28. conv_layers.append(model_children[i])
    29. outputs = []
    30. names = []
    31. for layer in conv_layers[0:]:
    32. # 2.每个卷积层对image进行计算
    33. image = layer(image)
    34. outputs.append(image)
    35. names.append(str(layer))
    36. # 3.进行维度转换
    37. print(outputs[0].shape) # torch.Size([1, 16, 28, 28]) 1-batch 16-channel 28-H 28-W
    38. print(outputs[0].squeeze(0).shape) # torch.Size([16, 28, 28]) 去除第0维
    39. # 将16颜色通道的feature map加起来,变为一张28×28的feature map,sum将所有灰度图映射到一张
    40. print(torch.sum(outputs[0].squeeze(0), 0).shape) # torch.Size([28, 28])
    41. processed_data = []
    42. for feature_map in outputs:
    43. feature_map = feature_map.squeeze(0) # torch.Size([16, 28, 28])
    44. gray_scale = torch.sum(feature_map, 0) # torch.Size([28, 28])
    45. # 取所有灰度图的平均值
    46. gray_scale = gray_scale / feature_map.shape[0]
    47. processed_data.append(gray_scale.data.numpy())
    48. # 4.可视化特征图
    49. figure = plt.figure()
    50. for i in range(len(processed_data)):
    51. x = figure.add_subplot(1, 2, i + 1)
    52. x.imshow(processed_data[i])
    53. x.set_title(names[i].split('(')[0])
    54. plt.show()
    55. if __name__ == '__main__':
    56. main()

  • 相关阅读:
    2023年黑客零基础从入门到精通学习成长路线(超多图、非常详细),看完这一篇就够了。
    Mongo 服务器上的 CPU 使用率很高,但 Mongo 似乎处于空闲状态
    小谈设计模式(1)—总序
    多线程C++更新MYSQL
    在启智平台上安装anconda(启智平台中新建调试任务,选的基础镜像中有conda的,就无需安装)
    Python 提取PDF文本和图片
    瑞吉外卖(28)- 用户下单功能开发(功能完结篇)
    UI自动化定位利器-xpath实战
    Java18新特性
    Windows虚拟机部署Docker
  • 原文地址:https://blog.csdn.net/qq_61706112/article/details/132858215