使用 TensorFlow 构建人工神经网络 (ANN) 教程

⚡ 智能摘要

人工神经网络通过将输入数据逐层传递,使用损失函数对结果进行评分,并通过优化器调整权重来进行学习。本教程将使用 TensorFlow 构建一个人工神经网络,并对 MNIST 数字进行分类。

  • 🔘 四个物体: 每个人工神经网络都由层、特征和标签、损失函数和优化器组成。
  • ☑️ 图层角色: 输入层被送入隐藏层,输出层的大小与分类任务中的类别数量相匹配。
  • ✅ 激活方式选择: ReLU 对负值返回零,使网络能够学习线性模型无法捕捉到的非线性模式。
  • 🧪 过拟合控制: 较小的网络、L1 或 L2 权重惩罚以及 0.2 到 0.5 之间的 dropout 率可以恢复泛化能力。
  • 🛠️ 六个搭建步骤: 导入 MNIST 数据集,对其进行缩放,创建特征列,定义 DNNClassifier,进行训练,然后添加正则化。
  • 📈 测量结果: 隐藏层分别为 300 和 100 个单元时,精度达到 0.9637143;正则化变体的精度下降到 0.95057142。

人工神经网络 (ANN)

什么是人工神经网络?

An 人工神经网络 (ANN) 人工神经网络是一种受生物神经网络启发而开发的计算机系统,它基于称为人工神经元的连接单元集合来构建人工大脑。它的设计目标是像人类一样分析和处理信息。人工神经网络具有自学习能力,随着数据的增加,能够产生更好的结果。

下图 trac即对这样的网络进行一次完整的遍历,从原始输入到修正权重的优化器。

人工神经网络流程图,包括输入层、两个加权层、预测层、损失函数和优化器。

人工神经网络 (ANN) 由四个主要对象组成:

  • 层数: 所有的学习过程都在各个层中进行。共有三层:1)输入层;2)隐藏层;3)输出层。
  • 特色和标签: 网络的输入数据(特征)和网络的输出(标签)
  • 损失函数: 用于评估学习阶段绩效的指标
  • 优化器: 通过更新网络中的知识来改进学习

神经网络接收输入数据,并将其传递到多个层中。然后,网络使用损失函数评估其性能。损失函数为网络提供掌握知识所需路径的指导。网络借助优化器来改进其知识。

如果你看一下上面的图,你就会明白底层机制。

该程序接收一些输入值,并将它们输入到两个全连接层中。想象一下你遇到一道数学题。你首先会阅读相应的章节来解答它。然后,你将新学到的知识应用到题目中。你很可能得不到理想的分数。神经网络也是如此:它第一次看到数据并进行预测时,结果不会与实际数据完全吻合。

为了提升知识水平,神经网络使用优化器。在这个比喻中,优化器可以理解为重读章节。通过再次阅读,你会获得新的见解。同样地,神经网络使用优化器更新知识,并测试这些新知识,以检查它还需要学习多少。程序会重复这一步骤,直到误差降至最低。

用数学题来类比,就好比你反复阅读课本章节,直到彻底理解课程内容。即使读了很多遍,如果仍然出错,就说明你已经掌握了当前知识的极限。你需要换一本教材或者尝试不同的方法来提高分数。神经网络也是如此。如果误差不再下降,损失曲线趋于平缓,说明当前的网络架构已经无法学习任何新内容。必须对网络进行更好的优化,才能提升其学习能力。

这四个对象直接对应于您在设计网络时配置的组件。

神经网络 Archi质地

人工神经网络架构由以下组件构成:

  • 层
  • 激活功能
  • 损失函数
  • 优化

层

每一层都是学习发生的地方。每一层都包含任意数量的神经元,每个神经元都有自己的权重。典型的神经网络通常由密集连接层(也称为全连接层)构成。这意味着所有输入都与输出相连。

