卷积常用于特征提取
实验过程注意认真体会 “特征提取” ,弄清楚为什么卷积能够提取特征
简单了解一下,大家常见的是二维卷积
平常生活中利用卷积可以识别检测,比如识别是猴子,马等,还有分类,利用一些特征判断是哪一类,最能接触到的就是人脸识别,通过提取每个人脸的特征,判断是否是这个人。
接下来在此章探索,学习卷积为什么能够提取特征
一、概念
用自己的语言描述 ”卷积、卷积核、特征图、特征选择、步长、填充、感受野“
卷积:卷积就是在输入数据上滑动一个窗口,跟上面的图一样,从而提取输入数据的特有的特征,如同你拿一块抹布在满是灰尘的地面上擦来擦去。
卷积核:是一个抹布,是一个矩阵,包含特定的权重和值(抹布上的清洁剂),通过在数据上滑动卷积核,提取特征。上面的红色和绿色的方框。
特征图:通过卷积后得到的特定特征,就是擦完地板后污渍和痕迹。
特征选择:挑选清洁剂的过程,最能解决问题的特征。
步长:提取时跳跃的步伐,可以一步一步擦拭,也可以大步大步,影响擦拭速度(提取的效率)和清洁程度(特征提取的精细程度)。
填充:擦拭地板之前,先在地面上喷洒一些水。这可以使得清洁剂更好地渗透到地板的缝隙中,清洁得更彻底。在卷积中,填充是在输入数据的边界上添加一些额外的像素点,以使得卷积操作能够更好地处理输入数据。
填充公式,输入尺寸N,卷积核尺寸F,填充P,步长S,
(N +2*P-F)/S+1。
例如
卷积两侧添加0的个数的公式为:
已知输入尺寸为4,卷积核尺寸为3,步长为1,填充大小为1
根据公式,输出尺寸为:
(4 - 3 + 2×1) / 1 + 1 = 4
所以,需要添加的0的个数为:
3 - 1 = 2
因此,卷积两侧需要添加2个0
感受野:通过卷积核的大小和步长决定的,如同人的视野,站的高望的远,影响提取到的特征的广度。
二、探究不同卷积核的作用
1.图1分别使用卷积核,输出特征图。
import torch
import torch.nn.functional as F
import matplotlib.pyplot as plt
featuremap = torch.tensor([[0, 0, 0, 255, 255, 255],
[0, 0, 0, 255, 255, 255],
[0, 0, 0, 255, 255, 255]])
# 确定卷积网络
class Cnet(torch.nn.Module):
def __init__(self, filter, kshape):
super(Cnet, self).__init__()
filter = torch.reshape(filter, kshape)
self.weight = torch.nn.Parameter(data=filter, requires_grad=False)
def forward(self, featuremap):
featuremap = F.conv2d(featuremap, self.weight, stride=1, padding=0)
return featuremap
# 确定卷积层
filter = torch.tensor([-1, 1])
# 更改卷积层的形状适应卷积函数
kshape = (1, 1, 1, 2)
# 生成模型
model = Cnet(filter=filter, kshape=kshape)
# 更改图片的形状适应卷积层
featuremap = torch.reshape(featuremap, (1, 1, 3, 6))
output = model(featuremap)
output = torch.reshape(output, (3, 5))
plt.imshow(output, cmap='gray')
plt.show()
另外
只需要改变卷积层形状适应卷积函数
2.图2使用 卷积核输出特征图
import torch
import torch.nn.functional as F
import matplotlib.pyplot as plt
featuremap = torch.tensor([[0, 0, 0, 255, 255, 255],
[0, 0, 0, 255, 255, 255],
[0, 0, 0, 255, 255, 255],
[255, 255, 255, 0, 0, 0],
[255, 255, 255, 0, 0, 0],
[255, 255, 255, 0, 0, 0]])
# 确定卷积网络
class Cnet(torch.nn.Module):
def __init__(self, filter, kshape):
super(Cnet, self).__init__()
filter = torch.reshape(filter, kshape)
self.weight = torch.nn.Parameter(data=filter, requires_grad=False)
def forward(self, featuremap):
featuremap = F.conv2d(featuremap, self.weight, stride=1, padding=0)
return featuremap
# 确定卷积层
filter = torch.tensor([-1, 1])
# 更改卷积层的形状适应卷积函数
kshape = (1, 1, 1, 2)
# 生成模型
model = Cnet(filter=filter, kshape=kshape)
# 更改图片的形状适应卷积层
featuremap = torch.reshape(featuremap, (1, 1, 6, 6))
output = model(featuremap)
output = torch.reshape(output, (6, 5))
plt.imshow(output, cmap='gray')
plt.show()
3.使用卷积核 图3,输出特征图
import torch
import torch.nn.functional as F
import matplotlib.pyplot as plt
featuremap = torch.tensor([[255, 255, 255, 255, 255, 255, 255, 255, 255],
[255, 0, 255, 255, 255, 255, 255, 0, 255],
[255, 255, 0, 255, 255, 255, 0, 255, 255],
[255, 255, 255, 0, 255, 0, 255, 255, 255],
[255, 255, 255, 255, 0, 255, 255, 255, 255],
[255, 255, 255, 0, 255, 0, 255, 255, 255],
[255, 255, 0, 255, 255, 255, 0, 255, 255],
[255, 0, 255, 255, 255, 255, 255, 0, 255],
[255, 255, 255, 255, 255, 255, 255, 255, 255], ])
# 确定卷积网络
class Cnet(torch.nn.Module):
def __init__(self, filter, kshape):
super(Cnet, self).__init__()
filter = torch.reshape(filter, kshape)
self.weight = torch.nn.Parameter(data=filter, requires_grad=False)
def forward(self, featuremap):
featuremap = F.conv2d(featuremap, self.weight, stride=1, padding=0)
return featuremap
# 确定卷积层
filter = torch.tensor([-1, 1])
# 更改卷积层的形状适应卷积函数
kshape = (1, 1, 1, 2)
# 生成模型
model = Cnet(filter=filter, kshape=kshape)
# 更改图片的形状适应卷积层
featuremap = torch.reshape(featuremap, (1, 1, 9, 9))
output = model(featuremap)
output = torch.reshape(output, (9, 8))
plt.imshow(output, cmap='gray')
plt.show()
4.实现灰度图的边缘检测,锐化,模糊。
参考链接:https://setosa.io/ev/image-kernels/
import numpy as np
import torch
from torch import nn
from torch.autograd import Variable
from PIL import Image
import matplotlib.pyplot as plt
im = Image.open('C:\\Users\\dell\\Desktop\\duolahuidu.jpg').convert('L') # 读入一张灰度图的图片
im = np.array(im, dtype='float32') # 将其转换为一个矩阵
print(im.shape[0], im.shape[1])
plt.imshow(im.astype('uint8'), cmap='gray') # 可视化图片
plt.title('原图')
plt.show()
im = torch.from_numpy(im.reshape((1, 1, im.shape[0], im.shape[1])))
conv1 = nn.Conv2d(1, 1, 3, bias=False) # 定义卷积
sobel_kernel = np.array([[-1, -1, -1],
[-1, 8, -1],
[-1, -1, -1]], dtype='float32') # 定义轮廓检测算子
sobel_kernel = sobel_kernel.reshape((1, 1, 3, 3)) # 适配卷积的输入输出
conv1.weight.data = torch.from_numpy(sobel_kernel) # 给卷积的 kernel 赋值
edge1 = conv1(Variable(im)) # 作用在图片上
x = edge1.data.squeeze().numpy()
print(x.shape) # 输出大小
plt.imshow(x, cmap='gray')
plt.show()
原图:
边缘检测
锐化 出现了灰色,学习了一下老师发的
归一化问题,映射,大于255,小于0
模糊
这个图效果不明显,如果大家做实验的原图找边缘较为清晰的
5.总结不同卷积核的特征和作用
边缘检测:边缘是图像的边缘(轮廓),目的是识别并突出这些轮廓,都使用特定的卷积核(也称为滤波器)来检测边缘。卷积核的主要特征是它们在水平和垂直方向上的权重不同,检测出水平和垂直的特征。
锐化:增强图像的细节和清晰度。通常使用一个包含正负值的卷积核来实现。这个卷积核的权重通常会在中心位置为正,而在其他位置为负。
模糊:减少图像的细节和噪声,通常使用一个包含正值的卷积核来实现。这个卷积核的权重通常会在中心位置为最大,并在逐渐远离中心的过程中逐渐减小。
实验总结:
在这个过程中,我的电脑原本有一张图,是彩色的,这个图需要转为灰度图,先前在matlab中学到过,在老师给的代码中的
convert('L'),
是用来转为灰度图,pillow库中的函数
探究不同卷积核的作用时,实验过程中不清楚需要转为矩阵,这个矩阵到底怎么写,参考学长的代码才明白作业5:卷积
卷积提取特征原理
通过卷积核在图像上滑动并执行卷积操作,从而提取出图像中的特征。卷积核是一个小的矩阵,它可以提取图像中的局部特征,例如边缘,在卷积过程中,卷积核会在图像上滑动,并对覆盖的局部区域进行卷积运算,从而得到一组特征映射图。这些特征映射图可以表达出图像中的特征
参考文献:
其他的我已经标注