24.8.31学习心得

每个输出通道可以识别特定模式,输入通道核识别并组合输入中的模式、

在CNN中,输入数据(如图像)通过多个卷积层进行处理。每个卷积层包含若干个卷积核(也称为滤波器或特征检测器),这些卷积核会在输入数据上滑动,对数据的不同部分执行逐元素的乘法操作,然后将结果相加得到一个输出值。这个过程可以理解为卷积核在寻找输入数据中的特定模式或特征。

  • 输入通道:如果你正在处理的是彩色图像,那么原始输入通常会有三个通道(红、绿、蓝)。每个通道代表了图像的一个方面,例如红色调、绿色调和蓝色调的强度。

  • 输出通道:一个卷积层可以产生多个输出通道,每个输出通道都是由该层的一个卷积核生成的特征图。每个这样的特征图(或激活图)代表了输入数据中不同模式的检测结果。例如,在第一个卷积层中,一些核可能会检测边缘,而另一些可能会检测颜色对比度。

  • 核识别并组合输入中的模式:卷积核通过其权重参数学习如何识别特定模式。随着网络层次的加深,更高级别的特征(如物体的部分或者整个物体)可以通过组合低级别的特征来识别。例如,边缘检测器(低级特征)可以在更高层组合成形状检测器(更高级特征)。

简单来说,这句话的意思是,卷积神经网络中的每个输出通道都对应一个能够识别输入数据中特定模式的卷积核,而这些模式的识别和组合有助于最终的任务(如分类、分割等)。


1x1的卷积层是卷积神经网络中的一种特殊类型的卷积层,它使用尺寸为1x1的卷积核。这种卷积层有以下几个关键作用和特点:

  1. 通道融合:1x1卷积层可以看作是对每个通道进行线性变换,而不改变空间维度(即图像的宽度和高度)。它通过这种方式可以有效地融合通道信息,减少参数数量。

  2. 降维或升维:通过改变1x1卷积层的输出通道数,可以对特征图的通道数进行调整。如果输出通道数少于输入通道数,它可以减少特征图的维度,起到降维的作用;如果输出通道数多于输入通道数,它可以增加特征图的维度,起到升维的作用。

  3. 参数共享:由于卷积核的尺寸很小,1x1卷积层的参数数量相对较少。这意味着在进行卷积操作时,每个输出特征图的每个位置都使用相同的权重,实现了参数共享。

  4. 减少计算量:1x1卷积层可以减少后续层的计算量。通过降维,可以减少后续层需要处理的数据量,从而减少计算复杂度。

  5. 增加非线性:虽然1x1卷积本身是线性操作(等价全连接),但在卷积之后通常会跟一个非线性激活函数(如ReLU),这可以增加网络的非线性能力,提高模型的表达能力。

  6. 网络瓶颈:在某些网络结构中,如Inception网络,1x1卷积层被用作网络的瓶颈层,以减少计算量并提高效率。

  7. 特征融合:在一些高级的网络结构中,1x1卷积层可以用于融合来自不同尺度的特征图,例如在特征金字塔网络(FPN)中,1x1卷积用于融合不同分辨率的特征图。

总的来说,1x1卷积层是一种高效的卷积操作,它在不改变空间维度的情况下,可以对通道进行有效的融合和调整,同时减少计算量和参数数量。


池化层(Pooling Layer)是卷积神经网络(CNN)中的一个重要组成部分,主要用于减少空间维度(宽度和高度),同时保留最重要的特征信息。池化层的主要目的是为了在网络中引入平移不变性,并且减少参数数量,从而降低过拟合的风险。以下是关于池化层的一些关键概念:

