• 卷积神经网络


    1.卷积层

    先引入一个二维卷积:

            f*g=\sum \sum f(a, b)g(i-a,j-b)

    表示f的索引(a,b)和g的索引(i-a,j-b)的对应和相加。

           对于一个二维数组A,其维度为w,h,使用一个卷积核为m,n,在不加以填充的前提条件下,输出维度为(w-m+1, h-n+1)。

    这样一个二维卷积计算为:

    1. def conv(x, k):
    2. H, W = k.shape
    3. output = np.zeros((x.shape[0]-H+1, x.shape[1]-W+1))
    4. for i in range(output.shape[0]):
    5. for j in range(output.shape[1]):
    6. output[i, j] = (X[i:i+H, j:j+W] * k).sum()
    7. return output

    2.特征映射和感受野

           卷积层也被称为特征映射,而某一层的任意元素x,受到前面几层的影响所包含的范围就是感受野。

            比如给定一个矩阵大小为9*9,第一层卷积核大小为3*3,第二层也为3*3,则输出后的第一层矩阵为A,大小为(7*7),一共四十九个元素,每个元素受到前面3*3的作用,因此这个第一层的感受野为3*3,第二层生成的矩阵大小为(5*5),它在前一层的感受野为3*3,原始图像的感受野为5*5,因此如果我们需要更大的感受野,可以加深卷积层的深度。

    3.填充和步幅

    1.填充

            在前面的卷积过程中,明显会丢失一些边缘信息,导致输出矩阵的维度减小了。为了维持输出矩阵的维度,可以给矩阵的边缘填充数行或者数列。

            假设卷积核的大小为(h,w),二维矩阵的大小(m,n)那么我们需要填充的高度和宽度为h-1和w-1,经过卷积层之后,维度将会保持不变。一般情况下卷积核的大小为奇数,这样容易计算,上下侧和左右侧都天骄(h-1)/2和(w-1)/2,如果为偶数,则上册添加(h-1)/2行,数字向上取整,底部添加(h-1)/2,数字向下取值。左右也是如此计算。

    2.步幅

    假设二维矩阵大小和卷积核大小还是(m,n)和(h,w);ph=h-1,pw=w-1

    在窗口移动的过程,水平移动的步长为sw,垂直移动的步长为sh,则输出的形状为(m-h+ph+sh)/sh,(n-w+pw+sw)/sw

    4.多输入输出通道

    1.多输入通道

    总所周知,图像一般是包含有三个通达的,因此他们一般是三维张量(3,h,w)

    当输入包含多个通道的时候,需要构造一个具有与输入数据相同输入通道的卷积核,假设图片是三维张量(3,h,w),则卷积核的大小为(3,h,w),卷积核的维度与图像的维度相卷积,然后累加,最后只输出一个二维矩阵,只有一个输出通道就是如此。

    1. def conv(x, k):
    2. H, W = k.shape
    3. output = np.zeros((x.shape[0]-H+1, x.shape[1]-W+1))
    4. for i in range(output.shape[0]):
    5. for j in range(output.shape[1]):
    6. output[i, j] = (x[i:i+H, j:j+W] * k).sum()
    7. return output
    8. def mul_cocv(X, K):
    9. t = X.shape[0]
    10. result = np.zeros((X.shape[1]-K.shape[1]+1, X.shape[2]-K.shape[2]+1))
    11. for i in range(t):
    12. result += conv(X[i], K[i])
    13. return result

    2.多输出通道

    上面讨论的输出都是单通道,再卷积神经网络中会用到多通道,卷积核大小为(output,input,h,w),将单通道扩展到多通道,就是将每一个卷积核通道与对应的多维矩阵进行卷积。

    1. def conv(x, k):
    2. H, W = k.shape
    3. output = np.zeros((x.shape[0]-H+1, x.shape[1]-W+1))
    4. for i in range(output.shape[0]):
    5. for j in range(output.shape[1]):
    6. output[i, j] = (x[i:i+H, j:j+W] * k).sum()
    7. return output
    8. def mul_cocv(X, K):
    9. t = X.shape[0]
    10. result = np.zeros((X.shape[1]-K.shape[1]+1, X.shape[2]-K.shape[2]+1))
    11. for i in range(t):
    12. result += conv(X[i], K[i])
    13. return result
    14. #多通道输出
    15. def mul_conv_out(X, K):
    16. output_shape = K.shape[0]
    17. result = []
    18. for i in range(output_shape):
    19. result.append(mul_cocv(X,K[i]))
    20. return np.array(result)

    3.1*1的卷积层

    M*N的卷积层可以学习到相邻像素的相关特征,1*1的卷积核的计算仅仅是将同一个像素的通道连接到了一起,做了一个线性变换,所以1*1的卷积核相当于贯穿输入维度的全连接层。

    PS:上面的所有运算都没有使用激活函数

    5.池化层

    池化层的作用是降低隐藏表示的空间分辨率,聚合信息,同时还能产生平移不变性。简单来讲,就是降低卷积层对 位置的敏感性,同时降低对空间降采样的敏感性。池化层没有太复杂的运算,只是把窗口的数据进行简单的计算,池化层一般分为两种,一个是最大池化层,另一个是平均池化层。

    1.最大池化层和平均池化层

    池化层的窗口和单通道的卷积层窗口计算规律一致,也可以调整步长和填充,默认情况下步幅和窗口大小一致。下面的代码时池化层的计算方法

    1. def pool2d(X, pool_size, mode="max"):
    2. h, w = pool_size
    3. output = np.zeros((X.shape[0]-h+1, X.shape[1]-w+1))
    4. for i in range(output.shape[0]):
    5. for j in range(output.shape[1]):
    6. if mode=="max":
    7. output[i,j] = X[i:i+h, j:j+w].max()
    8. elif mode == "avg":
    9. output[i,j] = X[i:i+h, j:j+w].mean()
    10. return output

    这里没有写步幅和填充怎么实现,但是也不是很难,就是稍微有点麻烦,在矩阵周围填充,还有移动过程的步长设置一下就行了。

    2.多个通道

    在处理多个通道的时候,池化层在每个通道上都进行了一次计算。

  • 相关阅读:
    0-JavaWeb基础总结
    【无标题】
    半导体晶片切割
    计算机网络原原理学习资料分享---第一章/第一节(为有梦想的自己加油!)
    Centos、OpenEuler OS更改源地址
    纽约时报个人叙事赛及纽约时报学生评论赛选哪个?
    AVL树详解(附带旋转步骤图,手把手带你上分)
    【力扣周赛】第 112 场双周赛
    pytest学习笔记
    新架构Mamba是否真的有用?
  • 原文地址:https://blog.csdn.net/weixin_42581560/article/details/133495296