卷积层介绍及其输出张量形状的分析

本文深入探讨深度学习中卷积层的参数及其计算过程,通过DQN模型实例讲解卷积层输出张量的形状变化,揭示Valid与Same卷积的区别,及卷积在减少数据尺寸、提取特征方面的作用。

卷积层在深度学习中常常用到。下面介绍一下卷积层中的参数,并使用一个DQN中的例子来推算卷积层输出张量的形状。

1. 卷积层参数及其意义

卷积层的意义在于提取给定的数据的特征,池化层的意义在于减少数据的大小,减少运算量。

1.1 卷积参数计算的过程分析

[l][l][l]:层数l
f[l]f^{[l]}f[l]:filter的大小
p[l]p^{[l]}p[l]:padding
s[l]s^{[l]}s[l]:步长stride
nc[l]n^{[l]}_cnc[l]:filter的数量(也就是输出数据Channel的数量)
nc[l−1]n^{[l-1]}_cnc[l1]:输入数据Channel的数量
bias:每层的偏离值,是一个实数,即为逻辑回归中的b参数

输入张量形状:nH[l−1]∗nW[l−1]∗n[l−1]n^{[l-1]}_H * n^{[l-1]}_W * n^{[l-1]}nH[l1]nW[l1]n[l1]
输出张量形状:nH[l]∗nW[l]∗nc[l]n^{[l]}_H * n^{[l]}_W * n^{[l]}_cnH[l]nW[l]nc[l]

其中可以计算获得
nH[l]=⌊nH[l−1]+2p[l]−f[l]s[l]+1⌋n^{[l]}_H = \lfloor \frac{n^{[l-1]}_H + 2p^{[l]} - f^{[l]}}{s^{[l]}} + 1 \rfloornH[l]=s[l]nH[l1]+2p[l]f[l]+1
nW[l]=⌊nW[l−1]+2p[l]−f[l]s[l]+1⌋n^{[l]}_W = \lfloor \frac{n^{[l-1]}_W + 2p^{[l]} - f^{[l]}}{s^{[l]}} + 1 \rfloornW[l]=s[l]nW[l1]+2p[l]f[l]+1

1.2 Valid与Same卷积

padding的作用是防止边缘的数据计算次数过少,导致计算结果难以显示边缘的特征。

  1. Valid卷积中无padding;
  2. Same卷积的输入与输出大小一致,padding的数值可由p=f−12p = \frac{f - 1}{2}p=2f1确定。其中f一般是奇数。

2. DQN数据处理模型

在Dueling DQN的forward函数中,先卷积运算了两次,并将获得的结果展开至一维,之后分别使用价值函数和优势函数计算Value和Advantage,再用Value和Advantage预测出Q值。

卷积过程: nn.Conv2d(conv1) -> ReLU -> nn.Conv2d(conv2) -> ReLU
Value计算过程: NoisyLinear(fc_h_v) -> ReLU -> NoisyLinear(fc_z_v) -> ReLU
Advantage计算过程: NoisyLinear(fc_h_a) -> ReLU -> NoisyLinear(fc_z_a) -> ReLU

class DQN(nn.Module):
    def __init__(self, args, action_space):
        super().__init__()
        self.atoms = args.atoms
        self.action_space = action_space

        # conv1,conv2与ReLU
        self.convs = nn.Sequential(nn.Conv2d(args.history_length, 32, 5, stride=2, padding=0), nn.ReLU(),
                                   nn.Conv2d(32, 32, 5, stride=2, padding=0), nn.ReLU())
        self.conv_output_size = 70688

        self.fc_h_v = NoisyLinear(self.conv_output_size, args.hidden_size, std_init=args.noisy_std)
        self.fc_h_a = NoisyLinear(self.conv_output_size, args.hidden_size, std_init=args.noisy_std)
        self.fc_z_v = NoisyLinear(args.hidden_size, self.atoms, std_init=args.noisy_std)
        self.fc_z_a = NoisyLinear(args.hidden_size, action_space * self.atoms, std_init=args.noisy_std)

def forward(self, x, log=False) -> torch.Tensor:
    x = self.convs(x)
    x = x.view(-1, self.conv_output_size)
    v = self.fc_z_v(F.relu(self.fc_h_v(x)))  # Value stream
    a = self.fc_z_a(F.relu(self.fc_h_a(x)))  # Advantage stream
    v, a = v.view(-1, 1, self.atoms), a.view(-1, self.action_space, self.atoms)
    q = v + a - a.mean(1, keepdim=True)  # Combine streams
    if log:  # Use log softmax for numerical stability
        q = F.log_softmax(q, dim=2)  # Log probabilities with action over second dimension
    else:
        q = F.softmax(q, dim=2)  # Probabilities with action over second dimension
    return q

