Pytorch深度学习实践(9)卷积神经网络

卷积神经网络

全连接神经网络

神经网络中全部是线性模型,是由线性模型串联起来的

全连接网络又叫全连接层

卷积神经网络

在全连接神经网络中,由于输入必须是一维向量,因此在处理图像时必须要对图像矩阵进行拉伸成一维的形式,这必然会导致损失一些空间信息

为了保证空间信息的完整性,因此我们需要使用卷积神经网络,直接出入图片,进行模型训练

基本步骤如下:

输入 – 卷积 – 下采样 – 卷积 – 下采样 – 全连接层 – 输出

在这里插入图片描述

其中,卷积和下采样工作称为特征提取 feature extraction,全连接层的工作叫做分类器 classification

图像

图像分为三个维度:

  • 通道(rgb

即表示为 C × H × W C×H×W C×H×W

卷积的运算

单通道卷积

在输入中,拿出和卷积核大小一致的矩阵,与卷积核进行数乘,让后放到输出的第一个单元格内
在这里插入图片描述

然后使用卷积核依次对输入进行遍历,最终填满所有的输出

在这里插入图片描述

多通道卷积

每一个通道都配有一个卷积核,对每个通道进行卷积操作,最后把所有通道的输出进行相加,得到最终的输出

原始图像几个通道,卷积核就要有几层

在这里插入图片描述

对于多通道图像,图像可以看作是立体的,卷积核也可以看作是立体的,经过卷积之后把各通道的输出相加,最终得到一个二维的张量
在这里插入图片描述

为了在训练过程中使得输出也具有多个通道,因此使用多个3维的卷积核

在这里插入图片描述

卷积层的设计

卷积核

三要素:

  • 输入的通道数
  • 输出的通道数
  • 卷积核尺寸的大小
# 实例化卷积层
conv_layer = torch.nn.Conv2d(in_channels, out_channels, kernel_size = kernel_size)
# 设置卷积核权重 (batch_sie, channel, w, h) = (1, 1, 3, 3)
kernel = torch.Tensor([1, 2, 3, 4, 5, 6, 7, 8, 9]).view(1, 1, 3, 3)
conv_layer.weight.data = kernel.data

通过卷积核后输出的大小: m × n × k e r n e l _ s i z e w i d t h × k e r n e l _ s i z e h e i g h t m×n×kernel\_size_{width}×kernel\_size_{height} m×n×kernel_sizewidth×kernel_sizeheight

其中, m m m为批量 b a t c h batch batch大小, n n n为通道数

padding填充

通过设置padding,即对原始图像进行填充,进而控制输出的大小,填充的部分一般默认用0代替

在这里插入图片描述

一般来说,如果卷积核是 3 × 3 3×3 3×3,则padding一圈,如果卷积核是 5 × 5 5×5 5×5,则padding两圈

卷积核大小为 n × n,则padding n / 2 n / 2 n/2(整除)圈

conv_layer = torch.nn.Conv2d(in_channels,  # 输入通道数
                             out_channels, # 输出通道数
                             kernel_size = kernel_size, # 卷积核大小
                             padding = 1,  # 填充层数
                             bias = False) # 不使用偏置

stride步长

每次遍历原始图像时的步长,可以有效地降低图像的宽度和高度

conv_layer = torch.nn.Conv2d(1, 1,
                             kernel_size = 3, # 卷积核大小
                             padding = 1,  # 填充层数
                             stride=2,  #步长
                             bias = False) # 不使用偏置

下采样

一般使用最大池化层,即MaxPooling

最大池化层步长默认大小为 2 × 2 2×2 2×2

先将输入按照步长大小分割,形成多个部分,然后再在各个部分中取最大值,作为输出
在这里插入图片描述

maxpooling_layer = torch.nn.MaxPool2d(kernel_size=2)

代码实战

使用卷积神经网络处理MNIST

构造卷积神经网络如下所示:
在这里插入图片描述

  • 卷积层不需要知道输入输出的大小
  • 但最后的全连接层(线性模型)需要定义输出输出的大小

在这里插入图片描述

不使用GPU版本

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

########## 准备数据集 ##########
batch_size = 64
## 实例化转换器
transform = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize((0.1307,), (0.3081,))
])
train_dataset = datasets.MNIST(root='./dataset/mnist/',
                               train=True,
                               download=False,
                               transform=transform)
train_loader = DataLoader(train_dataset,
                          shuffle=True,
                          batch_size=batch_size)
test_dataset = datasets.MNIST(root='./dataset/mnist/',
                              train=False,
                              download=False,
                              transform=transform)
test_loader = DataLoader(test_dataset, batch_size=batch_size)

