目录
5.1.2 二维卷积算子
5.1.3 二维卷积的参数量和计算量
5.1.4 感受野
5.1.5 卷积的变种
5.1.6 带步长和零填充的二维卷积算子
5.1.7 使用卷积运算完成图像边缘检测任务
选做
5.1 卷积
5.1.1 二维卷积运算
![](https://img-blog.csdnimg.cn/ec87e69830004abcaa9eba13a6019b5d.png)
5.1.2 二维卷积算子
在本书后面的实现中,算子都继承paddle.nn.Layer ,并使用支持反向传播的飞桨API进行实现,这样我们就可以不用手工写backword() 的代码实现。
import torch
import torch.nn as nn
class Conv2D(nn.Module):
def __init__(self, kernel_size,
weight_attr=torch.tensor([[0., 1.],[2., 3.]])):
super(Conv2D, self).__init__()
# 使用'paddle.create_parameter'创建卷积核
# 使用'paddle.ParamAttr'进行参数初始化
self.weight = nn.Parameter(weight_attr)
def forward(self, X):
"""
输入:
- X:输入矩阵,shape=[B, M, N],B为样本数量
输出:
- output:输出矩阵
"""
u, v = self.weight.shape
output = torch.zeros([X.shape[0], X.shape[1] - u + 1, X.shape[2] - v + 1])
for i in range(output.shape[1]):
for j in range(output.shape[2]):
output[:, i, j] = torch.sum(X[:, i:i+u, j:j+v]*self.weight, axis=[1,2])
return output
# 随机构造一个二维输入矩阵
torch.seed()
inputs = torch.tensor([[[1.,2.,3.],[4.,5.,6.],[7.,8.,9.]]])
conv2d = Conv2D(kernel_size=2)
outputs = conv2d(inputs)
print("input: {}, \noutput: {}".format(inputs, outputs))
torch.Size([2, 2])
input: tensor([[[1., 2., 3.],
[4., 5., 6.],
[7., 8., 9.]]]),
output: tensor([[[25., 31.],
[43., 49.]]], grad_fn=<CopySlices>)
5.1.3 二维卷积的参数量和计算量
随着隐藏层神经元数量的变多以及层数的加深,
使用全连接前馈网络处理图像数据时,参数量会急剧增加。
如果使用卷积进行图像处理,相较于全连接前馈网络,参数量少了非常多。
5.1.4 感受野
![](https://img-blog.csdnimg.cn/465993b58fac42da92c8f1fd5516e67e.png)
![](https://img-blog.csdnimg.cn/6d358fa2ab694636a15f8ae7c3932273.png)
5.1.5 卷积的变种
5.1.5.1 步长(Stride)
![](https://img-blog.csdnimg.cn/0292a79b9ab24ff6bb58ec464ef0ae47.png)
5.1.5.2 零填充(Zero Padding)
![](https://img-blog.csdnimg.cn/749365bb722d4c158080ef7bd90df469.png)
5.1.6 带步长和零填充的二维卷积算子
从输出结果看出,使用3×3大小卷积,
padding 为1,
当stride =1时,模型的输出特征图与输入特征图保持一致;
当stride =2时,模型的输出特征图的宽和高都缩小一倍。
【使用pytorch实现】
class Conv2D(nn.Module):
def __init__(self, kernel_size,stride=1, padding=0,
weight_attr=torch.tensor([[0., 1.],[2., 3.]])):
super(Conv2D, self).__init__()
# 使用'paddle.create_parameter'创建卷积核
# 使用'paddle.ParamAttr'进行参数初始化
self.weight = nn.Parameter(weight_attr)
# 步长
self.stride = stride
# 零填充
self.padding = padding
def forward(self, X):
"""
输入:
- X:输入矩阵,shape=[B, M, N],B为样本数量
输出:
- output:输出矩阵
"""
u, v = self.weight.shape
output = torch.zeros([X.shape[0], X.shape[1] - u + 1, X.shape[2] - v + 1])
for i in range(output.shape[1]):
for j in range(output.shape[2]):
output[:, i, j] = torch.sum(X[:, i:i+u, j:j+v]*self.weight, axis=[1,2])
return output
# 随机构造一个二维输入矩阵
torch.seed()
inputs = torch.tensor([[[1.,2.,3.],[4.,5.,6.],[7.,8.,9.]]])
conv2d = Conv2D(kernel_size=2)
outputs = conv2d(inputs)
print("input: {}, \noutput: {}".format(inputs, outputs))
inputs = torch.randn(size=[2, 8, 8])
conv2d_padding = Conv2D(kernel_size=3, padding=1)
outputs = conv2d_padding(inputs)
print("When kernel_size=3, padding=1 stride=1, input's shape: {}, output's shape: {}".format(inputs.shape, outputs.shape))
conv2d_stride = Conv2D(kernel_size=3, stride=2, padding=1)
outputs = conv2d_stride(inputs)
print("When kernel_size=3, padding=1 stride=2, input's shape: {}, output's shape: {}".format(inputs.shape, outputs.shape))
When kernel_size=3, padding=1 stride=1, input's shape: torch.Size([2, 8, 8]), output's shape: torch.Size([2, 8, 8])
When kernel_size=3, padding=1 stride=2, input's shape: torch.Size([2, 8, 8]), output's shape: torch.Size([2, 4, 4])
5.1.7 使用卷积运算完成图像边缘检测任务
【使用pytorch实现】
![](https://img-blog.csdnimg.cn/a60f3ca00eec4703a859555d36d53fab.jpeg)
![](https://img-blog.csdnimg.cn/7a42f97f0e53456a958c1b8f31f6e2f0.png)
# 可视化结果
plt.figure(figsize=(8, 4))
f = plt.subplot(121)
f.set_title('input image', fontsize=15)
plt.imshow(img)
f = plt.subplot(122)
f.set_title('output feature map', fontsize=15)
plt.imshow(outputs.detach().squeeze(), cmap='gray')
plt.savefig('conv-vis.pdf')
plt.show()
![](https://img-blog.csdnimg.cn/b4f104ac32a04a04a5ca31fff9693e5a.png)
选做
实现一些传统边缘检测算子,如:Roberts、Prewitt、Sobel、Scharr、Kirsch、Robinson、Laplacian
Roberts:
![](https://img-blog.csdnimg.cn/e3e5c5b585544f5eaf61ce8e131f122c.png) ![](https://img-blog.csdnimg.cn/da600cebb6e043499d88c152251fb7c6.png)
?Prewitt:
![](https://img-blog.csdnimg.cn/2b2ebc3796604074ac2d66a13e426722.png)
?![](https://img-blog.csdnimg.cn/c8819bd4bba24cac85a0372c7b016b71.png)
?Sobel:
?![](https://img-blog.csdnimg.cn/3546316c1fd748aab1c0d4944fc8c6d8.png)
?![](https://img-blog.csdnimg.cn/43b31f63affb4275acaa3525677a7df6.png)
?Scharr:
![](https://img-blog.csdnimg.cn/7f710f973d1e4cb8ba8fb589c6063f48.png)
![](https://img-blog.csdnimg.cn/7b1527fab8684c1fa10c70d44a2eb7d3.png)
?Kirsch:
![](https://img-blog.csdnimg.cn/1e153b27f34f4643b431657b49af9660.png)
?![](https://img-blog.csdnimg.cn/dbf5799ba2904db0b5181bb5bd4b4172.png)
?Robinson:
![5764eb45f5be9860326fbe30fd74de5e.png](https://img-blog.csdnimg.cn/img_convert/5764eb45f5be9860326fbe30fd74de5e.png)
?![](https://img-blog.csdnimg.cn/f4fa40b1e7ec4c4094570e01ecb187ea.png)
?Laplacian
?![](https://img-blog.csdnimg.cn/4f78284b6a454511b49f0990547151e5.png) ![](https://img-blog.csdnimg.cn/b4f104ac32a04a04a5ca31fff9693e5a.png)
总结:了解卷积的基本流程,了解卷积核的设置,步长的的设置,是否需要填充等问题
|