NNDL 作业5:卷积

作业1

编程实现

在这里插入图片描述

在这里插入图片描述

1. 图1使用卷积核(1,-1),输出特征图
2. 图1使用卷积核 ( 1 − 1 ) \binom{1}{-1} (11)输出特征图
代码实现:

import numpy as np
import torch
import matplotlib.pyplot as plt

plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号

w1 = np.array([1, -1], dtype='float32').reshape([1, 1, 1, 2])
w2 = np.array([1, -1], dtype='float32').T.reshape([1, 1, 2, 1])
print(w2)
w1 = torch.Tensor(w1)
w2 = torch.Tensor(w2)
conv1 = torch.nn.Conv2d(1, 1, [1, 2])
conv1.weight = torch.nn.Parameter(w1)

conv2 = torch.nn.Conv2d(1, 1, [2, 1])
conv2.weight = torch.nn.Parameter(w2)# 创建图像
img = np.ones([7, 6], dtype='float32')
img[:, 3:] = 0.
img[:, :3] = 255.
x = img.reshape([1, 1, 7, 6])
x = torch.Tensor(x)

y1 = conv1(x).detach().numpy()
y2 = conv2(x).detach().numpy()
plt.subplot(131).set_title('图1')
plt.imshow(img,cmap='gray')
plt.subplot(132).set_title('图1使用卷积核为(1,-1)结果')
plt.imshow(y1.squeeze(),cmap='gray')
plt.subplot(133).set_title('图1使用卷积核为(1,-1)T结果')
plt.imshow(y2.squeeze(),cmap='gray')
plt.show()

运行结果:
在这里插入图片描述

3. 图2使用卷积核(1,-1),输出特征图
4. 图2使用卷积核 ( 1 − 1 ) \binom{1}{-1} (11)输出特征图
代码实现:

import numpy as np
import torch
import matplotlib.pyplot as plt

plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号

w1 = np.array([1, -1], dtype='float32').reshape([1, 1, 1, 2])
w2 = np.array([1, -1], dtype='float32').T.reshape([1, 1, 2, 1])
print(w2)
w1 = torch.Tensor(w1)
w2 = torch.Tensor(w2)
conv1 = torch.nn.Conv2d(1, 1, [1, 2])
conv1.weight = torch.nn.Parameter(w1)

conv2 = torch.nn.Conv2d(1, 1, [2, 1])
conv2.weight = torch.nn.Parameter(w2)# 创建图像
img = np.ones([8, 8], dtype='float32')
img[:4, :4] = 0.
img[:4, 4:] = 255.
img[4:, :4] = 255.
img[4:, 4:] = 0.

x = img.reshape([1, 1, 8, 8])
x = torch.Tensor(x)

y1 = conv1(x).detach().numpy()
y2 = conv2(x).detach().numpy()
plt.subplot(131).set_title('图2')
plt.imshow(img, cmap='gray')
plt.subplot(132).set_title('图2使用卷积核为(1,-1)结果')
plt.imshow(y1.squeeze(), cmap='gray')
plt.subplot(133).set_title('图2使用卷积核为(1,-1)T结果')
plt.imshow(y2.squeeze(), cmap='gray')
plt.show()

运行结果:
在这里插入图片描述
5. 图3使用卷积核 ( 1 − 1 ) \begin{pmatrix} 1 & -1 \end{pmatrix} (11) ( 1 − 1 ) \begin{pmatrix} 1\\ -1\\ \end{pmatrix} (11) ( 1 − 1 − 1 1 ) \begin{pmatrix} 1 &-1 \\ -1&1 \end{pmatrix} (1111)输出特征图

import numpy as np
import torch
import matplotlib.pyplot as plt

plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号

w1 = np.array([1, -1], dtype='float32').reshape([1, 1, 1, 2])
w2 = np.array([1, -1], dtype='float32').T.reshape([1, 1, 2, 1])
w3 =  np.array([[1,-1,-1,1]],dtype='float32').reshape([1,1,2,2])