主要类型

  1. 最大池化(Max Pooling)

    • 最大池化是最常见的池化方法之一。在这个过程中,网络会选择一个特定大小的窗口(通常是2x2),并在每个窗口内选择最大的值作为输出。例如,如果在一个2x2的最大池化操作中,输入是一个4x4的矩阵,则输出会是一个2x2的矩阵,其中每个元素是从相应的2x2区域中选出的最大值。
    • 最大池化有助于捕捉最显著的特征,并且对噪声相对不敏感
  2. 平均池化(Average Pooling)

    • 平均池化则是取窗口内的所有值的平均值作为输出。这种方法相比于最大池化更倾向于保留背景信息,但可能会丢失一些显著的特征。
    • 平均池化对于平滑数据和减少噪声是有帮助的。
  3. 其他类型的池化

    • L2范数池化:这种池化方法计算窗口内所有值的平方和的平方根,然后除以窗口大小。
    • 全局池化(Global Pooling):通常用于网络的末端,将整个特征图缩减为单个向量,有助于减少网络参数。

工作原理

池化层通常会定义一个窗口大小(如2x2)和步长(stride),步长决定了窗口移动的步幅。步长通常等于窗口大小,但这不是必须的。池化操作按照指定的步长在输入特征图上滑动,对每个窗口应用选择的池化函数(如最大或平均),并将结果放入输出特征图中。

目的和优势

  • 减少参数数量:通过降低特征图的空间维度,减少了后续层所需的参数数量。
  • 平移不变性:池化操作使得网络对输入的微小平移更加鲁棒,即池化后的特征图对于输入的轻微位移变化不太敏感。
  • 控制过拟合:由于减少了参数数量,同时也减小了网络的学习空间,有助于防止过拟合。
  • 计算效率:池化层相比卷积层计算成本更低,可以加速训练过程。

使用场景

池化层通常位于一系列卷积层之后,用于逐步降低特征图的空间分辨率,直到特征图被压缩到适合全连接层处理的程度。

import torch
import torch.nn as nn
import torch.nn.functional as F

# 定义一个简单的卷积神经网络
class SimpleConvNet(nn.Module):
    def __init__(self):
        super(SimpleConvNet, self).__init__()
        # 定义一个卷积层
        self.conv1 = nn.Conv2d(in_channels=3, out_channels=16, kernel_size=3, padding=1)
        # 定义最大池化层
        self.maxpool = nn.MaxPool2d(kernel_size=2, stride=2)
        # 定义平均池化层
        self.avgpool = nn.AvgPool2d(kernel_size=2, stride=2)

    def forward(self, x):
        x = F.relu(self.conv1(x))
        # 应用最大池化
        maxpooled = self.maxpool(x)
        # 应用平均池化
        avgpooled = self.avgpool(x)
        return maxpooled, avgpooled

# 创建网络实例
model = SimpleConvNet()

# 创建一个随机输入张量,假设是一个3通道的图像
input_tensor = torch.randn(1, 3, 32, 32)

# 将输入传递给网络
maxpooled_output, avgpooled_output = model(input_tensor)

print("Input tensor shape:", input_tensor.shape)
print("Max pooled output shape:", maxpooled_output.shape)
print("Avg pooled output shape:", avgpooled_output.shape)

self.conv1 = nn.Conv2d(in_channels=3, out_channels=16, kernel_size=3, padding=1)

