numpy手搓卷積

## numpy實(shí)現(xiàn)卷積 ### 1 卷積本質(zhì) - 設(shè)計(jì)這樣的一個(gè) 濾波器(filter,也稱(chēng)為kernel),用這個(gè)filter,往我們的圖片上“蓋”,覆蓋一塊跟filter一樣大的區(qū)域之后,對(duì)應(yīng)元素相乘,然后求和。計(jì)算一個(gè)區(qū)域之后,就向其他區(qū)域挪動(dòng),接著計(jì)算,直到把原圖片的每一個(gè)角落都覆蓋到了為止。這個(gè)過(guò)程就是 “卷積”。 - 可以通過(guò)設(shè)計(jì)特定的filter,讓它去跟圖片做卷積,就可以識(shí)別出圖片中的某些特征。 - CNN(convolutional neural network),主要就是通過(guò)一個(gè)個(gè)的filter,不斷地提取特征,從局部的特征到總體的特征,從而進(jìn)行圖像識(shí)別等等功能 - filter中的參數(shù)是通過(guò)大量的數(shù)據(jù),讓機(jī)器自己去“學(xué)習(xí)”這些參數(shù)。 ### 2 Padding方式 - 每次卷積,圖像都縮小,采用padding的方法。每次卷積前,先給圖片周?chē)佳a(bǔ)一圈空白,讓卷積之后圖片跟原來(lái)一樣大,同時(shí),原來(lái)的邊緣也被計(jì)算了更多次。 - “讓卷積之后的大小不變”的padding方式,稱(chēng)為 “Same”方式, 把不經(jīng)過(guò)任何填白的,稱(chēng)為 “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計(jì)算公式 ![](https://upload-images.jianshu.io/upload_images/24901004-bdc12e5ed0e5587d.png) ### 3 多卷積核多通道 - 在單核單通道的基礎(chǔ)上執(zhí)行多遍,然后把結(jié)果累加。 - (1)一個(gè)循環(huán)是輸入通道數(shù)對(duì)循環(huán):把卷積核在每個(gè)通道數(shù)據(jù)上卷積,然后結(jié)果累加 - (2)一個(gè)循環(huán)是核個(gè)數(shù)對(duì)循環(huán):每個(gè)卷積核執(zhí)行步驟(1),然后把結(jié)果累加,如下圖 ![](https://ai-studio-static-online.cdn.bcebos.com/fe3bc0d615eb49398a94b05b6f4608bf8508b93a4a36401fb4f636a2604dd2b1) ![](https://ai-studio-static-online.cdn.bcebos.com/fdbd8960755043f7badbbbaddbf3fac3027434f1fc4f421884524daced9d8d28) ### 4 代碼實(shí)現(xiàn)(循環(huán)計(jì)算實(shí)現(xiàn)和矩陣計(jì)算實(shí)現(xiàn)) #### 4.1 一維卷積 在 NumPy 中實(shí)現(xiàn)卷積操作可以通過(guò)使用 `numpy.convolve` 函數(shù)或手動(dòng)編寫(xiě)卷積操作的代碼來(lái)完成。以下是兩種方法的示例: **方法一:使用 `numpy.convolve` 函數(shù)** `numpy.convolve` 函數(shù)用于執(zhí)行一維卷積操作。首先,您需要定義一個(gè)卷積核(濾波器),然后將它應(yīng)用于輸入信號(hào)。下面是一個(gè)示例: ```python import numpy as np # 定義輸入信號(hào) signal = np.array([1, 2, 3, 4, 5]) # 定義卷積核(濾波器) kernel = np.array([0.5, 1, 0.5]) # 使用 numpy.convolve 執(zhí)行卷積操作 convolution_result = np.convolve(signal, kernel, mode='valid') print("卷積結(jié)果:", convolution_result) ``` 在這個(gè)示例中,`signal` 是輸入信號(hào),`kernel` 是卷積核。`mode='valid'` 表示執(zhí)行有效卷積,即僅計(jì)算信號(hào)和卷積核完全重疊的部分。輸出將是卷積的結(jié)果。 **方法二:手動(dòng)實(shí)現(xiàn)卷積操作** 您也可以手動(dòng)編寫(xiě)卷積操作的代碼,通過(guò)遍歷輸入信號(hào)并應(yīng)用卷積核來(lái)計(jì)算卷積的結(jié)果。以下是一個(gè)示例: ```python import numpy as np # 定義輸入信號(hào) signal = np.array([1, 2, 3, 4, 5]) # 定義卷積核(濾波器) kernel = np.array([0.5, 1, 0.5]) # 初始化卷積結(jié)果數(shù)組 convolution_result = np.zeros(len(signal) - len(kernel) + 1) # 執(zhí)行卷積操作 for i in range(len(convolution_result)): convolution_result[i] = np.sum(signal[i:i + len(kernel)] * kernel) print("卷積結(jié)果:", convolution_result) ``` 這個(gè)示例手動(dòng)執(zhí)行了卷積操作,遍歷輸入信號(hào)并計(jì)算卷積結(jié)果。輸出將與使用 `numpy.convolve` 函數(shù)得到的結(jié)果相同。 這兩種方法都可用于實(shí)現(xiàn)簡(jiǎn)單的卷積操作。然而,對(duì)于更復(fù)雜的卷積神經(jīng)網(wǎng)絡(luò) (CNN) 等應(yīng)用,通常會(huì)使用深度學(xué)習(xí)框架(如 TensorFlow 或 PyTorch),它們提供了高度優(yōu)化的卷積操作,能夠更高效地處理大型數(shù)據(jù)集和復(fù)雜的模型。 #### 4.2 二維卷積 手動(dòng)實(shí)現(xiàn)二維圖片數(shù)據(jù)的卷積操作涉及到卷積核(濾波器)在輸入圖像上滑動(dòng)并執(zhí)行點(diǎn)積運(yùn)算的過(guò)程。以下是一個(gè)使用 NumPy 手動(dòng)實(shí)現(xiàn)的簡(jiǎn)單示例: ```python import numpy as np # 創(chuàng)建一個(gè)示例的二維圖片數(shù)據(jù)(4x4 像素) image = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]], dtype=np.float32) # 定義一個(gè)卷積核(濾波器) kernel = np.array([[1, 0], [0, -1]], dtype=np.float32) # 獲取輸入圖像和卷積核的尺寸 image_height, image_width = image.shape kernel_height, kernel_width = kernel.shape # 計(jì)算卷積后的輸出圖像的尺寸 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) # 執(zhí)行卷積操作 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) # 打印卷積結(jié)果 print(output_image) ``` 在這個(gè)示例中,我們首先創(chuàng)建了一個(gè)示例的二維圖片數(shù)據(jù)和一個(gè)卷積核。然后,我們計(jì)算了卷積后的輸出圖像的尺寸,并初始化一個(gè)用于存儲(chǔ)輸出的數(shù)組。接下來(lái),我們使用兩層嵌套的循環(huán)遍歷輸入圖像,并在每個(gè)位置執(zhí)行卷積操作,將結(jié)果存儲(chǔ)在輸出圖像中。最后,我們打印了卷積的結(jié)果。 這個(gè)示例是一個(gè)簡(jiǎn)單的手動(dòng)卷積實(shí)現(xiàn),用于說(shuō)明卷積的基本原理。在實(shí)際應(yīng)用中,通常會(huì)使用深度學(xué)習(xí)框架來(lái)執(zhí)行卷積操作,因?yàn)樗鼈兲峁┝烁叨葍?yōu)化的卷積操作,并且能夠處理更大的圖像和復(fù)雜的卷積核。手動(dòng)實(shí)現(xiàn)卷積通常用于教育目的或深入理解卷積的工作原理。 #### 4.3 添加padding和stride 要用 NumPy 實(shí)現(xiàn)類(lèi)似 PyTorch 的 Conv2D 函數(shù),需要考慮卷積核的大小、步幅、填充以及多通道的情況。以下是一個(gè)簡(jiǎn)化的示例,用 NumPy 實(shí)現(xiàn)一個(gè)基本的 2D 卷積操作: ```python import numpy as np def conv2d_numpy(input_data, kernel, stride=1, padding=0): # 獲取輸入數(shù)據(jù)的尺寸 input_height, input_width = input_data.shape # 獲取卷積核的尺寸 kernel_height, kernel_width = kernel.shape # 計(jì)算輸出圖像的尺寸 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)) # 填充輸入數(shù)據(jù)(根據(jù)填充數(shù)量添加額外的行和列) if padding > 0: input_data = np.pad(input_data, ((padding, padding), (padding, padding)), mode='constant') # 執(zhí)行卷積操作 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 # 創(chuàng)建一個(gè)示例的二維圖片數(shù)據(jù)(4x4 像素) image = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]], dtype=np.float32) # 定義一個(gè)卷積核(濾波器) kernel = np.array([[1, 0], [0, -1]], dtype=np.float32) # 執(zhí)行自定義的卷積操作 result = conv2d_numpy(image, kernel, stride=1, padding=0) # 打印卷積結(jié)果 print(result) ``` 這個(gè)示例中,我們首先定義了一個(gè)自定義的 `conv2d_numpy` 函數(shù),用于執(zhí)行二維卷積操作。然后,我們創(chuàng)建了一個(gè)示例的二維圖片數(shù)據(jù)和一個(gè)卷積核,并調(diào)用自定義函數(shù)來(lái)執(zhí)行卷積操作。最后,我們打印了卷積的結(jié)果。 請(qǐng)注意,這是一個(gè)簡(jiǎn)化的實(shí)現(xiàn),不包括多通道、批次處理以及更復(fù)雜的功能。實(shí)際上,深度學(xué)習(xí)框架(如 PyTorch)提供了高度優(yōu)化的卷積操作,能夠處理多通道、批次和更復(fù)雜的模型。手動(dòng)實(shí)現(xiàn)卷積通常用于教育目的或深入理解卷積的工作原理。 #### 4.4 多通道支持 要為 `conv2d_numpy` 函數(shù)添加多通道卷積支持,您需要考慮輸入數(shù)據(jù)和卷積核的通道維度,并執(zhí)行多通道卷積操作。以下是一個(gè)經(jīng)過(guò)修改的示例,支持多通道卷積: ```python import numpy as np def conv2d_numpy(input_data, kernel, stride=1, padding=0): # 獲取輸入數(shù)據(jù)的尺寸和通道數(shù) input_height, input_width, input_channels = input_data.shape # 獲取卷積核的尺寸和通道數(shù) kernel_height, kernel_width, kernel_channels = kernel.shape # 計(jì)算輸出圖像的尺寸 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)) # 填充輸入數(shù)據(jù)(根據(jù)填充數(shù)量添加額外的行和列) if padding > 0: input_data = np.pad(input_data, ((padding, padding), (padding, padding), (0, 0)), mode='constant') # 執(zhí)行多通道卷積操作 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 # 創(chuàng)建一個(gè)示例的多通道二維圖片數(shù)據(jù)(4x4 像素,3個(gè)通道) image = np.random.rand(4, 4, 3).astype(np.float32) # 定義一個(gè)多通道的卷積核(濾波器) kernel = np.random.rand(2, 2, 3).astype(np.float32) # 執(zhí)行多通道卷積操作 result = conv2d_numpy(image, kernel, stride=1, padding=0) # 打印卷積結(jié)果 print(result) ``` 這個(gè)示例中,我們修改了 `conv2d_numpy` 函數(shù)以支持多通道的輸入數(shù)據(jù)和卷積核。在執(zhí)行卷積操作時(shí),我們遍歷了通道維度并對(duì)每個(gè)通道進(jìn)行卷積,然后將結(jié)果相加以生成輸出。請(qǐng)注意,多通道卷積需要確保輸入圖像和卷積核的通道數(shù)匹配,否則會(huì)出現(xiàn)維度錯(cuò)誤。 本文由[mdnice](https://mdnice.com/?platform=6)多平臺(tái)發(fā)布
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容