卷积神经网络

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)。

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

def conv(x, k):
    H, W = k.shape
    output = np.zeros((x.shape[0]-H+1, x.shape[1]-W+1))
    for i in range(output.shape[0]):
        for j in range(output.shape[1]):
            output[i, j] = (X[i:i+H, j:j+W] * k).sum()
    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),卷积核的维度与图像的维度相卷积,然后累加,最后只输出一个二维矩阵,只有一个输出通道就是如此。

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

def mul_cocv(X, K):
    t = X.shape[0]
    result = np.zeros((X.shape[1]-K.shape[1]+1, X.shape[2]-K.shape[2]+1))
    for i in range(t):
        result += conv(X[i], K[i])
    return result

2.多输出通道

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

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

def mul_cocv(X, K):
    t = X.shape[0]
    result = np.zeros((X.shape[1]-K.shape[1]+1, X.shape[2]-K.shape[2]+1))
    for i in range(t):
        result += conv(X[i], K[i])
    return result
#多通道输出
def mul_conv_out(X, K):
    output_shape = K.shape[0]
    result = []
    for i in range(output_shape):
        result.append(mul_cocv(X,K[i]))
    return np.array(result)
        

3.1*1的卷积层

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

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

5.池化层

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

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

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

def pool2d(X, pool_size, mode="max"):
    h, w = pool_size
    output = np.zeros((X.shape[0]-h+1, X.shape[1]-w+1))
    for i in range(output.shape[0]):
        for j in range(output.shape[1]):
            if mode=="max":
                output[i,j] = X[i:i+h, j:j+w].max()
            elif mode == "avg":
                output[i,j] = X[i:i+h, j:j+w].mean()
    return output

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

2.多个通道

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

你可能感兴趣的:(cnn,深度学习,神经网络)