百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 热门文章 > 正文

教你从何从0开始使用Numpy实现卷积层

bigegpt 2024-09-25 14:27 4 浏览

CNN中的卷积操作

卷积层是CNNs网络中可以说是最重要的层了,卷积层的主要作用是对输入图像求卷积运算。如下图所示,输入图片的维数为[c_0,h_0,w_0] ;卷积核的维数为[c_1,c_0,h_k,w_k],其中c_0在图中没有表示出来,一个卷积核可以看成由c_1个维数为[c_0,h_k,w_k]的三维滤波器组成;除了这些参数通常在计算卷积运算的时候还有一些超参数比如:stride(步长):S,padding(填充):P。

根据上面所说的参数就可以求出输出特征的维数为[c_1,h_1,w_1],其中

h_1 = (h_0-h_k+2P)/S+1,

w_1 = (w_0-w_k+2P)/S+1。

卷积的计算过程其实很简单,但不是很容易说清楚,下面通过代码来说明。

基本环境设置:

%load_ext cython #代码运行在jupyter-notebook中
import matplotlib.pyplot as plt
import numpy as np
%matplotlib inline
plt.rcParams['figure.figsize'] = (10.0, 8.0) # set default size of plots
plt.rcParams['image.interpolation'] = 'nearest'
plt.rcParams['image.cmap'] = 'gray'

卷积层计算的代码如下,想象一副图像尺寸为MxM,卷积核mxm。在计算时,卷积核与图像中每个mxm大小的图像块做element-wise相乘,然后得到的结果相加得到一个值,然后再移动一个stride,做同样的运算,直到整副输入图像遍历完,上述过程得到的值就组成了输出特征,具体运算过程还是看代码。

def conv_forward_naive(x, w, b, conv_param):

out = None

stride = conv_param['stride']

pad = conv_param['pad']

N, C, W, H = x.shape

F, C, HH, WW = w.shape

H_out = 1 + (H + 2 * pad - HH) / stride

W_out = 1 + (W + 2 * pad - WW) / stride

npad = ((0,0), (0,0), (pad,pad), (pad,pad))

x_pad = np.pad(x, pad_width=npad, mode='constant', constant_values=0)

out = np.zeros((N, F, H_out, W_out))

for i in xrange(N):

for j in xrange(F):

for k in xrange(H_out):

for z in xrange(W_out):

out[i, j, k, z] = np.sum(x_pad[i, :, k*stride:k*stride+HH, z*stride:z*stride+WW]*w[j, :, :, :])+b[j]

cache = (x, w, b, conv_param)

return out, cache

下面来检测下上面的卷积计算代码,我们人为的设置两个卷积核(分别为求灰度特征,和边缘特征),然后对两幅输入图像求卷积,观察输出的结果:

from scipy.misc import imread, imresize
kitten, puppy = imread('kitten.jpg'), imread('puppy.jpg')
d = kitten.shape[1] - kitten.shape[0]
kitten_cropped = kitten[:, d/2:-d/2, :]
img_size = 200 # Make this smaller if it runs too slow
x = np.zeros((2, 3, img_size, img_size))
x[0, :, :, :] = imresize(puppy, (img_size, img_size)).transpose((2, 0, 1))
x[1, :, :, :] = imresize(kitten_cropped, (img_size, img_size)).transpose((2, 0, 1))
# Set up a convolutional weights holding 2 filters, each 3x3
w = np.zeros((2, 3, 3, 3))
# The first filter converts the image to grayscale.
# Set up the red, green, and blue channels of the filter.
w[0, 0, :, :] = [[0, 0, 0], [0, 0.3, 0], [0, 0, 0]]
w[0, 1, :, :] = [[0, 0, 0], [0, 0.6, 0], [0, 0, 0]]
w[0, 2, :, :] = [[0, 0, 0], [0, 0.1, 0], [0, 0, 0]]
# Second filter detects horizontal edges in the blue channel.
w[1, 2, :, :] = [[1, 2, 1], [0, 0, 0], [-1, -2, -1]]
# Vector of biases. We don't need any bias for the grayscale
# filter, but for the edge detection filter we want to add 128
# to each output so that nothing is negative.
b = np.array([0, 128])
# Compute the result of convolving each input in x with each filter in w,
# offsetting by b, and storing the results in out.
out, _ = conv_forward_naive(x, w, b, {'stride': 1, 'pad': 1})
def imshow_noax(img, normalize=True):
 """ Tiny helper to show images as uint8 and remove axis labels """
 if normalize:
 img_max, img_min = np.max(img), np.min(img)
 img = 255.0 * (img - img_min) / (img_max - img_min)
 plt.imshow(img.astype('uint8'))
 plt.gca().axis('off')
# Show the original images and the results of the conv operation
plt.subplot(2, 3, 1)
imshow_noax(puppy, normalize=False)
plt.title('Original image')
plt.subplot(2, 3, 2)
imshow_noax(out[0, 0])
plt.title('Grayscale')
plt.subplot(2, 3, 3)
imshow_noax(out[0, 1])
plt.title('Edges')
plt.subplot(2, 3, 4)
imshow_noax(kitten_cropped, normalize=False)
plt.subplot(2, 3, 5)
imshow_noax(out[1, 0])
plt.subplot(2, 3, 6)
imshow_noax(out[1, 1])
plt.show()