典型的神经网络接收一个输入向量和一个包含标签的标量。最简单的设置是二元分类,只有两个类别:0 和 1。

该网络接收输入,将其发送到所有连接的节点,并使用激活函数计算信号。下图放大了单个节点,以便您可以分别查看加权和以及激活步骤。

双层网络图,权重为 w11 至 w22,并标注了一个节点内的加权和及激活函数。

上图展示了这一概念。第一层存储输入值。第二层,称为隐藏层,接收来自前一层的加权输入。

  1. 第一个节点是输入值。
  2. 神经元被分解为输入部分和激活函数。左侧部分接收来自上一层的所有输入。右侧部分是输入经过激活函数处理后的总和。
  3. 输出值由隐藏层计算得出,用于进行预测。对于分类问题,输出值等于类别数。对于回归问题,仅预测一个值。

激活功能

节点的激活函数定义了给定一组输入时的输出。你需要一个激活函数,使网络能够学习非线性模式。ReLU(修正线性单元)是一种常用的激活函数。该函数对所有负值都返回零。

其他激活函数包括:

  • 分段线性
  • 乙状结肠
  • 谭
  • 泄漏ReLU

下图显示了为什么 ReLU 是这样描述的:对于每个负输入,曲线在零点处是平坦的,之后呈线性上升。

ReLU激活函数R(z) = max(0, z)的曲线图,对于负输入,曲线在零点处为平坦,对于正输入,曲线呈线性。

构建神经网络时要做出的关键决定是:

  • 神经网络有多少层
  • 每层有多少个隐藏单元

具有很多层和隐藏单元的神经网络可以学习数据的复杂表示,但这会使网络的计算成本非常高。

损失函数

定义隐藏层和激活函数后,需要指定损失函数和优化器。

对于二元分类问题,通常的做法是使用二元交叉熵损失函数。 线性回归您可以使用均方误差。

损失函数是评估优化器性能的重要指标。在训练过程中,该指标将被最小化。您需要根据所处理的问题类型仔细选择此数量。

优化

损失函数是衡量模型性能的指标。优化器通过调整网络权重来降低损失。虽然有多种优化器可供选择,但最常用的是随机梯度下降法。

常规的优化器有:

  • Momentum 优化
  • 内斯特罗夫加速梯度
  • 阿达格勒
  • Adam 优化

Archi单凭结构并不能保证模型可用。

神经网络的局限性

以下是神经网络的局限性:

过度拟合

复杂神经网络的一个常见问题是难以泛化到未见过的数据。权重较多的神经网络可以很好地识别训练集中的特定细节,但这往往会导致过拟合。如果数据在组内不平衡(即某些组的数据量不足),网络在训练过程中虽然学习效果很好,但却无法将这些模式泛化到从未见过的数据中。

这其中存在权衡取舍 机器学习 介于优化和泛化之间。

  • 优化模型需要找到能够最大限度减少训练集损失的最佳参数。
  • 然而,泛化表明模型对于看不见的数据如何表现。

为了防止模型捕捉到训练数据中的特定细节或不必要的模式,可以使用不同的技术。最佳方法是使用数据量充足且均衡的数据集。减少过拟合的技术称为正则化。以下三种技术是传统的入门方法。

技术 它限制了什么 本教程中的典型设置
网络规模 层数和隐藏单元数 两层隐藏层,分别为 300 和 100 个单位
L1/L2权重正则化 权重系数的大小 l1_regularization_strength 和 l2_regularization_strength 均为 0.01
退出 每个训练步骤中关闭的单元比例 掉线率为0.3

网络规模

层数过多、隐藏单元过多的神经网络通常非常复杂。降低模型复杂度的一个直接方法是减小模型规模。至于层数,并没有统一的最佳实践。你需要从少量层数开始,逐步增加层数,直到发现模型过拟合为止。

权重正则化

