单词云的一个世纪
由于缺乏作为可视化工具的精确性,云受到了 T2 的批评。但是它们看起来很有趣。
接下来是一系列的单词云,分别代表 20 世纪的每一个十年。每个十年的词云中的每个词都在那个十年的某个时候出现在《韦氏词典》或《牛津英语词典》中。
不过,不要让我知道具体是哪一年,因为两本词典在增加单词的时间上有所不同(因为一本反映了美国英语,另一本反映了英国英语)。每个人都可能在一个词进入流通领域后很久才加上这个词。有些词可能在某个特定的十年中出现,不是因为新造的,而是因为获得了新的含义。
我想你会同意,虽然这些词中的大多数以某种方式结合,抓住了特定十年的要点。他们抓住了它的俚语(是的, mook 听起来像 30 年代的 slam),它的重大事件(两次世界大战分别发生在十几岁和四十多岁的年轻人身上),以及它的技术进步(计算机术语甚至在 20 世纪 50 年代就开始出现,并且每十年变得更加流行)。
你还会注意到,很多看起来很现代的词出现的时间比你想象的要早得多(例如,迅猛龙,早在 20 年代就首次出现了)。
滚动愉快。。。
1900
1910
20 世纪 20 年代
20 世纪 30 年代
二十世纪四十年代
制作单词云的注意事项
我想把这些整合到一个 D3.js 可视化中——看着单词从一个 wordcloud 到下一个 word cloud 以 SVG 的形式动态显示会很酷——但是我找不到一个简单的方法来做屏蔽(不用写很多代码)。
我选择使用这个 Python repo ,它很棒,支持遮罩和自定义颜色。(遗憾的是,你不能让它输出 SVG,我可以将 SVG 加载到 D3.js 中,然后嵌入动画等。)
这篇博客文章有助于选择十年看起来合适的颜色(尽管我在这里和那里调整了她的调色板,以使每个十年都不同)。
来自未来的聊天机器人:用 Rasa 构建端到端的对话助手
Figure1: A Chatbot from future! by rawpixel on Unsplash
Y 你可能已经在我的上一篇文章中看到,我一直在使用 Rasa 构建聊天机器人。你会在 Rasa 上找到很多使用 Rasa APIs 构建聊天机器人的教程。但是我没有发现任何关于这些 API 的细节,不同的 API 参数是什么,这些参数是什么意思等等。在这篇文章中,我不仅会分享如何使用 Rasa 构建聊天机器人,还会讨论使用的 API 以及如何使用 Rasa 模型作为服务从 NodeJS 应用程序进行通信。
什么是 Rasa
Rasa 是一个开源的对话式人工智能框架。我喜欢 Rasa 的一点是,你不必拘泥于预先构建的模型或用例(Dialogflow 等)。).因此,您可以根据您的使用情形对其进行定制,这可以成为一项市场优势。Rasa 不是一个基于规则的框架(如僵尸工具),你不需要像 Dialogflow、Microsoft LUIS 或 Amazon Lex 那样担心将你的数据放在别人的云中。
Rasa 有两个主要组件— Rasa NLU 和 Rasa 核心。
NLU 是自然语言理解者。假设用户说“I want to order a book
”。NLU 的工作就是接受这个输入,理解用户的意图并在输入中找到实体。例如,在上面的句子中,意图是订购,实体是图书。Rasa NLU 内部使用Bag-of-Word (BoW)
算法寻找意图,使用Conditional Random Field (CRF)
寻找实体。尽管您可以使用其他算法通过 Rasa 来查找意图和实体。为此,您必须创建一个自定义管道。关于定制管道的细节超出了本文的范围。如果你有兴趣,可以查看这个链接。
Rasa 核心的工作主要是为聊天机器人生成回复消息。它采用 Rasa NLU ( 意图和实体)的输出,并应用机器学习模型来生成回复。我们将在稍后的 API 讨论中讨论更多可能的机器学习模型。
Figure2: Basic steps of Rasa app internally works to reply a message. Reference here.
如上图所示,输入消息由一个Interpreter
解释以提取intent
和entity
。然后,它被传递给跟踪对话当前状态的Tracker
。Policy
应用机器学习算法来确定什么应该是回复,并相应地选择Action
。Action
更新Tracker
以反映当前状态。
打造聊天机器人
假设我们正在构建一个客户服务聊天机器人。创建一个名为customer_bot
的目录,并在其中创建一个名为data
的目录。还要创建一个名为config_spacy.yml
的配置文件
$mkdir customer_bot
$cd customer_bot
$mkdir data
$vi config_spacy.yml
将中的config_spacy.yml
文件内容复制到此处。在配置文件中,我们指定了用于构建各种模型的管道类型。在这种情况下,我们使用Spacy
和Scikit-learn
来构建管道,并且仅支持如下配置中指定的English
语言:
language: "en"
pipeline: "spacy_sklearn"
您可以使用 Rasa 支持的其它管线类型,也可以创建自定义模型管线并在配置中指定它。
建立 NLU 模型
首先,我们需要建立 NLU 模型。拉莎·NLU 使用监督学习模型工作。因此,您需要训练数据来训练 NLU 模型。在训练数据中,我们需要指定该数据的intent
和entity
是什么。例如,如果机器人的输入文本是’ hi ,您可以将意图定义为’ greet '。在这种情况下没有实体。因此,训练数据集如下所示
{
"text": "hi",
"intent": "greet",
"entities": []
}
你可以使用我的 github 复制粘贴整个训练数据用于代码中。将其命名为data.json
并放入data
文件夹中。
手动创建这些 trining 数据非常耗时。因此,相反,你可以使用这个网络用户界面来创建数据来训练拉沙 NLU。
现在使用data.json
和config_spacy.yml
,我们需要训练一个 NLU 模型。创建nlu_model.py
并放在customer_bot
文件夹下。NLU 模特培训代码如下:
我们可以像下面这样调用上面的train_nlu
方法:
if __name__ == '__main__':
model_directory = train_nlu('./data/data.json', 'config_spacy.yml', './models/nlu')
让我们看看这是怎么回事。我们正在使用load_data
加载训练数据。load_data
函数读取训练数据并返回一个TrainingData
对象。然后我们使用通过config_spacy.yml
传递的配置创建一个Trainer
对象。现在使用那个trainer
对象,我们实际上可以训练数据来创建一个机器学习模型——在这种情况下,Rasa NLU 模型如图trainer.train(training_data)
所示。一旦模型被训练,我们需要将模型保存在一个目录中。我们通过调用Trainer
类的persist
方法来实现。正如您在上面看到的,在trainer.persist
中,我们指定了保存模型的目录,并为我们的模型指定了一个名称— customernlu
。
既然我们已经训练并保存了模型,我们可以像下面这样运行 NLU 模型:
def run_nlu(model_directory):
interpreter = Interpreter.load(model_directory)
建立对话管理模式
对话管理是 Rasa 核心的工作。在构建对话模型之前,我们需要定义我们希望对话如何流动。实质上,我们正在为对话模型创建一组训练示例。我们将创建一个文件stories.md
并将其放在data
文件夹中。让我们来看看stories.md
的一组样本数据。
使用 stories.md 训练对话模型
## story_001
* greet
- utter_greet
* order_product
- utter_ask_product_name
* order_product[router=829]
- slot{"router": "829"}
- action_order_product
* goodbye
- utter_goodbye
假设我们想要一个当用户说Hi
时开始的对话。我们可以将意图定义为greet
。当机器人发现一个greet
意图时,它会回复utter_greet
。utter_greet
的内容将在后面的domain
文件中定义。
插槽和动作
我们再举一个例子。假设用户说“I want to order an 829 router
”。机器人明白这是一个order_product
意图,实体是router
。实体的值是 829,这意味着有不同产品 ID 的路由器,但是用户只对 829 感兴趣。因此路由器及其值 829 在这里被定义为时隙的一部分slot{“router”: “829”}
。插槽本质上是你的机器人的内存,被定义为一个键值对。更多关于插槽的信息可以在这里找到。有时,来自机器人的回复消息不是静态消息。相反,机器人可能需要调用一些服务或执行一些其他计算来创建回复消息的内容。如上文action_order_product
所示,这些通过action
定义。在action_order_product
中实际发生的事情将在actions.py
中定义。
这个项目的stories.md
文件可以在这里找到。
关于stories
数据格式的详细说明是这里的。
定义域
我们将为名为customer_domain.yml
的域创建一个yml
文件,并将其放在customer_bot
目录中。域文件指定了slots
、intent
、entities
、actions
和templates
(例如在utter_greet
对不同话语的示例回复)。这个项目的域文件可以在这里找到。
actions.py
如果您的 bot 的回复消息都是静态消息,您不需要任何操作。但最有可能的情况并非如此。任何真实的机器人应用程序都会与一些其他服务进行通信,或者至少为它的一些回复进行实时计算。在我们的项目中,一旦产品被订购,机器人应该回复一个确认号。对于不同的用户/产品,此确认号码会有所不同。因此,产品订购流程将成为行动的一部分。为了简单起见,在我们当前的代码中,我们显示了一个硬编码的确认号,假设产品订单是成功的。
How to write an action in Rasa
你可以在这里找到这个项目的actions.py
文件。
训练对话模型
为了训练对话模型,我们将编写一个函数train_dialogue
。该函数需要 3 个参数——域文件、故事文件和训练后保存对话模型的路径。在 Rasa 中,我们使用代理类来训练对话模型。您通过传递domain
文件并指定一个policy
来创建一个agent
对象。政策本质上是模型。例如KerasPolicy
内部使用 LSTM 网络。在你的训练数据中记忆对话。根据您使用的 Rasa 核心版本,您可能有不同类型的可用策略。更多关于政策这里。
我们必须使用agent
对象的train
方法来训练使用stories.md
文件。如上图所示,您可以指定epochs
、batch_size
和validation_split
。我们将使用agent.persist
保存模型。
要运行对话模型,我们需要一个如run_customer_bot
方法所示的interpreter
对象。解释器做它所说的——解释输入给机器人的文本。凭直觉,您可能会理解,您需要之前创建的NLU model
来创建一个interpreter
对象。因为 NLU 的工作是解释传入的文本——理解intent
和entity
。然后您需要创建一个agent
对象,它接受interpreter
对象和您刚刚通过train_dialogue
方法创建的dialogue model
。一旦有了代理对象,就可以使用agent.handle_channel()
来运行将进行对话的机器人。在这种情况下,我们使用 Mac 终端作为输入/输出网关,因此我们将ConsoleInputChannel()
作为agent.handle_channel
的参数传递。Rasa 核心支持一些其他的输入通道或者你可以创建你自己的自定义通道。更多关于interpreter
的信息可以在这里找到。
你们中的一些人可能已经注意到dialogue_management_model.py
不是图 2 的 100%反映。例如,dialogue_management_model.py
中没有使用Tracker
对象。这是因为图 2 反映了内部发生的事情,而不一定是您用代码编写的内容。您仍然可以使用tracker
功能来了解对话的当前状态。关于追踪器更多的是这里。
怎么跑
本教程是在 MacBook 上完成的。按照 Rasa 文件安装 Rasa NLU 和 Rasa 核心。对于本教程,我使用了 NLU 版本0.12.3
和核心版本0.9.0a6
从我的 github 下载完整代码。
创建 NLU 模式
$python nlu_model.py
创建对话模型。注释出__main__
里面的run_customer_bot()
方法。然后运行下面的命令。
$python dialogue_management_model.py
现在取消__main__
处run_customer_bot()
方法的注释,注释掉train_dialogue()
方法的。然后再往下面跑。
$python dialogue_management_model.py
现在,您应该已经在终端中运行了 bot。
将模型作为服务使用
一旦您准备好了 NLU 和对话模型,您就可以将 Rasa 核心作为服务器运行,并从服务器应用程序与它通信
$cd customer_bot
$python -m rasa_core.server -d models/dialogue -u models/nlu/default/customernlu/ --debug -o out.log --cors *
Rasa 核心服务器默认运行在端口5005
上。假设用户说hello
。这个用户输入来自 NodeJS 服务器中的前端到后端。NodeJS 服务器希望与运行在端口5005
上的 Rasa 核心服务器通信,并希望从 Rasa bot 获得回复。下面的示例 NodeJS 代码可以做到这一点。
var messageToRasa = 'hello'
request.post(
'[http://localhost:5005/conversations/default/respond'](http://localhost:5005/conversations/default/respond'),
{ json: { 'query': messageToRasa} },
function (error, response, body) {
if (!error && response.statusCode == 200) { //body[0].text is the reply from Rasa
console.log(body[0].text)
}
else{
console.log(`Error: \n${error}`);
}
}
);
参考:
- Justina 关于如何使用 Rasa 构建一个简单聊天机器人的优秀教程
- 使用 Rasa 时的一些有趣的提示。
- 揭开拉莎·NLU 的神秘面纱。
- 条件随机场简介。
- 自然语言处理从业者指南这里。
- 带插图的 LSTM 指南。
- 更多关于 Rasa 核心政策的信息。
处理复杂 ML 问题的清单
很多时候,我们会遇到复杂的机器学习问题,这些问题很难分解为简单的子问题。那些在创业公司工作的人会想到这样一个事实,当我们试图解决如此复杂的用例时,我们经常有从一个实验跳到另一个实验的习惯。
在小队,我们的机器学习团队遇到了类似的挑战。尽管做了初步研究,我们有时会忘记我们的实验和方法。我们认识到,为了避免频繁的错误并在处理复杂的业务问题时保持清晰,我们必须有一个标准的清单。清单应该确保我们在解决任何复杂问题时不会遗漏关键要素。
在这篇博文中,我们将分享一个 三阶段清单 ,它可以用来处理复杂的 ML 问题。每个阶段都有一些检查点,可以帮助系统地解决问题。
第一阶段:问题发现和需求收集
检查点 1:了解业务问题
- 了解问题的相关背景。
- 用*第一原理思维技巧 把一个复杂的问题分解成单元问题。*
- 需要解决什么?
- 为什么需要这样做?
检查点 2:探索性数据分析
- 将数据转换成有用的格式,以进行过滤、合并和其他数据操作。
- 对几个项目进行抽样以了解数据的变化。
- 积累所有可能的统计数据,了解数据的特性,例如,数据集中不同类别之间的类别分布重叠、数据偏斜度、名义变量。
- 进行数据清理和分析,以消除任何异常值。创建相关的可视化。
- 找到一个好的在这里读上EDA。
检查点 3:定义目标
- 准确定义每个单元问题的目标。
- 准备相应的假设、约束和边缘案例。
- 列出并确定可接受的指标,如给定问题的错误率/准确度/精确度/召回数。
关卡 4:澄清疑点
- 消除相关团队/客户的所有疑虑。
- 验证目标、约束、边缘情况、假设和前提。
检查点 5:详尽的文献列表/过去的研究
- 阅读博客/文章,熟悉类似的问题和最新发展
- 查找在线发表的研究论文和调查论文。
- 探索类似问题的 Github 库。
检查点 6:选择有前途的文献
- 浏览每一篇文献,仔细阅读引言、建议的工作、图表。
- 尝试从高层次理解事物。
- 检查研究的目的是否与用例或相关阻碍因素相匹配。
- 核实文章是否介绍了现代研究,而不是历史工作。
- 直观地验证,如果提出的算法和提到的数据集似乎很好地解决了你的问题。
关卡 7:文学深潜
- 深入研究承诺的文献/可用的实现。
- 从文献中收集见解:寻找预处理步骤、特征、提议的管道和算法/架构、数据集、超参数、评估标准、其他细微差异、挑战、所用技术的利弊。
- 在开始执行之前,阅读 4-5 篇文献,也许可以从 2 篇或更多的文献中为你的实验寻找灵感。
- 我们在文学深度挖掘班遵循的一种格式是
Format used for Literature Summary while doing an exercise on literature deep-dive.
检查点 8:设计实验和流水线/算法
- 基于各种预处理、特征、分类层和从文献深度挖掘中获得的其他见解的组合,创建潜在方法的列表。
- 根据上面的列表为你的目标设计相关的实验。
- 过滤掉直觉上没有意义的实验。
- 根据 a)简单、直观且易于构建的 常识基线 对其余实验进行排序,b)根据数据集要求、实施和执行时间对实验的投资回报进行排序。
检查点 9:数据集估计和采集
- 基于文献调查,我们可以收集相关的公共数据集或要求内部数据集。
- 对不同实验所需的训练、验证和测试数据集的估计。
- 考虑到数据中的错误/异常值,可能会要求比你需要的多 20-25%的数据。
- 为数据集准备所需的模板(如果要由其他部门/客户共享)
- 遵循此处的数据验证核对表以避免差距:
- 注释模板(id、标签、时间等。)
- 每个类别的训练集的样本数
- 每个类别验证集的样本数
- 每个类别测试集的样本数
- 整个训练/验证和测试集的最小和最大样本,考虑异常值。
6.准备两套:
- 一个 虚拟集 ,用于在流水线实现过程中快速验证代码片段。
- 一个 最终设定 为最终实验岗位流水线实现。
第二阶段:实施和实验
检查点 10:执行代码
- 为预处理、特征、特征提取器、提取特征的后处理、最终特征向量形状、模型系列、架构、评估方法和度量标准定义不同的步骤。
- 为数据集和结果设计输入和输出格式。
- 基于 EDA 创建培训、验证和测试集。使用各种采样程序,如平衡集、分层集和其他采样技术。
- 设计和评估您的管道,同时考虑所有的边缘情况和限制。
- 为再现性和调试在每个步骤实现记录器。
- 使用虚拟数据集进行模拟运行,以验证管道的每个部分。捕捉 bug,修复,重新迭代。
- 从功能和代码两个角度进行验证。
- 一旦一切就绪,就开始实施。
- 配置您的系统,以便您可以轻松快速地重复实验。
检查点 11:数据准备
- 清理数据并移除异常值。验证此步骤后留下的数据是否足以用于训练和测试。
- 了解是否需要平衡数据或不平衡数据。
- 为所有父类和子类随机选择数据点。
- 形成最终的数据集,好好洗牌。
- 拆分数据并创建培训、验证和测试文件。
- 如果可能,保存上述文件,可能有助于以后重复实验。
- 训练集和验证集应该是测试集的近似副本,并且应该有足够的变化以有助于泛化。
- 如果测试集与生产过程中预期的不同,尝试消除选择偏差。
- 始终在管道中使用数据 id,即使在提供原始文件的不同排列时,也可以使用数据 id 将数据点特征映射回原始数据点。
- 如果使用扩充数据集,请确保验证集和训练集不包含同一数据点基本样本的不同扩充样本,因为这可能会提高验证准确性。
检查点 12:超参数优化
- 列出在选定的算法/管道上进行实验时可以改变的参数。
- 从博客、文献综述中找到上述参数的最佳值。
- 使用参数的默认值运行第一个实验,然后根据结果开始微调,以确定最佳值。
- 如果模型经过训练,则分析验证数据的性能。
- 如果有巨大的偏差,对超参数进行网格搜索。网格搜索可能会持续一段时间。拿杯咖啡!
- 如果你得到了一个相关的模型,进行 K-fold-cross-validation 以确保模型不会过度拟合。
- 来自 Andrew NG 在他的 DL 专业化课程 中的一些提示,a)总是在试图平衡训练和验证准确性之前过度拟合模型。b)让训练精度首先膨胀,在第一次迭代中去除漏失/ L2 正则化或任何其他过拟合减少方法。c)在训练任何深度学习模型时,使用模型检查点*、学习速率衰减和提前停止。*
- 此外,找到一个关于从深度学习专业化课程中学到的经验教训的博客。
检查点 13:定量和定性分析
- 我们应该分配足够的时间来分析实验。
- 检查在测试集上获得的模型的定性和定量结果。
- 如果在测试集上表现不好,就找原因。a)可能测试数据与预期完全不同。b)可能测试数据中存在噪声。c)可能需要处理测试集。d)可能评价方法存在根本性错误。e)可能模型有问题。
- 如果在先前实验的结果之后需要迭代,那么对实验失败的可能原因进行批判性分析。
- 在这里从各方面获得感悟,尝试打破自己的设计,找到漏洞。
- ***检查预处理数据:*预处理算法可能给出不正确的输出,这意味着我们的模型正在错误的数据上进行训练。
- ***特征形状:*检查生成的特征和特征向量形状。
- ***混洗数据:*在发送给模型进行训练之前,确保标签和数据点被混洗。
- ***使用偏移裁剪特征值:*如果我们知道特征处理过程中的某些特定操作可能会使任何特征的任何字段的值为无穷大,那么我们应该考虑使用偏移。
- 根据上述步骤决定可能的后续步骤,以获得好的和坏的结果。
- 基于分析,重复或移动到下一组实验。
检查点 14:管理实验
- 一个人可以按照电子表格来管理实验的一切,这样在后期就很容易比较了。
- 每个实验应记录的细节,a)实验标识符/名称,b)管道标识符,c)数据集标识符,d)管道组件和超参数(可以分开用于预处理、特征、分类),e)训练日志/模型日志,f)状态(成功、失败),g)失败/成功的原因,h)跟进问题。
- 做 根本原因分析 对于你的实验来说,哪些管用,哪些没用。记录失败和成功的原因。
- 在这里找到关于计划和运行实验的参考。
第三阶段:准备生产和后续步骤
检查点 15:整合
- 弄清楚如何整合模型。为生产环境准备实施管道。
- 让同行评审
- 在生产环境中使用虚拟数据集测试模型。
- 用最终设置测试模型,以检查生产结果与实验结果之间的任何差异。
检查点 16:采样
- 根据误差率估计抽样规模。您可以使用 SurveyMonkey 计算器获得具有统计显著性的样本量。
- 为您的模型进行必要的采样。
检查点 17:优化
- 现在是时候进一步优化流水线的速度、自动化、精度/召回率和可扩展性了。
- 选择下一个最佳渠道,重复或继续下一个业务问题:)
最后但同样重要的是,一旦你完成了你的研究/实验,做一个回顾。回顾和反思总是好的
- 什么进展顺利?
- 哪里出了问题?
- 重要经验!
尽管数据科学问题本质上几乎是循环的,上面的检查点没有固定的顺序。我们希望上述清单可以帮助您更全面地解决下一个数据科学问题。
班里的 ML 团队一直在使用上面的检查表来解决各种问题。感谢 Vedvasu Sharma 、 Aniket Bhatnagar 、 Medha Katehar a、 Pragya Jaiswal 为清单的清晰化所做的贡献。
闭环 NLP 查询预处理器和响应合成器
一项关于合成准确、引人入胜、上下文相关和个性化查询响应的专利申请
闭环自然语言查询预处理器和响应合成器架构接受自然语言查询并动态合成查询结果。查询结果可以是数据故事的形式。
该架构识别、选择候选响应元素,并将其组合成一致且有意义的查询结果。该体系结构还实现了可适应的传递机制,该机制响应连接带宽、查询源偏好、查询源特征和其他因素。来自多个来源的反馈调整了处理后续查询的架构
该体系结构实现了对自动生成有意义的查询响应领域中的许多困难技术问题的技术解决方案,假定手动搜索潜在相关信息的数据存储广泛且不可能。下面总结了一些技术解决方案的例子。该架构提供了用于回答问题的个性化机制,例如,响应于:提问者的角色和视角;时机考虑;语境;会话历史,包括先前的查询和响应,来自与查询实体具有相似特征的其他人的查询和响应历史,例如其他企业工程师或经理;和其他因素。该架构还可以标识输入查询中显式和隐式引用的实体,并在其搜索候选响应元素时使用所标识的实体。
该体系结构还实现查询预测,以在给定起始输入查询或输入查询序列和上下文的情况下,预先确定可能的后续查询。
该架构理解哪些度量、关键性能指标(KPI)和其他数据与输入查询的实质相关,响应于可配置的本体和其他模型,其内容为输入查询的实质提供预定义的上下文。例如,上下文可以描述一个特定的企业、它的市场、它的产品、工作流、度量以及它的企业活动。
该体系结构还识别输入查询中提出的问题类型,并将输入查询和候选响应元素与企业活动、目标、计划和其他目标相关联。该架构中的技术解决方案进一步标识输入查询中的时间参考框架、其在例如企业或竞争企业的预定义财政年度内的定位以及其他定时数据。该体系结构响应企业结构数据,例如组织结构和企业动态,以区分查询响应。
该体系结构的技术实现还实现了推荐引擎,用于在输入查询和查询结果的会话之后建议智能动作。推荐引擎提供了进一步的好处,即通过任何给定的查询和响应之后的建议、问题和数据故事来鼓励额外的交互会话。
仔细看看三种流行的人工智能技术以及它们是如何使用的
Photo by Roman Bozhko on Unsplash
从机器人流程自动化到机器学习算法,当今许多最具影响力的公司都在部署人工智能(AI)技术来推动业务成果。虽然大多数决策者都意识到新兴技术所带来的商业机会,但许多人却没有做好准备,仅仅是因为他们没有理解这些机会。
人工智能包括各种各样的技术和工具,有些已经存在了很长时间,有些则相对较新。尽管如此,有一点是明确的:企业正在更加努力地思考如何在 2018 年优先考虑人工智能。
根据国际数据公司(IDC)的数据,人工智能的广泛采用将从 2016 年的 80 亿美元跃升至 2020 年的 470 亿美元。下面让我们仔细看看三种流行的人工智能技术,以及创新公司是如何使用它们的。
机器学习
当公司谈论使用人工智能技术时,大多数指的是机器学习(ML)。作为人工智能计算最受欢迎的分支,ML 涉及通过从历史数据而不是人类命令中学习来训练算法执行任务。换句话说,计算机在没有显式编程的情况下学习。小型初创企业和主要品牌都使用 ML 来以更有效和结果驱动的方式访问、组织和决策数据。
在 SAP,机器学习是内容营销策略的重要组成部分。这家企业软件公司使用 ML 来分析内容,以便为他们的客户提供更加定制的体验。ML 算法通过主题映射发布的文章,帮助 SAP 通过内容个性化客户参与。
目标是帮助读者根据他们独特的行为和搜索历史找到更多相关的文章。对于 SAP 来说,ML-powered 技术使他们能够超越标准的推荐引擎,提供有针对性的见解和内容,在正确的时间以正确的创意体验吸引正确的客户。
计算机视觉
计算机视觉是人工智能的一个分支,研究计算机如何模仿人类的视觉以及人类查看和解释数字图像的能力。通过模式识别和图像处理,计算机视觉理解图片的内容,并对我们如何体验周围的世界产生了深远的影响。
Photo by Octavian Rosca on Unsplash
亚马逊使用计算机视觉技术,通过其亚马逊 Go 体验来改善顾客的实体购物。没有排队和结账,顾客只需使用 Amazon Go 应用程序进入商店,选择他们想要的商品,然后离开。怎么会?照相机拍下顾客购物时的照片。使用机器视觉、深度学习和传感器融合,亚马逊跟踪虚拟购物车中的商品,适当地向正确的亚马逊账户收费。
视觉引导的零售只是开始,因为计算机视觉也可能为智能城市打开大门,先进的视觉技术可能有助于减少道路上的碰撞和伤害。
机器人流程自动化
人工智能驱动的软件,如机器人流程自动化(RPA),已经成为世界各地公司的竞争优势。RPA 等数字技术提高了效率,减少了错误,甚至扰乱了公司打造客户体验的方式。
南非最大的银行标准银行通过 RPA 、ML 和认知自动化将传统流程数字化,提高了运营和后台工作的效率。结果,他们将客户入职时间从 20 天缩短到了 5 分钟!
RPA 软件为标准银行提供了应对金融服务挑战的灵活性和能力,同时与其他行业保持同步。RPA 技术减少了错误,将平凡的工作变成了有趣的事情,同时为客户提供了更丰富的体验。
总之
今天的客户期望数字的、无摩擦的体验。人工智能技术消除了对公司现有的海量数据进行解释和处理的负担。如上所述,聪明的企业使用这些工具来优化内容营销,提高运营效率,并提供屡获殊荣的客户体验。
GCP 特殊化张量流的无代码指南
边做边学。
我写这篇文章是为了让你理解 tensorflow 的细微差别,它是无代码的,通过这篇文章,你会对 tensorflow 实际上是如何工作的以及它的不同组件有一个概念。到目前为止,Google 的专长是检查实际代码和编码,以便你学得更好。这里提到的课程是 coursera 上 Google cloud 的“Tensorflow 简介”,包括向您介绍 tensor flow——Google 最著名的开源项目之一,也是 ML 行业的事实标准。学习 tensorflow 不仅可以帮助您创建模型,还可以理解和欣赏基于它构建的其他框架(如 keras 和 pytorch)的细微差别。这是一门信息量很大的课程,在三个模块中有很多东西要学。
Tensorflow,用于数值计算而不仅仅是机器学习的开源平台。写出用有向无环图表示的复杂数学函数。你可以借助 python 这样的高级编程语言来编写。名字从何而来?一维数列称为数组,而二维数组称为矩阵。现在三维数组被称为张量。张量是数据的 n 维数组(通常是 3 维或更多维)。Tensorflow 使用图是因为语言和硬件的可移植性(cpu 或 gpu)。这些图形计算模型是跨平台的,你可以用一种语言编写它们,但是使用计算模型,然后用不同的语言执行它们以提高速度。关于这一点最有趣的事实是在强大的机器上训练高度密集的模型,如云,然后使用训练好的模型,并将其部署在较小的硬件上,如手机,树莓派等。
有一个 tensorflow api 层次结构。它从用 c++编写自定义代码和制作自己的模块开始,这是非常低级的,涉及很多技术细节。tensorflow 的 python 级别为您提供了添加、子代理、创建张量等功能。tf.layers 的下一个级别,tf.losses 和 tf.metrics 帮助您进行更高的抽象,这是为了构建定制的神经网络模型而创建的。tf.estimator 的最高级别是 tf.estimator。用这种方式很容易理解层次结构。最后,google 云引擎使用 cmle 来运行 Tensorflow,而不管您使用的是什么抽象级别。
Tensorflow API Hierarchy
Tensorflow 的 python 级抽象让您可以构建我们之前讨论过的 DAG。要理解的最基本的事情是,最终在构建任何 DAG 之后,它只是一个模型。你可以把它想象成一个函数,函数运行于自身之中吗?他们没有我们需要打电话给他们。因此,在我们的例子中,我们首先需要创建一个会话来运行我们的模型,之后我们就像输入函数值一样输入模型值。所以本质上有两个步骤,创建图(DAG ),然后在会话中运行图。这被称为懒惰评估。
图表是你试图建立的计算模型。这些都是在 python api 的帮助下构建的。节点代表数学计算,而边代表节点之间传递的数据。最终,由于图表就像一个模型,它需要在会话的帮助下运行。所有需要的值都由 feed-dict 提供。张量是向量的推广,它们是数据的 n 维数组。简单地说,一个向量可以被认为是一系列的数字。当向量是二维的(即有行和列)时,它们被称为矩阵,三维或三维以上的向量通常被称为张量。这些是非常强大的数字仪器。在各种函数的帮助下,张量可以被制作、切片或整形。最后,我们在 tensorflow 中有变量,大多数变量是可训练的,神经网络的权重向量是可训练的变量,创建变量的最重要部分是考虑如何初始化它们。最后,如果你不想要变量,而只想有一个形式参数,并在运行时给它们输入值,那该怎么办?这是通过占位符解决的,占位符只是定义的变量,需要借助 tf.run()中的 feed-dict 参数进行初始化。
由于懒惰的评估,调试是棘手的。在调试的第一部分,您需要查找堆栈跟踪,然后是实际的错误消息。这通常非常简单,但是您可能会被错误消息的大小所困扰。然后用一些数据调用这个方法,检查哪里可能出错,然后改正。一些常见的问题是形状和数据类型问题。使用 tf.print、tfdbg 或 tensorboard 调试完整的程序。
估算器用于以简单的方式创建生产就绪模型。它们内嵌了许多样板代码,因此您不必再编写相同的代码。估算器是高级 tensorflow api 的一部分。估计器允许快速建模、检查点、内存不足的数据集、分布式训练等等。tf.estimator 具有所有这些功能。有许多预制的估算器,因为有一个通用的基础 api,你可以很快地把它换成其他预制的估算器,从而实现快速原型制作。
What Estimator API helps with
您可以按如下方式运行估算器,要素列类似于 api 的输入,您需要将数据集中的所有列插入到这些要素列中,例如,在房价预测的情况下,您的列可能是平方英尺和房屋类型,还可能有其他列,如带家具或不带家具等,有许多不同的数据类型来适应这些要素/属性…之后,通过使用预先制作的估计量(在这种情况下是线性回归量)来创建模型。train_input_fn 用于将训练数据集输入到模型中。predict_input_fn 用于将测试数据输入到模型中。
Using the estimator api
检查点就像游戏中的保存点,它们是成功运行后保存在某个位置的重量和其他参数。如果你认为一个模型没有达到标准,那么训练就从这个检查点开始,它们被内置在估计器中。estimator api 还具有从 numpy 数组或 pandas 数据帧馈送数据的功能。estimator api 还可以在 tf.dataset 的帮助下帮助您处理大型数据集。关于数据集,您需要了解的一件事是,ML 模型通常是通过批处理来训练的,每个批处理都有一个有限的大小,这表明无论整个数据集大小有多大,它最终都会被分解成多个批处理。这是由张量流促成的。随着并行而不是单机计算思想的进步,我们正在走向并行。数据并行性是当今训练 ML 模型的核心,Tensorflow 通过 train_and_evaluate 函数使这一点变得更容易,您需要使用该函数来提及训练和评估规范。为了评估你的训练,通常使用 tensorboard。
Cloud ML 引擎与您之前看到的整个 tensorflow 堆栈是正交的,它可以与堆栈中的任何抽象层进行交互并使用它。为什么是 CMLE?用于在多台机器上分配培训。向外扩展而不是向上扩展是关键。ML 算法计划收集比现有数据多 10 倍的数据,并将其整合到他们的系统中,这就是为什么他们比简单的数据系统好得多。另一件需要考虑的事情是,可以从分析原始数据中发现许多见解,并将这些见解作为特征进行整合会有很大帮助。
The Processing Cycle
你如何使用 CMLE?您需要使用 Tensorflow 创建您的计算图,然后打包您的 trainer 应用程序,最后配置并启动 CMLE 作业。在使用 CMLE 之前,您需要保留一个包结构,您可以使用 gcloud 命令来检查正确的包结构。最后,您可以通过获取作业的当前状态来监控作业,这可以通过 gcp web 控制台来完成。
CMLE 模块为本课程画上了一个句号,即 GCP 特殊化的 Tensorflow 简介。为了熟悉本文中谈到的 tensorflow 的各种组件,您可以查看可在此处找到的实验材料。完成本实验的最佳方式是通过查看 tensorflow 文档,同时尝试理解这些函数的细微差别。
多光谱激光雷达数据聚类的 K-Means 和 EM 方法比较
多年来,已经开发了几种类型的聚类算法。这些算法通常分为 4 个子类别(分割算法、分层算法、密度算法和基于模型的算法)。分割算法是最常用的算法,因为它们简单而直观。分区算法将数据分成几个分区,并根据某种标准对它们进行评估。相比之下,基于模型的算法为数据集中的每个分类假设一个统计模型,条件是假设的模型最适合该分类。作为对激光雷达数据进行分类的研究项目的一部分,我研究了用于树种分类的分区算法和基于模型的聚类算法之间的异同。我使用 K-means 和期望最大化估计作为上面两个类别的样本算法。这篇博文将会用一些很酷的视觉效果总结我的发现,但是如果你对更多的技术细节感兴趣,你可以在这里找到完整的调查。
k 均值
K-means 聚类可能是大多数人在开始机器学习课程时遇到的第一个无监督学习算法之一。它易于使用和直观。然而,如果我们沉迷于 K-means 背后的概率理论,很明显,该算法对数据的分布做出了非常一般的假设。K-means 算法试图在聚类间方差之和最小化的优化标准下检测数据集中的聚类。因此,K-均值聚类算法产生数据中已识别聚类状态的最小方差估计(MVE)。
该算法背后的直觉在于,平均而言,从聚类质心(𝜇𝑘)到聚类内的元素的距离在所有识别的聚类中应该是均匀的(这是我们稍后将看到的缺点)。尽管该方法在检测同质聚类时工作良好,但是由于其优化函数中固有的关于聚类的球形性质的简单假设(即,它假设所有聚类具有相等的协方差矩阵),该方法不可避免地存在缺点。
期望最大化估计
期望最大化(EM)是另一种流行的聚类算法,尽管有点复杂,它依赖于最大化可能性来找到数据集中底层子群体的统计参数。我不会深入 EM 背后的概率理论。如果你有兴趣,你可以在这里阅读更多。但是简单总结一下,EM 算法在两个步骤(E 步骤和 M 步骤)之间交替。在 E 步骤中,该算法试图使用统计参数的当前估计来找到原始似然性的下限函数。在 M 步骤中,该算法通过最大化下限函数(即确定统计参数的 MLE)来寻找这些统计参数的新估计。因为在每一步我们最大化下界函数,所以该算法总是产生比前一次迭代更高可能性的估计,并最终收敛到最大值。
那么是什么让 EM 比 K-means 更特别呢?与 K-means 不同,在 EM 中,聚类不限于球形。在 EM 中,我们可以约束算法以提供不同的协方差矩阵(球形、对角线和通用)。这些不同的协方差矩阵反过来允许我们控制聚类的形状,因此我们可以检测数据中具有不同特征的子群体。
Cluster Analysis: Original Data (left), k-means (middle), EM (right) (Illustration by Chire)
您可能已经注意到,在上图中,数据包含异常值,显示为黄色点。这两种算法都没有检测异常值的能力,因此我们必须对数据进行预处理,以减轻检测到的聚类中的异常值的影响。尤其是 EM,由于对协方差矩阵没有约束,因此它往往对异常值的存在很敏感。
泰坦激光雷达数据集
现在我们对 EM 的工作有了一些基本的了解,我们可以谈谈一些结果了。我从 Optech 的 Titan 传感器获得了一个多光谱激光雷达数据集,它有 3 个通道(532 纳米,1064 纳米和 1550 纳米)。该数据集是在多伦多斯卡伯勒上空收集的,飞行高度为 1500 米。为了对树种进行分类,我使用阈值技术对数据进行了预处理,去除了所有非树木覆盖类型。
LiDAR scan (Right Image) Titan multispectral LiDAR intensity data plotted in the spectral domain (Top Left: 1550 nm spectral band on the Vertical-Axis vs. 532 nm spectral band on the Horizontal-Axis, Top Right: 1550 nm spectral band on the Vertical-Axis vs. 1064 nm spectral band on the Horizontal-Axis, Bottom: 1064 nm spectral band on the Vertical-Axis vs. 532 nm spectral band on the Horizontal-Axis).
数据集还包含异常值,这些异常值在预处理阶段被删除。因为我已经实现了 K-means,所以我使用离群点去除聚类(ORC)方法从数据集中过滤离群点。
集群
使用上述 3 个光谱特征中的数据,我初步确定了数据集中的最佳聚类数。分区和基于模型的算法有一个主要缺点,即数据集内的聚类数需要由用户提供(基于密度的算法没有这个问题,但是需要指定其他阈值)。为了确定最佳的集群数量,我对一系列集群运行了 k-means 算法,并记录了每个分区的误差平方和(SSE) 。
Inter Cluster Variance for different number of clusters determined using k-means clustering. The red circle indicates the optimal number of clusters for the dataset.
然后,我使用图的渐近性质来挑选数据集中的最佳聚类数(这是基于我的主观解释,但是我发现 SSE 在 3 个聚类之后表现得相当渐近)。
我运行了 k-means 和 EM 算法的不同变体来获得以下聚类。对于 EM 算法,我主要关注协方差矩阵的三种配置(球形、对角线和完全填充(或通用))。
K-means (Left) vs EM with Spherical Covariance Matrix (Right)
EM with Generic Covariance Matrix (Left) vs EM with Diagonal Covariance Matrix (Right)
我发现 k-means 的结果最接近 EM 算法的球形变体,这正是我们所期望的。EM 的对角线变体允许每个聚类具有不同的大小,而通用协方差矩阵另外给予每个聚类在特征空间中不同的方向。
虽然通用协方差矩阵允许在检测数据中的不同亚群体时有更大的灵活性,但它肯定不是没有问题。在我疯狂编程期间,我在使用完全填充的协方差矩阵时遇到了一些收敛问题。我发现,由于协方差较大,解有时很容易发散。当我测试更高维度的数据集(即超光谱图像)时,情况尤其如此。具有全协方差模型的 EM 的收敛性问题并不新鲜;由于需要估计大量的参数,收敛到一个正确的解决方案也可能非常缓慢。
总之,EM 算法为流行的 k-means 提供了一个强大的替代方法,对聚类的特征有更好的控制。然而,EM 算法,像 k-means 一样,也产生次优解。换句话说,不能保证算法将产生最适合底层子群体的模型(即聚类)。
Python 中完整的机器学习演练:第二部分
模型选择、超参数调整和评估
组装解决问题所需的所有机器学习部件可能是一项艰巨的任务。在这一系列文章中,我们将使用真实世界的数据集来实现机器学习工作流,以了解各种技术是如何结合在一起的。
在第一篇文章中,我们清理并结构化了数据,进行了探索性的数据分析,开发了一组在我们的模型中使用的特性,并建立了一个我们可以用来衡量性能的基线。在本文中,我们将了解如何在 Python 中实现和比较几个机器学习模型,执行超参数调整以优化最佳模型,并在测试集上评估最终模型。
这个项目的完整代码是 GitHub 上的,与本文对应的第二本笔记本在这里。您可以随意使用、共享和修改代码!
模型评估和选择
提醒一下,我们正在进行一项监督回归任务:使用纽约市建筑能源数据,我们希望开发一个模型,可以预测建筑的能源之星得分。我们的重点是预测的准确性和模型的可解释性。
有吨的机器学习模型可供选择,决定从哪里开始可能是令人生畏的。虽然有一些图表试图告诉你使用哪种算法,但我更喜欢尝试几种,看看哪种效果最好!机器学习仍然是一个主要由经验(实验)而不是理论结果驱动的领域,并且几乎不可能提前知道哪个模型会做得最好。
一般来说,从简单、可解释的模型(如线性回归)开始是一个好主意,如果性能不够好,就转向更复杂但通常更精确的方法。下图显示了准确性与可解释性权衡的(极不科学的)版本:
Interpretability vs. Accuracy (Source)
我们将评估涵盖复杂性范围的五种不同模型:
- 线性回归
- K-最近邻回归
- 随机森林回归
- 梯度推进回归
- 支持向量机回归
在这篇文章中,我们将着重于实现这些方法,而不是它们背后的理论。对于任何对学习背景感兴趣的人,我强烈推荐统计学习入门(网上免费提供)或使用 Scikit-Learn 和 TensorFlow 进行机器学习。这两本教科书都很好地解释了理论,并分别展示了如何有效地使用 R 和 Python 中的方法。
输入缺失值
虽然我们在清理数据时删除了丢失值超过 50%的列,但仍然有相当多的观察值丢失。机器学习模型无法处理任何缺失的值,所以我们必须填充它们,这是一个被称为插补的过程。
首先,我们将读入所有数据,并提醒自己它看起来像什么:
import pandas as pd
import numpy as np# Read in data into dataframes
train_features = pd.read_csv('data/training_features.csv')
test_features = pd.read_csv('data/testing_features.csv')
train_labels = pd.read_csv('data/training_labels.csv')
test_labels = pd.read_csv('data/testing_labels.csv')**Training Feature Size: (6622, 64)
Testing Feature Size: (2839, 64)
Training Labels Size: (6622, 1)
Testing Labels Size: (2839, 1)**
每个值NaN
代表一个缺失的观察值。虽然有多种方法来填充缺失数据,但我们将使用一种相对简单的方法,即中位数插补。这会用列的中值替换列中所有缺失的值。
在下面的代码中,我们创建了一个策略设置为 median 的 Scikit-Learn Imputer
对象。然后我们在训练数据上训练这个对象(使用imputer.fit
,并用它来填充训练和测试数据中缺失的值(使用imputer.transform
)。这意味着用来自训练数据的相应中值来填充测试数据中的缺失值。
(我们必须以这种方式进行插补,而不是对所有数据进行训练,以避免测试数据泄漏的问题,即来自测试数据集的信息溢出到训练数据中。)
# Create an imputer object with a median filling strategy
imputer = Imputer(strategy='median')# Train on the training features
imputer.fit(train_features)# Transform both training data and testing data
X = imputer.transform(train_features)
X_test = imputer.transform(test_features)**Missing values in training features: 0
Missing values in testing features: 0**
所有的特征现在都有真实的有限值,没有遗漏的例子。
特征缩放
缩放是指改变特征范围的一般过程。这是必要的,因为特征以不同的单位测量,因此涵盖不同的范围。诸如支持向量机和 K-最近邻之类的方法考虑了观测值之间的距离度量,这些方法受到特征范围的显著影响,并且缩放允许它们学习。虽然像线性回归和随机森林这样的方法实际上并不需要特性缩放,但是当我们比较多个算法时,采取这一步骤仍然是最佳实践。
我们将通过将每个特征放在 0 到 1 的范围内来缩放特征。这是通过取特性的每个值,减去特性的最小值,然后除以最大值减去最小值(范围)来完成的。这种特定版本的缩放通常被称为标准化,另一个主要版本被称为标准化。
虽然这个过程很容易手工实现,但是我们可以使用 Scikit-Learn 中的MinMaxScaler
对象来实现。这种方法的代码与插补的代码相同,只是用了一个定标器而不是插补器!同样,我们确保仅使用训练数据进行训练,然后转换所有数据。
# Create the scaler object with a range of 0-1
scaler = MinMaxScaler(feature_range=(0, 1))# Fit on the training data
scaler.fit(X)# Transform both the training and testing data
X = scaler.transform(X)
X_test = scaler.transform(X_test)
现在,每个要素的最小值为 0,最大值为 1。缺失值插补和特征缩放是几乎任何机器学习管道中都需要的两个步骤,因此了解它们是如何工作的是一个好主意!
在 Scikit-Learn 中实现机器学习模型
在我们清理和格式化数据的所有工作之后,实际上用模型创建、训练和预测是相对简单的。我们将使用 Python 中的 Scikit-Learn 库,它有很好的文档和一致的模型构建语法。一旦您知道如何在 Scikit-Learn 中制作一个模型,您就可以快速实现各种算法。
我们可以用梯度推进回归器来说明模型创建、训练(使用.fit
)和测试(使用.predict
)的一个例子:
**Gradient Boosted Performance on the test set: MAE = 10.0132**
模型创建、训练和测试都是一行!为了构建其他模型,我们使用相同的语法,只是改变了算法的名称。结果如下所示:
为了客观地看待这些数字,使用目标的中值计算的原始基线是 24.5。显然,机器学习适用于我们的问题,因为在基线上有显著的改进!
梯度提升回归量 (MAE = 10.013)略胜随机森林(10.014 MAE)。这些结果并不完全公平,因为我们主要使用超参数的默认值。特别是在支持向量机等模型中,性能高度依赖于这些设置。尽管如此,我们将从这些结果中选择梯度推进回归变量进行模型优化。
用于模型优化的超参数调整
在机器学习中,在我们选择了一个模型之后,我们可以通过调整模型超参数来优化它。
首先,什么是超参数,它们与参数有何不同?
- 模型超参数最好被认为是数据科学家在训练前设置的机器学习算法的设置。例如随机森林中的树木数量或 K-最近邻算法中使用的邻居数量。
- 模型参数是模型在训练期间学习的内容,例如线性回归中的权重。
控制超参数通过改变模型中欠拟合和过拟合之间的平衡来影响模型性能。欠拟合是指我们的模型不够复杂(它没有足够的自由度)来学习从特征到目标的映射。一个欠拟合模型有高偏差,我们可以通过使我们的模型更复杂来纠正它。
过度拟合是指我们的模型基本上记住了训练数据。过度拟合模型具有高方差,我们可以通过正则化来限制模型的复杂度,从而对其进行校正。欠拟合和过拟合模型都不能很好地概括测试数据。
选择正确的超参数的问题是,对于每个机器学习问题,最佳集合都是不同的!因此,找到最佳设置的唯一方法是在每个新数据集上尝试多种设置。幸运的是,Scikit-Learn 有许多方法可以让我们有效地评估超参数。此外,像 TPOT 上位实验室这样的项目正在尝试使用遗传编程这样的方法来优化超参数搜索。在这个项目中,我们将坚持用 Scikit-Learn 来做这件事,但是请继续关注 auto-ML 场景的更多工作!
交叉验证随机搜索
我们将实施的特定超参数调整方法称为交叉验证随机搜索:
- 随机搜索 指的是我们将用来选择超参数的技术。我们定义一个网格,然后随机抽样不同的组合,而不是网格搜索,我们穷尽地尝试每一个组合。(令人惊讶的是,随机搜索的表现几乎和网格搜索一样好,运行时间大幅减少。)
- 交叉验证 是我们用来评估超参数选定组合的技术。我们使用 K-Fold 交叉验证,而不是将训练集分成单独的训练集和验证集,这减少了我们可以使用的训练数据量。这包括将训练数据分成 K 个折叠,然后经历一个迭代过程,其中我们首先在 K-1 个折叠上训练,然后在第 K 个折叠上评估性能。我们重复这个过程 K 次,在 K 重交叉验证结束时,我们取 K 次迭代中每一次的平均误差作为最终的性能测量。
K = 5 的 K 倍交叉验证的思想如下所示:
K-Fold Cross Validation with K = 5 (Source)
使用交叉验证执行随机搜索的整个过程是:
- 建立一个超参数网格来评估
- 随机抽样超参数组合
- 使用所选组合创建模型
- 使用 K-fold 交叉验证评估模型
- 确定哪些超参数效果最好
当然,我们实际上并不手动完成这项工作,而是让 Scikit-Learn 的RandomizedSearchCV
来处理所有的工作!
轻微分流:梯度升压法
由于我们将使用梯度推进回归模型,我至少应该给一点背景知识!该模型是一种集成方法,这意味着它是由许多弱学习者构建而成的,在这种情况下是个体决策树。一种 bagging 算法,如随机森林并行训练弱学习者,并让他们投票做出预测,而一种增强方法如梯度增强,依次训练学习者,每个学习者“专注于”前一个学习者所犯的错误。
助推方法近年来变得流行,并经常赢得机器学习比赛。梯度提升方法是一种特殊的实现方式,它使用梯度下降,通过在先前学习者的残差上顺序训练学习者来最小化成本函数。梯度增强的 Scikit-Learn 实现通常被认为不如其他库(如 XGBoost )有效,但它对于我们的小数据集来说足够好,并且相当准确。
返回超参数调谐
在梯度增强回归器中有许多超参数需要调整,您可以查看 Scikit-Learn 文档了解详情。我们将优化以下超参数:
loss
:最小化损失函数n_estimators
:要使用的弱学习器(决策树)的数量max_depth
:每个决策树的最大深度min_samples_leaf
:决策树的一个叶节点所需的最小样本数min_samples_split
:拆分决策树节点所需的最小样本数max_features
:用于分割节点的最大特征数
我不确定是否有人真正理解所有这些是如何相互作用的,找到最佳组合的唯一方法是尝试它们!
在下面的代码中,我们构建了一个超参数网格,创建了一个RandomizedSearchCV
对象,并对 25 个不同的超参数组合使用 4 重交叉验证来执行超参数搜索:
执行搜索后,我们可以检查RandomizedSearchCV
对象以找到最佳模型:
# Find the best combination of settings
random_cv.best_estimator_**GradientBoostingRegressor(loss='lad', max_depth=5,
max_features=None,
min_samples_leaf=6,
min_samples_split=6,
n_estimators=500)**
然后,我们可以使用这些结果,通过为网格选择接近这些最佳值的参数来执行网格搜索。然而,进一步的调整不太可能显著改进我们的模型。一般来说,适当的特征工程对模型性能的影响要比最广泛的超参数调整大得多。这是应用于机器学习的收益递减定律:特征工程让你走了大部分路,而超参数调整通常只提供很小的好处。
我们可以尝试的一个实验是改变估计器(决策树)的数量,同时保持其余的超参数不变。这直接让我们观察这个特定设置的效果。参见笔记本了解的实现,但以下是结果:
随着模型使用的树的数量增加,训练和测试误差都减小。然而,训练误差比测试误差下降得更快,我们可以看到我们的模型过度拟合:它在训练数据上表现非常好,但在测试集上不能达到同样的性能。
我们总是预计测试集的性能至少会有所下降(毕竟,模型可以看到训练集的真实答案),但是显著的差距表明过度拟合。我们可以通过获取更多的训练数据来解决过度拟合问题,或者通过 hyerparameters 来降低我们模型的复杂性。在这种情况下,我们将把超参数留在原处,但我鼓励任何人尝试减少过度拟合。
对于最终的模型,我们将使用 800 个估计量,因为这在交叉验证中产生了最低的误差。现在,是时候测试这个模型了!
对测试集进行评估
作为负责任的机器学习工程师,我们确保不让我们的模型在任何训练点看到测试集。因此,我们可以使用测试集性能作为我们的模型在现实世界中部署时的性能指标。
对测试集进行预测并计算性能相对简单。这里,我们将默认梯度推进回归器的性能与调整后的模型进行比较:
# Make predictions on the test set using default and final model
default_pred = default_model.predict(X_test)
final_pred = final_model.predict(X_test)**Default model performance on the test set: MAE = 10.0118.
Final model performance on the test set: MAE = 9.0446.**
超参数调整将模型的精度提高了约 10%。根据不同的用例,10%可能是一个巨大的改进,但这需要大量的时间投入!
我们还可以使用 Jupyter 笔记本中的%timeit
magic 命令来计时训练这两个模型需要多长时间。首先是默认模型:
%%timeit -n 1 -r 5
default_model.fit(X, y)**1.09 s ± 153 ms per loop (mean ± std. dev. of 5 runs, 1 loop each)**
1 秒训练似乎很合理。最终调优的模型没有这么快:
%%timeit -n 1 -r 5
final_model.fit(X, y)**12.1 s ± 1.33 s per loop (mean ± std. dev. of 5 runs, 1 loop each)**
这展示了机器学习的一个基本方面:它总是一个权衡取舍的游戏。我们必须不断地平衡准确性和可解释性,偏差和方差,准确性和运行时间,等等。正确的混合最终取决于问题。在我们的例子中,相对而言,运行时间增加 12 倍是很大的,但从绝对意义上来说,并不显著。
一旦我们有了最终的预测,我们就可以研究它们,看看它们是否表现出任何明显的偏差。左侧是预测值和实际值的密度图,右侧是残差直方图:
Density Plot of Predicted and Actual Values (left) and Histogram of Residuals (right)
模型预测似乎遵循实际值的分布,尽管密度峰值更接近于训练集的中值(66),而不是真正的密度峰值(接近 100)。残差接近正态分布,尽管我们看到一些大的负值,其中模型预测远低于真实值。在下一篇文章中,我们将更深入地解读这个模型的结果。
结论
在本文中,我们介绍了机器学习工作流程中的几个步骤:
- 缺失值的插补和特征的缩放
- 几种机器学习模型的评估和比较
- 使用随机网格搜索和交叉验证的超参数调谐
- 评估测试集上的最佳模型
这项工作的结果表明,机器学习适用于使用可用数据预测建筑物能源之星得分的任务。使用梯度增强回归器,我们能够预测测试集上的分数在真实值的 9.1 分之内。此外,我们看到超参数调优可以提高模型的性能,但在时间投入方面要付出很大的代价。这是我们在开发机器学习解决方案时必须考虑的众多权衡之一。
在第三篇文章中(此处),我们将深入观察我们创造的黑箱,并试图理解我们的模型是如何做出预测的。我们还将确定影响能源之星评分的最大因素。虽然我们知道我们的模型是准确的,但我们想知道为什么会做出这样的预测,这告诉了我们什么问题!
一如既往,我欢迎反馈和建设性的批评,可以通过 Twitter @koehrsen_will 联系。
Python 中完整的机器学习项目演练:第一部分
Photo by Ross Sneddon on Unsplash
把机器学习的碎片放在一起
通读一本数据科学书籍或参加一门课程,感觉就像你掌握了各个部分,但不太知道如何将它们组合在一起。采取下一步措施并解决一个完整的机器学习问题可能会令人生畏,但保留并完成第一个项目将让你有信心解决任何数据科学问题。这一系列文章将通过一个真实世界的数据集来介绍一个完整的机器学习解决方案,让您了解所有这些部分是如何组合在一起的。
我们将逐步遵循一般的机器学习工作流程:
- 数据清理和格式化
- 探索性数据分析
- 特征工程和选择
- 在性能指标上比较几种机器学习模型
- 对最佳模型执行超参数调整
- 评估测试集上的最佳模型
- 解释模型结果
- 得出结论并记录工作
在这个过程中,我们将看到每个步骤如何流入下一个步骤,以及如何用 Python 具体实现每个部分。完整的项目可以在 GitHub 上找到,这里有的第一个笔记本。第一篇文章将涵盖第 1-3 步,其余部分将在后续文章中讨论。
(注意,这个问题最初是在一家初创公司的工作筛选中作为“任务”交给我的。完成工作后,我得到了这份工作,但后来公司的首席技术官辞职了,他们无法再招聘新员工。我猜这就是创业现场的情况吧!)
问题定义
在我们开始编码之前,第一步是理解我们试图解决的问题和可用的数据。在这个项目中,我们将使用来自纽约市的公开建筑能源数据。
目标是使用能源数据建立一个模型,该模型可以预测建筑物的能源之星得分,并解释结果以找到影响得分的因素。
这些数据包括能源之星得分,这使得这成为一个受监督的回归机器学习任务:
- 监督:我们可以访问特征和目标,我们的目标是训练一个模型,它可以学习两者之间的映射
- **回归:**能源之星得分是一个连续变量
我们希望开发一个既准确——它可以预测接近真实值的能源之星分数——又可解释 —我们可以理解模型预测的模型。一旦我们知道了目标,我们就可以在挖掘数据和构建模型时用它来指导我们的决策。
数据清理
与大多数数据科学课程让你相信的相反,并不是每个数据集都是一组完美的观察值,没有缺失值或异常(看看你的 mtcars 和 iris 数据集)。现实世界的数据是杂乱的,这意味着我们需要在开始分析之前将数据清理并转换成可接受的格式。数据清理是大多数实际数据科学问题中不光彩但必要的一部分。
首先,我们可以像熊猫DataFrame
一样加载数据,然后看一看:
import pandas as pd
import numpy as np# Read in data into a dataframe
data = pd.read_csv('data/Energy_and_Water_Data_Disclosure_for_Local_Law_84_2017__Data_for_Calendar_Year_2016_.csv')# Display top of dataframe
data.head()
What Actual Data Looks Like!
这是包含 60 列的完整数据的子集。我们已经可以看到一些问题:首先,我们知道我们想要预测ENERGY STAR Score
,但是我们不知道任何列是什么意思。虽然这不一定是一个问题——我们经常可以在没有任何变量知识的情况下建立准确的模型——但我们希望关注可解释性,并且至少理解一些列可能是重要的。
当我最初从初创公司获得任务时,我不想问所有列名的含义,所以我查看了文件的名称,
并决定搜索“土法 84”。这让我看到了这个页面,它解释说这是纽约市的一项法律,要求所有一定规模的建筑报告它们的能源使用情况。更多的搜索把我带到了所有列的定义。也许查看文件名是一个显而易见的开始,但对我来说,这是一个提醒,要慢慢来,这样你就不会错过任何重要的东西!
我们不需要研究所有的栏目,但我们至少应该了解能源之星评分,它被描述为:
基于报告年份自我报告的能源使用情况的 1 到 100%的排名。能源之星评分是用于比较建筑物能源效率的相对指标。
这解决了第一个问题,但是第二个问题是丢失的值被编码为“不可用”。这是 Python 中的一个字符串,这意味着即使包含数字的列也将被存储为object
数据类型,因为 Pandas 将包含任何字符串的列转换为包含所有字符串的列。我们可以使用dataframe.info()
方法查看列的数据类型:
# See the column data types and non-missing values
data.info()
果然,一些明显包含数字的列(如 ft)被存储为对象。我们不能对字符串进行数值分析,所以这些必须被转换成数字(特别是float
)数据类型!
下面是一小段 Python 代码,它将所有“不可用”的条目替换为非数字(np.nan
),这可以解释为数字,然后将相关列转换为float
数据类型:
一旦正确的列是数字,我们就可以开始研究数据了。
缺失数据和异常值
除了不正确的数据类型之外,处理真实世界数据时的另一个常见问题是缺少值。这些可能由于许多原因而出现,并且必须在我们训练机器学习模型之前填充或移除。首先,让我们大致了解一下每一列中有多少缺失值(代码见笔记本)。
(为了创建这个表,我使用了这个堆栈溢出论坛中的一个函数)。
虽然我们总是希望小心地删除信息,但是如果一个列有很高百分比的缺失值,那么它可能对我们的模型没有用。移除列的阈值应该取决于问题(这里有一个讨论),对于这个项目,我们将移除任何缺失值超过 50%的列。
在这一点上,我们可能还想删除离群值。这些可能是由于数据输入中的打字错误、单位错误,或者它们可能是合法但极端的值。对于这个项目,我们将根据极端异常值的定义移除异常值:
- 低于第一个四分位数 3÷四分位数间距
- 高于第三个四分位数+3÷四分位数间距
(有关删除列和异常的代码,请参见笔记本)。在数据清理和异常移除过程结束时,我们留下了超过 11,000 个建筑物和 49 个特征。
探索性数据分析
既然繁琐但必要的数据清理步骤已经完成,我们可以继续探索我们的数据了!探索性数据分析 (EDA)是一个开放式的过程,我们通过计算统计数据并制作图表来发现数据中的趋势、异常、模式或关系。
简而言之,EDA 的目标是学习我们的数据能告诉我们什么。它通常从高层次的概述开始,然后随着我们发现数据中感兴趣的部分,缩小到特定的领域。这些发现本身可能是有趣的,或者它们可以用于通知我们的建模选择,例如通过帮助我们决定使用哪些功能。
单变量图
我们的目标是预测能源之星得分(在我们的数据中被重命名为score
),因此一个合理的起点是检查这个变量的分布。直方图是可视化单个变量分布的一种简单而有效的方法,使用matplotlib
很容易制作。
import matplotlib.pyplot as plt# Histogram of the Energy Star Score
plt.style.use('fivethirtyeight')
plt.hist(data['score'].dropna(), bins = 100, edgecolor = 'k');
plt.xlabel('Score'); plt.ylabel('Number of Buildings');
plt.title('Energy Star Score Distribution');
这个看起来挺可疑的!能源之星得分是一个百分位数排名,这意味着我们希望看到一个统一的分布,每个分数分配给相同数量的建筑。然而,大量的建筑要么得分最高(100 分),要么得分最低(1 分)(能源之星得分越高越好)。
如果我们回到分数的定义,我们会看到它是基于“自我报告的能源使用情况”,这可能解释了非常高的分数。要求建筑业主报告他们自己的能源使用情况就像要求学生报告他们自己的考试成绩一样!因此,这可能不是衡量建筑能效的最客观的标准。
如果我们有无限的时间,我们可能想要调查为什么这么多的建筑有非常高和非常低的分数,我们可以通过选择这些建筑并查看它们的共同点。然而,我们的目标只是预测分数,而不是设计一个更好的建筑评分方法!我们可以在报告中注明分数的分布是可疑的,但我们主要关注的是预测分数。
寻找关系
EDA 的主要部分是搜索特征和目标之间的关系。与目标相关的变量对模型是有用的,因为它们可用于预测目标。检查分类变量(仅取有限的一组值)对目标的影响的一种方法是通过使用seaborn
库的密度图。
一个密度图可以被认为是一个平滑的直方图,因为它显示了单个变量的分布。我们可以按类别给密度图着色,看看分类变量如何改变分布。以下代码根据建筑类型(仅限于超过 100 个数据点的建筑类型)绘制了能源之星得分的密度图:
我们可以看到,建筑类型对能源之星得分有显著影响。办公楼往往得分较高,而酒店得分较低。这告诉我们,我们应该在建模中包括建筑类型,因为它确实对目标有影响。作为分类变量,我们必须对建筑类型进行一次性编码。
类似的图表可用于显示各区的能源之星得分:
行政区对得分的影响似乎没有建筑类型大。尽管如此,我们可能希望将它包含在我们的模型中,因为各行政区之间存在细微的差异。
为了量化变量之间的关系,我们可以使用皮尔逊相关系数。这是对两个变量之间线性关系的强度和方向的度量。得分+1 是完美的线性正关系,得分-1 是完美的负线性关系。相关系数的几个值如下所示:
Values of the Pearson Correlation Coefficient (Source)
虽然相关系数不能捕捉非线性关系,但它是开始弄清楚变量如何相关的好方法。在 Pandas 中,我们可以很容易地计算数据帧中任何列之间的相关性:
# Find all correlations with the score and sort
correlations_data = data.corr()['score'].sort_values()
与目标的最负(左)和正(右)相关性:
在特征和目标之间有几个很强的负相关,最负的是不同类别的 EUI(这些度量在它们的计算方式上略有不同)。EUI——能源使用强度 —是一栋建筑使用的能源量除以建筑的平方英尺。它旨在衡量建筑的效率,分数越低越好。直观地说,这些相关性是有意义的:随着 EUI 的增加,能源之星得分往往会降低。
双变量图
为了可视化两个连续变量之间的关系,我们使用散点图。我们可以在点的颜色中包含附加信息,例如分类变量。例如,下图显示了能源之星得分与按建筑类型着色的站点 EUI 的关系:
这个图让我们想象相关系数为-0.7 是什么样子。随着现场 EUI 降低,能源之星得分增加,这种关系在各种建筑类型中保持稳定。
我们将制作的最后一个探索图被称为 Pairs 图。这是一个伟大的探索工具,因为它让我们看到多对变量之间的关系以及单个变量的分布。这里我们使用 seaborn 可视化库和PairGrid
函数创建一个 Pairs 图,上面的三角形是散点图,对角线是直方图,下面的三角形是 2D 核密度图和相关系数。
为了看到变量之间的相互作用,我们寻找行和列的交叉点。例如,要查看Weather Norm EUI
与score
的相关性,我们查看Weather Norm EUI
行和score
列,看到相关系数为-0.67。除了看起来很酷之外,这样的图可以帮助我们决定在建模中包含哪些变量。
特征工程和选择
特征工程和选择通常为机器学习问题提供最大的时间回报。首先,我们来定义一下这两个任务是什么:
- 特征工程:获取原始数据并提取或创建新特征的过程。这可能意味着对变量进行转换,例如自然对数和平方根,或者对分类变量进行一次性编码,以便它们可以在模型中使用。一般来说,我认为特征工程就是从原始数据中创建额外的特征。
- 特征选择:在数据中选择最相关特征的过程。在特征选择中,我们移除特征以帮助模型更好地概括新数据并创建更易解释的模型。一般来说,我认为特征选择就是减去特征,所以我们只剩下那些最重要的。
机器学习模型只能从我们提供的数据中学习,因此确保数据包含我们任务的所有相关信息至关重要。如果我们不给一个模型输入正确的数据,那么我们就是在让它失败,我们不应该期望它学习!
对于本项目,我们将采取以下特征工程步骤:
- 一键编码分类变量(区和物业使用类型)
- 加入数值变量的自然对数变换
一键编码是在模型中包含分类变量所必需的。机器学习算法无法理解“办公室”的建筑类型,所以如果建筑是办公室,我们必须将其记录为 1,否则记录为 0。
添加变换后的要素可以帮助我们的模型了解数据中的非线性关系。采用平方根、自然对数或各种幂的特征是数据科学中的常见做法,可以基于领域知识或实践中最有效的方法。这里我们将包括所有数字特征的自然对数。
以下代码选择数字特征,对这些特征进行对数变换,选择两个分类特征,对这些特征进行一次性编码,并将这两个集合连接在一起。这看起来工作量很大,但在熊猫中却相对简单!
在这个过程之后,我们有超过 11,000 个观察值(建筑物)和 110 个列(特征)。并非所有这些特征都可能对预测能源之星得分有用,因此现在我们将转向特征选择以移除一些变量。
特征选择
我们数据中的 110 个特征中有许多是多余的,因为它们彼此高度相关。例如,这是一个站点 EUI 与天气标准化站点 EUI 的关系图,其相关系数为 0.997。
彼此高度相关的特征被称为共线,移除这些特征对中的一个变量通常可以帮助机器学习模型进行概括,并更具可解释性。(我应该指出,我们讨论的是功能与其他功能的相关性,而不是与目标的相关性,这有助于我们的模型!)
有多种方法可以计算要素之间的共线性,其中最常用的一种方法是方差膨胀因子。在这个项目中,我们将使用相关系数来识别和移除共线特征。如果一对特征之间的相关系数大于 0.6,我们将丢弃其中一个特征。对于实现,看一下笔记本(和这个栈溢出答案)
虽然这个值看起来有些武断,但我尝试了几种不同的阈值,这个选择产生了最佳模型。机器学习是一个经验领域,通常是关于实验和发现什么表现最好!在特征选择之后,我们剩下总共 64 个特征和 1 个目标。
# Remove any columns with all na values
features = features.dropna(axis=1, how = 'all')
print(features.shape)**(11319, 65)**
建立基线
我们现在已经完成了数据清理、探索性数据分析和功能工程。开始建模前的最后一步是建立一个简单的基线。这基本上是一个猜测,我们可以根据它来比较我们的结果。如果机器学习模型没有击败这个猜测,那么我们可能不得不得出结论,机器学习对于这项任务来说是不可接受的,或者我们可能需要尝试一种不同的方法。
对于回归问题,合理的原始基线是猜测测试集中所有示例的训练集目标的中值。这为任何车型设定了相对较低的超越门槛。
我们将使用的指标是 平均绝对误差 (mae) ,它测量预测的平均绝对误差。回归有许多度量标准,但我喜欢吴恩达的建议选择一个单一的度量标准,然后在评估模型时坚持使用它。平均绝对误差易于计算和解释。
在计算基线之前,我们需要将数据分为训练集和测试集:
- 特征的训练集是我们在训练期间连同答案一起提供给我们的模型的。目标是让模型学习特征和目标之间的映射。
- 特征的测试集用于评估训练好的模型。模型不允许看到测试集的答案,并且必须仅使用特征进行预测。我们知道测试集的答案,因此我们可以将测试预测与答案进行比较。
我们将使用 70%的数据进行培训,30%的数据进行测试:
# Split into 70% training and 30% testing set
X, X_test, y, y_test = train_test_split(features, targets,
test_size = 0.3,
random_state = 42)
现在我们可以计算原始基线性能:
**The baseline guess is a score of 66.00
Baseline Performance on the test set: MAE = 24.5164**
在测试集上,天真的估计大约有 25 点的误差。分数范围从 1 到 100,所以这代表了 25%的误差,这是一个很低的超越标准!
结论
在本文中,我们走过了机器学习问题的前三个步骤。定义问题后,我们:
- 清理并格式化原始数据
- 执行探索性数据分析以了解数据集
- 开发了一套将用于我们的模型的功能
最后,我们还完成了建立基线的关键步骤,我们可以根据基线来判断我们的机器学习算法。
第二篇文章(此处可用)将展示如何使用 Scikit-Learn 评估机器学习模型,选择最佳模型,并执行超参数调整以优化模型。第三个岗位,处理模型解释和报告结果,在这里。
一如既往,我欢迎反馈和建设性的批评,可以通过 Twitter @koehrsen_will 联系。
Python 中完整的机器学习演练:第三部分
解释机器学习模型并呈现结果
机器学习模型经常被批评为黑箱:我们把数据放在一边,得到答案——通常是非常准确的答案——另一边没有解释。在展示完整的机器学习解决方案的本系列的第三部分中,我们将深入研究我们开发的模型,以尝试并理解它如何进行预测,以及它可以教给我们关于该问题的什么。我们将通过讨论机器学习项目中最重要的部分来结束:记录我们的工作并展示结果。
本系列的第一部分涵盖了数据清理、探索性数据分析、特性工程和特性选择。第二部分涵盖了输入缺失值、实现和比较机器学习模型、使用交叉验证的随机搜索进行超参数调整,以及评估模型。
这个项目的所有代码都在 GitHub 上。第三本 Jupyter 笔记本,对应本帖,在此。我鼓励任何人分享、使用和构建这些代码!
提醒一下,我们正在解决一个监督回归机器学习问题。使用纽约市建筑能源数据,我们开发了一个可以预测建筑能源之星得分的模型。我们构建的最终模型是一个梯度推进回归器,它能够将测试数据的能源之星得分预测到 9.1 分以内(1-100 分)。
模型解释
梯度推进回归变量位于模型可解释性的尺度的中间:整个模型很复杂,但它是由数百个决策树组成的,它们本身是很容易理解的。我们将从三个方面来理解我们的模型是如何进行预测的:
- 特征重要性
- 可视化单个决策树
- LIME:局部可解释的模型不可知解释
前两种方法专门针对树的集合,而第三种方法——正如你可能从名称中猜到的那样——可以应用于任何机器学习模型。LIME 是一个相对较新的包,代表了正在进行的解释机器学习预测的努力中令人兴奋的一步。
特征重要性
特征重要性试图显示每个特征与预测目标任务的相关性。特征重要性的技术细节很复杂(它们测量平均杂质减少量,或因包含特征而减少的误差),但我们可以使用相对值来比较哪些特征最相关。在 Scikit-Learn 中,我们可以从任何基于树的学习者集合中提取特征重要性。
使用model
作为我们的训练模型,我们可以使用model.feature_importances_
找到特征重要性。然后,我们可以将它们放入熊猫数据框架中,并显示或绘制前十个最重要的:
Site EUI
( )能源使用强度)和Weather Normalized Site Electricity Intensity
是最重要的特征,占总重要性的 66%以上。在前两个特征之后,重要性显著下降,这表明我们可能不需要保留数据中的所有 64 个特征来实现高性能。(在Jupyter 笔记本中,我看了一下仅使用前 10 个功能的情况,发现该模型并不十分准确。)
基于这些结果,我们终于可以回答我们最初的一个问题:建筑物能源之星得分的最重要指标是站点 EUI 和天气标准化站点电力强度。虽然我们确实希望小心不要过度解读特征重要性,但它们是开始理解模型如何做出预测的有用方式。
可视化单个决策树
虽然整个梯度推进回归可能难以理解,但任何一个单独的决策树都是非常直观的。我们可以使用 Scikit-Learn 函数 [export_graphviz](http://scikit-learn.org/stable/modules/generated/sklearn.tree.export_graphviz.html)
来想象森林中的任何一棵树。我们首先从系综中提取一棵树,然后将其保存为点文件:
使用 Graphviz 可视化软件我们可以从命令行将点文件转换成 png 文件:
dot -Tpng images/tree.dot -o images/tree.png
结果是一个完整的决策树:
Full Decision Tree in the Model
这有点让人不知所措!尽管这棵树的深度只有 6(层数),但还是很难理解。我们可以修改对export_graphviz
的调用,并将我们的树限制在更合理的深度 2:
Decision Tree Limited to a Depth of 2
树中的每个节点(框)有四条信息:
- 这个问题问的是数据点的一个特性的值:这决定了我们是向右还是向左离开节点
mse
是节点误差的度量samples
是节点中实例(数据点)的数量value
是节点中所有样本的目标估计值
Individual Node in Decision Tree
(叶节点只有 2 个。–4.因为它们代表最终估计值,并且没有任何子代)。
决策树通过从称为根的顶部节点开始,沿着树向下工作来预测数据点。在每一个节点,数据点会被问一个是或否的问题。例如,上面节点的问题是:建筑物的场地 EUI 是否小于或等于 68.95?如果答案是肯定的,那么该建筑被放置在右边的子节点中,如果答案是否定的,那么该建筑被放置在左边的子节点中。
在树的每一层重复该过程,直到数据点被放置在树的底部的叶节点中(叶节点从小树图像中被裁剪)。对叶节点中所有数据点的预测是value
。如果在一个叶节点中有多个数据点(samples
),它们都得到相同的预测。随着树的深度增加,训练集上的误差将减少,因为有更多的叶节点,并且示例可以被更精细地划分。然而,太深的树将过度适应训练数据,并且将不能推广到新的测试数据。
在第二篇文章的中,我们调整了许多模型超参数,它们控制着每棵树的各个方面,比如树的最大深度和一个叶节点所需的最小样本数。这两者对欠拟合和过拟合的平衡都有重大影响,可视化单个决策树允许我们看到这些设置如何工作。
虽然我们不能检查模型中的每一棵树,但是查看一棵树可以让我们了解每个学习者如何做出预测。这种基于流程图的方法看起来很像人类做决策的方式,一次回答一个关于单个值的问题。基于决策树的集成将许多单个决策树的预测结合起来,以创建一个更准确、方差更小的模型。树的集合往往非常准确,并且解释起来也很直观。
局部可解释的模型不可知解释(LIME)
我们将探索的试图理解我们的模型如何“思考”的最后一个工具是模型解释领域的一个新入口。 LIME 旨在通过使用线性回归等简单模型在数据点附近局部创建模型的近似来解释来自任何机器学习模型的单个预测。完整细节可在论文中找到。
在这里,我们将使用 LIME 来检查模型完全错误的预测,以了解它可能会告诉我们关于模型为什么会出错的信息。
首先,我们需要找到我们的模型最容易出错的观察结果。我们通过使用模型进行训练和预测,并提取模型误差最大的示例来实现这一点:
**Prediction: 12.8615
Actual Value: 100.0000**
接下来,我们创建 LIME explainer 对象,向它传递我们的训练数据、模式、训练标签和数据中的特性名称。最后,我们要求解释者对象解释错误的预测,传递给它观察和预测函数。
解释这一预测的图表如下:
以下是解释该图的方法:y 轴上的每个条目表示一个变量的一个值,红色和绿色条显示该值对预测的影响。例如,顶部条目显示站点 EUI 大于 95.90,这从预测中减去了大约 40 个点。第二个条目说天气标准化的站点电力强度小于 3.80,这为预测增加了大约 10 分。最终预测是截距项加上这些单独贡献的总和。
我们可以通过调用 explainer .show_in_notebook()
方法来查看相同的信息:
# Show the explanation in the Jupyter Notebook
exp.show_in_notebook()
Output from LIME Explainer Object
这通过显示每个变量对预测的贡献,在左侧显示了模型的推理过程。右边的表格显示了数据点变量的实际值。
对于本例,模型预测值约为 12,而实际值为 100!虽然最初这一预测可能令人费解,但通过查看解释,我们可以看到这不是一个极端的猜测,而是给定数据点值的合理估计。该站点 EUI 相对较高,我们预计能源之星得分较低(因为 EUI 与得分高度负相关),这是我们的模型得出的结论。在这种情况下,逻辑是错误的,因为该建筑的满分是 100 分。
当一个模型是错误的时候,它可能是令人沮丧的,但是诸如此类的解释帮助我们理解为什么模型是不正确的。此外,基于这一解释,我们可能想要调查为什么该建筑尽管有如此高的场地 EUI 却得到了满分。也许我们可以了解到一些新的问题,如果不研究这个模型,我们可能会忽略这些问题。诸如此类的工具并不完美,但它们对帮助我们理解模型大有帮助,这反过来可以让我们做出更好的决策。
记录工作和报告结果
任何技术项目中经常被忽视的部分是文档和报告。我们可以做世界上最好的分析,但是如果我们不与清楚地交流结果,那么他们将不会有任何影响!
当我们记录一个数据科学项目时,我们会将所有版本的数据和代码打包,以便其他数据科学家可以复制或构建我们的项目。重要的是要记住,代码被阅读的次数比它被编写的次数要多,我们要确保我们的工作是可以理解的对他人和我们自己如果我们几个月后再回来看的话。这意味着在代码中加入有用的注释,并解释你的推理。我发现 Jupyter 笔记本是一个很好的文档工具,因为它们允许一个接一个的解释和编码。
Jupyter 笔记本也是一个很好的与他人交流发现的平台。使用笔记本扩展,我们可以在我们的最终报告中隐藏代码,因为虽然这很难相信,但并不是每个人都想在一个文档中看到一堆 Python 代码!
就我个人而言,我很难简明扼要地总结我的工作,因为我喜欢浏览所有的细节。然而,重要的是在你演讲的时候理解你的听众并且相应地调整信息。考虑到这一点,以下是我对这个项目的 30 秒总结:
- 使用纽约市的能源数据,可以建立一个模型,将建筑物的能源之星得分预测到 9.1 分以内。
- 站点 EUI 和天气标准化电力强度是预测能源之星得分的最相关因素。
最初,我被一家初创公司作为筛选工作的“任务”给了这个项目。为了期末报告,他们想看我的工作和结论,所以我做了一个 Jupyter 笔记本上交。然而,我没有在 Jupyter 中直接转换为 PDF,而是将其转换为一个 Latex .tex
文件,然后在 texStudio 中编辑,然后渲染为用于最终版本的 PDF。Jupyter 的默认 PDF 输出有一个体面的外观,但它可以通过几分钟的编辑得到显著改善。此外,Latex 是一个强大的文档准备系统,了解基础知识很有好处。
一天结束时,我们的工作的价值取决于它所促成的决策,而能够展示结果是一项至关重要的技能。此外,通过正确记录工作,我们允许其他人复制我们的结果,给我们反馈,以便我们可以成为更好的数据科学家,并为未来建立我们的工作。
结论
在这一系列的帖子中,我们已经走过了一个完整的端到端机器学习项目。我们从清理数据开始,进入模型构建,最后看如何解释机器学习模型。提醒一下,机器学习项目的一般结构如下:
- 数据清理和格式化
- 探索性数据分析
- 特征工程和选择
- 在性能指标上比较几种机器学习模型
- 对最佳模型执行超参数调整
- 评估测试集上的最佳模型
- 尽可能解释模型结果
- 得出结论,写一份证据充分的报告
虽然具体步骤因项目而异,并且机器学习通常是一个迭代而不是线性过程,但本指南应该在您处理未来的机器学习项目时很好地为您服务。我希望这个系列已经给了你信心,让你能够实现你自己的机器学习解决方案,但是记住,我们没有一个人自己做到这一点!如果你需要任何帮助,有许多令人难以置信的支持社区,你可以在那里寻求建议。
在我的学习过程中,我发现了一些有用的资源:
- 用 Scikit-Learn 和 Tensorflow 进行动手机器学习 ( 这本书的 Jupyter 笔记本在线免费提供)!
- 统计学习入门
- Kaggle:数据科学和机器学习之家
- Datacamp :练习数据科学编码的入门教程
- Coursera :许多学科的免费和付费课程
- Udacity :付费编程和数据科学课程
一如既往,我欢迎反馈和讨论,可以通过 Twitter @koehrsen_will 联系。
关于如何在 Google Colab(免费 GPU)上使用 Keras 微调深度神经网络的全面指南
I like sweet oranges.
在 CPU 上训练深度神经网络比较困难。本教程将指导你如何使用谷歌协作实验室上的 Keras 对 VGG-16 网络进行微调,谷歌协作实验室是一个免费的 GPU 云平台。如果你是谷歌实验室的新手,这是一个适合你的地方,你会学到:
- 如何在 Colab 上创建您的第一个 Jupyter 笔记本,并使用免费的 GPU。
- 如何在 Colab 上上传和使用您的自定义数据集。
- 如何在前景分割领域对 Keras 预训练模型(VGG-16)进行微调。
现在,让我们开始吧…
1.创建您的第一个 Jupyter 笔记本
假设您已经登录了您的 Google 帐户。请遵循以下步骤:
**一)。**导航至http://drive.google.com。
b)。您将在左侧窗格中看到我的驱动器选项卡。现在,在里面创建一个文件夹,比如说 Colab 笔记本。
c)。在已创建的文件夹内的右窗格的其他地方单击右键,选择更多 > 协同实验室。另一个窗口会弹出来,你可以给你的笔记本起个别的名字,比如说 myNotebook.ipynb 。加油!!!您已经在 Colab 上创建了您的第一个笔记本😄
2.为笔记本电脑设置 GPU 加速器
在笔记本中,选择运行时 > 改变运行时类型。将弹出一个窗口。然后,选择您的运行时类型,从硬件加速器下拉菜单中选择 GPU 并保存您的设置(如下图)。
3.将您的自定义数据集上传到 Colab
您已经完成了在 GPU 上运行笔记本的设置。现在,让我们把你的数据集上传到 Colab。在本教程中,我们工作在前景分割,从背景中提取前景物体(下图)。
images are taken from changedetection.net
将数据集上传到 Colab 有几个选项,但是,在本教程中我们考虑两个选项;首先,我们上传到 GitHub 并从它克隆到 Colab,其次,我们上传到 Google Drive 并直接在我们的笔记本上使用。你可以选择任何一个选项。或 **b)。**下图:
a)。从 GitHub 克隆
让我们将上述数据集克隆到创建的笔记本中。在你笔记本的单元格中,运行!git clone [https://github.com/lim-eren/CDnet2014.git](https://github.com/lim-eren/CDnet2014.git).
你会看到这样的东西:
搞定了。让我们列出训练集,看看它是否有效:
开始了。训练集包含 25 个输入帧和 25 个真实帧。跳过**部分 b)。并跳转到第 4 节。**如果你做到了这一步。
b)。从 Google Drive 下载
另一个选择是将你的数据集上传到 Google Drive,然后从中克隆。假设你已经压缩了上面的训练集,比如说 CDnet2014.zip ,上传到 Google Drive 和 myNotebook.ipynb 在同一个目录下。现在,右键点击cdnet 2014 net . zip>获取可共享链接。复制文件的 id 并将其存储在某个地方(我们稍后会用到)。
然后,通过运行以下代码验证 Colab 以访问 Google Drive。按照链接获取验证码并粘贴到下面的文本框中,然后按 Enter 键。
然后,让我们将 CDnet2014net.zip 文件内容下载到我们的 Jupyter 笔记本中(用上一步获得的 id 替换YOUR_FILE_ID
),并通过运行以下代码将其解压缩:
搞定了。您已经将数据集从 Google Drive 下载到 Colab。让我们继续第 4 节使用这个数据集建立一个简单的神经网络。
4.微调你的神经网络
在您的数据集下载到 Colab 后,现在让我们在前景分割域中微调 Keras 预训练模型。请遵循以下步骤:
**一)。**首先,将该代码片段添加到您的笔记本上,以获得跨机器的可再现结果(请在您笔记本的单元格中运行该代码片段):
**b)。**创建一个从 Colab 加载数据的函数。该函数返回输入图像(X)和相应的基本事实(Y):
c)。初始一个普通的编码器-解码器模型。我们采用 VGG-16 预训练模型作为编码器,其中所有全连接层都被移除,只有最后一个卷积层(block5_conv3
)被微调,其余层被冻结。我们使用转置卷积层来恢复解码器部分的特征分辨率。
因为这是一个二元分类问题,所以使用了binary_crossentropy
,网络的输出将是 0 和 1 之间的概率值。这些概率值需要被阈值化,以便获得二进制标签 0 或 1,其中标签 0 表示背景,标签 1 表示前景。
**维。**我们设定学习率为 5e-4,batch_size 为 1,validation_split 为 0.2,max-epochs 为 100,当验证损失在 5 个时期内停止改善时,将学习率降低 10 倍,当验证损失在 10 个时期内停止改善时,提前停止训练。现在,让我们训练模型。
Training with GPU
一个纪元大约需要 1 秒,太快了!!!在验证集上,最高准确率达到 98%以上。不错吧?现在,让我们暂停一下。我们来对比一下训练有 GPU** 和没有 GPU的速度吧(如果你愿意可以跳过这个对比直接跳到测试部分)。要在没有 GPU 的情况下进行训练,请将硬件加速器设置为无**(参见第 2 节。以上)。这是训练日志。在没有 GPU 的情况下,一个历元需要大约 **30 秒,**而使用 GPU 训练时只需要 1 秒(大约快 30 倍👏).
Training without GPU
现在,让我们用 Colab GPU 在测试集上测试训练好的模型(你可以运行 *!ls */test/**
来查看带有相应地面实况的测试帧)。
加油!!!对于一个普通的网络,我们只需要使用 25 个training+validation
例子就可以达到 98.94% 的测试精度😄。注意,由于训练样本的随机性,你可能会得到和我相似的结果(不完全相同但只有很小的精度差异)。
注意一个问题:我们的模型过度拟合训练数据,解决这个问题是你的工作。提示:使用正规化技术,如辍学、 L2 、批量正规化。
**e)。**让我们通过运行以下代码来绘制分段掩码:
开始了。分割结果一点都不差!大多数对象边界被错误分类,这个问题主要是由于在训练期间的损失计算中考虑了空标签(对象边界周围的模糊像素)的情况。我们可以通过在损耗中省略这些 void 标签来进一步提高性能。你可以参考这里的或者这里的关于如何做。
test result on CDnet2014 dataset (changedetection.net)
本教程的完整源代码可在 GitHub 中获得。
摘要
在本教程中,您已经学习了如何使用 Google Colab GPU,并以快速的方式训练了网络。您还学习了如何在前景分割领域中微调 Keras 预训练模型,您可能会在未来的研究中发现这一点。
如果你喜欢这个帖子,请随意分享或鼓掌。请过得愉快!🎊😁
卷积神经网络综合指南 ELI5 方法
人工智能见证了在弥合人类和机器能力之间的差距方面的巨大发展。研究人员和爱好者一样,致力于该领域的许多方面,使惊人的事情发生。许多这样的领域之一是计算机视觉领域。
该领域的目标是使机器能够像人类一样看待世界,以类似的方式感知世界,甚至将这些知识用于多种任务,如图像和视频识别、图像分析和分类、媒体娱乐、推荐系统、自然语言处理等。具有深度学习的计算机视觉的进步已经随着时间的推移而构建和完善,主要是在一种特定的算法上——一种卷积神经网络。
准备好尝试自己的卷积神经网络了吗?查看土星云免费计算(包括免费 GPU)。
介绍
A CNN sequence to classify handwritten digits
卷积神经网络(ConvNet/CNN) 是一种深度学习算法,可以接受输入图像,为图像中的各个方面/对象分配重要性(可学习的权重和偏差),并能够区分彼此。与其他分类算法相比,ConvNet 中所需的预处理要低得多。在原始方法中,滤波器是手工设计的,经过足够的训练,ConvNets 有能力学习这些滤波器/特性。
ConvNet 的架构类似于人脑中神经元的连接模式,其灵感来自视觉皮层的组织。单个神经元只在视野中被称为感受野的有限区域内对刺激做出反应。这些区域的集合重叠覆盖了整个可视区域。
为什么 ConvNets 优于前馈神经网络?
Flattening of a 3x3 image matrix into a 9x1 vector
图像不过是像素值的矩阵,对吗?那么,为什么不干脆将图像扁平化(例如,将 3×3 的图像矩阵转化为 9×1 的向量)并将其输入到多级感知器中进行分类呢?哦…不完全是。
在极其基本的二进制图像的情况下,该方法在执行类别预测时可能显示平均精度分数,但是当涉及到整体上具有像素依赖性的复杂图像时,该方法将几乎没有精度。
通过应用相关过滤器,ConvNet 能够成功捕捉图像中的空间和时间相关性。由于所涉及的参数数量的减少和权重的可重用性,该架构对图像数据集执行更好的拟合。换句话说,可以训练网络更好地理解图像的复杂程度。
输入图像
4x4x3 RGB Image
在图中,我们有一个 RGB 图像,它由三个颜色平面(红色、绿色和蓝色)分开。图像存在于许多这样的色彩空间中——灰度、RGB、HSV、CMYK 等。
你可以想象一旦图像达到 8K (7680×4320)的尺寸,计算量会有多大。ConvNet 的作用是将图像简化为一种更容易处理的形式,而不会丢失对获得良好预测至关重要的特征。当我们要设计一个不仅擅长学习特征,而且可扩展到大规模数据集的架构时,这一点很重要。
卷积层—内核
Convoluting a 5x5x1 image with a 3x3x1 kernel to get a 3x3x1 convolved feature
图像尺寸= 5(高)x 5(宽)x 1(通道数,如 RGB)
在上面的演示中,绿色部分类似于我们的 5x5x1 输入图像,I 。卷积层第一部分的卷积运算中涉及的元素称为内核/滤波器,K ,用黄色表示。我们选择了 K 作为一个 3x3x1 的矩阵。
Kernel/Filter, K = 1 0 1
0 1 0
1 0 1
由于步长= 1(非步长),内核移位 9 次,每次在 K 和内核所悬停的图像部分 P 之间执行逐元素 乘法运算( 哈达玛乘积 )。
Movement of the Kernel
过滤器以一定的步幅值向右移动,直到解析完整的宽度。继续前进,它向下跳到具有相同步幅值的图像的开头(左侧),并重复该过程,直到遍历整个图像。
Convolution operation on a MxNx3 image matrix with a 3x3x3 Kernel
在具有多个通道(例如 RGB)的图像的情况下,内核具有与输入图像相同的深度。在 Kn 和 In 栈之间进行矩阵乘法([K1,I1];[K2,I2];[K3,I3]),所有结果与偏差相加,得到一个压缩的单深度通道卷积特征输出。
Convolution Operation with Stride Length = 2
卷积操作的目的是从输入图像中提取高级特征,如边缘。ConvNets 不必仅限于一个卷积层。按照惯例,第一个 ConvLayer 负责捕获边缘、颜色、渐变方向等低级特征。随着图层的增加,该架构也适应了高级功能,为我们提供了一个对数据集中的图像有全面了解的网络,就像我们会做的那样。
该操作有两种类型的结果-一种是与输入相比,卷积特征的维数减少,另一种是维数增加或保持不变。这是通过在前一种情况下应用有效填充,或者在后一种情况下应用相同填充来完成的。
SAME padding: 5x5x1 image is padded with 0s to create a 6x6x1 image
当我们将 5x5x1 图像放大为 6x6x1 图像,然后对其应用 3x3x1 内核时,我们发现卷积矩阵的维数为 5x5x1。因此得名——同垫。
另一方面,如果我们在没有填充的情况下执行相同的操作,我们会看到一个矩阵,它具有内核(3x3x1)本身的维度— 有效填充。
下面的存储库包含了许多这样的 gif,它们将帮助你更好地理解垫高和步幅长度是如何协同工作以达到我们需要的结果的。
深度学习背景下的卷积算法技术报告——VDU moulin/conv 算法
github.com](https://github.com/vdumoulin/conv_arithmetic)
汇集层
3x3 pooling over 5x5 convolved feature
与卷积层类似,汇集层负责减小卷积要素的空间大小。这是为了通过降维来降低处理数据所需的计算能力。此外,它对于提取旋转和位置不变的主导特征是有用的,从而保持有效训练模型的过程。
有两种类型的池:最大池和平均池。最大池从内核覆盖的图像部分返回最大值。另一方面,平均池返回内核覆盖的图像部分的所有值的平均值。
最大池也表现为噪音抑制。它完全丢弃有噪声的激活,并且在降维的同时执行去噪。另一方面,平均池只是作为一种噪声抑制机制来执行降维。因此,我们可以说最大池比平均池性能好得多。
Types of Pooling
卷积层和汇集层一起形成卷积神经网络的第 I 层。根据图像的复杂性,这种层的数量可以增加,以捕捉更低层次的细节,但代价是更多的计算能力。
在经历了上述过程之后,我们已经成功地使模型理解了特征。接下来,我们将使最终输出变平,并将其输入常规神经网络进行分类。
分类—全连接层(FC 层)
添加全连接层是学习由卷积层的输出表示的高级特征的非线性组合的(通常)廉价方式。全连接层正在学习该空间中可能的非线性函数。
既然我们已经将输入图像转换成适合多层感知器的形式,我们应该将图像展平成一个列向量。平坦化的输出被馈送到前馈神经网络,并且反向传播被应用于训练的每次迭代。在一系列时期内,该模型能够区分图像中的主要特征和某些低级特征,并使用 Softmax 分类技术对其进行分类。
有各种可用的 CNN 架构,它们是构建算法的关键,在可预见的未来,这些算法将作为一个整体为 AI 提供动力。其中一些列举如下:
- LeNet
- AlexNet
- VGGNet
- 谷歌网
- 雷斯内特
- ZFNet
GitHub 笔记本——使用 TensorFlow 的 MNIST 数据集识别手写数字
[## ss-is-master-chief/MNIST 数字。识别器-CNN
CNN 识别运行 10 个时期的手写数字(MNIST)的实现。准确率:98.99% …
github.com](https://github.com/ss-is-master-chief/MNIST-Digit.Recognizer-CNNs)
准备好尝试自己的卷积神经网络了吗?查看土星云免费计算(包括免费 GPU)。
多维数据有效可视化的图形语法综合指南
了解利用图形框架的分层语法实现有效数据可视化的有效策略
介绍
可视化多维数据是一门艺术,也是一门科学。由于我们的二维(2-D)渲染设备的限制,随着维度数量的增加,在两个以上的数据维度(属性或特征)上构建有效的可视化变得具有挑战性。在我之前的一篇文章 【多维数据有效可视化的艺术】 中,我们已经广泛地介绍了有效的多维数据可视化的一些策略,并提供了实际操作的例子。在本文中,我们将介绍我们用来构建这些可视化的分层框架,称为***‘图形的语法’***。我们还将探索图形框架分层语法背后的基本概念,并讨论我们如何使用每个特定的分层组件在多维数据上构建有效的可视化。示例将用 Python 展示,但是,如果您感兴趣,您可以轻松地用 R 复制相同的内容。
动机
数据可视化和讲故事一直是任何数据科学管道中最重要的阶段之一,涉及到从数据中提取有意义的见解,不管数据或项目有多复杂。举个简单的例子 【十几只雷龙】——下图描绘了十二个不同的数据集。
你能猜出这些看起来非常不同的数据集之间的共同点吗?
The Datasaurus Dozen — What is common among these diverse datasets?
答:所有数据集的汇总统计数据完全相同!
这是著名的安斯科姆四重奏的有趣变体,你们很多人可能都很熟悉,如下图所示。
Anscombe’s quartet — Different datasets with same summary statistics
这些演示的关键要点是,“不要盲目相信你的数据,开始根据你的数据建模”。汇总统计数据总是具有欺骗性。在继续进行特征工程和构建统计、机器学习和深度学习模型之前,请始终可视化和理解您的数据属性。
另一个非常重要的动机来源,特别是对于有效的数据可视化,可以从几个世纪前的一些优秀案例研究中获得,当时我们甚至没有计算机,更不用说 Python 或 R!第一幅是约翰·斯诺著名的可视化作品,描绘了 1854 年英国伦敦爆发的宽街霍乱!
Visualizing the Broad Street Cholera outbreak which helped find the root cause of the disease outbreak!
你可以看到一个简单的手绘可视化是如何帮助找到 19 世纪 50 年代宽街霍乱爆发的根本原因的。另一个有趣的可视化是由现代护理实践之母佛罗伦萨南丁格尔建立的,她对护理和统计有着根深蒂固的兴趣。
Causes of Mortality in the Army of the East — Florence Nightingale
上图描绘了一个极区图,描述了 19 世纪 50 年代军队中的死亡原因。我们可以看到,这一可视化绝对不是简单化的,但它传达了正确的见解——清楚地显示了士兵死于可预防疾病的比例,这些疾病基于伤口或其他原因。这应该为有效的数据可视化提供足够的动力!
理解图形的语法
为了理解图形的语法,我们需要理解语法是什么意思。下图简要总结了这两个方面。
基本上,图形语法是一个框架,它遵循分层的方法,以结构化的方式描述和构建可视化或图形。涉及多维数据的可视化通常有多个组件或方面,利用这种分层的图形语法有助于我们描述和理解可视化中涉及的每个组件——在数据、美学、比例、对象等方面。
图形框架的原始语法是由 Leland Wilkinson 提出的,它详细地涵盖了与有效数据可视化相关的所有主要方面。我肯定会推荐感兴趣的读者去看看这本书,只要他们有机会!
第一版序言在 1980 年代为 SYSTAT 编写图形之前,我首先讲授了一个关于…
www.springer.com](https://www.springer.com/in/book/9780387245447)
然而,我们将使用它的一个变体——称为图形框架的分层语法,它是由著名的数据科学家 Hadley Wickham 提出的,他也是著名的 R visualization 软件包[**ggplot2**](https://ggplot2.tidyverse.org/)
的创建者。读者应该看看他的论文,标题是 【图形的分层语法】 ,其中详细介绍了他提出的图形分层语法,还谈到了他为 R 编程语言构建的开源实现框架**ggplot2**
[## 图形的分层语法
图形语法是一种工具,它使我们能够简明地描述图形的组成部分。这样的语法…
vita.had.co.nz](http://vita.had.co.nz/papers/layered-grammar.html)
哈德利的图形分层语法使用几个分层组件来描述任何图形或可视化。最值得注意的是,它与威尔金森提出的原始图形语法有一些不同,如下图所示。
Mapping between components of Wilkinson’s grammar (left) and the layered grammar (right)
你可以看到语法中有各种各样的成分,可以用来建立和描述可视化。我已经确定了 七个 这样的主要组件,它们通常帮助我在多维数据上建立有效的可视化。下图显示了语法中每个特定组件的一些细节。
Major components of the Grammar of Graphics
我们用一个金字塔架构来展示组件的内在分层结构。通常,为了用一个或多个维度构建或描述任何可视化,我们可以使用如下组件。
- 数据:始终从数据开始,确定你想要可视化的维度。
- 美观:根据数据尺寸,图中各数据点的位置确定轴。还要检查是否需要任何形式的编码,包括大小、形状、颜色等等,这些对于绘制多个数据维度都很有用。
- **标度:**我们是否需要对潜在值进行标度,用一个特定的标度来表示多个值或一个范围?
- **几何对象:**这些通常被称为“几何对象”。这将涵盖我们在可视化上描绘数据点的方式。应该是点,条,线之类的?
- **统计:**我们是否需要在可视化中显示一些统计度量,如集中趋势、扩散、置信区间的度量?
- Facets: 我们需要根据特定的数据维度创建支线剧情吗?
- **坐标系:**可视化应该基于哪种坐标系——是笛卡尔坐标系还是极坐标坐标系?
现在,我们将通过一些实际操作的例子来看看如何利用这个分层框架来为多维数据构建有效的数据可视化。
动作图形的语法
现在,我们将把我们在上一节中学到的概念应用到一些实际数据上。我们将使用 Python 来构建我们所有的可视化,但是我也推荐人们查看 R 中的**ggplot2**
包,这是迄今为止最鼓舞人心的框架之一,用于构建漂亮和干净的出版物质量的可视化。我们确实有一个用 Python 编写的[**ggplot**](http://ggplot.yhathq.com)
框架,它是由 Yhat,Inc. 构建的。但是,如果你检查一下存储库,在过去的两年里没有提交或更新,不幸的是,这导致了一些错误,特别是由于与**pandas**
的新版本的向后不兼容问题。因此,为了模拟 Python 中图形语法的真正分层语法,我们将使用另一个有趣的框架[**plotnine**](https://plotnine.readthedocs.io/en/stable/)
。
[## Python - plotnine 0.4.0 文档的图形语法
plotnine 是 Python 中图形语法的一个实现,它基于 ggplot2。该语法允许用户…
plotnine.readthedocs.io](https://plotnine.readthedocs.io/en/stable/)
Plotnine 是基于**ggplot2**
的图形框架分层语法的开源 Python 实现。因此,使用这个分层语法中先前指定的组件,我们可以构建有效的可视化。
从数据开始
我们总是从加载并查看我们想要分析和可视化的数据集开始。我们将使用著名的[**mtcar**](https://stat.ethz.ch/R-manual/R-devel/library/datasets/html/mtcars.html)**s**
数据集作为**plotnine**
中预加载的数据集之一。
mtcars 数据集由从 1974 年美国杂志《汽车趋势中提取的数据组成,描述了 32 款汽车(1973-74 款)的油耗和汽车设计及性能的 10 个其他属性。上图中描述了每个属性的详细信息。让我们现在建立一些可视化。
可视化二维(2d)
我们现在可以使用图形框架的分层语法中的一些组件(包括数据、比例、美学和几何图形)来可视化高达二维的数据。在这种情况下,我们为几何对象选择一个点或散点图来表示每个数据点。
从上面的可视化中我们可以清楚的看到**mpg**
和猫**wt**
是负相关的。
三维可视化
为了从我们的数据集中可视化三维,我们可以利用颜色作为我们的美学组件之一,来可视化除了其他两个维度之外的一个额外的维度,如下例所示。
在上面的可视化中,我们使用颜色美学以及其他两个数据维度(变量)将具有不同数量档位的汽车描述为单独的类别。很明显,平均而言,**gears**
数较少的汽车往往**wt**
较高,而**mpg**
较低。
可视化四维(四维)
为了从我们的数据集中可视化四维,除了包括几何图形、数据和比例在内的其他常规组件之外,我们还可以利用颜色和大小作为我们的两个美学要素。
可视化向我们展示了美学在帮助我们在单个绘图中可视化多个数据维度方面有多么强大。很明显,**cyl**
(气缸)数量较高的汽车的**gears**
数量较低,反过来,它们的**wt**
较高而**mpg**
较低。
或者,我们也可以使用颜色和刻面来描述四维数据,而不是大小,如下例所示。
刻面无疑是构建有效数据可视化的最强大的组件之一,如上面的可视化所示,我们可以清楚地看到具有较高**cyl**
计数的汽车具有较低的**gear**
计数,并且趋势与之前的颜色和尺寸可视化相似。
可视化数据维度和统计数据
为了可视化数据维度和一些相关的统计数据(比如拟合线性模型),我们可以在分层语法中利用统计数据和其他组件。
这使我们能够看到基于**wt**
的**mpg**
的线性模型趋势。
可视化五维空间
要在五维空间中可视化数据,您现在已经知道该如何操作了!我们将利用美学的力量,包括颜色、尺寸和小平面。
这里我们用**am**
作为刻面,其中 0 表示自动挡的车,1 表示手动挡的车。该图显示,与自动变速器的汽车相比,手动变速器的汽车具有更高的档位数量。此外,大多数气缸数量较多的汽车(**cyl**
)都配有自动变速器。其他见解与我们在前面的情节中观察到的相似。
可视化六维(6-D)
为了在六个维度上可视化数据,我们可以在 y 轴上添加一个额外的面,在 x 轴上添加一个面,并添加颜色和大小作为美观。
我们将变速器(**am**
)表示为 0(自动)和 1(手动),作为在 y 轴上的一个小平面,将化油器数量(**carb**
)表示为在 x 轴上的一个小平面,此外,使用与我们之前的绘图类似的其他美学来表示其他尺寸。从上面的图像中可以看出一个有趣的现象,档位较多的汽车有手动变速器(**am**
)和较多的化油器(**carb**
)。你注意到其他有趣的见解了吗?
我们能再高点吗?
紧迫的问题是,我们能超越六维吗?当然,突破二维渲染设备的限制来可视化更多的数据维度肯定会变得越来越困难。
一种方法是使用更多的面和支线剧情。除此之外,如果数据集具有时间方面,也可以使用时间的概念,如下例所示。
Hans Rosling’s famous visualization of global population, health and economic indicators
这描绘了 汉斯·罗斯林的 著名的描绘全球各国人口、健康和各种经济指标的可视化作品。这也在 官方 ted 大会 上展示过,如果大家还没做过,我推荐大家去看看!
这将为您提供一个很好的视角,让您了解如何利用图形的分层语法来可视化多维数据。
结论
正如我一再提到的,数据可视化既是一门科学,也是一门艺术。本文将为您提供足够的动力和示例,让您开始理解和利用图形框架的分层语法,在多维数据上构建自己的有效可视化。
本文中使用的所有代码都可以作为 Jupyter 笔记本 以及其他内容和幻灯片在 my GitHub 资源库 中获得。
多维数据的有效可视化艺术
github.com](https://github.com/dipanjanS/art_of_data_visualization)
我确实讲述了如何在稍微复杂一些的数据上使用 Python 中最先进的数据可视化框架(如**seaborn**
和**matplotlib**
)来可视化多维数据。如果你有兴趣,下面的文章 中的 应该可以帮你入门。
有效数据可视化的策略
towardsdatascience.com](/the-art-of-effective-visualization-of-multi-dimensional-data-6c7202990c57)
我最近在 2018 年 ODSC的一次会议上谈到了这些文章的主要部分。你可以在这里查看 完整的演讲议程和幻灯片 。一旦发布,我会在 YouTube 上发布这次会议的演讲!
[## 多维数据的有效可视化艺术-实践方法- ODSC 印度…
描述性分析是与数据科学项目或…相关的任何分析生命周期的核心组成部分之一
confengine.com](https://confengine.com/odsc-india-2018/proposal/6846/the-art-of-effective-visualization-of-multi-dimensional-data-a-hands-on-approach)
有反馈给我吗?或者有兴趣与我一起从事研究、数据科学、人工智能,甚至发表一篇关于 TDS 的文章?可以在LinkedIn上联系我。
[## Dipanjan Sarkar -数据科学家-英特尔公司| LinkedIn
查看 Dipanjan Sarkar 在世界最大的职业社区 LinkedIn 上的个人资料。Dipanjan 有 6 份工作列在…
www.linkedin.com](https://www.linkedin.com/in/dipanzan/)
感谢 杜巴 编辑本文。
在深度学习中通过真实世界的应用转移学习的综合实践指南
用知识转移的力量进行深度学习!
Source: Pixabay
介绍
人类有跨任务传递知识的天生能力。我们在学习一项任务时获得的知识,我们以同样的方式用来解决相关的任务。任务越相关,我们就越容易转移或交叉利用我们的知识。一些简单的例子是,
- 知道如何骑摩托车⮫学习如何骑汽车
- 知道如何演奏古典钢琴⮫学习如何演奏爵士钢琴
- 了解数学和统计⮫学习机器学习
在上述每个场景中,当我们试图学习新的方面或主题时,我们不会从头开始学习一切。我们从过去学到的知识中转移和利用我们的知识!
到目前为止,传统的机器学习和深度学习算法一直被设计为孤立工作。这些算法被训练来解决特定的任务。一旦特征空间分布发生变化,就必须从头开始重建模型。迁移学习是克服孤立的学习范式,利用从一项任务中获得的知识来解决相关任务的思想。在本文中,我们将全面介绍迁移学习的概念、范围和实际应用,甚至展示一些实际例子。更具体地说,我们将涉及以下内容。
- 迁移学习的动机
- 理解迁移学习
- 迁移学习策略
- 深度学习的迁移学习
- 深度迁移学习策略
- 深度迁移学习的类型
- 迁移学习的应用
- 案例研究 1:具有数据可用性约束的图像分类
- 案例研究 2:具有大量类别和较少数据可用性的多类别细粒度图像分类
- 转移学习优势
- 转移学习挑战
- 结论&未来范围
我们将把迁移学习视为一个通用的高级概念,它始于机器学习和统计建模的时代,然而,在本文中,我们将更专注于深度学习。
**注意:**所有案例研究将逐步涵盖代码和输出的细节。这里描述的案例研究及其结果完全基于我们在编写本书时实施和测试这些模型时进行的实际实验: 用 Python 进行迁移学习 (细节在本文末尾)。
鉴于网络上的信息过载,本文旨在尝试涵盖理论概念,并在一个地方展示深度学习应用的实际动手示例。所有的例子都将包含在 Python 中,使用 keras 和 tensorflow 后端,这是老手或刚开始深度学习的人的完美匹配!对 PyTorch 感兴趣?请随意转换这些例子并联系我,我会在这里和 GitHub 上展示你的作品!
迁移学习的动机
我们已经简单地讨论过,人类不会从头开始学习所有的东西,也不会利用和转移他们以前学习领域的知识到新的领域和任务中。鉴于对 真正的人工智能 的狂热,数据科学家和研究人员认为迁移学习可以进一步推动我们朝着的方向前进。事实上, 吴恩达 ,知名教授和数据科学家,一直与谷歌大脑、百度、斯坦福和 Coursera 有联系,最近在 NIPS 2016 上给出了一个惊人的教程,名为‘使用深度学习构建 AI 应用的基本要素’,他提到**
监督学习之后——迁移学习将是 ML 商业成功的下一个驱动力
推荐有兴趣的乡亲们去看看 NIPS 2016 的 他的有趣教程 。
事实上,迁移学习并不是 21 世纪 10 年代才出现的概念。神经信息处理系统(NIPS) 1995 年研讨会学会学习:归纳系统中的知识巩固和转移被认为为该领域的研究提供了最初的动力。从那以后,学会学习、知识巩固、归纳迁移等术语就和迁移学习互换使用了。不变的是,不同的研究人员和学术文本从不同的背景下提供定义。Goodfellow 等人在他们的名著深度学习中提到了泛化背景下的迁移学习。它们的定义如下:
在一种情况下学到的东西被用来在另一种情况下提高概括能力。
因此,关键的动机,尤其是考虑到深度学习的背景,是这样一个事实,即解决复杂问题的大多数模型需要大量的数据,考虑到标记数据点所花费的时间和精力,为监督模型获取大量的标记数据可能非常困难。一个简单的例子是 ImageNet 数据集 , ,它拥有数百万张属于不同类别的图像,这要归功于从斯坦福开始的多年努力!
The popular ImageNet Challenge based on the ImageNet Database
然而,为每个领域获取这样的数据集是困难的。此外,大多数深度学习模型都非常专门针对特定领域甚至特定任务。虽然这些可能是最先进的模型,具有非常高的准确性,并超越了所有基准,但它只会在非常特定的数据集上使用,当用于新任务时,性能最终会大幅下降,而新任务可能仍然与它接受训练的任务相似。这形成了迁移学习的动机,它超越了特定的任务和领域,并试图了解如何利用来自预训练模型的知识,并使用它来解决新问题!
理解迁移学习
这里要记住的第一件事是,迁移学习并不是一个新的概念,它对于深度学习来说是非常具体的。建立和训练机器学习模型的传统方法与使用遵循迁移学习原则的方法之间存在明显的差异。
Traditional Learning vs Transfer Learning
传统的学习是孤立的,纯粹基于特定的任务、数据集和在其上训练单独的孤立模型而发生。没有保留可以从一个模型转移到另一个模型的知识。在迁移学习中,您可以利用以前训练的模型中的知识(特征、权重等)来训练新的模型,甚至解决新任务中数据较少的问题!
让我们借助一个例子来理解前面的解释。假设我们的任务是在一家餐馆的限定区域内识别图像中的物体。让我们将这个任务在其定义的范围内标记为。给定此任务的数据集,我们训练一个模型并对其进行调整,使其在来自同一域(餐馆)的看不见的数据点上表现良好(一般化)。当我们没有足够的训练样本来完成特定领域的任务时,传统的监督 ML 算法就会失效。假设,我们现在必须从公园或咖啡馆的图像中检测物体(比方说,任务 T2 )。理想情况下,我们应该能够应用为 T1 训练的模型,但在现实中,我们面临着性能下降和不能很好概括的模型。这种情况的发生有多种原因,我们可以将其统称为模型对训练数据和领域的偏好。**
迁移学习应该使我们能够利用以前学习的任务中的知识,并将它们应用到更新的相关任务中。如果我们对于任务有明显更多的数据,我们可以利用它的学习,并且对于任务(其具有明显更少的数据)概括这种知识(特征、权重)。在计算机视觉领域中的问题的情况下,某些低级特征,例如边缘、形状、拐角和强度,可以在任务之间共享,从而实现任务之间的知识转移!此外,正如我们在前面的图中所描述的,当学习新的目标任务时,来自现有任务的知识作为额外的输入。**
形式定义
现在让我们来看看迁移学习的正式定义,然后利用它来理解不同的策略。在他们的论文、、中,潘和杨用领域、任务和边际概率提出了一个理解迁移学习的框架。该框架定义如下:
*一个域, D ,定义为由特征空间、【ꭕ】*和边际概率、p(χ)组成的二元元组,其中χ为样本数据点。因此,我们可以在数学上把定义域表示为 D = {ꭕ,p(χ)}
这里的表示如上所述的特定向量。另一方面,一个任务, T 可以定义为标签空间的二元元组, γ ,以及目标函数,【η。从概率的角度,目标函数也可以表示为P(γ|χ)。****
因此,有了这些定义和表述,我们可以如下定义迁移学习,这要感谢 Sebastian Ruder 的一篇优秀文章。
情节
基于我们之前的定义,现在让我们来看看涉及迁移学习的典型场景。
为了更清楚地说明术语 领域 和 任务 之间的区别,下图试图用一些例子来解释它们。
关键要点
正如我们到目前为止所看到的,迁移学习就是在目标任务中利用源学习者的现有知识的能力。在迁移学习过程中,必须回答以下三个重要问题:
- ****转什么:这是整个流程的第一步,也是最重要的一步。为了提高目标任务的绩效,我们试图寻找关于哪部分知识可以从源转移到目标的答案。当试图回答这个问题时,我们试图确定知识的哪一部分是源特定的,以及源和目标之间的共同点。
- ****何时转移:有些情况下,为了转移知识而转移知识可能会比改善任何事情都更糟糕(也称为负迁移)。我们应该致力于利用迁移学习来提高目标任务的绩效/结果,而不是降低它们。我们需要小心什么时候转移,什么时候不转移。
- 如何转移:**一旦回答了什么和何时,我们就可以继续确定跨领域/任务实际转移知识的方法。这涉及到对现有算法和不同技术的更改,我们将在本文后面的部分中讨论。此外,为了更好地理解如何转移,最后列出了具体的案例研究。**
这应该有助于我们定义迁移学习可以应用的各种场景和可能的技术,我们将在下一节讨论。
迁移学习策略
有不同的迁移学习策略和技术,可以根据领域、手头的任务和数据的可用性来应用。我非常喜欢我们之前提到的关于迁移学习的论文中的下图, 迁移学习调查 。
Transfer Learning Strategies
因此,根据上图,迁移学习方法可以根据所涉及的传统 ML 算法的类型进行分类,例如:
- ****归纳迁移学习:在这个场景中,源域和目标域是相同的,但是源任务和目标任务是不同的。这些算法试图利用源域的归纳偏差来帮助改进目标任务。根据源域是否包含标记数据,这可以进一步分为两个子类别,分别类似于多任务学习和自学学习。
- ****无监督迁移学习:这种设置类似于归纳迁移本身,重点是目标领域的无监督任务。源域和目标域相似,但任务不同。在这种情况下,标记的数据在任一域中都不可用。
- ****直推式迁移学习:在这种情景中,源任务和目标任务有相似之处,但对应的域不同。在此设置中,源域有许多标记数据,而目标域没有。这可以进一步分类为子类别,指的是特征空间不同或边际概率不同的设置。
我们可以在下表中总结上述每种技术的不同设置和场景。
Types of Transfer Learning Strategies and their Settings
上一节讨论的三个迁移类别概述了迁移学习可以应用的不同环境,并对其进行了详细研究。要回答在这些类别之间传递什么的问题,可以采用以下一些方法:
- ****实例转移:将知识从源领域重用到目标任务通常是一个理想的场景。在大多数情况下,源域数据不能直接重用。相反,源域中的某些实例可以与目标数据一起重用,以改善结果。在归纳迁移的情况下,如戴和他们的合作者的 AdaBoost 等修改有助于利用来自源域的训练实例来改进目标任务。
- ****特征表示转移:这种方法旨在通过识别可以从源域利用到目标域的良好特征表示,来最小化域差异并降低错误率。根据标注数据的可用性,可对基于要素制图表达的传输应用监督或非监督方法。
- ****参数转移:这种方法基于相关任务的模型共享一些参数或超参数的先验分布的假设。与同时学习源任务和目标任务的多任务学习不同,对于迁移学习,我们可以对目标域的损失应用额外的权重来提高整体表现。
- ****关系型知识转移:与前面三种方法不同,关系型知识转移试图处理非 IID 数据,比如非独立同分布的数据。换句话说,数据,其中每个数据点都与其他数据点有关系;例如,社交网络数据利用关系知识转移技术。
下表清楚地总结了不同迁移学习策略之间的关系以及要迁移什么。
Transfer Learning Strategies and Types of Transferable Components
现在让我们利用这种理解,了解迁移学习如何应用于深度学习的环境中。
面向深度学习的迁移学习
我们在上一节中讨论的策略是可以应用于机器学习技术的一般方法,这使我们产生了一个问题,迁移学习真的可以应用于深度学习的环境中吗?
深度学习模型是又被称为 归纳学习 的代表。归纳学习算法的目标是从一组训练样本中推断出一个映射。例如,在分类的情况下,模型学习输入要素和类标签之间的映射。为了让这样的学习器能够很好地对看不见的数据进行归纳,它的算法使用了一组与训练数据的分布相关的假设。这几组假设被称为 感应偏置 。归纳偏差或假设可以由多个因素来表征,例如它所限制的假设空间和通过假设空间的搜索过程。因此,这些偏差会影响模型在给定任务和领域中学习的方式和内容。
Ideas for deep transfer learning
归纳迁移技术 利用源任务的归纳偏差来辅助目标任务。这可以通过不同的方式来实现,例如通过限制模型空间来调整目标任务的归纳偏差,缩小假设空间,或者在来自源任务的知识的帮助下对搜索过程本身进行调整。下图直观地描述了这一过程。
Inductive transfer (Source: Transfer learning, Lisa Torrey and Jude Shavlik)
除了归纳迁移,归纳学习算法还利用贝叶斯和分层迁移技术来帮助改进学习和目标任务的执行。
深度迁移学习策略
深度学习近年来取得了长足的进步。这使我们能够解决复杂的问题并取得惊人的成果。然而,这种深度学习系统所需的训练时间和数据量要比传统的 ML 系统多得多。有各种各样的深度学习网络,它们具有最先进的性能(有时与人类的性能一样好,甚至更好),已经在计算机视觉和自然语言处理(NLP)等领域进行了开发和测试。在大多数情况下,团队/人员共享这些网络的详细信息,供他人使用。这些预先训练的网络/模型形成了深度学习背景下迁移学习的基础,或者我喜欢称之为 【深度迁移学习】 。让我们看看深度迁移学习的两个最流行的策略。
现成的预训练模型作为特征提取器
深度学习系统和模型是分层的架构,在不同的层学习不同的特征(分层特征的分层表示)。然后,这些层最终连接到最后一层(在监督学习的情况下,通常是完全连接的层),以获得最终输出。这种分层架构允许我们利用预训练的网络(如 Inception V3 或 VGG ),而无需其最终层作为其他任务的固定特征提取器。
Transfer Learning with Pre-trained Deep Learning Models as Feature Extractors
这里的关键思想是仅利用预训练模型的加权层来提取特征,而不是在为新任务训练新数据的过程中更新模型层的权重。
例如,如果我们在没有最终分类层的情况下使用 AlexNet,它将帮助我们根据隐藏状态将新领域任务中的图像转换为 4096 维向量,从而使我们能够利用来自源领域任务的知识从新领域任务中提取特征。这是使用深度神经网络执行迁移学习的最广泛使用的方法之一。
现在可能会出现一个问题,这些预先训练好的现成功能在不同任务中的实际效果如何?
在现实世界的任务中,它看起来确实工作得很好,如果上表中的图表不是很清楚,下面的图应该会使事情更加清楚,关于他们在不同的基于计算机视觉的任务中的表现!
Performance of off-the-shelf pre-trained models vs. specialized task-focused deep learning models
根据上图中的红色和粉红色条,您可以清楚地看到,预训练模型的功能始终优于非常专业的以任务为重点的深度学习模型。
微调现成的预培训模型
这是一个更复杂的技术,我们不仅替换最后一层(用于分类/回归),而且我们还选择性地重新训练一些先前的层。深度神经网络是具有各种超参数的高度可配置的架构。正如前面所讨论的,最初的层被认为是捕捉一般的特征,而后来的层更关注手边的特定任务。下图描述了一个人脸识别问题的例子,网络的初始低层学习非常一般的特征,而高层学习非常特定的任务特征。
利用这种洞察力,我们可以在重新训练时冻结(固定权重)某些层,或者微调其余层以满足我们的需要。在这种情况下,我们利用网络整体架构方面的知识,并使用其状态作为我们再训练步骤的起点。这反过来帮助我们用更少的培训时间获得更好的表现。
冻结还是微调?
这就给我们带来了一个问题,我们应该冻结网络中的图层以将其用作特征提取器,还是也应该在此过程中微调图层?
这应该给我们一个很好的视角,让我们了解这些策略是什么,以及何时应该使用它们!
预训练模型
迁移学习的一个基本要求是要有在源任务中表现良好的模型。幸运的是,深度学习世界相信分享。他们各自的团队已经公开分享了许多最先进的深度学习架构。这些跨越了不同的领域,例如计算机视觉和 NLP,这是深度学习应用中最受欢迎的两个领域。预训练模型通常以模型在被训练到稳定状态时获得的数百万个参数/权重的形式被共享。每个人都可以通过不同的方式使用预先训练好的模型。著名的深度学习 Python 库 keras 提供了下载一些流行模型的接口。你也可以从网上获得预先训练好的模型,因为大多数模型都是开源的。
对于计算机视觉 ,可以利用一些流行的模型包括,
对于自然语言处理 任务,由于 NLP 任务的多变性质,事情变得更加困难。您可以利用单词嵌入模型,包括:
但是等等,还没完呢!最近,在自然语言处理的迁移学习方面有了一些很好的进展。最值得注意的是,
它们肯定很有前途,我相信它们很快会被广泛应用于现实世界。
深度迁移学习的类型
关于迁移学习的文献已经经历了多次反复,正如本章开始时提到的,与迁移学习相关的术语一直被不严格地使用,而且经常互换。因此,有时很难区分迁移学习、领域适应和多任务学习。放心,这些都是有关联的,并试图解决类似的问题。总的来说,你应该总是把迁移学习看作一个一般的概念或原则,在这里我们将尝试使用源任务领域的知识来解决一个目标任务。
领域适应
领域自适应通常指源领域和目标领域之间的边际概率不同的场景,例如*【p(xₛ】≠p(xₜ)*。源域和目标域的数据分布存在固有的偏移或漂移,需要调整以转移学习。例如,标记为正面或负面的电影评论的语料库将不同于产品评论情感的语料库。如果用于对产品评论进行分类,根据电影评论情感训练的分类器将看到不同的分布。因此,在这些场景中,领域适应技术被用于迁移学习。
领域混淆
我们学习了不同的迁移学习策略,甚至讨论了从源到目标迁移知识的内容、时间和方式这三个问题。特别是,我们讨论了特征表征转移是如何有用的。值得重复的是,深度学习网络中的不同层捕获不同的特征集。我们可以利用这个事实来学习领域不变特征,并提高它们跨领域的可移植性。我们不允许模型学习任何表示,而是推动两个领域的表示尽可能地相似。这可以通过将某些预处理步骤直接应用于表示本身来实现。其中一些已经由孙、贾士丰和 Kate Saenko 在他们的论文【】【易域改编的回归】 中讨论过。Ganin 等人也提出了这种对表示相似性的推动。艾尔。在他们的论文中, 【神经网络的领域对抗训练】 。这种技术背后的基本思想是向源模型添加另一个目标,通过混淆领域本身来鼓励相似性,因此产生了领域混淆。**
多任务学习
多任务学习与迁移学习略有不同。在多任务学习的情况下,几个任务被同时学习,而不区分源和目标。在这种情况下,学习者一次接收关于多个任务的信息,与学习者最初不知道目标任务的迁移学习相比。下图对此进行了描述。
Multitask learning: Learner receives information from all tasks simultaneously
一次性学习
深度学习系统天生就需要数据,因此它们需要许多训练样本来学习权重。这是深度神经网络的一个限制因素,尽管人类学习并非如此。例如,一旦给孩子看了苹果的样子,他们可以很容易地识别不同种类的苹果(用一个或几个训练例子);而 ML 和深度学习算法却不是这样。一次性学习是迁移学习的一种变体,我们试图根据一个或几个训练例子来推断所需的输出。这在现实世界中很有帮助,在现实世界中,不可能为每个可能的类都标记数据(如果这是一个分类任务),在现实世界中,可以经常添加新的类。飞飞和他们的合著者的里程碑式的论文 【一次学习的对象类别】 ,被认为是创造了一次学习这个术语和这个子领域的研究。提出了一种基于贝叶斯框架的物体分类表示学习方法。这种方法后来得到了改进,并使用深度学习系统进行了应用。
零射击学习
零射击学习是迁移学习的另一个极端变体,它依赖于没有标记的例子来学习一项任务。这听起来可能难以置信,尤其是当使用例子学习是大多数监督学习算法的内容时。零数据学习或零短期学习方法,在训练阶段本身进行巧妙的调整,以利用额外的信息来理解看不见的数据。在他们关于深度学习的书中,Goodfellow 和他们的合著者将零射击学习呈现为学习三个变量的场景,例如传统的输入变量 x ,传统的输出变量 y ,以及描述任务的附加随机变量 T 。从而训练模型学习 P(y | x,T) 的条件概率分布。零镜头学习在机器翻译等场景中很方便,在这些场景中,我们甚至可能没有目标语言的标签。
迁移学习的应用
深度学习无疑是已经被用来非常成功地收获迁移学习的好处的算法的特定类别之一。以下是几个例子:
- ****NLP 的迁移学习:当涉及到 ML 和深度学习时,文本数据呈现出各种各样的挑战。这些通常使用不同的技术进行转换或矢量化。已经使用不同的训练数据集准备了嵌入,例如 Word2vec 和 FastText。通过转移来自源任务的知识,它们被用在不同的任务中,例如情感分析和文档分类。除此之外,像通用句子编码器和 BERT 这样的新模型无疑为未来提供了无数的可能性。
- ****音频/语音的迁移学习:类似于 NLP 和计算机视觉等领域,深度学习已经成功用于基于音频数据的任务。例如,为英语开发的自动语音识别(ASR)模型已经成功地用于提高其他语言(如德语)的语音识别性能。此外,自动说话人识别是迁移学习有很大帮助的另一个例子。
- ****用于计算机视觉的迁移学习:深度学习已经非常成功地用于各种计算机视觉任务,例如使用不同 CNN 架构的对象识别和标识。在他们的论文中,Yosinski 和他们的合著者(https://arxiv.org/abs/1411.1792)介绍了他们的发现,即较低层如何充当传统的计算机视觉特征提取器,如边缘检测器,而最后几层则致力于特定任务的特征。
因此,这些发现有助于利用现有的最先进的模型,如 VGG,AlexNet 和 Inceptions,来完成目标任务,如风格转换和人脸检测,这些目标任务与这些模型最初训练的目标不同。现在让我们探索一些真实世界的案例研究,并建立一些深度迁移学习模型!
案例研究 1:具有数据可用性约束的图像分类
在这个简单的案例研究中,将研究一个图像分类问题,其约束条件是每个类别的训练样本数量非常少。我们问题的数据集可以在 Kaggle 上获得,并且是最受欢迎的基于计算机视觉的数据集之一。
主要目标
我们将使用的数据集来自非常流行的 狗对猫挑战赛 , ,我们的主要目标是建立一个深度学习模型,可以成功地识别图像并将其分类为或 狗 。
Source: becominghuman.ai
用 ML 来说,这是一个基于图像的二元分类问题。在开始之前,我要感谢 Francois Chollet 不仅创建了令人惊叹的深度学习框架**keras**
,还在他的著作【Python 深度学习】 中谈到了迁移学习在现实世界中有效的问题。我以此为灵感,在本章中描绘了迁移学习的真正力量,所有结果都基于在我自己的基于 GPU 的云设置(AWS p2.x)中构建和运行每个模型
构建数据集
首先,从数据集页面下载**train.zip**
文件,并将其存储在您的本地系统中。下载完成后,将其解压缩到一个文件夹中。这个文件夹将包含 25,000 张狗和猫的图片;也就是说,每个类别有 12,500 个图像。虽然我们可以使用所有 25,000 张图片,并在它们的基础上建立一些不错的模型,但如果你还记得的话,我们的问题目标包括每个类别有少量图片的额外约束。为此,让我们构建自己的数据集。
****import** **glob**
**import** **numpy** **as** **np**
**import** **os**
**import** **shutil****np.random.seed(42)****
现在,让我们加载原始训练数据文件夹中的所有图像,如下所示:
****(12500, 12500)****
我们可以用前面的输出验证每个类别有 12,500 张图片。现在让我们构建更小的数据集,这样我们就有 3,000 张图像用于训练,1,000 张图像用于验证,1,000 张图像用于我们的测试数据集(两种动物类别具有相等的代表性)。
****Cat datasets: (1500,) (500,) (500,)
Dog datasets: (1500,) (500,) (500,)****
现在我们的数据集已经创建好了,让我们将它们分别写到磁盘的不同文件夹中,这样我们就可以在将来的任何时候访问它们,而不用担心它们是否存在于我们的主内存中。
由于这是一个图像分类问题,我们将利用 CNN 模型或 ConvNets 来尝试解决这个问题。我们将从头开始构建简单的 CNN 模型,然后尝试使用正则化和图像增强等技术进行改进。然后,我们将尝试并利用预先训练的模型来释放迁移学习的真正力量!
准备数据集
在我们开始建模之前,让我们加载并准备数据集。首先,我们加载一些基本的依赖项。
****import** **glob**
**import** **numpy** **as** **np**
**import** **matplotlib.pyplot** **as** **plt**
**from** **keras.preprocessing.image** **import** **ImageDataGenerator, load_img, img_to_array, array_to_img****%matplotlib inline****
现在让我们使用下面的代码片段加载数据集。
****Train dataset shape: (3000, 150, 150, 3)
Validation dataset shape: (1000, 150, 150, 3)****
我们可以清楚地看到,我们有 3000 个训练图像和 1000 个验证图像。每幅图像的大小为**150 x 150**
,有三个通道用于红色、绿色和蓝色(RGB ),因此赋予每幅图像**(150, 150, 3)**
的尺寸。我们现在将缩放每张像素值在**(0, 255)**
到**(0, 1)**
之间的图像,因为深度学习模型在小输入值的情况下工作得非常好。
前面的输出显示了我们训练数据集中的一个样本图像。现在让我们设置一些基本的配置参数,并将我们的文本类标签编码成数值(否则,Keras 将抛出一个错误)。
****['cat', 'cat', 'cat', 'cat', 'cat', 'dog', 'dog', 'dog', 'dog', 'dog'] [0 0 0 0 0 1 1 1 1 1]****
我们可以看到,我们的编码方案将数字**0**
分配给**cat**
标签,将**1**
分配给**dog**
标签。我们现在准备建立我们的第一个基于 CNN 的深度学习模型。
从零开始的简单 CNN 模型
我们将首先建立一个具有三个卷积层的基本 CNN 模型,结合最大池技术从我们的图像中自动提取特征,并对输出卷积特征图进行下采样。
A Typical CNN (Source: Wikipedia)
我们假设你对 CNN 有足够的了解,因此不会涉及理论细节。请随意参考我的书或网上任何解释卷积神经网络的资源!现在让我们利用 Keras 来构建我们的 CNN 模型架构。
前面的输出显示了我们的基本 CNN 模型摘要。正如我们之前提到的,我们使用三个卷积层进行特征提取。展平层用于展平第三个卷积层输出的**17 x 17**
特征图的**128**
。这被馈送到我们的密集层,以获得图像应该是一只*【1】*还是一只 猫(0) 的最终预测。所有这些都是模型训练过程的一部分,所以让我们使用下面利用**fit(…)**
函数的代码片段来训练我们的模型。
以下术语对于训练我们的模型非常重要:
**batch_size**
表示每次迭代传递给模型的图像总数。- 每次迭代后,更新层中单元的权重。
- 总迭代次数总是等于训练样本总数除以
**batch_size**
- 一个历元是指完整的数据集已经通过网络一次,即所有的迭代都是基于数据批次完成的。
我们使用 30 的**batch_size**
,我们的训练数据总共有 3000 个样本,这表明每个时期总共有 100 次迭代。我们针对总共 30 个时期训练该模型,并因此在我们的 1,000 幅图像的验证集上验证它。
****Train on 3000 samples, validate on 1000 samples
Epoch 1/30
3000/3000 - 10s - loss: 0.7583 - acc: 0.5627 - val_loss: 0.7182 - val_acc: 0.5520
Epoch 2/30
3000/3000 - 8s - loss: 0.6343 - acc: 0.6533 - val_loss: 0.5891 - val_acc: 0.7190
...
...
Epoch 29/30
3000/3000 - 8s - loss: 0.0314 - acc: 0.9950 - val_loss: 2.7014 - val_acc: 0.7140
Epoch 30/30
3000/3000 - 8s - loss: 0.0147 - acc: 0.9967 - val_loss: 2.4963 - val_acc: 0.7220****
基于训练和验证准确性值,看起来我们的模型有点过度拟合。我们可以使用下面的代码片段来绘制模型的准确性和误差,以获得更好的视角。
Vanilla CNN Model Performance
您可以清楚地看到,经过 2-3 个时期后,模型开始过度拟合训练数据。在我们的验证集中,我们得到的平均准确率大约是 72% ,这是一个不错的开始!我们能改进这个模型吗?
正则化 CNN 模型
让我们改进我们的基本 CNN 模型,增加一个卷积层,另一个密集的隐藏层。除此之外,我们将在每个隐藏的密集层后添加**0.3**
的 dropout 以实现正则化。基本上,退出是深度神经网络中一种强大的正则化方法。它可以分别应用于输入图层和隐藏图层。Dropout 通过将层中一小部分单元的输出设置为零来随机屏蔽这些单元的输出(在我们的示例中,是密集层中 30%的单元)。
****Train on 3000 samples, validate on 1000 samples
Epoch 1/30
3000/3000 - 7s - loss: 0.6945 - acc: 0.5487 - val_loss: 0.7341 - val_acc: 0.5210
Epoch 2/30
3000/3000 - 7s - loss: 0.6601 - acc: 0.6047 - val_loss: 0.6308 - val_acc: 0.6480
...
...
Epoch 29/30
3000/3000 - 7s - loss: 0.0927 - acc: 0.9797 - val_loss: 1.1696 - val_acc: 0.7380
Epoch 30/30
3000/3000 - 7s - loss: 0.0975 - acc: 0.9803 - val_loss: 1.6790 - val_acc: 0.7840****
Vanilla CNN Model with Regularization Performance
您可以从前面的输出中清楚地看到,我们仍然以过度拟合模型而告终,尽管这花费的时间稍长,并且我们还获得了大约 78% 的稍好的验证准确性,这是不错的,但并不惊人。模型过度拟合的原因是因为我们的训练数据少得多,并且模型在每个时期都看到相同的实例。解决这个问题的一种方法是利用图像增强策略,用现有图像的微小变化来增强我们现有的训练数据。我们将在下一节详细介绍这一点。让我们暂时保存这个模型,这样我们可以在以后使用它来评估它在测试数据上的性能。
****model.save(‘cats_dogs_basic_cnn.h5’)****
图像增强的 CNN 模型
让我们通过使用适当的图像增强策略添加更多数据来改进我们的正则化 CNN 模型。由于我们以前的模型每次都是在相同的小样本数据点上训练的,它不能很好地概括,并在几个时期后结束了过度拟合。图像增强背后的思想是,我们遵循一个设定的过程,从我们的训练数据集中获取现有图像,并对它们应用一些图像变换操作,如旋转、剪切、平移、缩放等,以产生现有图像的新的、改变的版本。由于这些随机转换,我们每次得到的图像并不相同,我们将利用 Python 生成器在训练期间将这些新图像输入到我们的模型中。
Keras 框架有一个出色的实用程序**ImageDataGenerator**
,可以帮助我们完成前面的所有操作。让我们为我们的训练和验证数据集初始化两个数据生成器。
在**ImageDataGenerator**
中有很多选项可用,我们只是利用了其中的一些。请随意查看 文档 以获得更详细的观点。在我们的训练数据生成器中,我们接收原始图像,然后对它们执行一些转换来生成新图像。其中包括以下内容。
- 使用
**zoom_range**
参数以**0.3**
的系数随机缩放图像。 - 使用
**rotation_range**
参数将图像随机旋转**50**
度。 - 使用
**width_shift_range**
和**height_shift_range**
参数,按照图像宽度或高度的**0.2**
因子,随机水平或垂直平移图像。 - 使用
**shear_range**
参数随机应用基于剪切的变换。 - 使用
**horizontal_flip**
参数随机水平翻转一半图像。 - 在我们应用任何前面的操作(尤其是旋转或平移)之后,利用
**fill_mode**
参数为图像填充新的像素。在这种情况下,我们只是用最近的周围像素值填充新像素。
让我们看看这些生成的图像可能是什么样子,以便您可以更好地理解它们。我们将从我们的训练数据集中选取两个样本图像来说明这一点。第一个图像是一只猫的图像。
Image Augmentation on a Cat Image
您可以在之前的输出中清楚地看到,我们每次都生成新版本的训练图像(带有平移、旋转和缩放),并且我们还为它分配了一个 cat 标签,以便模型可以从这些图像中提取相关特征,并记住这些是猫。现在让我们看看图像增强是如何在一个样本狗图像上工作的。
Image Augmentation on a Dog Image
这向我们展示了图像增强如何有助于创建新图像,以及如何在这些图像上训练模型来帮助克服过度拟合。请记住,对于我们的验证生成器,我们只需要将验证图像(原始图像)发送给模型进行评估;因此,我们只缩放图像像素(在 0-1 之间),不应用任何变换。我们只对训练图像应用图像增强变换。现在,让我们使用我们创建的图像增强数据生成器来训练一个具有正则化的 CNN 模型。我们将使用与之前相同的模型架构。
我们在这里将默认学习速率降低了 10 倍,以防止模型陷入局部最小值或过度拟合,因为我们将发送大量带有随机变换的图像。为了训练模型,我们现在需要稍微修改我们的方法,因为我们正在使用数据生成器。我们将利用 Keras 的**fit_generator(…)**
函数来训练这个模型。**train_generator**
每次生成 30 幅图像,因此我们将使用**steps_per_epoch**
参数并将其设置为 100,以根据每个时期的训练数据在 3000 幅随机生成的图像上训练模型。我们的**val_generator**
每次生成 20 幅图像,因此我们将**validation_steps**
参数设置为 50,以在所有 1,000 幅验证图像上验证我们的模型准确性(记住,我们不是在扩充我们的验证数据集)。
****Epoch 1/100
100/100 - 12s - loss: 0.6924 - acc: 0.5113 - val_loss: 0.6943 - val_acc: 0.5000
Epoch 2/100
100/100 - 11s - loss: 0.6855 - acc: 0.5490 - val_loss: 0.6711 - val_acc: 0.5780
Epoch 3/100
100/100 - 11s - loss: 0.6691 - acc: 0.5920 - val_loss: 0.6642 - val_acc: 0.5950
...
...
Epoch 99/100
100/100 - 11s - loss: 0.3735 - acc: 0.8367 - val_loss: 0.4425 - val_acc: 0.8340
Epoch 100/100
100/100 - 11s - loss: 0.3733 - acc: 0.8257 - val_loss: 0.4046 - val_acc: 0.8200****
我们得到了大约 82% 的验证准确度,这比我们以前的模型几乎好了4–5%。此外,我们的训练精度与验证精度非常相似,表明我们的模型不再过度拟合。下面描述了每个历元的模型精度和损失。
Vanilla CNN Model with Image Augmentation Performance
虽然在验证准确性和损失方面存在一些尖峰,但总体而言,我们看到它更接近于训练准确性,损失表明我们获得了一个比我们以前的模型概括得更好的模型。让我们现在保存这个模型,这样我们就可以稍后在我们的测试数据集上评估它。
****model.save(‘cats_dogs_cnn_img_aug.h5’)****
我们现在将尝试利用迁移学习的力量,看看我们是否能建立一个更好的模型!
利用预先训练的 CNN 模型进行迁移学习
当构建新模型或重用它们时,预训练模型以以下两种流行的方式使用:
- 使用预先训练的模型作为特征提取器
- 微调预训练模型
我们将在本节中详细讨论这两个问题。我们将在本章中使用的预训练模型是流行的 VGG-16 模型,由牛津大学的 视觉几何小组 创建,该小组专门为大规模视觉识别构建非常深的卷积网络。
像 VGG-16 这样的预训练模型是在具有许多不同图像类别的巨大数据集(ImageNet)上已经预训练的模型。考虑到这一事实,该模型应该已经学习了特征的健壮层次,这些特征相对于由 CNN 模型学习的特征是空间、旋转和平移不变的。因此,该模型已经学习了属于 1,000 个不同类别的超过一百万个图像的特征的良好表示,可以充当适用于计算机视觉问题的新图像的良好特征提取器。这些新图像可能永远不会存在于 ImageNet 数据集中,或者可能属于完全不同的类别,但是模型应该仍然能够从这些图像中提取相关的特征。
这使我们能够利用预先训练的模型作为新图像的有效特征提取器,来解决各种复杂的计算机视觉任务,例如用较少的图像解决我们的猫和狗的分类器,甚至建立狗的品种分类器、面部表情分类器等等!在针对我们的问题释放迁移学习的力量之前,让我们简要讨论一下 VGG-16 模型架构。
了解 VGG-16 模型
VGG-16 模型是建立在 ImageNet 数据库上的 16 层(卷积和全连接)网络,该数据库是为了图像识别和分类的目的而建立的。这个模型是由卡伦·西蒙扬和安德鲁·齐泽曼建立的,并在他们题为‘用于大规模图像识别的超深度卷积网络’的论文中提到。我推荐所有感兴趣的读者去阅读这篇文章中的优秀文献。下图描述了 VGG-16 模型的架构。
VGG-16 Model Architecture
您可以清楚地看到,我们共有使用**3 x 3**
卷积滤镜的**13**
卷积层,以及用于缩减采样的 max pooling 层,并且共有两个完全连接的隐藏层,每个层中有**4096**
个单元,后面是一个密集的**1000**
个单元层,其中每个单元代表 ImageNet 数据库中的一个图像类别。我们不需要最后三层,因为我们将使用我们自己的完全连接的密集层来预测图像是一只狗还是一只猫。我们更关心前五个模块,这样我们可以利用 VGG 模型作为有效的特征提取器。
对于其中一个模型,我们将通过冻结所有五个卷积块来将其用作简单的特征提取器,以确保它们的权重不会在每个时期后更新。对于最后一个模型,我们将对 VGG 模型进行微调,其中我们将解冻最后两个块(块 4 和块 5),以便在我们训练自己的模型时,它们的权重在每个时期(每批数据)得到更新。在下面的框图中,我们展示了前面的架构,以及我们将使用的两种变体(基本特征提取器和微调),这样您可以获得更好的视觉效果。
Block Diagram showing Transfer Learning Strategies on the VGG-16 Model
因此,我们最关心的是利用 VGG-16 模型的卷积块,然后展平最终输出(来自特征图),以便我们可以将它馈送到我们自己的分类器的密集层中。
作为特征提取器的预训练 CNN 模型
让我们利用 Keras,加载 VGG-16 模型,并冻结卷积块,以便我们可以将其用作图像特征提取器。
从前面的输出可以清楚地看到,VGG-16 模型的所有层都被冻结了,这很好,因为我们不希望它们的权重在模型训练期间发生变化。VGG-16 模型中的最后一个激活特征图(来自**block5_pool**
的输出)为我们提供了瓶颈特征,然后可以将其展平并馈入完全连接的深度神经网络分类器。下面的代码片段显示了来自我们训练数据的样本图像的瓶颈特征。
****bottleneck_feature_example = vgg.predict(train_imgs_scaled[0:1])
print(bottleneck_feature_example.shape)
plt.imshow(bottleneck_feature_example[0][:,:,0])****
Sample Bottleneck Features
我们展平 vgg_model 对象中的瓶颈特征,使它们准备好被提供给我们的全连接分类器。在模型训练中节省时间的一种方法是使用该模型,从我们的训练和验证数据集中提取出所有特征,然后将它们作为输入提供给我们的分类器。现在让我们从我们的训练和验证集中提取出瓶颈特性。
****Train Bottleneck Features: (3000, 8192)
Validation Bottleneck Features: (1000, 8192)****
前面的输出告诉我们,我们已经为 3,000 幅训练图像和 1,000 幅验证图像成功提取了维度为**1 x 8192**
的平坦瓶颈特征。现在让我们构建我们的深度神经网络分类器的架构,它将这些特征作为输入。
正如我们之前提到的,大小为 8192 的瓶颈特征向量充当我们的分类模型的输入。在密集层方面,我们使用与之前模型相同的架构。现在来训练这个模型。
****Train on 3000 samples, validate on 1000 samples
Epoch 1/30
3000/3000 - 1s 373us/step - loss: 0.4325 - acc: 0.7897 - val_loss: 0.2958 - val_acc: 0.8730
Epoch 2/30
3000/3000 - 1s 286us/step - loss: 0.2857 - acc: 0.8783 - val_loss: 0.3294 - val_acc: 0.8530
Epoch 3/30
3000/3000 - 1s 289us/step - loss: 0.2353 - acc: 0.9043 - val_loss: 0.2708 - val_acc: 0.8700
...
...
Epoch 29/30
3000/3000 - 1s 287us/step - loss: 0.0121 - acc: 0.9943 - val_loss: 0.7760 - val_acc: 0.8930
Epoch 30/30
3000/3000 - 1s 287us/step - loss: 0.0102 - acc: 0.9987 - val_loss: 0.8344 - val_acc: 0.8720****
Pre-trained CNN (feature extractor) Performance
我们得到了一个验证准确率接近 88%的模型,几乎比我们的基本 CNN 图像增强模型提高了 5-6%,这是非常好的。不过,这个模型似乎有些过度拟合了。在第五个时期之后,模型训练和验证准确性之间存在相当大的差距,这在某种程度上表明模型在那之后对训练数据过度拟合。但总的来说,这似乎是目前为止最好的模式。让我们尝试在这个模型上使用我们的图像增强策略。在此之前,我们使用下面的代码将这个模型保存到磁盘。
****model.save('cats_dogs_tlearn_basic_cnn.h5')****
预训练 CNN 模型作为图像增强的特征提取器
我们将利用以前使用的相同的数据生成器来训练和验证数据集。为了便于理解,构建它们的代码描述如下。
让我们现在建立我们的深度学习模型并训练它。我们不会像上次一样提取瓶颈特性,因为我们将在数据生成器上进行培训;因此,我们将把**vgg_model**
对象作为输入传递给我们自己的模型。我们将学习率稍微降低,因为我们将训练 100 个纪元,并且不希望对我们的模型层进行任何突然的权重调整。请记住,VGG-16 模型的层仍然被冻结在这里,我们仍然使用它作为一个基本的特征提取器而已。
****Epoch 1/100
100/100 - 45s 449ms/step - loss: 0.6511 - acc: 0.6153 - val_loss: 0.5147 - val_acc: 0.7840
Epoch 2/100
100/100 - 41s 414ms/step - loss: 0.5651 - acc: 0.7110 - val_loss: 0.4249 - val_acc: 0.8180
Epoch 3/100
100/100 - 41s 415ms/step - loss: 0.5069 - acc: 0.7527 - val_loss: 0.3790 - val_acc: 0.8260
...
...
Epoch 99/100
100/100 - 42s 417ms/step - loss: 0.2656 - acc: 0.8907 - val_loss: 0.2757 - val_acc: 0.9050
Epoch 100/100
100/100 - 42s 418ms/step - loss: 0.2876 - acc: 0.8833 - val_loss: 0.2665 - val_acc: 0.9000****
Pre-trained CNN (feature extractor) with Image Augmentation Performance
我们可以看到,我们的模型的整体验证精度为 90% ,比我们之前的模型略有提高,而且训练和验证精度也相当接近,表明模型没有过拟合。现在让我们将这个模型保存在磁盘上,以便将来对测试数据进行评估。
****model.save(‘cats_dogs_tlearn_img_aug_cnn.h5’)****
我们现在将微调 VGG-16 模型以构建我们的最后一个分类器,其中我们将解冻块 4 和 5,正如我们在前面的框图中所描述的那样。
带有微调和图像增强的预训练 CNN 模型
我们现在将利用存储在**vgg_model**
变量中的 VGG-16 模型对象,解冻卷积块 4 和 5,同时保持前三个块冻结。下面的代码帮助我们实现了这一点。
从前面的输出中可以清楚地看到,属于块 4 和块 5 的卷积和池层现在是可训练的。这意味着当我们传递每批数据时,这些层的权重也将随着每个历元中的反向传播而更新。我们将使用与先前模型相同的数据生成器和模型架构,并训练我们的模型。我们稍微降低了学习速率,因为我们不想陷入任何局部最小值,我们也不想突然更新可训练的 VGG-16 模型层的权重一个可能对模型产生不利影响的大因子。
****Epoch 1/100
100/100 - 64s 642ms/step - loss: 0.6070 - acc: 0.6547 - val_loss: 0.4029 - val_acc: 0.8250
Epoch 2/100
100/100 - 63s 630ms/step - loss: 0.3976 - acc: 0.8103 - val_loss: 0.2273 - val_acc: 0.9030
Epoch 3/100
100/100 - 63s 631ms/step - loss: 0.3440 - acc: 0.8530 - val_loss: 0.2221 - val_acc: 0.9150
...
...
Epoch 99/100
100/100 - 63s 629ms/step - loss: 0.0243 - acc: 0.9913 - val_loss: 0.2861 - val_acc: 0.9620
Epoch 100/100
100/100 - 63s 629ms/step - loss: 0.0226 - acc: 0.9930 - val_loss: 0.3002 - val_acc: 0.9610****
Pre-trained CNN (fine-tuning) with Image Augmentation Performance
从前面的输出中我们可以看到,我们的模型获得了大约 96% 的验证精度,这比我们之前的模型提高了 6% 。总体而言,该模型在验证准确性方面比我们的第一个基本 CNN 模型提高了 24% 。这真的说明了迁移学习是多么有用。我们可以看到,这里的精度值非常好,尽管模型看起来可能有点过度拟合训练数据,但我们仍然获得了很高的验证精度。现在让我们使用下面的代码将这个模型保存到磁盘上。
****model.save('cats_dogs_tlearn_finetune_img_aug_cnn.h5')****
现在让我们通过在我们的测试数据集上实际评估它们的性能来测试我们所有的模型。
在测试数据上评估我们的深度学习模型
我们现在将评估我们到目前为止构建的五个不同的模型,首先在我们的测试数据集上测试它们,因为仅仅验证是不够的!我们还构建了一个叫做**model_evaluation_utils**
的漂亮的实用模块,我们将使用它来评估我们的深度学习模型的性能。在开始之前,让我们加载必要的依赖项和我们保存的模型。
现在是最后测试的时候了,我们通过在测试数据集上进行预测来测试我们的模型的性能。在我们尝试进行预测之前,让我们先加载并准备我们的测试数据集。
****Test dataset shape: (1000, 150, 150, 3)
['dog', 'dog', 'dog', 'dog', 'dog'] [1, 1, 1, 1, 1]****
现在我们已经准备好了缩放数据集,让我们通过对所有测试图像进行预测来评估每个模型,然后通过检查预测的准确性来评估模型性能。
模型 1:基本 CNN 性能
模型 2:具有图像增强性能的基本 CNN
模型 3:迁移学习——预训练 CNN 作为特征提取器的性能
模型 4:迁移学习——预训练的 CNN 作为具有图像增强性能的特征提取器
模型 5:迁移学习——具有微调和图像增强性能的预训练 CNN
我们可以看到,我们肯定有一些有趣的结果。每个后续模型都比前一个模型表现得更好,这是意料之中的,因为我们对每个新模型都尝试了更先进的技术。
我们最差的模型是我们的基本 CNN 模型,模型精度和 F1 分数约为 78% ,我们最好的模型是我们经过迁移学习和图像增强的微调模型,这使我们的模型精度和 F1 分数为 96% ,考虑到我们是从 3000 个图像训练数据集训练我们的模型,这真是令人惊讶。现在让我们画出最坏和最好模型的 ROC 曲线。
ROC curve of our worst vs. best model
这应该让你很好地了解预训练模型和迁移学习可以产生多大的影响,特别是在处理复杂问题时,我们有像更少的数据这样的限制。我们鼓励您用自己的数据尝试类似的策略!
案例研究 2:具有大量类别和较少数据可用性的多类别细粒度影像分类
现在,在这个案例研究中,让我们升级游戏,让图像分类的任务更加激动人心。在之前的案例研究中,我们构建了一个简单的二进制分类模型(尽管我们使用了一些复杂的技术来解决小数据约束问题!).在这个案例研究中,我们将专注于细粒度图像分类的任务。与通常的图像分类任务不同,细粒度图像分类是指识别更高级别类别中不同子类的任务。
主要目标
为了帮助更好地理解这项任务,我们将围绕 斯坦福狗 数据集进行讨论。顾名思义,这个数据集包含了不同犬种的图像。在这种情况下,任务是识别这些狗的品种。因此,高层次的概念是狗本身,而任务是正确地分类不同的子概念或子类——在这种情况下,是品种。
我们将利用通过 Kaggle 可用这里可用的数据集。我们将只使用训练数据集,因为它已经标记了数据。该数据集包含大约 10,000 张 120 种不同犬种的标记图像。因此,我们的任务是建立一个细粒度的 120 类分类模型,对 120 种不同的犬种进行分类。绝对有挑战性!
加载和浏览数据集
让我们通过加载数据和查看一批图像样本来看看数据集的样子。
Sample dog breed images and labels
从前面的网格中,我们可以看到在分辨率、照明、缩放级别等方面有很多变化,同时图像不仅仅包含一只狗,还包含其他狗和周围的项目。这将是一个挑战!
构建数据集
让我们先看看数据集标签是什么样子的,以便了解我们正在处理什么。
****data_labels = pd.read_csv('labels/labels.csv')
target_labels = data_labels['breed']****print(len(set(target_labels)))
data_labels.head()****------------------
120****
我们接下来要做的是使用下面的代码为磁盘中的每个图像添加精确的图像路径。这将有助于我们在模型训练期间轻松定位和加载图像。
现在是准备我们训练、测试和验证数据集的时候了。我们将利用以下代码来帮助我们构建这些数据集!
****Initial Dataset Size: (10222, 299, 299, 3)****Initial Train and Test Datasets Size: (7155, 299, 299, 3) (3067, 299, 299, 3)****Train and Validation Datasets Size: (6081, 299, 299, 3) (1074, 299, 299, 3)****Train, Test and Validation Datasets Size: (6081, 299, 299, 3) (3067, 299, 299, 3) (1074, 299, 299, 3)****
我们还需要将文本类标签转换为一次性编码标签,否则我们的模型将无法运行。
****((6081, 120), (3067, 120), (1074, 120))****
一切看起来都井然有序。现在,如果您还记得之前的案例研究,图像增强是处理每类数据较少的一种好方法。在这种情况下,我们总共有 10222 个样本和 120 个类。这意味着,平均每堂课只有 85 张图片!我们使用来自**keras.**
的**ImageDataGenerator**
实用程序来完成这项工作
现在我们已经准备好了数据,下一步就是实际构建我们的深度学习模型!
使用 Google 的 Inception V3 模型进行迁移学习
现在我们的数据集已经准备好了,让我们开始建模过程。我们已经知道如何从头开始构建深度卷积网络。我们也了解实现良好性能所需的微调量。在这项任务中,我们将利用迁移学习的概念。预训练模型是开始迁移学习任务所需的基本要素。
在这个案例研究中,我们将集中利用一个预先训练的模型作为特征提取器。我们知道,深度学习模型基本上是神经元互连层的堆叠,最后一层充当分类器。这种架构使深度神经网络能够捕捉网络中不同级别的不同特征。因此,我们可以利用这一特性将它们用作特征提取器。这可以通过移除最后一层或使用倒数第二层的输出来实现。倒数第二层的这个输出然后被馈送到另外一组层中,接着是分类层。我们将使用谷歌的 Inception V3 模型 作为我们的预训练模型。
基于前面的输出,您可以清楚地看到,Inception V3 模型非常庞大,有很多层和参数。让我们现在开始训练我们的模型。我们使用**fit_generator(...)**
方法训练模型,以利用上一步中准备的数据扩充。我们将批量大小设置为**32**
,并训练 15 个时期的模型。
****Epoch 1/15
190/190 - 155s 816ms/step - loss: 4.1095 - acc: 0.2216 - val_loss: 2.6067 - val_acc: 0.5748
Epoch 2/15
190/190 - 159s 836ms/step - loss: 2.1797 - acc: 0.5719 - val_loss: 1.0696 - val_acc: 0.7377
Epoch 3/15
190/190 - 155s 815ms/step - loss: 1.3583 - acc: 0.6814 - val_loss: 0.7742 - val_acc: 0.7888
...
...
Epoch 14/15
190/190 - 156s 823ms/step - loss: 0.6686 - acc: 0.8030 - val_loss: 0.6745 - val_acc: 0.7955
Epoch 15/15
190/190 - 161s 850ms/step - loss: 0.6276 - acc: 0.8194 - val_loss: 0.6579 - val_acc: 0.8144****
Performance of our Inception V3 Model (feature extractor) on the Dog Breed Dataset
该模型在仅仅 15 个时期内在训练集和验证集上实现了超过 80%的准确性,这是值得称赞的性能。右边的图显示了损失下降并收敛到大约**0.5**
的速度。这是一个清晰的例子,说明迁移学习是多么强大而简单。
在测试数据上评估我们的深度学习模型
训练和验证性能相当好,但是在看不见的数据上性能如何呢?因为我们已经将原始数据集分成了三个独立的部分。这里要记住的重要一点是,测试数据集必须经历与训练数据集相似的预处理。考虑到这一点,在将测试数据集输入函数之前,我们也要对其进行缩放。
****Accuracy: 0.864
Precision: 0.8783
Recall: 0.864
F1 Score: 0.8591****
该模型实现了惊人的 86% 准确率以及测试数据集上的 F1 分。考虑到我们刚刚用我们这边最少的输入训练了 15 个纪元,迁移学习帮助我们实现了一个相当不错的分类器。我们还可以使用下面的代码来检查每个类的分类指标。
我们还可以使用下面的代码以一种视觉上吸引人的方式可视化模型预测。
Model predictions on test data for dog breeds!
上图展示了模型性能的直观证明。正如我们所看到的,在大多数情况下,该模型不仅预测正确的狗品种,而且有很高的可信度。
转移学习优势
在前面的章节中,我们已经以这样或那样的方式介绍了迁移学习的一些优点。通常,迁移学习使我们能够建立更强大的模型,这些模型可以执行各种各样的任务。
- 有助于解决具有多种约束的复杂现实问题
- 解决诸如很少或几乎没有标注数据可用性的问题
- 基于领域和任务,将知识从一个模型转移到另一个模型的容易程度
- 提供了一条在未来某一天实现人工智能的道路!
转移学习挑战
迁移学习具有巨大的潜力,是现有学习算法普遍需要的改进。然而,有一些与迁移学习相关的问题需要更多的研究和探索。除了难以回答转移什么、何时转移和如何转移的问题之外,负转移和转移界限也提出了重大挑战。
- ****负迁移:到目前为止,我们讨论的案例都是基于源任务的知识迁移来讨论目标任务的改进。迁移学习有时会导致成绩下降。负迁移是指知识从源到目标的迁移并没有带来任何改善,反而导致目标任务的整体绩效下降。负迁移可能有多种原因,例如源任务与目标任务没有足够的相关性,或者迁移方法不能很好地利用源任务和目标任务之间的关系。避免负迁移非常重要,需要仔细研究。在他们的工作中,Rosenstien 和他们的合作者根据经验展示了当源和目标太不相似时,蛮力转移如何降低目标任务的性能。Bakker 和他们的合著者的贝叶斯方法,以及其他探索基于聚类的解决方案以识别相关性的技术,正在被研究以避免负迁移。
- ****迁移界限:迁移学习中量化迁移也很重要,它影响迁移的质量及其可行性。为了测量迁移的数量,Hassan Mahmud 和他们的合作者使用 Kolmogorov 复杂性来证明某些理论界限,以分析迁移学习和测量任务之间的相关性。伊顿和他们的合著者提出了一种新颖的基于图表的方法来衡量知识转移。对这些技术的详细讨论超出了本文的范围。鼓励读者使用本节中概述的出版物来探索这些主题的更多内容!
结论和未来范围
这可能是我最长的一篇文章了,它全面地介绍了迁移学习的概念、策略、深度迁移学习的重点、挑战和优势。我们还介绍了两个实际案例研究,让您很好地了解如何实现这些技术。如果你正在阅读这一部分,通读这篇相当长的文章值得称赞!
迁移学习肯定会成为机器学习和深度学习在行业主流采用中取得成功的关键驱动因素之一。我绝对希望看到更多的预训练模型和创新的案例研究,它们利用了这一概念和方法。对于我未来的一些文章,你肯定可以期待下面的一些。
- 自然语言处理的迁移学习
- 音频数据的迁移学习
- 面向生成性深度学习的迁移学习
- 更复杂的计算机视觉问题,如图像字幕
让我们期待更多关于迁移学习和深度学习的成功故事,使我们能够建立更多智能系统,让世界变得更美好,并推动我们自己的个人目标!
以上所有内容都以某种形式摘自我最近的一本书,,这本书可以在 Packt 网站以及 Amazon 上找到。****
*** [## 用 Python 实践迁移学习:实现高级深度学习和神经网络模型…
深度学习通过监督、非监督和强化学习简化到下一个级别,使用…
www.amazon.com](https://www.amazon.com/Hands-Transfer-Learning-Python-TensorFlow-ebook/dp/B07CB455BF/ref=zg_bsnr_16977170011_71?_encoding=UTF8&psc=1&refRID=3VS8TYPZGN776BFEZJVG)
没有时间通读这本书或者现在没有时间?别担心,您仍然可以访问我们在 GitHub 库 上实现的所有精彩示例和案例研究!
通过使用 Python 深度学习生态系统转移先前的学习来简化深度学习…
github.com](https://github.com/dipanjanS/hands-on-transfer-learning-with-python)
非常感谢我的合著者Raghav&Tamoghna与我一起为这本书铺平了道路!
感谢 Francois Chollet 和他令人惊叹的书 【用 Python 进行深度学习】 为本文中使用的一些示例提供了很多动机和灵感。
我所见过的关于深度学习的最清晰的解释…阅读是一种享受。
www.manning.com](https://www.manning.com/books/deep-learning-with-python)
有反馈给我吗?或者有兴趣与我一起从事研究、数据科学、人工智能甚至发表一篇关于TDS的文章?可以在LinkedIn上联系我。
[## Dipanjan Sarkar —数据科学家—英特尔公司| LinkedIn
查看 Dipanjan Sarkar 在世界最大的职业社区 LinkedIn 上的个人资料。Dipanjan 有 6 份工作列在…
www.linkedin.com](https://www.linkedin.com/in/dipanzan/)
感谢 Durba 编辑本文。***