tf-ws-merge-0

25 阅读1小时+

TensorFlow 研讨会(一)

原文:annas-archive.org/md5/92a4018e7ab653973d73d2eb5915e580

译者:飞龙

协议:CC BY-NC-SA 4.0

前言

关于本书

如果你希望学习如何在 TensorFlow 中构建深度学习模型以解决实际问题,那么这本书非常适合你。

本书从介绍 TensorFlow 开始,带领你了解张量的基本数学运算,以及数据预处理方法,用以构建模型并通过 TensorFlow 资源节省开发时间。你将构建回归和分类模型,使用正则化防止模型对训练数据过拟合,并创建卷积神经网络以解决图像数据集上的分类任务。最后,你将学习实现预训练、递归和生成模型,并创建自己定制的 TensorFlow 组件,在模型中使用。

在阅读完本书后,你将具备使用 TensorFlow 框架构建、训练和评估深度学习模型的实际技能。

关于作者

Matthew Moocarme 是一位经验丰富的数据科学家,拥有超过八年的创建和使用机器学习模型的经验。他有物理科学背景,持有 CUNY 研究生中心的物理学博士学位。目前,他带领一个数据科学家和工程师团队,在媒体和广告领域构建和整合机器学习模型,应用于各种场景。在闲暇时,Matthew 通过发布作品、参加会议演讲和举办工作坊与数据科学社区分享自己的知识。

Anthony So 是数据科学领域的知名领袖。他在利用高级分析和人工智能解决不同行业复杂商业问题方面拥有丰富经验,涉及金融服务、媒体和电信等行业。他目前是一个最具创新力的金融科技初创公司首席数据官。他也是多本畅销书的作者,涵盖数据科学、机器学习和深度学习等领域。他曾在多个黑客松比赛中获奖,如 Unearthed、GovHack 和 Pepper Money 等。Anthony 拥有两个硕士学位,一个是计算机科学,另一个是数据科学与创新。

Anthony Maddalone 是 TieSet 的研究工程师,TieSet 是位于硅谷的分布式人工智能和联邦学习领域的领导者。他曾是一个成功初创公司的创始人兼 CEO。Anthony 和妻子及两个孩子一起生活在科罗拉多州,享受户外活动的时光。他还是乔治亚理工学院工业工程方向的分析学硕士候选人。

本书适合人群

本书适合任何希望加深对深度学习理解,并开始使用 TensorFlow 构建神经网络的人。如果你具备 Python 编程及其库的基本知识,以及对数据科学和机器学习基础的通用理解,将帮助你更轻松地掌握本书所涉及的内容。

关于章节

第一章TensorFlow 机器学习简介,介绍了支撑 TensorFlow 和机器学习模型开发的数学概念,包括张量和线性代数。

第二章加载和处理数据,教你如何加载和处理各种数据类型,包括表格数据、图像、音频和文本,以便将它们输入到机器学习模型中。

第三章TensorFlow 开发,介绍了 TensorFlow 提供的各种开发工具,帮助你构建模型,包括 TensorBoard、TensorFlow Hub 和 Google Colab。这些工具可以加快开发速度,并帮助你理解模型的架构和性能。

第四章回归与分类模型,引导你通过使用 TensorFlow 构建回归和分类任务的模型。你将学习如何构建简单的模型、使用哪些层以及为每个任务选择合适的损失函数。

第五章分类模型,展示了如何使用 TensorFlow 构建分类模型。你将学习如何定制神经网络的架构,以适应二分类、多类分类或多标签分类。

第六章正则化与超参数调优,讨论了帮助防止模型过拟合的不同方法,例如正则化、丢弃法(dropout)或提前停止(early stopping)。你还将学习如何进行自动超参数调优。

第七章卷积神经网络,展示了如何构建包含卷积层的神经网络。这些网络因其在处理图像时的优良表现而广受欢迎,因为它们包含卷积层。

第八章预训练网络,教你如何利用预训练模型来实现更好的性能,而无需从头开始训练模型。

第九章递归神经网络,介绍了另一种类型的深度学习架构——递归神经网络,这种架构最适合处理时序数据,例如时间序列或文本。

第十章自定义 TensorFlow 组件,通过教你如何构建自己的自定义 TensorFlow 组件,如损失函数和神经网络层,扩展你的技能。

第十一章生成模型,展示了如何通过训练模型在数据集上发现潜在的模式和表示,从而生成新的和创新的数据。训练好的模型将能够生成完全新的、令人信服的真实例子。

规范

文本中的代码词、数据库表名、文件夹名称、文件名、文件扩展名、路径名、虚拟 URL 和用户输入按如下方式显示:

"TensorFlow 可以通过导入特定的库在 Python 中使用。你可以使用 import 语句在 Python 中导入库。"

屏幕上看到的单词,例如在菜单或对话框中显示的,也会以相同的格式呈现。

代码块的设置如下:

int_variable = tf.Variable(4113, tf.int16)
int_variable

新的重点词汇如下所示:“反向传播是确定损失函数对模型参数的导数的过程。”

代码片段中的关键部分被加粗如下:

df = pd.read_csv('Bias_correction_ucl.csv')

代码展示

跨越多行的代码通过反斜杠 (\) 来分隔。当代码执行时,Python 会忽略反斜杠,并将下一行的代码视为当前行的直接延续。

例如,

year_dummies = pd.get_dummies(df['Date'].dt.year, \
                              prefix='year')
year_dummies

代码中添加了注释,以帮助解释特定的逻辑部分。单行注释使用 # 符号表示,如下所示:

# Importing the matplotlib library
import matplotlib.pyplot as plt

最低硬件要求

为了获得最佳体验,我们推荐以下硬件配置:

  • 处理器:双核或更高

  • 内存:4 GB RAM

  • 存储:10 GB 可用空间

下载代码包

从 GitHub 下载代码文件,地址为 packt.link/Z7pcq。请参考这些代码文件以获取完整的代码包。这里的文件包含每一章的练习、活动以及一些中间代码。当您遇到困难时,这些文件可以作为有用的参考。

在 GitHub 仓库页面,您可以点击绿色的 Code 按钮,然后点击 Download ZIP 选项,将完整代码作为 ZIP 文件下载到您的磁盘(参见 图 0.1)。然后,您可以将这些代码文件解压到您选择的文件夹中,例如 C:\Code

图 0.1:下载 ZIP 选项

图 0.1:下载 ZIP 选项

在您的系统上,解压后的 ZIP 文件应该包含 GitHub 仓库中的所有文件:

图 0.2:GitHub 代码目录结构

图 0.2:GitHub 代码目录结构

设置您的环境

在详细探索本书之前,您需要设置特定的软件和工具。在接下来的部分,您将看到如何进行设置。

在您的系统上安装 Anaconda

本书中所有练习和活动的代码都可以通过 Jupyter Notebook 执行。您需要先安装 Anaconda Navigator,它是一个可以访问 Jupyter 笔记本的界面。Anaconda Navigator 会作为 Anaconda Individual Edition 的一部分安装,Anaconda 是一个适用于 Windows、macOS 和 Linux 的开源 Python 分发平台。安装 Anaconda 时也会安装 Python。请前往 www.anaconda.com/distribution/

  1. 在打开的页面中,点击 Download 按钮(由 1 标注)。确保下载的是 Individual Edition图 0.3:Anaconda 主页

    图 0.3:Anaconda 主页

  2. 安装程序应立即开始下载。网站会默认根据您的系统配置选择合适的安装程序。如果您更喜欢为其他操作系统(Windows、macOS 或 Linux)以及系统配置(32 位或 64 位)下载 Anaconda,可以点击框底部的获取附加安装程序链接(参考图 0.3)。页面应该会滚动到一个部分(参考图 0.4),允许您根据所需的操作系统和配置选择不同的选项。本书建议您使用最新版本的 Python(3.8 或更高版本)。图 0.4: 根据操作系统下载 Anaconda

    图 0.4: 根据操作系统下载 Anaconda

  3. 请按照屏幕上显示的安装步骤进行操作。图 0.5: Anaconda 设置

    图 0.5: Anaconda 设置

  4. 在 Windows 系统中,如果您之前从未在系统中安装过 Python,可以勾选提示将 Anaconda 添加到您的PATH的复选框。这样,您就可以在默认命令提示符中运行 Anaconda 特有的命令(如conda)。如果您已经安装了 Python,或者之前安装过 Anaconda 的旧版本,建议您不要勾选此选项(您可以通过 Anaconda Prompt 应用来运行 Anaconda 命令)。根据您的系统配置,安装可能需要一些时间。图 0.6: Anaconda 安装步骤

    图 0.6: Anaconda 安装步骤

    若要获取更详细的安装说明,您可以点击以下链接查阅官方文档:Linux 版请点击此链接(docs.anaconda.com/anaconda/install/linux/);macOS 版请点击此链接(docs.anaconda.com/anaconda/install/mac-os/);Windows 版请点击此链接(docs.anaconda.com/anaconda/install/windows/)。

  5. 要检查 Anaconda Navigator 是否正确安装,请在您的应用程序中查找Anaconda Navigator。查找一个具有以下图标的应用程序。根据您的操作系统,图标的外观可能会有所不同。图 0.7: Anaconda Navigator 图标

    图 0.7: Anaconda Navigator 图标

    您还可以使用操作系统的搜索功能来搜索该应用程序。例如,在 Windows 10 上,您可以使用Windows 键 + S组合键,然后输入Anaconda Navigator。在 macOS 上,您可以使用 Spotlight 搜索。在 Linux 上,您可以打开终端,输入anaconda-navigator命令并按Return键。

    图 0.8: 在 Windows 10 上搜索 Anaconda Navigator

    图 0.8: 在 Windows 10 上搜索 Anaconda Navigator

    有关如何验证是否已安装 Anaconda Navigator 的详细步骤,请参考以下链接:docs.anaconda.com/anaconda/install/verify-install/

  6. 点击图标打开 Anaconda Navigator。首次加载可能需要一些时间,但安装成功后,你应该看到类似的界面:图 0.9:Anaconda Navigator 界面

图 0.9:Anaconda Navigator 界面

如果你对安装过程有更多问题,可以参考 Anaconda 文档中的常见问题列表:docs.anaconda.com/anaconda/user-guide/faq/

启动 Jupyter Notebook

打开 Anaconda Navigator 后,你可以从这个界面启动 Jupyter Notebook。以下步骤将指导你如何操作:

  1. 打开 Anaconda Navigator,你应该能看到以下界面:图 0.10:Anaconda Navigator 界面

    图 0.10:Anaconda Navigator 界面

  2. 现在,点击 LaunchJupyter Notebook 面板下启动本地系统上的 Jupyter Notebook 界面:图 0.11:Jupyter Notebook 启动选项

    图 0.11:Jupyter Notebook 启动选项

  3. 点击 Launch 按钮后,你会注意到,尽管前面截图显示的窗口没有变化,但在默认浏览器中会打开一个新标签页。这就是所谓的Notebook Dashboard。它会默认打开到你的根目录。对于 Windows 用户,这个路径类似于 C:\Users\<用户名>。在 macOS 和 Linux 上,它会是 /home/<用户名>/图 0.12:Notebook Dashboard

    图 0.12:Notebook Dashboard

    请注意,你也可以通过在终端或命令提示符中运行 jupyter notebook 命令来直接打开 Jupyter Notebook,或者像在图 0.8中那样,在应用程序中搜索 Jupyter Notebook

  4. 你可以使用这个仪表板作为文件浏览器,导航到你下载或存储书中代码文件的目录(关于如何从 GitHub 下载文件,请参考下载代码包章节)。一旦你导航到目标目录,就可以开始创建新的笔记本。或者,如果你已经从我们的代码库下载了代码,也可以打开现有的笔记本(笔记本文件扩展名为 .inpyb)。这里的菜单非常简便易用:图 0.13:Jupyter Notebook 导航菜单选项介绍

    图 0.13:Jupyter Notebook 导航菜单选项介绍

    如果你通过操作系统的文件资源管理器更改了目录,但在 Jupyter Notebook 导航器中没有显示更改后的文件,可以点击刷新笔记本列表按钮(标注为1)。要退出,点击退出按钮(标注为2)。要创建一个新文件(一个新的 Jupyter 笔记本),你可以点击新建按钮(标注为3)。

  5. 点击New按钮将会弹出如下的下拉菜单:图 0.14:创建一个新的 Jupyter 笔记本

图 0.14:创建一个新的 Jupyter 笔记本

你可以通过选择Python 3来开始并创建你的第一个笔记本;然而,建议你同时安装我们提供的虚拟环境,这样可以帮助你安装本书所需的所有软件包。接下来的章节将教你如何安装它。

注意

你可以在这里找到关于 Jupyter 笔记本界面和快捷键的详细教程:jupyter-notebook.readthedocs.io/en/stable/notebook.html#the-jupyter-notebook

安装 tensorflow 虚拟环境

当你运行习题和活动的代码时,你会发现即使安装了 Anaconda,仍然有一些库需要在书中的不同阶段单独安装。也许你已经安装了这些库,但它们的版本可能与我们使用的版本不同,这可能会导致不同的结果。正因如此,我们在本书中提供了一个environment.yml文件,它将:

  1. 一次性安装本书所需的所有软件包和库。

  2. 确保你的库版本与我们为本书编写代码时使用的版本匹配。

  3. 确保你根据本课程编写的代码与任何其他编程环境分开。

你可以通过点击以下链接下载environment.yml文件:packt.link/Z7pcq

保存此文件,最好将其保存在你运行本书代码的同一文件夹中。如果你已经按照《下载代码包》章节的说明从 GitHub 下载了代码,那么该文件应该已经存在于父目录中,你无需单独下载它。

要设置环境,请按照以下步骤操作:

  1. 在 macOS 上,从 Launchpad 打开终端(你可以在此处找到关于终端的更多信息:support.apple.com/en-in/guide/terminal/apd5265185d-f365-44cb-8b09-71a064a42125/mac)。在 Linux 上,打开你所在发行版的终端应用程序。在 Windows 上,你可以直接搜索应用程序并打开 Anaconda Prompt。你可以通过打开开始菜单并搜索Anaconda Prompt来做到这一点。图 0.15:在 Windows 上搜索 Anaconda Prompt

    图 0.15:在 Windows 中搜索 Anaconda Prompt

    应该会打开一个新的终端,默认情况下,它将在你的主目录中启动:

    图 0.16:Anaconda 终端提示符

    ](tos-cn-i-73owjymdk6/26338fbf525542089a7a8ee2dc8684b9)

    图 0.16:Anaconda 终端提示符

    在 Linux 系统中,它将显示如下:

    图 0.17:Linux 中的终端

    ](tos-cn-i-73owjymdk6/6393826ffea64eee94a020fc71fc1ccf)

    图 0.17:Linux 中的终端

  2. 在终端中,使用cd命令导航到保存environment.yml文件的目录。例如,如果你把文件保存在Documents\The-TensorFlow-Workshop中,那么在命令提示符下输入以下命令并按Enter键:

    cd Documents\The-TensorFlow-Workshop
    

    请注意,命令可能会根据你的目录结构和操作系统有所不同。

  3. 现在你已导航到正确的文件夹,在终端中键入或粘贴以下命令来创建新的conda环境。按Enter键运行该命令:

    conda env create -f environment.yml
    

    这将安装tensorflow虚拟环境及运行本书代码所需的库。如果安装过程中有提示要求你确认,输入y并按Enter键继续创建环境。根据你的系统配置,过程可能需要一些时间才能完成。

    注意

    若要查看完整的conda命令列表,请访问以下链接:conda.io/projects/conda/en/latest/index.html

    若要查看有关如何管理conda环境的详细指南,请访问以下链接:conda.io/projects/conda/en/latest/user-guide/tasks/manage-environments.html

  4. 完成后,在终端中键入或粘贴以下命令来激活新安装的环境——tensorflow

    conda activate tensorflow
    

    如果安装成功,你将看到环境名称的括号内由base更改为tensorflow

    图 0.18:环境名称出现在终端

    ](github.com/OpenDocCN/f…)

    图 0.18:环境名称出现在终端

  5. 在新激活的conda环境中运行以下命令来安装ipykernel

    pip3 instead of pip. 
    
  6. 在同一环境中,运行以下命令以将ipykernel添加为 Jupyter 内核:

    python -m ipykernel install --user --name=tensorflow
    
  7. **仅限 Windows:**如果你使用的是 Windows 系统,请键入或粘贴以下命令。否则,你可以跳过此步骤并退出终端:

    conda install pywin32
    
  8. 启动 Jupyter 笔记本时,选择创建的tensorflow内核。图 0.19:选择 tensorflow 内核

    ](tos-cn-i-73owjymdk6/0eb1d507d00a43f694104fe90326c027)

