深度学习(PyTorch)——卷积神经网络(CNN)基础篇

B站up主“刘二大人”视频 笔记

卷积的概念:
从单通道卷积讲起:即input图像是单通道,卷积核kernel也是单通道,那么输出必然也是单通道。这里还没有讲到扩充padding和滑动步长stride,所以只关注输入和输出矩阵的尺寸大小;

讲到这,刘老师介绍了CCD相机模型,这是一种通过光敏电阻,利用光强对电阻的阻值影响,对应地影响色彩亮度实现不同亮度等级像素采集的原件。三色图像是采用不同敏感度的光敏电阻实现的。

还介绍了矢量图像(也就是PPT里通过圆心、边、填充信息描述而来的图像,而非采集的图像);

接下来讲到三通道input图像的卷积操作:实为将三个通道的input分别与三个通道kernel对应相乘,再将对应位置相加,最后输出单通道output图像的过程;

此处的input、kernel、output的形状,以及通道数channel,是要非常注意的,我们玩卷积神经网络,其中,向的卷积层中传递的参数,与这里的参数一一对应,要非常熟悉每一个参数位置,应该是谁的channel值,后面的full connected layer也是一样,传入的是位置参数,也就是说,每一个位置必须是所需对应的参数,决不能混乱;

在后面讲了三个卷积的基本操作,扩充padding、步长stride和池化pooling:

padding是为了让源图像最外一圈或多圈像素(取决于kernel的尺寸),能够被卷积核中心取到。这里有个描述很重要:想要使源图像(1,1)的位置作为第一个与kernel中心重合,参与计算的像素,想想看padding需要扩充多少层,这样就很好计算了吧;
stride操作指的是每次kernel窗口滑动的步长,默认值当然是1了,插句话,假设不使用扩充padding,output图像的尺寸就会缩小,想要使输出的尺寸与输入尺寸保持不变,看看上一个知识点的padding描述,就很好计算需要外圈加几圈去保证输出的尺寸了吧;

只有一个地方需要特别注意的地方,就是整个网络建立完以后,是不关心输入图像的宽度和高度大小的,也就是说,无论来多大尺寸的图像,我(网络)都能处理,需要改动的仅是Fully Connected Layer(分类器)的输入,需要通过前面最后一层的计算来求得;而FC的输出,是确定的(分10类就输出10)。

程序如下:

import torch
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

# prepare dateset

batch_size = 64
transforms = transforms.Compose([transforms.ToTensor(),  # 把输入的图像转变成张量 通道*宽度*高度,取值在(0,1)
                                 transforms.Normalize((0.1307,), (0.3081,))])  # 归一化,0.1307均值和0.3081方差

train_dataset = datasets.MNIST(root='../dataset/mnist/',
                               train=True,
                               download=True,
                               transform=transforms)
train_loader = DataLoader(train_dataset,
                          shuffle=True,
                          batch_size=batch_size)
test_dataset = datasets.MNIST(root='../dataset/mnist/',
                              train=False,
                              download=True,
                              transform=transforms)
test_loader = DataLoader(train_dataset,
                         shuffle=False,
                         batch_size=batch_size)

# design model using class


class Net(torch.nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = torch.nn.Conv2d(1, 10, kernel_size=5)  # 输入通道1个,输出通道10个,卷积盒的大小为5*5
        self.conv2 = torch.nn.Conv2d(10, 20, kernel_size=5)
        self.pooling = torch.nn.MaxPool2d(2)  # 池化
        self.fc = torch.nn.Linear(320, 10)

    def forward(self, x):
        # flatten data from (n,1,28,28)to(n,784)
        batch_size = x.size(0)  # x.size(0)=n
        x = F.relu(self.pooling(self.conv1(x)))
        x = F.relu(self.pooling(self.conv2(x)))
        x = x.view(batch_size, -1)  # flatten 变成全连接网络所需要的输入
        x = self.fc(x)  # 用全连接层做变换
        return x


model = Net()

'''在显卡上运行'''
# device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
# model.to(device)
'''在显卡上运行'''

# construct loss and optimizer
criterion = torch.nn.CrossEntropyLoss()  # 构造损失函数,交叉熵损失
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.5)  # 构造优化器 lr为学习率,momentum为冲量来优化训练过程

# training cycle forward, backward, update


def train(epoch):
    running_loss = 0.0
    for batch_idx, data in enumerate(train_loader, 0):
        # 获得一个批次的数据和标签
        inputs, target = data

        '''在显卡上运行'''
        # inputs, target = inputs.to(device), target.to(device)
        '''在显卡上运行'''

        optimizer.zero_grad()
        # 获得模型预测的结果(64,10)
        outputs = model(inputs)
        # 交叉熵代价函数outputs(64,10),targe(64)
        loss = criterion(outputs, target)
        loss.backward()
        optimizer.step()

        running_loss += loss.item()
        if batch_idx % 300 == 299:  # 300次迭代输出一次loss
            print('[%d, %5d] loss:%.3f' % (epoch+1, batch_idx+1, running_loss/300))
            running_loss = 0.0


def test():  # 不需要反向传播,只需要正向的
    correct = 0
    total = 0
    with torch.no_grad():  # 不需要计算梯度
        for data in test_loader:
            inputs, labels = data

            '''在显卡上运行'''
            # inputs, target = inputs.to(device), target.to(device)
            '''在显卡上运行'''

            outputs = model(inputs)
            _, predicted = torch.max(outputs.data, dim=1)  # dim=1 列是第0个维度,行是第1个维度,返回值是每一行最大值和每一行最大值下标
            total += labels.size(0)  # labels.size是一个(N,1)的元组,labels.size(0)=N
            correct += (predicted == labels).sum().item()  # 张量之间的比较运算,然后求和取标量
    print('accuracy on test set:%d %% ' % (100 * correct / total))


if __name__ == '__main__':
    epoch_list = []
    acc_list = []
    for epoch in range(10):
        train(epoch)
        acc = test()
        epoch_list.append(epoch)
        acc_list.append(acc)
    plt.plot(epoch_list, acc_list)
    plt.ylabel('accuracy')
    plt.xlabel('epoch')
    plt.show()

运行结果如下:

 

视频截图如下: 

feature extraction(特征提取层):可以通过卷积运算,从而找到输入的某些特征

卷积层可以保留输入数据的空间结构和空间信息

下采样可以减少数据量,降低运算时间和复杂度,防止过拟合

单通道的卷积

 3通道的卷积

输入通道数=卷积核的通道数

 该种类的卷积核个数=输出通道数

 

 

 

 

 

  

 

 

  

 

 用交叉熵损失,因此最后一层不激活

 

 

 

 

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值