图像经过卷积后,输入结果如下所示:

im2col

运行上面代码的时候,我们发现对这两张图片计算卷积还是比较慢的,而在CNN中是存在大量的卷积运算的,所以我们需要一个更加快速的计算卷积的方法。如下图所示为Caffe中计算卷积的示意图,通过上面普通卷积运算的实现我们可以发现,卷积操作实际上是在对输入特征的一定范围内和卷积核滤波器做点乘,如下图我们可以利用这一特性把卷积操作转换成两个大矩阵相乘。

把输入图像要经行卷积操作的这一区域展成列向量的操作通常称为im2col,具体过程如下图所示。

下图为一个具体的例子,看懂下面这个图应该就会清楚上面的做法。

下面的im2col_cython是使用Cython代码来实现im2col功能,有关Cython在Python中的具体使用可参考:Python速度优化-Cython中numpy以及多线程的使用

%%cython

import cython

cimport numpy as np

import numpy as np

ctypedef fused DTYPE_t:

np.float32_t

np.float64_t

def im2col_cython(np.ndarray[DTYPE_t, ndim=4] x, int field_height,

int field_width, int padding, int stride):

cdef int N = x.shape[0]

cdef int C = x.shape[1]

cdef int H = x.shape[2]

cdef int W = x.shape[3]

cdef int HH = (H + 2 * padding - field_height) / stride + 1

cdef int WW = (W + 2 * padding - field_width) / stride + 1

cdef int p = padding

cdef np.ndarray[DTYPE_t, ndim=4] x_padded = np.pad(x,

((0, 0), (0, 0), (p, p), (p, p)), mode='constant')

cdef np.ndarray[DTYPE_t, ndim=2] cols = np.zeros(

(C * field_height * field_width, N * HH * WW),

dtype=x.dtype)

# Moving the inner loop to a C function with no bounds checking works, but does

# not seem to help performance in any measurable way.

cdef int c, ii, jj, row, yy, xx, i, col

for c in range(C):

for yy in range(HH):

for xx in range(WW):

for ii in range(field_height):

for jj in range(field_width):

row = c * field_width * field_height + ii * field_height + jj

for i in range(N):

col = yy * WW * N + xx * N + i

cols[row, col] = x_padded[i, c, stride * yy + ii, stride * xx + jj]

return cols

调用上面的im2col_cython函数来实现卷积操作:

def conv_forward_im2col(x, w, b, conv_param):
 """
 A fast implementation of the forward pass for a convolutional layer
 based on im2col and col2im.
 """
 N, C, H, W = x.shape
 num_filters, _, filter_height, filter_width = w.shape
 stride, pad = conv_param['stride'], conv_param['pad']
 # Check dimensions
 assert (W + 2 * pad - filter_width) % stride == 0, 'width does not work'
 assert (H + 2 * pad - filter_height) % stride == 0, 'height does not work'
 # Create output
 out_height = (H + 2 * pad - filter_height) / stride + 1
 out_width = (W + 2 * pad - filter_width) / stride + 1
 out = np.zeros((N, num_filters, out_height, out_width), dtype=x.dtype)
 # x_cols = im2col_indices(x, w.shape[2], w.shape[3], pad, stride)
 x_cols = im2col_cython(x, w.shape[2], w.shape[3], pad, stride)
 res = w.reshape((w.shape[0], -1)).dot(x_cols) + b.reshape(-1, 1)
 out = res.reshape(w.shape[0], out.shape[2], out.shape[3], x.shape[0])
 out = out.transpose(3, 0, 1, 2)
 cache = (x, w, b, conv_param, x_cols)
 return out, cache

测试使用im2col方法的卷积操作,从输出的图片可以看出和原始卷积方法一样。

out, _ = conv_forward_im2col(x, w, b, {'stride': 1, 'pad': 1})
# Show the original images and the results of the conv operation
plt.subplot(2, 3, 1)
imshow_noax(puppy, normalize=False)
plt.title('Original image')
plt.subplot(2, 3, 2)
imshow_noax(out[0, 0])
plt.title('Grayscale')
plt.subplot(2, 3, 3)
imshow_noax(out[0, 1])
plt.title('Edges')
plt.subplot(2, 3, 4)
imshow_noax(kitten_cropped, normalize=False)
plt.subplot(2, 3, 5)
imshow_noax(out[1, 0])
plt.subplot(2, 3, 6)
imshow_noax(out[1, 1])
plt.show()

下面来测试一下使用两种方法的时间,使用原始的卷积操作每次循环需要2.19s,而使用im2col方法则只需要28.3ms,时间大概缩短了77倍,当然这其中也包括了使用Cython所降低的时间,但总体上来说还是大大加快了卷积的计算速度。

虽然使用im2col方法加快了计算速度,但也会使用更多的内存,因为把输入图像转换为col的时候,会有很多重复的元素。