防止过拟合的常用方法是对网络权重添加约束。这种约束迫使网络权重只能取较小的值。该约束被添加到误差损失函数中。正则化有两种类型:

  • L1(套索): 成本与权重系数的绝对值成正比。
  • L2(山脊): 成本与权重系数的平方成正比。

退出

Dropout 是一种奇特但实用的技术。使用 Dropout 的网络意味着在训练过程中,一些单元会被随机关闭,使其输出信号变为零。假设你有一个权重数组 [0.1, 1.7, 0.7, -0.9]。如果神经网络使用了 Dropout,它将变为 [0.1, 0, 0, -0.9],其中 0 随机分布。控制 Dropout 的参数是 Dropout 率。该率决定了有多少单元会被关闭。通常 Dropout 率介于 0.2 和 0.5 之间。

一个简单的交互式示例使训练循环更容易观察。

TensorFlow 中的神经网络示例

以下是一个人工神经网络的实际应用示例,展示了神经网络如何处理典型的分类问题。有两个输入 x1 和 x2,每个输入都有一个随机值。输出是一个二元类别。目标是根据这两个特征对标签进行分类。为了完成这项任务,神经网络架构定义如下:

  • 两个隐藏层
  • 第一层有四个完全连接的神经元
  • 第二层有两个完全连接的神经元
  • 激活函数为 ReLU。
  • 添加学习率为 2 的 L0.003 正则化

该网络将以 10 的批次大小,经过 180 个 epoch 的迭代来优化权重。在下面的 ANN 示例动画中,您可以看到权重如何随时间演变,以及网络如何改进分类图。ping.

浏览器神经网络权重随训练轮次变化的动画演示

首先,网络为所有权重分配随机值。

  • 使用随机权重(即不进行优化)时,输出损失为 0.453。下图用不同颜色表示该网络。
  • 一般来说,橙色代表负值,而蓝色代表正值。
  • 数据点具有相同的表示方法:蓝色代表正标签,橙色代表负标签。

浏览器测试环境在第一次迭代中使用了随机权重,权重为 -0.43,测试损失为 0.453。

在第二层隐藏层中,线条的颜色根据权重的正负而变化。橙色线条代表负权重,蓝色线条代表正权重。

如您所见,在输出图中ping该网络出现了相当多的错误。现在来看看优化后网络的表现。

下图展示了人工神经网络 (ANN) 示例优化后的结果。首先,您可以看到网络已成功学习了如何对数据点进行分类。与之前的图片相比,初始权重为 -0.43,而优化后权重为 -0.95。

四个游乐场展示板显示了最终的重量,蓝线表示正重量,数据点分类正确。

这个想法可以推广到具有更多隐藏层和神经元的网络。您可以自行尝试不同的设置。 TensorFlow 游乐场.

下面的步骤演示如何用代码针对真实数据集实现相同的概念。

如何使用 TensorFlow 训练神经网络

以下是训练神经网络的详细步骤。 TensorFlow 使用 API 的估计器 DNNClassifier 的 ANN。

我们将使用 MNIST 数据集来训练你的第一个神经网络。使用 TensorFlow 其实并不复杂。预处理步骤与之前的教程完全相同。具体操作如下:

  1. 导入数据
  2. 转换数据
  3. 构建张量
  4. 建立模型
  5. 训练和评估模型
  6. 改进模型

版本说明: 本教程中的代码针对的是 TensorFlow 1.x Estimator API。tf-estimator 包的最终版本随 TensorFlow 2.15 发布,而 tf.estimator 已在 TensorFlow 2.16 中移除。要在当前版本上运行这些步骤,要么将 TensorFlow 版本锁定为 2.15,要么使用 tf.keras.layers.Dense 和 model.fit() 重建相同的两层网络。

步骤1)导入数据

首先,您需要导入必要的库。您可以使用以下方法导入 MNIST 数据集。 scikit学习 如下面的 TensorFlow 神经网络示例所示。

