Net: Conv2d && Dilated

  • Post author:
  • Post category:其他


本文主要讲解PyTorch中的卷积函数Conv2d以及对应的空洞卷积Dilated



Conv2d


nn.Conv2d(in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True, padding_mode='zeros', device=None, dtype=None)

此函数作一个卷积操作,将输入为



(

N

,

 

C

i

n

,

 

H

,

 

W

)

(N, ~C_{in}, ~H, ~W)






(


N


,







C











i


n



















,






H


,






W


)





的输入变为



(

N

,

 

C

o

u

t

,

 

H

o

u

t

,

 

W

o

u

t

)

(N, ~C_{out}, ~H_{out}, ~W_{out})






(


N


,







C











o


u


t



















,







H











o


u


t



















,







W











o


u


t



















)





,其中



N

N






N





是batch size,



C

C






C





代表通道数,



H

W

H和W






H





W





分别是图像的长和宽

输出的长和宽的计算





H

o

u

t

=

H

i

n

+

2

p

a

d

d

i

n

g

[

0

]

d

i

l

a

t

i

o

n

[

0

]

(

k

e

r

n

e

l

_

s

i

z

e

[

0

]

1

)

1

s

t

r

i

d

e

[

0

]

+

1

W

o

u

t

=

W

i

n

+

2

p

a

d

d

i

n

g

[

1

]

d

i

l

a

t

i

o

n

[

1

]

(

k

e

r

n

e

l

_

s

i

z

e

[

1

]

1

)

1

s

t

r

i

d

e

[

1

]

+

1

H_{out} = \frac{H_{in}+2*padding[0]-dilation[0]*(kernel\_size[0]-1)-1}{stride[0]}+1 \\ W_{out} = \frac{W_{in}+2*padding[1]-dilation[1]*(kernel\_size[1]-1)-1}{stride[1]}+1







H











o


u


t





















=



















s


t


r


i


d


e


[


0


]















H











i


n





















+




2









p


a


d


d


i


n


g


[


0


]









d


i


l


a


t


i


o


n


[


0


]









(


k


e


r


n


e


l


_


s


i


z


e


[


0


]









1


)









1






















+








1









W











o


u


t





















=



















s


t


r


i


d


e


[


1


]















W











i


n





















+




2









p


a


d


d


i


n


g


[


1


]









d


i


l


a


t


i


o


n


[


1


]









(


k


e


r


n


e


l


_


s


i


z


e


[


1


]









1


)









1






















+








1





参数的含义


  • in_channels

    ([

    int

    ]) – 输入图像通道数

  • out_channels

    ([

    int

    ])– 输出图像通道数(等于卷积核的数目)

  • kernel_size

    ([

    int

    ]

    or

    [

    tuple

    ]) – 卷积核的大小

  • stride

    ([

    int

    ]

    or

    [

    tuple

    ]

    ,


    optional

    ) – 卷积核移动的步长. Default: 1

  • padding

    ([

    int

    ]

    ,

    [

    tuple

    ]

    or

    [

    str

    ]

    ,


    optional

    ) – 图像填充的数目. Default: 0

  • padding_mode

    (

    string

    *,*

    optional

    ) – 填充模式

    'zeros'

    ,

    'reflect'

    ,

    'replicate'

    or

    'circular'

    . Default:

    'zeros'

  • dilation

    ([

    int

    ]

    or

    [

    tuple

    ]

    ,


    optional

    ) – Spacing between kernel elements. Default: 1

  • groups

    ([

    int

    ]

    ,


    optional

    ) – Number of blocked connections from input channels to output channels. Default: 1

  • bias

    ([

    bool

    ]

    ,


    optional

    ) – If

    True

    , adds a learnable bias to the output. Default:

    True

例子

''' padding=0,stride=1,kernel_size=3 '''
x = torch.randn(1,1,4,4)
l = nn.Conv2d(in_channels=1, out_channels=1, kernel_size=3) 
y = l(x)
print(y.size())  # torch.Size([1, 1, 2, 2])

''' padding=2,stride=1,kernel_size=4 '''
x = torch.randn(1,1,5,5)
l = nn.Conv2d(in_channels=1, out_channels=1, kernel_size=4, padding=2)
y = l(x) 		 
print(y.size())  # torch.Size([1, 1, 6, 6])

下面图示了一个4*4图片,kernel size=4 stride=1 padding=0的卷积图示(只展示了一个卷积核)


注意:对于padding的图,仅仅变化的就是原图,其余的过程不变



Padding

padding的一个作用是,当我们用kernal size=3 stride=1的卷积核对图片进行操作时,如果不进行padding,最后的特征图会比原图片小,所以要进行padding,padding的方式有四种:

zeros, reflect, replicate, circular

,下面举例说明其区别

首先我们初始化一个(1, 1, 4, 4)的矩阵,之后都对这个矩阵进行操作,其中卷积的权重我们初始化为1,卷积核的大小和数量也为1,这样每次卷积之后输入的矩阵x原来的元素是不会发生变化的

x = torch.nn.Parameter(torch.reshape(torch.arange(0,16,dtype=torch.float), (1,1,4,4)))
'''
Parameter containing:
tensor([[[[ 0.,  1.,  2.,  3.],
          [ 4.,  5.,  6.,  7.],
          [ 8.,  9., 10., 11.],
          [12., 13., 14., 15.]]]], requires_grad=True)
'''