print(w3)
w1 = torch.Tensor(w1)
w2 = torch.Tensor(w2)
w3 = torch.Tensor(w3)

conv1 = torch.nn.Conv2d(1, 1, [1, 2])
conv1.weight = torch.nn.Parameter(w1)

conv2 = torch.nn.Conv2d(1, 1, [2, 1])
conv2.weight = torch.nn.Parameter(w2)

conv3 = torch.nn.Conv2d(1,1,[2,2])
conv3.weight = torch.nn.Parameter(w3)
# 创建图像
img = np.ones([9, 9], dtype='float32')
for i in range(7):
    img[i+1,i+1]=255.
    img[i+1,7-i]=255.

x = img.reshape([1, 1, 9, 9])
x = torch.Tensor(x)

y1 = conv1(x).detach().numpy()
y2 = conv2(x).detach().numpy()
y3 = conv3(x).detach().numpy()
plt.subplot(221).set_title('图3')
plt.imshow(img, cmap='gray')
plt.subplot(222).set_title('图3使用卷积核为(1,-1)结果')
plt.imshow(y1.squeeze(),cmap='gray')
plt.subplot(223).set_title('图3使用卷积核为(1,-1)T结果')
plt.imshow(y2.squeeze(),cmap='gray')
plt.subplot(224).set_title('图3使用卷积核为[[1 -1],[-1 1]]结果')
plt.imshow(y3.squeeze(),cmap='gray')
plt.show()

运行结果:
在这里插入图片描述

作业2

一、概念

用自己的语言描述“卷积、卷积核、特征图、特征选择、步长、填充、感受野”。
1、卷积:它是通过两个函数f和g生成第三个函数的一种数学运算,表征函数f与g经过翻转和平移的重叠部分的面积。
卷积的计算公式如下:
在这里插入图片描述
f(t)先不动, g(-t)相当于g(t)函数的图像沿y轴(t=0)做了一次翻转。g(x-t)相当于g(-t)的整个图像沿着t轴进行了平移,向右平移了x个单位。他们相乘之后围起来的面积就是h(x)。
在这里插入图片描述
在这里插入图片描述
离散卷积的定义为:
在这里插入图片描述
2、卷积核:卷积核就相当于数字图像处理中的滤波算子。
例如:
在这里插入图片描述
输入图像:由三个矩阵构成——RGB三通道,其中每个元素都是0-255之间的一个整数。
卷积核:一个矩阵。
输出图像:一个矩阵构成,在深度学习中称作特征图。对于每个颜色通道都有一个特征图。
假设输入图像为7×7×3(长×宽×通道数),卷积核大小为3×3×3(长×宽×通道数),那我们就要在图像中取出3×3×3大小的区块。具体的卷积过程如下:
(下图中输入图像为RGB三通道图像,两个卷积核(w0和w1))
在这里插入图片描述
3、特征图:在每个卷积层,数据都是以三维形式存在的。你可以把它看成许多个二维图片叠在一起,其中每一个称为一个feature map。在输入层,如果是灰度图片,那就只有一个feature map;如果是彩色图片,一般就是3个feature map(红绿蓝)。层与层之间会有若干个卷积核(kernel),上一层和每个feature map跟每个卷积核做卷积,都会产生下一层的一个feature map。
在CNN的设定里,Feature Map是卷积核卷出来的,你用各种情况下的卷积核去乘以原图,会得到各种各样的feature map。
个人理解:从多角度去分析图片,不同的特征提取(核)会提取到不同的feature,模型为了达到最优解的目的,来找到能解释现象的最佳的一组卷积核。主要是和卷积核(kernel)区分开,kernel是要算的那个w权重矩阵,而feature map 是输入或者输出。
4、特征选择:对当前学习任务有价值的属性称为是 “相关特征”,没有价值的属性称为是 “无关特征”,从给定的特征集中选择出相关特征子集的过程,就称为是 “特征选择”。
其中还有一种特征称为是 “冗余特征”,这些特征指的是可以从其他特征中推演出来的特征。
(2)特征选择的重要性
特征选择是一个“数据预处理”过程,它的重要性体现在两个方面:
减轻维度灾难问题。
去除无关特征可以降低学习的难度。
5、步长:卷积步长也叫卷积步幅,英文名字是stride,代表滤波器每移动一次移动的步幅,s=2则滤波器每次移动2格。
6、填充: 填充是将输入图像的边缘用0填充,是为了减少边缘信息的丢失(因为像素点矩阵内部的像素点都会经过多次运算,边缘像素点相比之下计算次数少,就会造成边缘信息的丢失);保持输入输出图像尺寸一致,因为正常来讲,卷积得到的特征图像要比原始图像少,为了保持一致,就需要补0.
7、感受野:感受野(Receptive Field)的概念:在卷积神经网络中,感受野的定义是 卷积神经网络每一层输出的特征图(feature map)上的像素点在原始输入图像上映射的区域大小。第一层卷积层的输出特征图像素的感受野大小等于卷积核大小,其它卷积层的输出特征图的感受野的大小和它之前所有层的卷积核大小和步长有关系。
在这里插入图片描述