图 0.19:选择 tensorflow 内核

一个新标签页将会打开,里面是一个新的、未命名的 Jupyter 笔记本,你可以开始编写代码:

图 0.20:新的 Jupyter 笔记本

](tos-cn-i-73owjymdk6/55b5375b2f77499d8a16cb0b9c480870)

图 0.20:新的 Jupyter 笔记本

联系我们

我们欢迎读者的反馈。

customercare@packtpub.com

勘误:尽管我们已尽一切努力确保内容的准确性,但错误难免会发生。如果你在本书中发现错误,我们将不胜感激,感谢你能向我们报告。请访问 www.packtpub.com/support/err… 并填写表格。

copyright@packt.com 并附上材料的链接。

如果你有兴趣成为一名作者:如果你在某个领域拥有专业知识,并且有兴趣写作或为书籍做贡献,请访问 authors.packtpub.com

请留下评论

通过在亚马逊上留下详细、公正的评论,让我们知道你的想法。我们感谢所有的反馈——这帮助我们继续制作优秀的产品,并帮助有志的开发者提升技能。请花几分钟时间给出你的想法——这对我们意义重大。你可以通过点击以下链接留下评论:packt.link/r/1800205252

第一章:1. 使用 TensorFlow 进行机器学习介绍

概述

在本章中,你将学习如何创建、利用和应用线性变换到 TensorFlow 编程的基本构建块——张量。然后,你将利用张量来理解与神经网络相关的复杂概念,包括张量重塑、转置和乘法。

介绍

机器学习ML)已经渗透到许多人未曾察觉的日常生活的各个方面。从日常社交媒体推荐到在线搜索结果,它们都由机器学习算法驱动。这些算法最初在研究环境中解决特定问题,但随着其可访问性不断扩展,它们的应用场景也变得越来越广泛。各类研究人员和企业都认识到,使用模型来优化各自运营的每个环节具有重要价值。医生可以使用机器学习来决定诊断和治疗方案,零售商可以利用 ML 在合适的时间将合适的产品送到店铺,而娱乐公司可以使用 ML 向客户提供个性化的推荐。

在数据时代,机器学习模型已被证明是任何数据驱动型公司的宝贵资产。海量数据使得可以创建强大且准确的模型来完成各种任务,从回归到分类,从推荐到时间序列分析,甚至是生成艺术,这些内容将在本次研讨会中介绍。所有这些任务都可以通过 TensorFlow 构建、训练和部署。

TensorFlow API 拥有大量功能,使其在所有构建机器学习模型或处理张量(多维数值数组)的机器学习从业者中广受欢迎。对于研究人员来说,TensorFlow 是创建新机器学习应用的合适选择,因为它提供了高度的定制和灵活性。对于开发者而言,TensorFlow 是一个优秀的机器学习库选择,因为它在模型从开发到生产环境的部署方面非常方便。综合来看,TensorFlow 的灵活性和易于部署使得它成为许多从业者的智能选择,他们希望使用各种数据源构建高效的机器学习模型,并在生产环境中复制这些学习成果。

本章提供了 TensorFlow API 的实用介绍。你将学习如何执行与机器学习相关的数学操作,这些操作将为你使用 TensorFlow 构建高效 ML 模型奠定坚实的基础。你将首先学习基本操作,例如如何使用 API 创建变量。接下来,你将学习如何执行线性变换,如加法,然后再深入到更高级的任务,包括张量乘法。

在 TensorFlow 中实现人工神经网络

TensorFlow 提供的高级灵活性非常适合构建人工神经网络ANNs)。ANNs 是受到大脑神经元连接启发的算法,旨在复制人类学习的过程。它们由多个层组成,信息通过这些层从输入传播到输出。

图 1.1 展示了一个人工神经网络(ANN)的可视化表示。输入层位于左侧,在这个示例中,输入层有两个特征(X1 和 X2)。输入层与第一个隐藏层连接,后者有三个单元。来自前一层的所有数据会传递给第一个隐藏层的每个单元。然后,数据被传递到第二个隐藏层,第二个隐藏层同样有三个单元。再次地,来自上一层每个单元的信息会传递给第二个隐藏层的每个单元。最后,所有来自第二个隐藏层的信息都会传递到输出层,输出层有一个单元,表示每组输入特征的单个数字。

图 1.1:一个具有两个隐藏层的人工神经网络(ANN)的可视化表示

图 1.1:一个具有两个隐藏层的人工神经网络(ANN)的可视化表示

ANNs 已被证明能够成功学习具有复杂和非线性关系的大规模非结构化数据集,如音频、图像和文本数据。尽管结果可能令人印象深刻,但 ANNs 的配置存在很大的可变性。例如,层数、每层的大小以及应该使用哪种非线性函数是决定 ANNs 配置的一些因素。TensorFlow 提供的类和函数不仅非常适合构建和训练 ANNs,此外,该库还提供了一套工具,帮助在训练过程中可视化和调试 ANNs。

与传统的机器学习算法(如线性回归和逻辑回归)相比,人工神经网络(ANNs)在数据量较大的情况下能够超越这些算法。ANNs 的优势在于它们能够处理非结构化数据,并且不一定需要特征工程。数据预处理可能是一个耗时的过程。因此,如果数据量较大,许多实践者更倾向于选择 ANNs。

来自各行各业的许多公司都利用 TensorFlow 构建人工神经网络(ANN)用于他们的应用。由于 TensorFlow 得到了 Google 的支持,该公司将该库应用于大部分机器学习应用的研究、开发和生产。然而,许多其他公司也使用该库。像 Airbnb、可口可乐、Uber 和 GE Healthcare 等公司,都在进行各种任务时使用该库。人工神经网络的使用尤其具有吸引力,因为只要提供足够的数据并进行适当训练,它们就能实现显著的准确性。例如,GE Healthcare 使用 TensorFlow 构建 ANN,从磁共振图像中识别特定的解剖结构,不论其朝向如何,以提高速度和准确性。通过使用 ANN,他们能够在几秒钟内识别出解剖结构,准确率超过 99%,无论头部如何旋转,而这在没有 ANN 的情况下需要经过训练的专业人员花费更多时间才能完成。

尽管许多公司都在使用人工神经网络,但 ANN 可能不是解决所有业务问题的最佳选择。在这种环境下,你需要回答以下问题,以确定 ANN 是否是最合适的选择:

  • 问题是否有数值解决方案? 包括人工神经网络(ANN)在内的机器学习算法,基于输入数据生成预测的数值结果。例如,机器学习算法可能会预测一个给定的数字,如根据城市的位置和先前的天气条件预测温度,或者根据先前的股票价格预测股价,或者将图像分类为某个给定的类别。在这些例子中,基于提供的数据生成数值输出,并且只要有足够的标注数据,模型就能表现得很好。然而,当期望的结果更为抽象,或需要创意时,比如创作一首新歌,那么机器学习算法可能不是最合适的选择,因为可能没有明确的数值解决方案可供参考。

  • 是否有足够的合适标注数据来训练模型? 对于监督学习任务,你必须至少拥有一些标注数据来训练模型。例如,如果你想构建一个模型来预测某个公司的金融股票数据,你首先需要历史训练数据。如果该公司尚未上市很长时间,可能就没有足够的训练数据。人工神经网络通常需要大量的数据。当处理图像时,ANN 通常需要数百万个训练样本来开发出准确且稳健的模型。这可能是决定哪个算法适合给定任务的一个关键因素。

既然你已经了解了什么是 TensorFlow,那么请考虑以下 TensorFlow 的优缺点。

TensorFlow 的优点

以下是许多从业者在决定是否使用 TensorFlow 进行机器学习时所考虑的几个主要优点:

  • 库管理:TensorFlow 库有一个庞大的开发者社区,他们不断更新库,发布新版本以修复 bug,增加新的函数和类,以反映当前领域的进展,并支持多种编程语言。

  • 流水线:TensorFlow 支持端到端的模型生产,从在支持 GPU 处理的高并行环境中开发模型,到一整套模型部署工具。此外,TensorFlow 还有轻量级的库,用于将训练好的 TensorFlow 模型部署到移动设备和嵌入式设备上,例如物联网IoT)设备。

  • 社区支持:使用并支持该库的开发者社区庞大,他们互相支持,正因如此,初学者能轻松地获得他们想要的结果。

  • 开源:TensorFlow 是一个开源库,其代码库对任何人开放,允许用户根据自己的需求使用和修改。

  • 支持多种语言:虽然该库本身是为 Python 设计的,但现在也可以在 JavaScript 中训练和部署模型。

TensorFlow 的缺点

以下是使用 TensorFlow 的一些缺点:

  • 计算速度:由于 TensorFlow 的主要编程语言是 Python,因此它的计算速度不如其他语言(如 C++)的原生实现。

  • 陡峭的学习曲线:与其他机器学习库(如 Keras)相比,TensorFlow 的学习曲线较为陡峭,这可能会使得新手在没有现成示例代码的情况下,创建自己的模型变得具有挑战性。

现在你已经了解了 TensorFlow 是什么,接下来的部分将演示如何使用 Python 来操作 TensorFlow 库。

Python 中的 TensorFlow 库

你可以通过导入特定的库在 Python 中使用 TensorFlow。你可以使用import语句在 Python 中导入库:

import tensorflow as tf

在之前的命令中,你已导入了 TensorFlow 库并使用了简写tf

在接下来的练习中,你将学习如何导入 TensorFlow 库并检查其版本,以便你能够利用库提供的类和函数,这是使用该库时非常重要和必要的第一步。

练习 1.01:验证你的 TensorFlow 版本

在这个练习中,你将加载 TensorFlow 并检查系统中安装的版本。

执行以下步骤:

  1. 打开一个 Jupyter 笔记本来实现这个练习,在终端中输入jupyter notebook

  2. 通过在 Jupyter 单元格中输入以下代码来导入 TensorFlow 库:

    import tensorflow as tf
    
  3. 使用以下命令验证 TensorFlow 的版本:

    tf.__version__
    

    这将产生以下输出:

    '2.6.0'
    

    从之前的输出中可以看到,TensorFlow 的版本是2.6.0

    注意

    如果你没有按照前言中的步骤设置环境,版本可能会在你的系统上有所不同。

在这个练习中,你成功导入了 TensorFlow。你还检查了系统上安装的 TensorFlow 版本。

这个任务可以在 Python 中对任何导入的库执行,并且对于调试和参考文档非常有用。

使用 TensorFlow 的潜在应用非常广泛,它已经取得了令人印象深刻的成果,像 Airbnb 这样的公司利用 TensorFlow 对平台上的图像进行分类,GE Healthcare 则使用 TensorFlow 在大脑的 MRI 图像中识别解剖结构。要学习如何为自己的应用创建强大的模型,你首先需要学习构成 TensorFlow 中可实现的机器学习模型的基本数学原理和运算。数学运算可能会让新用户感到畏惧,但对它们的全面理解是构建高效模型的关键。

张量简介

张量可以被看作是人工神经网络(ANNs)的核心组件——输入数据、输出预测以及在训练过程中学习到的权重都是张量。信息通过一系列线性和非线性变换传播,将输入数据转化为预测结果。本节展示了如何对张量应用线性变换,如加法、转置和乘法。其他线性变换,如旋转、反射和剪切,也存在。然而,它们在人工神经网络中的应用较为少见。

标量、向量、矩阵和张量

张量可以表示为多维数组。张量所跨越的维度数量称为张量的阶数。阶数为012的张量常常使用,并且各自有独立的名称,分别是标量向量矩阵,尽管术语张量可以用来描述它们中的任何一个。图 1.2展示了不同阶张量的一些示例。从左到右分别是标量、向量、矩阵和一个三维张量,每个元素表示一个不同的数字,下标表示该元素在张量中的位置:

图 1.2:标量、向量、矩阵和张量的可视化表示

图 1.2:标量、向量、矩阵和张量的可视化表示

标量、向量、矩阵和张量的正式定义如下:

  • 标量:标量由一个单一的数字组成,因此它是一个零维数组,是零阶张量的例子。标量没有任何轴。例如,物体的宽度就是一个标量。

  • 向量:向量是一维数组,是一阶张量的例子。它们可以被看作是值的列表。向量有一个轴。给定物体的宽度、高度和深度的大小是一个向量场的例子。

  • 矩阵:矩阵是具有两个轴的二维数组,是二阶张量的一个例子。矩阵可能用于存储多个对象的大小。矩阵的每个维度包含每个对象的大小(宽度、高度、深度),另一个矩阵维度则用于区分对象。

  • 3或更多。张量可以用来存储多个对象的大小及其随时间变化的位置。矩阵的第一维包含每个对象的大小(宽度、高度、深度),第二维用于区分不同的对象,第三维描述这些对象随时间变化的位置。

张量可以使用 TensorFlow 库中的Variable类来创建,并传入一个表示张量的值。标量可以传入浮动值或整数,向量可以传入浮动值或整数的列表,矩阵可以传入浮动值或整数的嵌套列表,依此类推。以下命令演示了如何使用Variable类,其中传入了张量的预期值列表以及任何需要显式定义的其他属性:

tensor1 = tf.Variable([1,2,3], dtype=tf.int32, \
                      name='my_tensor', trainable=True)

结果Variable对象具有几个常用的属性,具体如下:

  • dtypeVariable对象的数据类型(对于上面定义的张量,数据类型是tf.int32)。该属性的默认值由传入的值决定。

  • shapeVariable对象的维度数和每个维度的长度(对于上面定义的张量,形状是[3])。该属性的默认值也由传入的值决定。

  • nameVariable对象的名称(对于上面定义的张量,张量的名称定义为'my_tensor')。该属性的默认值为Variable

  • trainable:该属性指示Variable对象是否可以在模型训练过程中更新(对于上面定义的张量,trainable参数设置为true)。该属性的默认值是true

    注意

    你可以在这里阅读更多关于Variable对象属性的内容:www.tensorflow.org/api_docs/python/tf/Variable

Variable对象的shape属性可以按如下方式调用:

tensor1.shape

shape属性给出了张量的形状,即它是标量、向量、矩阵等。前面命令的输出将是[3],因为该张量只有一个维度,且该维度上有三个值。

可以使用 TensorFlow 中的rank函数来确定张量的阶数。通过将张量作为唯一的参数传递给该函数,结果将是一个整数值:

tf.rank(tensor1)

以下命令的输出将是一个零维整数张量,表示输入张量的阶数。在此情况下,tensor1的阶数为1,因为该张量只有一个维度。

