2.4-tensorflow2-官网教程-自定义训练-鸢尾花分类-全连接神经网络

这个教程将利用机器学习的手段来对鸢尾花按照物种进行分类。本教程将利用 TensorFlow 来进行以下操作:

 1. 构建一个模型,
 2. 用样例数据集对模型进行训练,以及
 3. 利用该模型对未知数据进行预测。

TensorFlow 编程
本指南采用了以下高级 TensorFlow 概念:

 1. 使用 TensorFlow 默认的 eager execution 开发环境,
 2. 使用 Datasets API 导入数据,
 3. 使用 TensorFlow 的 Keras API 来构建各层以及整个模型。

本教程的结构同很多 TensorFlow 程序相似:

 1. 数据集的导入与解析
 2. 选择模型类型
 3. 对模型进行训练
 4. 评估模型效果
 5. 使用训练过的模型进行预测

1.环境的搭建

#导入 TensorFlow 以及其他需要的 Python 库。 默认情况下,TensorFlow 用 eager execution 来实时评估操作, 返回具体值而不是建立一个稍后执行的计算图。 如果您习惯使用 REPL 或 python 交互控制台, 对此您会感觉得心应手。
import os
import matplotlib.pyplot as plt
import tensorflow as tf
print("TensorFlow version: {}".format(tf.__version__))
print("Eager execution: {}".format(tf.executing_eagerly()))
#TensorFlow version: 2.3.0
#Eager execution: True
鸢尾属约有 300 个品种,但我们的程序将仅对下列三个品种进行分类:

 1. 山鸢尾
 2. 维吉尼亚鸢尾
 3. 变色鸢尾

Figure 1. 山鸢尾, 变色鸢尾, , and 维吉尼亚鸢尾 (by Frank Mayfield, CC BY-SA 2.0).

2.导入和解析训练数据集


使用 tf.keras.utils.get_file 函数下载训练数据集文件。该函数会返回下载文件的文件路径:
train_dataset_url = "https://storage.googleapis.com/download.tensorflow.org/data/iris_training.csv"

train_dataset_fp = tf.keras.utils.get_file(fname=os.path.basename(train_dataset_url),
                                           origin=train_dataset_url)

print("Local copy of the dataset file: {}".format(train_dataset_fp))

我们可以从该数据集视图中注意到以下信息:

 1. 第一行是表头,其中包含数据集信息:
 2. 共有 120 个样本。每个样本都有四个特征和一个标签名称,标签名称有三种可能。
 3. 后面的行是数据记录,每个样本各占一行,其中:
   1. 前四个字段是特征: 这四个字段代表的是样本的特点。在此数据集中,这些字段存储的是代表花卉测量值的浮点数。
   2. 最后一列是标签:即我们想要预测的值。对于此数据集,该值为 012 中的某个整数值(每个值分别对应一个花卉名称)

# CSV文件中列的顺序
column_names = ['sepal_length', 'sepal_width', 'petal_length', 'petal_width', 'species']

feature_names = column_names[:-1]
label_name = column_names[-1]

print("Features: {}".format(feature_names))
print("Label: {}".format(label_name))

class_names = ['Iris setosa', 'Iris versicolor', 'Iris virginica']
#创建一个 tf.data.Dataset
batch_size = 32

train_dataset = tf.data.experimental.make_csv_dataset(
    train_dataset_fp,
    batch_size,
    column_names=column_names,
    label_name=label_name,
    num_epochs=1)

features, labels = next(iter(train_dataset))

