图像基本概念图像是由像素点组成的每个像素点的取值范围为: [0, 255] 。像素值越接近于0颜色越暗接近于黑色像素值越接 近于255颜色越亮接近于白色。在深度学习中我们使用的图像大多是彩色图彩色图由RGB3个通道组成如下图所示import numpy as np import matplotlib.pyplot as plt def test01(): # 全0数组是黑色的图像 img np.zeros([200, 200, 3]) plt.imshow(img) plt.show() # 全255数组是白色的图像 img np.full([200, 200, 3], 255) plt.imshow(img) plt.show() # 读取图像展示 img plt.imread(data/img.jpg) print(image shape: , img.shape) plt.imshow(img) plt.axis(off) plt.show() test01()CNN概述卷积神经网络Convolutional Neural Network是含有卷积层的神经网络. 卷积层的作用就是用来自动学习、提取图 像的特征。CNN网络主要由三部分构成卷积层、池化层和全连接层构成1. 卷积层负责提取图像中的局部特征2. 池化层用来大幅降低参数量级(降维)3. 全连接层用来输出想要的结果。卷积计算1. input 表示输入的图像2. filter 表示卷积核, 也叫做卷积核(滤波矩阵)3. input 经过 filter 得到输出为最右侧的图像该图叫做特征图卷积运算本质上就是在卷积核和输入数据的局部区域间做点积。最终的特征图结果为:Padding通过上面的卷积计算过程最终的特征图比原始图像小很多如果想要保持经过卷积后的图像大小不变, 可以在原图周围 添加padding 来实现.Stride按照步长为1来移动卷积核计算特征图如下所示如果把Stride 增大为2也是可以提取特征图的如下图所示多通道卷积计算实际中的图像都是多个通道组成的我们怎么计算卷积呢如下图所示:多卷积核卷积计算特征图大小输出特征图的大小与以下参数息息相关:1. size: 卷积核/过滤器大小一般会选择为奇数比如有1*1 、3*3、5*52. Padding: 零填充的方式3. Stride: 步长那计算方法如下图所示:1. 输入图像大小: W x W2. 卷积核大小: F x F3. Stride: S4. Padding: P5. 输出图像大小: N x N以下图为例:1. 图像大小: 5 x 52. 卷积核大小: 3 x 33. Stride: 14. Padding: 15. (5 - 3 2) / 1 1 5, 即得到的特征图大小为: 5 x 5PyTorch卷积层APIimport torch import torch.nn as nn import matplotlib.pyplot as plt def test(): # 读取图像形状640,640,3 img plt.imread(data/img.jpg) plt.imshow(img) plt.axis(off) plt.show() # 构建卷积层 # out_channels表示卷积核个数 # 修改out_channels,stride,padding观察特征图耳朵变化情况 conv nn.Conv2d( in_channels3, out_channels3, kernel_size3, stride2, padding0 ) # 输入形状BatchSize, Channel, Height, Width # img形状torch.Size([3,640,640]) img torch.tensor(img).permute(2, 0, 1) # img形状torch.Size([1,3,640,640]) img img.unsqueeze(0) # 将图像送入卷积层中 feature_map_img conv(img.to(torch.float32)) # 打印特征图的形状,torch.Size([1, 3, 319, 319]) print(feature_map_img.shape) test()池化层计算池化层(Pooling) 降低维度, 缩减模型大小提高计算速度。StridePadding多通道池化层计算PyTorch池化API层import torch import torch.nn as nn def test01(): # 定义输入数据[1,3,3] inputs torch.tensor([[[0, 1, 2], [3, 4, 5], [6, 7, 8]]]).float() # 修改stridepadding观察效果 # 1.最大池化层 polling nn.MaxPool2d(kernel_size2, stride1, padding0) output polling(inputs) print(最大池化层: \n, output) # 2. 平均池化 polling nn.AvgPool2d(kernel_size2, stride1, padding0) output polling(inputs) print(平均池化\n, output) test01()最大池化层: tensor([[[4., 5.], [7., 8.]]]) 平均池化 tensor([[[2., 3.], [5., 6.]]])卷积神经网络案例咱们使用前面的学习到的知识来构建一个卷积神经网络, 并训练该网络实现图像分类. 要完成这个案例咱 们需要学习的内容如下:1. 了解CIFAR10 数据集2. 搭建卷积神经网络3. 编写训练函数4. 编写预测函数CIFAR10 数据集CIFAR-10数据集5万张训练图像、1万张测试图像、10个类别、每个类别有6k个图像图像大小32×32×3。下图列举了 10个类每一类随机展示了10张图片搭建图像分类网络我们要搭建的网络结构如下:我们要搭建的网络结构如下:1. 输入形状: 32x322. 第一个卷积层输入3 个Channel, 输出6 个Channel, Kernel Size 为: 3x33. 第一个池化层输入30x30, 输出15x15, Kernel Size 为: 2x2, Stride 为: 24. 第二个卷积层输入6 个Channel, 输出16 个Channel, Kernel Size 为 3x35. 第二个池化层输入13x13, 输出6x6, Kernel Size 为: 2x2, Stride 为: 26. 第一个全连接层输入576 维, 输出120 维7. 第二个全连接层输入120 维, 输出84 维8. 最后的输出层输入84 维, 输出10 维我们在每个卷积计算之后应用relu激活函数来给网络增加非线性因素。import matplotlib.pyplot as plt import torch import torch.nn as nn from torchvision.datasets import CIFAR10 from torchvision.transforms import ToTensor, Compose from torchsummary import summary from torch.utils.data import DataLoader import time BATCH_SIZE 8 class ImageClassification(nn.Module): def __init__(self): super(ImageClassification, self).__init__() self.conv1 nn.Conv2d(3, 6, stride1, kernel_size3) self.pool1 nn.MaxPool2d(kernel_size2, stride2) self.conv2 nn.Conv2d(6, 16, stride1, kernel_size3) self.pool2 nn.MaxPool2d(kernel_size2, stride2) self.linear1 nn.Linear(576, 120) self.linear2 nn.Linear(120, 84) self.out nn.Linear(84, 10) def forward(self, x): # 卷积relu池化 x torch.relu(self.conv1(x)) x self.pool1(x) # 卷积relu池化 x torch.relu(self.conv2(x)) x self.pool2(x) # 将特征图做成以为向量的形式相当于特征向量 x x.reshape(x.size(0), -1) # 全连接层 x torch.relu(self.linear1(x)) x torch.relu(self.linear2(x)) # 返回输出结果 return self.out(x) def create_dataset(): train CIFAR10(rootdata, trainTrue, transformCompose([ToTensor()])) test CIFAR10(rootdata, trainFalse, transformCompose([ToTensor()])) return train, test def train(model, train_dataset): # 构建损失函数 criterion nn.CrossEntropyLoss() # 构建优化方法 optimizer torch.optim.Adam(model.parameters(), lr1e-3) # 训练100轮 epoch 100 for epoch_idx in range(epoch): dataloader DataLoader(train_dataset, batch_sizeBATCH_SIZE, shuffleTrue) sam_num 0 total_loss 0.0 start time.time() for x, y in dataloader: output model(x) # 计算损失 loss criterion(output, y) # 梯度清零 optimizer.zero_grad() loss.backward() optimizer.step() total_loss loss.item() sam_num 1 print(epoch:, epoch_idx 1, loss:, total_loss / sam_num, , time.time() - start) # 模型保存 torch.save(model.state_dict(), data/image_classification.pth) if __name__ __main__: train_dataset, test_dataset create_dataset() print(数据集类别, train_dataset.class_to_idx) print(训练集数据集, train_dataset.data.shape) print(测试集数据集, test_dataset.data.shape) # 数据集类别 {airplane: 0, automobile: 1, bird: 2, cat: 3, deer: 4, # dog: 5, frog: 6, horse: 7, ship: 8, truck: 9} # 训练集数据集 (50000, 32, 32, 3) # 测试集数据集 (10000, 32, 32, 3) plt.figure(figsize(2, 2)) plt.imshow(train_dataset.data[1]) plt.title(train_dataset.targets[1]) plt.show() model ImageClassification() summary(model, input_size(3, 32, 32), batch_size1) train(model, train_dataset)