二、探究不同卷积核的作用

1、不同数值的卷积核对于图像卷积的影响,试着用这个网站试一下:https://setosa.io/ev/image-kernels/
在这里插入图片描述
在这里插入图片描述
2、不同大小的卷积核的影响:
大卷积核
优点:感受域范围大
举例:AlexNet、LeNet等网络都使用了比较大的卷积核,如5×5、11×11
缺点:参数量多:计算量大
小卷积核
优点:参数量少;计算量小;整合三个非线性激活层代替单一非线性激活层,增加模型判别能力
举例:VGG之后
缺点:感受域不足;深度堆叠卷积(也就是堆叠非线性激活),容易出现不可控的因素
3、不同形状的卷积核的影响:
如果我们将一个3×3的卷积核变成一个1×3的卷积核和一个3×1的卷积核,那么会有:
3×3卷积计算量:9×9 = 81次乘法
3×3卷积和3×1卷积的累加计算量:3×15+3×9 = 72次乘法
可以看出的是,1×3的卷积核和3×1的卷积核的运算是比3×3的运算速度快的。

三、编程实现

1、实现灰度图的边缘检测、锐化、模糊。(必做)

读入图片:

import numpy as np
import torch
from torch import nn
from torch.autograd import Variable
from PIL import Image
import matplotlib.pyplot as plt

plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号 #有中文出现的情况,需要u'内容
# https://blog.csdn.net/weixin_40123108/article/details/83510592
file_path = '1.jpg'
im = Image.open(r'1.jpg').convert('L')  # 读入一张灰度图的图片
im = np.array(im, dtype='float32')  # 将其转换为一个矩阵
print(im.shape[0], im.shape[1])
plt.imshow(im.astype('uint8'), cmap='gray')  # 可视化图片
plt.title('原图')
plt.show()

在这里插入图片描述
灰度图的边缘检测:

im = torch.from_numpy(im.reshape((1, 1, im.shape[0], im.shape[1])))
conv1 = nn.Conv2d(1, 1, 3, bias=False)  # 定义卷积

sobel_kernel = np.array([[-1, -1, -1],
                         [-1, 8, -1],
                         [-1, -1, -1]], dtype='float32')  # 定义轮廓检测算子
sobel_kernel = sobel_kernel.reshape((1, 1, 3, 3))  # 适配卷积的输入输出
conv1.weight.data = torch.from_numpy(sobel_kernel)  # 给卷积的 kernel 赋值

edge1 = conv1(Variable(im))  # 作用在图片上

x = edge1.data.squeeze().numpy()
print(x.shape)  # 输出大小

plt.imshow(x, cmap='gray')
plt.show()