print(features)
OrderedDict([('sepal_length', <tf.Tensor: shape=(32,), dtype=float32, numpy=
array([6.5, 4.6, 4.7, 5.4, 6.9, 6.1, 5.8, 6.3, 5.4, 6.7, 7.6, 5.4, 5.5,
       6.8, 5. , 4.6, 5.8, 6.1, 5. , 4.9, 7.7, 6.3, 6.2, 5.4, 5.7, 5.1,
       7.4, 6.5, 5.8, 6.1, 5.4, 5.5], dtype=float32)>), ('sepal_width', <tf.Tensor: shape=(32,), dtype=float32, numpy=
array([3. , 3.6, 3.2, 3.4, 3.1, 2.6, 4. , 2.3, 3.7, 3.1, 3. , 3.9, 2.4,
       2.8, 3.4, 3.2, 2.7, 2.9, 3.2, 3. , 2.8, 2.5, 3.4, 3. , 3.8, 2.5,
       2.8, 3.2, 2.7, 2.8, 3.9, 3.5], dtype=float32)>), ('petal_length', <tf.Tensor: shape=(32,), dtype=float32, numpy=
array([5.5, 1. , 1.3, 1.5, 4.9, 5.6, 1.2, 4.4, 1.5, 4.4, 6.6, 1.3, 3.8,
       4.8, 1.5, 1.4, 4.1, 4.7, 1.2, 1.4, 6.7, 5. , 5.4, 4.5, 1.7, 3. ,
       6.1, 5.1, 5.1, 4. , 1.7, 1.3], dtype=float32)>), ('petal_width', <tf.Tensor: shape=(32,), dtype=float32, numpy=
array([1.8, 0.2, 0.2, 0.4, 1.5, 1.4, 0.2, 1.3, 0.2, 1.4, 2.1, 0.4, 1.1,
       1.4, 0.2, 0.2, 1. , 1.4, 0.2, 0.2, 2. , 1.9, 2.3, 1.5, 0.3, 1.1,
       1.9, 2. , 1.9, 1.3, 0.4, 0.2], dtype=float32)>)])
plt.scatter(features['petal_length'],
            features['sepal_length'],
            c=labels,
            cmap='viridis')

plt.xlabel("Petal length")
plt.ylabel("Sepal length")
plt.show()

在这里插入图片描述

def pack_features_vector(features, labels):
  """将特征打包到一个数组中"""
  features = tf.stack(list(features.values()), axis=1)
  return features, labels

#然后使用 tf.data.Dataset.map 方法将每个 (features,label) 对中的 features 打包到训练数据集中:

train_dataset = train_dataset.map(pack_features_vector)
#Dataset 的特征元素被构成了形如 (batch_size, num_features) 的数组。我们来看看前几个样本:

features, labels = next(iter(train_dataset))

print(features[:5])
tf.Tensor(
[[5.  3.  1.6 0.2]
 [6.4 3.2 4.5 1.5]
 [6.6 3.  4.4 1.4]
 [6.8 2.8 4.8 1.4]
 [6.9 3.1 4.9 1.5]], shape=(5, 4), dtype=float32)

3 选择模型类型

选择模型
我们需要选择要进行训练的模型类型。模型具有许多类型,挑选合适的类型需要一定的经验。本教程使用神经网络来解决鸢尾花分类问题。神经网络可以发现特征与标签之间的复杂关系。神经网络是一个高度结构化的图,其中包含一个或多个隐含层。每个隐含层都包含一个或多个神经元。 神经网络有多种类别,该程序使用的是密集型神经网络,也称为全连接神经网络 : 一个层中的神经元将从上一层中的每个神经元获取输入连接。例如,图 2 显示了一个密集型神经网络,其中包含 1 个输入层、2 个隐藏层以及 1 个输出层:

在这里插入图片描述

使用 Keras 创建模型
TensorFlow tf.keras API 是创建模型和层的首选方式。通过该 API,您可以轻松地构建模型并进行实验,而将所有部分连接在一起的复杂工作则由 Keras 处理。

