掘金 人工智能 04月30日 17:08
神经网络内部卷积实现
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

本文深入探讨了卷积神经网络(CNN)中的零填充(Zero-Padding)技术。零填充通过在输入数据周围添加零值像素,主要用于控制卷积操作后输出的空间尺寸,并尽可能保留边缘信息。文章详细解释了零填充在保持输出尺寸、保留边缘信息和支持更深网络方面的重要作用,并提供了零填充的实现方法和卷积计算的函数示例,有助于理解CNN中零填充的原理与应用。

📏 **保持输出尺寸**: 普通卷积操作会导致特征图尺寸缩小。通过零填充,可以控制输出尺寸,公式为OutputSize=(n+2p−k)/s−1,其中n是输入尺寸,p是填充量,k是卷积核大小,s是步长。

🖼️ **保留边缘信息**: 边缘像素被卷积核完整覆盖的次数较少,信息容易丢失。零填充能让边缘像素更多地参与卷积计算,避免信息损失,从而提升模型性能。

layers **支持更深的网络**: 在深层网络中,多次卷积可能导致特征图尺寸过小,无法继续运算。零填充可以维持特征图的尺寸,从而支持更深的网络结构设计。

🧮 **实现卷积计算**: 介绍了如何使用NumPy实现卷积计算中的关键步骤,包括使用np.multiply进行逐元素乘法,以及如何通过循环遍历样本和卷积核,完成卷积层的前向传播。

Zero-Padding

在卷积神经网络(CNN)中,‌Zero-Padding(零填充)‌是一种在输入数据(如图像)的周围添加零值像素的技术。它的主要目的是控制卷积操作后输出的空间尺寸(宽度和高度),同时尽可能多地保留边缘信息。

Zero-Padding的作用:

(1)保持输出尺寸

(2)保留边缘信息

(3)支持更深的网络

Zero-Padding实现

def zero_pad(X, pad):    """    对数据集X的所有样本进行0填充    Parameters:    X -- numpy数组,未填充的数据集,        shape=[num_samples, num_Height, num_Width, num_Chanel]    pad -- 是一个整数,表示对样本高宽填充的大小    Returns:    numpy数组,填充后的数据集    """    X_pad = np.pad(X, ((0,0), (pad,pad), (pad,pad), (0,0)), mode='constant')    return X_pad    import numpy as npX = np.random.randn(5,3,3,3)pad = 1X_pad = zero_pad(X, pad)print(f"X.shape={X.shape}")print(f"X_pad.shape={X_pad.shape}")print("填充前red:")print(X[0,:,:,0])print("填充后red通道:")print(X_pad[0,:,:,0])
X.shape=(5, 3, 3, 3)X_pad.shape=(5, 5, 5, 3)填充前red:[[-1.15376398 -0.75258694  0.24848238] [ 2.77979566 -0.32868589 -1.54132054] [-0.21763341 -2.30183587 -0.40836615]]填充后red通道:[[ 0.          0.          0.          0.          0.        ] [ 0.         -1.15376398 -0.75258694  0.24848238  0.        ] [ 0.          2.77979566 -0.32868589 -1.54132054  0.        ] [ 0.         -0.21763341 -2.30183587 -0.40836615  0.        ] [ 0.          0.          0.          0.          0.        ]]

实现一次卷积计算函数

这一部分中,实现一步卷积,也就是将滤波器应用于输入的单个位置。

np.multiply是NumPy 库中用于执行逐元素乘法(Element-wise Multiplication)的函数。它与 * 运算符在数组之间的运算效果相同,但与矩阵乘法(np.dot 或 @)完全不同

def conv_single_step(a_slice, w, b):    """    Arguments:    a_slice -- numpy数组,输入数据切片,           (n_h_filter, n_w_filter, n_c_filter)    w -- numpy数组,过滤器权值参数,           (n_h_filter, n_w_filter, n_c_filter)    b -- 标量,过滤器偏置参数,(1,1,1)        Returns:    Z -- 一个数值, sum(a_slice*w) + b。    """    s = np.multiply(a_slice, w)    Z = np.sum(s)    Z = Z + float(b)    # Z = Z + b    return Z    #1、随机生成一个大小为[3,3,3]的过滤器权值矩阵w#2、随机生成一个大小为[1,1,1]的过滤器偏置矩阵b#3、随机生成一个供卷积运算的的输入切片x;#4、调用conv_single_step函数并输出结果z。w = np.random.rand(3,3,3)b = 10x = np.random.rand(3,3,3)z = conv_single_step(x, w, b)print(z)#18.384722200888632