在以下练习中,您将学习如何使用 TensorFlow 的 Variable 类创建各种秩的张量。

练习 1.02:在 TensorFlow 中创建标量、向量、矩阵和张量

三个不同政党在 A 和 B 两个选区的不同候选人所获得的选票如下:

图 1.3:三种不同政治派别候选人的选票(不同政治派别和不同选区的选票分布)

在 A 和 B 两个选区的各个政党的候选人选票分布](tos-cn-i-73owjymdk6/b2d32b4dc56546169a5068a571d356ef)

图 1.3:三种不同政党在 A、B 两个选区的不同候选人获得的选票数

您需要执行以下操作:

  • 创建一个标量来存储选区 A 中 X 政党 候选人 1 的选票数,即 4113,并检查其形状和秩。

  • 创建一个向量来表示 X 政党在 A 选区中三名候选人所获得选票的比例,并检查其形状和秩。

  • 创建一个矩阵来表示 XY 政党在三个不同候选人中的选票,并检查其形状和秩。

  • 创建一个张量来表示三名候选人在两个不同选区、三种不同政党中的选票,并检查其形状和秩。

执行以下步骤以完成本练习:

  1. 导入 TensorFlow 库:

    import tensorflow as tf
    
  2. 使用 TensorFlow 的 Variable 类创建一个整数变量,并传入 4113 来表示某个候选人获得的选票数。同时,传入 tf.int16 作为第二个参数,以确保输入的数字是整数数据类型。打印结果:

    int_variable = tf.Variable(4113, tf.int16)
    int_variable
    

    这将产生以下输出:

    <tf.Variable 'Variable:0' shape=() dtype=int32, numpy=4113>
    

    在这里,您可以看到所创建变量的属性,包括名称 Variable:0、形状、数据类型以及张量的 NumPy 表示。

  3. 使用 TensorFlow 的 rank 函数打印创建的变量的秩:

    tf.rank(int_variable)
    

    这将产生以下输出:

    <tf.Tensor: shape=(), dtype=int32, numpy=0>
    

    从 NumPy 对张量的表示中可以看到,创建的整数变量的秩是 0

  4. 通过调用 numpy 属性访问秩的整数变量:

    tf.rank(int_variable).numpy()
    

    这将产生以下输出:

    0
    

    标量的秩是 0

    注意

    rank 函数的所有属性都可以被调用,包括 shapedtype 属性。

  5. 调用整数的 shape 属性以查看张量的形状:

    int_variable.shape
    

    这将产生以下输出:

    TensorShape([])
    

    上面的输出表明张量的形状没有大小,代表它是一个标量。

  6. 打印标量变量的 shape,以 Python 列表的形式表示:

    int_variable.shape.as_list()
    

    这将产生以下输出:

    []
    
  7. 使用 TensorFlow 的 Variable 类创建一个 vector 变量。传入一个列表来表示三名候选人所获得选票的比例,并传入第二个参数 tf.float32 以确保它是一个 float 数据类型。打印结果:

    vector_variable = tf.Variable([0.23, 0.42, 0.35], \
                                  tf.float32)
    vector_variable
    

    这将产生以下输出:

    <tf.Variable 'Variable:0' shape(3,) dtype=float32, 
    numpy=array([0.23, 0.42, 0.35], dtype=float32)>
    

    您可以看到,形状和 NumPy 属性与之前创建的标量变量不同。现在的形状是 (3,),表示张量是一个一维的,沿该维度有三个元素。

  8. 使用 TensorFlow 的 rank 函数打印 vector 变量的秩,作为 NumPy 变量:

    tf.rank(vector_variable).numpy()
    

    这将产生以下输出:

    1
    

    在这里,您可以看到,向量变量的秩为 1,确认该变量是一维的。

  9. 打印 vector 变量的形状作为 Python 列表:

    vector_variable.shape.as_list()
    

    这将产生以下输出:

    [3]
    
  10. 使用 TensorFlow 的 Variable 类创建一个矩阵变量。传入一个整数的列表列表,表示在两个不同选区中,三个不同候选人的投票结果。该矩阵将有三列,表示候选人,和两行,表示选区。传入第二个参数,数据类型为 tf.int32,以确保其为整数数据类型。打印结果:

    matrix_variable = tf.Variable([[4113, 7511, 6259], \
                                   [3870, 6725, 6962]], \
                                  tf.int32)
    matrix_variable
    

    这将产生以下输出:

    图 1.4:TensorFlow 变量的输出

    图 1.4:TensorFlow 变量的输出

  11. 打印矩阵变量的秩作为 NumPy 变量:

    tf.rank(matrix_variable).numpy()
    

    这将产生以下输出:

    2
    

    在这里,您可以看到矩阵变量的秩为2,确认该变量是二维的。

  12. 打印矩阵变量的形状作为 Python 列表:

    matrix_variable.shape.as_list()
    

    这将产生以下输出:

    [2, 3]
    
  13. 使用 TensorFlow 的 Variable 类创建一个张量变量。传入一个三重嵌套的整数列表,表示三个不同候选人在两个不同选区、三个政党中的投票结果。打印结果:

    tensor_variable = tf.Variable([[[4113, 7511, 6259], \
                                    [3870, 6725, 6962]], \
                                   [[5102, 7038, 6591], \
                                    [3661, 5901, 6235]], \
                                   [[951, 1208, 1098], \
                                    [870, 645, 948]]])
    tensor_variable
    

    这将产生以下输出:

    图 1.5:TensorFlow 变量的输出

    图 1.5:TensorFlow 变量的输出

  14. 打印张量变量的秩作为 NumPy 变量:

    tf.rank(tensor_variable).numpy()
    

    这将产生以下输出:

    3
    

    在这里,您可以看到,张量变量的秩为 3,确认该变量是三维的。

  15. 打印张量变量的形状作为 Python 列表:

    tensor_variable.shape.as_list()
    

    这将产生以下输出:

    [3, 2, 3]
    

    结果显示,生成的张量的形状是一个列表对象。

在这个练习中,您已经成功地使用 TensorFlow 的 Variable 类从政治投票数据中创建了各种秩的张量。首先,您创建了标量,这是秩为 0 的张量。接下来,您创建了向量,这是秩为 1 的张量。然后,创建了矩阵,这是秩为 2 的张量。最后,创建了秩为 3 或更高的张量。您通过使用 TensorFlow 的 rank 函数确认了所创建的张量的秩,并通过调用张量的 shape 属性验证了它们的形状。

在下一部分,您将结合张量,通过张量加法创建新张量。

张量加法

张量可以相加以创建新的张量。在本章中,你将使用矩阵的例子,但这一概念可以扩展到任何秩的张量。矩阵在特定条件下可以与标量、向量和其他矩阵相加,这个过程被称为广播。广播是指对不同形状的张量进行数组算术运算的过程。

如果两个矩阵形状相同,则可以将它们相加(或相减)。对于这种矩阵-矩阵加法,结果矩阵由输入矩阵逐元素相加得到。因此,结果矩阵的形状与两个输入矩阵相同。你可以定义矩阵Z = [Z_ij]为矩阵和Z = X + Y,其中z_ij = x_ij + y_ij,并且Z中的每个元素是XY中相同位置元素的和。

矩阵加法是交换律的,这意味着XY的顺序无关,即X + Y = Y + X。矩阵加法也是结合律的,这意味着即使加法顺序不同,或者即使运算应用多次,结果也相同,即X + (Y + Z) = (X + Y) + Z

相同的矩阵加法原则适用于标量、向量和张量。以下图为例:

图 1.6:矩阵-矩阵加法的视觉示例

图 1.6:矩阵-矩阵加法的视觉示例

标量也可以与矩阵相加。在这里,矩阵的每个元素都与标量逐个相加,如图 1.7所示:

图 1.7:矩阵-标量加法的视觉示例

图 1.7:矩阵-标量加法的视觉示例

加法是一个重要的变换,因其在张量中应用非常频繁。例如,在开发人工神经网络(ANN)时,一个常见的变换是为层添加偏置。这是将与 ANN 层大小相同的常量张量数组加到该层上。因此,了解如何以及何时应用这个看似简单的变换是很重要的。

张量加法可以通过使用add函数并传递张量作为参数来在 TensorFlow 中执行,或者简单地使用+运算符,如下所示:

tensor1 = tf.Variable([1,2,3])
tensor2 = tf.Variable([4,5,6])
tensor_add1 = tf.add(tensor1, tensor2)
tensor_add2 = tensor1 + tensor2

在以下练习中,你将执行 TensorFlow 中标量、向量和矩阵的张量加法。

练习 1.03:在 TensorFlow 中执行张量加法

A 区和 B 区三种不同政治党派不同候选人投票数如下:

图 1.8:三种不同政治党派在三个不同候选人中的投票情况 A 区和 B 区的政党

图 1.8:A 区和 B 区三种不同政治党派不同候选人投票数

你的任务如下:

  • 存储 A 区政治党派 X 获得的总票数。

  • 存储 A 区每个政党获得的总票数。

  • 存储两个选区中每个政党所投的总票数。

执行以下步骤完成本次练习:

  1. 导入 TensorFlow 库:

    import tensorflow as tf
    
  2. 使用 TensorFlow 的 Variable 类创建三个标量变量,表示在选区 A 中政党 X 的三位候选人所投的票数:

    int1 = tf.Variable(4113, tf.int32)
    int2 = tf.Variable(7511, tf.int32)
    int3 = tf.Variable(6529, tf.int32)
    
  3. 创建一个新变量,用来存储政党 X 在选区 A 中的总票数:

    int_sum = int1+int2+int3
    
  4. 打印两个变量之和作为 NumPy 变量的结果:

    int_sum.numpy()
    

    这将产生以下输出:

    18153
    
  5. 创建三个向量,表示在选区 A 中不同政党的投票数量,每个向量有一行三列:

    vec1 = tf.Variable([4113, 3870, 5102], tf.int32)
    vec2 = tf.Variable([7511, 6725, 7038], tf.int32)
    vec3 = tf.Variable([6529, 6962, 6591], tf.int32)
    
  6. 创建一个新变量,用来存储每个政党在选区 A 中的总票数:

    vec_sum = vec1 + vec2 + vec3
    
  7. 打印两个变量之和作为 NumPy 数组的结果:

    vec_sum.numpy()
    

    这将产生以下输出:

    array([18153, 17557, 18731])
    
  8. 通过执行对向量中每个元素的加法,验证向量加法是否符合预期:

    print((vec1[0] + vec2[0] + vec3[0]).numpy())
    print((vec1[1] + vec2[1] + vec3[1]).numpy())
    print((vec1[2] + vec2[2] + vec3[2]).numpy())
    

    这将产生以下输出:

    18153
    17557
    18731
    

    你可以看到,三个向量上的+操作仅仅是向量的逐元素加法。

  9. 创建三个矩阵,用来存储每个选区中各政党的候选人所投的票数:

    matrix1 = tf.Variable([[4113, 3870, 5102], \
                           [3611, 951, 870]], tf.int32)
    matrix2 = tf.Variable([[7511, 6725, 7038], \
                           [5901, 1208, 645]], tf.int32)
    matrix3 = tf.Variable([[6529, 6962, 6591], \
                           [6235, 1098, 948]], tf.int32)
    
  10. 验证这三个张量是否具有相同的形状:

    matrix1.shape == matrix2.shape == matrix3.shape
    

    这将产生以下输出:

    True
    
  11. 创建一个新变量,用来存储两个选区中每个政党所投的总票数:

    matrix_sum = matrix1 + matrix2 + matrix3
    
  12. 打印两个变量之和作为 NumPy 数组的结果:

    matrix_sum.numpy()
    

    这将产生以下输出,表示每个选区中每个候选人和每个政党的总票数:

    图 1.9:作为 NumPy 变量的矩阵求和输出

    图 1.9:作为 NumPy 变量的矩阵求和输出

  13. 通过执行对向量中每个元素的加法,验证张量加法是否符合预期:

    print((matrix1[0][0] + matrix2[0][0] + matrix3[0][0]).numpy())
    print((matrix1[0][1] + matrix2[0][1] + matrix3[0][1]).numpy())
    print((matrix1[0][2] + matrix2[0][2] + matrix3[0][2]).numpy())
    print((matrix1[1][0] + matrix2[1][0] + matrix3[1][0]).numpy())
    print((matrix1[1][1] + matrix2[1][1] + matrix3[1][1]).numpy())
    print((matrix1[1][2] + matrix2[1][2] + matrix3[1][2]).numpy())
    

    这将产生以下输出:

    18153
    17557
    18731
    15747
    3257
    2463
    

    你可以看到,+ 操作等同于对创建的三个矩阵进行逐元素加法。

在本次练习中,你成功地对代表政治候选人选票的数据进行了张量加法。这个转换可以通过使用+操作来实现。你还验证了加法是逐元素进行的,并且确保转换有效的一种方式是确保张量具有相同的秩和形状。

在接下来的活动中,你将进一步练习在 TensorFlow 中进行张量加法。

活动 1.01:在 TensorFlow 中进行张量加法

你在一家公司工作,该公司有三个地点,每个地点有两位销售人员,并且每个地点销售三种产品。你需要对张量进行求和,以表示各地点每个产品的总收入。

图 1.10:每个销售人员在不同地点销售的不同产品数量

图 1.10:每个销售人员在不同地点销售的不同产品数量

你将采取的步骤如下:

  1. 导入 TensorFlow 库。

  2. 使用 TensorFlow 的 Variable 类,创建两个标量来表示 Location X 上所有销售人员的 Product A 总收入。第一个变量的值为 2706,第二个变量的值为 2386

  3. 创建一个新变量作为标量的和并打印结果。

    你应该得到以下输出:

    5092
    
  4. 使用 TensorFlow 的 Variable 类创建一个值为 [2706, 2799, 5102] 的向量和一个值为 95 的标量。

  5. 创建一个新变量,将标量与向量相加,表示 Salesperson 1Location X 的销售目标并打印结果。

    你应该得到以下输出:

    图 1.11:整数向量求和的输出,作为 NumPy 变量

    图 1.11:整数向量求和的输出,作为 NumPy 变量

  6. 使用 TensorFlow 的 Variable 类创建三个秩为 2 的张量,表示每个销售人员、产品和位置的收入。第一个张量的值为 [[2706, 2799, 5102], [2386, 4089, 5932]],第二个张量的值为 [[5901, 1208, 645], [6235, 1098, 948]],第三个张量的值为 [[3908, 2339, 5520], [4544, 1978, 4729]]

  7. 创建一个新变量作为矩阵的和并打印结果:图 1.12:矩阵求和的输出,作为 NumPy 变量

图 1.12:矩阵求和的输出,作为 NumPy 变量

注意

本活动的解答可以通过此链接找到。

在接下来的章节中,你将学习如何改变张量的形状和秩。

形状重塑

一些操作,如加法,只有在满足特定条件时才能应用于张量。重塑是修改张量形状的一种方法,使得这些操作可以执行。重塑将张量的元素重新排列成一个不同大小的张量。只要总元素的数量保持不变,任何大小的张量都可以进行重塑。

例如,一个 (4x3) 矩阵可以被重塑为一个 (6x2) 矩阵,因为它们都有 12 个元素。秩,即维度的数量,也可以在重塑过程中发生变化。例如,一个秩为 2(4x3) 矩阵可以被重塑为一个秩为 3(3x2x2) 张量。该 (4x3) 矩阵也可以被重塑为一个 (12x1) 向量,其秩从 2 变为 1

