编码器——如何编写,如何使用
从头做起
通过这个“从头开始”的演练,探索编码器在机器学习中的多种用途!
在一个完美的世界里,所有的程序员、科学家、数据工程师、分析师和机器学习工程师都梦想所有的数据都能以最干净的形式到达他们的家门口。不幸的是,人类在开始用二进制或“哔哔哔”说话之前就发展了语音字母。因此,不幸的是,在处理数据集时,遇到单词(或“哔哔哔”语言中的“字符串”)而不是数字是非常常见的,即使是当今最干净的数据集也是如此。
数据、字符串和单词组合的问题在于,人工大脑无法直接分析单词。计算机是定量说话,而不是定性说话。让计算机解释单词,尤其是带有主观意义或情感的句子,就像让饼干怪兽吃芹菜一样;
这是不可能的。
幸运的是,这个问题有一个解决方案——有许多不同的方法可以将单词转换成数字进行分析!虽然这样做可能无法让计算机分析关于单词的某些事情,但它肯定有助于解决你在数据科学这一教育领域可能遇到的常见机器学习问题。通常,每当机器学习使用字符串时,数据科学家都会使用编码器。事不宜迟,我们来看看一些编码器!
独热编码器
我是世上最有趣的人。
如果你是机器学习的新手,你应该尽快掌握的一个技巧是对数据帧进行一次热编码的能力。一键编码,也称为一键编码或哑编码,采用一种非常激进的方法来处理分类变量。通常,我在尽可能少的类别的情况下使用 One-Hot。这是因为首先,与其他可用的算法相比,一位热编码数据占用了大量的内存和磁盘空间。此外,One-Hot 确实在这种光线下闪闪发光。
当处理大型分类特征集时,One-Hot 可以将 5 列数据帧转换为 50 列数据帧,这非常难以处理!最重要的是,通常随着类别中的更高股份,One-Hot 的有效性可能会急剧下降。为了理解为什么会发生这种情况,让我们写一个一次性编码器,看看当我们使用它时会发生什么。我们将从定义函数开始。当使用数据修改和数据破坏方法时,最起码做一个断言或浅层复制是一个好主意**。因为我们正在处理数据帧,所以使用像 copy 这样的库可能是个好主意,尤其是在 Python 中。对于这个示例,我不打算这样做——因为我的意图是将列添加到我的数据框架中,而我的数据本身是非常不重要的,并且仅用于演示目的。**
function onehot(df,symb)
copy = df
接下来,我们需要遍历数据帧中的唯一值:
for c in unique(copy[!,symb])
接下来,我们将使用一点聪明的迭代语法在这个循环中创建一行一热算法:
copy[!,Symbol(c)] = copy[!,symb] .== c
基本上,它所做的是遍历 copy 的“ symb”
列上的所有值。这个例子中的 Symb 当然代表了我们字典的关键列。我们用copy[!, Symbol(c)]
添加一个新的键,然后将它设置为一个条件。的。Julia 中的操作数和操作数是一回事,只是对于整个数组。因此,这将用布尔值(true 或 false)填充新列,这些值对应于原始列中的值是否对应于新列的值。现在我们将返回复制数据帧并结束我们的函数。
function onehot(df,symb)
copy = df
for c in unique(copy[!,symb])
copy[!,Symbol(c)] = copy[!,symb] .== c
end
return(copy)
end
这在实践中是什么样子的?
看一看:
如您所见,我们现在有四个布尔列。天气列中的每个唯一字符串都有一列。
顺序编码
使分类特征数值化的一种完全不同的方法是序数编码。顺序编码器不采用使用布尔表示值的一次性方法,而是使用整数——
谁能想到呢?!
序数编码比一键编码占用更少的 CPU,更重要的是占用更多的内存。每当类别非常高的时候,顺序编码确实一枝独秀。在某一点上,一次性编码是跟不上的,顺序编码是正确的选择。序数编码器到底是怎么把字符串变成整数的?
让我们看一些代码来找出答案!
正如我在之前的例子中解释的那样,将变量复制到这里是明智的。添加一个简单的副本比因为一些混乱的数据而不得不原路返回或重新开始工作要好得多,如果你在 REPL 工作,尤其如此。在这个函数中,我要做的第一件事是创建一个集合。
function OrdinalEncoder(array)
uni = Set(array)
集合是一种奇妙的类型,在 Julia 和 Python 中都可用,它将使获取唯一值比其他方式更快更简单。在我们得到我们的集合之后,我们将创建一个新的字典:
lookup = Dict()
这不仅是一个“类型”意义上的字典,而且是一个非常真实的字典,用于查找与键对应的值。然而,在我们可以在字典中搜索我们最喜欢的单词之前,我们需要填充它。我们可以通过迭代地枚举我们的集合并将那些键和相应的值添加到我们的字典中来做到这一点:
for (i, value) in enumerate(uni)
push!(lookup, (value => i))
end
接下来,我们将创建一个新阵列:
newarray = []
然后,在检查字典中它对应的键之后,我们将迭代地将我们的值追加回它:
for row in array
newvalue = lookup[row]
append!(newarray, newvalue)
end
然后我将添加我的 predict()函数,并返回一个类型以方便使用它。
predict() = newarray
()->(predict)
整体功能如下:
function OrdinalEncoder(array)
uni = Set(array)
lookup = Dict()
for (i, value) in enumerate(uni)
push!(lookup, (value => i))
end
newarray = []
for row in array
newvalue = lookup[row]
append!(newarray, newvalue)
end
predict() = newarray
()->(predict)
end
注意到什么可疑的了吗?
幸运的是,这个函数也可以简化到令人痛苦的程度。看看这个:
function OrdinalEncoder(array)
uni = Set(array)
lookup = Dict()
[push!(lookup, (value => i)) for (i, value) in enumerate(uni)]
predict() = [row = lookup[row] for row in array]
()->(predict)
end
那好多了!
现在让我们在数据集上测试一下。
oe = OrdinalEncoder(df[:Weather])
df[:OrdinalEncoded] = oe.predict()
如您所见,顺序编码器只是枚举数据帧中的所有唯一值,然后将该值重新应用于列中的所有观察值。非常简单,但也是我今天要介绍的三种编码器中最通用和最有效的。这款编码器的伟大之处在于,它在很大程度上是“一刀切”的体验。这是因为性能不一定是最重要的,它可以很好地处理大类别和小类别,尽管它可能会失去一些准确性,这取决于它所处的环境。
标签编码器
什么是标签编码器?阅读这篇文章的人很可能知道什么是标签编码器——因为我们刚刚从头开始创造了一个!没错,标签编码器和顺序编码器是一样的——至少在功能上是一样的。不,这与我们看到的虚拟编码和一位热码编码的情况不太一样。这两个术语存在的全部原因在于 Sklearn 构建其预处理包的方式。为了让标签编码器和顺序编码器都非常有效地工作,它们需要分开。这两者之间的最大区别是标签编码器通常用于目标,而序号编码器通常用于编码特征——就是这样!所以,如果你想知道代码是什么样子的,就在这里盖上函数定义,假装它写着“LabelEncoder”
function OrdinalEncoder(array)
uni = Set(array)
lookup = Dict()
[push!(lookup, (value => i)) for (i, value) in enumerate(uni)]
predict() = [row = lookup[row] for row in array]
()->(predict)
end
ASCII 编码器
ASCII 编码器,也称为浮点编码器(为什么所有编码器都需要两个名称?)使用对拼音字母和符号进行编号的 ASCII 系统,根据字符串中包含的字符创建唯一的类别。这既有效又通用,因为该系统不仅可以应用于标准的分类问题,还可以应用于自然语言处理!最重要的是,这也非常容易做到,而且非常有效,尤其是在处理具有许多不同值的数据集时。
创建 ASCII 编码器的第一步是将字符串分成字符。这可以通过 split()方法或字符串上的迭代循环来完成。虽然后者更密集,这是我通常更喜欢的。
for dim in array
newnumber = 0
for char in dim
接下来,你要做一个操纵的决定。如果我们试图对这些字符执行某种自然语言处理,或者如果我们有绝对大量的类别,那么逐个字符地创建一个新的整数可能是明智的,这个新的整数是一系列数字,代表字符串中的各个字符。然而,由于我们只是试图对一个非常小的数据集进行分类,因此我建议将数字相加,就像这样:
newnumber += Float64(char)
然后,我们将它添加到新的数字列表中,并像以前一样创建预测函数,我们开始吧:
function FloatEncoder(array)
encoded_array = []
for dim in array
newnumber = 0
for char in dim
newnumber += Float64(char)
end
append!(encoded_array, newnumber)
end
predict() = encoded_array
()->(predict)
enddf[:FloatEncoder] = fe.predict()
正如你所看到的,你会得到一个非常不同的结果,而且这个算法也可以被操纵来实现比分类编码更多的目标。
结论
编码器。是。厉害!学习读取数据和使用正确的编码器可能是使用每个编码器的最大问题。幸运的是,理解它们是如何工作的,并且能够编写它们,这使得想象什么样的编码器在您的特定情况下可能工作得非常好变得容易得多。不管你在这方面处于什么样的情况,你都会从中学习,并且能够以新的方式应用你新发现的技能。感谢您阅读我的文章,祝您白天(或晚上)休息愉快!)
机器学习中的分类变量编码
如何向机器学习模型输入分类数据
尼克·希利尔在 Unsplash 上的照片
分类数据需要以特殊的方式处理,才能用作机器学习模型中的一个特征。在说这种特殊方式之前,不如先说一下什么是分类数据。
分类数据表示一组有限的离散值。所以分类变量从有限的几个值中取一个值。分类数据的一些例子:
- 汽车品牌:福特,丰田,宝马,…
- 服装尺码:小号,中号,大号,加大号,…
- 显示某种级别的类别:低、中、高
- 颜色:蓝色,红色,黄色,…
分类数据可以根据它所代表的内容分成几组:
**名义数据:**类别并不意味着任何定量测量,数据中通常没有顺序。例如,种族、性别、语言是分类变量,但我们不能对这些变量的不同类别进行排序。
**序数数据:**与名义数据不同,类别之间是有顺序的。一个类别可以优于另一个类别,反之亦然。
- 低、中、高
- 冷,暖,热
现在是预处理分类数据的时候了,这样我们就可以在机器学习模型中使用它们。计算机只能处理用数字表示的信息。这就是为什么我们不能给机器学习模型类别或字符串作为输入。
我们首先需要将类别转换成数字。这个过程叫做标签编码。有些类别已经是数字了,比如电影分级从 1 到 5。我们不需要对这种分类变量应用标签编码步骤。
如果分类变量不是有序的(也就是说,它们没有等级顺序),标签编码是不够的。我们需要使用“哑元或“一个热码”编码对名义分类变量进行编码。假设我们对代表汽车品牌的分类变量进行了标签编码。编码器标签“道奇”为 3,“GMC”为 1。如果我们只是对这个变量进行标签编码,一个模型会认为“Dodge”比“GMC”更重要或更优越,这是不正确的。优选地,将每个类别表示为仅取两个值 1 和 0 的列。对于“道奇”品牌的汽车,只有“道奇”一栏的值变成 1,其他栏都是 0。通过这种方式,我们可以确保类别之间没有层次结构。
让我们看一个例子,这样就更清楚了。我创建了一个样本数据框架:
数据帧包括名义(品牌)和顺序(条件)数据。
标签编码
给类别分配标签的一种方法是使用 scikit-learn 的 LabelEncoder() :
因此,标签编码器为每个类别分配了一个编号。最好为每个类别使用单独的标签编码器,以防我们需要对列进行逆变换。然而,这种方法存在一个问题。您可能已经注意到,“条件”列中的平凡性没有保留。分配的标签有:
- 好:1
- 平均值:0
- 差:2
如果普通性很重要,我们可以使用 Pandas replace 函数手动标记编码这些类别:
我们只需创建一个将类别映射到标签的字典,然后将这个字典作为参数传递给 replace 函数。
虚拟和一个热编码
虚拟或 one 热编码器将每个类别转换为取值为 0 或 1 的二进制列。让我们首先应用来自 scikit-learn 的 OneHotEncoder() :
这个过程非常简单。我们启动一个 OneHotEncoder()对象,并使用数据应用 fit_transform 方法。值得一提的是下降参数。数据集包含品牌列中的 6 个类别和条件列中的 3 个类别。因此编码器应该总共返回 9 列。但是,返回的数组有 7 列。原因是我们要求编码器删除第一列,这是有意义的,因为我们不会因为删除一列而错过任何信息。考虑有 6 个类别的“品牌”栏。我们删除了第一类的列,即“奥迪”。如果其他五列中的值为 0,则该行代表“奥迪”。看一下原始 dataframe,看到第四行的品牌是奥迪。此外,编码功能数组中第四行的前五列都是零。
另一种做这个操作的方法是使用熊猫的 get_dummies 功能。Get_dummies 函数返回一个数据帧,通过组合原始列名和类别名来分配列名。
pd.get_dummies(df)
我们还删除了第一列:
pd.get_dummies(df, drop_first=True)
感谢您的阅读。如果您有任何反馈,请告诉我。
使用 Python 加密和解密文件— Python 编程
在本文中,我们将讨论如何使用 Python 加密和解密文件。
马库斯·斯皮斯克在 Unsplash 上的照片
目录
- 介绍
- 创建密钥
- 加载密钥
- 加密文件
- 解密文件
- 完整的面向对象编程示例
- 结论
介绍
今天,我们观察来自所有不同来源的数据,最终挑战变成了数据的安全性和隐私性。这不仅涉及企业持有的主要数据集,还涉及 AI/ML 模型和算法,以及最终的预测数据。
随着越来越多的行业在决策中采用数据科学实践,数据量也在不断增长。在 AI/ML 和云计算的加密和安全领域,已经发现了几家公司,它们现在甚至允许对加密数据进行计算。
在不断发展的数据和信息传输世界中,文件内容的安全性仍然是公司最关心的问题之一。一些信息可以用密码保护(电子邮件、登录),而其他通过电子邮件或 FTP 传输的信息如果用一些关键字保护,效率会很低。这就是文件加密发挥重要作用的地方,它提供了参与文件传输的各方所寻求的安全性和便利性。
那么什么是加密呢?它是将信息转换成某种形式的代码以隐藏其真实内容的过程。访问文件信息的唯一方法是解密它。加密/解密的过程称为密码学。
让我们看看如何使用 Python 加密和解密我们的一些文件。我们将遵循对称加密,这意味着使用相同的密钥来加密和解密文件。
为了继续学习本教程,我们需要以下 Python 库:cryptography。
如果您没有安装它们,请打开“命令提示符”(在 Windows 上)并使用以下代码安装它们:
pip install cryptography
我们还需要一个我们将要使用的样本文件。下面是样本。包含一些学生成绩数据的 csv 文件:
https://pyshark.com/wp-content/uploads/2020/08/grades.csv
创建密钥
在我们的例子中,我们将使用对称方程:
Fernet 是经过认证的加密技术,它不允许在没有“密钥”的情况下读取和/或修改文件。
现在,让我们创建密钥,并将其保存在与数据文件相同的文件夹中:
如果您检查 Python 代码所在的目录,您应该会看到 mykey.key 文件。您可以用任何文本编辑器打开它(在我的例子中,它显示在本地目录中,因为我使用的是 VS 代码)。该文件应该包含一行,它是某种字符顺序的字符串。对我来说就是“vld 8 H2 teijk qpkkkndnknu 8 ya 2 fpibmoo 5 oc 7 jknasvk =”。
加载密钥
生成加密密钥后,我们需要将其加载到我们的环境中,以便加密/解密文件。
以下步骤非常简单,只需打开 mykey.key 文件并将其存储在本地内存中:
为了验证,我们将看到以下输出:
VlD8h2tEiJkQpKKnDNKnu8ya2fpIBMOo5oc7JKNasvk=
加密密钥现在作为密钥变量存储在本地。
加密文件
既然我们有了要加密的文件和加密密钥,我们现在将编写一个函数来利用它们并返回加密的文件:
让我们讨论一下我们在这里做了什么:
- 我们将 Fernet 对象初始化为本地变量 f
- 接下来,我们将原始数据(grades.csv 文件)读入原始数据
- 然后,我们使用 Fernet 对象加密数据,并将其存储为加密的
- 最后,我们将它写入一个新的。名为“enc_grades.csv”的 csv 文件
您可以在这里查看加密文件:
https://pyshark . com/WP-content/uploads/2020/09/enc _ grades . CSV
解密文件
加密文件后,例如,成功地将文件传输到另一个位置,您会想要访问它。现在,这些数据是加密格式的。下一步是将其解密回原始内容。
我们现在要遵循的过程是上一部分加密的逆过程。完全相同的过程,但现在我们将从加密文件到解密文件:
让我们讨论一下我们在这里做了什么:
- 我们将 Fernet 对象初始化为 store is 作为一个局部变量 f
- 接下来,我们将我们的加密数据(enc_grades.csv 文件)读入加密的
- 然后,我们使用 Fernet 对象解密数据,并将其存储为解密的
- 最后,我们将它写入一个新的。名为“dec_grades.csv”的 csv 文件
您可以在这里查看解密后的文件:
https://pyshark . com/WP-content/uploads/2020/09/dec _ grades . CSV
把“dec_grades.csv”和原来的“grades.csv”对比一下,你会发现其实这两个内容是完全一样的。我们的加密/解密过程是成功的。
完整的面向对象编程示例
这是一个额外的部分,我把一切都组织得更有条理:
这是一个使用上述类进行加密/解密的示例:
结论
本文介绍了使用 Python 进行基本的对称文件加密和解密。我们已经讨论了密码库的一些部分,并创建了一个完整的过程示例。
如果你有任何问题或者对编辑有任何建议,欢迎在下面留下评论,并查看我的更多 Python 编程文章。
原载于 2020 年 9 月 1 日【https://pyshark.com】。
Google Colab 中 ResNet 的端到端改编—第 1 部分
入门
只需点击几下鼠标,就能训练出一个深度神经网络
来自 Unsplash.com,马库斯·斯皮斯克
我在这篇文章中提供的代码示例是几个小时的挫折和在互联网上四处搜寻的结果。
当我第一次开始自学深度神经网络时,我想找到一些我可以随时下载、即插即用并运行的东西——,但这很难找到。(再次)借用杰瑞米·霍华德的话,我真的很欣赏他如何从几行代码开始,证明训练一个深度神经网络不应该是令人生畏的。我想用 Google Colab 做类似的事情。
不涉及代码和硬件要求的细节,一开始,我真的很想体验一下训练需要多长时间,过程是什么样的,以及“端到端”网络的整个代码库是什么样的,它做了以下四件事:
- 下载并建立了一个深度神经网络
- 获取数据集并对其进行格式化以用于训练
- 训练神经网络并进行验证
- 准备好接受输入进行测试
输入谷歌 Colab。我就不多说了,除非给你这个:
你不需要知道任何 Python 来运行这个,你只需要两样东西——1)一个谷歌账户,这样你就可以启动笔记本;2)一个 Kaggle 账户。
这段代码下载了一个由成千上万张狗和猫的图像(标记为)组成的数据集,通过 ResNet-18 架构运行该数据集进行训练,一旦完成,它将为您提供一种轻松测试网络的方法。
让我们开始吧。
1.获取您的 Kaggle API JSON
首先,登录 Kaggle,点击右上角的图标,进入“我的账户”。向下滚动到标题为“API”的部分,然后单击“创建新令牌”。这将下载一个名为“kaggle.json”的 JSON 文件(希望下载到您的下载文件夹中)。
2.启动笔记本
查看下面的屏幕截图—确保在单击“更改运行时类型”时选择了 GPU,然后单击“保存”。然后选择“全部运行”。
Google Colab 上的运行时菜单。作者上传
3.上传您的 Kaggle JSON
我已经试着让这变得尽可能简单。向下滚动一点,注意到代码正在等待您上传您在步骤 1 中下载的 JSON 文件。
单击“选择文件”并选择您的 kaggle.json 文件。这将验证您的身份,以便您能够获取数据集。
代码正在等待您的 Kaggle JSON 文件。作者上传
4.向下滚动
我这样说并不是开玩笑,但是一旦你上传了 JSON 文件,代码就开始快速移动,很可能已经超过了你在页面上的位置,并且很可能已经开始训练,看起来像这样:
模型训练正在进行中。作者上传
这将需要一点时间,但不会太多,它可能运行在一个高端 GPU 上,为这样的任务而构建。
等待代码完成训练。它将输出这样一行:
‘Training complete in 4m 51s’
Best val Acc: 0.989370
5.准备好一张狗或猫的照片了吗
同样,与上面等待 JSON 文件的方式类似,代码现在正在等待您上传图片。由于它只在狗和猫身上进行训练,我建议从这些动物中挑选一只来测试一下。任何其他动物都可能提供异常但肯定不可靠的结果。
单击“选择文件”选择您的图片。
我发现了一张很棒的猫的照片:
来源:Unsplash.com
成功!作者上传
几个音符
我肯定掩饰了上面代码的一些细节,因为我想向你展示这个极其复杂的过程是可以实现的。
Colab 的美妙之处在于,你不需要快速的互联网连接,或高端 GPU 或大量的内存来了解深度神经网络的内部工作方式。
我们在英特尔至强处理器和 NVIDIA 显卡上训练了上述模型(ResNet-18)。对于世界上的绝大多数人来说,这种硬件在本地是买不到的,因为它们的成本太高(几千美元)。
我们用一个几乎 1Gb 大小的数据集训练了上面的模型,下载 Colab 服务器只需几秒钟。在本地运行所需的时间和带宽也不是世界上大多数人能够获得的。
自学深度神经网络不应该受到你面前的技术的阻碍,你也不应该在头脑中想象这是如何在硬件上完成的。
有了我提供的 Colab 笔记本,你可以用一台简单的电脑和最少的网络连接来运行它。
但这只是第一部分!我希望你能在接下来的几周内加入我,我们将按部就班地解开这段代码。
请在下面留下任何问题,我会尽力回答。
参考
[1] 深度学习用 Pytorch ,2020 年 10 月访问
[2] 神经网络与 Pytorch。【2020 年 10 月访问
Google Colab 中 ResNet 的端到端适配—第 2 部分:硬件和数据集设置
端到端 Resnet
CPU、GPU、数据集设置
来源:Unsplash.com
我希望你们都有机会预览本系列的第 1 部分,它不需要任何 python 知识,只需要一个 Google 和 Kaggle 帐户(后者只是为了验证你自己,所以你可以下载数据集。)
作为快速概述,我们能够在 ResNet-18 架构上训练狗与猫数据集(总共 25,000 张图像)。一旦完成训练,你就可以上传你最喜欢的猫或狗的照片,并观察输出结果。
我将把这个系列分成 5 个部分:
- 介绍
- 硬件和数据集设置
- 图像预处理
- 建筑培训
- 真实世界测试
旁白
一旦你完成了训练,当你输入一张猫头鹰的照片时会发生什么?
来源:Unsplash.com
输出是‘狗’!虽然只有 78.41%的把握。(如果最后一个单元格有问题,只需使用左侧的箭头重新运行它。)
我已经插入了所有东西,从物品到我朋友的照片(他们看起来有点像猫),结果到处都是。有时,概率在 90%以上。
如果还不清楚的话,我要强调这一点——你必须知道使用训练网络的基础数据,否则你的预测将是不可靠的,并且取决于你使用它的目的,是危险的。你对这些数据了解得越多,你对输出的理解就越丰富。
不要用“人工智能”这个时髦词,但如果我要描述我们所建立的东西,我会称之为“狭义人工智能”。这不是人工通用智能(AGI) 。在这里我们只能辨别狗和猫。
库导入
这些是运行整个程序所需的库。‘torch’是 PyTorch(类似于机器学习库 Tensorflow)。“torchvision”包含最流行的模型和数据集以及图像转换(稍后讨论)。“matplotlib”让我们可以创建图像的图形和表格。
当您看到“从 ABC 进口 XYZ”时,我们尽量不输入 ABC。XYZ 每次都可以用 XYZ。例如:
现在,我们可以只使用“listdir”命令,而不是键入“os.listdir”。这是一个简单的例子,但是浓缩类似下面这样的代码有助于简化我们的代码:
你会看到在库导入单元格的末尾是:
想想那个“!”将命令传递到命令行,而不是 python 内核,这样你就可以安装你需要的库,比如‘ka ggle’(让我们下载数据集)。
CPU、内存和 GPU
我提到过 Google Colab 中的高端 CPU 和 GPU。
这将向命令行传递一个命令,以获取有关 CPU 的信息,而“grep”(全局正则表达式打印)搜索纯文本数据。如果你跑了!你会得到一个很长的输出列表,但我们只是想知道有多少个 cpu,型号和 GHz。
与上面类似,‘啊!’ cat /proc/meminfo '给出了一个很长的输出列表,但是我们只想知道总 RAM(因此 grep MemTotal)
CUDA(计算统一设备架构)是由 Nvidia 设计的,旨在让我们这样的程序员访问支持 CUDA 的 GPU 来加速我们的数学运算(在这种情况下,是图像分析)。有很多帖子在不同的细节层次上讨论了这是如何工作的。
注意我们通过’ torch.cuda.is_available()'使用 pytorch 库,它输出一个布尔值(True vs False)。如果为真,我们还可以使用 pytorch 库来获取设备的名称。
这个设备名称会根据 Google Colab 提供的内容不时更改(有时你根本无法获得 GPU,因为你已经用完了当天的配额)。今天早上是特斯拉 P100。有时我会得到一个超快的特斯拉 T4(免费的!).
获取数据集
卡格尔号。在此步骤中,您下载的“JSON”文件将通过以下方式导入:
如果您参考库导入部分,您会看到这一行:
“files.upload()”允许您上传 kaggle.JSON。
上面的命令都传递给机器命令行,而不是 python 内核。创建一个名为“kaggle”的目录,并将您上传的 kaggle.json 文件复制到新创建的目录中。
“chmod 600”允许用户读写 kaggle.json 文件。这很重要,因为 kaggle 库使用 JSON 文件来验证您下载名为“dogs-vs-cats”的数据集。
最后,解压缩(悄悄地,用-q ),但也覆盖(-o)以防你已经下载并解压缩了它。
请在下面留下任何问题,我会尽力回答。
参考
[1] 深度学习与 Pytorch ,2020 年 10 月访问
【2】神经网络与 Pytorch。【2020 年 10 月接入
Google Colab 中 ResNet 的端到端适配第 3 部分:图像预处理
端到端 Resnet
为训练准备数据集
来源:Unsplash.com
快速回顾一下我们到目前为止所做的工作:
第一部分 —整个项目概述。不需要 python,只需要一个 Google 和 Kaggle 账户。希望您已经说服自己,您个人能够完整地运行代码,并对其进行测试。
第二部分 —库和数据库都是从 Kaggle 导入的。它被解压缩到一个文件夹中。我们还做了一个简短的概述,介绍了如何确定您正在使用哪种硬件。在处理像我们这样的图像数据库时,GPU 信息很重要。
链接到 Colab 笔记本: 猫&狗— Resnet-18
在我们能够将图像“加载”到架构中进行训练之前,我们必须首先对它们进行预处理。
创建文件夹结构
上面的代码创建了以下结构(val 和 train 位于主数据集文件夹下,而 dogs 和 cats 文件夹位于它们各自的子文件夹中):
dataset_dogs_vs_cats
train
dogs
cats
val
dogs
cats
对于那些想要命名的人,我们正在这里用标记的数据执行监督的机器学习。我们给数据“贴标签”的方式是把它放在一个文件夹里。代码将被告知使用包含图像的文件夹的名称作为标签。
旁白
将来我几乎肯定会在这个问题上犯错,但你对神经网络了解得越多,“建模”和“模型”这两个词就开始变得模糊,你总是会说“我们正在用这个特定的模型来建模我们的问题。”
当提到模型的技术定义时,我鼓励你使用架构这个词。我承认我的代码会有类似‘train _ model’的语句,但在这种情况下,model = architecture,即 ResNet-18 架构。“我们正在用这种特殊的架构来建模我们的问题”听起来更容易接受。
整理我们的数据
第一步是将数据分为训练和测试。我们将使用训练数据来训练我们的架构(调整参数)。ResNet-18 有 1100 万个可训练参数。测试集将用于衡量架构的执行情况,以“测试”的形式向其显示新数据。
“src_directory”包含所有图像。“listdir”获取源目录中所有文件的列表,如果文件以“cat”开头,我们将它放在 cats 文件夹中,与 dog 相同。这是在“file.startswith('cat 或 dog ')”中捕获的。
您可以看到,默认情况下,目的地是“train”文件夹,除非一个随机数(默认为 0 到 1 之间)小于 0.25,这种情况应该发生在 25%左右,在这种情况下,文件会被传送到“val”文件夹。
图像转换
这里需要解释一下。让我去掉一行——“调整大小”。ResNet 架构要求图像为 224x224(为什么不在本文讨论范围之内),因此 train 和 val(验证)图像都必须调整大小。
让我们倒着做。行“ToTensor()”设置我们的图像用于计算。它本质上是一个多维数组(高度、宽度、颜色空间)。每个[train,val]的“归一化”功能根据三个 RGB 通道归一化数据。第一组数字是平均值,第二组是标准差。使用这些特定的归一化值是因为 torchvision 架构(如 ResNet)已经在 ImageNet 上进行了训练,并基于数百万张图像进行了计算。
剩下三种变换—旋转、RandomHorizontalFlip 和 RandomResizedCrop。与“为什么”相比,这些转换的“是什么”更容易理解。本质上,您希望向您的网络呈现尽可能多的不同的训练图像。增加这些图片种类的一种方法是使用庞大的数据集——在这种情况下,有近 19,000 张训练图像。
我们能够通过对图像进行小的修改来人为地增加图像的多样性。
旋转和 RandomHorizontalFlip 是不言自明的。
RandomResizedCrop 从图像(本例中为 224x224)中选取一小块,随机选取的范围在 0.96 到 1.0 之间,随机选取的纵横比在 0.95 到 1.05 之间。
数据加载器
数据加载器允许将数据集批量交付到用于培训的架构中。它们对于确保简化的数据流至关重要。相应地,您看到设置的第一个变量是 batch_size = 16。如果您在训练时遇到困难(尤其是 GPU 内存问题),请以 2 的倍数减少批量。
Data_dir 设置训练和验证图像的主目录。数据集。“ImageFolder”允许像我们之前所做的那样设置标签——文件夹的名称是标签本身(而不是嵌入在文件名中或存储在其他地方的标签)。您可以看到,我们在上面定义的“数据转换”应用于“图像数据集”变量中。
“torch.utils.data.DataLoader”允许将“image_datasets”合并到“dataloaders”变量中。
我们后来在最后两行中将“dataloaders”变量拆分为“train_dataloader”和“val_dataloader”。
最后,确保使用 GPU:device = torch . device(" cuda:0 ")。在接下来的步骤中,我们将确保架构加载到 GPU 上。
请在下面留下任何问题,我会尽力回答。
参考
[1] 深度学习与 Pytorch ,2020 年 10 月访问
【2】神经网络与 Pytorch。【2020 年 10 月接入
Google Colab 中 ResNet 的端到端适配—第 4 部分:培训
端到端 ResNet
继续,但现在是“大卡哈纳”
现在,我们必须解决整个项目的核心问题,以及在此之前的所有问题,以便无缝地进行培训——下载数据集,格式化所有内容以便输入网络,为图像处理创建数据转换,以及创建有助于以结构化方式插入图像的数据加载器。
如果你刚刚加入,我已经做了一个 colab 笔记本,让你运行整个代码(一次点击),最后,允许你上传一张图片进行测试。这个特殊的数据集和网络旨在区分狗和猫,但你可以上传任何你想生成输出的图片。
这样做实际上是很有启发性的,尤其是对你将来想做的任何工作。**了解基础数据、其问题和偏差对于解释结果至关重要。**每个数据集都有偏差,都是不完美的,这并不一定意味着它是无用的。
以下是前面部分的链接:
[## Google Colab 中 ResNet 的端到端改编—第 1 部分
只需点击几下鼠标,就能训练出一个深度神经网络
towardsdatascience.com](/end-to-end-adaptation-of-resnet-in-google-colab-part-1-5e56fce934a6) [## Google Colab 中 ResNet 的端到端适配—第 2 部分:硬件和数据集设置
评估您的硬件— CPU 和 GPU,并设置您的数据集
towardsdatascience.com](/end-to-end-adaptation-of-resnet-in-google-colab-part-2-hardware-dataset-setup-f23dd4e0004d) [## Google Colab 中 ResNet 的端到端适配第 3 部分:图像预处理
为训练准备数据集
towardsdatascience.com](/end-to-end-adaptation-of-resnet-in-google-colab-part-3-image-pre-processing-fe30917d9aa2)
下面我们先来解开 train_model 到底是怎么回事:
我粘贴了上面的整个函数,只是为了大致了解它有多大,但它将被分成几个部分:
几个定义
Epoch —底层数据对模型的一个完整呈现(呃,*架构,*正如我告诉自己我会说的)。
训练阶段 —如果您还记得,我们使用了 75/25 的比率(80/20 和 70/30 也很常见),我们随机分割数据集,将 75%分配给训练集,25%分配给验证集。随机地做是很重要的,因为如果你把所有的图片都按顺序排列,如果不随机的话,你可能会在训练阶段过度表现狗或猫(结果,架构会更好地“训练”一种动物而不是另一种动物)。
验证阶段 —我们分配给验证集的 25%不应用于培训。这是向网络显示新数据的最佳方式,以查看它是否学习得很好。就像教一个孩子加法一样,你不会想提出同样的问题,而是一个相似的问题来看看孩子是否学会了加法。
优化零毕业生——这本身并不是一个“词汇”术语,但知道这一点很重要。当梯度在小批量中生成时,它们将继续传播通过(这是每个训练周期所不希望的;你想重新开始)。zero_grad 功能使您能够为每个迷你批次重新开始计算梯度。
重物搬运
大部分繁重的工作都在这里完成:
第一个 if/else 语句将模型设置为训练或评估模式(pytorch 特性)。默认情况下,模型处于训练模式。有趣的是,如果您不使用 dropout layers 或批处理规范化,这个约定并不太重要,但是拥有这个约定对于将来验证您的代码(以及您如何使用 pytorch)是非常重要的。
然后使用数据加载器迭代数据,并使用“inputs.to(device)”和“labels.to(device)”行将代码加载到 GPU 中。我们之前讨论过通过 Colab 使用高端 GPU 的能力。
with torch . set _ grad _ enabled(phase = = ’ train ')-括号仅在阶段确实处于训练模式时为真,允许在训练模式期间计算梯度,loss.backward(同样,在训练期间)将计算梯度,optimizer.step 使用最近的计算更新所有梯度。
现在,如果阶段不是列车,则 set_grad_enabled 变为 False,不计算梯度,也不更新任何内容。模型只评估输入的图像(这是你在训练中想要的)。
“scheduler.step()”是一行很小的代码,但是对于获得更低的错误率是至关重要的。改变学习率对超参数调整至关重要。开始时,你希望学习率高,这样才有效,随着训练的进行,你希望降低学习率。想象一下,试图找到一个领域的最低点。你希望一开始就迈出大步,这样你就不会错过任何山谷,也不会被困在地图的一个小角落里。但是当你发现山谷时,你不会想在山谷的墙壁上反弹,因为你的脚步很大。让你的步数(这里是学习率)变小会让你更有效地找到最低点。
最后,计算精度,并且如果该特定精度的历元比最佳精度(初始设置为 0)好,则更新 best_acc 变量,并且也更新模型权重,并且重复整个过程。
模型下载&参数确定
名副其实,我们使用的是 Resnet18 型号。全连接层(model_ft.fc)有两个最终输出(猫对狗)。然后,我们将模型加载到 GPU 上,并将损失函数定义为 CrossEntropyLoss 。
对这个损失函数的讨论超出了一个介绍性系列,但可以说,它非常常用于分类(而不是回归)模型,并且被许多其他帖子和视频所涵盖。
优化函数(SGD——随机梯度下降)也是我鼓励你阅读(或观看 youtube 视频)的内容。
最后是学习率调度器——如上所述,我们希望学习率随着 epoch #变大而变小,以便更好地微调架构(权重)和降低损耗。
最后,我们将所有这些放在一起,让它运行:
model_ft = train_model(model_ft, criterion, optimizer_ft, exp_lr_scheduler,num_epochs=10)
我建议你至少做 5-10 个周期来说服自己有一个合理的停止点,迭代超过 100 个周期会大大减少收益。
如果你正在阅读上面的文章,并发现它过于简单,我为你领先我几光年而鼓掌。但是,如果上面的某些部分没有意义,请留下评论,我会将您连接到适当的资源。
本系列的目标不是深入研究神经网络——我没有资格这么做。我们的目标是让您相信这种架构对您来说是可行的,您可以在高端计算上运行它,并上传您自己的映像以供最终测试——我已经对此进行了概述。
下一次——上传一张照片和相关的细节。
参考
[1] 深度学习用 Pytorch ,2020 年 10 月访问
[2] 神经网络与 Pytorch。【2020 年 10 月访问
[4] Kaggle API。2020 年 10 月访问
端到端定量分析—从 SKLearn 到 Spark
来自 Pexels 的 Manuel Geissinger 的照片
构建 AWS 管道
在之前的一篇文章中,我描述了如何使用 Amazon Web Services (AWS)建立一个自动化的工作流程。我们已经探索了如何使用 AWS 的命令行工具 awscli 来加速弹性 Map Reduce (EMR)集群。
在那篇文章中,我们已经看到了如何使用 sklearn 的DecisionTreeClassifier
将价格运动分类为“上升”或“下降”(1 或 0,二元分类问题)。
使用 sklearn 的一个缺点是,它使用一台机器来执行所有计算。这种设置会随着数据的增加而增加运行时间,即使我们的 EMR 集群可以包含多台能够进行分布式计算的机器。这就是 Spark 推出其版本的DecisionTreeClassifier
的原因。我们将在本教程中比较 sklearn 和 Spark 的使用。
火花和 PySpark
Spark 是一个 Apache 框架,旨在跨多台机器进行并行和分布式处理。这个想法是将工作分解成独立的块,这些块都可以被计算(划分数据),然后汇集独立计算的结果。Spark 非常强大,但是,对于 Python 程序员来说,可悲的是,它是用 Java 编写的。这就是 PySpark 发挥作用的地方。它是围绕 Spark 框架的 python 包装器。
Spark 结合了来自 pandas 的几个抽象,比如 dataframes,以及来自 sklearn 的几个抽象,比如转换和机器学习技术。
将我们的数据转换成火花数据帧
我们要做的第一件事是将我们的熊猫数据帧转换成 spark 数据帧。这是一个非常常见的操作,因此 PySpark 有一个内置函数来完成这个操作。
将我们的库存熊猫数据框架转换为 spark 数据框架
注意,我们使用了 Spark 的内置类型来指定转换的模式。这一步是强烈推荐并节省大量加工时间。如果不这样做,Spark 会尝试自己推断模式。
还要注意,我们在模式中将nullable
属性设置为False
。这也节省了处理时间,因为 Spark 在进行转换时不必担心某些列包含空值。
完成后,您会注意到我们可以打印 spark 数据帧的模式来查看其结构:
root
| — Open_pct: double (nullable = false)
| — Close_pct: double (nullable = false)
| — High_pct: double (nullable = false)
| — Low_pct: double (nullable = false)
| — Volume_pct: double (nullable = false)
| — Target: double (nullable = false)
将特征转换成矢量
Scikit-learn 模型用于表格数据;numpy 数组或 pandas 数据帧。然而,Spark 机器学习模型需要稍微不同的架构。
虽然 pandas 和 numpy 利用单台机器上的高效内存使用,但 Spark 更关心如何轻松地将数据分布到不同的机器上。因此,它需要将每个数据点封装在一个vector
类中。我们需要使用一个VectorAssembler
将我们的特性列转换成一个包含向量的列。我们必须告诉VectorAssembler
哪些列要插入到这个新列中。
使用向量汇编程序创建向量列
root
|-- Open_pct: double (nullable = false)
|-- Close_pct: double (nullable = false)
|-- High_pct: double (nullable = false)
|-- Low_pct: double (nullable = false)
|-- Volume_pct: double (nullable = false)
|-- Target: double (nullable = false)
|-- features: vector (nullable = true)
现在,当我们检查模式时,我们看到我们添加了一个存储数据的 vector 类型的单列。在这种方法下,每个数据点都是一个封装的项目,可以在我们的集群中发送。
使用决策树分类器
Spark 有两个主要的机器学习库; MLlib 和 ML 。首选的库是 ML,因为 MLlib 正在慢慢淡出。我们将使用 ML 中的决策树分类器。
这部分和我们使用 sklearn 还蛮像的;我们初始化我们的模型,拟合它,然后要求预测。有两个主要区别:
1)我们必须在同一个数据框架中指定特性和目标列。决策树希望所有特征都位于一列(vector 类型)中。
2)与 sklearn 决策树不同,这里没有单独的predict
和predict_proba
方法。一个非常详细的数据帧作为我们的预测返回,其中包含硬类预测、概率预测和许多其他项目。
我们将运行以下代码来使用决策树:
运行决策树分类器
我们已经采取了几个步骤,让我们来分解一下:
- 我们将数据分为 80%的训练数据和 20%的测试数据。请注意,与 sklearn 不同的是,这里没有专门的函数,但它是数据帧的一个特性
- 我们将数据帧分成 10 个分区。每个分区都是我们的数据的一个原子块,当它在节点之间传递时不会被进一步分割。每个分区将驻留在单个节点上,这意味着我们已经将数据帧切割成 10 个可以四处发送的数据块。
这一步必须包括在内,因为默认情况下 Spark 只使用 2 个分区,这使得大量数据被发送。 - 我们必须初始化决策树,并明确告诉它应该对哪些列进行操作。我们说我们有一个“features”列(vector 类型)和一个“Target”列(double 类型)。一旦我们的树被初始化,我们可以使用
fit
方法使它适合训练数据。 - 用一种
transform
方法(而不是predict
)抓住我们的预测。这些预测来自它们自己的火花数据框架。 - 打印该模型的总运行时间。在我的例子中,打印输出是:
run-time: 3.55
- 打印出我们的预测数据框架的模式和预测。请注意,预测数据帧也包含测试数据帧的所有列:
root
| — Open_pct: double (nullable = false)
| — Close_pct: double (nullable = false)
| — High_pct: double (nullable = false)
| — Low_pct: double (nullable = false)
| — Volume_pct: double (nullable = false)
| — Target: double (nullable = false)
| — features: vector (nullable = true)
| — rawPrediction: vector (nullable = true)
| — probability: vector (nullable = true)
| — prediction: double (nullable = false) +--------------+----------+-----------+
| rawPrediction|prediction|probability|
+--------------+----------+-----------+
|[0.0,131301.0]| 1.0| [0.0,1.0]|
|[0.0,131301.0]| 1.0| [0.0,1.0]|
|[0.0,131301.0]| 1.0| [0.0,1.0]|
|[0.0,131301.0]| 1.0| [0.0,1.0]|
|[0.0,131301.0]| 1.0| [0.0,1.0]|
|[0.0,131301.0]| 1.0| [0.0,1.0]|
|[0.0,131301.0]| 1.0| [0.0,1.0]|
|[0.0,131301.0]| 1.0| [0.0,1.0]|
|[0.0,131301.0]| 1.0| [0.0,1.0]|
|[0.0,131301.0]| 1.0| [0.0,1.0]|
|[0.0,131301.0]| 1.0| [0.0,1.0]|
|[0.0,131301.0]| 1.0| [0.0,1.0]|
|[0.0,131301.0]| 1.0| [0.0,1.0]|
|[0.0,131301.0]| 1.0| [0.0,1.0]|
|[0.0,131301.0]| 1.0| [0.0,1.0]|
|[0.0,131301.0]| 1.0| [0.0,1.0]|
|[0.0,131301.0]| 1.0| [0.0,1.0]|
|[0.0,131301.0]| 1.0| [0.0,1.0]|
|[0.0,131301.0]| 1.0| [0.0,1.0]|
|[0.0,131301.0]| 1.0| [0.0,1.0]|
+--------------+----------+-----------+
only showing top 20 rows
AWSCLI 的配置
我们将需要使用一个新的命令,其中包含了更多的信息
aws2 emr create-cluster \
--name “Spark cluster with step” \
--release-label emr-5.29.0\
--applications Name=Spark \
--log-uri s3://**logs**/logs/ \
--ec2-attributes KeyName=**my-key-pair**,AvailabilityZone=us-west-2a \
--instance-groups **file://instanceGroupConfig.json** \
--bootstrap-actions Path=s3://**scripts-and-set-up**/bootstrap_file.sh \
--configuration **file://config.json** \
--steps Name=”Command Runner”,Jar=”command-runner.jar”,Args=[“spark-submit”,
”--conf”,”spark.executor.memory=18g”,\
”--conf”,”spark.driver.memory=16g”,\
”--conf”,”spark.rpc.message.maxSize=1500",\
”--deploy-mode=cluster”,”s3://**workflow-scripts/process_data.py**, s3://**data-files**/AAPL.csv”] \
--use-default-roles \
--auto-terminate
我不会探究每一个新的参数,因为我在之前的帖子中探究了create-cluster
命令。但是,我要指出的是,您必须将 s3 存储桶设置为您自己的存储桶。
说到这里,让我们来看看我们添加的几个新参数:
--instance-groups file://instanceGroupConfig.json
—我们实际上可以使用一个配置文件来指定部署多少个节点以及部署哪种类型的节点。我的集群使用了 4 个节点;1 个主节点、1 个任务节点和 2 个核心节点
instanceGroupConfig.json
- 这是我们集群的另一个配置文件,但是它概述了我们的资源管理器(YARN)应该如何工作。它基本上允许我们在主节点上消耗大量内存
配置. json
- 我们这里有相当多的火花配置参数。它们控制整体内存管理。每个执行器应该分配高达 18Gb 的内存来运行,控制所有执行器的驱动程序应该分配 16Gb 的内存来运行,最后 Spark 应该能够在执行器和驱动程序之间一次发送高达 1.5Gb 的数据包。我花了一些时间通过反复试验来调整这些参数。我不会说它们是最优的,但它们允许进行比较。
比较两个决策树的运行时间
为了便于比较,让我们来看看我之前用于 sklearn 树和 Spark 树的代码。
使用 sklearn 的决策树分类器
>>> run-time: 9.19
使用 Spark 的 ML 决策树分类器
>>> run-time: 3.55
使用 Spark 的决策树最终会使数据处理速度提高一倍以上。这符合我们的预期,因为 Spark 可以削减任务和核心节点之间的工作。然而,这个特殊的例子变得稍微复杂一些。
虽然 Spark 的决策树显示了明显的优越性能,但在这种情况下,使用 Spark 并没有快多少。
使用 sklearn 决策树的集群总共运行了 14 分钟,而 Spark 集群运行了 13 分钟。运行时间接近是因为将数据帧转换成 Spark 数据帧本身就是一项成本高昂的操作。
然而,我们在这个实例中探索的数据只有大约 4GB 大小。随着数据大小和集群大小的增加,这种差异肯定会增加。Spark 被设计为运行在万亿字节的数据上,甚至更多。所以这个例子仅仅说明了部署基于 Spark 的机器学习工作流的过程。
用于 PySpark 处理的整个脚本如下所示:
process _ data _ with _ 火花. py
结论
Spark 可用于加速您的机器学习需求,由于它包含许多与 sklearn 相同的算法,转换非常容易。一旦您熟悉了 Spark 框架,PySpark 接口允许几乎无缝的转换。然而,为了达到熟悉的程度,人们必须超越机器学习算法的通常知识,并深入了解配置和内存管理知识,以允许 Spark 应用程序发挥其全部潜力。
我写这篇文章的时候很开心,我希望你读的时候也开心。关于 Spark,我还有一些东西需要学习,但我希望能让您的学习体验更轻松。
迄今为止的成本
在试验 3-4 个节点的集群时,以及花了相当多的时间来实现指定显式模式节省了相当多的处理时间,我不得不花更多的钱来学习如何使用 Spark。我希望这篇教程确实能为阅读它的人节省时间和金钱,但是对我来说总的花费大约是 60 美元。我建议你在使用 Spark 和 EMR 进行原型开发时要小心,因为这很容易增加费用,但是如果不尝试和失败,你就无法学会如何使用这些工具。
端到端案例研究:自行车共享需求预测
阿纳托利·阿尼金在 Unsplash 上拍摄的照片
大家好!!
欢迎来到这个关于自行车共享需求预测的博客。这个数据集取自 Kaggle 。在这篇博客中,我们将经历简单而有效的预处理步骤,然后我们将更深入地挖掘数据,并应用各种机器学习回归技术,如决策树、随机森林和 Ada boost 回归器。我们将通过使用 GridSearchCV 对每个回归器算法进行参数调整来找到最佳的超参数。
在分析每个模型的误差后,我们将选择一个给出最小均方根对数误差(RMSLE)分数的模型,并使用它建立一个模型。
最后,我们将看到如何使用函数将整个代码包含在 python 中以获得更高的效率。希望,你会喜欢。
1)数据预处理
- 理解数据
给定的训练数据集具有 10886 行和 12 列。季节、假日、工作日列是绝对的。除了’ datetime '之外,其余都是数字列。
使用’ datetime ‘列获得另外两个功能’ time ‘和’ month '。
删除不必要的列。
分类列上的一个热编码。
用每个相应列的中值输入空值。
- 使用 python 函数的代码:
2)模型构建:
我已经根据“工作日”列分离了数据,因为与非工作日相比,工作日的需求变化很大。
我建立了两个模型,一个预测“休闲”,另一个预测“注册”。预测的“计数”是预测的“临时”和预测的“注册”的总和。这里,我只展示了预测工作日“已注册”的代码。同样的技术可以用于预测工作日的“休闲”和非工作日的“休闲”、“注册”。最后可以检查全部代码。
- 线性回归
线性回归在这里被用作基础模型,尽管我们知道线性回归在这里不起作用。我们拟合该模型以使用该模型的‘均方误差’( mean _ squared _ log _ error)作为参考来检查其他模型的表现如何。
- 决策树
对’ max_depth ‘和’ min_samples_leaf '参数进行参数调整。
用最佳参数建立决策树模型。
- 随机森林
对’ n_estimators ‘、 max_depth 和’ min_samples_leaf 参数进行参数调整。
用最佳参数建立随机森林模型。
- Ada-Boost
用基本模型作为我们在上面找到的“最佳随机森林模型”来寻找最佳的 n 估计量。
用最佳 n 估计量建立一个最终的 Ada 推进模型。
3)分析错误
上述模型在工作日预测“注册”的均方根对数误差( RMSLE ):
每个模型的 RMSLE 分数
随机森林的 RMSLE 分数最低,非工作日也是如此。因此,我们可以得出结论,随机森林是这里的最佳模型。
4)最终模型
在对整个数据进行模型拟合后,以下是工作日和非工作日的 RMLSE 得分。
一个工作日和非工作日的 RMSLE 分数
整体数据的 RMSLE 分数结果为 0.351。
使用 python 函数的代码:
5)特征重要性
对于工作日,预测“已登记”的重要特征是:
对于工作日,预测“休闲”的重要特征是:
非工作日的特性重要性也类似于工作日。因此,时间、湿度、温度和月份是所有情况下最重要的特征。
6)模型测试
由于测试数据缺少一些列,我们将编写一个新的函数,使用以前的模型来预测“计数”。
使用 python 函数的代码:
更新和保存 CSV 文件:
最后在 Kaggle 提交了这个文件后,我得到了一个 RMSLE 的分数 0.513。
你可以在这里找到完整的代码。
端到端数据仪表板,包含 Plotly Dash 和 Heroku:美国失业数据
此处显示的仪表板的第一个选项卡
数据科学
有很多经济数据来自不同的部门,劳工部,经济分析署,BLS,弗雷德,NBER,美国人口普查局——我们如何把这些数据放在一起,看看这些数字背后的人们?
在过去的几个月里,我们已经看到令人厌恶的大数字都以同样的方式显示——通过直线图和条形图,有一个大的跳跃。当然,这是展示变化的好方法,但很难理解或真正理解仅仅一句台词。台词让你觉得“哦,哇,不寻常”,就是这样。我认为,这些数据需要以一种与个人相关的方式呈现(呈现给他们知道的人、地方和行业),以帮助用户比较美国各地的统计数据。
这需要一个数据仪表板,具体来说,它的目标是:
允许用户轻松地比较和查看美国劳动力中的问题和模式,最终导致更深入的“为什么”问题和后续研究。
GitHub 仓库中的一些代码和数据在这里,仪表盘可以在usa-data-dashboard.herokuapp.com找到。如果你在手机上,去usa-data-dashboard-mobile.herokuapp.com获得更好的观看体验。总的来说,这个项目花了四天时间,大概有 1000 行代码。这个应用程序本身有 500 行代码。
这个应用程序分三步完成
- 获取和清理数据
- 创建 Plotly 图表和 Dash 应用程序
- 部署到 Heroku 并进行优化
获取和清理数据
为了开始了解数据背后的人,以及我们如何帮助他们,我们需要向我们展示地点、人员和原因的图表。我决定尽可能细化,并决定使用美国县(人口普查区)级数据来显示失业、社会人口统计和行业依赖。美国在人口普查中报告了 3000 多个县。正如人们所料,这是 4 天中最长也是最艰难的部分,大约 2.5 天,可能有点干。我选定的数据集是由于更新的准确性和一致性:
- 匹配以下内容的一整套标识符:联邦信息处理标准(FIPS)、基于核心的统计区域(CBSA)、大都市区域名称、县名称、州名称 大约 2020 年
- 2010-2020 年 BLS 各县失业情况
- BLS 按行业分列的就业人数(州和市区)2019–2020
- 美国人口普查局数据:人口统计和平均收入 2018
考虑到相似数据的来源数量之多,协调 ID 和更新频率,项目的开始非常混乱。我花了大约半天时间来梳理副标题中列出的每个网站,看看在哪里可以找到最一致的数据和标识符。虽然它在我的数据集上被列为第一名,但直到最后我才真正把它拼凑起来。这很困难,原因有三:
- 各种数据源之间,县和城市地区的分组或拼写通常略有不同。
- 我发现的数据集和键都来自不同的日期,所以映射中的细微变化导致了额外的四五个小时来检查工作表中的名称,以找到最佳的组合。
- 美国的县名不是唯一的
本质上,它都与美国人口普查局的代码相关联,其中 FIPS 匹配县名,CBS 匹配大都市地区,FIPS 匹配 CBSA(如果该县是大都市地区的一部分)。您可以在我的FIPS to CBSA.xlsx
文件中找到这个映射。这是用 NBER 以及 BLS 键的组合创建的。这都是 USCB 人用的,他们是这样分解的:
这里的 FIPS 应该是 06067
下面是它是如何连接的:我从他们的数据库中的本地失业系列 ID 数据开始(这是 3200 次查询/每次拉动的最大 200 次= 16 次拉动),并使用他们的area_code
到area_text
的转换来获得县名和列名(这在我的US BLS Codes.xlsx
文件中)。这些可以追溯到 1990 年,但我只从 2010 年非调整。
然后,我看了州和大都市地区经济概览,得到了行业就业月度数据。这只能追溯到 2019 年 12 月。我能够从 EAG 的每一页得到行业分类,就像这一页一样。
USCB 的人口普查数据也很难在县一级找到,所以我过去常常在地区一级的司法地图上找到数据文件,这是一个 1.2GB 的postgreSQL
文本转储文件。我必须下载postgreSQL
,安装postGIS
插件,然后pd_dump
将文件存入数据库。我使用psycopg2
库将数据库表读入 Python,然后使用这种方法获取县平均比赛细目。在用公正地图核对百分比数据时,我去掉了“其他种族”,因为这个领域似乎没有包括在总人口中。
如果你对我如何清理文件感到好奇,请查看回购和这个脚本。我还没有清理脚本,但我认为它非常简单,所有读取的文件都在存储库中。忽略第 18–21 行,由于名称不一致,我没有使用那个代码文件。
创建 Plotly 图表和 Dash 应用程序
现在我们将深入研究代码,特别是应用程序布局是如何制作的。作为参考,以下是截至 2020 年 6 月 16 日的 app 代码。我删除了大约 150 行数据读取和操作,这些内容看起来会很混乱,我们将在后面讨论。Dash 实现从第 83 行开始。
我假设你对布局和回调有一个基本的了解,如果没有,那么请查看 Plotly Dash 文档。
提醒一下,任何图表都可以被绘制成图表——它只是静态的。对于这个仪表板*,我使用了四种类型的图:***
Plotly 图形对象:go。“美国-各州”定位模式的 choropleth
左栏,标签 1
这个示例使用了三个回调函数,一个选择要显示的行业类型,两个选择日期。滑块还不接受datetime
对象,所以这是唯一的解决方法。
plot_unemploy_choro_state()是我在脚本前面第 64 行定义的函数。
plot ly Express:px . choropleth _ map box 一个县(FIPS)级地块
左栏,标签 1
现在我们变得有点复杂了,我使用了一个链式回调在一个下拉列表中选择数据集(人口普查数据或 BLS 县失业数据),然后在第二个下拉列表中显示要绘制的值。
这看起来很可怕,但如果你慢慢来,这很简单。第一个回调选择在第二个下拉列表中显示的标签,第二个回调通过“数据类型”过滤相关的数据集 df,并将其设置为要返回的fig
。
Plotly Express: px.line 和 px.bar
右栏,标签 1
好了,现在是整个右侧。本质上,这里所发生的是县选择照顾所有的图表。一旦我有了一个县,我就用 BLS 失业县的数据绘制一个线图,从美国人口普查局 2018 年的数据中提取该县的人口统计数据,然后使用州数据(来自图表 1)和 CBSA 大都市区数据(这两个数据都来自 EAG 数据源)更新行业就业。
county 是 state 的连锁回调,因为 county 的名称在美国不是唯一的。因为我有一个映射文件设置,我可以很容易地使用 dict 从后端的所有其他工作表中提取。
一步一步来看,第一个回调设置了 counties 下拉列表。如果选择了 not county,第二次回调会弹出一个警告。第三次、第四次、第五次回调都是以类似的方式使用 px.bar。最后回调的是历史折线图。这里有一堆操作在进行,但是不要太担心那些。
第二页签:比较视图
在我构建了第一个选项卡之后,我才设计第二个选项卡。我希望第一个帮助用户找到奇怪的县和州,然后第二个在你找到感兴趣的州/县后,一次比较尽可能多的县/州。
各州的比较如下所示:
左栏,标签 2
县与县的比较如下:
右栏,标签 2
图像中有一个收入图表,但你可以自己看一下。这基本上是相同的代码,但我使用了 px.bar 的不同版本,并在下拉列表中启用了multi=True
,这样就可以根据需要填充尽可能多的行或条。
你不必这样做,但是我使用了 Dash Bootstrap 组件,而不是布局、标签和卡片的标准样式表(在特定区域设置边界)。它们有很好的文档,确实有助于简化应用程序代码的组织,所以如果你还没有尝试过,我建议你尝试一下。我首先创建了空白标签和卡片布局,然后开始填充。你会看到我的app.layout
很短,在第 297-304 行。
部署到 Heroku 并进行优化
如果你做到了这一步,那么恭喜你!理解别人所做的数据流程和仪表板构建并不是一件容易的事情。我这么说是为了避免你的痛苦——一旦你有了一两个本地运行的基本图表, 部署到 Heroku 。 Heroku 有一个所谓的 R15 限制,基本上意味着如果你的应用超过 512mb X 2 workers =1024mb 的内存使用量,它就会崩溃(使用heroku logs --tail
检查崩溃)。此链接底部有一个部署基本 dash 应用程序的分步指南。如果你运行的是 Windows,使用venv\Scripts\activate
而不是source
命令。
随着你的进展,你可以添加更多的图表和测试功能——如果你带来的不仅仅是基本的 dash/pandas/numpy 包,这一点尤其重要,因为你可能已经做出了一些花哨的东西,但在推送到 heroku 时,pip 由于这样或那样的原因不工作。这真的很像使用任何软件时的提示:“早存,常存”。
对于大多数简单的应用程序,你不需要关心优化,但对于这一个,我有超过 1GB 的数据和脚本中一些昂贵的操作。为了解决这个问题,我试图限制像.unstack()
这样的操作来保存行,并将较大的文件分割成多个 csv 文件,然后在app.py
文件中执行大多数位于Labor Data Prep.py
文件中的操作。这就是为什么在进入 dash 应用程序之前有将近 200 行,一些文件在操作后从 csv 中的 3000 行变成了app.py
文件中的 1,600,000 行。
我经常遇到 R15 错误,持续使用大约 1100 多 mb 的内存,即使应用程序上只有两个图表。我把procfile
改成了包含preload
,以牺牲一些性能为代价节省了内存。
*web: gunicorn app:server --preload*
此外,它有助于了解不同的动态类型 (web、worker、clock 等)以及水平和垂直缩放。你可能需要为更多的内存扩展应用付费。
在这里你可以看到我的测试和内存使用历史。这些错误显示在 H10-R15 中,严重错误导致应用程序崩溃。
对于企业来说,还有一整套从每月 5 美元到 1000 美元以上的附加服务。我花了一些时间研究缓存,看看性能是否会更快,但最终决定没有必要。我在回调之前缓存了尽可能多的变量——尽量避免太多的 dataframe 操作(比如 df[df[“column”]==var]),尤其是对于链式回调。
经过大量的测试和修改(确切地说是 40 个版本),我已经让我的应用程序始终运行在 600mb。
最终仪表板
我们完事了。总而言之,数据仪表板不应该是您进行数据分析的首选,但是当有太多视图需要显示或探索时,它是一个不错的选择。
要记住的事情:
- 从一个仪表板的关键目标/目的开始
- 花点时间收集和核对数据,看看已经取得了什么成果。
- 仔细挑选你的图表和回拨设计,在开始之前做好布局!
- 按需部署,不要在最后批量部署。一下子优化完会很痛苦。
在我们有越来越多的开放数据可用的时候,我鼓励每个人开始用更人性化的视角探索数据——而不是只关注你能或不能预测什么。祝你好运!
这里表达的所有观点都是我个人的,并不代表我所属的那些人的观点。
端到端数据科学项目:使用回归预测二手车价格
图片来自 Pixabay 的 JOERG-DESIGN
介绍
大约每年售出 4000 万辆二手车。有效的定价策略可以帮助任何公司在竞争激烈的市场中高效地销售其产品并获取利润。
在汽车行业,定价分析对于公司和个人在出售或购买汽车之前评估汽车的市场价格起着至关重要的作用。
我想通过这个数据科学项目实现两个主要目标。首先,根据历史数据,通过考虑一组特征来估计二手车的价格。第二,更好地了解有助于确定二手车价格的最相关特征。
数据
将用于该项目的数据可在 Kaggle 和获得,这些数据来自 Craigslist,这是世界上最大的二手车销售网站。
该数据库由 423,857 行和 25 个特征组成,其中一个特征将是我们要预测的连续因变量(“价格”)。
数据库概述
方法学
EDA
数字特征在这个回归模型中起着很大的作用,所以很好地理解它们在数据库中的分布是很重要的。
数字特征的统计数据
我们的重点将是“价格”、“年份”和“里程表”。如上图所示,这三个特征的最大值/最小值和百分位数之间有很大的差异。这是异常值存在的一个指标,异常值会极大地阻碍我们模型的性能。它们将在以后处理。
缺失值&重复值
在了解了我们将要使用的数据库之后,务必检查是否有任何缺失值(NaN)。
数据库中某些要素的值缺失
大多数特性都有大量的缺失值,但是仅仅删除所有具有 NaN 值的行是不实际的,因为这样会使数据库变得过于稀疏。
现在,我将把它留在那里,只去掉一些不会带来任何附加值的功能。保留它们只会让模型更难解释数据库。
从数据库中删除的一组要素
最后,还需要检查数据库中是否有重复值。
在这种情况下,数据库中有几个副本。它们将通过删除现有的重复行来处理,但第一行除外,第一行将被保留。
处理数据库中的重复项
特色工程
首先,我将在“描述”列上使用正则表达式。此功能包含每辆二手车的广告文本。
目标是从那里获得关键信息,以便填充数据库中其他列的 NaN 值。我们要填充的列是那些具有分类值但没有太多唯一值的列:
使用正则表达式的模式匹配
完成此操作后,有值被不一致地添加。例如,我们在同一列中有这些类型的值:“awd”和“awd”。为了统一字符串,将使用 strip()方法。
处理不一致的数据输入
通过这个 Regex 步骤,数据库获得了成千上万的新条目,用一致的数据填充了大量缺失的值。由于我们不再需要“描述”功能,我将删除它。
下一步,是时候让处理数据库中的离群值了。将被处理的三列是:“里程表”、“价格”和“年份”。
让我们从想象前两个开始:
价格和里程表值的分布
由于“价格”在最小值和 25%百分位之间以及在最大值和 75%百分位之间有如此大的差异,我将在两端省去 10%的值。
价格两端的价值下降 10%
接下来,是时候关注“里程表”了。这个特性有 NaN 值,所以处理起来比较棘手。让我们用散点图来显示异常值。
显示里程表上的异常值
因为离群值开始于大约 3,000,000;我将放弃超过这个值的值。此外,去掉最小值(0)也是一个好主意,因为它与 25%的百分位数有很大不同。这样,“里程表”功能也已成功调整。
调整后的里程表功能
为了结束这一步,特征“年份”的异常值将以与“里程表”中相同的方式进行处理。
接下来,我想通过使用数据库中其他现有列的来处理另外两个相关特性。它们是:“条件”和“标题 _ 状态”。它们非常相似,基本上告诉我们二手车的状态(干净、脏、新、好、坏……)。
为此,我将使用“里程表”值。“里程表”功能是一个连续的功能,因此最好将其值分组到几个箱中作为参考。
标题 _ 状态与里程表
“title_status”的大部分值都是干净的,所以我将把“干净”添加到该列的所有 NaN 值中。接下来,是时候检查“状况”了:
状况与里程表
在这种情况下,值的差异更大。使用上面的图表作为指导,我将填写“条件”的 NaN 值。最后,因为“condition”和“title_status”是相互关联的,所以将它们合并到一个特性中是一个好主意。
填充 NaN 值和连接要素
最后,现在是时候再次查看缺失值图表了。我会应用其他方法来处理它们。
数据库中缺少值
考虑到丢失值的数量,我将把特性分成三个不同的组,并删除具有最多 NaN 值的“size”。
首先,NaN 值少于 5%的行将删除缺少值的行。
删除具有 NaN 值的行
第二,NaN 值小于 20%的那些将通过使用 fillna()函数填充。
在具有缺失值的要素中使用 fillna()
最后,最后一个特性“cylinders”将通过使用另一个列(“drive”)来处理,以推断它的值,因为我觉得它是模型的一个相关特性。
利用另一列填写 NaN 值
在本特性工程部分的结尾,将“区域”和“州”合并成一个特性是一个好主意,因为它们是紧密相关的。
将区域和州连接成一个特征
分类变量编码
在数据库中,既有数字变量,也有分类变量。但是,为了继续下面的步骤,需要将这些分类值编码成数字数据。这将在标签编码的帮助下完成。
分类变量编码
相关性
当两个变量高度相关时,它们对我们要预测的因变量的影响是一样的。在这种情况下,建议删除其中一个。
相关矩阵
在这种情况下,没有一个特性是高度相关的,所以我们让它们保持原样。
造型
是时候开始这个项目的建模了。这一次,我将只使用随机森林回归模型来获得“价格”预测。
随机森林算法是决策树的集合。对于我们的项目来说,它肯定会派上用场,因为它有能力处理具有更高维度的大型数据集,并且不允许在模型中过度拟合树。
为了开始建模,我们希望将数据库分为训练集和测试集。这项工作将以 80:20 的比例完成。像往常一样,我们将首先重新索引数据库,并将因变量“价格”作为最后一列,以便进行更简单的拆分。
重新索引并拆分成训练/测试集
在分割之后,由于独立特征的值存在很大的差异,因此有必要实现特征缩放。务必在拆分数据库后进行,以避免数据泄漏到机器学习模型中。
将特征缩放应用于 X_train 和 X_test
然后,我们使用交叉验证方法在训练集中拟合模型,以便更精确地估计模型的准确性。我将利用 R (R 平方)指标来评估模型的性能。
R 是一个无标度分数,这意味着值太大或太小都没有关系,R 将总是小于或等于 1。越接近 1 越好。
顺便提一下,由于百分比在评估结果时更有洞察力,我将把我们从 R 得到的值转换成百分比。
基于 R 度量评估模型
我们一开始就获得了超过 85.48%的分数。一点也不差。但是我们可以通过调整超参数来进一步改善它。
一旦模型的超参数得到优化,就应该再次训练它(使用交叉验证)并再次检查它在训练集上的性能。
随机森林回归模型的超参数调整
从上面的图片中我们可以看到,在优化了超参数之后,分数变得更好了。
最后,一旦训练完成,模型已经从训练数据中学习,剩下的就是检查它在测试集中的表现如何。这将是我们模型的关键时刻。
对测试集的预测
我们的模型在训练集和测试集中的良好表现表明,结果似乎相当可靠。事实上,它在测试集中的预测更加准确(87.03%),这一点尤其值得注意。
结果
对于这个项目,为了预测二手车的价格,我只使用了一个模型:随机森林回归变量。
它在如此大的数据集上表现出了出色的性能,并且在整个训练和测试过程中表现一致。更重要的是,测试集的结果优于训练集,其预测准确率为 87.03%。
该项目的目标之一是创建一个能够估计二手车价格的模型,我们已经实现了这个目标。
第二个目标是在估计因变量“价格”时,找出哪些特性是最相关的:
随机森林模型中每个特征的重要性
结论
通过这个项目,我们建立了一个模型,在给定一组特征的情况下,该模型可以以 87.03%的准确率预测二手车的价格。当公司和个人试图了解如何估计一辆汽车的价值时,这些信息可能具有巨大的价值,更重要的是,了解决定其定价的关键因素。
正如所料,到目前为止,在计算价格时,车辆的年份是主要因素,几乎占 43%,其次是里程表。有趣的是,我期望汽车的状态和里程表有很深的关联,但是在这两个指标之间的相关性差异上有很大的差距。
也就是说,这个地区似乎也起了作用,这完全有道理。可能会有更多的通用汽车在任何地方都受欢迎,但像跑车或敞篷车这样的专业汽车更适合温暖的地区,而大型卡车和 SUV 在寒冷的地方会发挥更好的作用。
掌握定价的艺术不是一件容易的事情,但是通过对历史数据的研究,有可能找到导致准确结果的模式。在出售或在市场上购买汽车之前,获得这些知识可以为你提供一个比较优势。
关于这个项目内核的更多信息,请访问:https://github.com/josem-gp
使用 Azure 的端到端深度学习教程
在 Azure 上学习深度学习
了解如何设置深度学习工作区,构建自定义数据集,使用 azure pipelines 通过持续部署来培训和部署模型。
简介:
本文的目标是在 azure 上建立一个深度学习工作区,在 azure 上构建和部署端到端的深度学习项目。我们将首先构建一个定制的图像数据集,以在生产中部署模型。本文是由微软学生合作伙伴(印度)项目发起的 MSP 开发者故事的一部分。
我们将会建造什么?
我们将构建一个口袋妖怪图像分类器来分类令人敬畏的新手皮卡丘、小火龙、杰尼龟和妙蛙种子。
mini-pokedex.azurewebsites.net的现场演示
我们将遵循的步骤:
- 使用 Bing 图像搜索 API 构建自定义图像数据集
- 使用 azure Data Science VM 设置我们的深度学习工作区
- 使用快速人工智能在 Azure 数据科学虚拟机中构建和训练模型。
- 构建一个 web 应用程序,通过 API 和 dockerizing 使用我们的模型。
- 将 web 应用程序的 Docker 映像推送到 azure 容器注册表。
- 从 azure 容器注册表在 Linux 容器 VM 中部署 web 应用程序。
- 使用 azure 管道设置连续部署。
注意:
开始之前,请确保您在 Azure 上拥有一个有效订阅的帐户。如果你是 STEM 的学生,你可以使用 Azure for Student s 免费订阅,或者你可以使用 Azure 免费帐户。
步骤 1:使用 Bing 图像搜索 api 构建自定义图像数据集
我们将使用 Bing 图像搜索 API,转到 Bing 图像搜索 API 页面,点击尝试 Bing 图像搜索并登录。然后通过填写必填字段来激活您的服务,如下所示:
给它一个名字,我把它命名为dataset-search-API,你可以根据它的可用性尝试任何不同的东西。选择您合适的订阅。对于 定价层,F1 将是合适的,因为它每月提供 1000 笔免费交易。创建一个 资源组搜索-API ,你可以给它起任何名字,但是在 Azure 中工作时要记住的重要一点是给资源组起一个合适的名字,因为你以后会使用资源组的名字来跟踪费用和删除资源。 为资源组选择一个位置 , 接受条件 , 点击创建 。然后 等待 创建您的资源。一旦创建了 ,点击转到资源 。
创建阿炳图像搜索资源
- 你可以找到 bing 图片搜索资源页面的 API 键。
- 然后 git 克隆这个 repo:image-dataset-bing-API
- 在 VS 代码中打开它,并创建一个名为。并将文件 .env.example 的内容粘贴到其中。
- 然后从你的资源页面复制你的 bing 图片搜索 API 密匙并粘贴到。env 文件放在适当的位置。
- 用python-m venv venv创建一个虚拟环境
- 使用venv \ Scripts \ activate . bat(windows 中)或source venv/bin/activate(Linux 中)激活它
- 使用pip install-r requirements . txt安装依赖项
- 使用 python search_bing_api.py 这样的脚本—查询“妙蛙种子”
- 对杰尼龟小火龙的皮卡丘重复上述过程。
- 现在你有了一个名为 dataset 的文件夹,里面有每个口袋妖怪的图像。
- 浏览图片,删除那些你觉得不相关的。
- 像我在这里做的那样,将文件夹(数据集)添加到一个新的 git repo 中 pokemon-image-dataset
现在 GitHub 中有了一个带有自定义图像的 repo,让我们开始下一步:
第二步:使用 azure Data Science VM 建立我们的深度学习工作区
我们将制作一个 NC6 宣传片,这是一个带有 1 个 K80 NVIDIA GPU (1/2 物理卡)的 Linux 虚拟机,它是 12 GB GPU 和 6 个 CPU 内核。
你可以在这里了解更多关于虚拟机的信息。
如果你需要一个详细的安装程序,你可以参考快速人工智能 azure 页面,否则你可以遵循以下说明。
- 我们将使用 fast ai 团队创建的模板来设置虚拟机:单击此链接将带您进入虚拟机创建页面。
- 创建一个名为 DSVM 的新资源组,根据您的喜好设置位置。
- 设置管理员用户名(小写或 Jupyter Hub 登录失败,出现 500 内部服务器错误),设置密码
- 设置适当的虚拟机名称,我将其命名为 DSVM-DL 并在虚拟机大小中选择 NC6 Promo
- 选择接受条款,然后单击购买。
现在等待,直到资源被创建。单击通知图标以了解它是否已创建,并在创建时单击转到资源组。
在“resource,group”页面中,单击您在上面为其命名的虚拟机。并单击您的公共 IP,如下图所示
单击 ip 将其设置为静态
点击 IP 将带您到一个配置为您的公共 IP,现在改变分配为静态从动态,你也可以设置一个 DNS 名称标签。由于这一步,您的虚拟机 IP 将不会改变后,重新启动。该页面将如下图所示
设置静态 IP
现在我们已经完成了 DSVM 的设置,让我们进入下一步
步骤 3:使用快速人工智能在 Azure 数据科学虚拟机中构建和训练模型。
由于你已经设置了一个带 GPU 的 DSVM,你可以通过 ssh 将带 azure 笔记本或使用到 DSVM 中并使用。我推荐第二种方法,因为它给你更多的灵活性。首先,让我向您展示 azure notebooks 方法,然后我们将开始使用带有 SSH 的 VM。
在 Azure 笔记本上使用 Azure DSVM。
- 前往notebooks.azure.com,登录并创建一个用户 id。
- 然后单击我的笔记本并创建一个新笔记本。
- 现在,要在 azure 笔记本中使用带有 GPU 的 VM,请将选项 Run on Free Compute 更改为 Run on Direct Compute。
- 现在你可以开始在带有 GPU 的 DSVM 上使用 azure 笔记本了。
更改计算步骤的屏幕
SSH 进入 DSVM,从那里使用
这种方法比上面的方法更灵活。对于 windows 用户,我推荐使用 wsl 在这一步之前,只需在当前 shell 中键入 wsl 即可启动。
要连接到您的虚拟机,请使用:
ssh <username>@<VM Public IP> and enter password
用下面的命令设置 Jupyter 笔记本并启动 Jupyter
jupyter notebook password
// Enter password:
// Verify password:jupyter notebook --port 8888
创建从虚拟机到 localhost:9999 的 ssh 隧道
ssh -L 9999:127.0.0.1:8888 <username>@<VM Public IP>
现在进入 localhost:9999 使用 jupyter 笔记本,输入密码开始使用。
你可以创建一个文件夹,制作一个名为 pokedex-dl 的笔记本,然后开始工作。
**注意:**请参考 pokedex.ipynb 训练并将您的模型导出到 outputs 文件夹。我已经在笔记本上解释了每一个步骤,如果你有任何疑问,请在下面评论。
跟随 pokedex.ipynb 之后,您将有一个名为 poke_predictor_resnet34 的输出文件夹,从 Jupyter 笔记本下载。 上传模型到 Dropbox获取可共享链接 。
步骤 4:构建一个 web 应用程序,通过 API 使用我们的模型,并对其进行 dockerizing。
第一个 git 克隆:pokedex-在本地部署。用你的共享链接替换 server.py 中的 dropbox 链接。你也应该根据你的喜好改变 index.html。
您可以在 docker 中运行 pokedex-deploy ,使用
docker build -t poke-image . && docker run --rm -it -p 5000:5000 poke-image
也可以用自己喜欢的图像名称替换poke-image
。
现在我们已经准备好了 docker 图像,我们可以进入下一步了
第五步:将 web 应用的 Docker 映像推送到 azure 容器注册表。
首先我们需要设置 azure CLI,请咨询docs.microsoft.com/en-us/cli/azure/install-azure。给 Windows 用户的提示:-试试 Chocolatey 你可以参考chocolatey.org/packages/azure-cli进行安装。
别忘了az login
现在我们将使用 Azure CLI 创建一个私有容器注册表。容器注册表基本上是 docker 图像的 GitHub,docker hub 是一个公共容器注册表。
如果您需要以下步骤的更多细节,请参考容器-注册表-入门-azure-CLI
# create a resource group named container_registry_rg
az group create - name container_registry_rg - location eastus# create container registry named pokeRegistry
az acr create --resource-group container_registry_rg --name pokeRegistry --sku Basic# Login to your container registry
az acr login --name pokeregistry# tag your container registry in following format,
docker tag poke-image pokeregistry.azurecr.io/poke-image:v1# Push image to container registry, it will take a while
docker push pokeregistry.azurecr.io/poke-image:v1# You can verify if it's uploaded by
az acr repository list --name pokeregistry --output table# Important Please don't forget this,important for deployment
az acr update -n pokeregistry --admin-enabled true
步骤 6:从 azure 容器注册中心在 Linux 容器 VM 中部署 web 应用程序。
在 portal.azure.com去天蓝色。并选择创建资源、 Web ,然后选择 Web App for Containers 或者你可以直接点击这个链接去那里。
点击 create,在页面中填写详细信息并创建一个新的资源组。请更改 Sku 和尺寸默认选项:B1 基本在开发/测试中,因为它将足以满足基本需求。不要忘记在 Docker 标签中将图像源设置为 Azure 容器注册表。
使用容器的 Web 应用程序进行部署
完成后,点击“转到资源”,您可以在 URL 找到您的网络应用程序 URL
恭喜你现在已经部署了你的深度学习模型🚀
步骤 7:使用 azure 管道设置连续部署。
现在在 azure 的 web 应用页面上,你会发现一个叫做**部署中心的东西,**这是 azure 中最酷的东西之一。它将帮助我们在 Azure 中创建 CI/CD 管道。
- 单击部署中心
- 选择源代码位置(Github)并授权它
- 选择您的存储库
- 它会自动检测 docker 文件,只需点击下一步
- 创建 Azure DevOps 组织并选择使用容器注册表中的现有组织,单击完成
- 完成页面后,单击“在中发布管道”
以上步骤可以在下面的 gif 中看到:
azure 部署中心
现在你必须在dev.azure.com如果不去那里,在 dev.azure.com的组织内部找到你的项目。
通过当前的设置,我们已经为我们的项目建立了 CI/CD 管道,这要感谢部署中心。
如果你对你的代码做了任何修改,并把它推送到 GitHub,它会构建一个新的镜像,把它添加到你的容器注册表中并进行部署。
但是我们现在有两个问题需要解决
- 想象一下,你不断地修改你的代码,你的容器注册表(10 GB)将被所有未使用的图片使用
- 如果您编辑您的 Readme.md,它将构建一个新的映像并部署它。
要解决这两个问题,请访问您在 dev.azure.com的组织内部的项目页面,并观看下面的视频。
哇哦。如果你到了这里,恭喜你🎉。如果你有任何疑问,请在评论区发表。
使用 Streamlit 和 Heroku 进行部署
每一个渴望进入数据科学领域的新手,都有一大堆项目放在自己的桌面上,无人触及。我们把它们放到网上怎么样??
本文中使用的所有代码和截图都来自我今年早些时候参与的一个个人项目。GitHub 回购的代码在这里被链接,部署的模型在这里被链接
使用 STREAMLIT 构建 UI:
首先,您需要将 streamlit 安装在您的系统上,或者您正在进行这个项目的虚拟环境中。
如果您没有安装 streamlit,请打开命令提示符并键入:
pip install streamlit
一旦安装了 streamlit,您应该查看 streamlit 的官方文档,以熟悉其 python 库提供的各种小部件。我将从以下我认为最有用的小部件开始:
- 要输入纯文本
streamlit.write('Text data')
2.创建下拉列表
choices = ['1', '2', '3']
selected_ch = streamlit.selectbox('Pick a number', choices)
3.要创建滑块
num = streamlit.slider('Enter num', min_val, max_val, step)
4.接受输入
inp = streamlit.text_input('Enter some text here', default)
num = streamlit.number_input('Number', default)
使用上面的小部件,我们可以为我们的应用程序创建一个简单的 UI。当我第一次尝试这样做时,我用了不到 15 分钟就完成了整个 UI!这真的没有那么难!
如果您对此有任何疑问,请查看 streamlit 的官方文档。
将它保存在一个. py 文件中(比如“stream.py”)。
使用 streamlit 构建的 UI 示例[图片由作者提供]
部署到 Heroku:
如果这是你第一次部署到 Heroku,这可能会有点混乱。我将带你完成这最后一步,之后你的网站将在互联网上直播!这难道不令人兴奋吗???我们开始吧!
有很多方法可以做到这一点。然而,我将用最简单的方法开始
- 第一步:创建一个 Heroku 账户,如果你还没有的话
这很简单。转到 Heroku 注册页面并填写那里给出的表格。
- 第二步:创建一个新的应用程序,并给它一个合适的名字。
单击仪表板上的“新建”选项。您将被重定向到此页面
作者图片
- 步骤 3:转到存储 stream.py 文件的文件夹
创建一个名为’ Procfile ‘的文件,这是一个文件类型,因此,没有任何扩展名,如’。txt ‘或’。xlsx。在 Procfile 中键入以下内容
web: sh setup.sh && streamlit run stream.py
- 第 4 步:在同一个目录中创建一个名为 requirements.txt 的文件,并列出到目前为止您在项目中使用的所有模块。
- 步骤 5:创建一个名为“setup.sh”的文件,并用以下内容填充它:
mkdir -p ~/.streamlit/
echo "\
[server]\n\
headless = true\n\
port = $PORT\n\
enableCORS = false\n\
\n\
" > ~/.streamlit/config.toml
- 步骤 6:将整个文件夹上传到 GitHub repo 中,比如 this repo 。
- 第七步:打开你在 Heroku 上创建的新应用,点击“连接到 GitHub”图标
单击突出显示的图标[作者图片]
- 第 8 步:输入你的 GitHub 库名并点击连接
- 步骤 9:单击部署分支
[图片由作者提供]
瞧啊。!你的网站现在必须是活的!如果你已经做到这一步,请与我联系或留下评论,让我知道这篇文章是否对你有帮助。祝你未来的项目一切顺利。
使用 Flask 的机器学习模型的端到端部署
使用 Flask 设计和构建利用机器学习的端到端 Web 应用程序
利用数据和可视化技能——照片由 Arian Darvishi 在 Unsplash 上拍摄
机器学习很漂亮——也很漂亮,如果它工作正常的话。然而,你只能把结果展示给和你一样理解过程的人。当有人知道它是如何工作的时候,魔力就消失了,并且在没有视觉帮助的情况下带领其他人经历它是什么…就像看着油漆变干一样令人兴奋。
因此,一个有效的思路是有一些视觉辅助,一些易于使用的东西,以及一些可以显示输出的东西,而不局限于 Jupyter 笔记本或终端。这里介绍 Flask : 一个完全用 Python 编写的 web 应用框架。它拥有最小的设置和快速的开发时间。这意味着学习一门只用于 web 部署的语言没有额外的麻烦——普通的 Python 也可以。
使用 Flask,我们现在可以将我们的机器学习模型带入生活(或者至少将它们带出笔记本和终端)。我们开始吧!
示例问题—问题分类
机器学习可以用来解决分类问题,并建立一个实用的模型,我们来看看一个简单而有效的挑战——问题分类。有关挑战的详细信息可在这里找到。
这个问题的目标是开发一个简单的机器学习模型,稍后可以使用 Flask 部署该模型。
准备数据集
数据集非常标准,有 5 列:Index、Questions、Cat0、Cat1、Cat2。
Cat1 只是 Cat0 中对应数据点的缩写。第一类只有 6 个类别,而第二类更深入,对每个问题都有更细的分类。作为准备数据集的一部分,我们可以检查唯一值以处理类不平衡,删除重复值并移除空值(如果有)。需要注意的另一个有趣的点是,我们不能直接使用分类标签,所以我们必须将 Cat1 和 Cat2 数据点中的每一个都转换成一个类别号,以便在我们的模型中用作目标变量。
这可以简单地通过以下方式完成:
#read the dataset
df = pd.read_csv('dataset.csv')#drop duplicates and values, if any
df.drop_duplicates(inplace=True)
df.dropna(inplace=True)
df.reset_index(inplace=True, drop=True)#convert categorical values into class numbers for our target variables
df['cat_label'] = pd.factorize(df['Category1'])[0]
df['topic_label'] = pd.factorize(df['Category2'])[0]
决定特征提取方法
如前所述,文本/分类值不能直接用于机器学习模型。要使用它们,我们需要将它们转换成数值或特征。文本中的特征提取和特征工程是指从数字格式的数据中提取信息。为了简单起见,我们使用简单直观的方法将文本转换成可用的特征。TF-IDF 是一种将文本数据建模为可用特征的非常直观的方法:
TF-IDF:语料库中所有单词的术语频率 x 逆文档频率。
制作分类模型
我们现在已经选择了一种将文本转换成特征的方法,并且已经形成了目标变量。现在剩下的就是拟合一个模型……但是,哪一个呢?在决定最终的模型之前,测试不同的模型是很重要的。此外,通过 sklearn — 建模最佳分类算法是一项非常简单的任务,我们可以使用简单的 fit()和 predict()查看不同模型的输出。
对于这个项目,我们选择 SVM,线性支持向量机,决策树和随机森林作为我们的分类器。
将我们到目前为止讨论的内容放入一个简单的工作流中,我们得到:
为了评估我们的哪个模型工作得更好,我们需要计算和比较分类器之间的精确度。由于这是一个重复的过程,我们可以通过定义一个函数来评估分类器,使我们更容易。
运行评估脚本后,我们发现 LinearSVC 比其他的要好一些。在这一点上,我们可以将它作为我们的机器学习模型,但我们也可以调整并可能提高我们模型的性能。因此,下一步是使用 GridSearchCV 为我们的模型找到最佳参数。
对于任务 2,我们也可以遵循相同的流程。没有什么变化,除了通过记住我们数据集中的类不平衡来建模。
因为我们已经找到了我们的最佳模型并可能对其进行了调整,所以我们希望保存它以直接运行未来的预测,而不必再次训练分类器。回想一下,我们还使用了一个适合我们数据的矢量器。因此,也必须为我们的测试和预测数据存储相同的矢量器。
请记住,我们在类别 1 中有 6 个班级,在类别 2 中有 40+个班级。记住它们的一个简单方法是在 json/text 文件中保存 category_var:class_num 的映射。这很容易做到,就像这样:
#dictionaries to map category to label
cat_label_dict, topic_label_dict = {},{}
for val in df['Category1'].unique():
cat_label_dict[val] = df[df['Category1']==val]['cat_label'].unique()[0]
for val in df['Category2'].unique():
topic_label_dict[val] = df[df['Category2']==val]['topic_label'].unique()[0]#print and check the dictionaries
print(cat_label_dict, topic_label_dict)#save the mappings in text files
with open('category_labels.txt', 'w') as f:
f.write(str(cat_label_dict))
with open('topic_labels.txt', 'w') as f:
f.write(str(topic_label_dict))
从保存的文件中制作预测函数
我们已经成功地完成了模型的训练、调整和保存!然而,我们的代码有点乱:到处都是,而且结构也不是很好。为了预测结果,我们需要一个函数将输入句子转换为小写,使用保存的矢量器提取特征,并使用保存的模型调用预测函数。为此,让我们从保存的文件中创建一个简单的预测函数。这段模块化代码也将在我们部署应用程序时对我们有所帮助。
制作 web 应用程序来部署模型
因为我们的 ML 模型现在已经准备好了,并且可以使用单个函数调用,所以我们准备部署它。对于这一部分,我们需要在本地机器上安装 Flask。
可以通过在终端中运行以下命令来简单地安装 Flask:
sudo apt-get install python3-flask
pip install flask
对于这部分,首选 VSCode 之类的 IDE 或者 Sublime Text 之类的编辑器。它们有助于自动完成,并对我们的代码结构有很好的了解。
每个基于 Flask 的 web 应用程序都有 3 个不同的东西——一个**‘模板’文件夹(存储 html 页面),一个‘静态’文件夹(存储 css 设计和一个可选的‘图像’**文件夹:存储图像),以及一个运行应用程序的 python 文件(通常按照惯例命名为 app.py)。
由于许多人(像我一样)不太擅长设计 Web 应用程序,一个快速的解决方法是使用已经可用的 HTML 模板。选择一个适合您的用例,或者可以修改以适合您的用例。这里的是免费 html 模板设计的起点。
可以演示一下模板,自己试试。您也可以在在线编辑器中进行更改,并直接在浏览器中查看。如果你不习惯使用传统的编辑器和检查输出,它可以帮助你快速设计网页。
对于这个项目,我为我的 web 应用程序选择了一个主页和一个预测页面。确保所有的 html 文件都在 templates 文件夹中,它们的 css 在 static 文件夹中。
在应用程序的预测页面中可以看到主要的实现—
最后,我们构建我们的 app.py,它运行我们的后端:ML 模型。为此,我们使用前面编写的预测函数,并为每个 html 页面定义路径。通过定义路由,我们的意思是告诉代码当点击一个特定的本地 html 页面引用时要呈现什么页面。
此外,因为我们接受模型的输入(通常通过 HTML 表单),所以我们需要相应地设置表单动作和方法。一个非常简单的方法是使用 url_for ,它将路由直接设置到大括号内的参数。在这里,我们将其设置为 predict(),这是 app.py 中预测函数的名称。
为了访问在 html 页面上使用表单进行的任何输入,我们使用 requests . form[‘【T2]’]。
将所有这些合并到一个 app.py 文件中,我们将它编写如下—
要运行我们的应用程序,我们只需输入
python3 app.py
结果应该是这样的:
在端口 5000 上成功运行 Flask 应用程序
这标志着使用 Flask 部署我们的项目的结束。
为什么要学习如何为项目制作 WebApps?
作为一名机器学习工程师/数据科学家,或者是任何数据相关领域的爱好者/实践者,展示产品端到端开发的知识非常重要。Flask 与 pure Python 无缝集成,因此很容易开发应用程序。Flask 应用于构建概念证明、演示解决方案以及展示发展和增长。
学习 Flask 这样的简单框架也有助于完善开发人员的技能。一般来说,数据科学更依赖于你如何有效地向一群可能并不特别关注技术或数据的人展示你的想法。
数据科学家本质上仍然是软件工程师。因此,构建、测试、开发和部署应用程序应该是每个软件工程师技能的一部分。
如果你喜欢这篇文章,发表评论并鼓掌表达你的感激之情!您也可以使用我的 linkedin 个人资料直接与我联系。
这个项目的全部代码可以在我的 github 仓库中找到。
端到端机器学习平台比较
对业界领先的机器学习平台的简短对比。
由 Martin Reisch 在 Unsplash 上拍摄的照片
任何参与将机器学习模型部署到生产中的组织都知道它会带来业务和技术挑战,并且通常会通过使用机器学习平台来解决这些挑战中的一些挑战,并辅以一些 MLOps 流程来提高团队的成熟度和治理。
对于在生产中运行多种模型并寻求采用 ML 平台的组织,他们通常要么在内部构建一个端到端的 ML 平台(优步、 Airbnb 、脸书学习者、谷歌 TFX 等),要么购买。在这篇文章中,我将比较一些你可以买到的 ML 平台。
什么时候需要一个端到端的 ML 平台?
你应该先回答另一个问题。“你想解决什么问题?”。如果你想不出任何现存的问题,那么实施新技术就毫无意义。然而,如果您遇到了一些问题,例如,跟踪生产中的模型或版本,增加对 ML 实验的管理,随着数据科学团队的增长共享笔记本电脑,或者主动监控数据漂移和/或功能漂移,那么您很可能正在或即将走上实施 ML 平台组件的道路。
为了帮助这个过程,我对我认为的 ML 平台的关键组件进行了高层次的比较。
比较
以下比较考虑了开箱即用的功能。例如,不部署开源解决方案来弥补功能上的差距或自行开发。
点击此处查看链接:https://gist . github . com/ash his/f54a 523 bb 5390d 55 a 46 FCE 415 bcdc 691
我在从 github 嵌入表格时遇到了一些问题,所以如果你想浏览上表中的链接,请点击这里。
特色店?
您可能已经注意到,没有一个解决方案提供功能存储。特色商店是一个相当新的组成部分,我怀疑在不久的将来会有更多的组织将它加入到他们的 ML 平台中。他们有一些可用的开源解决方案,在这个神奇的网站上有更多的研究资料。记住,在把时间和金钱投入到一个无关紧要的问题之前,把注意力集中在你要解决的问题上。
“你想解决什么问题?”
结论
在这篇短文的结尾,我想强调一些其他值得一提的产品,但它们没有包括在这个比较中。 DataRobot , IBM Watson Studio , H2o.ai ,数据砖块 & Cloudera 。随着机器学习领域的迅速变化,我将努力在未来几个月保持这篇文章的最新状态。你不必听我的,只要看看今年 Spark + AI 峰会上 Databricks 的 MLflow 博客上的所有公告就知道了!
如果您想将您的产品添加到这一比较中,请通过我的 LinkedIn 联系我。
关于我:我是数据&机器学习的产品负责人,生活在商业、数据和机器学习的交汇点。想联系的可以在LinkedIn上联系我。
端到端机器学习项目:第二部分
杰克·安斯蒂在 Unsplash 上的照片
在之前的帖子中,我们看到了我如何训练一个图像分类模型,从数据准备开始到训练模型的不同迭代,都使用了卷积神经网络和转移学习来获得一个对美钞进行分类的最终模型。如果你还没有,我建议你先浏览一下那篇文章,然后再来看这篇文章。
Part-1(前一篇) :准备数据并训练图像分类模型
Part-2(后一篇):使用 Flask 和 Docker 部署模型
训练完模型后,下一个挑战就是展示它。我不想在云资源托管上花费太多,所以我尝试了许多不同的选项,但找不到一个看起来足够容易快速启动和运行的选项。相信我,当我说有大量的资源和教程讨论如何创建和训练你的深度学习模型,但只有少数资源谈论部署这些模型。
用什么“工具”?
当我接近完成这个模型的时候,这个问题在我的脑海里打转。我知道我想部署这种模式,但不确定平台——它应该是一个本地移动应用程序还是一个 web 应用程序。在进一步讨论之后,我选择了一个快捷的 web 应用程序,这样就可以通过浏览器从任何设备访问它。
我选择了用Flask*—*一个轻量级的 WSGI web 应用框架。它是可用的最流行的 Python web 应用程序框架之一,以其简单易用以及能够扩展以构建更复杂的应用程序而闻名。
对于这个部署,我选择使用我现有的云服务器— a Nanode ,以避免投资额外的云资源,并决定采用基于容器的方法。
容器是一个标准的软件单元,它将代码及其所有依赖项打包,以便应用程序能够快速可靠地从一个计算环境运行到另一个计算环境。(来源)
我决定使用 Docker、 ,它提供了一种使用公共运行时在同一台机器上运行多个容器的方法,即 Docker 引擎 。
图 1:使用 Docker 的容器化应用程序
对于托管应用程序,我选择了 Nginx,它提供了一个代理服务器来托管您的 web 应用程序。
NGINX 是一个免费、开源、高性能的 HTTP 服务器和反向代理,以及一个 IMAP/POP3 代理服务器。NGINX 以其高性能、稳定性、丰富的特性集、简单的配置和低资源消耗而闻名。(来源)
构建基于 Flask 的 web 应用程序
我发现这个非常有用的 GitHub 项目 [1],它提供了一个简单的模板来使用 Flask 将你训练好的图像分类模型部署为一个 web 应用。我对[1]中的代码做了一些修改,通过加载我训练过的模型(我正在使用一个*)使它特定于我的模型的目标。tf* 模型而不是使用 .h5 文件)、设置输出类名、设置成功预测的概率阈值等。所有这些更改都是对作为 flask web 应用程序主要后端的 app.py 文件进行的。
我还对这个项目的 CSS(网页样式)和 JavaScript 文件做了一些小的改动。
你可以参考这个项目的我的 GitHub 库的所有这些变化。
设置服务器(正确…)
这是这个部署难题中最重要的一块,我可能花了最多的时间来研究、完成和设置它,甚至比构建模型本身还多。
第一步是根据操作系统(OS)在您的服务器上安装最新版本的 Docker。我有一个 Ubuntu 盒子作为我的服务器,所以我按照这个快速指南 [2]安装 Docker,这是一帆风顺的。
下一步是找到一种方法,使用多个 docker 容器在同一服务器上部署不同的应用程序。经过大量的谷歌搜索,我偶然发现了这篇令人惊叹的文章【3】,它与我试图实现的目标相似,作者用非常好和简单的方式解释了这一切。
图 2:使用 Nginx 反向代理和 Docker 的部署
这里,nginx 反向代理充当这个设置的主容器,监听外部端口 80 (HTTP)和 443 (HTTPS),充当世界和从容器之间的通信媒介。从容器本身的内部工作是隐藏的,用户在访问这些应用程序时看不到任何区别。
按照[3]中的示例 docker-compose.yml ,我为充当主容器的服务器设置了我的 nginx 反向代理和 SSL 版本,同时按照 docker-compose 中的定义设置了网络。
下一步是创建一个从属容器,它将托管我的 web 应用程序。为此,我基于[3]和这个 post [4】的组合创建了一个容器应用程序,它使用 docker 文件来设置承载项目的容器。基于我的项目需求,我修改了 docker-compose 和 Dockerfile。
图片-3: Dockerfile(作者提供图片)
项目容器基于 docker hub 的tensor flow-2 . 0 . 0-py3 docker image,使用 python3 和 tensorflow-2.0。点击这里查看你可以在项目中使用的其他 tensorflow 图片列表。下载完基础映像后,我将项目的 flask 应用程序和模型复制到这个容器中,并使用 pip 安装运行项目的需求。
图 4: Docker 撰写(作者提供照片)
最终的 docker-compose 文件使用上述 docker 文件来创建一个名为 usbills 的容器,该容器托管模型和 web 应用程序。它还创建了一个 nginx 服务,这个服务依赖 依赖**usbills容器,也就是说,如果构建 us bills 容器时出现问题,nginx 容器将不会被创建。
这个 nginx 容器的 environment 部分设置了一个 VIRTUAL_HOST,它是这个 web 应用程序的 DNS 名称,一旦部署了这个容器,就可以访问它。这个 nginx 容器充当从容器,并根据从服务器主容器接收的请求工作。
一旦创建了这两个文件,并且我确保了主容器正常工作,那么只需编写一行命令就可以托管这个应用程序了。
$ docker-compose up -d
结论
如上面的 docker-compose 所示,通过访问这个链接,可以从任何设备和浏览器访问这个 web 应用程序。在我最终建立和部署这个模型之前,我花了很多时间搜索、阅读、理解、尝试和失败。这种多容器部署方法还为将来在同一台服务器上使用类似的 docker-compose 设置轻松部署任何其他应用程序奠定了基础。
希望您喜欢这个两部分的系列。我知道这种方法可能不适合每个人,但希望它能帮助那些和我处境相同的人,他们正在寻找部署我训练有素的模型的方法,而不必花费大量的云资源。请随意使用这种方法来共享您的模型部署的链接,或者如果您有任何其他比这种方法更好的方法。
不断学习,打造酷炫模型。下次见…
参考
[1] 用 flask 作为 web app 在 10 分钟内部署 Keras 模型
【2】如何安装 Docker 并拉取映像进行容器部署
【3】托管多个站点使用 Docker 和 NGINX 反向代理使用 SSL
【4】NGINX 作为 flask app 的反向代理使用 Docker
【5】什么是容器?
端到端机器学习项目:第 1 部分
比约恩·斯内尔德斯在 Unsplash 上的照片
端到端机器学习 关注的是准备你的数据,在上面训练一个模型,然后部署那个模型。这两部分系列的目标是展示如何为图像分类模型开发和部署端到端的机器学习项目,并使用迁移学习。
尽管有大量的其他在线资源向您详细展示了如何构建您自己的模型,但是很少有资源深入研究如何部署这些模型。本文是第二部分的前身,第二部分将展示部署步骤。如果你已经熟悉构建这样一个模型,并且正在寻找如何部署它的方法,那么我建议你浏览一下这篇文章,看看第 2 部分。
第一部分(本文):准备数据并训练图像分类模型
第二部分:使用 Flask 和 Docker 部署构建好的模型
机器学习 模型目前被广泛用于构建聊天机器人、语音助手、无人驾驶汽车等。一个具体的进步是在图像识别和分类领域。卷积神经网络(CNN)尤其被证明在从图像中学习方面非常有帮助,这导致了在创建最先进模型方面的重大突破,如 Resnet 、 Alexnet 、 Inception 等。这已经被证明在 Imagenet 数据集上对图像进行分类时非常有效。
在这篇文章中,我们将看到如何从头开始训练一个图像分类模型,并使用 Resnet 模型中预先训练好的权重。这种技术称为迁移学习,非常受欢迎,因为它有助于使用使用大得多的数据集和计算资源训练的权重,以最小的变化应用于另一个数据集。通常,您只需根据数据集更改输出图层,就可以从这些预训练的权重中获益。这个项目中模型的目标是对不同的美钞进行分类,并使用 Tensorflow 2.x 和 Keras 构建。
要求
第一个挑战是收集数据。由于找不到任何适合这个项目的数据集,我最终拍摄了不同美钞的照片来创建我自己的数据集。该最终数据集包含大约 180 幅图像,其中包括一些负图像,即没有任何美钞的图像,因此当图像中有美钞时,模型可以更好地区分。
我使用paper space Gradient来训练模型,这非常类似于 Google Colab,并提供免费的 GPU 和基于 Jupyter 笔记本的环境来训练模型。在我看来,这上面的免费 GPU 比 Google Colab 里面提供的好一点。
数据准备和加载
由于这些图像的大小都不同,第一步是做一些数据准备,并将它们的大小调整为相同的大小。Resnet 期望输入图像大小为 224x224 ,因此我调整了数据集中图像的大小以匹配。我还使用数据扩充技术来补充我的数据集,这也有助于减少过度拟合。
数据扩充 通过应用产生看起来可信的图像的随机变换,帮助从现有训练样本生成更多训练数据。目标是在训练时,你的模特永远不会两次看到完全相同的图片。这将模型暴露给数据的更多方面,从而允许它更好地进行归纳。
如下图 1 所示,对图像进行了处理和加载。
图片-1:数据准备步骤(作者提供图片)
20%的可用图像,没有增强,被留在一边用于 验证 。
重要的是保持验证集不变,以便更好地评估您训练的模型。
剩余的图像用于训练模型。类别标签采用一键编码。
图片-2:班级指数(作者照片)
图 3:可视化数据集(作者照片)
训练一个简单的 CNN 模型
既然我已经加载并扩充了数据集,下一步就是训练模型。我首先创建一个简单的 CNN 模型,它有一个由 4 个卷积层和最大池层组成的集合,然后是一个带有 T2 激活函数的输出层。
图 4:简单的 CNN 模型架构(作者拍摄)
我把这个模型设定为 100 个 纪元 *。*我还为 使用了一个回调函数,提前停止(more info), 当它看到模型没有进一步改进并且开始过拟合时,就停止训练。对于该模型训练,验证损失在第 30 个时期附近停止下降,并且由于提前停止,训练在第 40 个时期停止。使用另一个回调函数— 模型检查点 保存第 30 时段的最佳模型—。**
图 5:简单的 CNN 模型图(作者照片)
使用迁移学习训练模型
简单的 CNN 模型在验证集上表现不太好,所以尝试创建更好的模型的下一步是使用迁移学习。我选择了 Resnet50v2 作为基础模型的 imagenet 权重。感谢 Keras,它使得使用TF . Keras . applications包在一行中获得这些权重变得容易得多,拥有一个模型架构列表,如 resnet、inception 等。用他们预先训练好的重量。
在开始编译和训练基础模型之前,冻结(防止训练期间体重更新)是很重要的。您可以通过设置
layer.trainable = False
来冻结模型的单层。一个模型可以有许多层,所以将整个模型的可训练标志设置为假将冻结所有层。
在冻结了基本 Resnet50v2 模型的层之后,我添加了一个 GlobalAveragePooling 层,然后是一个激活了 softmax 的密集层,以获得所有类的预测值。
图片-6:迁移学习模型架构(作者提供图片)
注意,在图 6 中,大约 2350 万个参数(对应于基本 Resnet50v2 模型)被冻结并标记为不可训练参数。我们只训练大约 14000 个与最终输出层相关的参数。
下一步是使用 adam optimizer 编译和训练模型,其中分类 _ 交叉熵损失是根据准确性度量计算的。
注意这里使用的 categorical _ crossentropy,因为每个标签都由一个独热向量表示。如果单个值(类的索引)代表每个标签,应该使用 sparse _ categorical _ crossentropy。
与简单的 CNN 模型类似,我将这个模型设置为使用相同的两个回调函数训练 100 个纪元,但这个模型的性能甚至更差。验证损失在仅仅 4 个时期后开始增加,这非常糟糕,但这可能是因为基础模型的预训练 imagenet 权重不直接与我的数据集一起工作,并且可能我必须重新训练基础模型的一些层,以帮助它学习特定于我的数据集的特征。
使用迁移学习对模型进行微调和训练
预先训练的基础 Resnet50v2 模型在这个现成的数据集上表现不太好,但仍有一些希望,以 微调 的形式。
****微调基础模型是迁移学习中的一个过程,在这个过程中,你训练模型的最上面几层,保持这些层的权重不变。这将强制将权重从通用要素映射调整为与这些顶层的当前数据集特定关联的要素。
在使用了几次之后,我发现调整基本模型的前 70 层在这个数据集上工作得非常好。您可能需要经过几轮讨论才能得出适合您的特定数据集的数字。 Resnet50v2 模型总共有 190 层,不包括输出层,所以我保持前 120 层的权重冻结,并在我的数据集上重新训练后 70 层的权重。
图 7:微调的模型架构(作者提供照片)
图 8:微调后的模型拱门(作者拍摄)
如果你仔细观察图 8,你会发现这个微调模型有超过 1800 万个可训练参数,相比之下,当我保持基本模型的所有权重不变时,只有大约 14000 个可训练参数(参见图 6)。
与其他两个模型类似,我将这个经过微调的模型设置为使用相同的两个回调函数运行 100 个时期。在第 24 代左右,验证损失开始非常缓慢地增加,这表明模型从这一点开始缓慢地过度拟合。最佳模型在这一瞬间被保存。
图 9:微调后的模型图(作者提供照片)
结论
在使用不同的模型进行了几次迭代之后,我能够训练一个在我的数据集上表现良好的模型。迁移学习肯定很有帮助,并且是一种在你自己的数据集上快速建立模型的巧妙技术,同时获得预先训练的成功模型的好处。
改进该模型的下一步将是添加更多数据,并尝试使用类激活图(CAMs) 来了解模型关注图像的哪些部分。
你可以在这里 找到用来训练这三个型号 的笔记本和代码。
**在本系列的下一部分中,我们将看到如何使用 Flask 和 Docker 部署训练好的模型。现在就来看看吧,享受创建新数据集、训练模型和部署它们的乐趣。
下次见……
端到端机器学习项目:综述和分类
将评论分为正面或负面的项目
图 1(来源:作者)
在本文中,我们将讨论一个分类问题,包括将评论分为正面或负面。此处使用的评论是客户对 ABC 服务的评论。
数据收集和预处理
这个特定项目中使用的数据是从网上搜集的,数据清理是在这个笔记本中完成的。
在这篇文章中,我们将学习如何使用 Python 抓取 web 数据。简化。
towardsdatascience.com](/web-scraping-scraping-table-data-1665b6b2271c)
在我们抓取之后,数据被保存到一个.txt file
文件中,这里是一行文件的例子(代表一个数据点)
{'socialShareUrl': 'https://www.abc.com/reviews/5ed0251025e5d20a88a2057d', 'businessUnitId': '5090eace00006400051ded85', 'businessUnitDisplayName': 'ABC', 'consumerId': '5ed0250fdfdf8632f9ee7ab6', 'consumerName': 'May', 'reviewId': '5ed0251025e5d20a88a2057d', 'reviewHeader': 'Wow - Great Service', 'reviewBody': 'Wow. Great Service with no issues. Money was available same day in no time.', 'stars': 5}
数据点是一个字典,我们对reviewBody
和stars
感兴趣。
我们将评论分类如下
1 and 2 - Negative
3 - Neutral
4 and 5 - Positive
在收集数据时,网站上有 36456 条评论。数据高度不平衡:总评论中 94%是正面的,4%是负面的,2%是中性的。在这个项目中,我们将在不平衡数据和平衡数据上拟合不同的 Sklearn 模型(去掉过多的正面数据,这样我们就有相同数量的正面和负面评论)。)
下图显示了数据的构成:
图 2:数据构成(来源:作者)
在图 2 和上面的图中,我们可以看到数据非常不平衡。这可能是问题的征兆吗?我们会看到的。
让我们从导入必要的包开始,并定义我们将用来对给定的审查消息进行分类的类Review
这里,我们将加载数据,并使用Review
类将评论消息分类为正面、负面或中性
Wow. Great Service with no issues. Money was available same day in no time.POSITIVE
将数据分成训练集和测试集
Size of train set: 25519
Size of train set: 10937
在我们继续深入之前,我们需要理解单词袋的概念。
词汇袋
正如我们所知,计算机只理解数字,因此我们需要使用单词袋模型将我们的评论消息转换成数字列表。
一个单词包是描述单词在文档中出现的文本表示。它涉及两件事:一是已知单词的词汇。对已知单词的存在的测量。
单词袋模型是在文档分类中使用的支持模型,其中每个单词的出现(频率)被用作训练分类器的特征。
举例:
考虑这两个评论
- ABC 汇款团队的卓越服务。推荐
- 糟糕的服务。交易延迟三天。不推荐。
从上面的两个句子,我们可以推导出下面的字典
【优秀,服务,通过,通过,ABC,汇款,团队,推荐,不良,交易,延迟,为,三,天,不要】
我们现在对这个字典进行标记化,以生成下面两个数据点,现在可以用它们来训练分类器
图 3(来源:作者)
在 python 中,标记化是按如下方式完成的
['abc', 'bad', 'by', 'days', 'delayed', 'don', 'excellent', 'for', 'recommend', 'remit', 'services', 'team', 'the', 'three', 'transaction'][[1 0 1 0 0 0 1 0 1 1 1 1 1 0 0]
[0 1 0 1 1 1 0 1 1 0 1 0 0 1 1]]
既然我们已经理解了单词袋的概念,现在让我们将这些知识应用到我们的train_x
和test_x
中
在不平衡数据中训练模型
此时,我们已经有了可以用来拟合模型的向量,我们可以继续这样做了
支持向量机
Review Message: easy efficient first class
Actual: POSITIVE
Prediction: ['POSITIVE']
图 4:拟合 SVM 产生的混淆矩阵(来源:作者)
训练的其他模型包括集合随机森林、朴素贝叶斯、决策树和逻辑回归。一个链接到完整代码。
不平衡数据下的模型性能评估
- 精度
使用准确性度量对模型进行评估,结果如下
图 5:模型在不平衡数据上的表现(来源:作者)
我们得到了 90%的准确率,是正确的还是有问题?答案是,有问题。
数据是不平衡的,使用准确性作为评估标准不是一个好主意。以下是类别分布情况
----------TRAIN SET ---------------
Positive reviews on train set: 23961 (93.89%)
Negative reviews on train set: 1055 (4.13%)
Neutral reviews on train set: 503 (1.97%) ----------TEST SET ---------------
Positive reviews on test set: 10225 (93.48%)
Negative reviews on test set: 499 (4.56%)
Neutral reviews on test set: 213 (1.95%)
如果分类器正确预测了测试集中所有正面评论,而没有负面和中性评论,会发生什么?分类器的准确率将达到 93.48% !!!!!!
这意味着我们的模型将有 93.48%的准确性,我们将认为该模型是好的,但在现实中,该模型“只知道最好”如何预测一个类别(正面评论)。事实上,从图 4 来看,SVM 预测根本没有中立的评论
为了进一步理解这个问题,让我们引入另一个度量: **F1 得分,**并用它来评估我们的模型。
- F1 得分
F1 分数是精确度和召回率的调和平均值。
精确度和召回率衡量模型正确分类正面案例和负面案例的程度。在这里阅读更多。
当我们根据这个指标评估我们的模型时,结果如下
图 6(表格) :不同分类器的 F1 分数(来源:作者)
图 7(绘图) :不同分类器的 F1 分数(来源:作者)
从图 6 和图 7 中,我们现在知道模型在分类正面评论方面非常好,而在预测负面和中性评论方面很差。
使用平衡数据
作为平衡数据的一种方式,我们决定随机删除一些积极的评论,以便我们使用均匀分布的评论来训练模型。这一次,我们在 1055 条正面评论和 1055 条负面评论上训练模型。我们也放弃了中立阶级。
图 8:平衡数据的分布(来源:作者)
(您也可以考虑使用过采样技术来解决数据不平衡的问题)
训练完模型后,我们得到了以下结果
图 9:平衡数据的模型精确度(来源:作者)
SVM 获得了 88.9%准确率的最佳结果,在检查 F1 分数(如下)后,我们现在可以意识到,这些模型预测负面评论与正面评论一样好。
图 10(表格) :不同分类器的 F1 分数(来源:作者)
图 11(绘图):不同分类器的 F1 分数(来源:作者)
如果我们观察显示 SVM 结果的混淆矩阵,我们会注意到该模型在预测这两类中都很好
图 12:使用 SVM 结果生成的混淆矩阵
找到完整的代码在这里
结论
在完成这个项目后,我希望你能够了解到:
- 根据不平衡的数据拟合一个或多个模型可能(在大多数情况下确实如此)导致不良结果。
- 在处理不平衡的数据时,准确性不是一个好的衡量标准。
- 大部分工作是在预处理阶段完成的。
感谢您的阅读:-)
TFX 在 TensorFlow 2.x 上的端到端机器学习
去年年底 Tensorflow 2.0 发布时,我非常兴奋。毕竟,它承诺了比 1.x 版本更令人愉快的开发人员体验(或者被称为来自地狱的 Java 的深度学习等价物)。对部署模型有强大支持的 Keras 层?算我一个!
然而,当我意识到对将 TF 2.0 模型投入生产的支持并不是我想象的那样时,我的兴奋是短暂的。当然, TensorFlow Extended 是一个选项,但考虑到文档尚未跟上,这不是一个特别令人愉快的选项。
尽管如此,我还是不耐烦了;还有,急于执行。接下来是一段充满泪水和欢呼的艰苦旅程,所有人都在寻找一个真正的奖励,那就是一个工作的机器学习管道。我向你们展示我在 r̶a̶n̶t̶s̶的发现,希望你们不必重蹈我的覆辙。不管怎样,直到下一个版本。
这是(不是)什么
这篇文章绝不是关于构建生产就绪的 TF 2.0 管道的方法的权威文章。它展示了部署 ML 模型的一个可能的工作流,该工作流考虑了内存约束和训练服务偏差(以及其他因素)。如果这些概念听起来很陌生,我推荐阅读谷歌的机器学习规则。有神经网络和机器学习生命周期的经验肯定会有帮助。
Gojek 采用的机器学习生命周期示例
您将学习如何:
- 使用 TF 变换执行特征插补和缩放
- 使用 Keras functional API 和特性列构建模型
- 为服务于的 TF 导出一个重用转换图的模型
为了简短起见,我将只展示代码片段。
1.安装依赖项
您将需要以下 Python 包。因为我们将使用 Apache Beam 来运行我们的 TF 转换管道,所以让我们也安装它。
*pip install apache-beam==2.16.0 tensorflow==2.0.0 tensorflow-transform==0.15.0*
2.使用 TF 变换预处理数据
本指南假设读者熟悉 TF 转换,这涉及到在一个preprocessing_fn
中编写由射束管道执行的转换。关于如何开始的更多信息可以在这里找到。
让我们为一个数值变量age
编写一个简单的转换,用平均值估算缺失值并应用特征缩放。
*import tensorflow as tf
import tensorflow_transform as tftdef preprocessing_fn(inputs):
outputs = inputs.copy()
age = outputs["age"]
mean_age = tft_mean(age)
age = impute(age, -1, mean_age)
outputs["age"] = tft.scale_to_z_score(age)
return outputs*
停下来。TF 变换不支持使用tft.mean()
分析器计算平均值吗?为什么我们需要自己编写tft_mean
的实现?这是因为 TF 变换有一个已知问题,其中 nan 可能会为某些分析器产生意外结果。为了解决这个问题,我们只使用非空值来计算平均值。
*def tft_mean(tensor):
finite_indices = tf.math.is_finite(tensor.values)
finite_values = tf.boolean_mask(tensor.values, finite_indices)
return tft.mean(finite_values)*
现在,让我们使用平均年龄来估算缺失值。有两种方法表示缺失值:第一,通过使用稀疏处理器进行排除;第二,通过使用一些任意值(例如,-1
代表数字变量,或者NULL
代表分类变量)。让我们考虑这两种情况。
*def impute(tensor, missing, replacement):
sparse = tf.sparse.SparseTensor(
tensor.indices, tensor.values, [tf.shape(tensor)[0], 1]
)
dense = tf.sparse.to_dense(sp_input=sparse, default_value=replacement)
return tf.where(tf.equal(tensor, missing), replacement, dense)*
然后,您可以运行您的 TF 转换管道,不要忘记导出转换图,以便我们可以在以后重用它!
*import apache_beam as beam
import tensorflow_transform.beam as tft_beam
import tempfilewith beam.Pipeline() as pipeline:
with tft_beam.Context(temp_dir=tempfile.mkdtemp()):
# read raw data
raw_data = pipeline >> beam.io.ReadFromTFRecord(...)
# apply transformation
transformed_data, transform_fn = (
(raw_data, raw_metadata) >> tft_beam.AnalyzeAndTransformDataset(preprocessing_fn)
)
# export transform graph
_ = (
transform_fn >> tft_beam.WriteTransformFn("data/tft/")
)*
3.使用 Keras 图层和要素列构建模型
是时候进行一些功能工程了。TensorFlow 特性列为常见操作(如一键编码)提供了一个简洁的 API。让我们为一个数字变量age
和一个分类变量country
定义特性列。
*features = [
tf.feature_column.numeric_column("age"),
tf.feature_column.indicator_column(
tf.feature_column.categorical_column_with_vocabulary_list(
"country", ["America", "Japan", "China"],
)
),
]*
在 Keras functional API 中使用特性列可能有点棘手。你需要使用一个输入层来实例化一个 Keras 张量。
*from tensorflow.keras.layers import Inputfeature_inputs = {
"age": Input(name="age", shape=(), dtype=tf.float32),
"country": Input(name="country", shape=(), dtype=tf.string),
}*
我们现在可以将它输入到 Keras DenseFeatures 层,并继续定义我们的神经网络架构。
*from tensorflow.keras.layers import Dense, DenseFeatures
from tensorflow.keras import Modeloutput_1 = DenseFeatures(features)(feature_inputs)
output_2 = Dense(16, activation="relu")(output_1)
preds = Dense(10, activation="softmax")(output_2)
model = Model(inputs=feature_inputs, outputs=preds)model = model.compile(...)
model.fit(...)*
4.导出模型和调用转换图
恭喜你走到这一步!在训练我们的模型之后,我们将把我们的模型导出为一个保存的模型来部署它。为了防止训练和服务之间的偏差,我们需要加载导出的转换图,以便对服务输入运行相同的转换。
*tft_dir = "data/tft/" # location of exported transform_fntft_output = tft.TFTransformOutput(tft_dir)
tft_output.transform_raw_features(raw_serving_inputs)*
在 Tensorflow 1.x 中,当导出您的模型时,您将在serving_input_receiver_fn
中包含上述逻辑。然而,随着我们远离 TF 2.x 中的估计器 API,这个功能已经被弃用了。相反,我们需要通过覆盖save()
方法来修改 Keras 模型的服务签名。
*class ExportModel(tf.keras.Model):
def __init__(self, model, tft_dir):
super().__init__(self)
self.model = model
self.tft_output = tft.TFTransformOutput(tft_dir)
@tf.function(input_signature=[SERVING_FEATURE_SPEC])
def serving_fn(self, inputs):
transformed = self.tft_output.transform_raw_features(inputs)
return {"preds": self.model(transformed)} def save(self, output_dir):
signatures = {"serving_default": self.serving_fn}
tf.saved_model.save(self, output_dir, signatures)ExportModel(model, "data/tft/").save("data/model/1/")*
然后我们可以使用 TF 服务来服务我们的模型。
希望这有所帮助。再见。