卷积层-实现卷积前向传播

在卷积层的前向传播过程中,需要使用多个过滤器在输入数据上对其进行卷积运算。每个过滤器都会输出一个2D矩阵。然后,堆叠这些2D输出矩阵以获得3D矩阵作为卷积层的输出。

关键点:

注意:

A_prev -- 卷积层的输入: shape=[num_samples, num_H_sample, num_W_sample, num_C_sample]

W -- 卷积层的所有卷积核组成的权值张量:shape=[num_H_filter, num_W_filter, num_C_filter, num_filters],

这个 num_C_sample==num_C_filter

import numpy as npdef zero_pad(X, pad):    """    对数据集X的所有样本进行0填充    Parameters:    X -- numpy数组,未填充的数据集,        shape=[num_samples, num_Height, num_Width, num_Chanel]    pad -- 是一个整数,表示对样本高宽填充的大小    Returns:    numpy数组,填充后的数据集    """    X_pad = np.pad(X, ((0,0), (pad,pad), (pad,pad), (0,0)), mode='constant')    return X_paddef conv_single_step(a_slice, w, b):    """    Arguments:    a_slice -- numpy数组,输入数据切片,           (n_h_filter, n_w_filter, n_c_filter)    w -- numpy数组,过滤器权值参数,           (n_h_filter, n_w_filter, n_c_filter)    b -- 标量,过滤器偏置参数,(1,1,1)        Returns:    Z -- 一个数值, sum(a_slice*w) + b。    """    s = np.multiply(a_slice, w)    Z = np.sum(s)    Z = Z + float(b)    # Z = Z + b    return Zdef conv_3d(inp, W, B, stride, pad):    """    Functions:    对3d数据进行卷积计算        Parameters:    inp -- numpy数组,卷积层的输入           shape=[num_samples, num_H_sample, num_W_sample, num_C_sample]    W -- numpy数组,卷积层的所有卷积核(过滤器)组成的权值张量         shape=[num_H_filter, num_W_filter, num_C_filter, num_filters]    B -- 卷积层所有卷积核的偏置组成的向量:          shape=[1,1,1,num_filters]    stride -- 卷积移动的步长    pad -- 填充大小        Returns:    Z -- 线性输出,卷积运算后的结果    """    n_samples, n_H_sample, n_W_sample, n_C_sample = inp.shape # 样本    n_h_filter, n_w_filter, n_c_filter, n_filters = W.shape #卷积核    n_H = int((n_H_sample - n_h_filter + 2*pad)/stride) + 1    n_W = int((n_W_sample - n_w_filter + 2*pad)/stride) + 1    n_C = n_filters    Z = np.zeros((n_samples, n_H, n_W, n_C)) # 构造输出矩阵     inp_pad = zero_pad(inp, pad) #pading    for i in range(n_samples):          # 遍历训练集的每个样本        sample = inp_pad[i]         # 选择第i个样本                for h in range(n_H):               # 遍历输出矩阵体的高            # 垂直方向,初始 h=0 0:stride            vert_start = stride * h             # 固定样本垂直方向上的起始位置             vert_end = vert_start  + n_h_filter  # 固定样本垂直方向上的结束位置              for w in range(0, n_W):                   # 遍历输出矩阵的宽                # 水平方向 初始 w=0 0:stride                horiz_start = stride * w             # 固定样本在水平方向上的起始位置                horiz_end = horiz_start + n_w_filter  # 固定样本在水平方向上的结束位置                for c in range(0, n_C):                    # 从样本上切片 (n_h_filter, n_w_filter, n_c_filter)                    a_slice = sample[vert_start:vert_end,horiz_start:horiz_end,:]                    Z[i,h,w,c] = conv_single_step(a_slice,W[:,:,:,c],B[:,:,:,c])    return Zsample=np.random.randn(10,5,5,3)# sample =sample[0]  # 得到第i个样本print("样本的shape:",sample.shape)W=np.random.randn(3,3,3,8)B=np.random.randn(1,1,1,8)Z = conv_3d(sample, W, B, stride=1, pad=0)print("卷积后的shape:",Z.shape)    #样本的shape: (10, 5, 5, 3)#卷积后的shape: (10, 3, 3, 8)

Fish AI Reader

Fish AI Reader

AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

FishAI

FishAI

鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

联系邮箱 441953276@qq.com

相关标签

零填充 卷积神经网络 图像处理 深度学习
相关文章