这条语句定义了一个二维的卷积层conv1,它是卷积神经网络中的基本组件之一。下面逐一解释各个参数的意义:

  • in_channels=3:指定了输入数据的通道数。在这个例子中,我们假设输入是一个彩色图像,通常有三个通道(红、绿、蓝),所以in_channels设置为3。

  • out_channels=16:指定了卷积层输出的特征图数量,也就是卷积核的数量。在这个例子中,conv1层会产生16个特征图,每个特征图都是由一个3x3的卷积核与输入数据进行卷积操作的结果。16个卷积核的数值并不相同,但形状相同。由于每个卷积核的数值不相同,所以可以识别图像中的不同特征。

    out_channels=16意味着卷积层将会产生16个不同的特征图,每个特征图是由一个独立的卷积核生成的。下面我会用更通俗的语言来解释这一点。

    卷积核数量的理解

  • 输入通道:在我们的例子中,输入是一个3通道的图像(例如RGB图像)。这意味着每个像素点都有三个值,分别对应红、绿、蓝三种颜色。

  • 卷积核:当我们说out_channels=16时,意味着我们想要从输入图像中提取出16种不同的特征。每个特征图是由一个3x3大小的卷积核生成的,这个卷积核会“看”输入图像的每个3x3的小区域,并根据卷积核中的权重计算一个输出值。

  • 生成特征图:每个卷积核都会在输入图像上滑动,对每个3x3的区域做卷积操作(即与该区域的每一个像素值做点积操作),然后将结果相加得到一个值。这个值就是输出特征图上对应位置的值。因为有16个不同的卷积核,所以会生成16个不同的特征图。

  • 多个卷积核:16个卷积核就像是16个不同的“滤镜”,每个“滤镜”都专注于查找图像中的不同特征。有的可能关注边缘,有的可能关注颜色的对比度,还有些可能关注某些特定的纹理模式。

  • 学习权重每个卷积核内部都有自己的权重(十六个卷积核),这些权重是在训练过程中通过反向传播算法不断调整的。权重的调整使得卷积核能够更好地识别特定的特征。

  • 特征图:当一个卷积核扫描完整张图片后,它会生成一张新的图像——特征图。这张特征图的每个像素值都是由原图中相应位置的3x3区域通过卷积核计算得出的。因为有16个不同的卷积核,所以会得到16张不同的特征图,每一张特征图都强调了原图中的某种特征。

  • kernel_size=3:定义了卷积核的大小。这里的kernel_size设置为3,意味着卷积核是一个3x3的矩阵,它会在输入数据上滑动,与输入数据进行逐元素的乘法运算,然后将结果相加。

  • padding=1:指定了在输入数据周围添加的零填充的数量。这里的padding设置为1,意味着在输入数据的每一侧(上下左右)都会添加一个像素宽的零边界。这样做是为了保持输出特征图的尺寸与输入数据的尺寸一致,避免因卷积操作导致的尺寸缩小。


LeNet:

import torch
import torch.nn as nn
import torch.nn.functional as F

# 定义 LeNet 网络类
class LeNet(nn.Module):
    def __init__(self):
        super(LeNet, self).__init__()
        
        # 定义第一个卷积层
        # 输入通道数为 1(灰度图像)
        # 输出通道数为 6(即产生 6 个特征图)
        # 卷积核大小为 5x5
        # padding 设置为 0,意味着没有填充
        self.conv1 = nn.Conv2d(in_channels=1, out_channels=6, kernel_size=5)

        # 定义第二个卷积层
        # 输入通道数为 6(来自上一层的特征图数量)
        # 输出通道数为 16(即产生 16 个特征图)
        # 卷积核大小为 5x5
        # padding 设置为 0,意味着没有填充
        self.conv2 = nn.Conv2d(in_channels=6, out_channels=16, kernel_size=5)

        # 定义第一个全连接层
        # 输入节点数为 16 * 5 * 5 (来自上一层的特征图数量 * 高 * 宽)
        # 输出节点数为 120
        self.fc1 = nn.Linear(16 * 5 * 5, 120)

        # 定义第二个全连接层
        # 输入节点数为 120
        # 输出节点数为 84
        self.fc2 = nn.Linear(120, 84)

        # 定义第三个全连接层(输出层)
        # 输入节点数为 84
        # 输出节点数为 10(MNIST 数据集有 10 个类别)
        self.fc3 = nn.Linear(84, 10)

    def forward(self, x):
        # 第一个卷积层 + 激活函数 + 最大池化
        # 输入形状: (batch_size, 1, 28, 28)
        # 输出形状: (batch_size, 6, 28, 28) -> ReLU -> (batch_size, 6, 14, 14) (经过 2x2 池化)
        x = F.max_pool2d(F.relu(self.conv1(x)), (2, 2))

        # 第二个卷积层 + 激活函数 + 最大池化
        # 输入形状: (batch_size, 6, 14, 14)
        # 输出形状: (batch_size, 16, 10, 10) -> ReLU -> (batch_size, 16, 5, 5) (经过 2x2 池化)
        x = F.max_pool2d(F.relu(self.conv2(x)), (2, 2))

        # 将特征图拉平为一维向量
        # 输入形状: (batch_size, 16, 5, 5)
        # 输出形状: (batch_size, 16 * 5 * 5)
        x = x.view(-1, self.num_flat_features(x))

        # 第一个全连接层 + 激活函数
        # 输入形状: (batch_size, 16 * 5 * 5)
        # 输出形状: (batch_size, 120)
        x = F.relu(self.fc1(x))

        # 第二个全连接层 + 激活函数
        # 输入形状: (batch_size, 120)
        # 输出形状: (batch_size, 84)
        x = F.relu(self.fc2(x))

        # 第三个全连接层(输出层)
        # 输入形状: (batch_size, 84)
        # 输出形状: (batch_size, 10)
        x = self.fc3(x)

        return x

    
