TensorFlow 实战(一)(3)

简介: TensorFlow 实战(一)

TensorFlow 实战(一)(2)https://developer.aliyun.com/article/1522665

2.3 TensorFlow 中与神经网络相关的计算

这里我们将讨论一些支撑深度神经网络的关键低级操作。假设你在学校学习计算机视觉课程。对于你的作业,你必须使用各种数学运算来操作图像,以实现各种效果。我们将使用一张著名的狒狒图像(图 2.7),这是计算机视觉问题的常见选择。


图 2.7 狒狒的图像

2.3.1 矩阵乘法

你的第一个任务是将图像从 RGB 转换为灰度。为此,你必须使用矩阵乘法。让我们首先了解什么是矩阵乘法。

Lena 的故事

尽管我们在练习中使用了狒狒的图像,但长期以来,一直有一个传统,即使用 Lena(一位瑞典模特)的照片来演示各种计算机视觉算法。关于这是如何成为计算机视觉问题的规范的背后有一个非常有趣的故事,您可以在mng.bz/enrZ上阅读。

使用 tf.matmul()函数在两个张量之间执行矩阵乘法。对于两个矩阵,tf.matmul()执行矩阵乘法(例如,如果您有大小为[4,3]和大小为[3,2]的矩阵,矩阵乘法将得到一个[4,2]张量)。图 2.8 说明了矩阵乘法操作。


图 2.8 在一个 4×3 矩阵和一个 3×2 矩阵之间进行矩阵乘法,得到一个 4×2 矩阵。

更一般地说,如果您有一个 n×m 矩阵(a)和一个 m×p 矩阵(b),则矩阵乘法 c 的结果如下:


但是,如果您有高维张量 a 和 b,则将在 a 的最后一个轴上和 b 的倒数第二个轴上执行总乘积。a 和 b 张量的维度除了最后两个轴外都需要相同。例如,如果您有一个大小为[3,5,7]的张量 a 和大小为[3,7,8]的张量 b,则结果将是一个大小为[3,5,8]的张量。

回到我们的问题,给定三个 RGB 像素,您可以使用以下方法将其转换为灰度像素。

0.3 * R + 0.59 * G + 0.11 * B

这是将任何 RGB 图像转换为灰度图像的常见操作(mng.bz/p2M0),这取决于手头的问题是否重要。例如,要从图像中识别数字,颜色并不那么重要。通过将图像转换为灰度,您实质上通过减少输入的大小(一个通道而不是三个)并去除噪声特征(即,颜色信息),从而帮助模型。

给定一个 512×512×3 的图像,如果您将其与代表所提供权重的 3×1 数组相乘,您将得到大小为 512×512×1 的灰度图像。然后,我们需要删除灰度图像的最后一个维度(因为它是一个),最终得到大小为 512×512 的矩阵。对此,您可以使用 tf.squeeze()函数,该函数删除大小为一的任何维度(请参阅下一个列表)。

列表 2.2 使用矩阵乘法将 RGB 图像转换为灰度图像

from PIL import Image                                          ❶
import tensorflow as tf
import numpy as np
x_rgb = np.array(Image.open("baboon.jpg")).astype('float32')   ❷
x_rgb = tf.constant(x_rgb)                                     ❸
grays = tf.constant([[0.3], [0.59] ,[0.11]])                   ❹
x = tf.matmul(x_rgb, grays)                                    ❺
x = tf.squeeze(x)                                              ❻

❶ PIL 是用于基本图像处理的 Python 库。

❷ 大小为 512×512×3 的 RGB 图像被加载为 NumPy 数组。

❸ 将 NumPy 数组转换为 tf.Tensor。

❹ 作为一个 3×1 数组的 RGB 权重

❺ 执行矩阵乘法以获得黑白图像

❻ 去掉最后一个维度,即 1

矩阵乘法在全连接网络中也是一项重要操作。为了从输入层到隐藏层,我们需要使用矩阵乘法和加法。暂时忽略非线性激活,因为它只是一个逐元素的转换。图 2.9 可视化了您之前构建的 MLP 的隐藏层计算。