tf.keras.Sequential 模型是层的线性堆叠。该模型的构造函数会采用一系列层实例;在本示例中,采用的是 2 个密集层(各自包含10个节点),以及 1 个输出层(包含 3 个代表标签预测的节点。第一个层的 input_shape 参数对应该数据集中的特征数量,它是一项必需参数:

model = tf.keras.Sequential([
  tf.keras.layers.Dense(10, activation=tf.nn.relu, input_shape=(4,)),  # 需要给出输入的形式
  tf.keras.layers.Dense(10, activation=tf.nn.relu),
  tf.keras.layers.Dense(3)
])
#使用模型
#我们快速了解一下此模型如何处理一批特征:

predictions = model(features)
predictions[:5]
<tf.Tensor: shape=(5, 3), dtype=float32, numpy=
array([[-0.7071651 ,  0.47789907, -0.00770754],
       [-1.4103267 ,  0.88527995,  0.12433483],
       [-1.3858227 ,  0.8719123 ,  0.11802539],
       [-1.4489397 ,  0.9073442 ,  0.13221698],
       [-1.4966192 ,  0.9378521 ,  0.1352278 ]], dtype=float32)>
#要将这些对数转换为每个类别的概率,请使用 softmax 函数:
tf.nn.softmax(predictions[:5])
<tf.Tensor: shape=(5, 3), dtype=float32, numpy=
array([[0.15914552, 0.5205486 , 0.3203059 ],
       [0.0642252 , 0.6377857 , 0.29798916],
       [0.0663994 , 0.6348718 , 0.29872882],
       [0.06093013, 0.6429145 , 0.29615542],
       [0.05706754, 0.65112835, 0.29180405]], dtype=float32)>
#对每个类别执行 tf.argmax 运算可得出预测的类别索引。不过,该模型尚未接受训练,因此这些预测并不理想。

print("Prediction: {}".format(tf.argmax(predictions, axis=1)))
print("    Labels: {}".format(labels))

4 训练模型

训练 是一个机器学习阶段,在此阶段中,模型会逐渐得到优化,也就是说,模型会了解数据集。目标是充分了解训练数据集的结构,以便对未见过的数据进行预测。如果您从训练数据集中获得了过多的信息,预测便会仅适用于模型见过的数据,但是无法泛化。此问题被称之为过拟合—就好比将答案死记硬背下来,而不去理解问题的解决方式。

鸢尾花分类问题是监督式机器学习的一个示例: 模型通过包含标签的样本加以训练。 而在非监督式机器学习中,样本不包含标签。相反,模型通常会在特征中发现一些规律。

定义损失和梯度函数
在训练和评估阶段,我们都需要计算模型的损失。 这样可以衡量模型的预测结果与预期标签有多大偏差,也就是说,模型的效果有多差。我们希望尽可能减小或优化这个值。

我们的模型会使用 tf.keras.losses.SparseCategoricalCrossentropy 函数计算其损失,此函数会接受模型的类别概率预测结果和预期标签,然后返回样本的平均损失。
#我们的模型会使用 tf.keras.losses.SparseCategoricalCrossentropy 函数计算其损失,此函数会接受模型的类别概率预测结果和预期标签,然后返回样本的平均损失。

loss_object = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)
def loss(model, x, y):
  y_ = model(x)

  return loss_object(y_true=y, y_pred=y_)


l = loss(model, features, labels)
print("Loss test: {}".format(l))
Loss test: 1.136272668838501
使用 tf.GradientTape 的前后关系来计算梯度以优化你的模型:

def grad(model, inputs, targets):
  with tf.GradientTape() as tape:
    loss_value = loss(model, inputs, targets)
  return loss_value, tape.gradient(loss_value, model.trainable_variables)

5 创建优化器

优化器 会将计算出的梯度应用于模型的变量,以使 loss 函数最小化。您可以将损失函数想象为一个曲面(见图 3),我们希望通过到处走动找到该曲面的最低点。梯度指向最高速上升的方向,因此我们将沿相反的方向向下移动。我们以迭代方式计算每个批次的损失和梯度,以在训练过程中调整模型。模型会逐渐找到权重和偏差的最佳组合,从而将损失降至最低。损失越低,模型的预测效果就越好。
optimizer = tf.keras.optimizers.Adam(learning_rate=0.01)
loss_value, grads = grad(model, features, labels)

