目录
神经网络是许多现代人工智能(AI)应用的核心。人工神经网络(ANN)是一个松散地基于大脑结构的模型:它由称为神经元的连接元素组成,每个连接都有一个数字权重。卷积神经网络(CNN)是特殊类型的人工神经网络,可以解决计算机视觉(CV)问题,例如图像分类、对象检测和一般识别。
CNN的主要构建块是卷积层。这些层由小过滤器组成,这些过滤器提取图像中的相关特征,每一层根据前几层的输入提取更抽象的特征——一直到最终结果。这种方法非常有效,以至于最先进的CNN在从一大集中准确识别不同人的面孔方面可以胜过人类。
在本文中,我们将向您展示如何从头开始创建非常简单的图像分类CNN。我们将使用以下工具:
- Anaconda*导航器来管理我们的项目
- Intel®发行版Python *开发基本代码
- Intel®针对 TensorFlow*的优化,用于构建和训练我们的神经网络
我们假设你熟悉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性能。此优化的核心是Intel® oneAPI深度神经网络库 (oneDNN),它是一组用于DL应用的构建模块,包括卷积层和池化层—任何CNN模型的基本组件。该库是Intel® oneAPI基础工具包的一部分,该工具包是一组用于开发跨不同架构的高性能人工智能、机器学习(ML)和其他应用的库。
所有oneAPI 组件的编程模型是统一的,因此它可以使用相同的代码在CPU、GPU或FPGA上进行部署。Intel继续开发oneAPI组件,以支持新的处理器,并通过利用新的指令集扩展来优化性能。
使用oneDNN原语作为核心TensorFlow算法的后端实现可为DNN模型提供更高的性能,并确保性能针对较新的处理器架构进行优化。
让我们开始编码
让我们从简单的CNN开始。该神经网络使用键入的数字对图像进行分类。网络的输入将是28 × 28像素的小灰度图像,输出将是0到9的每个数字的概率数组。第一步是构建CNN的TensorFlow模型。我们将使用 Keras API来完成此任务,因为在创建第一个神经网络时更容易理解。
在DL环境中编写并运行以下代码:
import os
os.environ['TF_ENABLE_ONEDNN_OPTS'] = '1'
import tensorflow
tensorflow.__version__
代码的前两行打开会话的oneDNN 优化,最后两行检查TensorFlow框架的版本。请注意,从 TensorFlow 2.9 开始,oneDNN优化默认处于打开状态,如您希望在没有这些优化的情况下测试性能,则必须将其设置为 0。
接下来,使用输入层初始化CNN模型:
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Input
model = Sequential()
inp = Input(shape=(28, 28, 1))
model.add(inp)
我们为CNN使用了“顺序”模型。该模型具有最简单的结构,具有顺序层,其中一层的输出是下一层的输入。然后,我们将输入层添加到模型中。所有TensorFlow模型都需要知道输入数据类型。在我们的例子中,这是一个三维为28、28和1的张量。此输入对应于具有一个颜色通道的28 × 28像素的图像(灰度图像)。
卷积层
让我们继续编写以下代码:
from tensorflow.keras.layers import Conv2D
conv = Conv2D(32, (5, 5), padding="same", strides=(1, 1))
model.add(conv)
该代码初始化卷积层“Conv2D”并将其放置在第一个输入层之后。这个卷积层是我们神经网络的关键元素。它负责从输入图像中提取几何特征,然后由下一层使用。我们创建了具有32个大小为(5,5)的内核(或过滤器)的层。接下来的两个参数指定如何将这些滤镜应用于输入图像:步幅指定垂直和水平偏移,填充指定是否必须使用额外的像素填充输入图像以处理输入数据。
激活层
任何卷积层后面都应该有一个激活层。该层为模型引入了激活函数,该函数根据神经元的权重和输入控制神经元是否会“触发”(提供输出)。最近深度神经网络(DNN)最流行的激活函数是整流线性单元(ReLU)。以下代码将激活层添加到我们的模型中:
from tensorflow.keras.layers import Activation
conv_act = Activation("relu")
model.add(conv_act)
池化层
DNN的另一个重要元素是池化操作。该操作的目标是减少将馈送到下一层的数据的空间维度。我们将使用最大池化操作,因为它已被证明在CNN模型中对特征图进行下采样是有效的。
from tensorflow.keras.layers import MaxPooling2D
pool = MaxPooling2D((4, 4))
model.add(pool)
添加的MaxPooling2D图层初始化为池大小(4, 4)。这意味着对于垂直轴和水平轴,图层数据输出的空间维度都会减少四倍。因此,在第一层之后,最初的28 × 28像素图像将减少为7 × 7的数字输出,依此类推。
池化操作有两个目的。一种是使模型独立于提取的特征位置的细微差异,另一种是减少下一个处理层的数据量,从而使模型更快。
到目前为止可视化我们的模型
现在,我们的模型由四层组成:输入层、卷积层、激活层和池化层。在模型构建的任何阶段,我们都可以通过调用model.summary方法来查看有关其结构的信息。该方法的输出如下图所示:
我们可以看到有关每个图层的输出形状的信息。例如,在池化层之后,我们可以看到输出的空间维度从28减少到7四倍,正如预期的那样。另一个重要的信息是每层中可训练参数的数量。我们模型中的卷积层有832个这样的参数。可训练参数是图层的系数(权重),其值随训练过程进行调整。它们的数量直接影响训练时间:数量越大,训练过程越长。
扁平和密集的层
让我们继续使用以下代码构建模型:
from tensorflow.keras.layers import Flatten
from tensorflow.keras.layers import Dense
flat = Flatten()
model.add(flat)
dense = Dense(128)
model.add(dense)
dense_act = Activation("sigmoid")
model.add(dense_act)
在此之后,我们的模型输出以下摘要:
上面的代码添加了一个“扁平化”层,该层将三维张量(7,7,32) 从池化层转换为具有1568个分量的平面向量。然后,它将一个具有128个神经元的“密集”层和一个sigmoid激活函数添加到模型中。这就是所谓的隐藏全连接层。它位于最后一个分类层之前,其目标是在神经模型的最后一部分构建多层感知器(MLP),因为MLP通常是分类神经网络中的最后一个块。
分类层
模型的最后一层必须是具有10个输出值的分类层:每个数字的概率。我们将使用具有10个神经元的密集层和Softmax激活函数作为现代分类器模型的常见选择。
out = Dense(10)
model.add(out)
out_act = Activation("softmax")
model.add(out_act)
我们模型的最终摘要如下图所示:
训练模型
模型创建的下一阶段是加载训练和验证数据集。我们将使用一个小数据集1,训练数据中的每个数字有100个图像,验证数据中每个数字有10个图像。下载数据集并将其提取到工作文件夹。我们使用ImageDataGenerator类,它是一个实用程序类,提供数据集加载、图像预处理和数据增强等功能。若要加载数据集,请在创建模型后立即运行以下代码:
from tensorflow.keras.preprocessing.image import ImageDataGenerator
datagen = ImageDataGenerator(rescale=1.0/255.0)
train_dataset = datagen.flow_from_directory("<your-train-data-file-path-here>", color_mode='grayscale', target_size=(28, 28), class_mode="categorical")
val_dataset = datagen.flow_from_directory("<your-validation-data-file-path-here>", color_mode='grayscale', target_size=(28, 28), class_mode="categorical")
这会使用rescale参数初始化生成器,以将图像数据规范化为[0,1.0]的间隔。加载数据时,我们将类模式指定为分类模式,以便为分类问题生成适当的数据。
最后一步是使用数据集训练我们的模型
from tensorflow.keras.optimizers import SGD
opt_method = SGD(learning_rate=0.1)
model.compile(optimizer=opt_method, loss="categorical_crossentropy", metrics=["accuracy"])
history = model.fit(train_dataset, validation_data=val_dataset, epochs=10)
我们使用SGD优化器,这应该是训练新模型时的默认选择。categorical_crossentropy是多类分类问题的推荐损失函数。对于我们的简单模型和小数据集来说,10个训练epoch的小计数就足够了。以下是训练过程的输出:
模型的最终准确率为训练数据的96.6%,验证数据的最终准确率为94%。请注意,由于过程的非确定性,使用相同的数据训练相同的模型可能会产生略有不同的结果。
测试出来
现在我们可以测试模型并为单个图像运行它:
from tensorflow.keras.preprocessing.image import load_img
from tensorflow.keras.preprocessing.image import img_to_array
img_file = "<your-test-data-file-path-here>\\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]
digit = prob.argmax()
digit_prob = prob[digit]
print(prob)
print("Predicted digit = " + str(digit))
print("Digit probability = " + 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]
Predicted digit = 7
Digit probability = 0.98355985
该模型正确预测图像包含数字7,概率约为98%。
祝贺!您已经创建了第一个神经网络。如果要保存已训练的模型,可以使用以下命令:
model.save("<your-model-file-path-here>")
结论
在本文中,我们学习了如何使用TensorFlow框架创建一个非常简单的神经网络。作为一个实际的例子,我们构建了一个CNN,用于用键入的数字对图像进行分类。我们提供了构建包含两个块的顺序模型的步骤。第一个块包含一个卷积层,充当特征提取器。第二个块是一个带有一个隐藏的全连接层的感知器,是一种常见的分类器,通常用于现代DNN。
在训练模型和运行推理时,我们使用Intel TensorFlow 优化加快了周转时间。此版本的框架由oneDNN库提供支持,该库是用于AI应用程序的oneAPI工具包的一部分。
虽然我们创建了一个非常简单的神经网络,但这演示了使用TensorFlow框架构建和训练DNN是多么容易。现代最先进的模型包含数百甚至数千层,TensorFlow框架允许您轻松创建它们,而Intel TensorFlow优化可加快训练和推理运行。
本文最初发表于 Create Your First Neural Network with Python and TensorFlow
https://www.codeproject.com/Articles/5344692/Create-Your-First-Neural-Network-with-Python-and-T