图 2.9 计算发生在隐藏层的插图。x 是输入(1×4),W 是权重矩阵(4×3),b 是偏差(1×3),最终,h 是输出(1×3)。

2.3.2 卷积操作

接下来的任务是实现边缘检测算法。知道可以使用卷积操作检测边缘后,您还想使用 TensorFlow 展示自己的技能。好消息是,您可以做到!

卷积操作在卷积神经网络中非常重要,卷积神经网络是用于图像相关的机器学习任务(例如图像分类、物体检测)的深度网络。卷积操作将 窗口(也称为filterkernel)移动到数据上,同时在每个位置产生单个值。卷积窗口在每个位置都有一些值。对于给定位置,卷积窗口中的值是元素乘积并与数据中与该窗口重叠的部分相加,以产生该位置的最终值。卷积操作如图 2.10 所示。


图 2.10 卷积操作的计算步骤

根据您选择的卷积窗口的值,您可以产生一些独特的效果。您可以尝试在setosa.io/ev/image-kernels/上尝试一些流行的核。边缘检测也是一种流行的计算机视觉技术,可以使用卷积操作来实现。TensorFlow 提供了 tf.nn.convolution()函数来执行卷积。

首先,我们将黑白狒狒图片存储在 tf.Tensor 中,并将其输入变量命名为 x,x 是一个大小为 512×512 的矩阵。现在,让我们从中创建一个名为 y 的新变量:

y = tf.constant(x)

接下来,让我们定义我们的边缘检测 filter。我们将使用一种名为 近似拉普拉斯滤波器 的边缘检测滤波器,它是一个填有 -1 值的 3 × 3 矩阵,除了最中间的值是 8 外。请注意,内核的总和为零:

filter = tf.Variable(np.array([[-1,-1,-1],[-1,8,-1],[-1,-1,-1]]).astype('float32'))

接下来我们需要对 y 和 filter 进行 reshape,因为 tf.nn.convolution() 函数接受具有非常特定形状的输入和 filter。第一个约束是 y 和 filter 应具有相同的 rank。在这里,rank 指数据中的维数个数。我们这里有 rank2 的张量,将进行二维卷积。要执行 2D 卷积,输入和 kernel 都需要是 rank 4。因此我们需要对输入和 kernel 进行几步重塑:

  1. 在输入的开始和结尾添加两个更多的维度。开始的维度表示批量维度,最后的维度表示通道维度(例如,图像的 RGB 通道)。虽然在我们的示例中值为 1,但我们仍然需要这些维度存在(例如,一个大小为[512,512]的图像将重塑为[1,512,512,1])。
  2. 在 filter 的末尾添加两个大小为 1 的额外维度。这些新维度表示输入和输出通道。我们有一个单通道(即灰度)输入,我们也希望产生一个单通道(即灰度)的输出(例如,一个大小为[3,3]的核将被重塑为[3,3,1,1])。

注意 张量的阶数是指该张量的维数。这与矩阵的秩不同。

如果你不完全明白为什么我们添加了这些额外的维度,不要担心。当我们在后面的章节中讨论卷积神经网络中的卷积操作时,这将更有意义。现在,你只需要理解卷积操作的高级行为就可以了。在 TensorFlow 中,你可以按如下方式重塑 y 和 filter:

y_reshaped = tf.reshape(y, [1,512,512,1])
filter_reshaped = tf.reshape(filter, [3,3,1,1])

这里,y 是一个 512×512 的张量。表达式 tf.reshape(y, [1,512,512,1])将 y(即一个 2D 张量)重塑为一个 4D 张量,大小为 1×512×512×1。同样,filter(即一个大小为 3×3 的 2D 张量)被重塑为一个 4D 张量,大小为 3×3×1×1。请注意,在重塑过程中元素的总数保持不变。现在你可以计算卷积输出如下:

y_conv = tf.nn.convolution(y_reshaped, filter_reshaped)

你可以将边缘检测的结果可视化并将其与原始图像进行比较,如图 2.11 所示。


