Python 迁移学习实用指南:1~5(1)https://developer.aliyun.com/article/1426846
特征提取与工程
数据准备是任何 ML 项目中最长,最复杂的阶段。 在讨论 CRISP-DM 模型时,强调了同样的道理,在该模型中,我们提到了数据准备阶段如何占用 ML 项目中总时间的 60-70%。
对原始数据集进行预处理和处理后,下一步就是使其可用于 ML 算法。 特征提取是从原始属性派生特征的过程。 例如,在处理图像数据时进行特征提取是指从原始像素级数据中提取红色,蓝色和绿色通道信息作为特征。
同样,特征工程指的是使用数学变换从现有特征中推导其他特征的过程。 例如,特征工程将帮助我们从一个人的月收入中得出一个特征,例如年收入(基于用例要求)。 由于特征提取和工程设计都可以帮助我们将原始数据集转换为可用形式,因此 ML 实践者可以互换使用这些术语。
特征工程策略
将原始数据集(后期清理和整理)转换为可以由 ML 算法使用的特征的过程是领域知识,用例需求和特定技术的组合。 因此,特征描述了基础数据的各种表示形式,并且是特征工程过程的结果。
由于特征工程将原始数据转换为自身的有用表示形式,因此根据手头的数据类型,可以使用各种标准技术和策略。 在本节中,我们将讨论其中一些策略,简要介绍结构化和非结构化数据。
处理数值数据
数值数据通常以整数或浮点数的形式在数据集中可用,并且通常称为连续数值数据,通常是 ML 友好数据类型。 友好地说,我们指的是可以直接在大多数 ML 算法中摄取数字数据的事实。 但是,这并不意味着数字数据不需要其他处理和特征工程步骤。
有多种技术可以从数值数据中提取和工程化特征。 让我们看一下本节中的一些技术:
- 原始度量:这些数据属性或特征可以直接以其原始或本机格式使用,因为它们出现在数据集中而无需任何其他处理。 示例可以是年龄,身高或体重(只要数据分布不太偏斜!)。
- 计数:在某些情况下,诸如计数和频率之类的数字特征也很有用,以描绘重要的细节。 例如,信用卡欺诈事件的发生次数,歌曲收听次数,设备事件发生的次数等等。
- 二值化:我们经常可能想对出现或特征进行二值化,特别是仅指示是否存在特定项或属性(通常以 1 表示)或不存在(以 0 表示)。 这在构建推荐系统等场景中很有用。
- 合并:此技术通常将来自分析中的任何特征或属性的连续数值分组或分组为离散的分组,以使每个分组都覆盖特定的数值范围。 一旦获得了这些离散的箱子,我们就可以选择在其上进一步应用基于分类数据的特征工程。 存在各种装箱策略,例如固定宽度装箱和自适应装箱。
笔记本feature_engineering_numerical_and_categorical_data.ipynb
中提供了代码片段,以更好地理解数字数据的特征工程。
处理类别数据
常见的另一类重要数据是类别数据。 类别特征具有离散值,这些离散值属于一组有限的类。 这些类可以表示为文本或数字。 根据类别的顺序,类别特征分别称为标称和序数。
标称特征是具有有限值集合但没有任何自然顺序的那些类别特征。 例如,天气季节,电影类型等都是标称特征。 具有有限类集并具有自然顺序的类别特征称为序数特征。 例如,星期几,着装大小等都是常规的。
通常,特征工程中的任何标准工作流程都涉及将这些类别值转换为数字标签的某种形式,然后在这些值上应用某种编码方案。 流行的编码方案简要介绍如下:
- 单热编码:此策略为类别属性创建 n 个二元值列,假设存在 n 个不同类别
- 虚拟编码:此策略为类别属性创建 n-1 个二元值列,假定存在 n 个不同类别
- 特征散列:如果我们使用散列函数将多个特征添加到单个容器或存储桶(新特征)中,则可以利用此策略,当我们具有大量特征时通常会使用
笔记本feature_engineering_numerical_and_categorical_data.ipynb
中提供了代码片段,以更好地理解类别数据的特征工程。
处理图像数据
图像或视觉数据是丰富的数据源,可以使用 ML 算法和深度学习解决几个用例。 图像数据提出了很多挑战,需要经过仔细的预处理和转换,然后才能被任何算法使用。 对图像数据执行特征工程的一些最常见方法如下:
- 利用元数据信息或 EXIF 数据:诸如图像创建日期,修改日期,尺寸,压缩格式,用于捕获图像的设备,分辨率,焦距等属性。
- 像素和通道信息:每个图像都可以视为像素值矩阵或(
m, n, c
)矩阵,其中m
代表行数,n
代表列数,c
指向颜色通道(例如 R,G 和 B)。 然后可以根据算法和用例的要求将这种矩阵转换为不同的形状。 - 像素强度:有时很难处理具有多种颜色通道的彩色图像。 基于像素强度的特征提取依赖于基于强度的像素合并,而不是利用原始像素级别的值。
- 边缘检测:可以利用相邻像素之间对比度和亮度的急剧变化来识别物体边缘。 有不同的算法可用于边缘检测。
- 对象检测:我们采用边缘检测的概念并将其扩展到对象检测,然后将识别出的对象边界用作有用的特征。 同样,可以基于可用图像数据的类型来利用不同的算法。
基于深度学习的自动特征提取
到目前为止讨论的图像数据和其他类型的特征提取方法需要大量时间,精力和领域知识。 这种特征提取有其优点和局限性。
最近,人们已经研究了深度学习,特别是卷积神经网络(CNN),并将其用作自动特征提取器。 CNN 是针对图像数据进行优化的深度神经网络的特例。 卷积层是任何 CNN 的核心,它们基本上会在图像的高度和宽度上应用滑动滤镜。 像素值与这些滤镜的点积会生成跨多个周期学习的激活图。 在每个层次上,这些卷积层都有助于提取特定特征,例如边缘,纹理,角等。
深度学习和 CNN 还有很多,但是为了简单起见,让我们假设 CNN 在每一层都可以帮助我们自动提取不同的低级和高级特征。 反过来,这使我们免于手动执行特征提取。 我们将在接下来的章节中更详细地研究 CNN,并了解它们如何帮助我们自动提取特征。
处理文本数据
数值和分类特征就是我们所谓的结构化数据类型。 它们在 ML 工作流中更易于处理和利用。 文本数据是非结构化信息的重要来源之一,同样重要。 文本数据提出了与句法理解,语义,格式和内容有关的多个挑战。 文本数据还提出了转换为数字形式的问题,然后才能被 ML 算法使用。 因此,在进行文本数据的特征工程之前,需要进行严格的预处理和清理步骤。
文本预处理
在进行任何特征提取/工程设计之前,文本数据需要仔细而勤奋的预处理。 预处理文本数据涉及多个步骤。 以下是一些最广泛使用的文本数据预处理步骤的列表:
- 分词
- 转换为小写
- 删除特殊字符
- 缩放
- 停用词删除
- 拼写更正
- 词干和词条去除
在与用例有关的章节中,我们将详细介绍大多数技术。 为了更好地理解,读者可以参考《Python 实用机器学习》的第 4 章和第 7 章(Sarkar 及其合著者,Springer,2017 年)。
特征工程
通过上一节中提到的方法对文本数据进行正确处理后,我们就可以利用以下一些技术来进行特征提取和转换为数值形式。 Jupyter 笔记本feature_engineering_text_data.ipynb
中提供了可更好地理解文本数据特征的代码片段:
- 词袋模型:这是迄今为止最简单的文本数据向量化技术。 在此技术中,每个文档都表示为
N
维度上的向量,其中N
表示预处理语料库中所有可能的单词,向量的每个组成部分表示单词的存在或其频率。 - TF-IDF 模型:词袋模型在非常简单的假设下工作,有时会导致各种问题。 最常见的问题之一与某些单词由于频率很高而使其余单词黯然失色有关,因为词袋模型利用绝对频率进行向量化。 词频逆文档频率(TF-IDF)模型通过缩放/归一化绝对频率来缓解此问题。 在数学上,模型定义如下:
tfidf(w, D) = tf(W, D) * idf(w, D)
在这里,tfidf(w, D)
表示每个单词w
在文档D
中的 TF-IDF 分数,tf(w, D)
是中每个单词w
在文档D
中的词频,idf(w, D)
表示逆文档频率,计算为语料库C
中总文档数除以w
所在的文档数的对数转换。
除了词袋和 TF-IDF 外,还有其他转换,例如 N-gram 袋,以及单词嵌入,例如 Word2vec,GloVe 等。 我们将在后续章节中详细介绍其中的几个。
特征选择
特征提取和工程设计的过程可帮助我们从基础数据集中提取特征并生成特征。 在某些情况下,这会导致大量输入要处理的算法。 在这种情况下,怀疑输入中的许多特征可能是多余的,并可能导致复杂的模型甚至过拟合。 特征选择是从可用/生成的完整特征集中识别代表性特征的过程。 预期所选特征集将包含所需信息,以使算法能够解决给定任务而不会遇到处理,复杂性和过拟合的问题。 特征选择还有助于更好地理解建模过程中使用的数据,并加快处理速度。
特征选择方法大致可分为以下三类:
- 过滤方法:顾名思义,这些方法可帮助我们根据统计得分对特征进行排名。 然后,我们选择这些特征的子集。 这些方法通常与模型输出无关,而是独立地评估特征。 基于阈值的技术和统计检验(例如相关系数和卡方检验)是一些受欢迎的选择。
- 包装器方法:这些方法对特征子集的不同组合的表现进行比较搜索,然后帮助我们选择表现最佳的子集。 向后选择和正向消除是用于特征选择的两种流行的包装方法。
- 嵌入式方法:这些方法通过了解哪个特征子集将是最好的,从而提供了前面两种方法中的最好方法。 正则化和基于树的方法是流行的选择。
特征选择是构建 ML 系统过程中的重要方面。 如果不谨慎处理,它也是造成系统偏差的主要来源之一。 读者应注意,应该使用与训练数据集分开的数据集来进行特征选择。 将训练数据集用于特征选择将始终导致过拟合,而将测试集用于特征选择则会高估模型的表现。
最受欢迎的库提供了多种特征选择技术。 诸如scikit-learn
之类的库提供了开箱即用的这些方法。 在后面的章节中,我们将看到并利用其中的许多内容。
总结
在任何旅程中,了解概念和技术的牢固基础和共同基础都非常重要。 通过本章有关机器学习基础知识的章节,我们试图实现这一目标。 在开始学习深度学习,迁移学习和更高级的概念之前,必须为 ML 概念奠定坚实的基础。 在本章中,我们涵盖了相当多的基础,并提供了更详细地研究概念的重要指示。
我们通过理解机器学习为何如此重要以及它是一个完全不同的范例来开始本章。 我们简要讨论了 AI,机器学习和深度学习之间的关系。 然后,本章继续介绍了不同的机器学习技术,例如有监督,无监督和强化学习。 我们详细讨论了通常使用哪些不同的监督和非监督方法。
本章还简要介绍了用于 ML 项目工作流程的 CRISP-DM 模型以及 ML 流水线。 我们还讨论了《权力的游戏》幻想世界中战斗数据集的 EDA,以应用不同的概念并了解 EDA 的重要性。 在本章的最后,介绍了特征提取和工程以及特征选择。
在接下来的章节中,我们将以这些概念为基础,并最终在涉及不同实际使用案例的章节中应用所学知识。 欢迎登机!
二、深度学习基础
本章从深度学习真正含义的最基本基础开始,然后深入到围绕神经网络的其他基本概念和术语,深入探讨了深度学习的基本知识。 将向读者概述神经网络的基本构建模块,以及如何训练深度神经网络。 涵盖模型训练的概念,包括激活函数,损失函数,反向传播和超参数调整策略。 这些基础概念对于正在尝试深度神经网络模型的初学者和经验丰富的数据科学家都将有很大的帮助。 我们特别关注如何建立具有 GPU 支持的强大的基于云的深度学习环境,以及设置内部深度学习环境的技巧。 对于希望自己构建大规模深度学习模型的读者来说,这将非常有用。 本章将涵盖以下主题:
- 什么是深度学习?
- 深度学习基础
- 建立具有 GPU 支持的强大的基于云的深度学习环境
- 建立具有 GPU 支持的强大的本地深度学习环境
- 神经网络基础
什么是深度学习?
在机器学习(ML)中,我们尝试自动发现用于将输入数据映射到所需输出的规则。 在此过程中,创建适当的数据表示形式非常重要。 例如,如果我们要创建一种将电子邮件分类为垃圾邮件/火腿的算法,则需要用数字表示电子邮件数据。 一个简单的表示形式可以是二元向量,其中每个组件从预定义的单词表中描述单词的存在与否。 同样,这些表示是与任务相关的,也就是说,表示可能会根据我们希望 ML 算法执行的最终任务而有所不同。
在前面的电子邮件示例中,如果我们要检测电子邮件中的情感,则不必标识垃圾邮件/火腿,而更有用的数据表示形式可以是二元向量,其中预定义词汇表由具有正极性或负极性的单词组成。 大多数 ML 算法(例如随机森林和逻辑回归)的成功应用取决于数据表示的质量。 我们如何获得这些表示? 通常,这些表示是人为制作的特征,通过做出一些明智的猜测来进行迭代设计。 此步骤称为特征工程,是大多数 ML 算法中的关键步骤之一。 支持向量机(SVM)或一般的内核方法,试图通过将数据的手工表示转换为更高维度的空间来创建更相关的数据表示,使得使用分类或回归来解决 ML 任务变得容易。 但是,SVM 很难扩展到非常大的数据集,并且在诸如图像分类和语音识别等问题上并不成功。 诸如随机森林和梯度提升机(GBMs)之类的集合模型创建了一组弱模型,这些模型专门用于很好地完成小任务,然后将这些弱模型以一些方式组合来产生最终输出。 当我们有非常大的输入尺寸时,它们工作得很好,而创建手工制作的特征是非常耗时的步骤。 总而言之,所有前面提到的 ML 方法都以浅浅的数据表示形式工作,其中涉及通过一组手工制作的特征进行数据表示,然后进行一些非线性转换。
深度学习是 ML 的一个子字段,在其中创建数据的分层表示。 层次结构的较高级别由较低级别的表示形式组成。 更重要的是,通过完全自动化 ML 中最关键的步骤(称为特征工程),可以从数据中自动学习这种表示层次。 在多个抽象级别上自动学习特征允许系统直接从数据中学习输入到输出的复杂表示形式,而无需完全依赖于人工制作的特征。
深度学习模型实际上是具有多个隐藏层的神经网络,它可以帮助创建输入数据的分层层次表示。 之所以称为深度,是因为我们最终使用了多个隐藏层来获取表示。 用最简单的术语来说,深度学习也可以称为分层特征工程(当然,我们可以做更多的事情,但这是核心原理)。 深度神经网络的一个简单示例可以是具有多个隐藏层的多层感知器(MLP)。 下图中考虑基于 MLP 的人脸识别系统。 它学习到的最低级别的特征是对比度的一些边缘和图案。 然后,下一层能够使用那些局部对比的图案来模仿眼睛,鼻子和嘴唇。 最后,顶层使用这些面部特征创建面部模板。 深度网络正在组成简单的特征,以创建越来越复杂的特征,如下图所示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eF14sl5y-1681567233313)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/32d3a718-5dc8-4ced-a248-bf868068ea3c.png)]
为了理解深度学习,我们需要对神经网络的构建模块,如何训练这些网络以及如何将这样的训练算法扩展到非常大的深度网络有一个清晰的了解。 在深入探讨有关神经网络的更多细节之前,让我们尝试回答一个问题:为什么现在要进行深度学习? 神经网络的理论,甚至是卷积神经网络(CNN)都可以追溯到 1990 年代。 他们之所以变得越来越受欢迎的原因归结于以下三个原因:
- 高效硬件的可用性:摩尔定律使 CPU 具有更好,更快的处理能力和计算能力。 除此之外,GPU 在大规模计算数百万个矩阵运算中也非常有用,这是任何深度学习模型中最常见的运算。 诸如 CUDA 之类的 SDK 的可用性已帮助研究社区重写了一些可高度并行化的作业,以在少数 GPU 上运行,从而取代了庞大的 CPU 集群。 模型训练涉及许多小的线性代数运算,例如矩阵乘法和点积,这些运算在 CUDA 中非常有效地实现以在 GPU 中运行。
- 大型数据源的可用性和更便宜的存储:现在,我们可以免费访问大量带标签的文本,图像和语音训练集。
- 用于训练神经网络的优化算法的进展:传统上,只有一种算法可用于学习神经网络中的权重,梯度下降或随机梯度下降(SGD)。 SGD 具有一些局限性,例如卡在局部最小值和收敛速度较慢,这些都可以通过较新的算法来克服。 我们将在后面的“神经网络基础知识”的后续部分中详细讨论这些算法。
深度学习框架
深度学习广泛普及和采用的主要原因之一是 Python 深度学习生态系统,它由易于使用的开源深度学习框架组成。 但是,考虑到新框架如何不断发布以及旧框架将要寿终正寝,深度学习的格局正在迅速变化。 深度学习爱好者可能知道 Theano 是由 Yoshua Bengio 领导的 MILA 创建的第一个也是最受欢迎的深度学习框架。 不幸的是,最近宣布,在 Theano 的最新版本(1.0)于 2017 年发布之后,对 Theano 的进一步开发和支持将结束。因此,了解那里可以利用哪些框架来实现和解决问题至关重要。 深度学习。 这里要记住的另一点是,几个组织本身正在建立,获取和启动这些框架(通常试图在更好的功能,更快的执行等方面相互竞争),以使每个人都受益。 下图展示了截至 2018 年最受欢迎的一些深度学习框架:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-d7p6aSMh-1681567233313)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/7ff92d2e-11bf-4c54-b366-f0f8d512d881.png)]
您还可以在迈向数据科学了解更多。 让我们简要看看一些最受欢迎的深度学习框架:
- Theano:默认情况下,Theano 是一个低级框架,可对多维数组(现在通常称为张量)进行高效的数值计算。 Theano 非常稳定,语法与 TensorFlow 非常相似。 它确实具有 GPU 支持,但功能有限,特别是如果我们要使用多个 GPU。 由于其在 1.0 之后的开发和停止支持,如果您打算将 theano 用于深度学习实现,则应格外小心。
- TensorFlow:这可能是最流行(或至少最流行)的深度学习框架。 它由 Google Brain 创建并于 2015 年开源,迅速吸引了 ML,深度学习研究人员,工程师和数据科学家的关注。 尽管初始发行版的表现存在问题,但它仍处于积极开发中,并且每个发行版都在不断完善。 TensorFlow 支持基于多 CPU 和 GPU 的执行,并支持多种语言,包括 C++,Java,R 和 Python。 它仅用于支持符号编程样式来构建深度学习模型,该模型稍微复杂一些,但是自 v1.5 起广泛采用,它开始支持更流行且易于使用的命令式编程样式(也称为立即执行)。 TensorFlow 通常是类似于 Theano 的低级库,但也具有利用高级 API 进行快速原型设计和开发的功能。 TensorFlow 的重要部分还包括
tf.contrib
模块,该模块包含各种实验功能,包括 Keras API 本身! - Keras:如果发现自己对利用底层深度学习框架来解决问题感到困惑,则可以始终依靠 Keras! 具有不同技能的人们广泛使用此框架,包括可能不是核心开发人员的科学家。 这是因为 Keras 提供了一个简单,干净且易于使用的高级 API,用于以最少的代码构建有效的深度学习模型。 这样做的好处是可以将其配置为在包括 theano 和 TensorFlow 在内的多个低级深度学习框架(称为后端)之上运行。 可通过 keras.io 访问 Keras 文档,并且非常详细。
- Caffe:这也是伯克利视觉与学习中心以 C++ (包括 Python 绑定)开发的第一个且相对较旧的深度学习框架之一。 关于 Caffe 的最好之处在于,它作为 Caffe Model Zoo 的一部分提供了许多预训练的深度学习模型。 Facebook 最近开放了 Caffe2 的源代码,它基于 Caffe 进行了改进,并且比其前身更易于使用。
- PyTorch:Torch 框架是用 Lua 编写的,非常灵活和快速,通常可以带来巨大的表现提升。 PyTorch 是用于构建深度学习模型的基于 Python 的框架,它从 Torch 汲取了灵感。 它不仅是 Torch 的扩展或 Python 包装器,而且本身就是一个完整的框架,从而改进了 Torch 框架架构的各个方面。 这包括摆脱容器,利用模块以及表现改进(例如内存优化)。
- CNTK:Cognitive Toolkit 框架已由 Microsoft 开源,并且支持 Python 和 C++ 。 语法与 Keras 非常相似,并且支持多种模型架构。 尽管不是很流行,但这是 Microsoft 内部用于其几种认知智能功能的框架。
- MXNet:这是由分布式机器学习社区(DMLC)开发的,该包是非常受欢迎的 XGBoost 包的创建者。 现在这是一个官方的 Apache Incubator 项目。 MXNet 是最早支持各种语言(包括 C++,Python,R 和 Julia)以及多种操作系统(包括 Windows)的深度学习框架之一,而其他 Windows 常常会忽略该框架。 该框架非常高效且可扩展,并支持多 GPU。 因此,它已成为 Amazon 选择的深度学习框架,并为此开发了一个高级接口,称为 Gluon。
- Gluon:这是一个高级深度学习框架,或者说是接口,可以在 MXNet 和 CNTK 的基础上加以利用。 Gluon 由 Amazon AWS 和 Microsoft 联合开发,与 Keras 非常相似,可以被视为直接竞争对手。 然而,它声称它将随着时间的推移支持更多的低层深度学习框架,并具有使人工智能(AI)民主化的愿景。 Gluon 提供了一个非常简单,干净和简洁的 API,任何人都可以使用它以最少的代码轻松构建深度学习架构。
- BigDL:将 BigDL 视为大规模的大数据深度学习! 该框架由 Intel 开发,可以在 Apache Spark 之上利用,以在 Hadoop 集群上以分布式方式构建和运行深度学习模型,作为 Spark 程序。 它还利用非常流行的英特尔数学内核库(MKL)来提高表现并提高表现。
上面的框架列表绝对不是深度学习框架的详尽列表,但是应该使您对深度学习领域中的内容有个很好的了解。 随意探索这些框架,并根据最适合您的情况选择任何一个。
永远记住,有些框架的学习曲线很陡峭,所以如果花时间学习和利用它们,不要灰心。 尽管每个框架都有各自的优点和缺点,但您应始终将更多的精力放在要解决的问题上,然后利用最适合解决问题的框架。
建立具有 GPU 支持的基于云的深度学习环境
深度学习在带有 CPU 的标准单 PC 设置中效果很好。 但是,一旦您的数据集开始增加大小,并且模型架构开始变得更加复杂,您就需要开始考虑在强大的深度学习环境中进行投资。 主要期望是该系统可以有效地构建和训练模型,花费较少的时间来训练模型,并且具有容错能力。 大多数深度学习计算本质上是数百万个矩阵运算(数据表示为矩阵),并且可以并行进行快速计算。 事实证明,GPU 在这方面可以很好地工作。 您可以考虑建立一个强大的基于云的深度学习环境,甚至是一个内部环境。 让我们看看如何在本节中建立一个强大的基于云的深度学习环境。
涉及的主要组件如下:
- 选择云提供商
- 设置您的虚拟服务器
- 配置您的虚拟服务器
- 安装和更新深度学习依赖项
- 访问您的深度学习云环境
- 在您的深度学习环境中验证 GPU 的启用
让我们更详细地研究这些组件中的每个组件,并逐步执行过程,以帮助您建立自己的深度学习环境。
选择云提供商
如今,有多家云提供商的价格可承受且具有竞争力。 我们希望利用平台即服务(PaaS)功能来管理数据,应用和基本配置。
下图显示了一些流行的云提供商:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ug8OpLlD-1681567233314)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/a1ec2d70-f56a-42f8-8ac8-08a88b943061.png)]
受欢迎的提供商包括亚马逊的 AWS,微软的 Azure 和 Google 的 Google 云平台(GCP)。 就本教程和本书而言,我们将利用 AWS。
设置您的虚拟服务器
您需要获取一个 AWS 账户才能执行本节中的其余步骤。 如果您还没有帐户,请转到这里创建一个帐户。 准备就绪后,您可以登录这里来登录您的帐户并导航到 AWS EC2 控制面板,该工具利用了弹性计算云(EC2)服务,这是 Amazon 云计算服务的基础。 到达那里后,请记住选择一个您选择的区域(我通常与美国东部一起去),然后单击“启动实例”以启动在云上创建新虚拟服务器的过程:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BQGGy2gz-1681567233314)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/38d54157-0b1a-4a50-bced-6460281a2b6f.png)]
单击启动实例按钮应带您到该页面,以选择您自己的 Amazon Machine Image(AMI)。 通常,AMI 由构建虚拟服务器所需的各种软件配置组成。 它包括以下内容:
- 实例的根卷的模板,其中包括服务器的操作系统,应用和其他配置设置。
- 启动许可设置,用于控制哪些 AWS 账户可以使用 AMI 启动实例。
- 块设备映射,用于指定启动实例时要附加到实例的存储卷。 您所有的数据都在这里!
我们将利用专门用于深度学习的预构建 AMI,因此我们不必花时间进行额外的配置和管理。 前往 AWS Marketplace 并选择深度学习 AMI(Ubuntu):
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ncC9ilsy-1681567233314)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/35852910-b11e-45b5-a94f-f0cf8df4d9ac.png)]
选择 AMI 之后,您需要选择实例类型。 对于支持 GPU 的深度学习,我们建议使用 p2.xlarge 实例,该实例功能强大且经济实惠,每小时使用成本约为 0.90 美元(截至 2018 年)。
P2 实例最多可提供 16 个 NVIDIA K80 GPU,64 个 vCPU 和 732 GiB 主机内存,以及总共 192 GB 的 GPU 内存,如以下屏幕快照所示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JTcRIaG9-1681567233314)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/55556fe2-bd04-47ea-a9c6-9660475b4950.png)]
接下来是配置实例详细信息。 除非希望启动多个实例,指定子网首选项以及指定关闭行为,否则可以保留默认设置。
下一步涉及添加存储详细信息。 通常,您具有根卷,可以在根卷中根据需要增加其大小,并添加额外的弹性块存储(EBS)卷以增加磁盘空间。
然后,我们看一下是否需要添加标签(区分大小写和键值对)。 目前我们不需要这个,所以我们跳过它。
我们将重点放在配置安全组的下一步上,特别是如果您想通过利用功能强大的 Jupyter 笔记本从外部访问深度学习设置。 为此,我们创建一个新的安全组并创建一个 Custom TCP 规则以打开并启用对端口8888
的访问,如下所示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cSnE3RMD-1681567233314)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/79fc8d9c-a2fb-49d6-8510-922dafbd2317.png)]
请注意,此规则通常允许任何 IP 监听您实例(我们将在其中运行 Jupyter 笔记本的实例)上的端口(8888
)。 如果需要,可以更改此设置,仅添加特定 PC 或笔记本电脑的 IP 地址,以提高安全性。 除此之外,我们稍后还将为 Jupyter 笔记本添加一个额外的密码保护功能,以提高安全性。
最后,您将需要通过创建密钥对(公钥和私钥)来启动实例,以安全地连接到实例。 如果您没有现有的密钥对,则可以创建一个新的密钥对,将私钥文件安全地存储到磁盘上,然后启动实例,如以下屏幕快照所示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ntwAkMIp-1681567233315)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/496b8ebd-2671-47eb-9222-c5ba6849f120.png)]
请注意,虚拟服务器启动和启动可能需要几分钟,因此您可能需要稍等片刻。 通常,您可能会发现由于帐户的限制或容量不足而导致实例启动失败。
如果遇到此问题,您可以请求增加使用的特定实例类型的限制(在我们的例子中为p2.xlarge
):
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NLZ2dCK7-1681567233315)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/75eb8b32-425b-4c71-aa65-fcf126587aca.png)]
通常,AWS 会在不到 24 小时内响应并批准您的请求,因此您可能需要稍等片刻才能获得批准,然后才可以启动实例。 启动实例后,您可以签出“实例”部分并尝试连接到该实例:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-T5VzfKEZ-1681567233315)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/2c2a21b9-8c3c-4008-802f-2ed5354d6f91.png)]
您可以使用本地系统中的命令提示符或终端(之前已存储了先前的私有 AWS 密钥)来立即连接到实例:
[DIP.DipsLaptop]> ssh -i "my-dl-box.pem" ubuntu@ec2-xxxxx.compute-1.amazonaws.com Warning: Permanently added 'ec2-xxxxx.compute-1.amazonaws.com' (RSA) to the list of known hosts. ======================================================================= Deep Learning AMI for Ubuntu ======================================================================= The README file for the AMI : /home/ubuntu/src/AMI.README.md Welcome to Ubuntu 14.04.5 LTS (GNU/Linux 3.13.0-121-generic x86_64) Last login: Sun Nov 26 09:46:05 2017 from 10x.xx.xx.xxx ubuntu@ip-xxx-xx-xx-xxx:~$
因此,这使您能够成功登录到自己的基于云的深度学习服务器!
配置您的虚拟服务器
让我们设置一些基本配置,以利用 Jupyter 笔记本的功能在虚拟服务器上进行分析和深度学习建模,而无需始终在终端上进行编码。 首先,我们需要设置 SSL 证书。 让我们创建一个新目录:
ubuntu@ip:~$ mkdir ssl ubuntu@ip:~$ cd ssl ubuntu@ip:~/ssl$
进入目录后,我们将利用 OpenSSL 创建新的 SSL 证书:
ubuntu@ip:~/ssl$ sudo openssl req -x509 -nodes -days 365 -newkey rsa:1024 -keyout "cert.key" -out "cert.pem" -batch Generating a 1024 bit RSA private key ......++++++ ...++++++ writing new private key to 'cert.key' ----- ubuntu@ip:~/ssl2$ ls cert.key cert.pem
现在,我们需要在前面提到的 Jupyter 笔记本中添加基于密码的安全性的附加层。 为此,我们需要修改 Jupyter 的默认配置设置。 如果您没有 Jupyter 的config
文件,则可以使用以下命令生成它:
$ jupyter notebook --generate-config
要为笔记本计算机启用基于密码的安全性,我们需要首先生成一个密码及其哈希。 我们可以如下利用Ipython.lib
中的passwd()
函数:
ubuntu@ip:~$ ipython Python 3.4.3 (default, Nov 17 2016, 01:08:31) Type 'copyright', 'credits' or 'license' for more information IPython 6.1.0 -- An enhanced Interactive Python. Type '?' for help. In [1]: from IPython.lib import passwd In [2]: passwd() Enter password: Verify password: Out[2]: 'sha1:e9ed12b73a30:142dff0cdcaf375e4380999a6ca17b47ce187eb6' In [3]: exit ubuntu@:~$
输入密码并进行验证后,该函数将向您返回一个哈希值,即您的密码哈希值(在这种情况下,我键入的密码密钥实际上是单词password
,因此您绝对不应使用!)。 复制并保存该哈希值,因为我们很快将需要它。
接下来,启动您喜欢的文本编辑器以编辑 Jupyter config
文件,如下所示:
ubuntu@ip:~$ vim ~/.jupyter/jupyter_notebook_config.py # Configuration file for jupyter-notebook. c = get_config() # this is the config object c.NotebookApp.certfile = u'/home/ubuntu/ssl/cert.pem' c.NotebookApp.keyfile = u'/home/ubuntu/ssl/cert.key' c.IPKernelApp.pylab = 'inline' c.NotebookApp.ip = '*' c.NotebookApp.open_browser = False c.NotebookApp.password = 'sha1:e9ed12b73a30:142dff0cdcaf375e4380999a6ca17b47ce187eb6' # replace this # press i to insert new text and then press 'esc' and :wq to save and exit ubuntu@ip:~$
现在,在开始构建模型之前,我们将研究实现深度学习的一些基本依赖项。
安装和更新深度学习依赖项
深度学习有几个主要方面,并且针对 Python 利用 GPU 支持的深度学习。 我们将尽力介绍基本知识,但可以根据需要随时参考其他在线文档和资源。 您也可以跳过这些步骤,转到下一部分,以测试服务器上是否已启用启用 GPU 的深度学习。 较新的 AWS 深度学习 AMI 设置了支持 GPU 的深度学习。
但是,通常设置不是最好的,或者某些配置可能是错误的,因此(如果您看到深度学习没有利用您的 GPU,(从下一部分的测试中),您可能需要遍历这些知识。 您可以转到“访问深度学习云环境”和“验证深度学习环境上的 GPU 启用”部分,以检查 Amazon 提供的默认设置是否有效。 然后,您无需麻烦执行其余步骤!
首先,您需要检查是否已启用 Nvidia GPU,以及 GPU 的驱动程序是否已正确安装。 您可以利用以下命令进行检查。 请记住,p2.x 通常配备有 Tesla GPU:
ubuntu@ip:~$ sudo lshw -businfo | grep -i display pci@0000:00:02.0 display GD 5446 pci@0000:00:1e.0 display GK210GL [Tesla K80] ubuntu@ip-172-31-90-228:~$ nvidia-smi
如果正确安装了驱动程序,则应该看到类似于以下快照的输出:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pGoZcP3W-1681567233315)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/9da92d67-d3ef-48f5-9ea0-369abb747e48.png)]
如果出现错误,请按照以下步骤安装 Nvidia GPU 驱动程序。 切记根据您使用的 OS 使用其他驱动程序链接。 我有一个较旧的 Ubuntu 14.04 AMI,为此,我使用了以下命令:
# check your OS release using the following command ubuntu@ip:~$ lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 14.04.5 LTS Release: 14.04 Codename: trusty # download and install drivers based on your OS ubuntu@ip:~$ http://developer.download.nvidia.com/compute/cuda/repos/ubuntu1404/ x86_64/cuda-repo-ubuntu1404_8.0.61-1_amd64.deb ubuntu@ip:~$ sudo dpkg -i ./cuda-repo-ubuntu1404_8.0.61-1_amd64.deb ubuntu@ip:~$ sudo apt-get update ubuntu@ip:~$ sudo apt-get install cuda -y # Might need to restart your server once # Then check if GPU drivers are working using the following command ubuntu@ip:~$ nvidia-smi
如果您能够根据之前的命令查看驱动程序和 GPU 硬件详细信息,则说明驱动程序已成功安装! 现在,您可以集中精力安装 Nvidia CUDA 工具包。 通常,CUDA 工具包为我们提供了一个用于创建高表现 GPU 加速应用的开发环境。 这就是用来优化和利用我们 GPU 硬件的全部功能的工具。 您可以在这个页面上找到有关 CUDA 的更多信息并下载工具包。
请记住,CUDA 非常特定于版本,并且我们的 Python 深度学习框架的不同版本仅与特定 CUDA 版本兼容。 我将在本章中使用 CUDA 8。 如果已经为您安装了 CUDA,并且与服务器上的深度学习生态系统一起正常工作,请跳过此步骤。
要安装 CUDA,请运行以下命令:
ubuntu@ip:~$ wget https://s3.amazonaws.com/personal-waf/cuda_8.0.61_375.26_linux.run ubuntu@ip:~$ sudo rm -rf /usr/local/cuda* ubuntu@ip:~$ sudo sh cuda_8.0.61_375.26_linux.run # press and hold s to skip agreement and also make sure to select N when asked if you want to install Nvidia drivers # Do you accept the previously read EULA? # accept # Install NVIDIA Accelerated Graphics Driver for Linux-x86_64 361.62? # ************************* VERY KEY **************************** # ******************** DON"T SAY Y ****************************** # n # Install the CUDA 8.0 Toolkit? # y # Enter Toolkit Location # press enter # Do you want to install a symbolic link at /usr/local/cuda? # y # Install the CUDA 8.0 Samples? # y # Enter CUDA Samples Location # press enter # Installing the CUDA Toolkit in /usr/local/cuda-8.0 … # Installing the CUDA Samples in /home/liping … # Copying samples to /home/liping/NVIDIA_CUDA-8.0_Samples now… # Finished copying samples.
一旦安装了 CUDA,我们还需要安装 cuDNN。 该框架也由 Nvidia 开发,代表 CUDA 深度神经网络(cuDNN)库。 本质上,该库是 GPU 加速的库,由用于深度学习和构建深度神经网络的多个优化原语组成。 cuDNN 框架为标准深度学习操作和层(包括常规激活层,卷积和池化层,归一化和反向传播)提供了高度优化和优化的实现! 该框架的目的是加快深度学习模型的训练和表现,特别是针对 Nvidia GPU 的深度学习模型。 您可以在这个页面上找到有关 cuDNN 的更多信息。 让我们使用以下命令安装 cuDNN:
ubuntu@ip:~$ wget https://s3.amazonaws.com/personal-waf/cudnn-8.0- linux-x64-v5.1.tgz ubuntu@ip:~$ sudo tar -xzvf cudnn-8.0-linux-x64-v5.1.tgz ubuntu@ip:~$ sudo cp cuda/include/cudnn.h /usr/local/cuda/include ubuntu@ip:~$ sudo cp cuda/lib64/libcudnn* /usr/local/cuda/lib64 ubuntu@ip:~$ sudo chmod a+r /usr/local/cuda/include/cudnn.h /usr/local/cuda/lib64/libcudnn*
完成后,请记住使用您喜欢的编辑器(我们使用vim
)将以下几行添加到~/.bashrc
的末尾:
ubuntu@ip:~$ vim ~/.bashrc # add these lines right at the end and press esc and :wq to save and # quit export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/usr/local/cuda/lib64:/usr/local/cuda /extras/CUPTI/lib64" export CUDA_HOME=/usr/local/cuda export DYLD_LIBRARY_PATH="$DYLD_LIBRARY_PATH:$CUDA_HOME/lib" export PATH="$CUDA_HOME/bin:$PATH" ubuntu@ip:~$ source ~/.bashrc
通常,这会处理我们 GPU 的大多数必需依赖项。 现在,我们需要安装并设置 Python 深度学习依赖项。 通常,AWS AMI 随 Anaconda 发行版一起安装。 但是,如果它不存在,您可以始终参考这里以根据 Python 和 OS 版本下载您选择的发行版。 通常,我们使用 Linux / Windows 和 Python3 并利用本书中的 TensorFlow 和 Keras 深度学习框架。 在 AWS AMI 中,可能会安装不兼容的框架版本,这些框架版本不适用于 CUDA,或者可能是纯 CPU 版本。 以下命令安装 TensorFlow 的 GPU 版本,该版本在 CUDA 8 上最有效:
# uninstall previously installed versions if any ubuntu@ip:~$ sudo pip3 uninstall tensorflow ubuntu@ip:~$ sudo pip3 uninstall tensorflow-gpu # install tensorflow GPU version ubuntu@ip:~$ sudo pip3 install --ignore-installed --upgrade https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow_gpu-1.2.0-cp34-cp34m-linux_x86_64.whl
接下来,我们需要将 Keras 升级到最新版本,并删除所有剩余的config
文件:
ubuntu@ip:~$ sudo pip install keras --upgrade ubuntu@ip:~$ sudo pip3 install keras --upgrade ubuntu@ip:~$ rm ~/.keras/keras.json
现在,我们几乎准备开始利用云上的深度学习设置。 紧紧抓住!
访问您的深度学习云环境
我们真的不想一直坐在服务器上的终端并在其中进行编码。 由于我们要利用 Jupyter 笔记本进行交互式开发,因此我们将从本地系统访问云服务器上的笔记本。 为此,我们首先需要在远程实例上启动 Jupyter 笔记本服务器。
登录到您的虚拟服务器并启动 Jupyter 笔记本服务器:
[DIP.DipsLaptop]> ssh -i my-dl-box.pem ubuntu@ec2-xxxxx.compute-1.amazonaws.com =================================== Deep Learning AMI for Ubuntu =================================== Welcome to Ubuntu 14.04.5 LTS (GNU/Linux 3.13.0-121-generic x86_64) Last login: Sun Feb 25 18:23:47 2018 from 10x.xx.xx.xxx # navigate to a directory where you want to store your jupyter notebooks ubuntu@ip:~$ cd notebooks/ ubuntu@ip:~/notebooks$ jupyter notebook [I 19:50:13.372 NotebookApp] Writing notebook server cookie secret to /run/user/1000/jupyter/notebook_cookie_secret [I 19:50:13.757 NotebookApp] Serving notebooks from local directory: /home/ubuntu/notebooks [I 19:50:13.757 NotebookApp] 0 active kernels [I 19:50:13.757 NotebookApp] The Jupyter Notebook is running at: https://[all ip addresses on your system]:8888/ [I 19:50:13.757 NotebookApp] Use Control-C to stop this server and shut down all kernels (twice to skip confirmation).
现在,我们需要在本地实例上启用端口转发,以便从本地计算机的浏览器访问服务器笔记本。 利用以下语法:
sudo ssh -i my-dl-box.pem -N -f -L local_machine:local_port:remote_machine:remote_port ubuntu@ec2-xxxxx.compute-1.amazonaws.com
这将开始将本地计算机的端口(在我的情况下为8890
)转发到远程虚拟服务器的端口8888
。 以下是我用于设置的内容:
[DIP.DipsLaptop]> ssh -i "my-dl-box.pem" -N -f -L localhost:8890:localhost:8888 ubuntu@ec2-52-90-91-166.compute-1.amazonaws.com
这也称为 SSH 隧道。 因此,一旦开始转发,请转到本地浏览器并导航到localhost
地址https://localhost:8890
,我们将其转发到虚拟服务器中的远程笔记本服务器。 确保您在地址中使用https
,否则会收到 SSL 错误。
如果到目前为止您已正确完成所有操作,则应在浏览器中看到一个警告屏幕,并且按照以下屏幕截图中的步骤进行操作,则在任何笔记本上工作时,都应该会看到熟悉的 Jupyter 用户界面:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ble9W7xt-1681567233316)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/484ebcb5-b14e-4c76-945e-b6562391ba5f.png)]
您可以放心地忽略“您的连接不是私人警告”; 之所以显示它,是因为我们自己生成了 SSL 证书,并且尚未得到任何可信机构的验证。
在您的深度学习环境中验证 GPU 的启用
最后一步是确保一切正常,并且我们的深度学习框架正在利用我们的 GPU(我们需要按小时支付!)。 您可以参考Test GPU enabling.ipynb
Jupyter 笔记本来测试所有代码。 我们将在这里详细介绍。 我们首先要验证的是keras
和tensorflow
是否已正确加载到我们的服务器中。 可以通过如下导入它们来验证:
import keras import tensorflow Using TensorFlow backend.
如果您看到前面的代码加载没有错误,那就太好了! 否则,您可能需要追溯以前执行的步骤,并在线搜索要获取的特定错误; 查看每个框架的 GitHub 存储库。
最后一步是检查tensorflow
是否已启用以使用我们服务器的 Nvidia GPU。 您可以使用以下测试对此进行验证:
In [1]: from tensorflow.python.client import device_lib ...: device_lib.list_local_devices() Out [1]: [name: "/cpu:0" device_type: "CPU" memory_limit: 268435456 locality { } incarnation: 9997170954542835749, name: "/gpu:0" device_type: "GPU" memory_limit: 11324823962 locality { bus_id: 1 } incarnation: 10223482989865452371 physical_device_desc: "device: 0, name: Tesla K80, pci bus id: 0000:00:1e.0"]
如果您观察到上述输出,则可以看到我们的 GPU 列在设备列表中,因此在训练我们的深度学习模型时它将利用相同的 GPU。 您已经在云上成功建立了强大的深度学习环境,您现在可以使用它使用 GPU 来更快地训练深度学习模型!
永远记住,AWS 按小时收费实例,并且您不希望在完成分析和构建模型后保持实例运行。 您始终可以根据需要从 EC2 控制台重新启动实例。
建立具有 GPU 支持的强大的本地深度学习环境
通常,用户或组织可能不希望利用云服务,尤其是在其数据敏感的情况下,因此要专注于构建本地深度学习环境。 这里的主要重点应该是投资于正确的硬件类型,以实现最佳表现并利用正确的 GPU 来构建深度学习模型。 关于硬件,特别强调以下方面:
- 处理器:如果您想宠爱自己,则可以投资 i5 或 i7 Intel CPU,或者 Intel Xeon。
- RAM:为您的内存至少投资 32 GB DDR4 或更好的 RAM。
- 磁盘:1 TB 硬盘非常好,您还可以投资最少 128 GB 或 256 GB 的 SSD 来快速访问数据!
- GPU:也许是深度学习中最重要的组件。 投资 NVIDIA GPU,以及拥有 8 GB 以上 GTX 1070 的所有产品。
您不应该忽略的其他事项包括主板,电源,坚固的外壳和散热器。
设置完钻机之后,对于软件配置,您可以重复上一部分中的所有步骤,但不包括云设置,您应该一切顺利!
神经网络基础
让我们尝试熟悉一下神经网络背后的一些基本概念,这些基本概念使所有深度学习模型都获得成功!
一个简单的线性神经元
线性神经元是深度神经网络的最基本组成部分。 可以如下图所示。 在这里,X = {x1, ... ,xn}
代表输入向量, w[i]
是神经元的权重。 给定一个包含一组输入目标值对的训练集,线性神经元尝试学习一种线性变换,该变换可以将输入向量映射到相应的目标值。 基本上,线性神经元通过线性函数W^T x = y
近似输入输出关系:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1TgiUQU7-1681567233316)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/9c4a31dd-9384-4d77-9229-5a45c60b24f9.png)]
简单线性神经元和简单非线性神经元的示意图
让我们尝试用这个简单的神经元为玩具问题建模。 员工 A 从自助餐厅购买午餐。 他们的饮食包括鱼,薯条和番茄酱。 他们每个人得到几个部分。 收银员只告诉他们一顿饭的总价。 几天后,他们能算出每份的价格吗?
好吧,这听起来像一个简单的线性编程问题,可以很容易地通过解析来解决。 让我们使用前面的线性神经单元来表示这个问题。 在这里,X = {x[fish], x[ketchup], x[chips]}
和我们有相应的权重(w[fish], w[ketchup], w[chips])
。
每个进餐价格对各部分的价格给出线性约束:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-efhO4WUD-1681567233316)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/04c9762f-de07-4d2a-885b-beee4afb50ae.png)]
假设t[n]
为真实价格,y[n]
由我们的模型估计的价格,由前面的线性方程式给出。 目标与我们的估计之间的剩余价格差为t[n] - y[n]
。 现在,不同餐点的这些残差可以为正或负,并且可以抵消,从而使总体误差为零。 处理此问题的一种方法是使用平方和残差:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-A2sgCpNW-1681567233316)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/a7a8c6fa-4111-49ce-bcd9-4c63458b427c.png)]
如果我们能够最大程度地减少此误差,则可以对每件商品的一组权重/价格进行很好的估计。 因此,我们得出了一个优化问题。 让我们首先讨论一些解决优化问题的方法。
基于梯度的优化
优化基本上涉及最小化或最大化某些函数f(x)
,其中x
是数值向量或标量。 在此,f(x)
被称为目标函数或准则。 在神经网络中,我们称其为成本函数,损失函数或误差函数。 在前面的示例中,我们要最小化的损失函数为E
。
假设我们有一个函数y = f(x)
,其中x
和y
是实数。 此函数的导数告诉我们此函数如何随x
的微小变化而变化。 因此,可以通过无穷大地更改x
来使用导数来减小函数的值。 假设对于x
,f'(x) > 0
。 这意味着,如果我们沿着x
的正数增加x
,则f(x)
将会增加,因此对于足够小的ε
,f(x-ε) < f(x)
。 注意f(x)
可以通过在导数的相反方向以小步长移动x
来减少:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-b93ZwRf3-1681567233316)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/1f3da55c-feb9-4e0a-80b3-65112938b1ab.png)]
函数值沿导数的相反方向或相反方向的变化方式
如果导数f'(x) < 0
,则导数不提供信息,我们需要朝哪个方向移动以达到函数最小值。 在局部最优(最小/最大)时,导数可以为零。 如果x
处的函数f(x)
的值小于所有相邻点,则将点称为局部最小值。 同样,我们可以定义一个局部最大值。 某些点既不能是最大值,也不能是最小值,但是导数f'(x)
在这些点上为零。 这些称为鞍点。 下图说明了f'(x) = 0
的三种情况:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xE8s86Ac-1681567233317)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/c7eb65b7-41d2-4873-943e-07764f579812.png)]
单个变量函数的最小,最大和鞍点。 在所有三个突出显示的点上导数f'(x) = 0
在x
的所有可能值中达到f
的最小值的点称为全局最小值。 一个函数可以具有一个或多个全局最小值。 可能存在局部最小值,而不是全局最小值。 但是,如果函数是凸函数,则可以保证它只有一个全局最小值,而没有局部最小值。
通常,在 ML 中,我们希望最小化几个变量f
的实值函数:R^n -> R
。 几个变量的实值函数的一个简单示例是热板温度函数f(x1, x2) = 50 - x1^2 - 2x2^2
,其在板上的坐标为x = (x1, x2)
。 在深度学习中,我们通常最小化损失函数,该函数是多个变量(例如神经网络中的权重)的函数。 这些函数具有许多局部最小值,许多鞍点被非常平坦的区域包围,并且它们可能具有也可能没有任何全局最小值。 所有这些使得优化此类函数非常困难。
几个变量的函数的导数表示为偏导数,当我们更改其中一个输入变量x[i]
,并保持其他不变时,它将衡量函数的变化率。 关于所有变量的偏导数向量称为f
的梯度向量,用∇f
表示。 我们还可以找出函数相对于任意方向v
(单位向量)的变化速度。 这是通过在单位向量v
,即点积∇f · v
的方向上投影梯度向量∇f
来计算的。 这在v
方向上被称为f
的定向导数,通常用∇[v]
表示。 为了使f
最小化,我们需要找到一个方向u
,在其中要更改x
,以使f
的值最大程度地减小。
令x[a]
为非常接近x
的点,即||x - x[a]||
非常小。 首先,泰勒级数围绕x
的阶展开式为:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-W2EY1Voc-1681567233317)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/c7b1a382-402e-4cd3-8c9a-783da142e863.png)]
上式中的最后一项对于x[a]
足够接近x
可以忽略。 第二项表示f
沿x[a] - x
的方向导数。 这里有:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-G0E1LIrW-1681567233317)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/323c9d93-2e26-419b-9ed4-16099e6a5350.png)]
因此,如果cos(θ)
最小,则f(x)
最大减小,即 -1,如果θ = π
,即x[a] - x
应该指向与梯度向量,f
相反的方向,则f(x)
会最大程度地减小。 这是最陡下降方向:-∇f
或最陡梯度下降的方向。 我们在下图中对此进行说明:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yn2Q9R4m-1681567233317)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/dc2ec3d2-6f44-4905-85bf-cf64dc2599ed.png)]
热板
热板示例:给定坐标(x
和y
)上的温度由函数f(x, y) = 50 - y^2 - 2x^2
表示。 板在中心(0, 0)
处最热,温度为 50。点(x, y)
处的梯度向量由给出f = (-4x, -2y)
。 板上的点(2.3, 2)
的温度为 40。 该点位于恒温轮廓上。 显然,如红色箭头所示,在与梯度相反的方向上移动,步长为ε
,温度降低至 30。
让我们使用tensorflow
实现热板温度函数的梯度下降优化。 我们需要初始化梯度下降,所以让我们从x = y = 2
开始:
import tensorflow as tf #Initialize Gradient Descent at x,y =(2, 2) x = tf.Variable(2, name='x', dtype=tf.float32) y = tf.Variable(2, name='y', dtype=tf.float32) temperature = 50 - tf.square(y) - 2*tf.square(x) #Initialize Gradient Descent Optimizer optimizer = tf.train.GradientDescentOptimizer(0.1) #0.1 is the learning rate train = optimizer.minimize(temperature) grad = tf.gradients(temperature, [x,y]) #Lets calculate the gradient vector init = tf.global_variables_initializer() with tf.Session() as session: session.run(init) print("Starting at coordinate x={}, y={} and temperature there is {}".format( session.run(x),session.run(y),session.run(temperature))) grad_norms = [] for step in range(10): session.run(train) g = session.run(grad) print("step ({}) x={},y={}, T={}, Gradient={}".format(step, session.run(x), session.run(y), session.run(temperature), g)) grad_norms.append(np.linalg.norm(g)) plt.plot(grad_norms)
以下是前面代码的输出。 在每个步骤中,如梯度向量所建议的,计算x
,y
的新值,以使总温度最大程度地降低。 请注意,计算出的梯度与前面所述的公式完全匹配。 我们还在每个步骤之后计算梯度范数。 以下是梯度在 10 次迭代中的变化方式:
Starting at coordinate x=2.0, y=2.0 and temperature there is 38.0 step (0) x=2.79,y=2.40000, T=28.55, Gradient=[-11.2, -4.8000002] step (1) x=3.92,y=2.88000, T=10.97, Gradient=[-15.68, -5.7600002] .......... step (9) x=57.85,y=12.38347, T=-6796.81, Gradient=[-231.40375, -24.766947]
Jacobian 矩阵和 Hessian 矩阵
有时,我们需要优化其输入和输出为向量的函数。 因此,对于输出向量的每个分量,我们需要计算梯度向量。 对于f: R^n -> R^m
,我们将有m
个梯度向量。 通过将它们排列成矩阵形式,我们得到n x m
个偏导数J[ij] = ∂f(x)[i]/∂x[j]
的矩阵,称为 Jacobian 矩阵。
对于单个变量的实值函数,如果要在某个点测量函数曲线的曲率,则需要计算在更改输入时导数将如何变化。 这称为二阶导数。 二阶导数为零的函数没有曲率,并且是一条平线。 现在,对于几个变量的函数,有许多二阶导数。 这些导数可以布置在称为 Hessian 矩阵的矩阵中。 由于二阶偏导数是对称的,即:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wqZ6kste-1681567233318)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/3657cb60-4e28-4e83-bd5b-324637f867ad.png)]
Hessian 矩阵是实对称的,因此具有实特征值。 相应的特征向量代表不同的曲率方向。 最大和最小特征值的大小之比称为黑森州的条件数。 它测量沿每个本征维的曲率彼此相差多少。 当 Hessian 条件数较差时,梯度下降的效果较差。 这是因为,在一个方向上,导数迅速增加,而在另一个方向上,它缓慢地增加。 梯度下降并没有意识到这一变化,因此,可能需要很长时间才能收敛。
对于我们的温度示例,Hessian 为:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AfBm15u5-1681567233318)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/96c6867c-f6a9-4daa-bb4b-aa31e80cf6a9.png)]
最大曲率的方向是最小曲率的方向的两倍。 因此,沿着y
遍历,我们将更快地到达最小点。 从前面的热板图中所示的温度轮廓中也可以看出这一点。
我们可以使用二阶导数曲率信息来检查最佳点是最小还是最大。 对于单个变量,f'(x) = 0
,f''(x) > 0
表示x
是f
的局部最小值, 并且f'(x) = 0
,f''(x) < 0
表示x
是局部最大值。 这称为二阶导数测试(请参见下图解释曲率)。 类似地,对于几个变量的函数,如果 Hessian 在x
为正定(即所有本征值均为正),则f
会在x
达到局部最小值。 如果 Hessian 在x
处为负定值,则f
在x
处达到局部最大值。 如果 Hessian 同时具有正和负特征值,则x
是f
的鞍点。 否则,测试没有定论:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qvSMAnUT-1681567233318)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/25e288db-cbec-4a2b-a1dd-636f85fae3c7.png)]
解释曲率
存在基于使用曲率信息的二阶导数的优化算法。 牛顿法就是这样一种方法,对于凸函数,它只需一步就可以达到最佳点。
导数链式规则
令f
和g
均为单个变量的实值函数。 假设y = g(x)
和z = f(g(x)) = f(y)
。
然后,导数的链式规则指出:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OsZlZMOu-1681567233318)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/46fda9c6-12cf-4933-9a8a-14d4eb2bd6ec.png)]
同样,对于几个变量的函数,令x ∈ R^m
,y ∈ R^n
,g: R^m -> R^n
,f: R^n -> R
,y = g(x)
,z = f(y)
,然后:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UsISQtai-1681567233318)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/3e5c28bf-979d-492c-afea-53f995e924d7.png)]
因此,z
相对于x
的梯度∂z/∂x
表示为 Jacobian ∂y/∂x
与∂z/∂y
梯度向量的乘积。 因此,对于多个变量的函数,我们具有导数的链式规则,如下所示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EPVdu5Fs-1681567233319)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/03d7d7d4-46f1-4cf2-a857-d315b9503cef.png)]
神经网络学习算法由几个这样的雅可比梯度乘法组成。
随机梯度下降
几乎所有的神经网络学习都由一种非常重要的算法提供支持:SGD。 这是常规梯度下降算法的扩展。 在 ML 中,损失函数通常写为样本损失函数之和,作为自助餐厅示例中的平方误差E
。 因此,如果我们有m
个训练示例,则梯度函数也将具有m
个可加项。
梯度的计算成本随着m
线性增加。 对于十亿大小的训练集,前面的梯度计算将花费很长时间,并且梯度下降算法将朝着收敛的方向非常缓慢地进行,从而在实践中无法进行学习。
SGD 取决于对梯度实际上是期望值的简单理解。 我们可以通过在小样本集上计算期望值来近似。 可以从训练集中随机抽取m'
(比m
小得多的小批量)样本大小,并且梯度可以近似为计算单个梯度下降步骤。 让我们再次考虑自助餐厅示例。 应用链式规则,误差函数(三个变量的函数)的梯度由下式给出:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dIxn0LnN-1681567233319)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/95f79b2d-3b5e-4219-bc97-62174d8ce7d2.png)]
现在,代替使用所有 n 训练示例来计算导数,如果我们从训练示例中抽取少量随机样本,我们仍然可以合理地近似导数。
E
的梯度给出了权重更新的估计值。 我们可以通过将其乘以一个常数ε
(称为学习率)来进一步控制它。 取得非常高的学习率可能会增加而不是使优化目标函数值最小化。
在 SGD 中,在将每个小批量展示给算法后,将更新权重。 将整个训练数据一次呈现给训练算法需要很多数据点/批量大小的步骤。 一个周期描述了算法看到整个数据集的次数。
以下是自助餐厅问题的keras
代码。 假设鱼类的实际价格为 150 美分,薯条为 50 美分,番茄酱为 100 美分。 我们已随机生成餐中物品的样本部分。 假设初始的价格为每份 50 美分。 30 个周期后,我们得到的估计值与商品的真实价格非常接近:
#The true prices used by the cashier p_fish = 150; p_chips = 50; p_ketchup = 100 #sample meal prices: generate data meal prices for 10 days. np.random.seed(100) portions = np.random.randint(low=1, high=10, size=3 ) X = []; y = []; days = 10 for i in range(days): portions = np.random.randint(low=1, high=10, size=3 ) price = p_fish * portions[0] + p_chips * portions[1] + p_ketchup * portions[2] X.append(portions) y.append(price) X = np.array(X) y = np.array(y) #Create a linear model from keras.layers import Input, Dense from keras.models import Model from keras.optimizers import SGD price_guess = [np.array([[ 50 ], [ 50],[ 50 ]]) ] #initial guess of the price model_input = Input(shape=(3,), dtype='float32') model_output = Dense(1, activation='linear', use_bias=False, name='LinearNeuron', weights=price_guess)(model_input) sgd = SGD(lr=0.01) model = Model(model_input, model_output) #define the squared error loss E stochastic gradient descent (SGD) optimizer model.compile(loss="mean_squared_error", optimizer=sgd) model.summary() _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= input_4 (InputLayer) (None, 3) 0 _________________________________________________________________ LinearNeuron (Dense) (None, 1) 3 ================================================================= Total params: 3 Trainable params: 3 Non-trainable params: 0 _________________________________________________________________ #train model by iterative optimization: SGD with mini-batch of size 5. history = model.fit(X, y, batch_size=5, epochs=30,verbose=2)
在下图中,我们显示了学习率对迭代 SGD 算法收敛的影响:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-53z02R0W-1681567233319)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/fcfbb0ab-e892-4392-8372-fcf9dfbaecdf.png)]
学习率对自助餐厅问题 SGD 收敛速度的影响
下表显示了 SGD 在LR = 0.01
的连续周期如何更新价格猜测:
周期 | w_fish |
w_chips |
w_ketchup |
0(初始) | 50 | 50 | 50 |
1 | 124.5 | 96.3 | 127.4 |
5 | 120.6 | 81.7 | 107.48 |
10 | 128.4 | 74.7 | 104.6 |
15 | 133.8 | 68.9 | 103.18 |
30 | 143.07 | 58.2 | 101.3 |
50 | 148.1 | 52.6 | 100.4 |
非线性神经元
线性神经元很简单,但是在计算上受到限制。 即使我们使用多层线性单元的深层栈,我们仍然具有仅学习线性变换的线性网络。 为了设计可以学习更丰富的转换集(非线性)的网络,我们需要一种在神经网络的设计中引入非线性的方法。 通过使输入的线性加权总和通过非线性函数,我们可以在神经单元中引起非线性。
尽管非线性函数是固定的,但是它可以通过线性单元的权重来适应数据,权重是该函数的参数。 此非线性函数称为非线性神经元的激活函数。 一个简单的激活函数示例是二元阈值激活,相应的非线性单元称为 McCulloch-Pitts 单元。 这是一个阶跃函数,不可微分为零。 同样,在非零点,其导数为零。 其他常用的激活函数是 Sigmoid,tanh 和 ReLu。 下图提供了这些函数的定义和图解:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-D7waq4Ts-1681567233319)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/965ff81d-4930-4829-ab82-679911178735.png)]
激活函数图
这是激活函数定义:
函数名称 | 定义 |
二元阈值 | [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-C2BsxmqZ-1681567233320)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/c1d4835d-3647-4413-9da0-8e0b5ab7d2e0.png)] |
Sigmoid | [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-R8UXMMDi-1681567233320)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/721c6c66-6a07-4a20-a6c0-b8db4789461e.png)] |
tanh | [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XQOOb6x5-1681567233320)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/d6ae84fd-03b3-4511-9ce7-cf04ed45a6c9.png)] |
ReLU | [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bE2hkIB6-1681567233320)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/af2bf69a-947a-4c6e-a8f5-09769d6c213b.png)] |
或 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qVqhlwrL-1681567233320)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/7137e27c-ad6f-4d2b-a734-7add27c6a166.png)] |
如果我们有一个 K 类(K > 2
)分类问题,那么我们基本上想学习条件概率分布P(y | x)
。 因此,输出层应具有 K 个神经元,其值应为 1。为了使网络了解所有 K 单元的输出应为 1, 使用 softmax 激活函数。 这是 Sigmoid 激活的概括。 像 Sigmoid 函数一样,softmax 函数将每个单元的输出压缩为 0 到 1 之间。
而且,它会将每个输出相除,以使输出的总和等于 1:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-juV8Q2Mo-1681567233321)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-tl-py/img/099f52bb-312d-4d9b-a510-8824481123e2.png)]
Python 迁移学习实用指南:1~5(3)https://developer.aliyun.com/article/1426848