读书笔记-深度学习入门之pytorch-第四章(含卷积神经网络实现手写数字识别)(详解)

1、卷积神经网络在图片识别上的应用

(1)局部性:对一张照片而言,需要检测图片中的局部特征来决定图片的类别

(2)相同性:可以用同样的模式去检测不同照片的相同特征,只不过这些特征处于图片中不同的位置,但是特征检测所做的操作是不变的

(3)不变性:对于一张大图片,如果我们进行下采样,图片的性质基本保持不变

2、全连接神经网络处理大尺寸图像的缺点:

(1)首先将图像展开为向量会丢失空间信息;

(2)其次参数过多效率低下,训练困难;

(3)同时大量的参数也很快会导致网络过拟合。

3、卷积神经网络

主要由这几类层构成:输入层、卷积层,ReLU层、池化(Pooling)层和全连接层

(1)卷积层的作用:做特征提取

 只需要定义移动的步长,我们就可以遍历图像中的所有点,比如定义步长为1,遍历过程如下图所示

上述过程是基于无填充的情况,在有填充的情况下,对于图像边缘的点,会用0填充,示意如下

遍历所有点从而得到一张新的图,这样的图称之为特征图,示例如下

所以卷积层是用来做特征提取的。

(2)池化层作用:(下采样计数)

去除特征图中的冗余信息,降低特征图的维度,减少网络中参数的数量,有效控制过拟合

参考博文:卷积神经网络(CNN)详解 - 知乎

卷积和池化简单介绍_BEIERMODE666的博客-CSDN博客_池化索引

4、卷积神经网络实现手写数字识别

(1)CNN

import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torchvision import datasets, transforms
import torchvision
from torch.autograd import Variable
from torch.utils.data import DataLoader
import cv2

# 数据集加载
train_dataset = datasets.MNIST(
    root='./num/',
    train=True,
    transform=transforms.ToTensor(),
    download=True
)
test_dataset = datasets.MNIST(
    root='./num/',
    train=False,
    transform=transforms.ToTensor(),
    download=True
)

batch_size = 64

train_loader = torch.utils.data.DataLoader(
    dataset=train_dataset,
    batch_size=batch_size,
    shuffle=True
)

test_loader = torch.utils.data.DataLoader(
    dataset=test_dataset,
    batch_size=batch_size,
    shuffle=True
)

# 单批次数据预览
# 实现单张图片可视化
images, labels = next(iter(train_loader))
img = torchvision.utils.make_grid(images)

img = img.numpy().transpose(1, 2, 0)
std = [0.5, 0.5, 0.5]
mean = [0.5, 0.5, 0.5]
img = img * std + mean
print(labels)
cv2.imshow('win', img)
key_pressed = cv2.waitKey(0)


# 神经网络模块
class CNN(nn.Module):
    def __init__(self):
        super(CNN, self).__init__()
        self.layer1 = nn.Sequential(
            nn.Conv2d(1, 16, kernel_size=3),
            nn.BatchNorm2d(16),
            nn.ReLU(inplace=True)
        )

        self.layer2 = nn.Sequential(
            nn.Conv2d(16, 32, kernel_size=3),
            nn.BatchNorm2d(32),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=2, stride=2)
        )

        self.layer3 = nn.Sequential(
            nn.Conv2d(32, 64, kernel_size=3),
            nn.BatchNorm2d(64),
            nn.ReLU(inplace=True)
        )

        self.layer4 = nn.Sequential(
            nn.Conv2d(64, 128, kernel_size=3),
            nn.BatchNorm2d(128),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=2, stride=2)
        )

        self.fc = nn.Sequential(
            nn.Linear(128 * 4 * 4, 1024),
            nn.ReLU(inplace=True),
            nn.Linear(1024, 128),
            nn.ReLU(inplace=True),
            nn.Linear(128, 10)
        )

    def forward(self, x):
        x = self.layer1(x)
        x = self.layer2(x)
        x = self.layer3(x)
        x = self.layer4(x)
        x = x.view(x.size(0), -1)
        x = self.fc(x)
        return x


# 训练模型
if torch.cuda.is_available():
    device = 'cuda'
else:
    device = "cpu"

net = CNN().to(device)

criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(params=net.parameters(), lr=1e-3)