########## 定义模型 ##########
class Net(torch.nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = torch.nn.Conv2d(1, 10, kernel_size=5) # 卷积层1
        self.conv2 = torch.nn.Conv2d(10, 20, kernel_size=5) # 卷积层2
        self.pooling = torch.nn.MaxPool2d(2)  # 池化层
        self.fc = torch.nn.Linear(320, 10)  # 全连接层

    def forward(self, x):
        batch_size = x.size(0)
        ## 先输入卷积层 在输入池话层 最后输入到relu中做非线性变换
        # 1
        x = F.relu(self.pooling(self.conv1(x)))
        # 2
        x = F.relu(self.pooling(self.conv2(x)))
        ## 全连接层
        # 先把输入平铺 flatten 操作
        x = x.view(batch_size, -1)
        x = self.fc(x)
        return x

model = Net()

########## 损失函数核优化器定义 ##########
criterion = torch.nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(model.parameters(), lr = 0.01, momentum=0.5)

########## 模型训练 ##########
def train(epoch):
    running_loss = 0.0
    for batch_index, data in enumerate(train_loader, 0):
        inputs, target = data
        optimizer.zero_grad()

        # forward
        outputs = model(inputs)
        loss = criterion(outputs, target)
        # backward
        loss.backward()
        # update
        optimizer.step()

        running_loss += loss.item()
        if batch_index % 300 == 299:
            print('[%d %5d] loss: %.3f' % (epoch + 1, batch_index + 1, running_loss / 300))
            running_loss = 0.0

########## 模型测试 ##########
def test():
    correct = 0
    total = 0
    with torch.no_grad():
        for data in test_loader:
            inputs, target = data
            outputs = model(inputs)
            _, predicted = torch.max(outputs.data, dim=1)
            total += target.size(0)
            correct += (predicted == target).sum().item()
    print('Accuracy on test set: %d %%' % (100 * correct / total))
    return 100 * correct / total

######### main ##########
if __name__ == '__main__':
    accuracy_history = []
    epoch_history = []
    for epoch in range(50):
        train(epoch)
        accuracy = test()
        accuracy_history.append(accuracy)
        epoch_history.append(epoch)
    plt.plot(epoch_history, accuracy_history)
    plt.xlabel('epoch')
    plt.ylabel('accuracy(%)')
    plt.show()

使用GPU版本

  • 设置模型训练设备

    device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
    
  • 把模型放入GPU

    model.to(device)
    
  • 把数据放入GPU

    inputs, target = inputs.to(device), target.to(device)
    
import torch
import matplotlib.pyplot as plt
from torchvision import transforms
from torchvision import datasets
from torch.utils.data import DataLoader
import torch.nn.functional as F

########## 准备数据集 ##########
batch_size = 64
## 实例化转换器
transform = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize((0.1307,), (0.3081,))
])
train_dataset = datasets.MNIST(root='./dataset/mnist/',
                               train=True,
                               download=False,
                               transform=transform)
train_loader = DataLoader(train_dataset,
                          shuffle=True,
                          batch_size=batch_size)
test_dataset = datasets.MNIST(root='./dataset/mnist/',
                              train=False,
                              download=False,
                              transform=transform)
test_loader = DataLoader(test_dataset, batch_size=batch_size)

########## 定义模型 ##########
class Net(torch.nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = torch.nn.Conv2d(1, 10, kernel_size=5) # 卷积层1
        self.conv2 = torch.nn.Conv2d(10, 20, kernel_size=5) # 卷积层2
        self.pooling = torch.nn.MaxPool2d(2)  # 池化层
        self.fc = torch.nn.Linear(320, 10)  # 全连接层

    def forward(self, x):
        batch_size = x.size(0)
        ## 先输入卷积层 在输入池话层 最后输入到relu中做非线性变换
        # 1
        x = F.relu(self.pooling(self.conv1(x)))
        # 2
        x = F.relu(self.pooling(self.conv2(x)))
        ## 全连接层
        # 先把输入平铺 flatten 操作
        x = x.view(batch_size, -1)
        x = self.fc(x)
        return x

model = Net()
## 使用gpu
if torch.cuda.is_available():
    print("使用gpu训练")
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
## 将模型放入设备
model.to(device)
########## 损失函数核优化器定义 ##########
criterion = torch.nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(model.parameters(), lr = 0.01, momentum=0.5)

########## 模型训练 ##########
def train(epoch):
    running_loss = 0.0
    for batch_index, data in enumerate(train_loader, 0):
        inputs, target = data
        ## 将数据放入设备
        inputs, target = inputs.to(device), target.to(device)
        optimizer.zero_grad()

        # forward
        outputs = model(inputs)
        loss = criterion(outputs, target)
        # backward
        loss.backward()
        # update
        optimizer.step()

        running_loss += loss.item()
        if batch_index % 300 == 299:
            print('[%d %5d] loss: %.3f' % (epoch + 1, batch_index + 1, running_loss / 300))
            running_loss = 0.0

########## 模型测试 ##########
def test():
    correct = 0
    total = 0
    with torch.no_grad():
        for data in test_loader:
            inputs, target = data
            ## 将数据放入设备
            inputs, target = inputs.to(device), target.to(device)
            outputs = model(inputs)
            _, predicted = torch.max(outputs.data, dim=1)
            total += target.size(0)
            correct += (predicted == target).sum().item()
    print('Accuracy on test set: %d %%' % (100 * correct / total))
    return 100 * correct / total

######### main ##########
if __name__ == '__main__':
    accuracy_history = []
    epoch_history = []
    for epoch in range(50):
        train(epoch)
        accuracy = test()
        accuracy_history.append(accuracy)
        epoch_history.append(epoch)
    plt.plot(epoch_history, accuracy_history)
    plt.xlabel('epoch')
    plt.ylabel('accuracy(%)')
    plt.show()

在这里插入图片描述

  • 7
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值