图 2.11 原始黑白图像与边缘检测结果的比较

在下一节中,我们将讨论另一种操作,即 pooling 操作。

2.3.3 Pooling 操作

我们接下来的任务是将经过边缘检测后的图像的宽度和高度减半。例如,如果我们有一个 512×512 的图像,并且需要将其调整为 256×256,pooling 操作是实现这一目标的最佳方式。出于这个原因,pooling(或子采样)操作在卷积神经网络中常被用于减小输出的尺寸,以便可以使用更少的参数从数据中学习。

为什么它被称为 pooling 操作?

子采样操作之所以也被称为“pooling”可能是因为这个词的含义以及统计学的原因。pooling一词用于描述将事物合并为一个单一实体,这也正是此操作所做的(例如通过平均值或取最大值)。在统计学中,你会发现术语pooled variance,它是两个群体之间方差的加权平均值(mng.bz/OGdO),本质上将两个方差合并为一个方差。

在 TensorFlow 中,您可以调用 tf.nn.max_pool()函数进行最大池化,调用 tf.nn.avg_pool()函数进行平均池化:

z_avg = tf.nn.avg_pool(y_conv, (1,2,2,1), strides=(1,2,2,1), padding='VALID')
z_max = tf.nn.max_pool(y_conv, (1,2,2,1), strides=(1,2,2,1), padding='VALID')

池化操作是卷积神经网络中常见的另一种操作,它的工作原理与卷积操作类似。但与卷积操作不同的是,池化操作的内核中没有值。在给定位置,池化操作取得与数据中内核重叠的部分的平均值或最大值。在给定位置产生平均值的操作称为平均池化,而产生最大值的操作称为最大池化。图 2.12 说明了最大池化操作。


图 2.12:最大池化操作。池化窗口在图像上从一个位置移动到另一个位置,同时一次产生一个值(即与池化窗口重叠的图像中的最大值)。

我们有一个形状为[1,510,510,1]的 4D 张量 y_conv。你可能会注意到,这些维度略小于原始图像的大小(即 512)。这是因为,在对具有 h 高度和 w 宽度的图像进行没有额外填充的大小为 c×c 的窗口卷积时,得到的图像的维度为 h-c+1 和 w-c+1。我们可以进行如下所示的池化操作。您可以使用以下函数进行平均池化或最大池化:

z_avg = tf.nn.avg_pool(y_conv, (1,2,2,1), strides=(1,2,2,1), padding='VALID')
z_max = tf.nn.max_pool(y_conv, (1,2,2,1), strides=(1,2,2,1), padding='VALID')

这将得到两个图像,z_avg 和 z_max;它们的形状都是[1,255,255,1]。为了仅保留高度和宽度维度并移除大小为 1 的冗余维度,我们使用 tf.squeeze()函数:

z_avg = np.squeeze(z_avg.numpy())
z_max = np.squeeze(z_max.numpy())

您可以使用 Python 的绘图库 matplotlib 绘制 z_avg 和 z_max 并获得图 2.13 中所示的结果。代码已在笔记本中提供。


图 2.13:边缘检测后的结果与平均或最大池化后的结果

图 2.13 显示了不同类型池化的效果。仔细观察,您会看到平均池化结果更加一致和连续,而最大池化结果则更加嘈杂。

请注意,与卷积操作不同,我们没有提供滤波器(或内核),因为池化操作没有滤波器。但是我们需要传递窗口的维度。这些维度表示输入的相应维度(即它是一个[batch 维度、高度、宽度、通道]的窗口)。除此之外,我们还传递了两个参数:stride 和 padding。我们将在后面的章节中详细讨论这些参数。

练习 5

给定一个大小为 256×256 的灰度图像 img 和一个大小为 5×5 的卷积滤波器 f。你能编写 tf.reshape()函数调用和 tf.nn.convolution()操作吗?输出的大小会是多少?

很好!现在你已经了解了深度学习网络中最常用的操作。我们将在此结束关于 TensorFlow 基础知识的讨论。在下一章中,我们将讨论 TensorFlow 中提供的一个高级 API,称为 Keras,它对于模型构建特别有用。