图 1.13 说明了张量的重塑。左侧是一个形状为 (3x2) 的张量,它可以被重塑为形状为 (2x3)(6)(6x1) 的张量。在这里,元素的数量,即六,保持不变,尽管张量的形状和秩发生了变化:

图 1.13:将 (3x2) 张量重塑为不同形状张量的可视化表示

图 1.13:将 (3x2) 张量重塑为不同形状张量的可视化表示

张量的形状重塑可以通过 TensorFlow 的 reshape 函数来实现,并将张量和新张量的目标形状作为参数传入:

tensor1 = tf.Variable([1,2,3,4,5,6])
tensor_reshape = tf.reshape(tensor1, shape=[3,2])

在这里,创建了一个新的张量,其元素与原张量相同;然而,形状是[3,2],而不是[6]

下一部分介绍了张量转置,这是另一种修改张量形状的方法。

张量转置

当一个张量被转置时,张量中的元素会按特定顺序重新排列。转置操作通常用张量上的 T 上标表示。张量中每个元素的新位置可以通过 (x12…k)T = xk…21来确定。对于秩为2`的矩阵或张量,行变为列,反之亦然。矩阵转置的示例如图 1.14所示。任何秩的张量都可以进行转置,且通常会导致形状的变化:

图 1.14:在 (3x2) 矩阵上的张量转置的可视化表示

图 1.14:在 (3x2) 矩阵上的张量转置的可视化表示

下图展示了矩阵AB的转置特性:

图 1.15:张量转置特性,其中 X 和 Y 是张量

图 1.15:张量转置特性,其中 X 和 Y 是张量

如果一个张量的转置等于原张量,则称该张量为对称的。

张量转置可以通过 TensorFlow 的 transpose 函数来实现,并将张量作为唯一参数传入:

tensor1 = tf.Variable([1,2,3,4,5,6])
tensor_transpose = tf.transpose(tensor1)

在进行张量转置时,只有一个可能的结果;然而,改变张量形状则有多个可能的结果,这取决于输出的目标形状。

在以下练习中,使用 TensorFlow 演示张量的形状重塑和转置操作。

练习 1.04:在 TensorFlow 中执行张量重塑和转置

在本练习中,你将学习如何使用 TensorFlow 库进行张量形状重塑和转置。

执行以下步骤:

  1. 导入 TensorFlow 库,并使用 TensorFlow 的 Variable 类创建一个具有两行四列的矩阵:

    import tensorflow as tf
    matrix1 = tf.Variable([[1,2,3,4], [5,6,7,8]])
    
  2. 通过调用矩阵的shape属性,将矩阵作为 Python 列表来验证矩阵的形状:

    matrix1.shape.as_list()
    

    这将产生以下输出:

    [2, 4]
    

    你会看到矩阵的形状是[2,4]

  3. 使用 TensorFlow 的 reshape 函数,通过传入矩阵和所需的新形状,将矩阵更改为具有四行两列的矩阵:

    reshape1 = tf.reshape(matrix1, shape=[4, 2])
    reshape1
    

    你应该得到以下输出:

    图 1.16:重塑后的矩阵

    图 1.16:重塑后的矩阵

  4. 通过调用 shape 属性并将其作为 Python 列表来验证重塑后的矩阵的形状:

    reshape1.shape.as_list()
    

    这将产生以下输出:

    [4, 2]
    

    在这里,你可以看到矩阵的形状已经改变为你期望的形状[4,2]

  5. 使用 TensorFlow 的 reshape 函数将矩阵转换为一行八列的矩阵。将矩阵和期望的新形状作为参数传递给 reshape 函数:

    reshape2 = tf.reshape(matrix1, shape=[1, 8])
    reshape2
    

    你应该会得到以下输出:

    <tf.Tensor: shape=(1, 8), dtype=int32, numpy=array([[1, 2, 3, 4, 5, 6, 7, 8]])>
    
  6. 通过调用 shape 属性作为 Python 列表来验证重新塑形后的矩阵形状:

    reshape2.shape.as_list()
    

    这将产生以下输出:

    [1, 8]
    

    前面的输出确认了重新塑形矩阵的形状为 [1, 8]

  7. 使用 TensorFlow 的 reshape 函数将矩阵转换为八行一列的矩阵,将矩阵和期望的新形状作为参数传递给 reshape 函数:

    reshape3 = tf.reshape(matrix1, shape=[8, 1])
    reshape3
    

    你应该会得到以下输出:

    图 1.17:形状为 (8, 1) 的重新塑形矩阵

    图 1.17:形状为 (8, 1) 的重新塑形矩阵

  8. 通过调用 shape 属性作为 Python 列表来验证重新塑形后的矩阵形状:

    reshape3.shape.as_list()
    

    这将产生以下输出:

    [8, 1]
    

    前面的输出确认了重新塑形矩阵的形状为 [8, 1]

  9. 使用 TensorFlow 的 reshape 函数将矩阵转换为大小为 2x2x2 的张量。将矩阵和期望的新形状作为参数传递给 reshape 函数:

    reshape4 = tf.reshape(matrix1, shape=[2, 2, 2])
    reshape4
    

    你应该会得到以下输出:

    图 1.18:形状为 (2, 2, 2) 的重新塑形矩阵

    图 1.18:形状为 (2, 2, 2) 的重新塑形矩阵

  10. 通过调用 shape 属性作为 Python 列表来验证重新塑形后的矩阵形状:

    reshape4.shape.as_list()
    

    这将产生以下输出:

    [2, 2, 2]
    

    前面的输出确认了重新塑形矩阵的形状为 [2, 2, 2]

  11. 使用 TensorFlow 的 rank 函数验证秩是否已更改,并将结果作为 NumPy 变量打印:

    tf.rank(reshape4).numpy()
    

    这将产生以下输出:

    3
    
  12. 使用 TensorFlow 的 transpose 函数将大小为 2X4 的矩阵转换为大小为 4x2 的矩阵:

    transpose1 = tf.transpose(matrix1)
    transpose1
    

    你应该会得到以下输出:

    图 1.19:转置矩阵

    图 1.19:转置矩阵

  13. 验证 reshape 函数和 transpose 函数在应用于给定矩阵时,是否会产生不同的结果:

    transpose1 == reshape1
    

    图 1.20:验证转置和重新塑形产生不同结果

    图 1.20:验证转置和重新塑形产生不同结果

  14. 使用 TensorFlow 的 transpose 函数转置 步骤 9 中的重新塑形矩阵:

    transpose2 = tf.transpose(reshape4)
    transpose2
    

    这将产生以下输出:

    图 1.21:转置后的重新塑形张量的输出

图 1.21:转置后的重新塑形张量的输出

这个结果展示了在重新塑形和转置张量后,得到的张量的形状。

在本次练习中,你已成功通过重新塑形或转置操作修改了张量的形状。你研究了在重新塑形和转置操作后,张量的形状和秩如何变化。

在接下来的活动中,你将测试如何使用 TensorFlow 重新塑形和转置张量的知识。

活动 1.02:在 TensorFlow 中执行张量的重塑和转置

在此活动中,你需要模拟将 24 名学校儿童分组进行课堂项目。每个重新塑形或转置后的张量的维度将表示每个小组的大小。

执行以下步骤:

  1. 导入 TensorFlow 库。

  2. 使用Variable类创建一个包含 24 个单调递增元素的单维张量,用来表示学校儿童的 ID。验证矩阵的形状。

    你应该得到以下输出:

    [24]
    
  3. 使用 TensorFlow 的reshape函数将矩阵重塑为 12 行 2 列,表示 12 对学校儿童。验证新矩阵的形状。

    你应该得到以下输出:

    [12, 2]
    
  4. 使用 TensorFlow 的reshape函数将原始矩阵重塑为3x4x2的形状,表示 3 组由 4 对学校儿童组成的小组。验证新张量的形状。

    你应该得到以下输出:

    [3, 4, 2]
    
  5. 验证新张量的秩为3

  6. 第 3 步中创建的张量进行转置,使用 TensorFlow 的transpose函数表示 12 名学生的 2 组。验证新张量的形状。

    你应该得到以下输出:

    [2, 12]
    

    注意

    本活动的解决方案可以通过此链接找到。

在本节中,你被介绍了一些人工神经网络(ANNs)的基本组件——张量。你还学习了张量的一些基本操作,如加法、转置和重新塑形。你通过使用 TensorFlow 库中的函数实现了这些概念。

在下一主题中,你将通过学习与人工神经网络(ANNs)相关的另一个重要变换——张量乘法,来扩展你对线性变换的理解。

张量乘法

张量乘法是另一个在构建和训练人工神经网络(ANNs)过程中常用的基本操作,因为信息通过网络从输入传递到结果,过程中涉及一系列加法和乘法。加法的规则简单且直观,但张量的规则则更加复杂。张量乘法不仅仅是元素之间的逐元素相乘,而是通过计算每个张量的整行/整列的点积来计算结果张量的每个元素。这一部分将解释二维张量或矩阵的乘法是如何工作的。但更高阶的张量也可以进行乘法操作。

给定矩阵 X = [xij]m x n,和另一个矩阵 Y = [yij]n x p,这两个矩阵的乘积是 Z = XY = [zij]m x p,每个元素 zij 都按元素定义如 Formula。结果矩阵的形状与矩阵乘积的外部维度相同,即第一个矩阵的行数和第二个矩阵的列数。为了使乘法有效,矩阵乘积的内部维度必须匹配,即第一个矩阵的列数和第二个矩阵的行数必须相对应。

矩阵乘法的内部和外部维度的概念显示在下图中,其中 X 表示第一个矩阵,Y 表示第二个矩阵:

Figure 1.22: 矩阵乘法中内部和外部维度的可视化表示

Figure 1.22: 矩阵乘法中内部和外部维度的可视化表示

与矩阵加法不同,矩阵乘法不是交换的,这意味着矩阵在乘积中的顺序很重要:

Figure 1.23: 矩阵乘法是非交换的

Figure 1.23: 矩阵乘法是非交换的

例如,假设你有以下两个矩阵:

Figure 1.24: 两个矩阵 X 和 Y

Figure 1.24: 两个矩阵 X 和 Y

构建乘积的一种方式是首先有矩阵 X,然后乘以 Y

Figure 1.25: 矩阵 X 乘以 Y 的可视化表示,X•Y

Figure 1.25: 矩阵 X 乘以 Y 的可视化表示,X•Y

这导致一个 2x2 的矩阵。构建乘积的另一种方式是首先有 Y,然后乘以 X

Figure 1.26: 矩阵 Y 乘以 X 的可视化表示,Y•X

Figure 1.26: 矩阵 Y 乘以 X 的可视化表示,Y•X

在这里你可以看到从乘积 YX 形成的矩阵是一个 3x3 的矩阵,与从乘积 XY 形成的矩阵非常不同。

在 TensorFlow 中,可以通过使用 matmul 函数执行张量乘法,并按照它们需要被乘的顺序将张量作为参数传递进去:

tensor1 = tf.Variable([[1,2,3]])
tensor2 = tf.Variable([[1],[2],[3]])
tensor_mult = tf.matmul(tensor1, tensor2)

张量乘法也可以通过使用 @ 运算符来实现,如下所示:

tensor_mult = tensor1 @ tensor2

标量-张量乘法要简单得多,只是张量中每个元素乘以标量,因此 λX = [λxij…k],其中 λ 是标量,X 是张量。

在 TensorFlow 中,可以通过使用 matmul 函数或使用 * 运算符来实现标量乘法:

tensor1 = tf.Variable([[1,2,3]])
scalar_mult = 5 * tensor1

在下面的练习中,您将使用 TensorFlow 库执行张量乘法。

练习 1.05:在 TensorFlow 中执行张量乘法

在本练习中,你将使用 TensorFlow 的 matmul 函数和 @ 运算符执行张量乘法。本练习将以三明治零售商的数据为例,表示不同三明治的配料及配料的成本。你将使用矩阵乘法来确定每个三明治的成本。

三明治食谱

图 1.27:三明治食谱

图 1.27:三明治食谱

配料详情

图 1.28:配料详情

图 1.28:配料详情

销售预测

图 1.29:销售预测

图 1.29:销售预测

执行以下步骤:

  1. 导入 TensorFlow 库:

    import tensorflow as tf
    
  2. 创建一个矩阵表示不同的三明治食谱,行代表三种不同的三明治种类,列代表五种不同配料的组合和数量,使用Variable类:

    matrix1 = tf.Variable([[1.0,0.0,3.0,1.0,2.0], \
                           [0.0,1.0,1.0,1.0,1.0], \
                           [2.0,1.0,0.0,2.0,0.0]], \
                          tf.float32)
    matrix1
    

    你应该得到以下输出:

    图 1.30:表示制作三明治所需配料数量的矩阵

    图 1.30:表示制作三明治所需配料数量的矩阵

  3. 通过调用矩阵的shape属性作为 Python 列表,验证矩阵的形状:

    matrix1.shape.as_list()
    

    这将产生以下输出:

    [3, 5]
    
  4. 创建一个第二个矩阵,表示每种配料的成本和重量,其中行代表五种配料,列代表配料的成本和重量(单位:克):

    matrix2 = tf.Variable([[0.49, 103], \
                           [0.18, 38], \
                           [0.24, 69], \
                           [1.02, 75], \
                           [0.68, 78]])
    matrix2
    

    你应该得到以下结果:

    图 1.31:表示每种配料的成本和重量的矩阵

    图 1.31:表示每种配料的成本和重量的矩阵

  5. 使用 TensorFlow 的matmul函数执行matrix1matrix2的矩阵乘法:

    matmul1 = tf.matmul(matrix1, matrix2)
    matmul1
    

    这将产生以下输出:

    图 1.32:矩阵乘法的输出

    图 1.32:矩阵乘法的输出

  6. 创建一个矩阵来表示五家不同商店对三种三明治的销售预测:

    matrix3 = tf.Variable([[120.0, 100.0, 90.0], \
                           [30.0, 15.0, 20.0], \
                           [220.0, 240.0, 185.0], \
                           [145.0, 160.0, 155.0], \
                           [330.0, 295.0, 290.0]])
    
  7. matrix3matrix1matrix2相乘的结果相乘,以给出每家五家商店的预期成本和重量:

    matmul3 = matrix3 @ matmul1
    matmul3
    

    这将产生以下输出:

    图 1.33:矩阵乘法的输出

图 1.33:矩阵乘法的输出

乘法得到的张量显示了每家商店三明治的预期成本以及总配料的预期重量。

在本练习中,你已经成功学会了如何使用几个操作符在 TensorFlow 中进行矩阵乘法。你使用了 TensorFlow 的matmul函数以及简写符号@操作符。它们都能执行乘法操作;不过,matmul函数有多个不同的参数,可以传入,使其更加灵活。

注意

你可以在这里阅读更多关于matmul函数的内容:www.tensorflow.org/api_docs/python/tf/linalg/matmul

在下一节中,你将探索一些与 ANN 相关的其他数学概念。你将探索前向传播和反向传播,以及激活函数。

优化

在本节中,你将学习一些对于训练机器学习模型至关重要的优化方法。优化是通过更新 ANN 各层的权重,使得 ANN 预测值与训练数据的真实值之间的误差最小化的过程。

前向传播

前向传播是信息在人工神经网络(ANN)中传播的过程。在网络的每一层都会发生一系列张量乘法和加法操作,直到最终输出。前向传播在图 1.37中进行了说明,展示了一个单隐层的 ANN。输入数据有两个特征,而输出层对每个输入记录只有一个值。

隐藏层和输出层的权重和偏差显示为具有适当索引的矩阵和向量。对于隐藏层,权重矩阵的行数等于输入特征的数量,列数等于隐藏层单元的数量。因此,W1有两行三列,因为输入X有两个特征。同样,W2有三行一列,隐藏层有三个单元,输出层的大小为一。然而,偏差始终是一个大小等于该层节点数量的向量,并与输入和权重矩阵的乘积相加。

图 1.34:单层人工神经网络

图 1.34:单层人工神经网络

执行前向传播的步骤如下:

  1. X是网络的输入,也是隐藏层的输入。首先,输入矩阵X与隐藏层的权重矩阵W1相乘,然后加上偏差b1

    z1 = X*W1 + b1

    下面是操作后结果张量的形状示例。如果输入的大小为nX2,其中n是输入示例的数量,W1的大小为2X3b1的大小为1X3,则结果矩阵z1的大小将为nX3

  2. z1是隐藏层的输出,它是W2与偏差b2相加后的结果:

    Y = z1 * W2 + b2

    为了理解最终张量的形状,考虑以下示例。如果输出层的输入z1大小为nX3W2的大小为3X1b1的大小为1X1,则结果矩阵Y的大小将为nX1,表示每个训练样本的一个结果。

该模型中的总参数数量等于W1W2b1b2中元素的总和。因此,可以通过求和每个权重矩阵和偏置参数中的元素来计算参数的数量,计算结果为6 + 3 + 3 + 1 = 13。这些是需要在训练人工神经网络(ANN)过程中学习的参数。

在前向传播步骤之后,你必须评估你的模型,并将其与实际目标值进行比较。这是通过使用损失函数来实现的。均方误差(Mean Squared Error,MSE),即真实值和预测值之间的平方差的均值,是回归任务中损失函数的一个例子。一旦计算出损失,就需要更新权重以减少损失,并且通过反向传播找出更新权重的量和方向。

反向传播

loss 函数对预测输出的影响如下:

loss = L(y_predicted)

损失函数对模型参数的导数可以告诉你,增加或减少模型参数是否会导致损失增加或减少。反向传播的过程通过应用微积分的链式法则,从神经网络的输出层到输入层,在每一层计算损失函数对模型参数的导数来实现。

微积分的链式法则是一种通过中间函数计算复合函数导数的技术。该函数的广义版本可以写作如下:

dz/dx = dz/dy * dy/dx

这里,dz/dx是复合函数,y是中间函数。在人工神经网络中,复合函数是损失函数与模型参数的关系,中间函数则表示隐藏层。因此,损失函数对模型参数的导数可以通过将损失对预测输出的导数与预测输出对模型参数的导数相乘来计算。

在下一节中,你将学习如何根据损失函数对每个权重的导数来更新权重参数,以最小化损失。

学习最优参数

在本节中,您将看到如何迭代选择最优权重。您知道前向传播通过一系列张量加法和乘法在网络中传输信息,而反向传播是理解每个模型权重变化对损失的过程。下一步是使用反向传播的结果更新权重,以便根据损失函数减少误差。这个过程称为学习参数,使用优化算法实现。一个常用的优化算法通常称为梯度下降

在学习最优参数时,应用优化算法直到损失函数达到最小值。通常在给定步数之后停止或在损失函数变化微不足道时停止。如果将损失作为每个模型参数的函数绘制,损失函数的形状类似于一个凸形,只有一个最小值,优化函数的目标是找到这个最小值。

下图显示了特定特征的损失函数:

图 1.35:梯度下降算法找到的可视化表示最优参数以最小化损失

图 1.35:梯度下降算法找到的最优参数以最小化损失

首先,通过随机设置每个权重的参数(在图中表示为 p1)。然后计算该模型参数的损失,记为 l1. 后向传播步骤确定了损失相对于模型参数的导数,并确定了模型应更新的方向。下一个模型参数 p2 等于当前模型参数减去学习率(α)乘以导数值。学习率是在模型训练过程之前设置的超参数。通过导数值的乘积,当参数远离导数绝对值较大的最小值时,会采取更大的步长。然后计算损失 l2,并继续该过程,直到达到最小损失 lm,并找到最优参数 pm。

总结一下,这些是优化算法执行以找到最优参数的迭代步骤:

  1. 使用前向传播和当前参数预测整个数据集的输出。

  2. 应用损失函数计算预测输出中所有示例的损失。

  3. 使用反向传播计算每层权重和偏差对损失的导数。

  4. 使用导数值和学习率更新权重和偏差。

TensorFlow 中的优化器

TensorFlow 中有几种不同的优化器,每个优化器都基于不同的优化算法,旨在找到损失函数的全局最小值。它们都基于梯度下降算法,尽管在实现上有所不同。TensorFlow 中可用的优化器包括以下几种:

  • 随机梯度下降SGD):SGD 算法将梯度下降应用于小批次的训练数据。在使用 TensorFlow 中的优化器时,还可以使用一个动量参数,它通过对计算出的梯度进行指数平滑,从而加速训练过程。

  • Adam:这是一种基于连续自适应估计一阶和二阶矩的 SGD 方法。

  • 均方根传播RMSProp):这是一种未公开的自适应学习率优化器。RMSProp 在每步找到损失最小值时,将学习率除以梯度平方的平均值,这样得到的学习率呈指数衰减。

  • Adagrad:该优化器具有参数特定的学习率,学习率会根据参数在训练过程中更新的频率进行调整。当参数收到更多更新时,每次更新的幅度会变小。

优化器的选择会影响训练时间和模型性能。每个优化器都有超参数,比如初始学习率,这些超参数必须在训练前进行选择,而调优这些超参数也会影响训练时间和模型性能。虽然 TensorFlow 中还有其他优化器未在此明确列出(可以在此处找到:www.tensorflow.org/api_docs/python/tf/keras/optimizers),但上述优化器在训练时间和模型性能上表现良好,是选择优化器时的一个安全的首选。TensorFlow 中可用的优化器位于tf.optimizers模块中;例如,一个学习率为0.001的 Adam 优化器可以如下初始化:

optimizer = tf.optimizer.adam(learning_rate=0.001)

在本节中,你已经看到了实现梯度下降的步骤,用以计算模型训练的最优参数。在梯度下降中,每一个训练样本都会用于学习这些参数。然而,在处理大规模数据集时,比如图像和音频数据,通常会采用批量训练,并在每次学习完一个批次后进行更新。当使用梯度下降进行批量数据训练时,这个算法被称为 SGD。TensorFlow 中提供了 SGD 优化器以及一系列其他高效的优化器,包括 Adam、RMSProp、Adagrad 优化器等。

在下一节中,你将探索不同的激活函数,这些函数通常应用于每一层的输出。

激活函数

激活函数是应用于 ANN 层输出的数学函数,通常用于限制或约束层的值。值可能需要被约束的原因是,如果没有激活函数,值和相应的梯度可能会爆炸或消失,从而导致结果不可用。这是因为最终值是每个后续层值的累积乘积。随着层数的增加,值和梯度爆炸到无穷大或消失到零的可能性增加。这个概念被称为梯度爆炸和消失问题。决定一个层中的节点是否应被激活是激活函数的另一个用途,这也就是它们的名字的由来。常见的激活函数及其在图 1.36中的可视化表示如下:

  • 阶跃函数:如果值超过某一阈值,则值为非零,否则为零。此内容如图 1.36a所示。

  • 线性函数:公式,它是输入值的标量乘积。此内容如图 1.36b所示。

  • Sigmoid函数:公式,类似于一个平滑的阶跃函数,具有平滑的梯度。此激活函数对于分类非常有用,因为其值被限制在 0 到 1 之间。此内容如图 1.36c所示。

  • x=0。此内容如图 1.36d所示。

  • 0。此内容如图 1.36e所示。

  • ELU指数线性单元)函数:公式,否则公式,其中公式是常数。

  • SELU缩放指数线性单元)函数:公式,否则公式,其中公式是常数。此内容如图 1.36f所示。

  • Swish函数:公式。此内容如图 1.36g所示:

图 1.36:常见激活函数的可视化表示

图 1.36:常见激活函数的可视化表示

可以通过利用tf.keras.activations模块中的激活函数,将激活函数应用于任何张量。例如,sigmoid 激活函数可以应用于一个张量,如下所示:

y=tf.keras.activations.sigmoid(x)

现在,让我们通过以下活动测试你到目前为止所获得的知识。

活动 1.03:应用激活函数

在此活动中,你将回顾本章中使用的许多概念,并将激活函数应用于张量。你将使用汽车销售数据示例,应用这些概念,展示各个销售人员的销售记录,并突出显示那些有净正销售的记录。

销售记录

图 1.37:销售记录

图 1.37:销售记录

车辆 MSRP

图 1.38:车辆 MSRP

图 1.38:车辆 MSRP

固定成本

图 1.39:固定成本

图 1.39:固定成本

执行以下步骤:

  1. 导入 TensorFlow 库。

  2. 创建一个 3x4 的张量作为输入,值为 [[-0.013, 0.024, 0.06, 0.022], [0.001, -0.047, 0.039, 0.016], [0.018, 0.030, -0.021, -0.028]]。这个张量的行表示不同销售代表的销售情况,列表示经销商提供的各种车辆,而值则表示与建议零售价(MSRP)的平均百分比差异。根据销售员是否能以高于或低于 MSRP 的价格售出车辆,数值为正或负。

  3. 创建一个 4x1 的权重张量,形状为 4x1,值为 [[19995.95], [24995.50], [36745.50], [29995.95]],表示汽车的 MSRP。

  4. 创建一个大小为 3x1 的偏置张量,值为 [[-2500.0], [-2500.0], [-2500.0]],表示每个销售员的固定成本。

  5. 对输入与权重进行矩阵乘法,以展示所有车辆的 MSRP 平均偏差,并加上偏置,减去销售员的固定成本。打印结果。

    您应该得到以下结果:

    图 1.40:矩阵乘法的输出

    图 1.40:矩阵乘法的输出

  6. 应用 ReLU 激活函数以突出净销售为正的销售员,并打印结果。

    您应该得到以下结果:

    图 1.41:应用激活函数后的输出

图 1.41:应用激活函数后的输出

注意

本活动的解决方案可以通过此链接查看。

在后续的章节中,您将学习如何为您的 ANN 添加激活函数,激活函数可以插入到层与层之间,或在定义层后直接应用。您将学习如何选择最适合的激活函数,这通常是通过超参数优化技术来实现的。激活函数是超参数的一个例子,超参数是学习过程开始前设定的参数,它可以进行调整以找到模型性能的最佳值。

总结

在本章中,您已了解了 TensorFlow 库。您学习了如何在 Python 编程语言中使用它。您创建了具有不同秩和形状的 ANN 构建块(张量),并使用 TensorFlow 对张量进行线性变换,实施了张量的加法、重塑、转置和乘法——这些都是理解 ANN 基础数学原理的基础。

在下一章中,你将提升对张量的理解,并学习如何加载各种类型的数据并进行预处理,以使其适合在 TensorFlow 中训练人工神经网络(ANN)。你将处理表格数据、视觉数据和文本数据,所有这些数据必须以不同的方式进行预处理。通过处理视觉数据(即图像),你还将学习如何使用那些无法全部加载到内存中的训练数据。

第二章:2. 加载和处理数据

概述

在本章中,你将学习如何加载和处理多种数据类型,以便在 TensorFlow 中建模。你将实现将数据输入到 TensorFlow 模型中的方法,从而优化模型训练。

在本章结束时,你将学会如何输入表格数据、图像、文本和音频数据,并进行预处理,使其适合用于训练 TensorFlow 模型。

介绍

在上一章中,你学习了如何使用 TensorFlow 创建、利用和应用线性变换到张量。该章首先介绍了张量的定义以及如何使用 TensorFlow 库中的 Variable 类创建张量。然后,你创建了不同阶数的张量,并学习了如何使用该库进行张量加法、重塑、转置和乘法操作。这些都是线性变换的例子。你通过讲解优化方法和激活函数并如何在 TensorFlow 库中访问它们,结束了这一章的内容。

在 TensorFlow 中训练机器学习模型时,必须向模型提供训练数据。可用的原始数据可能有多种格式——例如,表格型 CSV 文件、图像、音频或文本文件。不同的数据源以不同的方式加载和预处理,以便为 TensorFlow 模型提供数值张量。例如,虚拟助手使用语音查询作为输入交互,然后应用机器学习模型来解码输入的语音并执行特定的输出操作。为了创建这一任务的模型,必须将语音输入的音频数据加载到内存中。还需要一个预处理步骤,将音频输入转换为文本。之后,文本将被转换为数值张量以进行模型训练。这是一个例子,展示了从非表格型、非数值型数据(如音频数据)创建模型的复杂性。

本章将探讨一些常用的数据类型,这些数据类型用于构建机器学习模型。你将以高效的方式将原始数据加载到内存中,然后执行一些预处理步骤,将原始数据转换为适合训练机器学习模型的数值张量。幸运的是,机器学习库已经取得了显著的进展,这意味着使用图像、文本和音频等数据类型训练模型对于实践者来说变得非常可行。

探索数据类型

根据数据来源的不同,原始数据可以有不同的形式。常见的数据形式包括表格数据、图像、视频、音频和文本。例如,温度记录仪(用于记录给定地点随时间变化的温度)输出的数据是表格数据。表格数据是按行和列结构化的,在温度记录仪的例子中,每一列可能代表每条记录的某个特征,比如时间、地点和温度,而每一行则代表每条记录的数值。下表展示了数值型表格数据的示例:

图 2.1:一个由数值组成的表格数据的示例,包含 10 行数据

图 2.1:一个由数值组成的表格数据的示例,包含 10 行数据

图像数据代表另一种常见的原始数据形式,在构建机器学习模型时非常受欢迎。由于数据量巨大,这些模型也非常受欢迎。随着智能手机和监控摄像头记录下生活中的每一个瞬间,它们已经生成了大量可以用于训练模型的数据。

用于训练的图像数据的维度与表格数据不同。每张图像都有高度和宽度维度,并且颜色通道增加了第三个维度,而图像数量则增加了第四个维度。因此,图像数据模型的输入张量是四维的,而表格数据的输入张量是二维的。下图展示了从Open Images数据集(storage.googleapis.com/openimages/web/index.html)中提取的带标签的船只和飞机的训练示例;这些图像已经过预处理,使得它们的高度和宽度相同。这个数据可以用来训练一个二分类模型,将图像分类为船只或飞机:

图 2.2:可以用于训练机器学习模型的图像数据样本

图 2.2:可以用于训练机器学习模型的图像数据样本

其他类型的原始数据,如文本和音频,也可以用来构建机器学习模型。像图像一样,它们在机器学习社区中的受欢迎程度来自于大量可用的数据。音频和文本都有大小不确定的挑战。你将在本章后面探索如何克服这一挑战。下图展示了一个采样率为 44.1 kHz 的音频样本,这意味着音频数据每秒被采样 44,100 次。这是输入虚拟助手的原始数据类型的一个示例,虚拟助手通过这些数据解析请求并做出相应的动作:

图 2.3:音频数据的可视化表示

图 2.3:音频数据的可视化表示

现在你已经了解了在构建机器学习模型时可能遇到的一些数据类型,接下来的部分将揭示如何预处理不同类型的数据。

数据预处理

数据预处理是指将原始数据转换为适合机器学习模型使用的形式的过程。不同的数据类型将需要不同的预处理步骤,最基本的要求是,结果张量仅包含数值元素,如整数或小数。需要数值张量,因为模型依赖于线性变换,如加法和乘法,而这些变换只能在数值张量上执行。

虽然许多数据集仅包含数值字段,但也有很多数据集不止如此。它们可能包含字符串、布尔值、类别型或日期类型的字段,这些字段都必须转换为数值字段。有些转换可能很简单;例如,布尔值字段可以映射为 true 对应 1false 对应 0。因此,将布尔字段映射为数值字段是简单的,并且所有必要的信息都得以保留。然而,当转换其他数据类型(如日期字段)时,除非另有明确说明,否则转换为数值字段时可能会丢失信息。

一个可能的信息丢失示例是将日期字段通过 Unix 时间转换为数值字段。Unix 时间表示自 Unix 纪元以来经过的秒数;即 1970 年 1 月 1 日 00:00:00 UTC,忽略闰秒。使用 Unix 时间移除了月份、星期几、小时等的显式指示,而这些信息在训练模型时可能作为重要特征。

在将字段转换为数值数据类型时,重要的是尽可能保留信息上下文,因为这将有助于训练模型理解特征与目标之间的关系。以下图示展示了如何将日期字段转换为一系列数值字段:

图 2.4:日期列的数值编码

图 2.4:日期列的数值编码

如前图所示,左侧是日期字段,表示一个特定日期,而右侧则提供了一种方法,将其转化为数值信息:

  • 从日期中提取年份,作为整数。

  • 月份使用独热编码(one-hot encoding)。每个月份都有一个列,并且月份被二进制编码,如果日期的月份与该列的名称相符。

  • 创建了一个列,指示日期是否为周末。

这里仅是对date列进行编码的方法;并不是所有前述的方法都是必须的,且还有许多其他方法可以使用。将所有字段适当地编码为数值字段对于创建高效的机器学习模型至关重要,这样模型才能学习特征与目标之间的关系。

数据归一化是另一种预处理技术,用于加速训练过程。归一化过程会重新缩放字段,使它们都具有相同的尺度。这也有助于确保模型的权重具有相同的尺度。

在前面的图示中,year列的数量级为10³,而其他列的数量级为10⁰。这意味着列之间存在三个数量级的差异。字段的数值范围差异很大的话,可能会导致模型不够精确,因为在最小化误差函数时,可能无法找到最优的权重。这可能是由于在训练前定义的容忍限度或学习率,并不适用于这两个数量级的权重更新。在前面的例子中,重新缩放year列,使其与其他列具有相同的数量级,可能是有益的。

在本章中,你将探索多种方法来预处理表格数据、图像数据、文本数据和音频数据,以便将其用于训练机器学习模型。

处理表格数据

在本节中,你将学习如何将表格数据加载到 Python 开发环境中,以便可以用于 TensorFlow 建模。你将使用 pandas 和 scikit-learn 来利用有助于处理数据的类和函数,并探索可用于预处理数据的方法。

可以通过使用 pandas 的read_csv函数并传入数据集路径,将表格数据加载到内存中。这个函数非常适合且易于使用来加载表格数据,使用方法如下:

df = pd.read_csv('path/to/dataset')

为了对数据进行归一化,你可以使用在 scikit-learn 中可用的缩放器。可以应用多种缩放器;StandardScaler会对数据进行归一化,使数据集的字段均值为0,标准差为1。另一个常用的缩放器是MinMaxScaler,它会重新缩放数据集,使字段的最小值为0,最大值为1

要使用缩放器,必须先初始化并将其拟合到数据集。通过这样做,数据集就可以通过缩放器进行转换。实际上,拟合和转换过程可以通过使用fit_transform方法一步完成,如下所示:

scaler = StandardScaler()
transformed_df = scaler.fit_transform(df)

在第一个练习中,你将学习如何使用 pandas 和 scikit-learn 加载数据集并对其进行预处理,使其适合建模。

练习 2.01:加载表格数据并重新缩放数值字段

数据集 Bias_correction_ucl.csv 包含了针对韩国首尔的次日最高和最低气温预报的偏差修正信息。各字段代表给定日期的温度测量值、测量数据的天气站、与天气相关的模型预报指标(如湿度),以及次日的温度预报。你需要对数据进行预处理,使所有列符合正态分布,均值为 0,标准差为 1。你将以 Present_Tmax 列为例,展示其效果,该列表示给定日期和天气站的最高温度。

注意

数据集可以在这里找到:packt.link/l83pR

执行以下步骤以完成此练习:

  1. 打开一个新的 Jupyter notebook 来实现这个练习。将文件保存为 Exercise2-01.ipnyb

  2. 在新的 Jupyter Notebook 单元格中,导入 pandas 库,如下所示:

    import pandas as pd
    

    注意

    你可以在以下链接找到 pandas 的文档:pandas.pydata.org/docs/

  3. 创建一个新的 pandas DataFrame,命名为 df,并将 Bias_correction_ucl.csv 文件读取到其中。通过打印结果 DataFrame 来检查数据是否正确加载:

    df = pd.read_csv('Bias_correction_ucl.csv')
    df
    

    注意

    确保根据 CSV 文件在系统中的位置更改路径(高亮部分)。如果你从存储 CSV 文件的同一目录运行 Jupyter notebook,则可以直接运行上述代码而无需修改。

    输出结果如下:

    图 2.5:打印 DataFrame 后的输出结果

    ](tos-cn-i-73owjymdk6/9a7db49d73104d8e8938ad0147b4d4dd)

    图 2.5:打印 DataFrame 后的输出结果

  4. 使用 DataFrame 的 drop 方法删除 date 列,并传入列名。删除 date 列是因为它是非数值型字段,存在非数值型字段时无法进行缩放。由于要删除列,因此需要同时传入 axis=1inplace=True 参数:

    df.drop('Date', inplace=True, axis=1)
    
  5. 绘制表示数据集中各日期和天气站的最大温度的 Present_Tmax 列的直方图:

    ax = df['Present_Tmax'].hist(color='gray')
    ax.set_xlabel("Temperature")
    ax.set_ylabel("Frequency")
    

    输出结果如下:

    图 2.6:表示 Present_Tmax 列的温度与频率的直方图

    ](tos-cn-i-73owjymdk6/b058de14f83d45e082ee3b0b8d7e7a72)

    图 2.6:表示 Present_Tmax 列的温度与频率的直方图

    结果直方图显示了 Present_Tmax 列的值的分布。可以看到,温度值的范围从 20 到 38 摄氏度。绘制特征值的直方图是查看值的分布并判断是否需要缩放的好方法。

  6. 从 scikit-learn 的预处理包中导入 StandardScaler 类。初始化缩放器,拟合缩放器并使用缩放器的 fit_transform 方法对 DataFrame 进行变换。由于 fit_transform 方法的结果是一个 NumPy 数组,因此使用变换后的 DataFrame 创建一个新的 DataFrame df2。标准缩放器将对数值字段进行变换,使字段的均值为 0,标准差为 1

    from sklearn.preprocessing import StandardScaler
    scaler = StandardScaler()
    df2 = scaler.fit_transform(df)
    df2 = pd.DataFrame(df2, columns=df.columns)
    

    注意

    结果数据的均值和标准差可以输入到缩放器中。

  7. 绘制变换后的 Present_Tmax 列的直方图:

    ax = df2['Present_Tmax'].hist(color='gray')
    ax.set_xlabel("Normalized Temperature")
    ax.set_ylabel("Frequency")
    

    输出将如下所示:

    图 2.7:重新缩放后的 Present_Tmax 列的直方图

图 2.7:重新缩放后的 Present_Tmax 列的直方图

结果的直方图显示,温度值的范围大约从 -33 摄氏度,可以从直方图的 x 轴范围中看出。使用标准缩放器后,数值将始终具有 0 的均值和 1 的标准差。规范化特征可以加速模型训练过程。

在这个练习中,你成功地使用 pandas 库导入了表格数据,并使用 scikit-learn 库进行了一些预处理。数据的预处理包括删除 date 列和对数值字段进行缩放,使它们的均值为 0,标准差为 1

在以下活动中,你将使用 pandas 库加载表格数据,并使用 scikit-learn 中的 MinMax 缩放器对数据进行缩放。你将使用与之前练习中相同的数据集,该数据集描述了韩国首尔空气温度预报的偏差修正。

活动 2.01:加载表格数据并使用 MinMax 缩放器重新缩放数值字段

在此活动中,你需要加载表格数据并使用 MinMax 缩放器对数据进行重新缩放。数据集 Bias_correction_ucl.csv 包含了韩国首尔次日最大和最小空气温度预报的偏差修正信息。字段表示给定日期的温度测量值、测量指标的气象站、与天气相关的指标(如湿度)模型预测值以及次日的温度预测值。你需要对列进行缩放,使得每列的最小值为 0,最大值为 1

完成此活动的步骤如下:

  1. 打开一个新的 Jupyter notebook 来实现这个活动。

  2. 导入 pandas 和 Bias_correction_ucl.csv 数据集。

  3. 使用 pandas 的 read_csv 函数读取数据集。

  4. 删除 DataFrame 的 date 列。

  5. 绘制 Present_Tmax 列的直方图。

  6. 导入 MinMaxScaler 并将其拟合到并变换特征 DataFrame。

  7. 绘制变换后的 Present_Tmax 列的直方图。

    你应该得到类似以下的输出:

    图 2.8:活动 2.01 的预期输出

图 2.8:活动 2.01 的预期输出

注意

这个活动的解决方案可以通过这个链接找到。

转换非数值字段(如分类字段或日期字段)的一种方法是进行独热编码。0 表示除了与正确列对应的那一列外的所有列。新创建的虚拟列的列头对应于唯一值。独热编码可以通过使用 pandas 库的 get_dummies 函数来实现,并传入需要编码的列。一个可选的参数是提供前缀功能,为列头添加前缀,这对于引用列很有用:

dummies = pd.get_dummies(df['feature1'], prefix='feature1')

注意

使用 get_dummies 函数时,NaN 值会被转换为全 0。

在接下来的练习中,你将学习如何预处理非数值字段。你将使用与之前的练习和活动相同的数据集,该数据集描述了韩国首尔的气温预报偏差修正。

练习 2.02:预处理非数值数据

在这个练习中,你将通过使用 get_dummies 函数对 date 列的年份和月份进行独热编码来预处理 date 列。你将把独热编码后的列与原始 DataFrame 合并,确保结果 DataFrame 中的所有字段都是数值类型。

完成这个练习的步骤如下:

  1. 打开一个新的 Jupyter notebook 来实现这个练习。将文件保存为 Exercise2-02.ipnyb

  2. 在一个新的 Jupyter Notebook 单元格中,导入 pandas 库,如下所示:

    import pandas as pd
    
  3. 创建一个新的 pandas DataFrame,命名为 df,并将 Bias_correction_ucl.csv 文件读取到其中。通过打印结果 DataFrame 检查数据是否正确加载:

    df = pd.read_csv('Bias_correction_ucl.csv')
    

    注意

    确保根据文件在你系统上的位置更改路径(高亮部分)。如果你从存储 CSV 文件的目录运行 Jupyter notebook,你可以直接运行上述代码,而无需修改。

  4. 使用 pandas 的 to_datetime 函数将 date 列的数据类型更改为 Date

    df['Date'] = pd.to_datetime(df['Date'])
    
  5. 使用 pandas 的 get_dummies 函数为 year 创建虚拟列。将 date 列的年份作为第一个参数传入,并为结果 DataFrame 的列添加前缀。打印出结果 DataFrame:

    year_dummies = pd.get_dummies(df['Date'].dt.year, \
                                  prefix='year')
    year_dummies
    

    输出将如下所示:

    图 2.9:应用 get_dummies 函数处理日期列的年份后的输出

    图 2.9:应用 get_dummies 函数处理日期列的年份后的输出

    结果 DataFrame 只包含 0 和 1。1 对应于原始 date 列中存在的值。空值将在新创建的 DataFrame 中对所有列显示为 0。

  6. 通过从 date 列的月份创建虚拟列来重复此操作。打印出生成的 DataFrame:

    month_dummies = pd.get_dummies(df['Date'].dt.month, \
                                   prefix='month')
    month_dummies
    

    输出将如下所示:

    图 2.10:应用 get_dummies 函数的输出    到日期列的月份

    图 2.10:应用于日期列月份的 get_dummies 函数的输出

    结果 DataFrame 现在仅包含date列中月份的 0 和 1。

  7. 将原始 DataFrame 与您在步骤 56中创建的虚拟 DataFrame 连接起来:

    df = pd.concat([df, month_dummies, year_dummies], \
                   axis=1)
    
  8. 删除原始date列,因为它现在是多余的:

    df.drop('Date', axis=1, inplace=True)
    
  9. 验证所有列现在都是数值数据类型:

    df.dtypes
    

    输出如下所示:

    图 2.11:结果 DataFrame 的 dtypes 属性的输出

图 2.11:结果 DataFrame 的 dtypes 属性的输出

在这里,您可以看到结果 DataFrame 的所有数据类型都是数值的。这意味着它们现在可以传递到 ANN 中进行建模。

在此练习中,您成功导入了表格数据,并使用 pandas 和 scikit-learn 库预处理了date列。您使用了get_dummies函数将分类数据转换为数值数据类型。

注意

另一种从日期数据类型获取数值数据类型的方法是使用pandas.Series.dt访问器对象。有关可用选项的更多信息,请参阅:pandas.pydata.org/docs/reference/api/pandas.Series.dt.html

处理非数值数据是创建高性能模型的重要步骤。如果可能,应将任何领域知识传授给训练数据特征。例如,使用日期预测温度,就像在本章前面的练习和活动中使用的数据集一样,对月份进行编码将是有帮助的,因为温度很可能与年份的月份高度相关。然而,编码星期几可能没有用,因为星期几与温度可能没有相关性。使用这些领域知识可以帮助模型学习特征与目标之间的潜在关系。

在下一节中,您将学习如何处理图像数据,以便将其输入到机器学习模型中。

处理图像数据

各种组织每天生成大量图像,这些图像可用于创建预测模型,例如对象检测、图像分类和对象分割。在处理图像数据和其他一些原始数据类型时,通常需要预处理数据。使用 ANN 进行建模的最大优势之一是从原始数据创建模型时的最小预处理步骤。特征工程通常涉及使用领域知识从原始数据中创建特征,这是耗时的,并不能保证模型性能的提高。利用无需特征工程的 ANN 简化了训练过程,并且不需要领域知识。

例如,在医学图像中定位肿瘤需要经过多年训练的专家知识,但对于人工神经网络(ANNs)而言,只需要足够的标注数据进行训练。通常需要对这些图像进行少量的预处理步骤。这些步骤是可选的,但对于标准化训练过程和创建高性能模型是有帮助的。

一项预处理步骤是重新缩放。由于图像的颜色值是整数,范围从0255,它们被缩放为介于01之间的值,类似于活动 2.01加载表格数据并使用 MinMax Scaler 重新缩放数值字段。另一种常见的预处理步骤是图像增强,稍后在本节中你将进一步探讨,它本质上是通过增强图像来添加更多的训练样本,从而构建一个更强大的模型。

本节还介绍了批处理。批处理一次加载一批训练数据。这可能导致比一次性加载数据更慢的训练时间;然而,这允许你在非常大体量的数据集上训练模型。图像或音频训练是需要大量数据来获得良好性能的典型例子。

例如,一个典型的图像可能是 100 KB 大小。对于 100 万张图像的训练数据集,你将需要 100 GB 的内存,这对大多数人来说可能是不可实现的。如果模型以 32 张图像为一批进行训练,那么内存需求将小很多。批量训练使你能够增强训练数据,稍后在本节中你将进一步了解这一点。

图像可以通过一个名为ImageDataGenerator的类加载到内存中,该类可以从 Keras 的预处理包中导入。这个类最初来自 Keras,现在也可以在 TensorFlow 中使用。在加载图像时,你可以对它们进行重新缩放。通常的做法是将图像按 1/255 像素的值进行重新缩放。这意味着原本在 0 到 255 范围内的图像值现在将位于 0 到 1 之间。

ImageDataGenerator 可以通过以下方式初始化并进行重新缩放:

datagenerator = ImageDataGenerator(rescale = 1./255)

一旦初始化了 ImageDataGenerator 类,你可以使用 flow_from_directory 方法并传入图像所在的目录。该目录应包括按类标签标记的子目录,并且这些子目录应包含相应类别的图像。另一个需要传入的参数是所需的图像大小、批量大小以及类模式。类模式决定了生成的标签数组的类型。以下是使用 flow_from_directory 方法进行二分类的示例,批量大小为 25,图像大小为 64x64:

dataset = datagenerator.flow_from_directory\
          ('path/to/data',\
           target_size = (64, 64),\
           batch_size = 25,\
           class_mode = 'binary')

在接下来的练习中,你将利用 ImageDataGenerator 类将图像加载到内存中。

注意

提供的图像数据来自 Open Image 数据集,完整描述可以在这里找到:storage.googleapis.com/openimages/web/index.html

可以使用 Matplotlib 绘制图像来查看图像。这是验证图像是否与其相应标签匹配的一个有用练习。

练习 2.03:加载用于批量处理的图像数据

在本练习中,你将学习如何加载用于批量处理的图像数据。image_data文件夹包含一组船只和飞机的图像。你将加载船只和飞机的图像进行批量处理,并对它们进行重新缩放,使得图像值在01之间。然后,你的任务是打印出来自数据生成器的批次图像及其标签。

注意

你可以在此找到image_datapackt.link/jZ2oc

执行以下步骤来完成此练习:

  1. 打开一个新的 Jupyter Notebook 来实现本练习。将文件保存为Exercise2-03.ipnyb

  2. 在新的 Jupyter Notebook 单元格中,从tensorflow.keras.preprocessing.image导入ImageDataGenerator类:

    from tensorflow.keras.preprocessing.image \
         import ImageDataGenerator
    
  3. 实例化ImageDataGenerator类,并传递rescale参数,值为1./255,以将图像值转换为介于01之间:

    train_datagen = ImageDataGenerator(rescale =  1./255)
    
  4. 使用数据生成器的flow_from_directory方法,指示数据生成器加载图像数据。传入目标尺寸、批次大小和类别模式的参数:

    training_set = train_datagen.flow_from_directory\
                   ('image_data',\
                    target_size = (64, 64),\
                    batch_size = 25,\
                    class_mode = 'binary')
    
  5. 创建一个函数来显示批量图像。该函数将以 5x5 数组的形式绘制前 25 张图像及其对应的标签:

    import matplotlib.pyplot as plt
    def show_batch(image_batch, label_batch):\
        lookup = {v: k for k, v in \
                  training_set.class_indices.items()}
        label_batch = [lookup[label] for label in \
                       label_batch]
        plt.figure(figsize=(10,10))
        for n in range(25):
            ax = plt.subplot(5,5,n+1)
            plt.imshow(image_batch[n])
            plt.title(label_batch[n].title())
            plt.axis('off')
    
  6. 从数据生成器中获取一个批次并将其传递给函数以显示图像及其标签:

    image_batch, label_batch = next(training_set)
    show_batch(image_batch, label_batch)
    

    输出将如下所示:

    图 2.12:来自一批的图像

图 2.12:来自一批的图像

在这里,你可以看到一批船只和飞机的图像输出,这些图像可以输入到模型中。请注意,所有图像的大小相同,这是通过修改图像的长宽比实现的。这样可以确保图像在传入人工神经网络(ANN)时的一致性。

在本练习中,你将学习如何以批量的方式导入图像,以便它们可以用于训练人工神经网络(ANN)。图像是一次加载一个批次的,通过限制每个批次的训练图像数量,你可以确保不会超出计算机的 RAM。

在接下来的部分中,你将看到如何在图像加载时进行增强。

图像增强

图像增强是通过修改图像来增加可用训练样本数量的过程。该过程可以包括放大图像、旋转图像或水平/垂直翻转图像。如果增强过程不会改变图像的上下文,则可以进行增强。例如,当香蕉图像水平翻转时,它仍然可以被识别为香蕉,并且新生成的香蕉图像很可能是任意方向的。在这种情况下,训练过程中提供模型的两种方向将有助于构建一个更强大的模型。

然而,如果您有一张船只的图像,垂直翻转可能不合适,因为这并不代表船只通常在图像中的存在方式——船只不会倒立。图像增强的最终目标是增加训练图像的数量,这些图像应与物体在日常生活中的出现方式相似,并保留其上下文。这有助于训练出的模型在面对新的、未见过的图像时表现良好。图像增强的一个例子可以在下图中看到,图中的香蕉图像经过了三次增强;左侧图像为原始图像,右侧图像为增强后的图像。

右上角的图像是原始图像水平翻转后的结果,右中间的图像是原始图像放大了 15%,右下角的图像是原始图像旋转了 10 度。经过这个增强过程后,您会得到四张香蕉图像,每张图像的香蕉处于不同的位置和方向:

图 2.13:图像增强示例

图 2.13:图像增强示例

图像增强可以通过 TensorFlow 的 ImageDataGenerator 类在每批图像加载时进行。与图像重缩放类似,可以应用多种图像增强过程。常见增强过程的参数包括:

  • horizontal_flip:水平翻转图像。

  • vertical_flip:垂直翻转图像。

  • rotation_range:旋转图像至指定的度数。

  • width_shift_range:沿图像的宽度轴移动图像,最多移动指定的比例或像素量。

  • height_shift_range:沿图像的高度轴移动图像,最多移动指定的比例或像素量。

  • brightness_range:修改图像的亮度,最大可调整到指定的值。

  • shear_range:按指定量剪切图像。

  • zoom_range:按指定的比例放大图像。

图像增强可以在实例化 ImageDataGenerator 类时应用,示例如下:

datagenerator = ImageDataGenerator(rescale = 1./255,\
                                   shear_range = 0.2,\
                                   rotation_range= 180,\
                                   zoom_range = 0.2,\
                                   horizontal_flip = True)

在以下活动中,您将使用 TensorFlow 的 ImageDataGenerator 类进行图像增强。这个过程非常简单,只需要传入参数即可。您将使用与练习 2.03批处理图像数据加载中相同的数据集,该数据集包含了船只和飞机的图像。

活动 2.02:批处理图像数据加载

在这个活动中,你将加载图像数据进行批处理,并在此过程中增强图像。image_data文件夹包含一组船只和飞机的图像。你需要加载图像数据进行批处理,并通过随机扰动(如旋转、水平翻转图像和为图像添加剪切)调整输入数据。这将从现有的图像数据中创建额外的训练数据,并通过增加不同的训练样本数来提高机器学习模型的准确性和鲁棒性,即使只有少量样本可用。接着,你的任务是打印出从数据生成器中提取的一批带标签的图像。

这个活动的步骤如下:

  1. 打开一个新的 Jupyter notebook 来实现这个活动。

  2. tensorflow.keras.preprocessing.image导入ImageDataGenerator类。

  3. 实例化ImageDataGenerator并设置rescale=1./255shear_range=0.2rotation_range=180zoom_range=0.2horizontal_flip=True参数。

  4. 使用flow_from_directory方法,将数据生成器指向图像,同时传入目标尺寸64x64、批量大小25,并将类别模式设置为binary

  5. 创建一个函数,将前 25 个图像按 5x5 的数组显示,并附上相关标签。

  6. 从数据生成器中取一个批次,并将其传递给函数以显示图像及其标签。

    注意

    这个活动的解决方案可以通过这个链接找到。

在这个活动中,你批量增强了图像,使其可以用于训练人工神经网络(ANNs)。你已经看到,当图像作为输入时,它们可以被增强以生成更多有效的训练样本。

你学会了如何批量加载图像,这使得你可以在巨大的数据量上进行训练,而这些数据可能无法一次性全部加载到机器的内存中。你还学会了如何使用ImageDataGenerator类增强图像,它本质上是从训练集中的图像生成新的训练样本。

在下一节中,你将学习如何加载和预处理文本数据。

文本处理

文本数据代表了一大类易于获取的原始数据。例如,文本数据可以来自网页,如维基百科、转录的语音或社交媒体对话——这些数据量在大规模增加,且在用于训练机器学习模型之前必须进行处理。

处理文本数据可能会面临多种挑战,包括以下几种:

  • 存在成千上万种不同的单词。

  • 不同的语言带来了不同的挑战。

  • 文本数据通常在大小上有所不同。

有许多方法可以将文本数据转换为数值表示。一种方法是对单词进行独热编码,这就像你在练习 2.02中处理日期字段时做的那样,预处理非数值数据。然而,这在训练模型时会带来问题,因为如果数据集包含大量独特的单词,就会导致数据稀疏,从而可能导致训练速度缓慢并且模型可能不准确。此外,如果遇到一个新单词,而这个单词不在训练数据中,模型就无法使用该单词。

一种常用的方法是将整个文本转换为嵌入向量。已有预训练模型将原始文本转换为向量。这些模型通常在大量文本数据上训练。使用预训练模型的单词嵌入向量具有一些明显的优势:

  • 结果向量的大小是固定的。

  • 向量保持上下文信息,因此它们能受益于迁移学习。

  • 不需要对数据进行进一步的预处理,嵌入的结果可以直接输入到人工神经网络(ANN)中。

虽然 TensorFlow Hub 将在下一章中更深入地讲解,但下面是如何将预训练模型用作预处理步骤的示例。要加载预训练模型,您需要导入tensorflow_hub库。通过这样做,可以加载模型的 URL。然后,可以通过调用KerasLayer类将模型加载到环境中,KerasLayer类会将模型封装,使其可以像其他 TensorFlow 模型一样使用。可以如下创建:

import tensorflow_hub as hub
model_url = "url_of_model"
hub_layer = hub.KerasLayer(model_url, \
                           input_shape=[], dtype=tf.string, \
                           trainable=True)

输入数据的数据类型,由dtype参数指示,应作为输入传递给KerasLayer类,同时还需要一个布尔参数,指示权重是否可训练。一旦使用tensorflow_hub库加载了模型,就可以在文本数据上调用它,如下所示:

hub_layer(data)

这将通过预训练模型运行数据。输出将基于预训练模型的架构和权重。

在下面的练习中,您将学习如何加载包含文本字段的数据,批量处理数据集,并将预训练模型应用于文本字段,将该字段转换为嵌入向量。

注意

预训练模型可以在这里找到:tfhub.dev/google/tf2-preview/gnews-swivel-20dim/1

数据集可以在这里找到:archive.ics.uci.edu/ml/datasets/Drug+Review+Dataset+%28Drugs.com%29

练习 2.04:为 TensorFlow 模型加载文本数据

数据集drugsComTrain_raw.tsv包含与患者对特定药物的评价相关的信息,包括患者对药物的满意度评分以及与之相关的病情。在本练习中,您将加载文本数据进行批处理。您将应用一个来自 TensorFlow Hub 的预训练模型,对患者评论进行词嵌入。您需要只处理review字段,因为该字段包含文本数据。

执行以下步骤:

  1. 打开一个新的 Jupyter notebook 来实现这个练习。将文件保存为Exercise2-04.ipnyb

  2. 在新的 Jupyter Notebook 单元格中,导入 TensorFlow 库:

    import tensorflow as tf
    
  3. 使用库的make_csv_dataset函数创建一个 TensorFlow 数据集对象。将batch_size参数设置为1,并将field_delim参数设置为\t,因为数据集是制表符分隔的:

    df = tf.data.experimental.make_csv_dataset\
         ('../Datasets/drugsComTest_raw.tsv', \
          batch_size=1, field_delim='\t')
    
  4. 创建一个函数,将数据集对象作为输入,并对数据集进行洗牌、重复和批处理:

    def prep_ds(ds, shuffle_buffer_size=1024, \
                batch_size=32):
        # Shuffle the dataset
        ds = ds.shuffle(buffer_size=shuffle_buffer_size)
        # Repeat the dataset
        ds = ds.repeat()
        # Batch the dataset
        ds = ds.batch(batch_size)
        return ds
    
  5. 对您在步骤 3中创建的数据集对象应用该函数,设置batch_size等于5

    ds = prep_ds(df, batch_size=5)
    
  6. 获取第一批数据并打印出来:

    for x in ds.take(1):\
        print(x)
    

    您应该会看到类似以下的输出:

    图 2.14:来自数据集对象的一批数据

    图 2.14:来自数据集对象的一批数据

    输出表示输入数据的张量格式。

  7. 从 TensorFlow Hub 导入预训练的词嵌入模型,并创建一个 Keras 层:

    import tensorflow_hub as hub
    embedding = "https://tfhub.dev/google/tf2-preview"\
                "/gnews-swivel-20dim/1"
    hub_layer = hub.KerasLayer(embedding, input_shape=[], \
                               dtype=tf.string, \
                               trainable=True)
    
  8. 从数据集中取出一批数据,展平对应review字段的张量,应用预训练层并打印输出:

    for x in ds.take(1):\
        print(hub_layer(tf.reshape(x['review'],[-1])))
    

    这将显示以下输出:

    图 2.15:应用预训练模型后,评论列的一批数据    已应用于文本

图 2.15:应用预训练模型后,评论列的一批数据

上述输出表示了第一批药物评论的嵌入向量。具体的值乍一看可能没有太大意义,但嵌入中编码了基于数据集的信息,这些数据集是嵌入模型训练的基础。批处理大小为5,嵌入向量的大小为20,这意味着在应用预训练层后,得到的大小为5x20

在本练习中,您学习了如何导入可能包含各种数据类型的表格数据。您处理了review字段,并应用了预训练的词嵌入模型,将文本转换为数值张量。最终,您对文本数据进行了预处理和批处理,使其适合大规模训练。这是一种表示文本的方式,使其能够输入到 TensorFlow 的机器学习模型中。实际上,还可以使用其他预训练的词嵌入模型,这些模型可以在 TensorFlow Hub 上找到。在下一章中,您将进一步学习如何使用 TensorFlow Hub。

在本节中,你了解了如何为机器学习模型预处理文本数据的一种方法。实际上,你可以使用许多不同的方法来生成数值张量,例如,可以对单词进行独热编码、去除停用词、进行词干提取和词形还原,或者甚至做一些简单的操作,如统计每个评论中的单词数量。本节展示的方法具有优势,因为它简单易实施。此外,词嵌入方法能够结合文本中的上下文信息,而这些信息在其他方法中(如独热编码)难以编码。

最终,是否将任何领域知识应用于预处理步骤以保留尽可能多的上下文信息,取决于实践者自身。这将使任何后续模型能够学习特征和目标变量之间的潜在函数。

在接下来的章节中,你将学习如何加载和处理音频数据,以便这些数据可以用于 TensorFlow 模型。

音频处理

本节将演示如何批量加载音频数据,以及如何处理它以便用于训练机器学习模型。音频文件的预处理涉及一些高级信号处理步骤。这些步骤有些是可选的,但为了提供全面的音频数据处理方法,我们将呈现这些步骤。由于每个音频文件可能有数百 KB,因此你将利用批处理,就像处理图像数据时一样。批处理可以通过创建数据集对象来实现。创建数据集对象的一种通用方法是使用 TensorFlow 的 from_tensor_slice 函数。此函数通过沿张量的第一维切片来生成数据集对象,使用方式如下:

dataset = tf.data.Dataset\
            .from_tensor_slices([1, 2, 3, 4, 5])

可以通过 TensorFlow 将音频数据加载到 Python 环境中,方法是使用 read_file 函数将文件读取到内存中,然后使用 decode_wav 函数解码文件。在使用 decode_wav 函数时,必须传入样本率(即表示 1 秒钟数据点的数量)以及所需的通道。例如,如果传入 -1 作为所需通道的值,则将解码所有音频通道。导入音频文件的方式如下:

sample_rate = 44100
audio_data = tf.io.read_file('path/to/file')
audio, sample_rate = tf.audio.decode_wav\
                     (audio_data,\
                      desired_channels=-1,\
                      desired_samples=sample_rate)

与文本数据一样,你必须对数据进行预处理,以便生成的数值张量与数据的大小相匹配。这是通过在将数据转换到频域后对音频文件进行采样来实现的。音频采样可以看作是将音频文件切割成始终相同大小的片段。例如,一个 30 秒的音频文件可以切分成 30 个 1 秒钟的不重叠音频样本,同样,一个 15 秒钟的音频文件可以切分成 15 个 1 秒钟的不重叠样本。这样,最终你会得到 45 个大小相同的音频样本。

另一个常见的音频数据预处理步骤是将音频样本从时域转换到频域。在时域解释数据对于理解音频的强度或音量很有用,而频域则能帮助你发现哪些频率是存在的。这对于声音分类非常有用,因为不同的物体具有不同的特征声音,这些特征声音会出现在频域中。可以使用 stft 函数将音频数据从时域转换到频域。

该函数对输入数据进行短时傅里叶变换。函数的参数包括帧长度,这是一个整数值,表示窗口的长度(单位为样本);帧步长,这是一个整数值,描述了每次步进的样本数;以及 快速傅里叶变换 (FFT) 长度,这是一个整数值,表示要应用的 FFT 长度。频谱图是短时傅里叶变换的绝对值,因为它对视觉解释非常有用。可以按以下方式创建短时傅里叶变换和频谱图:

stfts = tf.signal.stft(audio, frame_length=1024,\
                       frame_step=256,\
                       fft_length=1024)
spectrograms = tf.abs(stfts)

另一个可选的预处理步骤是生成 梅尔频率倒谱系数 (MFCCs)。顾名思义,MFCC 是梅尔频率倒谱的系数。倒谱是音频信号短时功率谱的表示。MFCC 常用于语音识别和音乐信息检索等应用。因此,理解每一步 MFCC 的生成过程可能并不重要,但理解它们可以作为预处理步骤来增加音频数据管道的信息密度是非常有益的。

MFCC 是通过创建一个矩阵,将线性尺度映射到梅尔尺度来生成的。这个矩阵可以通过使用 linear_to_mel_weight_matrix 来创建,并传入生成的梅尔频谱中的带数、源频谱图中的频带数、采样率,以及要包含在梅尔频谱中的最低和最高频率。一旦线性到梅尔的权重矩阵创建完成,就可以使用 tensordot 函数在第一个轴上对频谱图进行张量收缩。

接下来,应用对值的对数转换以生成对数梅尔频谱图。最后,可以应用 mfccs_from_log_mel_spectrograms 函数,传入对数梅尔频谱图来生成 MFCC。以下是这些步骤的应用方法:

lower_edge_hertz, upper_edge_hertz, num_mel_bins \
    = 80.0, 7600.0, 80
linear_to_mel_weight_matrix \
    = tf.signal.linear_to_mel_weight_matrix\
      (num_mel_bins, num_spectrogram_bins, sample_rate, \
       lower_edge_hertz, upper_edge_hertz)
mel_spectrograms = tf.tensordot\
                   (spectrograms, \
                    linear_to_mel_weight_matrix, 1)
mel_spectrograms.set_shape\
    (spectrograms.shape[:-1].concatenate\
    (linear_to_mel_weight_matrix.shape[-1:]))
log_mel_spectrograms = tf.math.log(mel_spectrograms + 1e-6)
mfccs = tf.signal.mfccs_from_log_mel_spectrograms\
        (log_mel_spectrograms)[..., :num_mfccs]

在接下来的练习中,你将了解如何处理音频数据。与之前的练习 2.03加载图像数据以进行批量处理,以及练习 2.04为 TensorFlow 模型加载文本数据类似,你将批量加载数据以提高训练效率和可扩展性。你将使用 TensorFlow 的通用 read_file 函数加载音频文件,然后使用 TensorFlow 的 decode_wav 函数解码音频数据。接着,你将创建一个函数,从每个音频样本中生成 MFCC(梅尔频率倒谱系数)。最后,将生成一个数据集对象,传递给 TensorFlow 模型进行训练。你将使用的数据集是 Google 的语音命令数据集,包含时长为 1 秒的单词发音。

注意

数据集可以在这里找到:packt.link/Byurf

练习 2.05:为 TensorFlow 模型加载音频数据

在本练习中,你将学习如何为批量处理加载音频数据。数据集 data_speech_commands_v0.02 包含人们发音单词 zero 的语音样本,时长恰好为 1 秒,采样率为 44.1 kHz,意味着每秒有 44,100 个数据点。你将应用一些常见的音频预处理技术,包括将数据转换到傅里叶域、对数据进行采样以确保数据与模型大小一致,并为每个音频样本生成 MFCC。这样将生成一个预处理的数据集对象,可以输入到 TensorFlow 模型进行训练。

执行以下步骤:

  1. 打开一个新的 Jupyter Notebook 来实现这个练习。将文件保存为 Exercise2-05.ipnyb

  2. 在一个新的 Jupyter Notebook 单元中,导入 tensorflowos 库:

    import tensorflow as tf
    import os
    
  3. 创建一个函数,分别使用 TensorFlow 的 read_filedecode_wav 函数加载音频文件,并返回结果张量的转置:

    def load_audio(file_path, sample_rate=44100):
        # Load audio at 44.1kHz sample-rate
        audio = tf.io.read_file(file_path)
        audio, sample_rate = tf.audio.decode_wav\
                             (audio,\
                              desired_channels=-1,\
                              desired_samples=sample_rate)
        return tf.transpose(audio)
    
  4. 使用 os.list_dir 将音频数据的路径作为列表加载:

    prefix = " ../Datasets/data_speech_commands_v0.02"\
            "/zero/"
    paths = [os.path.join(prefix, path) for path in \
             os.listdir(prefix)]
    
  5. 测试函数,通过加载列表中的第一个音频文件并绘制它来验证:

    import matplotlib.pyplot as plt
    audio = load_audio(paths[0])
    plt.plot(audio.numpy().T)
    plt.xlabel('Sample')
    plt.ylabel('Value')
    

    输出将如下所示:

    图 2.16:音频文件的可视化表示

    图 2.16:音频文件的可视化表示

    图示显示了语音样本的波形。在某一时刻的振幅对应声音的音量;高振幅表示高音量。

  6. 创建一个函数,从音频数据中生成 MFCC。首先,应用短时傅里叶变换,将音频信号作为第一个参数,帧长设置为1024作为第二个参数,帧步长设置为256作为第三个参数,FFT 长度作为第四个参数。然后,取结果的绝对值来计算频谱图。频谱图的 bin 数由短时傅里叶变换的最后一个维度长度给出。接下来,定义 mel 权重矩阵的上下限分别为807600,mel 的 bin 数为80。然后,使用 TensorFlow 的信号包中的linear_to_mel_weight_matrix计算 mel 权重矩阵。接着,通过张量收缩使用 TensorFlow 的tensordot函数,沿频谱图的第 1 轴与 mel 权重矩阵进行计算,得到 mel 频谱图。然后,对 mel 频谱图取对数,最后使用 TensorFlow 的mfccs_from_log_mel_spectrograms函数计算 MFCC。最后,从函数中返回 MFCC。

    def apply_mfccs(audio, sample_rate=44100, num_mfccs=13):
        stfts = tf.signal.stft(audio, frame_length=1024, \
                               frame_step=256, \
                               fft_length=1024)
        spectrograms = tf.abs(stfts)
        num_spectrogram_bins = stfts.shape[-1]#.value
        lower_edge_hertz, upper_edge_hertz, \
        num_mel_bins = 80.0, 7600.0, 80
        linear_to_mel_weight_matrix = \
          tf.signal.linear_to_mel_weight_matrix\
          (num_mel_bins, num_spectrogram_bins, \
           sample_rate, lower_edge_hertz, upper_edge_hertz)
        mel_spectrograms = tf.tensordot\
                           (spectrograms, \
                            linear_to_mel_weight_matrix, 1)
        mel_spectrograms.set_shape\
        (spectrograms.shape[:-1].concatenate\
        (linear_to_mel_weight_matrix.shape[-1:]))
        log_mel_spectrograms = tf.math.log\
                               (mel_spectrograms + 1e-6)
        #Compute MFCCs from log_mel_spectrograms
        mfccs = tf.signal.mfccs_from_log_mel_spectrograms\
                (log_mel_spectrograms)[..., :num_mfccs]
        return mfccs
    
  7. 应用该函数为你在步骤 5中加载的音频数据生成 MFCC:

    mfcc = apply_mfccs(audio)
    plt.pcolor(mfcc.numpy()[0])
    plt.xlabel('MFCC log coefficient')
    plt.ylabel('Sample Value')
    

    输出如下所示:

    图 2.17:音频文件 MFCC 的可视化表示

    图 2.17:音频文件 MFCC 的可视化表示

    上面的图表显示了 MFCC 值在x轴上的分布,以及音频样本在y轴上的不同点。MFCC 是原始音频信号的另一种表示方式,显示在步骤 5中,已被证明在语音识别相关应用中非常有用。

  8. 加载AUTOTUNE,以便可以使用 CPU 的所有可用线程。创建一个函数,接受数据集对象,打乱数据集,使用你在步骤 3中创建的函数加载音频数据,使用你在步骤 6中创建的函数生成 MFCC,重复数据集对象,进行批处理,并进行预取操作。使用AUTOTUNE来根据可用的 CPU 预取数据,并设置缓冲区大小:

    AUTOTUNE = tf.data.experimental.AUTOTUNE
    def prep_ds(ds, shuffle_buffer_size=1024, \
                batch_size=64):
        # Randomly shuffle (file_path, label) dataset
        ds = ds.shuffle(buffer_size=shuffle_buffer_size)
        # Load and decode audio from file paths
        ds = ds.map(load_audio, num_parallel_calls=AUTOTUNE)
        # generate MFCCs from the audio data
        ds = ds.map(apply_mfccs)
        # Repeat dataset forever
        ds = ds.repeat()
        # Prepare batches
        ds = ds.batch(batch_size)
        # Prefetch
        ds = ds.prefetch(buffer_size=AUTOTUNE)
        return ds
    
  9. 使用你在步骤 8中创建的函数生成训练数据集。为此,使用 TensorFlow 的from_tensor_slices函数创建数据集对象,并传入音频文件的路径。之后,你可以使用你在步骤 8中创建的函数:

    ds = tf.data.Dataset.from_tensor_slices(paths)
    train_ds = prep_ds(ds)
    
  10. 获取数据集的第一批并打印出来:

    for x in train_ds.take(1):\
        print(x)
    

    输出如下所示:

    图 2.18:生成 MFCC 后的一批音频数据

图 2.18:生成 MFCC 后的一批音频数据

输出显示了第一批 MFCC 频谱值的张量形式。

在这个练习中,你导入了音频数据。你处理了数据集并对数据集进行了批处理,以便它适合大规模训练。这个方法是一个综合性的方案,其中数据被加载并转换到频域,生成了频谱图,然后最终生成了 MFCC。

在下一个活动中,你将加载音频数据并取输入的绝对值,随后对值进行对数缩放。这将确保数据集中没有负值。你将使用与练习 2.05中使用的相同音频数据集,即 Google 的语音命令数据集。该数据集包含 1 秒钟长的单词发音。

活动 2.03:为批处理加载音频数据

在此活动中,你将加载音频数据进行批处理。所执行的音频预处理技术包括取绝对值并使用 1 加上该值的对数。这样可以确保结果值为非负且以对数形式缩放。最终结果将是一个可以输入到 TensorFlow 模型中进行训练的预处理数据集对象。

该活动的步骤如下:

  1. 打开一个新的 Jupyter 笔记本以实现此活动。

  2. 导入 TensorFlow 和os库。

  3. 创建一个函数,使用 TensorFlow 的read_file函数加载音频文件,然后使用decode_wav函数解码。返回函数的结果张量的转置。

  4. 使用os.list_dir将文件路径加载到音频数据列表中。

  5. 创建一个函数,该函数接受一个数据集对象,对其进行打乱,使用你在步骤 2中创建的函数加载音频,并对数据集应用绝对值和log1p函数。此函数将数据集中的每个值加上1,然后对结果应用对数。接下来,重复数据集对象,对其进行批处理,并使用等于批处理大小的缓冲区大小进行预取。

  6. 使用 TensorFlow 的from_tensor_slices函数创建一个数据集对象,并传入音频文件的路径。然后,将你在第 4 步中创建的函数应用到第 5 步中创建的数据集上。

  7. 获取数据集的第一批数据并打印出来。

  8. 绘制批次中的第一个音频文件。

    输出结果如下:

    图 2.19:活动 2.03 的预期输出

图 2.19:活动 2.03 的预期输出

注意

本活动的解决方案可以通过此链接找到。

在此活动中,你学习了如何批量加载和预处理音频数据。你使用了在练习 2.05中使用的大部分函数,加载数据并解码原始数据。练习 2.05活动 2.03之间的区别在于预处理步骤;练习 2.05涉及为音频数据生成 MFCC,而活动 2.03则涉及对数据进行对数缩放。两者展示了可以用于所有音频数据建模应用的常见预处理技术。

在这一部分,你探索了如何将音频数据批量加载以用于 TensorFlow 模型。这个全面的方法展示了许多高级信号处理技术,这些技术为希望将音频数据应用于自己项目的从业者提供了良好的起点。

摘要

在本章中,你学习了如何加载不同形式的数据并为各种数据类型执行一些预处理步骤。你首先处理的是以 CSV 文件形式呈现的表格数据。由于数据集仅由一个 CSV 文件组成,你使用了 pandas 库将文件加载到内存中。

然后,你继续对数据进行预处理,通过缩放字段并将所有字段转换为数值数据类型。这一点很重要,因为 TensorFlow 模型只能对数值数据进行训练,如果所有字段的尺度相同,训练过程的速度和准确性都会得到提升。

然后,你探索了如何加载图像数据。你将数据批处理,这样就不需要一次性加载整个数据集,这也让你能够对图像进行数据增强。图像增强是有用的,因为它增加了有效的训练示例数量,并且有助于让模型更加稳健。

接下来,你学习了如何加载文本数据并利用预训练模型。这帮助你将文本嵌入到向量中,这些向量保留了关于文本的上下文信息。这样,你就可以将文本数据输入到 TensorFlow 模型中,因为它们需要数值张量作为输入。

最后,最后一部分讲解了如何加载和处理音频数据,并展示了一些高级信号处理技术,包括生成 MFCC(梅尔频率倒谱系数),它们可以用于生成信息密集的数值张量,并可以输入到 TensorFlow 模型中。

加载和预处理数据,以便将其输入到机器学习模型中,是训练任何机器学习模型的一个重要且必要的第一步。在下一章中,你将探索 TensorFlow 提供的许多资源,这些资源有助于模型构建的开发。