《PyTorch深度学习实践》学习笔记:卷积神经网络(基础篇)

文章目录

  • 1. 全连接神经网络与卷积神经网络
  • 2. 图像的本质
  • 3. 卷积运算
    • 3.1 单通道卷积运算
    • 3.2 三通道卷积运算
    • 3.3 卷积层其他的权重
  • 4. 池化运算(下采样)
  • 5. 实现简单的卷积神经网络
  • 6. 卷积神经网络实现MINST数据集分类
    • 6.1 数据集
    • 6.2 准备网络模型
    • 6.3 损失函数和优化器
    • 6.4 训练和测试
  • 7. 完整代码


1. 全连接神经网络与卷积神经网络

《PyTorch深度学习实践》学习笔记:卷积神经网络(基础篇)_第1张图片
之前我们学习的网络为全连接神经网络,一层一层的全部连接,也就是前一层的每一个节点都会和后面一层的所有节点进行连接。

全连接网络在数值计算的时候,会把信息拉成一维的,这样会丧失掉图片特征中的一些空间的信息。而卷积神经网络可以很好的保留图像的空间特征。

卷积神经网络的基本工作方式:
《PyTorch深度学习实践》学习笔记:卷积神经网络(基础篇)_第2张图片
输入一张图像,先进行卷积操作,然后通过Subsampling下采样减少元素数量,降低运算的需求。 最终为了实现分类,输出还是一个10维的向量。中间的过程可以采样不同的方式。

总的来看,首先经过卷积层,进行特征提取,经过特征提取之后,图片信息变成了一个向量;而后将向量接入一个全连接网络进行分类处理。

卷积和下采样称为特征提取器,全连接层作为分类器。


2. 图像的本质

《PyTorch深度学习实践》学习笔记:卷积神经网络(基础篇)_第3张图片
图像是一种栅格图像,每一个格子代表一个像素。

3. 卷积运算

3.1 单通道卷积运算

如图所示,选择 1 x 5 x 5 的单通道图像,3 x 3 的卷积核,进行卷积运算:
《PyTorch深度学习实践》学习笔记:卷积神经网络(基础篇)_第4张图片
《PyTorch深度学习实践》学习笔记:卷积神经网络(基础篇)_第5张图片
步骤:先在输入图像中,画出一个卷积核大小的(3x3)的窗口,而后将该窗口与卷积核做数乘+求(对应元素相乘);然后将该窗口从左往右、从上到下做遍历,每一次都进行数乘求和运算,最终由这些数乘求和数值组成的矩阵,就是卷积后的结果。

3.2 三通道卷积运算

对于输入图像,每一个通道都会配一个卷积核,也就是输入图像的通道数等于卷积核的通道数。每个通道根据上面讲的单通道的计算方式计算,得到一个矩阵,一共可以得到三个矩阵,将这三个矩阵求和,最终得到的结果就是三通道卷积的结果。
《PyTorch深度学习实践》学习笔记:卷积神经网络(基础篇)_第6张图片
《PyTorch深度学习实践》学习笔记:卷积神经网络(基础篇)_第7张图片
可以看到,只有一个卷积核,最终输出的是一个通道的结果。怎么输出多个通道呢?

单通道输出
《PyTorch深度学习实践》学习笔记:卷积神经网络(基础篇)_第8张图片
多通道输出

注意:输入图像的通道数和卷积核的通道数一样,而卷积核的个数和输出图像的通道数一样。
《PyTorch深度学习实践》学习笔记:卷积神经网络(基础篇)_第9张图片
构建一个卷积层,权重表示:
《PyTorch深度学习实践》学习笔记:卷积神经网络(基础篇)_第10张图片
在pytorch里面,卷积核kernel_size = 常数,代表是一个常数x常数的卷积核,而kernel_size也可以设置为一个元组,比如kernel_size=(5,3)代表卷积核的大小为长方形5x3,但是我们经常使用的卷积核还是kernel_size=3,代表3x3这样的卷积核。
《PyTorch深度学习实践》学习笔记:卷积神经网络(基础篇)_第11张图片
定义一个卷积层:输入通道、输出通道、卷积核大小。