epoch = 1
if __name__ == '__main__':
    arr_loss = []
    for epoch in range(epoch):
        sum_loss = 0.0
        for i, data in enumerate(train_loader):
            inputs, labels = data
            inputs, labels = Variable(inputs).to(device), Variable(labels).to(device)
            optimizer.zero_grad()  # 将梯度归零
            outputs = net(inputs)  # 将数据传入网络进行前向运算
            loss = criterion(outputs, labels)  # 得到损失函数
            loss.backward()  # 反向传播
            optimizer.step()  # 通过梯度做一步参数更新

            # print(loss)
            sum_loss += loss.item()
            if i % 100 == 99:
                arr_loss.append(sum_loss)
                print('[%d,%d] loss:%.03f' %
                      (epoch + 1, i + 1, sum_loss / 100))
                sum_loss = 0.0
    x = [1,2,3,4,5,6,7,8,9]
    y = arr_loss
    plt.plot(x, y)
    plt.show()
    net.eval()  # 将模型变换为测试模式
    correct = 0
    total = 0
    for data_test in test_loader:
        images, labels = data_test
        images, labels = Variable(images).to(device), Variable(labels).to(device)
        output_test = net(images)
        _, predicted = torch.max(output_test, 1)
        total += labels.size(0)
        correct += (predicted == labels).sum()
    print("correct1: ", correct)
    print("Test acc: {0}".format(correct.item() /
                                 len(test_dataset)))

准确率98.98%

(2)LeNet

class LeNet(nn.Module):
    def __init__(self):
        super(LeNet, self).__init__()
        self.layer1 = nn.Sequential(
            nn.Conv2d(1, 6, 3, padding=1),
            nn.MaxPool2d(2, 2)
        )

        self.layer2 = nn.Sequential(
            nn.Conv2d(6, 16, 5),
            nn.MaxPool2d(2, 2)
        )

        self.layer3 = nn.Sequential(
            nn.Linear(400, 120),
            nn.Linear(120, 84),
            nn.Linear(84, 10)
        )

    def forward(self, x):
        x = self.layer1(x)
        x = self.layer2(x)
        x = x.view(x.size(0), -1)
        x = self.layer3(x)
        return x

准确率:97.22%

(3)AlexNet

class AlexNet(nn.Module):
    def __init__(self):
        super(AlexNet, self).__init__()
        self.layer1 = nn.Sequential(  # 输入1*28*28
            nn.Conv2d(1, 32, kernel_size=3, padding=1),  # 32*28*28
            ######################################################
            # in_channels:输入数据深度
            # out_channels:输出数据深度
            # kernel_size:卷积核大小,也可以表示为(3,2)
            # stride: 滑动步长
            # padding: 是否零填充
            ######################################################
            # nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=2, stride=2),  # 32*14*14

            nn.Conv2d(32, 64, kernel_size=3, padding=1),  # 64*14*14
            # nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=2, stride=2),  # 64*7*7

            nn.Conv2d(64, 128, kernel_size=3, padding=1),  # 128*7*7
            # nn.ReLU(inplace=True),

            nn.Conv2d(128, 256, kernel_size=3, padding=1),  # 256*7*7
            # nn.ReLU(inplace=True),

            nn.Conv2d(256, 256, kernel_size=3, padding=1),  # 257*7*7
            # nn.ReLU(inplace=True),

            nn.MaxPool2d(kernel_size=3, stride=2)  # 256*3*3
        )

        self.layer2 = nn.Sequential(
            nn.Dropout(),
            nn.Linear(256 * 3 * 3, 1024),
            nn.ReLU(inplace=True),

            nn.Dropout(),
            nn.Linear(1024, 512),
            nn.ReLU(inplace=True),
            nn.Linear(512, 10)
        )

    def forward(self, x):
        x = self.layer1(x)
        x = x.view(x.size(0), 256 * 3 * 3)
        x = self.layer2(x)
        return x

准确率:98.25%

(4)VGG

class VGG(nn.Module):
    def __init__(self):
        super(VGG, self).__init__()
        self.layer1 = nn.Sequential(  # 输入1*28*28
            nn.Conv2d(1, 32, kernel_size=3, padding=1),  # 32*28*28
            nn.ReLU(inplace=True),

            nn.Conv2d(32, 32, kernel_size=3, padding=1),  # 32*28*28
            nn.ReLU(True),
            nn.MaxPool2d(kernel_size=2, stride=2),  # 32*14*14

            nn.Conv2d(32, 64, kernel_size=3, padding=1),  # 64*14*14
            nn.ReLU(True),

            nn.Conv2d(64, 64, kernel_size=3, padding=1),  # 64*14*14
            nn.ReLU(True),
            nn.MaxPool2d(kernel_size=2, stride=2),  # 64*7*7

            nn.Conv2d(64, 128, kernel_size=3, padding=1),  # 128*7*7
            nn.ReLU(True),
            nn.Conv2d(128, 128, kernel_size=3, padding=1),  # 128*7*7
            nn.ReLU(True),
            nn.Conv2d(128, 256, kernel_size=3, padding=1),  # 256*7*7
            nn.ReLU(True),
            nn.MaxPool2d(kernel_size=3, stride=2),  # 256*3*3

            
        )

        self.layer2 = nn.Sequential(
            nn.Linear(256 * 3 * 3, 1024),
            nn.ReLU(True),
            nn.Dropout(),

            nn.Linear(1024, 1024),
            nn.ReLU(True),
            nn.Dropout(),

            nn.Linear(1024, 10)
        )

    def forward(self, x):
        x = self.layer1(x)
        x = x.view(x.size(0), 256 * 3 * 3)
        x = self.layer2(x)
        return x

 

 