print("Step: {}, Initial Loss: {}".format(optimizer.iterations.numpy(),
                                          loss_value.numpy()))

optimizer.apply_gradients(zip(grads, model.trainable_variables))

print("Step: {},         Loss: {}".format(optimizer.iterations.numpy(),
                                          loss(model, features, labels).numpy()))
Step: 0, Initial Loss: 1.136272668838501
Step: 1,         Loss: 1.0750670433044434
训练循环
一切准备就绪后,就可以开始训练模型了!训练循环会将数据集样本馈送到模型中,以帮助模型做出更好的预测。以下代码块可设置这些训练步骤:

 1. 迭代每个周期。通过一次数据集即为一个周期。
 2. 在一个周期中,遍历训练 Dataset 中的每个样本,并获取样本的特征(x)和标签(y)。
 3. 根据样本的特征进行预测,并比较预测结果和标签。衡量预测结果的不准确性,并使用所得的值计算模型的损失和梯度。
 4. 使用 optimizer 更新模型的变量。
 5. 跟踪一些统计信息以进行可视化。
 6. 对每个周期重复执行以上步骤。

#num_epochs 变量是遍历数据集集合的次数。与直觉恰恰相反的是,训练模型的时间越长,并不能保证模型就越好。num_epochs 是一个可以调整的超参数。选择正确的次数通常需要一定的经验和实验基础。
## Note: 使用相同的模型变量重新运行此单元

# 保留结果用于绘制
train_loss_results = []
train_accuracy_results = []

num_epochs = 201

for epoch in range(num_epochs):
  epoch_loss_avg = tf.keras.metrics.Mean()
  epoch_accuracy = tf.keras.metrics.SparseCategoricalAccuracy()

  # Training loop - using batches of 32
  for x, y in train_dataset:
    # 优化模型
    loss_value, grads = grad(model, x, y)
    optimizer.apply_gradients(zip(grads, model.trainable_variables))

    # 追踪进度
    epoch_loss_avg(loss_value)  # 添加当前的 batch loss
    # 比较预测标签与真实标签
    epoch_accuracy(y, model(x))

  # 循环结束
  train_loss_results.append(epoch_loss_avg.result())
  train_accuracy_results.append(epoch_accuracy.result())

  if epoch % 50 == 0:
    print("Epoch {:03d}: Loss: {:.3f}, Accuracy: {:.3%}".format(epoch,
                                                                epoch_loss_avg.result(),
                                                                epoch_accuracy.result()))
Epoch 000: Loss: 1.103, Accuracy: 33.333%
Epoch 050: Loss: 0.068, Accuracy: 99.167%
Epoch 100: Loss: 0.057, Accuracy: 98.333%
Epoch 150: Loss: 0.089, Accuracy: 96.667%
Epoch 200: Loss: 0.048, Accuracy: 98.333%

可视化损失函数随时间推移而变化的情况:

#虽然输出模型的训练过程有帮助,但查看这一过程往往更有帮助。 TensorBoard 是与 TensorFlow 封装在一起的出色可视化工具,不过我们可以使用 matplotlib 模块创建基本图表。

#解读这些图表需要一定的经验,不过您确实希望看到损失下降且准确率上升。
fig, axes = plt.subplots(2, sharex=True, figsize=(12, 8))
fig.suptitle('Training Metrics')

axes[0].set_ylabel("Loss", fontsize=14)
axes[0].plot(train_loss_results)

axes[1].set_ylabel("Accuracy", fontsize=14)
axes[1].set_xlabel("Epoch", fontsize=14)
axes[1].plot(train_accuracy_results)
plt.show()

在这里插入图片描述

6.评估模型的效果

模型已经过训练,现在我们可以获取一些关于其效果的统计信息了。