3.3 卷积层其他的权重

填充padding:例如我们输入一个5x5大小的输入图像,通过3x3的卷积核进行卷积,此时输出图像为3x3。但是此时我们想要输出图像的大小和输入图像的大小是一样大,此时我们就需要进行对输入图像进行填充,padding = 3/2 = 1,此时就需要在输入图像填充一圈使其变成7x7。假如我们使用5x5大小的卷积核进行卷积,然后要求输出图像大小等于输入图像大小,此时我们需要填充padding = 5/2 = 2,填充2圈,使得原图像变成9x9。
《PyTorch深度学习实践》学习笔记:卷积神经网络(基础篇)_第12张图片
填充默认情况都是进行填充0。

代码实现:
《PyTorch深度学习实践》学习笔记:卷积神经网络(基础篇)_第13张图片
B:batch_size
C: 通道数
W:图像或卷积核的宽度
H:图像或卷积核的高度
O: 输出通道数
I:输入通道数

stride:步长,就是卷积核窗口在遍历图像时,每走一步的步长。
《PyTorch深度学习实践》学习笔记:卷积神经网络(基础篇)_第14张图片
《PyTorch深度学习实践》学习笔记:卷积神经网络(基础篇)_第15张图片
从左到右、从上到下都是每次移动两步。这个可以有效地降低特征图的宽度和高度。
《PyTorch深度学习实践》学习笔记:卷积神经网络(基础篇)_第16张图片
代码实现:
《PyTorch深度学习实践》学习笔记:卷积神经网络(基础篇)_第17张图片

4. 池化运算(下采样)

池化运算常用的是最大池化,它是没有权重的,2x2的池化默认stride=2。做最大池化,只是在一个通道内进行,不同的通道不会最大池化。
《PyTorch深度学习实践》学习笔记:卷积神经网络(基础篇)_第18张图片
所以说,做最大池化,通道的数量不会发生变化,只是2x2的最大池化,图像的大小会变为原来的一半。

代码实现:
《PyTorch深度学习实践》学习笔记:卷积神经网络(基础篇)_第19张图片

5. 实现简单的卷积神经网络

《PyTorch深度学习实践》学习笔记:卷积神经网络(基础篇)_第20张图片
步骤:

1.选择 5 x 5 的卷积核,输入通道为 1,输出通道为 10:此时图像矩阵经过 5 x 5 的卷积核后会小两圈,也就是4个数位,变成 24 x 24,输出通道为10;
2. 选择 2 x 2 的最大池化层:此时图像大小缩短一半,变成 12 x 12,通道数不变;
3. 再次经过 5 x 5 的卷积核,输入通道为 10,输出通道为 20:此时图像再小两圈,变成 8 *8,输出通道为20;
4. 再次经过 2 x 2 的最大池化层:此时图像大小缩短一半,变成 4 x 4,通道数不变;
5. 最后将图像整型变换成向量,输入到全连接层中:输入一共有 4 x 4 x 20 = 320 个元素,输出为 10.

5x5的卷积核就是少两圈,也就是图像大小-4。
《PyTorch深度学习实践》学习笔记:卷积神经网络(基础篇)_第21张图片
《PyTorch深度学习实践》学习笔记:卷积神经网络(基础篇)_第22张图片
这个网络模型还可以迁移到GPU上面进行训练:
《PyTorch深度学习实践》学习笔记:卷积神经网络(基础篇)_第23张图片
此外,还将输入的数据放到同一块显卡上。
《PyTorch深度学习实践》学习笔记:卷积神经网络(基础篇)_第24张图片
在测试里面,把测试数据也可以放到显卡上。
《PyTorch深度学习实践》学习笔记:卷积神经网络(基础篇)_第25张图片

6. 卷积神经网络实现MINST数据集分类