在这里插入图片描述
灰度图的锐化:

import cv2
import numpy as np
import matplotlib.pyplot as plt

#读取图像
img = cv2.imread('1.jpg')
lenna_img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

#灰度化处理图像
grayImage = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

#高斯滤波
gaussianBlur = cv2.GaussianBlur(grayImage, (3,3), 0)

#阈值处理
ret, binary = cv2.threshold(gaussianBlur, 127, 255, cv2.THRESH_BINARY)

#Roberts算子
kernelx = np.array([[-1,0],[0,1]], dtype=int)
kernely = np.array([[0,-1],[1,0]], dtype=int)
x = cv2.filter2D(binary, cv2.CV_16S, kernelx)
y = cv2.filter2D(binary, cv2.CV_16S, kernely)
absX = cv2.convertScaleAbs(x)
absY = cv2.convertScaleAbs(y)
Roberts = cv2.addWeighted(absX, 0.5, absY, 0.5, 0)

#Prewitt算子
kernelx = np.array([[1,1,1],[0,0,0],[-1,-1,-1]], dtype=int)
kernely = np.array([[-1,0,1],[-1,0,1],[-1,0,1]], dtype=int)
x = cv2.filter2D(binary, cv2.CV_16S, kernelx)
y = cv2.filter2D(binary, cv2.CV_16S, kernely)
absX = cv2.convertScaleAbs(x)
absY = cv2.convertScaleAbs(y)
Prewitt = cv2.addWeighted(absX,0.5,absY,0.5,0)

#Sobel算子
x = cv2.Sobel(binary, cv2.CV_16S, 1, 0)
y = cv2.Sobel(binary, cv2.CV_16S, 0, 1)
absX = cv2.convertScaleAbs(x)
absY = cv2.convertScaleAbs(y)
Sobel = cv2.addWeighted(absX, 0.5, absY, 0.5, 0)

#拉普拉斯算法
dst = cv2.Laplacian(binary, cv2.CV_16S, ksize = 3)
Laplacian = cv2.convertScaleAbs(dst)

#效果图
titles = ['Source Image', 'Binary Image', 'Roberts Image',
          'Prewitt Image','Sobel Image', 'Laplacian Image']
images = [lenna_img, binary, Roberts, Prewitt, Sobel, Laplacian]
for i in np.arange(6):
    plt.subplot(2,3,i+1),plt.imshow(images[i],'gray')
    plt.title(titles[i])
    plt.xticks([]),plt.yticks([])
plt.show()

在这里插入图片描述
灰度图像的模糊
均值模糊:

import cv2
import numpy as np
import matplotlib.pyplot as plt

if __name__ == "__main__":
    image = cv2.imread(r'1.jpg')

    image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    # 此为均值模糊
    # (30,1)为一维卷积核,指在x,y方向偏移多少位
    dst1 = cv2.blur(image, (30, 1))

    # 此为中值模糊,常用于去除椒盐噪声
    dst2 = cv2.medianBlur(image, 15)

    # 自定义卷积核,执行模糊操作,也可定义执行锐化操作
    kernel = np.ones([5, 5], np.float32) / 25
    dst3 = cv2.filter2D(image, -1, kernel=kernel)

    plt.subplot(2, 2, 1)
    plt.imshow(image)
    plt.axis('off')
    plt.title('Offical')

    plt.subplot(2, 2, 2)
    plt.imshow(dst1)
    plt.axis('off')
    plt.title('Box blur')

    plt.subplot(2, 2, 3)
    plt.imshow(dst2)
    plt.axis('off')
    plt.title('median blur')

    plt.subplot(2, 2, 4)
    plt.imshow(dst3)
    plt.axis('off')
    plt.title('defined blur')

    plt.show()

在这里插入图片描述
高斯模糊:

import cv2
import numpy as np
import matplotlib.pyplot as plt


def clamp(pv):
    if pv > 255:
        return 255
    if pv < 0:
        return 0
    else:
        return pv


