numpy手搓卷积

## numpy实现卷积 ### 1 卷积本质 - 设计这样的一个 滤波器(filter,也称为kernel),用这个filter,往我们的图片上“盖”,覆盖一块跟filter一样大的区域之后,对应元素相乘,然后求和。计算一个区域之后,就向其他区域挪动,接着计算,直到把原图片的每一个角落都覆盖到了为止。这个过程就是 “卷积”。 - 可以通过设计特定的filter,让它去跟图片做卷积,就可以识别出图片中的某些特征。 - CNN(convolutional neural network),主要就是通过一个个的filter,不断地提取特征,从局部的特征到总体的特征,从而进行图像识别等等功能 - filter中的参数是通过大量的数据,让机器自己去“学习”这些参数。 ### 2 Padding方式 - 每次卷积,图像都缩小,采用padding的方法。每次卷积前,先给图片周围都补一圈空白,让卷积之后图片跟原来一样大,同时,原来的边缘也被计算了更多次。 - “让卷积之后的大小不变”的padding方式,称为 “Same”方式, 把不经过任何填白的,称为 “Valid”方式。 #### 2.1 “Valid”方式 ![](https://ai-studio-static-online.cdn.bcebos.com/8131725726ac4e729751f6208a64e1b326d0c3b5e04f4600a7737b72ec6a6780) #### 2.1 “Same”方式 ![](https://ai-studio-static-online.cdn.bcebos.com/bd68f585f81d443292a5c8af76aae336718a4126cbb744c68629ca8eabd4a1ba) #### 2.3 Padding计算公式 ![](https://upload-images.jianshu.io/upload_images/24901004-bdc12e5ed0e5587d.png) ### 3 多卷积核多通道 - 在单核单通道的基础上执行多遍,然后把结果累加。 - (1)一个循环是输入通道数对循环:把卷积核在每个通道数据上卷积,然后结果累加 - (2)一个循环是核个数对循环:每个卷积核执行步骤(1),然后把结果累加,如下图 ![](https://ai-studio-static-online.cdn.bcebos.com/fe3bc0d615eb49398a94b05b6f4608bf8508b93a4a36401fb4f636a2604dd2b1) ![](https://ai-studio-static-online.cdn.bcebos.com/fdbd8960755043f7badbbbaddbf3fac3027434f1fc4f421884524daced9d8d28) ### 4 代码实现(循环计算实现和矩阵计算实现) #### 4.1 一维卷积 在 NumPy 中实现卷积操作可以通过使用 `numpy.convolve` 函数或手动编写卷积操作的代码来完成。以下是两种方法的示例: **方法一:使用 `numpy.convolve` 函数** `numpy.convolve` 函数用于执行一维卷积操作。首先,您需要定义一个卷积核(滤波器),然后将它应用于输入信号。下面是一个示例: ```python import numpy as np # 定义输入信号 signal = np.array([1, 2, 3, 4, 5]) # 定义卷积核(滤波器) kernel = np.array([0.5, 1, 0.5]) # 使用 numpy.convolve 执行卷积操作 convolution_result = np.convolve(signal, kernel, mode='valid') print("卷积结果:", convolution_result) ``` 在这个示例中,`signal` 是输入信号,`kernel` 是卷积核。`mode='valid'` 表示执行有效卷积,即仅计算信号和卷积核完全重叠的部分。输出将是卷积的结果。 **方法二:手动实现卷积操作** 您也可以手动编写卷积操作的代码,通过遍历输入信号并应用卷积核来计算卷积的结果。以下是一个示例: ```python import numpy as np # 定义输入信号 signal = np.array([1, 2, 3, 4, 5]) # 定义卷积核(滤波器) kernel = np.array([0.5, 1, 0.5]) # 初始化卷积结果数组 convolution_result = np.zeros(len(signal) - len(kernel) + 1) # 执行卷积操作 for i in range(len(convolution_result)): convolution_result[i] = np.sum(signal[i:i + len(kernel)] * kernel) print("卷积结果:", convolution_result) ``` 这个示例手动执行了卷积操作,遍历输入信号并计算卷积结果。输出将与使用 `numpy.convolve` 函数得到的结果相同。 这两种方法都可用于实现简单的卷积操作。然而,对于更复杂的卷积神经网络 (CNN) 等应用,通常会使用深度学习框架(如 TensorFlow 或 PyTorch),它们提供了高度优化的卷积操作,能够更高效地处理大型数据集和复杂的模型。 #### 4.2 二维卷积 手动实现二维图片数据的卷积操作涉及到卷积核(滤波器)在输入图像上滑动并执行点积运算的过程。以下是一个使用 NumPy 手动实现的简单示例: ```python import numpy as np # 创建一个示例的二维图片数据(4x4 像素) image = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]], dtype=np.float32) # 定义一个卷积核(滤波器) kernel = np.array([[1, 0], [0, -1]], dtype=np.float32) # 获取输入图像和卷积核的尺寸 image_height, image_width = image.shape kernel_height, kernel_width = kernel.shape # 计算卷积后的输出图像的尺寸 output_height = image_height - kernel_height + 1 output_width = image_width - kernel_width + 1 # 初始化输出图像 output_image = np.zeros((output_height, output_width), dtype=np.float32) # 执行卷积操作 for i in range(output_height): for j in range(output_width): output_image[i, j] = np.sum(image[i:i+kernel_height, j:j+kernel_width] * kernel) # 打印卷积结果 print(output_image) ``` 在这个示例中,我们首先创建了一个示例的二维图片数据和一个卷积核。然后,我们计算了卷积后的输出图像的尺寸,并初始化一个用于存储输出的数组。接下来,我们使用两层嵌套的循环遍历输入图像,并在每个位置执行卷积操作,将结果存储在输出图像中。最后,我们打印了卷积的结果。 这个示例是一个简单的手动卷积实现,用于说明卷积的基本原理。在实际应用中,通常会使用深度学习框架来执行卷积操作,因为它们提供了高度优化的卷积操作,并且能够处理更大的图像和复杂的卷积核。手动实现卷积通常用于教育目的或深入理解卷积的工作原理。 #### 4.3 添加padding和stride 要用 NumPy 实现类似 PyTorch 的 Conv2D 函数,需要考虑卷积核的大小、步幅、填充以及多通道的情况。以下是一个简化的示例,用 NumPy 实现一个基本的 2D 卷积操作: ```python import numpy as np def conv2d_numpy(input_data, kernel, stride=1, padding=0): # 获取输入数据的尺寸 input_height, input_width = input_data.shape # 获取卷积核的尺寸 kernel_height, kernel_width = kernel.shape # 计算输出图像的尺寸 output_height = (input_height - kernel_height + 2 * padding) // stride + 1 output_width = (input_width - kernel_width + 2 * padding) // stride + 1 # 初始化输出图像 output_data = np.zeros((output_height, output_width)) # 填充输入数据(根据填充数量添加额外的行和列) if padding > 0: input_data = np.pad(input_data, ((padding, padding), (padding, padding)), mode='constant') # 执行卷积操作 for i in range(0, input_height - kernel_height + 1, stride): for j in range(0, input_width - kernel_width + 1, stride): output_data[i // stride, j // stride] = np.sum(input_data[i:i+kernel_height, j:j+kernel_width] * kernel) return output_data # 创建一个示例的二维图片数据(4x4 像素) image = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]], dtype=np.float32) # 定义一个卷积核(滤波器) kernel = np.array([[1, 0], [0, -1]], dtype=np.float32) # 执行自定义的卷积操作 result = conv2d_numpy(image, kernel, stride=1, padding=0) # 打印卷积结果 print(result) ``` 这个示例中,我们首先定义了一个自定义的 `conv2d_numpy` 函数,用于执行二维卷积操作。然后,我们创建了一个示例的二维图片数据和一个卷积核,并调用自定义函数来执行卷积操作。最后,我们打印了卷积的结果。 请注意,这是一个简化的实现,不包括多通道、批次处理以及更复杂的功能。实际上,深度学习框架(如 PyTorch)提供了高度优化的卷积操作,能够处理多通道、批次和更复杂的模型。手动实现卷积通常用于教育目的或深入理解卷积的工作原理。 #### 4.4 多通道支持 要为 `conv2d_numpy` 函数添加多通道卷积支持,您需要考虑输入数据和卷积核的通道维度,并执行多通道卷积操作。以下是一个经过修改的示例,支持多通道卷积: ```python import numpy as np def conv2d_numpy(input_data, kernel, stride=1, padding=0): # 获取输入数据的尺寸和通道数 input_height, input_width, input_channels = input_data.shape # 获取卷积核的尺寸和通道数 kernel_height, kernel_width, kernel_channels = kernel.shape # 计算输出图像的尺寸 output_height = (input_height - kernel_height + 2 * padding) // stride + 1 output_width = (input_width - kernel_width + 2 * padding) // stride + 1 # 初始化输出图像 output_data = np.zeros((output_height, output_width)) # 填充输入数据(根据填充数量添加额外的行和列) if padding > 0: input_data = np.pad(input_data, ((padding, padding), (padding, padding), (0, 0)), mode='constant') # 执行多通道卷积操作 for i in range(0, input_height - kernel_height + 1, stride): for j in range(0, input_width - kernel_width + 1, stride): for k in range(kernel_channels): output_data[i // stride, j // stride] += np.sum(input_data[i:i+kernel_height, j:j+kernel_width, k] * kernel[:, :, k]) return output_data # 创建一个示例的多通道二维图片数据(4x4 像素,3个通道) image = np.random.rand(4, 4, 3).astype(np.float32) # 定义一个多通道的卷积核(滤波器) kernel = np.random.rand(2, 2, 3).astype(np.float32) # 执行多通道卷积操作 result = conv2d_numpy(image, kernel, stride=1, padding=0) # 打印卷积结果 print(result) ``` 这个示例中,我们修改了 `conv2d_numpy` 函数以支持多通道的输入数据和卷积核。在执行卷积操作时,我们遍历了通道维度并对每个通道进行卷积,然后将结果相加以生成输出。请注意,多通道卷积需要确保输入图像和卷积核的通道数匹配,否则会出现维度错误。 本文由[mdnice](https://mdnice.com/?platform=6)多平台发布
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容