准确率98.52%

(5)GoogLeNet

class InceptionA(torch.nn.Module):
    def __init__(self,in_channels):
        super(InceptionA,self).__init__()
        self.branch1x1 = torch.nn.Conv2d(in_channels,16,kernel_size=1)
 
        self.branch5x5_1 = torch.nn.Conv2d(in_channels,16,kernel_size=1)
        self.branch5x5_2 = torch.nn.Conv2d(16,24,kernel_size=5,padding=2)
 
        self.branch3x3_1 = torch.nn.Conv2d(in_channels,16,kernel_size=1)
        self.branch3x3_2 = torch.nn.Conv2d(16,24,kernel_size=3,padding=1)
        self.branch3x3_3 = torch.nn.Conv2d(24,24,kernel_size=3,padding=1)
 
        # self.branch_pool_1 = torch.nn.functional.avg_pool2d(in_channels,kernel_size=3,stride=1,padding=1)
        self.branch_pool_2 = torch.nn.Conv2d(in_channels,24,kernel_size=1)
 
    def forward(self,x):
        branch1x1 = self.branch1x1(x)
        branch5x5_1 = self.branch5x5_1(x)
        branch5x5_2= self.branch5x5_2(branch5x5_1)
 
        branch3x3_1 = self.branch3x3_1(x)
        branch3x3_2 = self.branch3x3_2(branch3x3_1)
        branch3x3_3 = self.branch3x3_3(branch3x3_2)
 
 
        branch_pool_1 = F.avg_pool2d(x, kernel_size=3, stride=1, padding=1)
        branch_pool_2 = self.branch_pool_2(branch_pool_1)
 
        outputs = torch.cat([branch1x1,branch5x5_2,branch3x3_3,branch_pool_2],dim=1)
 
        return outputs
 
 