def gaussian_noise(image):        # 加高斯噪声
    h, w, c = image.shape
    for row in range(h):
        for col in range(w):
            s = np.random.normal(0, 20, 3)
            b = image[row, col, 0]   # blue
            g = image[row, col, 1]   # green
            r = image[row, col, 2]   # red
            image[row, col, 0] = clamp(b + s[0])
            image[row, col, 1] = clamp(g + s[1])
            image[row, col, 2] = clamp(r + s[2])
    dst = cv2.GaussianBlur(image, (15, 15), 0)  # 高斯模糊
    return dst, image


if __name__ == "__main__":
    src = cv2.imread(r'1.jpg')
    plt.subplot(2, 2, 1)
    plt.imshow(src)
    plt.axis('off')
    plt.title('Offical')

    output, noise = gaussian_noise(src)
    cvdst = cv2.GaussianBlur(src, (15, 15), 0)   # 高斯模糊

    plt.subplot(2, 2, 2)
    plt.imshow(noise)
    plt.axis('off')
    plt.title('Gaussian Noise')

    plt.subplot(2, 2, 3)
    plt.imshow(output)
    plt.axis('off')
    plt.title('Gaussian Blur')

    plt.subplot(2, 2, 4)
    plt.imshow(cvdst)
    plt.axis('off')
    plt.title('defined blur by opencv')

    plt.show()

在这里插入图片描述
运动模糊:

# 图像模糊处理
# 运动模糊,亦称动态模糊,motion blur
# 运动模糊:由于相机和物体之间的相对运动造成的模糊

import numpy as np
import cv2
import matplotlib.pyplot as plt


def motion_blur(image, degree=12, angle=45):

    image = np.array(image)
    # 这里生成任意角度的运动模糊kernel的矩阵, degree越大,模糊程度越高
    M = cv2.getRotationMatrix2D((degree / 2, degree / 2), angle, 1)
    motion_blur_kernel = np.diag(np.ones(degree))
    motion_blur_kernel = cv2.warpAffine(motion_blur_kernel, M, (degree, degree))
    motion_blur_kernel = motion_blur_kernel / degree
    blurred = cv2.filter2D(image, -1, motion_blur_kernel)
    # convert to uint8
    cv2.normalize(blurred, blurred, 0, 255, cv2.NORM_MINMAX)
    blurred = np.array(blurred, dtype=np.uint8)
    return blurred


if __name__ == "__main__":

    img = cv2.imread(r'1.jpg')
    dst = motion_blur(img)

    plt.subplot(1, 2, 1)
    plt.imshow(img)
    plt.axis('off')
    plt.title('Offical')

    plt.subplot(1, 2, 2)
    plt.imshow(dst)
    plt.axis('off')
    plt.title('Motion blur')

    plt.show()

在这里插入图片描述

2、调整卷积核参数,测试并总结。(必做)

图像锐化和模糊已给出不同参数的结果。
所以仅需修改边缘检测卷积核的参数,观察效果。
步长=2:
在这里插入图片描述
步长=4:
在这里插入图片描述
步长小,提取的特征会更全面,但同时可能造成计算量增大,甚至过拟合等问题。步长大,计算量会下降,但很有可能错失一些有用的特征。随着步长的变大,像素点逐渐减少,并且图像提取的边界越来越模糊。
padding=2:
在这里插入图片描述
padding=4:
在这里插入图片描述
加入padding后图像的边缘数据也能被利用到,这样才能更好的扩张整张图像的边缘特征,保持了边界的信息。

3、使用不同尺寸图片,测试并总结。(必做)

换个图像试一下:
原图:
在这里插入图片描述
边缘检测:
在这里插入图片描述
锐化:
在这里插入图片描述
模糊:
均值模糊:
在这里插入图片描述
高斯模糊:
在这里插入图片描述
运动模糊:
在这里插入图片描述

4.探索更多类型卷积核。(选做)