6.1 数据集

# 准备数据集
batch_size = 64
transform = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize(mean=[0.1307,],std=[0.3081,])
])
train_dataset = datasets.MNIST(root="../dataset/mnist/",train=True,transform=transform,download=True)
test_dataset = datasets.MNIST(root="../dataset/mnist/",train=False,transform=transform,download=True)

train_dataloader = DataLoader(dataset=train_dataset,batch_size=batch_size,shuffle=True)
test_dataloader = DataLoader(dataset=test_dataset,batch_size=batch_size,shuffle=True)

6.2 准备网络模型

# 网络模型
class Model(nn.Module):
    def __init__(self):
        super(Model, self).__init__()
        self.conv1 = nn.Conv2d(1,10,kernel_size=5)
        self.conv2 = nn.Conv2d(10,20,kernel_size=5)
        self.pooling = nn.MaxPool2d(2)
        self.fc = nn.Linear(320,10)

    def forward(self,x):
        # Flatten data from (n,1,28,28) to (n,784)
        x = f.relu(self.conv1(x))
        # batch_size = x.size(0)
        x = self.pooling(x)
        x = f.relu(self.conv2(x))
        x = self.pooling(x)
        x = x.view(x.size()[0],-1)
        x = self.fc(x)
        return x
        # x = f.relu(self.pooling(self.conv1(x)))
        # x = f.relu(self.pooling(self.conv2(x)))
        # x = x.view(x.size(0), -1)
        # x = self.fc(x)
        # return x
model = Model()
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
model.to(device)

6.3 损失函数和优化器

# 优化器和损失函数
creation = nn.CrossEntropyLoss(reduction='mean')
optimizer = optim.SGD(model.parameters(),lr = 0.01,momentum=0.5)

6.4 训练和测试

# 训练
def train(epoch):
    running_loss = 0.0
    # for epoch in range(10):
    for i, data in enumerate(train_dataloader, 0):
        input, target = data
        input, target = input.to(device),target.to(device)
        y_pred = model(input)
        loss = creation(y_pred, target)
        # print(i+1,epoch+1,loss.item())
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

        running_loss += loss.item()
        if i % 300 == 299:
            print("{} {} loss:{:.3f}".format(epoch + 1, i + 1, running_loss / 300))
            running_loss = 0.0
# 测试
def test():
    total = 0
    correct = 0
    with torch.no_grad():
        for i,data in enumerate(test_dataloader,0):
            input,target = data
            input, target = input.to(device), target.to(device)
            y_pred = model(input)
            predicted = torch.argmax(y_pred.data,dim=1)
            total += target.size(0)
            correct += (predicted==target).sum().item()
        print("Accuracy on test set:{:.2f} %".format(100*correct/total))

7. 完整代码

import torch
import torch.nn as nn
from torchvision import transforms
from torchvision import datasets
from torch.utils.data import DataLoader
import torch.nn.functional as f
import torch.optim as optim
import matplotlib.pyplot as plt

# 准备数据集
batch_size = 64
transform = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize(mean=[0.1307,],std=[0.3081,])
])
train_dataset = datasets.MNIST(root="../dataset/mnist/",train=True,transform=transform,download=True)
test_dataset = datasets.MNIST(root="../dataset/mnist/",train=False,transform=transform,download=True)

train_dataloader = DataLoader(dataset=train_dataset,batch_size=batch_size,shuffle=True)
test_dataloader = DataLoader(dataset=test_dataset,batch_size=batch_size,shuffle=True)

# 网络模型
class Model(nn.Module):
    def __init__(self):
        super(Model, self).__init__()
        self.conv1 = nn.Conv2d(1,10,kernel_size=5)
        self.conv2 = nn.Conv2d(10,20,kernel_size=5)
        self.pooling = nn.MaxPool2d(2)
        self.fc = nn.Linear(320,10)

    def forward(self,x):
        # Flatten data from (n,1,28,28) to (n,784)
        x = f.relu(self.conv1(x))
        # batch_size = x.size(0)
        x = self.pooling(x)
        x = f.relu(self.conv2(x))
        x = self.pooling(x)
        x = x.view(x.size()[0],-1)
        x = self.fc(x)
        return x
        # x = f.relu(self.pooling(self.conv1(x)))
        # x = f.relu(self.pooling(self.conv2(x)))
        # x = x.view(x.size(0), -1)
        # x = self.fc(x)
        # return x

