机器学习101(译)

本文翻译自Get started with eager execution

摘要

本教程将介绍如何使用机器学习的方法,对鸢(yuan一声)尾花按照种类进行分类。

教程将使用Tensorflow的eager模式来:

  1. 建立一个模型
  2. 用示例数据进行训练
  3. 使用该模型对未知数据进行预测。

读者并不需要机器学习的经验,但是需要懂一些Python。

Tensorflow编程

Tensorflow提供了很多的API,但建议从从以下高级TensorFlow概念开始学习:

  • 在开发环境中开启eager模式
  • 使用Datasets API导入数据
  • 使用TensorFlow的Keras API来构建模型和layer。

通常情况下,TensorFlow程序会按照下面的流程编写:

  1. 导入和解析数据集。
  2. 选择模型的类型。
  3. 训练模型。
  4. 使用训练后的模型做预测。

第一个程序

教程将翻译自会使用jupyter notebook在浏览器中执行Python代码。谷歌提供了一个现成的工具Colab notebook eager模式在TensorFlow 1.7版本开始支持。

开启eager模式

eager模式能让代码立刻运行,返回具体的结果,而不是等计算图绘制完成后再执行。一旦在代码中开启了eager模式,就不能关掉了。具体说明见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)

幸运的是,有人已经创建了一个有萼片和花瓣测量结果组成的120组鸢尾花数据集。这是一个对机器学习初学者的经典数据集。

导入和解析数据集

使用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

可以看到:

  1. 第一条包含了数据集的信息:
  2. 一共有120组数据。每条都包含了4个特征和三个可能的标签之一。
  3. 后续行是数据记录,每行一个样本,其中:
  4. 前4栏是特征,在这里,这些字段保存花朵测量的数据,是浮点数。
  5. 最后一栏是标签,也是我们想要预测的结果。在这个数据集中,它是0,1或者2,每个数字对应一种花名。

每个标签都会与一个字符串相关联(例如“setosa”),但是使用数字会让程序处理得更快。标签号码会映射到一个名字,比如

  • 0: Iris setosa
  • 1: Iris versicolor
  • 2: Iris virginica

关于特征和标签的更多内容,请看ML Terminology section of the Machine Learning Crash Course

解析数据集

由于数据集是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

TensorFlow的Dataset API能够处理给模型提供数据的很多常见场景。这是一个高级API,可用来读取数据并将其转换为可训练数据格式。

该程序使用tf.data..TextlineDataset来读取CSV格式的文件,然后通过parse_csv函数解析其中的数据。tf.data.Dataset将输入流程表示为元素集合和一系列对这些元素起作用的转换。转换的方法被链接在一起或者按顺序调用--只要确保对返回的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标签之间正确的关系。

选择模型

已经有很多的机器学习模型存在了,需要一些经验才能为训练选择合适的模型。这里将使用神经网络来解决鸢尾花分类问题。神经网络能找出特征值和标签之间的复杂关系。它是由一个或多个隐藏层的高度结构化的计算图。每个隐藏层由一个或多个神经元组成。有好几类神经网络存在,本教程使用密集的,或者被称为完全连接的神经网络:某一层的神经元接接收来自前一层中每个神经元的输入连接。下图展示了一个由一个输入层,两个隐藏层和一个输出层组成的密集神经网络:

当训练了上图中的模型后,输入未标记的样本时,会产生三个预测,分别是该花为鸢尾属物种的可能性。这种预测被称为推断。在这个例子中,输出预测的总和是1.0。在上图中,预测结果是

  • 0.03: 山鸢尾
  • 0.95: 杂色鸢尾
  • 0.02: 维吉尼亚鸢尾

也就是说,模型预测,这个没有被标记的样本时杂色鸢尾。

使用Keras创建模型

TensorFlow的tf.keras API时创建模型和图层的首选方式。Keras会处理将所有内容连接在一起的复杂性,这让构建模型并进行实验变得很容易。详情请见Keras文档。

tf.keras.Sequential模型是一个线性堆栈层。其初始化需要一个图层实例列表,在本教程的示例中,领个密集图层各有10个节点,一个输出图层3个代表预测标签的节点。第一层的input_shape参数是必须的,对应于数据集中特征的数量。

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)
])

激活函数(代码中的activation)决定了单个神经元到下一层的输出。这个工作模式总体上和大脑神经元的连接方式相同。有许多可用的激活函数,隐藏层通常使用修正线性单元(即代码中的relu)。

隐藏层和神经元的理想数量取决于问题和数据集。像机器学习的其他很多方面一样,神经网络的各个部分的选择需要知识和实践。作为一个经验法则,增加隐藏层和神经元的数量通常会创建一个更强大的模型,这需要更多的数据来进行有效的训练。

训练模型

训练是机器学习中模型逐步优化或者说是模型学习数据集的阶段。训练的目标是充分了解训练数据集的结构,以及预测未知数据。如果通过训练对数据集了解太多,则预测仅适用于所看到的数据,而不能适用于一般的情况。这个问题被称之为过拟合--就像程序记住了答案而不是理解如何解决问题一样。

鸢尾花分类问题是监督式机器学习的一个例子,该模型从包含标签的样本中开始训练。在非监督式机器学习中,样本中不包含标签,相反,模型通常会在特征中找到模式。