上面的模糊用到了均值模糊、高斯模糊、运动模糊。
均值模糊:

# 此为均值模糊
# (30,1)为一维卷积核,指在x,y方向偏移多少位
dst1 = cv2.blur(image, (30, 1))

# 此为中值模糊,常用于去除椒盐噪声
dst2 = cv2.medianBlur(image, 15)

# 自定义卷积核,执行模糊操作,也可定义执行锐化操作
kernel = np.ones([5, 5], np.float32) / 25
dst3 = cv2.filter2D(image, -1, kernel=kernel)

高斯模糊:

cvdst = cv2.GaussianBlur(src, (15, 15), 0)   # 高斯模糊

运动模糊:
    # 这里生成任意角度的运动模糊kernel的矩阵, degree越大,模糊程度越高
    M = cv2.getRotationMatrix2D((degree / 2, degree / 2), angle, 1)
    motion_blur_kernel = np.diag(np.ones(degree))
    motion_blur_kernel = cv2.warpAffine(motion_blur_kernel, M, (degree, degree))
    motion_blur_kernel = motion_blur_kernel / degree
    blurred = cv2.filter2D(image, -1, motion_blur_kernel)
    # convert to uint8
    cv2.normalize(blurred, blurred, 0, 255, cv2.NORM_MINMAX)

运行结果在问题1中灰度图像的模糊处理。

5、尝试彩色图片边缘检测。(选做)

import numpy as np
import torch
from torch import nn
from torch.autograd import Variable
from PIL import Image
import matplotlib.pyplot as plt

plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号# 加载图片
file_path = '2.jpg'
im = Image.open(file_path)
im = np.array(im, dtype='float32')
im = np.transpose(im, (2, 1, 0))
im = im[np.newaxis, :]
im = torch.from_numpy(im)
conv1 = nn.Conv2d(3, 3, 3, bias=False)  # 定义卷积
outline = np.array([[[-1, -1, -1],
                     [-1, 8, -1],
                     [-1, -1, -1]],
                    [[-1, -1, -1],
                     [-1, 8, -1],
                     [-1, -1, -1]],
                    [[-1, -1, -1],
                     [-1, 8, -1],
                     [-1, -1, -1]]]
                   , dtype='float32').reshape((1, 3, 3, 3))
conv1.weight.data = torch.from_numpy(outline)

y1 = conv1(Variable(im)).data.squeeze().numpy()# 可视化
plt.imshow(y1, cmap='gray')
plt.show()

在这里插入图片描述

运行结果:
在这里插入图片描述

总结

众所周知,卷积神经网络是深度学习中非常有代表性的学习领域,而深度学习又是机器学习的主要分支,因此卷积神经网络就是用来让机器学习的过程途径,而机器要学的就是图像中的特征,“卷积”就是用来提取特征的。
在卷积神经网络面前,所有图像都是矩阵,矩阵中就是一个个的像素,这些像素组成了我们肉眼看到的图像。最经典的CNN便是Let-5网络
在这里插入图片描述
卷积过程有三个重要的概念需要知道:局部感知、参数共享、池化
局部感知:
即网络部分连通,每个神经元只与上一层的部分神经元相连,只感知局部,而不是整幅图像。
局部感知通过滑窗实现,局部像素关系紧密,较远像素相关性弱。因此只需要局部感知,在更高层将局部的信息综合起来就得到了全局的信息。受启发于生物视觉系统:局部敏感;对外界认知从局部到全局。
权值共享:
从一个局部区域学习到的信息,应用到图像的其它地方去。即用一个相同的卷积核去卷积整幅图像,相当于对图像做一个全图滤波。一个卷积核对应的特征比如是边缘,那么用该卷积核去对图像做全图滤波,即是将图像各个位置的边缘都滤出来。(帮助实现不变性)。不同的特征靠多个不同的卷积核实现。
图像的局部统计特征在整幅图像上具有重复性(即位置无关性)。即如果图像中存在某个基本图形,该基本图形可能出现在任意位置,那么不同位置共享相同权值可实现在数据的不同位置检测相同的模式。比如我们在第一个窗口卷积后得到的特征是边缘,那么这个卷积核对应的就是边缘特征的提取方式,那么我们就可以用这个卷积核去提取其它区域的边缘特征。
池化:
比如max pooling,它是取一个区域的最大值。因此当图像发生平移、缩放、旋转等较小的变化时,依然很有可能在同一位置取到最大值,与变化前的响应相同,由此实现了仿射不变性。average pooling同理,发生较小的仿射变化后,均值可能依然不变。
受启发于生物视觉系统:局部敏感;对外界认知从局部到全局。
图像的卷积过程就相当于设置好的卷积核(滤波器),在图像矩阵上不停的进行滑动,将图片化为一个个patcks,卷积后我们会得到一个全新的图像。

