机器学习101

摘要

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

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

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

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

Tensorflow编程

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

通常情况下,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.sparse_softmax_cross_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函数。可以把情况想象成一个曲面,通过在这个曲面上到处移动,来找到最低点

image

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

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编程指南

本文翻译自Get started with eager execution

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容

  • 机器学习术语表 本术语表中列出了一般的机器学习术语和 TensorFlow 专用术语的定义。 A A/B 测试 (...
    yalesaleng阅读 1,931评论 0 11
  • 本文编译自谷歌开发者机器学习术语表项目,介绍了该项目所有的术语与基本解释。 A 准确率(accuracy) 分类模...
    630d0109dd74阅读 1,929评论 0 1
  • A 准确率(accuracy) 分类模型预测准确的比例。在多类别分类中,准确率定义如下: 在二分类中,准确率定义为...
    630d0109dd74阅读 1,227评论 0 3
  • 人工智能安全和对抗机器学习101 跟随 7月24日 · 14 分钟阅读 图像通过skeeze从pixabay 介绍...
    李穆阅读 779评论 0 0
  • 支付宝的五福活动13日开始,百度的新年活动15号开始,这个月份又是一堆的羊毛可以薅了,新改版后的喵店比以前好多...
    在三线养娃阅读 31评论 0 1