摘要
本教程将介绍如何使用机器学习的方法,对鸢(yuan一声)尾花按照种类进行分类。
教程将使用Tensorflow的eager模式来:
- 建立一个模型
- 用示例数据进行训练
- 使用该模型对未知数据进行预测。
读者并不需要机器学习的经验,但是需要懂一些Python。
Tensorflow编程
- 在开发环境中开启
- 使用导入数据
- 使用TensorFlow的来构建模型和layer。
通常情况下,TensorFlow程序会按照下面的流程编写:
- 导入和解析数据集。
- 选择模型的类型。
- 训练模型。
- 使用训练后的模型做预测。
第一个程序
开启eager模式
from __future__ import absolute_import, division, print_function
import os
import matplotlib.pyplot as plt
import tensorflow as tf
import tensorflow.contrib.eager as tfe
tf.enable_eager_execution()
print("TensorFlow version: {}".format(tf.VERSION))
print("EAGER execution: {}".format(tf.executing_eagerly()))
输出
TensorFlow version: 1.7.0
EAGER execution: True
鸢尾花分类问题
假设你是一个植物学家,现在要寻找一种能够对发现的鸢尾花分类的进行自动分类的方法。机器学习提供了许多算法来对花进行分类,比如,一个复杂的机器学习程序可以根据照片对花进行分类。鸢尾花问题简单一些,我们根据萼片和花瓣的长度和宽度测量值对其进行分类。
鸢尾花大约有300种,不过我们的程序只区分以下三种:
- 山鸢尾(iris setosa)
- 维吉尼亚鸢尾(iris virginica)
- 杂色鸢尾(iris versicolor)
导入和解析数据集
使用Python下载数据集文件,并结构化数据
下载数据集
train_dataset_url = 'http://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))
输出
Local copy of the dataset file: /home/jovyan/.keras/datasets/iris_training.csv
检查数据
下载下来的数据使用csv格式存储,可以head -n5
看看前五条数据。
!head -n5 {train_dataset_fp}
结果
120,4,setosa,versicolor,virginica
6.4,2.8,5.6,2.2,2
5.0,2.3,3.3,1.0,1
4.9,2.5,4.5,1.7,2
4.9,3.1,1.5,0.1,0
可以看到:
- 第一条包含了数据集的信息:
- 一共有120组数据。每条都包含了4个特征和三个可能的标签之一。
- 后续行是数据记录,每行一个,其中:
- 前4栏是,在这里,这些字段保存花朵测量的数据,是浮点数。
- 最后一栏是,也是我们想要预测的结果。在这个数据集中,它是0,1或者2,每个数字对应一种花名。
每个标签都会与一个字符串相关联(例如“setosa”),但是使用数字会让程序处理得更快。标签号码会映射到一个名字,比如
-
0
: Iris setosa -
1
: Iris versicolor -
2
: Iris virginica
解析数据集
由于数据集是csv格式的文本,因此需要将特征和标签值解析为模型可以使用的格式。文件中的每一行都会被传给parse_csv
函数,该函数会抓取前四个特征值并将它们合并为单个tensor,然后自后一个字段会被解析为标签。最后函数返回特征tensor和标签tensor
def parse_csv(line):
example_defaults = [[0.], [0.], [0.], [0.], [0]] # sets field types
parsed_line = tf.decode_csv(line, example_defaults)
# First 4 fields are features, combine into single tensor
features = tf.reshape(parsed_line[:-1], shape=(4,))
# Last field is the label
label = tf.reshape(parsed_line[-1], shape=())
return features, label
创建用于训练的tf.data.Dataset
如果样本是随机排列的话,训练的效果是做好的。将buffer_size
设置为大于样本数量的值,然后调用tf.data.Dataset.shuffle
打乱输入数据条目的顺序。为了加速训练的速度,将[batch size]设置为32,来每次处理32个样本。
train_dataset = tf.data.TextLineDataset(train_dataset_fp)
train_dataset = train_dataset.skip(1)
train_dataset = train_dataset.map(parse_csv)
train_dataset = train_dataset.shuffle(buffer_size=1000)
train_dataset = train_dataset.batch(32)
features, label = tfe.Iterator(train_dataset).next()
print('example features:', features[0])
print('example label:', label[0])
输出为
example features: tf.Tensor([7.7 3. 6.1 2.3], shape=(4,), dtype=float32)
example label: tf.Tensor(2, shape=(), dtype=int32)
选择模型类型
为什么需要模型呢?
可以在不使用机器学习的情况下,确定四种特征与鸢尾花种类之间的关系吗?就是说,能否用传统的编程技术(比如大量的条件语句)来创建模型呢?如果有足够长的时间来进行研究,也许能发现这些特征值和鸢尾花物种之间的关系。不过对于更复杂的数据集来说,这样的方法会变得困难,甚至变得不可能实现。
一个好的机器学习方法能确定这个模型。如果将足够多有代表性的样本提供给正确的机器学习模型,程序就能找到特征值和B标签之间正确的关系。
选择模型
-
0.03
: 山鸢尾 -
0.95
: 杂色鸢尾 -
0.02
: 维吉尼亚鸢尾
也就是说,模型预测,这个没有被标记的样本时杂色鸢尾。
使用Keras创建模型
model = tf.keras.Sequential([
tf.keras.layers.Dense(10, activation='relu', input_shape=(4,)),
tf.keras.layers.Dense(10, activation='relu'),
tf.keras.layers.Dense(3)
])
隐藏层和神经元的理想数量取决于问题和数据集。像机器学习的其他很多方面一样,神经网络的各个部分的选择需要知识和实践。作为一个经验法则,增加隐藏层和神经元的数量通常会创建一个更强大的模型,这需要更多的数据来进行有效的训练。
训练模型
定义损失和梯度函数
def loss(model, x, y):
y_ = model(x)
return tf.losses.sparse_softmax_cross_entropy(labels=y, logits=y_)
def grad(model, inputs, targets):
with tfe.GradientTape() as tape:
loss_value = loss(model, inputs, targets)
return tape.gradient(loss_value, model.variables)
创建优化器
imageoptimizer = tf.train.GradientDescentOptimizer(learning_rate=0.01)
训练迭代
现在万事俱备,该模型已准备好接受训练了!训练循环将数据集样本提供给模型,以帮助它做出更好的预测。下面的代码设置了一些训练步骤:
- 迭代每个周期。每个周期是对整个数据集的一次完整遍历。
- 在该周期内,对训练数据集中的每个样本进行迭代,以获取其特征(
x
)和标签(y
)。 - 使用样本中特征进行预测,并于标签进行比较。测量预测的不准确性并使用它来计算模型的损失和梯度。
- 使用
optimizer
来更新模型的变量。 - 跟踪一些统计数据以进行可视化展示。
- 为每个周期执行一次上面的操作。
train_loss_results = []
train_accuracy_results = []
num_epoches = 201
for epoch in range(num_epoches):
epoch_loss_avg = tfe.metrics.Mean()
epoch_accuracy = tfe.metrics.Accuracy()
for x, y in tfe.Iterator(train_dataset):
grads = grad(model, x, y)
optimizer.apply_gradients(zip(grads, model.variables), global_step=tf.train.get_or_create_global_step())
epoch_loss_avg(loss(model, x, y))
epoch_accuracy(tf.argmax(model(x), axis=1, output_type=tf.int32), y)
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.005, Accuracy: 50.833%
Epoch 050: Loss: 0.384, Accuracy: 85.000%
Epoch 100: Loss: 0.257, Accuracy: 95.833%
Epoch 150: Loss: 0.183, Accuracy: 97.500%
Epoch 200: Loss: 0.134, Accuracy: 97.500%
可视化展示损失
要看懂这样的图表需要一些经验,但是我们期望的是看到损失下降,准确度上升。
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()
评估模型的有效性
现在模型已经过了训练,我们可以得到它表现的统计数据。
评估意味着确定模型预测的准确度。为了确定模型在鸢尾花分类问题上的有效性,先将一些萼片和花瓣的测量结果传递给模型,要求模型预测它们代表的鸢尾花种类,然后将预测结果与实际的标签进行比较。下表展示了一个比较准确的模型,在5次预测中正确了4次,达到了80%的准确率。
样本特征 | 标签 | 模型预测 |
---|---|---|
5.9 3.0 4.3 1.5 | 1 | 1 |
6.9 3.1 5.4 2.1 | 2 | 2 |
5.1 3.3 1.7 0.5 | 0 | 0 |
6.0 3.4 4.5 1.6 | 1 | 2 |
5.5 2.5 4.0 1.3 | 1 | 1 |
设置测试数据集
设置测试数据集和设置训练数据集差不多。下载CSV文件,解析数据,然后打乱数据顺序:
test_url = 'http://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.TextLineDataset(test_fp)
test_dataset = test_dataset.skip(1)
test_dataset = test_dataset.map(parse_csv)
test_dataset = test_dataset.shuffle(1000)
test_dataset = test_dataset.batch(32)
输出为
Downloading data from http://download.tensorflow.org/data/iris_test.csv
8192/573 [============================================================================================================================================================================================================================================================================================================================================================================================================================================] - 0s 0us/step
在测试数据集上评估模型
和训练不同,评估测试数据只需要一个周期。在下面的代码中,我们遍历测试集中的每个示例,并将模型的预测与实际的标签进行比较。这用于在整个测试集中测量模型的准确性。
test_accuracy = tfe.metrics.Accuracy()
for (x, y) in tfe.Iterator(test_dataset):
prediction = tf.argmax(model(x), axis=1, output_type=tf.int32)
test_accuracy(prediction, y)
print("Test set accuracy: {:.3%}".format(test_accuracy.result()))
输出为
Test set accuracy: 96.667%
使用训练好的模型进行预测
在实际场景中,无标签样本可能有多个来源,比如应用程序,CSV文件和feeds数据。现在,我们将手动提供三个无标签样本来预测其标签。每个种类被一个数字代表:
-
0
: 山鸢尾 -
1
:杂色鸢尾 -
2
:维吉尼亚鸢尾
class_ids = ['Iris setosa', 'Iris versicolor', 'Iris virginica']
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()
name = class_ids[class_idx]
print("Example {} prediction: {}".format(i, name))
预测结果为:
Example 0 prediction: Iris setosa
Example 1 prediction: Iris versicolor
Example 2 prediction: Iris virginica
预测全部正确!