65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 Python 和 TensorFlow 创建您的第一个神经网络

emptyStarIconemptyStarIconemptyStarIconemptyStarIconemptyStarIcon

0/5 (0投票)

2022 年 10 月 18 日

CPOL

9分钟阅读

viewsIcon

7686

在本文中,我们将向您展示如何从头开始创建一个非常简单的 CNN 来进行图像分类。

神经网络是许多现代人工智能 (AI) 应用的核心。人工神经网络 (ANN) 是一个松散基于大脑结构的模型:它由称为神经元的连接元素组成,每个连接都有一个数值权重。卷积神经网络 (CNN) 是 ANN 的特殊类型,可以解决计算机视觉 (CV) 问题,例如图像分类、对象检测和通用识别。

CNN 的主要构建块是卷积层。这些层由小的滤波器组成,用于从图像中提取相关特征,每一层都基于前一层输入的更抽象的特征——一直到最终结果。这种方法非常有效,以至于最先进的 CNN 在从大量人脸中准确识别不同人脸方面可以超越人类。

在本文中,我们将向您展示如何从头开始创建一个非常简单的 CNN 来进行图像分类。我们将使用以下工具:

  • Anaconda* Navigator 来管理我们的项目
  • Intel® Distribution for Python* 来开发基础代码
  • Intel® Optimization for 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 Deep Neural Network Library (oneDNN),这是一组用于 DL 应用程序的构建块,包括卷积层和池化层——任何 CNN 模型的基本组成部分。该库是 Intel® oneAPI Base Toolkit 的一部分,该工具包是一组用于在各种架构上开发高性能 AI、机器学习 (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 使用了 “Sequential”模型。此模型具有最简单的结构,包含顺序层,其中一层输出是下一层的输入。然后,我们将输入层添加到模型中。所有 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) 的核(或滤波器)。接下来的两个参数指定了这些滤波器如何应用于输入图像:步幅(strides)指定了垂直和水平的移动,填充(padding)指定了是否必须用额外的像素填充输入图像来处理输入数据。

激活层

任何卷积层之后都应该跟着一个激活层。该层将激活函数引入模型,该函数根据神经元的权重和输入控制该神经元是否会“激发”(提供输出)。最近的深度神经网络 (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 个此类参数。可训练参数是层(权重)的系数,其值通过训练过程进行调整。它们的数量直接影响训练时间:数量越多,训练过程越长。

Flatten 和 Dense 层

让我们继续使用以下代码来构建模型。

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)

之后,我们的模型输出以下摘要:

上面的代码添加了一个“flatten”层,将来自池化层的三维张量 (7, 7, 32) 转换为具有 1568 个分量的扁平向量。然后,它向模型添加了一个具有 128 个神经元和 sigmoid 激活函数的“dense”层。这是所谓的隐藏全连接层。它位于最后一个分类层之前,其目标是在神经网络模型的最后部分构建一个多层感知器 (MLP),因为 MLP 通常是分类神经网络的最终块。

分类层

我们模型的最后一层必须是一个分类层,有 10 个输出值:每个数字的概率。我们将使用一个具有 10 个神经元和 Softmax 激活函数的 dense 层,这是现代分类器模型的常见选择。

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] 区间。在加载数据时,我们将 `class_mode` 指定为 `categorical`,以生成适合我们分类问题的适当数据。

最后一步是使用数据集训练我们的模型。

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 Optimization for TensorFlow 加快了周转时间。此框架版本由 oneDNN 库提供支持,该库是用于 AI 应用程序的 oneAPI 工具包的一部分。

尽管我们创建了一个非常简单的神经网络,但这表明使用 TensorFlow 框架构建和训练 DNN 是多么容易。现代最先进的模型包含数百甚至数千层,而 TensorFlow 框架允许您轻松创建它们,而 Intel Optimization for TensorFlow 则加快了训练和推理的运行速度。

 

© . All rights reserved.