#  辅助方法 (num_flat_features 方法):
#  用于计算除批处理维度外的所有特征的数量,以便将特征图展平为一维向量。
    def num_flat_features(self, x):
        # 计算除 batch 维度外的所有特征数
        size = x.size()[1:]  # 所有维度,除了第一个维度(batch_size)
        num_features = 1
        for s in size:
            num_features *= s
        return num_features

# 创建 LeNet 实例
net = LeNet()
print(net)

1.在卷积神经网络(CNN)中,每个卷积层通常都会配有一个激活函数,这是为了引入非线性因素,使得网络能够学习更为复杂的特征表示。

2.卷积层本身并不直接增加通道数,但通过设计特定的卷积层,我们可以间接地增加通道数。具体来说,卷积层通过其输出通道数(即卷积核的数量)来确定生成的特征图的数量。因此,如果我们希望增加通道数,可以通过增加卷积层的输出通道数来实现。

  1. 输入通道数:这是指输入数据的通道数。例如,对于一个RGB图像,输入通道数为3。
  2. 输出通道数:这是指卷积层生成的特征图的数量,也即是卷积核的数量

AlexNet是一种深度卷积神经网络(CNN),由Alex Krizhevsky、Ilya Sutskever和Geoff Hinton在2012年提出。它在当年的ImageNet大规模视觉识别挑战赛(ILSVRC)中取得了显著的成绩,从而引起了深度学习在计算机视觉领域的广泛关注。以下是AlexNet的主要特点和结构:

  1. 深度架构:AlexNet是当时第一个在大规模图像识别任务中取得突破性成绩的深度网络,它有8层,包括5个卷积层、3个全连接层,以及一个输出层。

  2. ReLU激活函数:AlexNet使用了Rectified Linear Unit(ReLU)作为激活函数,它解决了之前网络中广泛使用的sigmoid和tanh激活函数的梯度消失问题,加快了训练速度。

  3. 数据增强:为了提高模型的泛化能力,AlexNet在训练过程中使用了数据增强技术,包括随机裁剪、水平翻转等,以增加训练样本的多样性。

  4. Dropout正则化:为了防止过拟合,AlexNet引入了Dropout技术。在训练过程中,随机丢弃一部分神经元,迫使网络学习更加鲁棒的特征。

  5. 局部响应归一化(Local Response Normalization, LRN):在某些卷积层之后,AlexNet使用了LRN层,它通过归一化相邻通道的激活值来增加网络的非线性。

  6. 重叠池化:AlexNet在某些卷积层之后使用了重叠的最大池化,这有助于保留更多的信息。

  7. GPU加速:由于AlexNet的深度和宽度,它需要大量的计算资源。AlexNet是最早利用GPU进行训练的网络之一,这大大提高了训练速度。

  8. 全连接层的优化:在全连接层之前,AlexNet使用了特征图的flatten操作,将多维的特征图展平成一维向量,然后输入到全连接层。

  9. softmax输出层:AlexNet的输出层使用了softmax激活函数,用于多分类任务,输出每个类别的概率。

AlexNet的具体结构如下:

  • 输入层:接受224x224x3的RGB图像。
  • 卷积层1:96个滤波器,大小为11x11,步长为4,使用ReLU激活函数。
  • 最大池化层1:3x3窗口,步长为2。
  • 卷积层2:256个滤波器,大小为5x5,使用ReLU激活函数。
  • 最大池化层2:3x3窗口,步长为2。
  • 卷积层3:384个滤波器,大小为3x3,使用ReLU激活函数。
  • 卷积层4:384个滤波器,大小为3x3,使用ReLU激活函数。
  • 卷积层5:256个滤波器,大小为3x3,使用ReLU激活函数。
  • 最大池化层3:3x3窗口,步长为2。
  • 全连接层1:4096个神经元,使用ReLU激活函数和Dropout。
  • 全连接层2:4096个神经元,使用ReLU激活函数和Dropout。
  • 输出层:1000个神经元(对应ImageNet的1000个类别),使用softmax激活函数。

