提示:前言
Python卷积神经网络CNN
提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档
提示:以下是本篇文章正文内容,下面案例可供参考
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
# Optionally, add value labels
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([])
我们看到卷积分类器有两部分:卷积基和密集层头部。 我们了解到,base 的工作是从图像中提取视觉特征,然后 head 将使用这些特征对图像进行分类。
在接下来的几节课中,我们将学习两种最重要的层类型,您通常会在卷积图像分类器的基础中找到它们。 这些是具有 ReLU 激活的卷积层和最大池化层。
本课是关于具有 ReLU 激活函数的卷积层。
在深入了解卷积的细节之前,让我们先讨论一下网络中这些层的用途。 我们将看到如何使用这三种操作(卷积、ReLU 和最大池化)来实现特征提取过程。
base 执行的特征提取包括三个基本操作:
下图说明了这个过程。 您可以看到这三个操作如何能够隔离原始图像的某些特定特征(在本例中为水平线)。
通常,网络将在单个图像上并行执行多个提取。 在现代卷积神经网络中,基础的最后一层产生超过 1000 个独特的视觉特征并不少见
卷积层执行过滤步骤。 您可以在 Keras 模型中定义一个卷积层,如下所示:
from tensorflow import keras
from tensorflow.keras import layers
model = keras.Sequential([
layers.Conv2D(filters=64, kernel_size=3), # activation is None
# More layers follow
])
我们可以通过查看它们与层的权重和激活的关系来理解这些参数。 让我们现在就这样做。
convnet 在训练期间学习的权重主要包含在其卷积层中。 我们称这些权重为内核。 我们可以将它们表示为小数组:
内核通过扫描图像并产生像素值的加权和来运行。 通过这种方式,内核将有点像偏光镜,强调或弱化某些信息模式。
内核定义卷积层如何连接到后面的层。 上面的内核会将输出中的每个神经元连接到输入中的九个神经元。 通过使用 kernel_size 设置内核的维度,您告诉 convnet 如何形成这些连接。 大多数情况下,内核将具有奇数维度——如 kernel_size=(3, 3) 或 (5, 5)——因此单个像素位于中心,但这不是必需的。
卷积层中的内核决定了它创建的特征类型。 在训练期间,卷积神经网络会尝试学习解决分类问题所需的特征。 这意味着为其内核找到最佳值。
网络中的激活我们称之为特征图。 当我们对图像应用滤镜时,它们就是结果; 它们包含内核提取的视觉特征。 这里有一些内核,上面有它们生成的特征图。
训练集
从内核中的数字模式,您可以看出它创建的特征图的种类。 通常,卷积在其输入中强调的内容将与内核中正数的形状相匹配。 上面的左侧和中间内核都将过滤水平形状。
使用 filters 参数,您可以告诉卷积层您希望它创建多少个特征映射作为输出。
过滤后,特征图通过激活函数。 整流器函数有一个像这样的图:
ReLU 激活函数的图表。
整流器函数的图形看起来像一条线,负部分“整流”为 0。
附有整流器的神经元称为整流线性单元。 出于这个原因,我们也可以将整流器函数称为 ReLU 激活函数甚至 ReLU 函数。
ReLU 激活可以在其自己的激活层中定义,但大多数情况下,您只会将其作为 Conv2D 的激活函数包含在内。
model = keras.Sequential([
layers.Conv2D(filters=64, kernel_size=3, activation='relu')
# More layers follow
])
与其他激活函数一样,ReLU 函数是非线性的。 从本质上讲,这意味着网络中所有层的总效果变得不同于将效果加在一起所获得的效果——这与仅使用一个层所获得的效果相同。 非线性确保特征在深入网络时以有趣的方式组合。 (我们将在第 5 课中更多地探讨这种“特征复合”。)
我们将在这个例子中自己进行提取,以更好地理解卷积网络在“幕后”做什么。
这是我们将用于此示例的图像:
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 = '../input/computer-vision-resources/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();
对于过滤步骤,我们将定义一个内核,然后将其应用于卷积。 这种情况下的内核是“边缘检测”内核。 您可以使用 tf.constant 定义它,就像您在 Numpy 中使用 np.array 定义数组一样。 这将创建 TensorFlow 使用的那种张量。
import tensorflow as tf
kernel = tf.constant([
[-1, -1, -1],
[-1, 8, -1],
[-1, -1, -1],
])
plt.figure(figsize=(3, 3))
show_kernel(kernel)
TensorFlow 在其 tf.nn 模块中包含许多由神经网络执行的常见操作。 我们将使用的两个是 conv2d 和 relu。 这些只是 Keras 层的函数版本。
下一个隐藏的单元格会重新格式化以使其与 TensorFlow 兼容。 细节对于这个例子并不重要。
现在让我们应用我们的内核,看看会发生什么
image_filter = tf.nn.conv2d(
input=image,
filters=kernel,
# we'll talk about these two in lesson 4!
strides=1,
padding='SAME',
)
plt.figure(figsize=(6, 6))
plt.imshow(tf.squeeze(image_filter))
plt.axis('off')
plt.show();
接下来是使用 ReLU 函数的检测步骤。 这个函数比卷积简单得多,因为它没有任何参数要设置。
现在我们已经创建了一个特征图! 这些图像是 head 用来解决其分类问题的图像。 我们可以想象,某些特征可能更具有汽车的特征,而其他特征可能更具有卡车的特征。 训练期间卷积网络的任务是创建可以找到这些特征的内核。