系列文章目录
- 计算机视觉入门 1)卷积分类器
- 计算机视觉入门 2)卷积和ReLU
- 计算机视觉入门 3)最大池化
- 计算机视觉入门 4)滑动窗口
- 计算机视觉入门 5)自定义卷积网络
- 计算机视觉入门 6) 数据集增强(Data Augmentation)
提示:仅为个人学习笔记分享,若有错漏请各位老师同学指出,Thanks♪(・ω・)ノ
目录
一、卷积和ReLU
特征提取
在深入探讨卷积的细节之前,让我们先讨论一下网络中这些层的作用。我们将看到如何使用这三个操作(卷积、ReLU和最大池化)来实现特征提取过程。
基础部分执行的特征提取包括三个基本操作:
- 过滤图像以寻找特定特征(卷积)
- 在过滤后的图像中检测该特征(ReLU)
- 对图像进行压缩以增强特征(最大池化)
下图说明了这个过程。你可以看到这三个操作是如何将原始图像的某些特定特征隔离出来的(在这种情况下是水平线)。
特征提取的三个步骤。
通常情况下,网络会在单个图像上并行执行多次特征提取。在现代的卷积神经网络中,基础部分的最后一层通常会生成超过1000个独特的视觉特征。
使用卷积进行滤波
卷积层执行滤波步骤。你可以像下面这样在Keras模型中定义一个卷积层:
from tensorflow import keras
from tensorflow.keras import layers
model = keras.Sequential([
layers.Conv2D(filters=64, kernel_size=3), # 激活函数为 None
# 后续添加更多层
])
接下来,我们将通过查看层间的权重和激活函数之间的关系来理解这些参数。
权重(Weights)
卷积神经网络在训练过程中学习的主要权重存储在其卷积层中,我们称这些权重为卷积核。我们可以将它们表示为小数组:
卷积核通过在图像上进行扫描,产生像素值的加权和。这种方式,卷积核就像是一种偏振镜头,强调或减弱某些信息模式。
卷积核起到一种镜头的作用。
卷积核定义了卷积层与其后一层之间的连接方式。下面的卷积核将把输出中的每个神经元与输入中的九个神经元相连接。通过使用kernel_size
来设置卷积核的维度,告诉卷积神经网络如何构建这些连接。通常情况下,卷积核的维度会是奇数,比如kernel_size=(3, 3)
或(5, 5)
,以便一个像素位于中心位置,但这并非必须。
卷积层中的卷积核决定了它创建哪些类型的特征。在训练过程中,卷积神经网络试图学习哪些特征对于解决分类问题是必要的。这意味着要找到卷积核的最佳值。
激活函数(Activations)
在神经网络中,我们称为特征图的就是网络中的激活。当我们将一个滤波器应用于图像时,它们就是结果;它们包含了卷积核提取的视觉特征。下面是一些用于可视化的滤波器,以及它们生成的特征图。
滤波器和特征图。
从卷积核中的数字模式中,你可以判断出它创建的特征图的类型。通常情况下,卷积核在输入中强调的特征会与卷积核中正数的形状相匹配。上述左侧和中间的滤波器都将过滤出水平形状的特征。
通过 filters
参数,你可以告诉卷积层要创建多少个特征图作为输出。
使用ReLU进行检测
在滤波之后,特征图会通过激活函数。
整流器函数 (rectifier function) 看起来像一条带有负部分被"整流"为0的直线,图形如下:
带有整流器的神经元称为修正线性单元。因此,我们也可以将整流器函数称为ReLU激活函数,甚至是ReLU函数。
可以在自己的Activation
层中定义ReLU激活,但通常你只需将其作为Conv2D
的激活函数。
model = keras.Sequential([
layers.Conv2D(filters=64, kernel_size=3, activation='relu')
# 后续添加更多层
])
你可以将激活函数视为根据某种重要性度量对像素值进行评分。ReLU激活函数表示负值不重要,因此将它们设置为0(“所有不重要的东西都一样不重要”)。
下面是ReLU应用于上面的特征图。注意它如何成功地隔离了特征。
和其他激活函数一样,ReLU函数是非线性的。基本上,这意味着网络中所有层的总效果会与将效果仅仅相加时不同,这与仅使用单一层所能实现的效果相同。
二、【代码示例】
步骤1:导入包、图片
import numpy as np
from itertools import product
def show_kernel(kernel, label=True, digits=None, text_size=28):
# Format kernel
kernel = np.array(kernel)
if digits is not None:
kernel = kernel.round(digits)
# Plot kernel
cmap = plt.get_cmap('Blues_r')
plt.imshow(kernel, cmap=cmap)
rows, cols = kernel.shape
thresh = (kernel.max()+kernel.min())/2
if label:
for i, j in product(range(rows), range(cols)):
val = kernel[i, j]
color = cmap(0) if val > thresh else cmap(255)
plt.text(j, i, val,
color=color, size=text_size,
horizontalalignment='center', verticalalignment='center')
plt.xticks([])
plt.yticks([])
import tensorflow as tf
import matplotlib.pyplot as plt
plt.rc('figure', autolayout=True)
plt.rc('axes', labelweight='bold', labelsize='large',
titleweight='bold', titlesize=18, titlepad=10)
plt.rc('image', cmap='magma')
image_path = 'car_feature.jpg'
image = tf.io.read_file(image_path)
image = tf.io.decode_jpeg(image)
plt.figure(figsize=(6, 6))
plt.imshow(tf.squeeze(image), cmap='gray')
plt.axis('off')
plt.show();
步骤2:定义核
import tensorflow as tf
kernel = tf.constant([
[-1, -1, -1],
[-1, 8, -1],
[-1, -1, -1],
])
plt.figure(figsize=(3, 3))
show_kernel(kernel)
步骤3:Filter
# Reformat for batch compatibility.
image = tf.image.convert_image_dtype(image, dtype=tf.float32)
image = tf.expand_dims(image, axis=0)
kernel = tf.reshape(kernel, [*kernel.shape, 1, 1])
kernel = tf.cast(kernel, dtype=tf.float32)
image_filter = tf.nn.conv2d(
input=image,
filters=kernel,
strides=1,
padding='SAME',
)
plt.figure(figsize=(6, 6))
plt.imshow(tf.squeeze(image_filter))
plt.axis('off')
plt.show();
步骤4:ReLU
image_detect = tf.nn.relu(image_filter)
plt.figure(figsize=(6, 6))
plt.imshow(tf.squeeze(image_detect))
plt.axis('off')
plt.show();