本次实验学了卷积基础,卷积在人工智能框架这门课讲过,这次细致了解了卷积、卷积核、特征图、特征选择、步长、填充、感受野。其中感受野之前是不太了解的,这次通过上网查资料知道了很多,具体如下:
1、感受野的作用:
特征图上的感受野越大,那么该特征图上每一个特征点所能看到的原始输入图形上的区域就越大,所以该它越能检测比较大的物体,但是也越容易忽略小的物体。所以越大的感受野,越能考虑到整体,越能观察到全局信息。所以在实际的feature map中,随着网络深度的加深,浅层(浅层指的是刚进入神经网络的那几层)的feature map的感受野较小,所以它们主要包含低级的信息(物体边缘,颜色,初级位置信息等),深层的feature map的感受野较大,所以它们包含高等信息(例如物体的语义信息:狗,猫,汽车等等)。
2、感受野的计算:
第一层卷积层的输出特征图像素的感受野大小等于卷积核大小,其它卷积层的输出特征图的感受野的大小和它之前所有层的卷积核大小和步长有关系。
在下图中,输入图形的大小是5x5,假设保持滑动窗口的步长stride=1,padding=0,经过第一次卷积,得到的特征图大小是3x3,经过第二层卷积,得到的特征 图大小是1x1,所以第一层特征图的感受野是3x3,第二层特征图的感受野是5x5。
在这里插入图片描述
那么有人肯定有这个疑问,上图的卷积过程需要经过两次卷积才可以将原始输入图形变成1x1的特征图,这跟使用一个5x5的卷积核进行一次卷积得到的特征图 的结果是一样的,那为什么非要进行两处卷积呢?
假设输入大小都是hxwxc,并且都使用c个卷积核(得到c个特征图),可以来计算一下其各自所需参数:
一个5x5的卷积所需参数:cx(5x5xc)=25c^2
2个3x3卷积核所需参数:2xcx(3x3xc)=18c^2
很明显,堆叠小的卷积核所需的参数更少一些,并且卷积过程越多,特征提取也会越细致,加入的非线性变换也随着增多(因为通常情况下每个卷积层后面一般 都加激活函数,这些激活函数可以完成非线性变换,所以卷积层越多,非线性变换也随着增多),还不会增大权重参数个数,这就是VGG网络的基本出发点,用 小的卷积核来完成体特征提取操作。
如图所示 7x7 的原始图像,经过kernel_size=3, stride=2的Conv1,kernel_size=2, stride=1的Conv2后,输出特征图大小为 2x2,很明显,原始图像的每个单元的感受野为1,Conv1的每个单元的感受野为3,而由于Conv2的每个单元都是由 2x2 范围的Conv1构成,因此回溯到原始图像,每个单元能够看到 5x5 大小的区域范围。
在这里插入图片描述

参考文章

https://blog.csdn.net/onehao/article/details/90028325
https://blog.csdn.net/ly_twt/article/details/101194389
https://blog.csdn.net/m0_56192771/article/details/122934841
https://blog.csdn.net/weixin_43873671/article/details/114268967

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值