摘要

  • TensorFlow 是一个端到端的机器学习框架。
  • TensorFlow 提供了一个生态系统,便于模型原型设计、模型构建、模型监控和模型提供。
  • TensorFlow 1 使用声明式图执行风格(先定义,然后运行),而 TensorFlow 2 使用命令式图执行风格(运行时定义)。
  • TensorFlow 提供了三个主要构建模块:tf.Variable(用于随时间变化的值)、tf.Tensor(随时间固定的值)和 tf.Operation(对 tf.Variable 和 tf.Tensor 对象执行的转换)。
  • TensorFlow 提供了几个用于构建神经网络的操作,如 tf.matmul、tf.nn.convolution 和 tf.nn.max_pool。
  • 您可以使用 tf.matmul 将 RGB 图像转换为灰度图像。
  • 您可以使用 tf.nn.convolution 来检测图像中的边缘。
  • 您可以使用 tf.nn.max_pool 来调整图像大小。

练习答案

练习 1: 2

练习 2: tf.Variable(np.array([[1,2,3],[4,3,2]], dtype=”int16”)

练习 3: tf.constant(np.random.normal(size=[4,1,5]))

练习 4: tf.reduce_mean(a, axis=1)

练习 5:

img_reshaped = tf.reshape(img, [1,256,256,1])
f_reshaped = tf.reshape(f, [5,5,1,1])
y = tf.nn.convolution(img_reshaped, f_reshaped)

最终输出的形状将是 [1,252,252,1]。卷积操作的结果大小为图像大小 - 卷积窗口大小 + 1。

第三章:Keras 和 TensorFlow 2 中的数据检索

本章涵盖的内容

  • Keras 中用于构建模型的不同 API
  • 检索和操作持久化数据

我们已经探讨了低级 TensorFlow API 的细节,比如定义 tf.Variable 对象和 tf.Tensor 对象,这些对象可以用来存储数字和字符串等。我们还查看了 TensorFlow 提供的一些常用功能,如 tf.Operation。最后,我们详细讨论了一些复杂的操作,比如矩阵乘法和卷积。如果你分析任何标准的深度神经网络,你会发现它由矩阵乘法和卷积等标准数学操作构成。

然而,如果你要使用低级别的 TensorFlow API 实现这些网络,你会发现自己在代码中多次复制这些操作,这将耗费宝贵的时间,并使代码难以维护。但好消息是你不需要这样做。TensorFlow 提供了一个名为 Keras 的子模块,它解决了这个问题,这也是本章的重点。Keras 是 TensorFlow 中的一个子库,它隐藏了构建模块,并为开发机器学习模型提供了高级 API。在本章中,我们将看到 Keras 提供了几种不同的 API,可以根据解决方案的复杂性来选择使用。

我们将通过讨论机器学习的另一个重要方面来结束本章:向模型提供数据。通常,我们需要从磁盘(或网络)中检索数据,并在将其提供给模型之前清理和处理数据。我们将讨论 TensorFlow 中几种不同的数据检索工具,如 tf.data 和 tensorflow-datasets API,以及它们如何简化读取和操作最终输入模型的数据。

3.1 Keras 模型构建 API

作为黑客马拉松的一部分,您正在开发一个花卉物种分类器。您的团队将创建几个不同的多层感知器变体,以便将它们的性能与花卉物种识别数据集进行比较。目标是训练能够在给定花卉的多个测量值的情况下输出花卉物种的模型。您需要开发的模型如下:

  • 模型 A——仅从提供的特征中学习的模型(基线)
  • 模型 B——除了使用特征本身外,还使用特征的主成分(详见 3.1.3 节)
  • 模型 C——一个使用非常规隐藏层计算的模型,它使用了一个乘法偏差,除了传统的加法偏差之外,这在神经网络中通常是找不到的(详见 3.1.4 节)

您计划使用 Keras,并且知道它提供了多个模型构建 API。为了快速提供结果,您需要知道在哪个模型中使用哪个 Keras API。

Keras (keras.io/) 最初是作为一个高级 API 启动的,可以使用多个低级后端(例如,TensorFlow、Theano),并允许开发人员轻松构建机器学习模型。换句话说,Keras 隐藏了低级操作的细节,并提供了一个直观的 API,您可以用几行代码构建模型。自从 TensorFlow 1.4 以来,Keras 已经集成到了 TensorFlow 中(www.tensorflow.org/guide/keras/overview)。您可以使用import tensorflow.keras导入 Keras。Keras 有三个主要的 API:

  • 顺序式
  • 函数式
  • 子类化

顺序式 API 是最容易使用的。然而,它是一个非常受限制的 API,只允许您创建一个以一个输入开始,经过一系列层,以及以一个输出结束的网络。接下来,函数式 API 需要更多的工作才能使用。但它也提供了更多的灵活性,例如具有多个输入、并行层和多个输出。最后,子类化 API 可以被认为是最难驾驭的。其思想是创建一个代表您的模型或模型中的一层的 Python 对象,同时使用 TensorFlow 提供的低级功能来实现所需的功能。让我们简要地介绍一下如何使用这些 API。但我们不会止步于此;在接下来的章节中,我们将更详细地了解这些 API。图 3.1 突出显示了 API 之间的主要区别。


图 3.1 顺序式、函数式和子类化 API 的比较。

在这里,对于模型 A,我们将使用顺序式 API,因为它是最简单的。要实现模型 B,其中将有两个输入层,我们将使用函数式 API。最后,要实现模型 C,其中我们需要实现一个自定义层,我们将使用子类化 API。

3.1.1 引入数据集

假设您决定使用一个名为鸢尾花数据集(archive.ics.uci.edu/ml/datasets/Iris)的流行机器学习数据集。这个数据集记录了几种不同种类的鸢尾花(Iris-setosa、Iris-versicolor 和 Iris-virginica)的萼片长度、萼片宽度、花瓣长度和花瓣宽度。对于每朵花,我们都有萼片长度/宽度和花瓣长度/宽度。正如您所看到的,每个输入都有四个特征,每个输入都可以属于三个类别之一。首先,让我们下载数据,对其进行快速分析,并将其格式化为我们可以方便地用于模型训练的格式。

首先,您需要确保环境设置正确,并且已安装所需的库,如附录 A 中所述。接下来,打开位于 Ch03-Keras-and-Data-Retrieval/3.1.Keras_APIs.ipynb 的 Jupyter 笔记本。现在,如笔记本中的代码所示,我们需要导入 requests 库来下载数据,导入 pandas 来操作该数据,当然,还有 TensorFlow:

import requests
import pandas as pd
import tensorflow as tf

现在我们将下载数据并将数据保存到文件中:

url = "https:/ /archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data"
r = requests.get(url)
# Writing data to a file
with open('iris.data', 'wb') as f:
  f.write(r.content)

然后,我们使用 pandas 库的 read_csv() 函数读取数据 (mng.bz/j2Op):

iris_df = pd.read_csv('iris.data', header=None)

这里,iris_df 是一个 pandas DataFrame (mng.bz/Wxaw)。在最简单的形式下,数据帧可以被认为是一个按行和列组织的信息矩阵。您可以使用 iris_df.head() 命令检查数据的前几行,其结果如下:

0     1       2       3       4
0     5.1     3.5     1.4     0.2     Iris-setosa
1     4.9     3.0     1.4     0.2     Iris-setosa
2     4.7     3.2     1.3     0.2     Iris-setosa

然后,我们将对数据进行一些装饰性修改,使其看起来更好。我们将提供适当的列名称(可从数据集的网页中获取)

iris_df.columns = ['sepal_length', 'sepal_width', 'petal_width', 'petal_length', 'label']

并将字符串标签映射为整数:

iris_df["label"] = iris_df["label"].map({'Iris-setosa':0, 'Iris-versicolor':1, 'Iris-virginica':2})

我们得到了以下改进后的 pandas DataFrame:

sepal_length   sepal_width   petal_width   petal_length   label
0     5.1             3.5           1.4           0.2            0
1     4.9             3.0           1.4           0.2            0
2     4.7             3.2           1.3           0.2            0

作为最后一步,我们将通过从每列中减去均值来将数据居中,因为这通常会导致更好的性能:

iris_df = iris_df.sample(frac=1.0, random_state=4321)
x = iris_df[["sepal_length", "sepal_width", "petal_width", "petal_length"]]
x = x - x.mean(axis=0)
y = tf.one_hot(iris_df["label"], depth=3)

在这里,print(x) 将输出

sepal_length  sepal_width  petal_width  petal_length
31      -0.443333        0.346    -2.258667     -0.798667
23      -0.743333        0.246    -2.058667     -0.698667
70       0.056667        0.146     1.041333      0.601333
100      0.456667        0.246     2.241333      1.301333
44      -0.743333        0.746    -1.858667     -0.798667
..            ...          ...          ...           ...

注意 在对数据进行洗牌后,索引不再按顺序排列。print(y) 将输出

tf.Tensor(
    [[1\. 0\. 0.]
     [1\. 0\. 0.]
     [0\. 1\. 0.]
     ...
     [0\. 0\. 1.]
     [0\. 0\. 1.]
     [0\. 1\. 0.]], 
shape=(150, 3), dtype=float32)

对数据进行洗牌是一个重要的步骤:数据是按特定顺序排列的,每个类别都紧跟在另一个后面。但是当数据被洗牌时,每个被呈现给网络的批次都有所有类别的良好混合,这样可以获得最佳结果。您还可以看到我们对 y(或标签)使用了一种称为 独热编码 的转换。独热编码将每个标签转换为唯一的零向量,其中一个元素为一。例如,标签 0、1 和 2 被转换为以下独热编码向量:

0 → [1, 0, 0]

1 → [0, 1, 0]

2 → [0, 0, 1]

3.1.2 顺序 API

数据准备就绪后,是时候实现模型 A 了,这是第一个神经网络。第一个模型非常简单,只需要提供的特征并预测花的种类。您可以使用 Keras 顺序 API,因为它是最简单的,我们所需要做的就是将几个层顺序堆叠在一起。图 3.2 描述了顺序 API 与其他 API 的比较。


图 3.2 顺序 API 与其他 API 的比较(被标记为灰色)

让我们创建一个具有以下特点的网络:

  • 一个具有 4 个节点的输入层
  • 一个具有 32 个节点的隐藏层
  • 一个具有 16 个节点的隐藏层
  • 一个 3 节点输出层

注意 每层节点数是模型的超参数。在这种情况下,我们任意选择了这些值。但为了获得最佳结果,我们应该使用一个超参数优化算法 (mng.bz/8MJB) 来找到给定问题的最佳超参数。

在定义模型之前,我们需要导入 TensorFlow 中的某些层和顺序模型。然后,您可以使用一行代码即可实现该模型(见下一个清单)。

利用 Sequential API 实现的模型 A,如 3.1 清单所示。

from tensorflow.keras.layers import Dense            ❶
from tensorflow.keras.models import Sequential       ❶
import tensorflow.keras.backend as K                 ❶
K.clear_session()                                    ❷
model = Sequential([                                 ❸
    Dense(32, activation='relu', input_shape=(4,)),  ❸
    Dense(16, activation='relu'),                    ❸
    Dense(3, activation='softmax')                   ❸
])

❶导入必要的模块和类。

❷在创建模型之前清除 TensorFlow 计算图。

❸使用 Sequential API 定义模型。

让我们分析一下我们刚刚做的。您可以使用 Sequential 对象创建一个顺序模型,然后传递一个层的序列,例如 Dense 层。一个层封装了神经网络中可以找到的典型的可重复使用的计算(例如隐藏层计算,卷积操作)。

Dense 层提供了全连接网络中所发生的核心计算(即通过 h = activation(xW + b)从输入(x)到隐藏输出(h))。Dense 层有两个重要参数:隐藏单元的数量和非线性激活函数。通过堆叠一组 Dense 层,您可以构建一个多层的全连接网络。我们正在使用以下层构建网络:

  • Dense(32, activation=‘relu’, input_shape=(4,))
  • Dense(16, activation=‘relu’)
  • Dense(3, activation=‘softmax’)

在第一个 Dense 层中,可以看到传递了一个额外的参数 input_shape。input_shape 是使用 TensorFlow 创建的任何模型的关键属性。您必须确切地知道要传递给模型的输入的形状,因为随后的所有层的输出都取决于输入的形状。实际上,某些层只能处理某些特定的输入形状。

在这个例子中,我们说输入的形状将是[None, 4]。虽然我们只在形状中指定了 4,但 Keras 会自动添加一个未指定的(即 None)维度到 input_shape 中,它表示输入的批次维度。正如您可能已经知道的,深度神经网络以批次的方式处理数据(即一次处理多个示例)。另一个尺寸(大小为 4)是特征维度,意味着网络可以接受具有四个特征的输入。将批次维度设为 None 将批次维度未指定,允许您在模型训练/推断时传递任意数量的示例。

一个层的另一个重要方面是层中使用的非线性激活函数。在这里,我们可以看到前两个层使用了 ReLU(修正线性单元)激活函数。它是前馈模型中非常简单但功能强大的激活函数。ReLU 具有以下功能:

y = max (0, x)

最后一层使用了 softmax 激活函数。正如之前讨论的,softmax 激活函数将最后一层(即 logits)的得分归一化为一个有效的概率分布。具体来说,


以一个示例为例,假设最后一层没有使用 softmax 激活函数产生了

[15, 30, 5]

应用 softmax 归一化将这些值转换为

[15/(15+30+5), 30/(15+30+5), 5/(15+30+5)]
= [0.3, 0.6, 0.1]

现在模型已经定义好了,我们需要执行一个关键步骤,称为模型编译,如果我们要成功地使用它的话。对于我们的模型,我们将使用

model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['acc'])