定义损失和梯度函数

训练和评估阶段都需要计算模型的损失。这可以用来衡量预测结果和期望标签之间的差距有多大,换句话说:模型的表现有多糟糕。我们想要最小化或者说优化这个差值。

我们使用tf.losses.sparsesoftmaxcross_entropy来计算损失,这个方法接受模型的预测和期望的标签作为参数。随着返回的损失值增大,预测的结果也随着变差。

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)

上面的代码中grad函数调用loss函数和tfe.GradientTape来记录用于优化模型梯度的操作。更多的例子见eager教程。

创建优化器

优化器将计算出的梯度应用于模型的变量以最小化loss函数。可以把情况想象成一个曲面,通过在这个曲面上到处移动,来找到最低点

梯度指向上升速度最快的方向,所以我们将以相反的方向行进,并沿着山丘向下移动。通过迭代计算每个步骤(或学习速率)的损失和梯度,我们将在训练期间调整模型。慢慢的,模型会找到权重和偏差的最佳组合,以最大限度地减少损失。损失越低,模型的预测效果就越好。

TensorFlow有很多用于训练的优化算法。本教程中的模型使用tf.train.GradientDescentOptimizer,这个优化器实现了标准梯度下降算法(SGD)。learning_rate 为每次迭代的步长。这是一个超参数,通常通过调整该参数来获得更好的结果。

optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.01)

训练迭代

现在万事俱备,该模型已准备好接受训练了!训练循环将数据集样本提供给模型,以帮助它做出更好的预测。下面的代码设置了一些训练步骤:

  1. 迭代每个周期。每个周期是对整个数据集的一次完整遍历。
  2. 在该周期内,对训练数据集中的每个样本进行迭代,以获取其特征(x)和标签(y)。
  3. 使用样本中特征进行预测,并于标签进行比较。测量预测的不准确性并使用它来计算模型的损失和梯度。
  4. 使用optimizer来更新模型的变量。
  5. 跟踪一些统计数据以进行可视化展示。
  6. 为每个周期执行一次上面的操作。

num_epochs是循环访问数据集集合的次数。反过来说,长时间训练模型并不能保证模型变得更好。num_epochs是一个可以调整的超参数,需要经验和实践才能找到正确的值。

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%

可视化展示损失

打印出训练的进度是很有用的,但是如果能更直观的看到整个过程就更好了。TensorFlow集成了一个非常好用的可视化工具TensorBoard,不过这里我会使用mathplotlib模块创建基本的图表。

要看懂这样的图表需要一些经验,但是我们期望的是看到损失下降,准确度上升。

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

预测全部正确!

要想深入了解机器学习模型,请查看TensorFlow编程指南。

原文发布于微信公众号 - 派森公园(demon-hsy)

原文发表时间:2018-04-20

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏AI研习社

SSD: Single Shot MultiBox Detector 深度学习笔记之SSD物体检测模型

算法概述 本文提出的SSD算法是一种直接预测目标类别和bounding box的多目标检测算法。 与faster rcnn相比,该算法没有生成 propos...

5037
来自专栏云时之间

EM算法学习(番外篇):HMM的参数估计

在上一篇文章中留下了个尾巴是关于EM算法在HMM隐马尔可夫模型的参数估计拓展上的应用.在学习EM算法以后,我们再去学习HMM的Baum-Weich算法就会相对的...

35611
来自专栏人工智能头条

十分钟掌握Keras实现RNN的seq2seq学习

1194
来自专栏绿巨人专栏

神经网络学习笔记-02-循环神经网络

3407
来自专栏AI科技评论

开发 | 手把手教你用 TensorFlow 实现文本分类(上)

由于需要学习语音识别,期间接触了深度学习的算法。利用空闲时间,想用神经网络做一个文本分类的应用, 目的是从头到尾完成一次机器学习的应用,学习模型的优化方法,同时...

3339
来自专栏人工智能LeadAI

Tensorflow之 CNN卷积神经网络的MNIST手写数字识别

前言 tensorflow中文社区对官方文档进行了完整翻译。鉴于官方更新不少内容,而现有的翻译基本上都已过时。故本人对更新后文档进行翻译工作,纰漏之处请大家指正...

5405
来自专栏机器学习算法原理与实践

MCMC(二)马尔科夫链

    在MCMC(一)蒙特卡罗方法中,我们讲到了如何用蒙特卡罗方法来随机模拟求解一些复杂的连续积分或者离散求和的方法,但是这个方法需要得到对应的概率分布的样本...

42532
来自专栏用户2442861的专栏

Logistic回归与梯度下降法

http://blog.csdn.net/acdreamers/article/details/44657979

521
来自专栏云时之间

EM算法学习(番外篇):HMM的参数估计

在上一篇文章中留下了个尾巴是关于EM算法在HMM隐马尔可夫模型的参数估计拓展上的应用.在学习EM算法以后,我们再去学习HMM的Baum-Weich算法就会相对的...

4157
来自专栏AI科技评论

干货 | 一篇文章教你用TensorFlow写名著

前言 最近看完了 LSTM 的一些外文资料,主要参考了 Colah 的 blog以及 Andrej Karpathy blog的一些关于 RNN 和 LST...

3608

扫码关注云+社区