AlexNet的成功不仅在于其在ImageNet竞赛中的优异表现,更在于它为后续的深度学习研究和应用奠定了基础,启发了后续许多更先进的网络结构,如VGGNet、GoogLeNet和ResNet等。

代码如下:

import torch
import torch.nn as nn

class AlexNet(nn.Module):
    def __init__(self, num_classes=1000):
        super(AlexNet, self).__init__()
        
        # 定义卷积层和池化层的序列
        self.features = nn.Sequential(
            # 第一个卷积层
            nn.Conv2d(3, 64, kernel_size=11, stride=4, padding=2),  # 输入通道数为3,输出通道数为64,卷积核大小为11x11,步长为4,填充为2
            nn.ReLU(inplace=True),  # ReLU 激活函数
            nn.MaxPool2d(kernel_size=3, stride=2),  # 最大池化层,窗口大小为3x3,步长为2
            
            # 第二个卷积层
            nn.Conv2d(64, 192, kernel_size=5, padding=2),  # 输入通道数为64,输出通道数为192,卷积核大小为5x5,填充为2
            nn.ReLU(inplace=True),  # ReLU 激活函数
            nn.MaxPool2d(kernel_size=3, stride=2),  # 最大池化层,窗口大小为3x3,步长为2
            
            # 第三个卷积层
            nn.Conv2d(192, 384, kernel_size=3, padding=1),  # 输入通道数为192,输出通道数为384,卷积核大小为3x3,填充为1
            nn.ReLU(inplace=True),  # ReLU 激活函数
            
            # 第四个卷积层
            nn.Conv2d(384, 256, kernel_size=3, padding=1),  # 输入通道数为384,输出通道数为256,卷积核大小为3x3,填充为1
            nn.ReLU(inplace=True),  # ReLU 激活函数
            
            # 第五个卷积层
            nn.Conv2d(256, 256, kernel_size=3, padding=1),  # 输入通道数为256,输出通道数为256,卷积核大小为3x3,填充为1
            nn.ReLU(inplace=True),  # ReLU 激活函数
            nn.MaxPool2d(kernel_size=3, stride=2),  # 最大池化层,窗口大小为3x3,步长为2
        )
        
        # 定义全局平均池化层
        self.avgpool = nn.AdaptiveAvgPool2d((6, 6))  # 适应性全局平均池化,输出大小为6x6
        
        # 定义全连接层的序列
        self.classifier = nn.Sequential(
            nn.Dropout(),  # Dropout 层,用于减少过拟合
            nn.Linear(256 * 6 * 6, 4096),  # 第一个全连接层,输入为256*6*6,输出为4096
            nn.ReLU(inplace=True),  # ReLU 激活函数
            nn.Dropout(),  # Dropout 层
            nn.Linear(4096, 4096),  # 第二个全连接层,输入为4096,输出为4096
            nn.ReLU(inplace=True),  # ReLU 激活函数
            nn.Linear(4096, num_classes)  # 输出层,输入为4096,输出为类别数(默认为1000)
        )

    def forward(self, x):
        # 前向传播过程
        # 通过卷积层和池化层
        x = self.features(x)
        
        # 通过全局平均池化层
        x = self.avgpool(x)
        
        # 将特征图展平为一维向量
        x = torch.flatten(x, 1)
        
        # 通过全连接层
        x = self.classifier(x)
        
        return x

# 创建 AlexNet 模型实例
model = AlexNet()
print(model)

 总的来说,数据加载器就像是模型的“厨师”,负责将“食材”(数据)准备好,然后按照合适的“菜单”(批量大小、是否打乱等)将“菜肴”(处理好的数据)端到模型的“餐桌”(训练或测试过程)上。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值