%timeit conv_forward_naive(x, w, b, {'stride': 1, 'pad': 1})
%timeit conv_forward_im2col(x, w, b, {'stride': 1, 'pad': 1})
1 loop, best of 3: 2.19 s per loop
10 loops, best of 3: 28.3 ms per loop

相关推荐

5分钟调色大片的方法(5分钟调色大片的方法有哪些)

哈喽大家好。在大家印象中一定觉得ps非常难学非常难。大家不要着急,小编的教学都是针对ps零基础的同学的,而且非常实用哦。只要大家跟着图文练习一两遍,保证大家立马学会~!好了,废话少说,下面开始我们今天...

闪白特效原来是这么用的(闪白特效怎么使用)

作者|高艳侠订阅|010-86092062闪白特效是影视作品中应用比较多的效果之一,那么具体该在哪些场景使用闪白特效?具体该如何操作?下面就以AdobePremiere(以下简称PR)为例,...

ppt常用小图标去哪里找?3个矢量素材网站推荐!

ppt是一个注重可视化表达的演示载体,除了高清图片,ppt中另一类常用的素材是各种小图标,也叫矢量图标,巧妙运用小图标能提升整体美观度和表现力,那么ppt常用小图标去哪里找呢?为方便各位快速找到合适的...

有什么好用的截图录屏工具?试试这9款

经常有朋友反馈苦于缺乏截屏和录屏的趁手工具,本期我们分享几个相当好用的截屏和录屏工具,希望能帮到大家。ScreenToGifScreenToGif是一款免费且开源的录屏工具。此款工具最大的特点是可以...

配色苦手福音!专业快速色环配色PS插件

今天橘子老师给的大家介绍的是一款快速配色的插件,非常强大配色苦手福音来啦!(获取方式见文末)【插件介绍】配色在后期设计中占有主导地位,好的配色能让作品更加抢眼Coolorus这款专业的配色插件,能够...

如何用PS抠主体?(ps怎么抠主体)

1.主体法抠图-抠花苞和花梗导入一张荷花苞的照片,点击上图中顶部“选择”菜单栏,下拉单击“主体”。可以看到,只有花苞被选中,但是花梗并没有被选中。接下来单击上图中左侧工具栏的“快速选择工具”,上图中顶...

2799元的4K电视,有保障吗?(买4k电视机哪个品牌好)

在上一期《电脑报》的3·15专题报道中,我们揭露了一款不靠谱的42英寸4K智能电视——TCLD42A561U。这款售价2699元的4K智能电视不仅4K画质方面存在严重问题,而且各种功能和应用体验也不理...

苹果电脑的Touch Bar推出一段时间了 这款工具可以帮你开发适用于它的APP

距离苹果推出带有TouchBar的MacBookPro已经有一段时间了,除了那些像Adobe、Google和Microsoft大公司在开发适用于TouchBar的应用之外,其实还有很多独立的开...

如魔法般吸取颜色的桌灯(如魔法般吸取颜色的桌灯叫什么)

色彩为生活带来的感官刺激,逐渐被视为理所当然。一盏桌灯运用它的神奇力量,将隐藏于物件中的颜色逐一释放,成为装点环境的空间魔法师。ColorUp是一款可以改变颜色的吸色台灯,沿用传统灯泡的造型,融入了拾...

一篇文章带你用jquery mobile设计颜色拾取器

【一、项目背景】现实生活中,我们经常会遇到配色的问题,这个时候去百度一下RGB表。而RGB表只提供相对于的颜色的RGB值而没有可以验证的模块。我们可以通过jquerymobile去设计颜色的拾取器...

ps拾色器快捷键是什么?(ps2019拾色器快捷键)

ps拾色器快捷键是什么?文章末尾有获取方式,按照以下步骤就能自动获得!学会制作PS特效需要一定程度的耐心和毅力。初学者可以从基本的工具和技术开始学习,逐渐提高他们的技能水平。同时,观看更多优秀的特效作...

免费开源的 Windows 截图录屏工具,支持 OCR 识别和滚动截图等

功能很强大、安装很小巧的免费截图、录屏工具,提供很多使用的工具来帮我么能解决问题,推荐给大家。关于ShareXShareX是一款免费的windows工具,起初是一个小巧的截图工具,经过多年的迭...

入门到精通系列PS教程:第13篇 · 拾色器、颜色问题说明及补充

入门到精通系列PS教程:第13篇·拾色器、颜色问题说明及补充作者|侯潇问题说明我的第12篇教程里,有个小问题没有说清楚。要说是错误,又不算是错误,只是没有说准确。写完那篇教程后,因为已经到了深...

PS冷知识:用吸管工具吸取屏幕上的任意颜色

今天,我们给大家介绍PS中的一个冷知识:用吸管工具可以吸取屏幕上的任意颜色。其实,操作起来是非常简单的。大多数情况下,我们认为,PS的吸管工具只能吸取PS软件作图区域范围内的颜色,最多加上画布四周的...

Windows 11 将提供内置颜色选择器工具

Windows11内置了颜色选择器,可以扫描并识别屏幕上的颜色并生成颜色代码。此外,微软还利用人工智能技术,让屏幕上的文本扫描和选择变得更加便捷。这两项功能均已在SnippingToolv1...