在这里,我们设置了模型的损失函数、优化器和度量标准。损失函数表示模型在给定数据上的表现如何(例如,分类交叉熵)。损失越低,模型就越好。除了损失函数之外,我们还使用了一个优化器,它知道如何改变模型的权重和偏差,以使损失减少。在这里,我们选择了损失函数 categorical_crossentropy(mng.bz/EWej),这通常在多类别分类问题中效果良好,以及优化器 adam(arxiv.org/pdf/1412.6980.pdf),由于其在各种问题中的出色表现,是一个常见的选择。我们还可以选择性地定义度量标准来关注模型(例如,模型准确率)。最后,我们可以使用以下方法检查您刚刚创建的模型

model.summary()

输出

Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense_3 (Dense)              (None, 32)                160       
_________________________________________________________________
dense_4 (Dense)              (None, 16)                528       
_________________________________________________________________
dense_5 (Dense)              (None, 3)                 51        
=================================================================
Total params: 739
Trainable params: 739
Non-trainable params: 0
_________________________________________________________________

模型摘要清晰地显示了层数、每个层的类型、每个层的输出形状以及每个层的参数数量。让我们使用之前准备好的数据集来训练这个模型,以对各种鸢尾花进行分类。我们使用方便的 fit()函数来训练一个 Keras 模型:

model.fit(x, y, batch_size=64, epochs=25)

fit()函数接受许多不同的参数:

  • X—数据特征
  • Y—数据标签(独热编码)
  • 批处理大小(可选)—单个批次中的数据点数量
  • epochs(可选)—模型训练期间重复数据集的次数

像 batch_size 和 epochs 这样的值是经验性地选择的。如果你运行前面的代码,你将得到以下结果:

Train on 150 samples
Epoch 1/25
150/150 [==============================] - 0s 2ms/sample - loss: 1.1773 - acc: 0.2667
Epoch 2/25
150/150 [==============================] - 0s 148us/sample - loss: 1.1388 - acc: 0.2933
...
Epoch 24/25
150/150 [==============================] - 0s 104us/sample - loss: 0.6254 - acc: 0.7400
Epoch 25/25
150/150 [==============================] - 0s 208us/sample - loss: 0.6078 - acc: 0.7400

看起来我们的小型项目相当成功,因为我们观察到训练准确率(“acc”)在只有 25 个 epochs 的情况下稳步增长到了 74%。然而,仅仅依靠训练准确率来决定一个模型是否表现更好是不明智的。有各种技术可以做到这一点,我们将在接下来的章节中进行回顾。

机器学习中的可重现性

可重现性是机器学习中的一个重要概念。可重现性意味着你可以运行一个实验,发布结果,并确保对你的研究感兴趣的人可以复现结果。它还意味着你将在多次试验中得到相同的结果。如果你看一下笔记本 ch02/1.Tensorflow_ Fundamentals.ipynb,你会看到我们已经采取的一项措施,以确保结果在多次试验中保持一致。你将在“Library imports and some setups”部分看到以下代码:

def fix_random_seed(seed):
    try:
        np.random.seed(seed)
    except NameError:
        print("Warning: Numpy is not imported. Setting the seed for Numpy failed.")
    try:
        tf.random.set_seed(seed)
    except NameError:
        print("Warning: TensorFlow is not imported. Setting the seed for TensorFlow failed.")
    try:
        random.seed(seed)
    except NameError:
        print("Warning: random module is not imported. Setting the seed for random failed.")
# Fixing the random seed
fix_random_seed(4321)

随机种子是影响研究可重复性的一个常见因素,因为神经网络普遍使用随机初始化。通过固定种子,你可以确保每次运行代码时都会得到相同的随机数序列。这意味着在多次试验中,模型的权重和偏置初始化是相同的,前提是其他条件没有改变。

为了确保你的代码能够产生一致的结果,请在尝试代码练习时调用 fix_random_seed 函数(通过运行第一个代码单元格)。

TensorFlow 实战(一)(4)https://developer.aliyun.com/article/1522667

相关文章
|
27天前
|
机器学习/深度学习 自然语言处理 TensorFlow
TensorFlow 实战(六)(2)
TensorFlow 实战(六)
24 0
|
13天前
|
机器学习/深度学习 TensorFlow API
TensorFlow与Keras实战:构建深度学习模型
本文探讨了TensorFlow和其高级API Keras在深度学习中的应用。TensorFlow是Google开发的高性能开源框架,支持分布式计算,而Keras以其用户友好和模块化设计简化了神经网络构建。通过一个手写数字识别的实战案例,展示了如何使用Keras加载MNIST数据集、构建CNN模型、训练及评估模型,并进行预测。案例详述了数据预处理、模型构建、训练过程和预测新图像的步骤,为读者提供TensorFlow和Keras的基础实践指导。
146 59
|
27天前
|
机器学习/深度学习 自然语言处理 TensorFlow
TensorFlow 实战(五)(5)
TensorFlow 实战(五)
19 1
|
27天前
|
自然语言处理 算法 TensorFlow
TensorFlow 实战(六)(3)
TensorFlow 实战(六)
21 0
|
27天前
|
机器学习/深度学习 数据可视化 TensorFlow
TensorFlow 实战(六)(1)
TensorFlow 实战(六)
25 0
|
27天前
|
存储 自然语言处理 TensorFlow
TensorFlow 实战(五)(4)
TensorFlow 实战(五)
21 0
|
27天前
|
数据可视化 TensorFlow 算法框架/工具
TensorFlow 实战(八)(4)
TensorFlow 实战(八)
25 1
|
27天前
|
TensorFlow API 算法框架/工具
TensorFlow 实战(八)(3)
TensorFlow 实战(八)
25 1
|
27天前
|
机器学习/深度学习 自然语言处理 TensorFlow
TensorFlow 实战(八)(5)
TensorFlow 实战(八)
25 0
|
27天前
|
并行计算 TensorFlow 算法框架/工具
TensorFlow 实战(八)(2)
TensorFlow 实战(八)
21 0