zeros

zeros就是填充的每个元素都为0

conv = torch.nn.Conv2d(1,1,1,1,padding=1,padding_mode='zeros',bias=False)
conv.weight = torch.nn.Parameter(torch.ones(1,1,1,1))
conv(x)
'''
tensor([[[[ 0.,  0.,  0.,  0.,  0.,  0.],
          [ 0.,  0.,  1.,  2.,  3.,  0.],
          [ 0.,  4.,  5.,  6.,  7.,  0.],
          [ 0.,  8.,  9., 10., 11.,  0.],
          [ 0., 12., 13., 14., 15.,  0.],
          [ 0.,  0.,  0.,  0.,  0.,  0.]]]], grad_fn=<ThnnConv2DBackward>)
'''


reflect

reflect是以矩阵的边为对称轴,填充元素为内部的对称元素

conv = torch.nn.Conv2d(1,1,1,1,padding=1,padding_mode='reflect',bias=False)
conv.weight = torch.nn.Parameter(torch.ones(1,1,1,1))
conv(x)
'''
tensor([[[[ 5.,  4.,  5.,  6.,  7.,  6.],
          [ 1.,  0.,  1.,  2.,  3.,  2.],
          [ 5.,  4.,  5.,  6.,  7.,  6.],
          [ 9.,  8.,  9., 10., 11., 10.],
          [13., 12., 13., 14., 15., 14.],
          [ 9.,  8.,  9., 10., 11., 10.]]]], grad_fn=<ThnnConv2DBackward>)
'''


replicate

填充元素均为矩阵边上的元素

conv = torch.nn.Conv2d(1,1,1,1,padding=2,padding_mode='replicate',bias=False)
conv.weight = torch.nn.Parameter(torch.ones(1,1,1,1))
conv(x)
'''
tensor([[[[ 0.,  0.,  0.,  1.,  2.,  3.,  3.,  3.],
          [ 0.,  0.,  0.,  1.,  2.,  3.,  3.,  3.],
          [ 0.,  0.,  0.,  1.,  2.,  3.,  3.,  3.],
          [ 4.,  4.,  4.,  5.,  6.,  7.,  7.,  7.],
          [ 8.,  8.,  8.,  9., 10., 11., 11., 11.],
          [12., 12., 12., 13., 14., 15., 15., 15.],
          [12., 12., 12., 13., 14., 15., 15., 15.],
          [12., 12., 12., 13., 14., 15., 15., 15.]]]], grad_fn=<ThnnConv2DBackward>)
'''


circular

不好讲,直接看图示结果吧,就是将原数据copy几份围绕在他的周围,然后按照所需的padding裁切

conv = torch.nn.Conv2d(1,1,1,1,padding=2,padding_mode='circular',bias=False)
conv.weight = torch.nn.Parameter(torch.ones(1,1,1,1))
conv(x)
'''
tensor([[[[10., 11.,  8.,  9., 10., 11.,  8.,  9.],
          [14., 15., 12., 13., 14., 15., 12., 13.],
          [ 2.,  3.,  0.,  1.,  2.,  3.,  0.,  1.],
          [ 6.,  7.,  4.,  5.,  6.,  7.,  4.,  5.],
          [10., 11.,  8.,  9., 10., 11.,  8.,  9.],
          [14., 15., 12., 13., 14., 15., 12., 13.],
          [ 2.,  3.,  0.,  1.,  2.,  3.,  0.,  1.],
          [ 6.,  7.,  4.,  5.,  6.,  7.,  4.,  5.]]]], grad_fn=<ThnnConv2DBackward>)
'''



Dilated

空洞卷积的函数与Conv的函数相同,唯一的区别就是修改dilation参数,dilation控制kernal中每个元素之间的距离:

这个链接给了一个很好的图示

dilation代表卷积核参数之间的空隙,不理解的可以直接看下图

下面通过一个例子展示DilatedConv的执行过程

x = torch.nn.Parameter(torch.reshape(torch.arange(0, 25, dtype=torch.float), (1, 1, 5, 5)))
print(x)
'''
Parameter containing:
tensor([[[[ 0.,  1.,  2.,  3.,  4.],
          [ 5.,  6.,  7.,  8.,  9.],
          [10., 11., 12., 13., 14.],
          [15., 16., 17., 18., 19.],
          [20., 21., 22., 23., 24.]]]], requires_grad=True)
'''

# Conv2d: dilation=1
conv = torch.nn.Conv2d(1, 1, 3, 1, padding=0, dilation=1, bias=False)
conv.weight = torch.nn.Parameter(torch.ones(1,1,3,3))
print(conv(x))
'''
tensor([[[[ 54.,  63.,  72.],
          [ 99., 108., 117.],
          [144., 153., 162.]]]], grad_fn=<ThnnConv2DBackward>)
'''

# Dilate: dilation=2
conv = torch.nn.Conv2d(1, 1, 3, 1, padding=0, dilation=2, bias=False)
conv.weight = torch.nn.Parameter(torch.ones(1,1,3,3))
print(conv(x))
'''
tensor([[[[108.]]]], grad_fn=<SlowConvDilated2DBackward>)
'''



版权声明:本文为weixin_41978699原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。