MNIST 数据集是测试新技术或算法最常用的数据集。它包含一系列 28×28 像素的图像,每张图像上都手写着 0 到 9 的数字。一组经过弹性失真训练的深度卷积网络将测试误差降低至 0.27%。

import numpy as np
import tensorflow as tf
np.random.seed(1337)

最初的演练是手动下载 MNIST 文件,并将 fetch_mldata 指向该文件夹。

from sklearn.datasets import fetch_mldata
mnist = fetch_mldata(' /Users/Thomas/Dropbox/Learning/Upwork/tuto_TF/data/mldata/MNIST original')
print(mnist.data.shape)
print(mnist.target.shape)

API说明: mldata.org 已不再在线,并且 fetch_mldata 已在 scikit-learn 0.22 中移除。在当前安装中,请将上述调用替换为 fetch_openml('mnist_784', version=1),这将下载相同的 70,000 个数字,并公开相同的数据和目标属性。

之后,你分割数据并得到两个数据集的形状。

from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(mnist.data, mnist.target, test_size=0.2, random_state=42)
y_train  = y_train.astype(int)
y_test  = y_test.astype(int)
batch_size =len(X_train)

print(X_train.shape, y_train.shape,y_test.shape )

步骤2)转换数据

在上一篇教程中,您学习了如何转换数据以限制异常值的影响。在本神经网络教程中,您将使用最小-最大缩放器来转换数据。公式如下:

(X-min_x)/(max_x - min_x)

scikit-learn 已经提供了一个实现此功能的函数:MinMaxScaler()

## resclae
from sklearn.preprocessing import MinMaxScaler
scaler = MinMaxScaler()
# Train
X_train_scaled = scaler.fit_transform(X_train.astype(np.float64))
# test
X_test_scaled = scaler.fit_transform(X_test.astype(np.float64))

步骤3)构造张量

您现在已经熟悉了创建的方法。 张量 在TensorFlow中,您可以将训练集转换为数值列。

feature_columns = [tf.feature_column.numeric_column('x', shape=X_train_scaled.shape[1:])]

步骤4)建立模型

该神经网络架构包含两个隐藏层,第一层有 300 个单元,第二层有 100 个单元。这些数值并非来自公式,而是经验得出的。您可以调整这些数值,并观察它们如何影响网络的准确率。

要构建模型,您需要使用 DNNClassifier 估计器。由于训练集中有十个类别,因此您需要将类别数设置为 10。您应该已经熟悉估计器对象的语法。参数 feature_columns、n_classes 和 model_dir 与之前的教程完全相同。参数 hidden_​​units 是新增的:它控制神经网络的层数以及每层连接的节点数。在下面的代码中,有两个隐藏层,第一个隐藏层连接 300 个节点,第二个隐藏层连接 100 个节点。

要构建估计器,请使用具有以下参数的 tf.estimator.DNNClassifier:

  • 特征列: 定义网络中使用的列。
  • hidden_​​units: 确定隐藏神经元的数量
  • n_classes: 确定要预测的类别数量
  • model_dir: 定义路径 张量板
estimator = tf.estimator.DNNClassifier(
    feature_columns=feature_columns,
    hidden_units=[300, 100], 
    n_classes=10, 
    model_dir = '/train/DNN')

步骤5)训练并评估模型

您可以使用 NumPy 输入函数来训练和评估模型。

# Train the estimator
train_input = tf.estimator.inputs.numpy_input_fn(
    x={"x": X_train_scaled},
    y=y_train,
    batch_size=50,
    shuffle=False,
    num_epochs=None)
estimator.train(input_fn = train_input,steps=1000) 
eval_input = tf.estimator.inputs.numpy_input_fn(
    x={"x": X_test_scaled},
    y=y_test, 
    shuffle=False,
    batch_size=X_test_scaled.shape[0],
    num_epochs=1)
estimator.evaluate(eval_input,steps=None) 

输出:

{'accuracy': 0.9637143,
 'average_loss': 0.12014342,
 'loss': 1682.0079,
 'global_step': 1000}

当前架构在评估集上的准确率约为 96%。

步骤6)改进模型

您可以尝试通过添加正则化参数来改进模型。

这里,估计器使用了一个近端 AdaGrad 优化器,dropout 率为 0.3,L1 和 L2 强度均设置为 0.01。在 TensorFlow 神经网络中,可以通过 train 对象加上优化器名称来访问优化器。TensorFlow 为近端 AdaGrad 优化器提供了一个内置 API。

要为深度神经网络添加正则化,可以使用 tf.train.ProximalAdagradOptimizer 并配合以下参数:

  • 学习率: 学习率
  • L1正则化: l1正则化强度
  • L2正则化: l2正则化强度
estimator_imp = tf.estimator.DNNClassifier(
    feature_columns=feature_columns,
    hidden_units=[300, 100],
    dropout=0.3, 
    n_classes = 10,
    optimizer=tf.train.ProximalAdagradOptimizer(
      learning_rate=0.01,
      l1_regularization_strength=0.01, 
      l2_regularization_strength=0.01
    ),
    model_dir = '/train/DNN1')
estimator_imp.train(input_fn = train_input,steps=1000) 
estimator_imp.evaluate(eval_input,steps=None) 

输出:

{'accuracy': 0.95057142,
 'average_loss': 0.17318928,
 'loss': 2424.6499,
 'global_step': 2000}

为了减少过拟合而选择的参数值并没有提高模型准确率。你的第一个模型准确率为 96%,而使用 L2 正则化器的模型准确率为 95%。你可以尝试不同的参数值,看看它们对准确率的影响。

常见问题

没有固定的公式。通常的经验法则是,隐藏层神经元的数量应保持在输入层和输出层神经元数量之间,或者接近输入层神经元数量加上输出层神经元数量的三分之二。大多数表格问题需要一到两个隐藏层;从小规模开始,逐步增加,直到模型过拟合为止。

并非如此。TensorFlow 2.16 中移除了 `tf.estimator`,并且 `tf.estimator.inputs.numpy_input_fn` 也已不存在。要么使用 TensorFlow 2.15,要么使用 `tf.keras.layers.Dense` 重建网络,每个层包含 300 个单元和 100 个单元,然后使用 `model.fit()` 进行训练。

神经网络架构搜索和自动调优库并行地扫描层数、层宽、学习率和dropout值,然后根据验证分数对候选方案进行排序。它们用精确的比较取代了手动试错,但计算预算和目标指标仍然由工程师设定。

是的。 GitHub 副驾驶 它可以根据简短的注释自动补全样板代码,例如输入管道、层堆栈和评估循环。请将其输出视为草稿:它可能会建议一些已被移除的 API,例如 fetch_mldata,因此在运行之前,请务必对照最新文档验证每个调用。

mldata.org 已关闭 scikit学习 0.22 版本中移除了 fetch_mldata 函数。请改用 fetch_openml('mnist_784', version=1)。该函数会下载相同的 70,000 个手写数字,并返回数据和目标属性,因此本教程的其余部分保持不变。

人工神经网络(ANN)将每一层中的每个单元与下一层中的每个单元连接起来,这适用于处理表格数据。 卷积网络 在图像上共享小型滤镜,而 循环网络 将状态传递到序列中。

基线模型过拟合程度并不严重,因此 0.3 的 dropout 加上 0.01 的 L1 和 L2 惩罚项基本消除了模型的有效容量。准确率从 0.9637143 下降到 0.95057142。正则化仅在训练集和测试集分数差距较大时才有效。

常见的应用场景包括图像和语音识别、自然语言理解、需求预测、信用评分、欺诈检测和推荐排序。它们的优势在于能够直接从原始数据中学习非线性关系;劣势在于与线性模型或基于树的模型相比,其可解释性有限。

总结一下这篇文章: