神经网络是许多现代人工智能 (AI) 应用的核心。人工神经网络 (ANN) 是一个松散地基于大脑结构的模型:它由称为神经元的连接元素组成,每个连接都有一个数值权重。卷积神经网络 (CNN) 是一种特殊类型的人工神经网络,可以解决计算机视觉 (CV) 问题,例如图像分类、对象检测和一般识别。
CNN 的主要构建块是卷积层。这些层由提取图像中相关特征的小过滤器组成,每一层都根据前一层的输入提取更多抽象特征——一直到最终结果。这种方法非常有效,以至于最先进的 CNN 在准确识别大集合中不同人的面部方面可以胜过人类。
在本文中,我们将向您展示如何从头开始创建一个非常简单的 CNN 用于图像分类。我们将使用以下工具:
我们假设您熟悉 Python 并具备神经网络的基本知识来遵循本指南。
您可以使用以下 Anaconda 命令安装软件包的 Intel 发行版:
conda install -c intel intelpython
conda install -c intel tensorflow
我们建议您在工作机器上使用这些工具设置深度学习 (DL) 环境,如 使用 Python 和 Anaconda 构建深度学习环境一文中所述。
我们将使用 Python 和 TensorFlow 创建一个 CNN,该 CNN 获取一个从 0 到 9 的输入数字的小图像,并输出它是什么数字。这是一个很好的开始用例,将为您理解 TensorFlow 框架的关键原理奠定良好的基础。
我们将使用 Intel Optimization for TensorFlow,它优化了在 Intel ®架构上运行时的 TensorFlow 性能。此优化的核心是英特尔® oneAPI 深度神经网络库 (oneDNN),它是一组用于 DL 应用程序的构建块,其中包括卷积层和池化层——任何 CNN 模型的基本组件。该库是英特尔® oneAPI Base Toolkit的一部分,后者是一组库,用于跨不同架构开发高性能 AI、机器学习 (ML) 和其他应用程序。
所有 oneAPI 组件的编程模型是统一的,因此它可以使用相同的代码部署在 CPU、GPU 或 FPGA 上。英特尔继续开发 oneAPI 组件以支持新的处理器并通过利用新的指令集扩展来优化性能。
使用 oneDNN 原语作为核心 TensorFlow 算法的后端实现,可为 DNN 模型提供更高的性能,并确保针对更新的处理器架构优化性能。
让我们从简单的 CNN 开始。该神经网络对带有输入数字的图像进行分类。网络的输入将是一个 28 × 28 像素的小灰度图像,输出将是从 0 到 9 的每个数字的概率数组。第一步是构建 CNN 的 TensorFlow 模型。我们将使用Keras API 来完成这项任务,因为在创建您的第一个神经网络时它更容易理解。
在您的 DL 环境中编写并运行以下代码:
导入操作系统
os.environ[ ' TF_ENABLE_ONEDNN_OPTS' ]= ' 1'
导入张量流
张量流.__版本__
代码的前两行为会话开启oneDNN优化,最后两行检查 TensorFlow 框架的版本。请注意,从TensorFlow 2.9开始,oneDNN 优化默认开启,如果您希望在没有这些优化的情况下测试性能,则必须将其设置为 0。
接下来,使用输入层初始化 CNN 模型:
从tensorflow.keras.models导入顺序
从tensorflow.keras.layers导入输入
模型=顺序()
inp = 输入(形状=(28 , 28 , 1))
模型.add(inp)
我们为我们的 CNN 使用了“顺序”模型。该模型具有最简单的结构,具有顺序层,其中一层的输出是下一层的输入。然后,我们将输入层添加到模型中。所有 TensorFlow 模型都需要知道输入数据的类型。在我们的例子中,这是一个具有 28、28 和 1 三个维度的张量。该输入对应于具有一个颜色通道的 28 × 28 像素的图像(灰度图像)。
让我们继续编写以下代码:
从tensorflow.keras.layers导入Conv2D
conv = Conv2D( 32 , ( 5 , 5 ), padding= "相同" , strides=( 1 , 1 ))
模型.add(conv)
该代码初始化一个卷积层“Conv2D”并将其放在第一个输入层之后。这个卷积层是我们神经网络的关键元素。它负责从输入图像中提取几何特征,然后由下一层使用。我们创建了具有 32 个大小为 (5, 5) 的内核(或过滤器)的层。接下来的两个参数指定如何将这些过滤器应用于输入图像:strides 指定垂直和水平移动,而 padding 指定是否必须用额外的像素填充输入图像以处理输入数据。
任何卷积层后面都应该有一个激活层。该层向模型引入了一个激活函数,该函数根据其权重和输入来控制神经元是否会“触发”(提供输出)。近期深度神经网络 (DNN) 最流行的激活函数是整流线性单元(ReLU)。以下代码将激活层添加到我们的模型中:
从tensorflow.keras.layers导入激活
conv_act = 激活(“ relu”)
model.add(conv_act)
DNN 的另一个重要元素是池化操作。该操作的目标是减少将馈送到下一层的数据的空间维度。我们将使用最大池化操作,因为它已被证明在 CNN 模型中对特征图进行下采样是有效的。
从tensorflow.keras.layers导入MaxPooling2D
池 = MaxPooling2D(( 4 , 4 ))
模型。添加(池)
添加的 MaxPooling2D 层使用 (4, 4) 的池大小进行初始化。这意味着图层数据输出的空间维度在垂直轴和水平轴上都减少了四倍。因此,最初的 28 × 28 像素图像在第一层之后被缩小为 7 × 7 数字输出,依此类推。
池化操作有两个目的。一是使模型独立于提取的特征位置的微小差异,二是减少后续处理层的数据量,从而使模型更快。
现在,我们的模型由四层组成:输入、卷积、激活和池化。在模型构建的任何阶段,我们都可以通过调用 model.summary 方法查看其结构信息。该方法的输出如下图所示:
我们可以看到关于每一层的输出形状的信息。例如,在池化层之后,我们可以看到输出的空间维度从 28 到 7 减少了四倍,正如预期的那样。另一个重要的信息是每一层中可训练参数的数量。我们模型中的卷积层有 832 个这样的参数。可训练参数是层的系数(权重),其值随训练过程调整。它们的数量直接影响训练时间:数量越大,训练过程越长。
让我们继续使用以下代码构建模型:
从tensorflow.keras.layers导入Flatten
从tensorflow.keras.layers导入密集
扁平=扁平化()
模型.add(平面)
密集=密集(128)
model.add(密集)
dense_act = 激活(“ sigmoid”)
model.add(dense_act)
在此之后,我们的模型输出以下摘要:
上面的代码添加了一个“扁平化”层,它将池化层的三维张量(7、7、32)转换为具有 1568 个分量的扁平向量。然后它在模型中添加一个具有 128 个神经元和一个 sigmoid 激活函数的“密集”层。这就是所谓的隐藏全连接层。它位于最后一个分类层之前,其目标是在神经模型的最后部分构建多层感知器 (MLP),因为 MLP 通常是分类神经网络中的最后一个块。
我们模型的最后一层必须是具有 10 个输出值的分类层:每个数字的概率。我们将使用具有 10 个神经元的密集层和 Softmax 激活函数作为现代分类器模型的常见选择。
出=密集(10)
模型.add(out)
out_act = 激活(“ softmax”)
model.add(out_act)
我们模型的最终总结如下图所示:
模型创建的下一阶段是加载训练和验证数据集。我们将使用一个小型数据集1 ,其中训练数据中的每个数字都有 100 个图像,验证数据中的每个数字有 10 个图像。下载数据集并将其提取到您的工作文件夹。我们使用ImageDataGenerator
类,它是一个实用类,提供数据集加载、图像预处理和数据增强等功能。要加载数据集,请在模型创建后立即运行以下代码:
从tensorflow.keras.preprocessing.image导入ImageDataGenerator
datagen = ImageDataGenerator(rescale=1.0/255. 0 )
train_dataset = datagen.flow_from_directory( " " , color_mode= '灰度' , target_size=( 28 , 28 ), class_mode= " categorical" )
val_dataset = datagen.flow_from_directory( " " , color_mode= ' grayscale' , target_size=( 28 , 28 ), class_mode= " categorical" )
这将使用 rescale 参数初始化生成器,以将图像数据归一化为 [0, 1.0] 的区间。加载数据时,我们将类模式指定为分类模式,以便为我们的分类问题生成适当的数据。
最后一步是使用数据集训练我们的模型
从tensorflow.keras.optimizers导入SGD
opt_method = SGD(learning_rate=0. 1 )
模型。编译(优化器=opt_method,损失= “分类交叉熵”,指标=[ “准确性” ])
历史 = model.fit(train_dataset,validation_data=val_dataset,epochs=10)
我们使用 SGD 优化器,它应该是训练新模型时的默认选择。是多类分类问题的categorical_crossentropy
推荐损失函数。对于我们的简单模型和小数据集来说,10 个训练 epoch 的数量就足够了。这是训练过程的输出:
该模型的最终准确率为 96.6% 的训练数据和 94% 的验证数据。请注意,由于过程的不确定性,使用相同数据训练相同模型可能会产生略有不同的结果。
现在我们可以测试模型并针对单个图像运行它:
从tensorflow.keras.preprocessing.image导入load_img
从tensorflow.keras.preprocessing.image导入img_to_array
img_file = " \\7.png"
img = load_img(img_file, color_mode = " grayscale" )
img_array = img_to_array(img)
in_data = img_array.reshape(( 1 , 28 , 28 , 1 ))/255。0
prob = model.predict(in_data)[ 0 ]
数字 = prob.argmax()
digit_prob = 概率[数字]
print (prob)
print ( "预测数字 = " + str (digit))
print ( "数字概率 = " + str (digit_prob))
我们得到以下输出:
[ 7 .85533484e- 05 1 .45643018e- 03 1 .24442745e- 02 1 .29656109e- 03
1 .41729815e- 05 4 .06741965e- 05 4 .37598487e- 07 9 .83559847e- 01
3 .04310001e- 04 8 .04647047e- 04 ]
预测数字 = 7
数字概率 = 0。98355985
该模型正确预测图像包含数字 7 的概率约为 98%。
恭喜!你已经创建了你的第一个神经网络。如果您希望保存训练好的模型,可以使用以下命令:
model.save( " " )