model = Model()
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
model.to(device)
# 优化器和损失函数
creation = nn.CrossEntropyLoss(reduction='mean')
optimizer = optim.SGD(model.parameters(),lr = 0.01,momentum=0.5)

# 训练
epoch_list = []
def train(epoch):
    running_loss = 0.0
    epoch_list.append(epoch+1)
    # for epoch in range(10):
    for i, data in enumerate(train_dataloader, 0):
        input, target = data
        input, target = input.to(device),target.to(device)
        y_pred = model(input)
        loss = creation(y_pred, target)
        # print(i+1,epoch+1,loss.item())
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

        running_loss += loss.item()
        if i % 300 == 299:
            print("{} {} loss:{:.3f}".format(epoch + 1, i + 1, running_loss / 300))
            running_loss = 0.0
# 测试
accuracy_list = []
def test():
    total = 0
    correct = 0
    with torch.no_grad():
        for i,data in enumerate(test_dataloader,0):
            input,target = data
            input, target = input.to(device), target.to(device)
            y_pred = model(input)
            predicted = torch.argmax(y_pred.data,dim=1)
            total += target.size(0)
            correct += (predicted==target).sum().item()
        accuracy = correct/total
        accuracy_list.append(accuracy)
        print("Accuracy on test set:{:.2f} %".format(100*correct/total))

if __name__ == '__main__':
    for epoch in range(10):
        train(epoch)
        test()

#画图
plt.plot(epoch_list,accuracy_list)
plt.xlabel('epoch')
plt.ylabel('accuracy')
plt.show()

输出结果
《PyTorch深度学习实践》学习笔记:卷积神经网络(基础篇)_第26张图片
《PyTorch深度学习实践》学习笔记:卷积神经网络(基础篇)_第27张图片
模型改变:

# 网络模型
class Model(nn.Module):
    def __init__(self):
        super(Model, self).__init__()
        self.conv1 = nn.Conv2d(1,16,kernel_size=3) #   (1,28,28) to (16,26,26)
        self.conv2 = nn.Conv2d(16,32,kernel_size=3) #  (16,13,13) to (32,11,11)
        self.conv3 = nn.Conv2d(32,64,kernel_size=3) # (32,5,5) to (64,3,3)
        self.pooling = nn.MaxPool2d(2)
        self.fc1 = nn.Linear(64*1*1,32)
        self.fc2 = nn.Linear(32,16)
        self.fc3 = nn.Linear(16,10)

    def forward(self,x):
        # Flatten data from (n,1,28,28) to (n,784)
        x = f.relu(self.conv1(x))
        # batch_size = x.size(0)
        x = self.pooling(x)
        x = f.relu(self.conv2(x))
        x = self.pooling(x)
        x = f.relu(self.conv3(x))
        x = self.pooling(x)
        x = x.view(x.size()[0],-1)
        x = self.fc1(x)
        x = self.fc2(x)
        x = self.fc3(x)
        return x
        # x = f.relu(self.pooling(self.conv1(x)))
        # x = f.relu(self.pooling(self.conv2(x)))
        # x = x.view(x.size(0), -1)
        # x = self.fc(x)
        # return x

输出结果:
《PyTorch深度学习实践》学习笔记:卷积神经网络(基础篇)_第28张图片
经过三层的卷积进行特征提取,可以发现准确前面上升的比之前更加快,但是总体上最终的准确率变化不大,还可以对网络模型进行不断地改进。

你可能感兴趣的:(pytorch,深度学习,cnn,pytorch)