评估 指的是确定模型做出预测的效果。要确定模型在鸢尾花分类方面的效果,请将一些花萼和花瓣测量值传递给模型,并要求模型预测它们所代表的鸢尾花品种。然后,将模型的预测结果与实际标签进行比较。例如,如果模型对一半输入样本的品种预测正确,则 准确率 为 0.5 。 图 4 显示的是一个效果更好一些的模型,该模型做出 5 次预测,其中有 4 次正确,准确率为 80%

在这里插入图片描述

7 建立测试数据集

评估模型与训练模型相似。最大的区别在于,样本来自一个单独的测试集,而不是训练集。为了公正地评估模型的效果,用于评估模型的样本务必与用于训练模型的样本不同。
#测试 Dataset 的建立与训练 Dataset 相似。下载 CSV 文本文件并解析相应的值,然后对数据稍加随机化处理:
test_url = "https://storage.googleapis.com/download.tensorflow.org/data/iris_test.csv"

test_fp = tf.keras.utils.get_file(fname=os.path.basename(test_url),
                                  origin=test_url)
test_dataset = tf.data.experimental.make_csv_dataset(
    test_fp,
    batch_size,
    column_names=column_names,
    label_name='species',
    num_epochs=1,
    shuffle=False)

test_dataset = test_dataset.map(pack_features_vector)

根据测试数据集评估模型:

#与训练阶段不同,模型仅评估测试数据的一个周期。在以下代码单元格中,我们会遍历测试集中的每个样本,然后将模型的预测结果与实际标签进行比较。这是为了衡量模型在整个测试集中的准确率。

test_accuracy = tf.keras.metrics.Accuracy()

for (x, y) in test_dataset:
  logits = model(x)
  prediction = tf.argmax(logits, axis=1, output_type=tf.int32)
  test_accuracy(prediction, y)

print("Test set accuracy: {:.3%}".format(test_accuracy.result()))
Test set accuracy: 96.667%
#例如,我们可以看到对于最后一批数据,该模型通常预测正确:

tf.stack([y,prediction],axis=1)
<tf.Tensor: shape=(30, 2), dtype=int32, numpy=
array([[1, 1],
       [2, 2],
       [0, 0],
       [1, 1],
       [1, 1],
       [1, 1],
       [0, 0],
       [2, 1],
       [1, 1],
       [2, 2],
       [2, 2],
       [0, 0],
       [2, 2],
       [1, 1],
       [1, 1],
       [0, 0],
       [1, 1],
       [0, 0],
       [0, 0],
       [2, 2],
       [0, 0],
       [1, 1],
       [2, 2],
       [1, 1],
       [1, 1],
       [1, 1],
       [0, 0],
       [1, 1],
       [2, 2],
       [1, 1]], dtype=int32)>

8 使用经过训练的模型进行预测

我们已经训练了一个模型并“证明”它是有效的,但在对鸢尾花品种进行分类方面,这还不够。现在,我们使用经过训练的模型对 无标签样本(即包含特征但不包含标签的样本)进行一些预测。

在现实生活中,无标签样本可能来自很多不同的来源,包括应用、CSV 文件和数据 Feed。暂时我们将手动提供三个无标签样本以预测其标签。回想一下,标签编号会映射到一个指定的表示法:

 0: 山鸢尾
 1: 变色鸢尾
 2: 维吉尼亚鸢尾

predict_dataset = tf.convert_to_tensor([
    [5.1, 3.3, 1.7, 0.5,],
    [5.9, 3.0, 4.2, 1.5,],
    [6.9, 3.1, 5.4, 2.1]
])

predictions = model(predict_dataset)

for i, logits in enumerate(predictions):
  class_idx = tf.argmax(logits).numpy()
  p = tf.nn.softmax(logits)[class_idx]
  name = class_names[class_idx]
  print("Example {} prediction: {} ({:4.1f}%)".format(i, name, 100*p))
Example 0 prediction: Iris setosa (99.9%)
Example 1 prediction: Iris versicolor (99.8%)
Example 2 prediction: Iris virginica (99.3%)
  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值