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

卷积层在深度学习中常常用到。下面介绍一下卷积层中的参数,并使用一个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
n c [ l ] n^{[l]}_c nc[l]:filter的数量(也就是输出数据Channel的数量)
n c [ l − 1 ] n^{[l-1]}_c nc[l1]:输入数据Channel的数量
bias:每层的偏离值,是一个实数,即为逻辑回归中的b参数

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

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

1.2 Valid与Same卷积

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

  1. Valid卷积中无padding;
  2. Same卷积的输入与输出大小一致,padding的数值可由 p = f − 1 2 p = \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值。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值