class Net(torch.nn.Module):
    def __init__(self):
        super(Net,self).__init__()
        self.conv1 = torch.nn.Conv2d(1,10,kernel_size=5)
        self.conv2 = torch.nn.Conv2d(88,20,kernel_size=5)
 
 
        self.incep1 = InceptionA(in_channels=10)
        self.incel2 = InceptionA(in_channels=20)
 
        self.mp = torch.nn.MaxPool2d(2)
        self.fc = torch.nn.Linear(1408,10)
 
    def forward(self,x):
        batch_size = x.size(0)
        x = F.relu(self.mp(self.conv1(x)))#1 =》10
        x = self.incep1(x) #10 => 88
        x = F.relu(self.mp(self.conv2(x)))
        x = self.incel2(x)
        x = x.view(batch_size,-1)
        x = self.fc(x)
        return x

 准确率:97.35%

  • 1
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 好的,第4的任务是使用pytorch搭建卷积神经网络识别手写数字。这个任务需要掌握pytorch的基本操作和卷积神经网络的原理,同时需要对手写数字数据集有一定的了解。通过这个任务,可以深入理解卷积神经网络在图像识别中的应用。 ### 回答2: 随着机器学习和人工智能技术的发展,卷积神经网络成为了图像识别领域的重要工具。PyTorch是流行的深度学习框架之一,可以方便地搭建神经网络模型,特别是卷积神经网络模型。 搭建卷积神经网络识别手写数字的步骤如下: 一、准备数据 我们需要手写数字的数据集,可以使用MNIST数据集,该数据集包括60,000个训练图像和10,000个测试图像。 二、定义模型 我们可以使用PyTorch提供的nn模块定义卷积神经网络模型。其中包括卷积层、池化层和全连接层等,还有激活函数、批量归一化等常见的组件。 三、训练模型 我们需要选择优化算法,例如随机梯度下降(SGD)、Adam等,然后根据训练数据进行训练。这个过程中需要定义损失函数,例如交叉熵损失函数。 四、测试模型 我们可以使用测试数据进行模型测试,计算分类准确率等指标。 代码演示: 以下是一个简单的卷积神经网络的代码示例,用于识别手写数字: ```python import torch import torch.nn as nn import torch.utils.data as Data import torchvision from torchvision import transforms # 定义数据处理方式 transform = transforms.Compose([ transforms.ToTensor(), # 将图片转换为Tensor transforms.Normalize((0.1307,), (0.3081,)) # 标准化 ]) # 准备数据集 train_set = torchvision.datasets.MNIST( root='./data/', train=True, transform=transform, download=True ) train_loader = Data.DataLoader( dataset=train_set, batch_size=64, shuffle=True ) test_set = torchvision.datasets.MNIST( root='./data/', train=False, transform=transform, download=True ) test_loader = Data.DataLoader( dataset=test_set, batch_size=64, shuffle=True ) # 定义卷积神经网络模型 class CNN(nn.Module): def __init__(self): super(CNN, self).__init__() self.conv1 = nn.Conv2d(1, 32, 3, 1, padding=1) self.conv2 = nn.Conv2d(32, 64, 3, 1, padding=1) self.dropout1 = nn.Dropout2d(0.25) self.dropout2 = nn.Dropout2d(0.5) self.fc1 = nn.Linear(64 * 7 * 7, 128) self.fc2 = nn.Linear(128, 10) def forward(self, x): x = self.conv1(x) x = nn.functional.relu(x) x = self.conv2(x) x = nn.functional.relu(x) x = nn.functional.max_pool2d(x, 2) x = self.dropout1(x) x = torch.flatten(x, 1) x = self.fc1(x) x = nn.functional.relu(x) x = self.dropout2(x) x = self.fc2(x) return nn.functional.log_softmax(x, dim=1) # 定义模型和训练参数 model = CNN() optimizer = torch.optim.Adam(model.parameters(), lr=0.01) criterion = nn.CrossEntropyLoss() # 训练模型 for epoch in range(10): model.train() for batch_idx, (data, target) in enumerate(train_loader): optimizer.zero_grad() output = model(data) loss = criterion(output, target) loss.backward() optimizer.step() # 测试模型 model.eval() test_loss = 0 correct = 0 with torch.no_grad(): for data, target in test_loader: output = model(data) test_loss += criterion(output, target).item() pred = output.argmax(dim=1, keepdim=True) correct += pred.eq(target.view_as(pred)).sum().item() test_loss /= len(test_loader.dataset) print('Epoch {} Test set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)'.format( epoch, test_loss, correct, len(test_loader.dataset), 100. * correct / len(test_loader.dataset))) ``` 这段代码定义了一个简单的卷积神经网络模型,包括两个卷积层、两个池化层和两个全连接层。训练10个epoch后,输出测试集的平均损失和分类准确率。 以上便是使用PyTorch搭建卷积神经网络识别手写数字的简要步骤和代码示例。 ### 回答3: 卷积神经网络是一种广泛应用于图像识别和自然语言处理等领域的深度学习模型。而PyTorch是一个非常优秀的深度学习框架,可以方便地实现卷积神经网络。在本题中,我们将使用PyTorch搭建卷积神经网络识别手写数字。 在使用PyTorch搭建卷积神经网络之前,需要先导入需要的库。这里我们需要导入torch、torchvision和numpy三个库。其中,torch是PyTorch的核心库,torchvision是一些通用的视觉工具集,numpy是Python中处理矩阵和数组的库。导入完成后,我们需要先定义一个卷积神经网络的类,这里我们命名为Net。 Net类中包括了网络的初始化、前向传播、训练和测试四个部分。在初始化中,我们定义了一些卷积层、池化层、全连接层、Dropout层和Batch Normalization层。这些层将构成我们的卷积神经网络。在前向传播中,我们定义了整个网络的逻辑。在训练和测试中,我们使用PyTorch提供的优化器和损失函数来进行训练和测试。 在搭建卷积神经网络之后,我们需要准备手写数字数据集,并进行数据的预处理。这里我们使用了MNIST数据集,该数据集包了一些手写数字的图像数据,每个图像对应一个数字标签。我们使用torchvision中的transforms来对数据进行预处理。预处理的步骤包括将图像转换为PyTorch张量、将像素点的值归一化等。最终我们得到了训练集和测试集两个数据集。 接着,我们需要将数据集输入到卷积神经网络中进行训练和测试。在训练过程中,我们按照批次对数据进行处理,然后将处理后的数据输入到网络中进行训练。在每个批次中,我们会计算模型的损失值,并使用PyTorch提供的优化器来更新网络中的参数。训练过程中,我们还会记录下网络的准确率和损失值等指标。在测试过程中,我们只需要将测试集输入到网络中,然后进行预测即可。最终,我们可以通过输出网络的预测结果来测试模型的准确率。 总的来说,使用PyTorch搭建卷积神经网络识别手写数字的过程包括了数据准备、网络搭建、训练和测试四个步骤。通过不断调整网络中的参数和优化策略,我们可以得到一个表现良好的卷积神经网络来进行手写数字识别任务。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值