3. 卷积层输出张量大小计算

以上述DQN中的卷积方式为例,计算最终输出至线性层中的张量的大小。
输入NN中的张量大小为4 * 200 * 200。

3.1 nn.Conv2d(conv1)

3.1.1 输入(即Env模块获得的State)

  • Channel: 4
  • Height: 200
  • Width: 200

3.1.2 卷积参数

  • Kernel(Filter)大小:5*5*5
  • Kernel(Filter)数量:32
  • 步长(Stride):2
  • 无Padding

3.1.3 输出

  • Channel: 32
  • Height: (200 - 5) / 2 + 1 = 98
  • Width: (200 - 5) / 2 + 1 = 98

3.2 nn.Conv2d(conv2)

3.2.1 输入

  • Channel: 32
  • Height: 98
  • Width: 98

3.2.2 卷积参数

  • Kernel(Filter)大小:5*5*5
  • Kernel(Filter)数量:32
  • 步长(Stride):2
  • 无Padding

3.2.3 输出

  • Channel: 32
  • Height: (98 - 5) / 2 + 1 = 47
  • Width: (98 - 5) / 2 + 1 = 47

3.3 结果展开

将conv2卷积获得的结果展开,获得的一维向量大小为Channel * Height * Width = 32 * 47 * 47 = 70688。之后将这个向量输入NoisyLinear进行处理,最后获得Q值。

### 卷积层的代码示例 在深度学习中,卷积层是卷积神经网络(CNN)的核心组成部分,广泛应用于图像识别、语音识别、自然语言处理等领域。以下是一个使用 `PyTorch` 实现的卷积层代码示例,展示如何构建一个简单的卷积层并进行前向传播。 ```python import torch import torch.nn as nn # 定义一个简单的卷积层 class SimpleConvolutionalLayer(nn.Module): def __init__(self, in_channels, out_channels, kernel_size): super(SimpleConvolutionalLayer, self).__init__() self.conv = nn.Conv2d(in_channels, out_channels, kernel_size) def forward(self, x): return self.conv(x) # 创建一个卷积层实例 # 输入通道数为1,输出通道数为3,卷积核大小为3x3 conv_layer = SimpleConvolutionalLayer(in_channels=1, out_channels=3, kernel_size=3) # 创建一个输入张量 (batch_size=1, in_channels=1, height=5, width=5) input_tensor = torch.randn(1, 1, 5, 5) # 进行前向传播 output_tensor = conv_layer(input_tensor) # 打印输出张量形状 print("输出张量形状:", output_tensor.shape) ``` #### 代码解释: 1. **定义卷积层**:`SimpleConvolutionalLayer` 类继承自 `nn.Module`,并使用 `nn.Conv2d` 定义了一个卷积层。`nn.Conv2d` 的参数包括输入通道数 (`in_channels`)、输出通道数 (`out_channels`) 和卷积核大小 (`kernel_size`)。 2. **前向传播**:在 `forward` 方法中,输入张量 `x` 通过卷积层进行计算。 3. **输入张量**:`input_tensor` 是一个随机生成的张量形状为 `(batch_size, in_channels, height, width)`,其中 `batch_size` 是批量大小,`in_channels` 是输入通道数,`height` 和 `width` 是输入图像的高度和宽度。 4. **输出张量**:卷积层输出张量形状为 `(batch_size, out_channels, new_height, new_width)`,其中 `new_height` 和 `new_width` 取决于卷积操作的步长和填充设置。 ### 卷积层的剪枝示例 除了实现卷积层,还可以对卷积层进行剪枝以优化模型性能。以下是一个简单的剪枝示例,展示如何通过将卷积核置零来实现剪枝。 ```python import torch import torch.nn.utils.prune as prune # 假设我们有一个卷积层 conv = nn.Conv2d(1, 3, 3) # 对卷积层进行剪枝,将20%的权重置零 prune.l1_unstructured(conv, name='weight', amount=0.2) # 查看剪枝后的权重 print("剪枝后的权重:", conv.weight) # 剪枝后,可以继续进行前向传播 input_tensor = torch.randn(1, 1, 5, 5) output_tensor = conv(input_tensor) print("剪枝后的输出形状:", output_tensor.shape) ``` #### 代码解释: 1. **剪枝方法**:使用 `prune.l1_unstructured` 方法对卷积层的权重进行剪枝,`amount=0.2` 表示将20%的权重置零。 2. **查看剪枝结果**:通过 `conv.weight` 查看剪枝后的权重矩阵。 3. **继续使用剪枝后的卷积层**:剪枝后的卷积层仍然可以正常进行前向传播。 这些示例展示了如何在深度学习中实现卷积层以及如何对卷积层进行剪枝。通过这些代码,可以更好地理解卷积层的工作原理及其在实际应用中的使用[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值