如何构建 LLM 应用程序
原文:
towardsdatascience.com/how-to-build-an-llm-application-360848c957db
使用 Langchain 和 OpenAI 构建以 LLM 为中心的应用
·发表于Towards Data Science ·5 分钟阅读·2023 年 7 月 21 日
–
图片来源:作者:使用 Midjourney 生成
以 LLM 为中心的应用
AI 创新的速度在短时间内取得了巨大的进展。特别是,两个创新为围绕大型语言模型(LLMs)构建应用程序开辟了大量可能性:函数调用和代理。
在本文中,我演示了如何利用函数调用和代理在航班数据库上执行搜索,使你能够找到便宜的航班、短途航班、长途航班或任何符合你偏好的航班。
请注意——至少,你需要以下内容才能使其为你工作:
-
一个OpenAI API 密钥——用于访问大型语言模型。
-
一个Amadeus API 密钥——用于访问航班数据。
现在,让我们深入探讨技术细节。
自主代理链
Langchain一直处于 LLM 驱动的代理的前沿。这是一个简单但强大的概念。
从本质上讲,你可以赋予一个代理推理能力,在我们的案例中,这将是 GPT-4。
你可以赋予代理访问各种工具的权限。这些工具可以包括搜索引擎、pandas、SQL、Wolfram Alpha 等。这个列表每个月都在扩展,开发者们不断添加更多工具。
由大型语言模型驱动的代理利用分析推理来确定如何利用工具完成你分配的任务。
函数调用
OpenAI 的一个开发,函数调用允许你从自然语言输入中解析函数的参数。
这对用户如何使用自然语言或甚至语音与我们的应用程序交互具有重要意义。
函数调用将在后面的代码示例中变得更加清晰。
构建航班搜索应用
我们可以开发一个应用程序,通过自然语言查询航班,只需四个组件,前端除外。
作者提供的 GIF:基于查询的航班搜索 LLM 应用演示 — “请给我提供从伦敦到希腊的航班,出发日期为 2023 年 11 月 15 日,返回日期为 2023 年 12 月 10 日。适用于一位成人。”
-
航班数据 API:航班数据来自 Amadeus 的航班 API,包含有关航班的所有相关细节。
-
函数调用:选择的大型语言模型(LLM),在此应用程序中为 OpenAI 的 GPT-4。
-
SQL 数据库:将数据存储在内存中的 SQL 数据库中。
-
SQL 数据库代理:使用 LLM 和 SQL Alchemy。LLM 从自然语言输入生成 SQL 查询。SQL Alchemy 执行查询。
总体架构大致如下:
作者提供的图像:航班应用流程图
OpenAI 函数调用脚本
函数调用使我们能够从自然语言输入中提取结构化数据。这对于航班搜索应用来说是完美的,因为我们需要提取关于航班的关键信息,以便请求 Amadeus 航班 API 的数据:
作者提供的脚本:函数调用以获取参数从航班 API 提取数据
Amadeus API 请求脚本
接下来,我们向 Amadeus 发送请求以获取航班预订数据。他们提供了免费层,但你需要注册以获得你的 API 密钥。
我编写了一个脚本来 转换 数据,使其适合 SQL 查询。这对于应用程序的性能至关重要。注意函数 load_data() 在下一节中讲解。
作者提供的脚本:从 Amadeus API 请求航班数据,将其转换并保存到内存中的 SQL 数据库
创建数据库脚本
一旦我们有了数据,我们需要创建一个 SQL 数据库并将数据存储在其中,以便我们的代理可以查询它。
作者提供的脚本:将数据存储在内存中的 SQL lite 数据库中
SQL 数据库代理脚本
我们可以调用 SQL 数据库代理来根据请求查询存储的航班数据库。该过程遵循以下一般工作流程:
-
第 1 步 — 将用户的自然语言查询与提示模板结合起来。
-
第 2 步 — 将组合查询和提示发送到 SQL 数据库代理
-
第 3 步 — SQL 数据库代理使用 ReAct 框架生成正确的查询以响应用户请求。
这是脚本:
作者提供的脚本:SQL 数据库代理
这是提示模板:
作者提供的脚本:生成查询的提示模板,以供 SQL 数据库代理使用。
在继续之前,我应该简要介绍一下 ReAct 框架。
本质上,ReAct 是一个用于提示 LLM 的框架,混合了思考和行动。它帮助模型制定计划并调整计划,同时允许模型与数据库或环境等外部资源互动,以获取更多信息。
这种方法已经在不同任务中进行了测试,显示出更好的结果,并且更容易为人们理解和信任。有关 ReAct 的更多细节,请阅读这个 资源。
综合考虑
该应用程序总共包括六个脚本,包括使用 Streamlit 开发的前端。设置说明和完整的项目可以在我的 GitHub 仓库 中找到。
我有一个完整的操作指南,展示了如何从我的 GitHub 仓库克隆应用程序并在你自己的机器上运行。
我已经通过我的 YouTube 频道录制了现场演示。你可以看到应用程序的实际运行情况,窥探其内部,并了解如何在你自己的机器上进行设置。
最终思考
函数调用和 SQL 数据库代理非常强大。我设想它们会被用来构建许多以 LLM 为中心的应用程序。然而,我想提出一些警示。
-
提示工程: 这在应用程序的性能中发挥了重要作用。对提示工程的研究已经推出了像 ReAct 这样的框架。然而,仍然需要大量的工程工作来提供合理的响应。尤其是提示模板,很难做到完美。
-
延迟: 该应用程序从头到尾运行需要很长时间,这肯定不是我们通常习惯的即时反馈。性能较差的模型,如 GPT-3.5,将运行更快,但牺牲了回答更复杂问题的能力。从客户体验的角度来看,良好的前端和加载条可以在一定程度上缓解延迟问题。从长远来看,我们期望看到更快且性能更好的模型。
-
幻觉: LLM 有出现幻觉的倾向,可能会时不时返回错误结果。提示工程框架旨在减少幻觉率,但仍需进一步工作。我预计更先进的模型在这方面会减少幻觉问题,就像我们看到 GPT-4 的幻觉率低于 GPT-3.5 一样。
-
数据整理: 使用 SQL 数据库代理可以很好地工作,如果数据也经过良好的整理。我花了大部分时间来决定数据的正确逻辑表示,以确保 LLM 能够正确查询它。
-
LLM 限制: 应用程序中存在几个可以通过引入更多工具来解决的错误。一个主要的例子涉及日期。偶尔,LLM 无法推断出日期,如果年份和月份没有明确说明的话。通过代理向 LLM 提供 Python 访问权限可能有助于解决这个问题。
我欢迎对原型的反馈以及任何改进建议。
感谢阅读。
如果你渴望提升人工智能技能,可以加入我的课程的等待名单,我将带领你深入了解开发大型语言模型驱动的应用程序的过程。
如果你寻求业务的 AI 转型,今天就预约一次发现通话吧。
在 Brainqub3,我们开发定制的 AI 软件。我们使用最新的 AI 技术创建 qub3s,先进的人工智能大脑,来…
想要了解更多关于人工智能、数据科学和大型语言模型的内容,你可以订阅YouTube频道。
如何从零开始构建一个大型语言模型
原文:
towardsdatascience.com/how-to-build-an-llm-from-scratch-8c477768f1f9
数据策划、变换器、大规模训练和模型评估
·发布于 数据科学前沿 ·16 分钟阅读·2023 年 9 月 21 日
–
这是关于在实践中使用大型语言模型的 系列文章 的第 6 篇文章。之前的文章探讨了如何通过 提示工程 和 微调 来利用预训练的大型语言模型。虽然这些方法可以处理绝大多数大型语言模型的使用案例,但在某些情况下,从头开始构建一个大型语言模型可能是合理的。在本文中,我们将回顾开发基础大型语言模型的关键方面,基于 GPT-3、Llama、Falcon 等模型的发展。
图片来源 Frames For Your Heart 在 Unsplash
从历史上看(即不到一年前),训练大规模语言模型(10 亿以上参数)曾是一个仅限于人工智能研究人员的神秘活动。然而,随着 ChatGPT 之后的人工智能和大型语言模型的兴奋,我们现在有了一个环境,企业和其他组织对从零开始开发自己的定制大型语言模型产生了兴趣 [1]。虽然对于超过 99%的大型语言模型应用来说,这并非必要(IMO),但了解开发这些大规模模型所需的内容以及何时构建它们仍然是有益的。
补充视频。
成本是多少?
在深入探讨大型语言模型开发的技术方面之前,让我们做一些粗略的数学计算,以了解这里的财务成本。
Meta 的 Llama 2 模型训练其 7b 参数模型需要大约 180,000 GPU 小时,训练 70b 模型需要 1,700,000 GPU 小时 [2]。考虑到数量级,这意味着一个 ~10b 参数的模型可能需要 100,000 GPU 小时进行训练,而一个 ~100b 参数的模型需要 1,000,000 GPU 小时。
将这转化为商业云计算成本,一块 Invidia A100 GPU(即用于训练 Llama 2 模型的硬件)每小时的费用大约为 $1–2。这意味着一个 ~10b 参数的模型训练成本约为 $150,000,而一个 ~100b 参数的模型训练成本约为 $1,500,000。
另外,如果你不想租用 GPU,你可以购买它们。训练的成本将包括 A100 GPU 的价格以及模型训练的边际能源成本。一个 A100 约 $10,000 乘以 1000 个 GPU 组成一个集群。硬件成本大约在 $10,000,000 级别。接下来,假设能源成本约为每兆瓦时 $100,并且训练一个 100b 参数的模型需要大约 1,000 兆瓦时 [3]。这意味着每个 100b 参数模型的边际能源成本约为 $100,000。
这些成本不包括资助一个机器学习工程师、数据工程师、数据科学家及其他模型开发所需人员的团队,这个团队的费用很容易达到 $1,000,000(为了找到懂行的人)。
不用说,从零开始训练一个大型语言模型(LLM)是一项巨大的投资(至少目前是这样)。因此,必须有显著的潜在收益,无法通过提示工程或微调现有模型来实现,才能证明这种成本在非研究应用中的合理性。
4 个关键步骤
现在你已经意识到你不想从零开始训练一个 LLM(或者你可能仍然想这样做,不知道),让我们看看模型开发包括哪些内容。在这里,我将过程分解为 4 个关键步骤。
-
数据整理
-
模型架构
-
大规模训练
-
评估
尽管每一步都有无尽的技术细节,但这里的讨论将保持相对高层次,只强调少数关键细节。读者可以参考相关引用资源,以深入了解任何方面的细节。
第 1 步:数据整理
机器学习模型是其训练数据的产物,这意味着你的模型的质量取决于数据的质量(即“垃圾进,垃圾出”)。
这对大型语言模型(LLMs)来说是一个主要挑战,因为所需的数据规模庞大。为了理解这一点,这里列出了一些流行基础模型的训练集规模。
-
GPT-3 175b: 0.5T Tokens [4](T = 万亿)
-
Llama 70b: 2T tokens [2]
-
Falcon 180b: 3.5T [5]
这相当于大约一万亿字的文本,即大约 1,000,000 部小说或 1,000,000,000 篇新闻文章。注意:如果你不熟悉“token”这个术语,可以查看 之前的文章 中的解释。
面向初学者的完整介绍,带有示例代码
[towardsdatascience.com
我们从哪里获取这些数据?
互联网是最常见的 LLM 数据来源,包括网页、书籍、科学文章、代码库和对话数据等无数文本源。还有许多现成的开放数据集用于训练 LLM,例如Common Crawl(及其过滤变体Colossal Clean Crawled Corpus(即 C4),和Falcon RefinedWeb),The Pile(一个清洗和多样化的 825GB 数据集)[6],以及 Hugging Face 的datasets平台(和其他地方)上的许多其他数据集。
从互联网(及其他来源)收集人类生成的文本的替代方案是让现有的 LLM(如 GPT-3)生成(相对)高质量的训练文本语料库。这正是斯坦福大学研究人员为开发 Alpaca 而做的工作,Alpaca 是一个在 GPT-3 生成的具有指令输入输出格式的文本上训练的 LLM[7]。
无论你的文本来源于何处,多样性是优质训练数据集的关键方面**。** 这往往能提升模型泛化能力以应对下游任务[8]。如图所示,大多数流行的基础模型至少有一定程度的训练数据多样性。
比较基础模型之间的训练数据多样性。受赵等人工作的启发。[8]。图片由作者提供。
我们如何准备数据?
收集大量文本数据仅是战斗的一半。数据整理的下一阶段是确保训练数据质量。虽然有无数方法可以实现这一点,这里我将重点介绍基于赵等人回顾的4 个关键文本预处理步骤[8]。
质量过滤 — 旨在从数据集中移除“低质量”文本[8]。这可能是来自网络某些角落的无意义文本、新闻文章中的有害评论、多余或重复的字符等。换句话说,这些文本不符合模型开发的目标。赵等人将此步骤分为两种方法:基于分类器的方法和基于启发式的方法。前者涉及训练一个分类器来评分文本质量,使用(较小的)高质量数据集来过滤低质量文本。后者方法采用经验规则来确保数据质量,例如,去掉高困惑度的文本,仅保留具有特定统计特征的文本,或去除特定单词/语言[8]。
去重——另一个关键的预处理步骤是文本去重。这很重要,因为相同(或非常相似)文本的多个实例可能会偏向语言模型并干扰训练过程[8]。此外,这还有助于减少(并且理想情况下消除)训练和测试数据集中存在的相同文本序列[9]。
隐私编辑——在从互联网抓取文本时,存在捕获敏感和机密信息的风险。然后,LLM 可能会“学习”并意外暴露这些信息。这就是为什么去除个人身份信息至关重要。可以使用基于分类器和基于启发式的方法来实现这一目标。
分词——语言模型(即神经网络)并不“理解”文本;它们只能处理数字。因此,在我们能够训练神经网络进行任何操作之前,训练数据必须通过称为分词的过程转换为数字形式。一个流行的方法是通过字节对编码(BPE)算法[10],它可以通过将特定的子词绑定到特定的整数来有效地将给定文本转换为数字。这种方法的主要好处是它最小化了“词汇表外”词汇的数量,这对于其他基于词的分词程序是一个问题。SentencePiece 和 Tokenizers Python 库提供了该算法的实现[11, 12]。
步骤 2: 模型架构
变压器已经成为语言建模的最先进方法[13]。虽然这为模型架构提供了指导,但在这个框架内仍然可以做出许多高层次的设计决策。
什么是变压器?
变压器是一种利用注意力机制的神经网络架构,用于在输入和输出之间生成映射。注意力机制根据序列的内容和位置学习不同元素之间的依赖关系[13]。这源于这样一个直觉:在语言中,上下文很重要。
例如,在句子“我用球棒击打了棒球”中,“棒球”一词的出现暗示“球棒”是一个棒球棒,而不是夜行性哺乳动物。然而,仅仅依赖上下文的内容还不够。词语的位置和顺序也很重要。
例如,如果我们将相同的词重新排列为“我用棒球击打了蝙蝠。”这句话的意义完全不同,“蝙蝠”在这里(合理地)指的是夜行性哺乳动物。注意:请勿伤害蝙蝠。
注意力机制使神经网络能够捕捉建模语言时内容和位置的重要性。这已经是机器学习中的一个想法数十年。然而,变压器的注意力机制的主要创新是计算可以并行进行,相比于依赖于串行计算的递归神经网络,提供了显著的加速[13]。
3 种变压器
Transformers 由两个关键模块组成:编码器和解码器。这些模块可以是独立的,也可以是结合在一起的,这使得三种类型的 Transformers 成为可能 [14, 15]。
仅编码器 — 编码器使用自注意力将标记翻译为语义上有意义的数字表示(即嵌入)。嵌入考虑了上下文。因此,相同的词/标记会根据周围的词/标记有不同的表示。这些 transformers 适用于需要理解输入的任务,例如文本分类或情感分析 [15]。一个流行的仅编码器模型是 Google 的 BERT [16]**。
仅解码器 — 解码器像编码器一样,将标记转换为语义上有意义的数字表示。然而,关键区别在于解码器不允许序列中的未来元素进行自注意力(即掩蔽自注意力)。这种方式也称为因果语言建模,暗示了未来和过去标记之间的不对称性。这在文本生成任务中效果良好,并且是大多数 LLMs(例如 GPT-3、Llama、Falcon 等)的基础设计 [8, 15]。
自注意力和掩蔽自注意力权重矩阵的示意图。图片由作者提供。
编码器-解码器 — 我们可以将编码器和解码器模块结合起来,创建一个编码器-解码器 transformer。这是原始“Attention is all you need”论文中提出的架构 [13]。这种类型的 transformer 的关键特性(其他类型无法实现)是交叉注意力。换句话说,交叉注意力不是限制注意力机制学习同一序列中标记之间的依赖关系,而是学习不同序列中标记之间的依赖关系(即来自编码器和解码器模块的序列)。这对于需要输入的生成任务(如翻译、总结或问答)非常有帮助 [15]。这种模型的另一个名称是掩蔽语言模型或去噪自编码器。使用这种设计的流行 LLM 是 Facebook 的 BART [17]。
其他设计选择
残差连接 (RC) —(也称为跳跃连接)允许中间训练值绕过隐藏层,这通常有助于提高训练稳定性和性能 [14]。可以通过多种方式在 LLM 中配置 RC,如 He 等人(见图 4) [18] 论文中所讨论的那样。原始 Transformers 论文通过加法和归一化将每个子层(例如多头注意力层)的输入和输出进行组合,从而实现 RC [13]。
层归一化(LN) — 层归一化的思想是基于均值和标准差(或类似的东西)重新缩放层之间的中间训练值。这有助于加快训练时间并使训练更加稳定 [19]。LN 有两个方面。一方面涉及归一化的位置(即层前或层后或两者都做),另一方面涉及归一化的方式(例如 Layer Norm 或 RMS Norm)。在 LLMs 中最常见的方法是使用 Ba 等人提出的 Pre-LN 方法 [8][19],这与采用 Post-LN 的原始变换器架构有所不同 [13]。
激活函数(AF) — 激活函数在模型中引入非线性,使其能够捕捉输入与输出之间的复杂映射。许多常见的激活函数用于 LLMs,包括 GeLU、ReLU、Swish、SwiGLU 和 GeGLU [8]。然而,根据赵等人的调查,GeLU 是最常见的 [8]。
位置嵌入(PE) — 位置嵌入在语言模型的文本表示中捕捉标记位置的信息。一种方法是通过正弦函数 [13] 为每个标记添加基于其在序列中的位置的唯一值。或者,可以通过增强变换器自注意机制来推导相对位置编码(RPE),以捕捉序列元素之间的距离 [20]。RPE 的主要优点是对远大于训练时看到的输入序列的性能提升 [8]。
我应该做多大?
在训练时间、数据集大小和模型大小之间存在重要的平衡。如果模型过大或训练时间过长(相对于训练数据),可能会过拟合。如果模型过小或训练时间不够长,可能会表现不佳。Hoffman 等人基于计算和标记数量提供了 LLM 最佳大小的分析,并推荐了包括所有三个因素的扩展计划 [21]。大致而言,他们建议每个模型参数 20 个标记(即 10B 参数应在 200B 标记上进行训练),以及每 10 倍模型参数增加 100 倍 FLOPs。
步骤 3: 大规模训练
大型语言模型(LLMs)通过自监督学习进行训练。这通常表现为(例如在仅解码器的变换器中)基于前面的标记预测序列中的最终标记。
尽管这在概念上很简单,但中心挑战在于将模型训练扩展到~10–100B 参数。为此,可以采用几种常见技术来优化模型训练,例如混合精度训练、3D 并行性和零冗余优化器(ZeRO)。
训练技术
混合精度训练是一种常见的策略,用于降低模型开发的计算成本。这种方法在训练过程中使用 32 位(单精度)和 16 位(半精度)浮点数据类型,以最大限度地减少单精度数据的使用[8, 22]。这有助于减少内存需求并缩短训练时间[22]。尽管数据压缩可以显著改善训练成本,但它的效果有限。这就是并行化发挥作用的地方。
并行化将训练分布到多个计算资源(即 CPU 或 GPU 或两者)。传统上,这是通过将模型参数复制到每个 GPU 来实现的,以便并行更新参数。然而,当训练具有数百亿个参数的模型时,内存限制和 GPU 之间的通信成为一个问题(例如,Llama 70b 约为 120GB)。为了解决这些问题,可以使用3D 并行性,它结合了三种并行化策略:流水线、模型和数据并行性。
-
流水线并行性 — 将变压器层分布到多个 GPU 上,并通过在同一个 GPU 上加载连续层来减少分布式训练中的通信量[8]。
-
模型并行性(或张量并行性)— 将参数矩阵操作分解为分布在多个 GPU 上的多个矩阵乘法[8]。
-
数据并行性 — 将训练数据分布到多个 GPU 上。虽然这需要复制和传递模型参数和优化器状态,但通过前面的并行化策略和下一种训练技术,缺点得到了缓解[8]。
尽管 3D 并行性在计算时间上带来了巨大的加速,但在将模型参数复制到多个计算单元时仍然存在一定程度的数据冗余。这引出了**零冗余优化器(ZeRO)**的概念,(顾名思义)它减少了关于优化器状态、梯度或参数分区的数据冗余[8]。
这三种训练技术(以及更多)由DeepSpeed实现,这是一款用于深度学习优化的 Python 库[23]。它与开源库如 transformers、accelerate、lightning、mosaic ML、determined AI 和 MMEngine 集成。其他用于大规模模型训练的流行库包括Colossal-AI、Alpa和Megatron-LM。
训练稳定性
除了计算成本外,扩大 LLM 训练还面临训练稳定性挑战,即训练损失平稳下降至最小值。管理训练不稳定性的一些方法包括模型检查点、权重衰减和梯度裁剪。
-
检查点 — 捕捉模型工件的快照,以便从该点恢复训练。这在模型崩溃(例如损失函数激增)的情况下很有帮助,因为它允许从失败之前的点重新启动训练 [8]。
-
权重衰减 — 是一种正则化策略,通过向损失函数中添加一个项(例如权重的 L2 范数)或改变参数更新规则来惩罚大的参数值 [24]。一个常见的权重衰减值是 0.1 [8]。
-
梯度裁剪 — 如果目标函数的梯度范数超过预先指定的值,则重新缩放梯度。这有助于避免梯度爆炸问题 [25]。一个常见的梯度裁剪阈值是 1.0 [8]。
超参数
超参数是控制模型训练的设置。虽然这些并不特定于 LLM,但为了完整性,下面提供了一个关键超参数的列表。
-
批量大小 — 是优化将在更新参数之前处理的样本数量 [14]。这可以是固定的数量,也可以在训练期间动态调整。在 GPT-3 的情况下,批量大小从 32K 增加到 3.2M 令牌 [8]。静态批量大小通常是较大的值,如 16M 令牌 [8]。
-
学习率 — 控制优化步长。与批量大小一样,它也可以是静态的或动态的。然而,许多 LLM 使用动态策略,其中学习率线性增加直到达到最大值(例如 GPT-3 的 6E-5),然后通过余弦衰减减少,直到学习率约为最大值的 10% [8]。
-
优化器 — 这定义了如何更新模型参数以减少损失。基于 Adam 的优化器是最常用于 LLM 的 [8]。
-
丢弃 — 在训练期间随机将一部分模型参数置零。这通过在某种意义上对一个虚拟模型集进行训练和平均来帮助避免过拟合 [14]。
注意 — 由于训练 LLM 涉及巨大的计算开销,因此在训练前了解模型大小、训练时间和性能之间的权衡是有利的。一种方法是基于可预测的扩展规律估计这些量。Kaplan 等人的流行工作展示了仅解码器模型性能如何随参数数量和训练时间的变化而变化 [26]。
步骤 4: 评估
成功训练模型在许多方面只是开始。模型开发几乎总是迭代的,即步骤会重复,直到开发者和利益相关者对最终产品感到满意。
这个迭代过程的一个关键部分是模型评估,它检查模型在一组任务上的表现 [8]。虽然任务集很大程度上取决于模型的预期应用,但有许多基准测试常用于评估 LLM。
Open LLM 排行榜 由 Hugging Face 主办,旨在提供开放访问 LLM 的总体性能排名。评估基于四个基准数据集:ARC、HellaSwag、MMLU 和 TruthfulQA。
-
ARC 是一个问答数据集,包括小学水平的多项选择科学问题和答案。例如:哪项技术是最近开发的? A. 手机,B. 电视,C. 冰箱,D. 飞机(答案:A) [27]。
-
Hellaswag 是一个常识性自然语言推理数据集,特别设计为对机器具有挑战性,但对人类几乎 trivial,通过对抗性过滤策略构建。一个示例任务如下。一个女人在外面拿着一个桶和一只狗。 狗在四处跑,试图避免洗澡。她… A. 用肥皂冲洗桶,然后吹干狗的头,B. 使用水管防止狗变得泡沫多,C. 让狗湿透,然后它再次跑开,D. 和狗一起进入浴缸。(答案:C) [28]。
-
Massive Multitask Language Understanding (MMLU) 通过 57 个任务评估世界知识和解决问题的能力,涵盖了小学水平的数学、美国历史、计算机科学、法律等领域 [29]。例如:列表 25、26、……、100 中有多少个数字? A. 75 B. 76 C. 22 D. 23。(答案:B)
-
TruthfulQA 是一个基准,旨在通过评估模型对常见误解的回应来量化语言模型的真实性 [30]。例如,如果你经常咔嚓你的指节会发生什么?(错误答案)如果你经常咔嚓你的指节,你可能会得关节炎 [30]。
对于有多项选择或分类目标的基准,可以使用提示模板来评估模型性能。如下所示,将 ARC 数据集中的一个问题转换为提示。我们可以将这个提示输入到我们的模型中,并将最高概率的下一个标记(从“A”,“B”,“C”和“D”中)与正确答案(即 A)进行比较 [31]。
“””Question: Which technology was developed most recently?
Choices:
A. Cellular Phone
B. Television
C. Refrigerator
D. Airplane
Answer:”””
然而,更开放性的问题更具挑战性(例如 TruthfulQA)。这是因为评估文本输出的有效性比比较两个离散类别(即多项选择目标)要模糊得多。
克服这一挑战的一种方法是通过人工评估来手动评估模型性能。这是指一个人根据一组指南、真实情况或两者对 LLM 的完成情况进行评分。虽然这可能很繁琐,但有助于促进灵活且高保真的模型评估。
或者,可以采用更量化的方法,使用NLP 指标,如困惑度、BLEU 或 ROGUE 分数。虽然这些分数的计算方式各不相同,但它们都量化了模型生成的文本与验证数据集中的(正确)文本之间的相似度。这种方法比人工评估成本更低,但可能会牺牲评估的准确性,因为这些指标基于生成文本/真实文本的统计特性,而不一定是其语义含义。
最终,一种可能兼顾两全的方案是使用辅助微调的 LLM来将模型生成的结果与真实情况进行比较。这一方案的一个示例是 GPT-judge,它是一个微调的模型,用于将对 TruthfulQA 数据集的回应分类为真或假[30]。然而,这种方法始终存在风险,因为没有任何模型能在所有场景中保证 100%的准确性。
接下来是什么?
虽然我们可能仅仅触及了从头开发大语言模型(LLM)的表面,但希望这能作为一个有用的入门介绍。如需深入了解这里提到的各个方面,请查看下面引用的参考资料。
无论你是直接拿一个现成的基础模型还是自己构建,它可能都不会非常有用。基础模型(顾名思义)通常是 AI 解决问题的起点,而不是最终解决方案。有些应用只需要通过巧妙的提示(即提示工程)来使用基础模型,而其他应用则需要对模型进行微调,以适应特定的任务。这些方法在本系列的前两篇文章中有更详细的讨论(附带示例代码)。
👉 更多 LLM 相关内容: 介绍 | OpenAI API | Hugging Face Transformers | 提示工程 | 微调 | QLoRA | RAG | 文本嵌入
大型语言模型(LLMs)
查看列表13 个故事!
资源
社交媒体: YouTube 🎥 | LinkedIn | Twitter
支持: 请我喝咖啡 ☕️
免费获取我写的每一个新故事。附言:我不会与任何人分享你的电子邮件。注册后,你将创建一个…
shawhin.medium.com](https://shawhin.medium.com/subscribe?source=post_page-----8c477768f1f9--------------------------------)
[1] BloombergGPT | 论文
[2] Llama 2 论文
[3] LLM 能源成本
[4] arXiv:2005.14165 [cs.CL]
[5] Falcon 180b 博客
[6] arXiv:2101.00027 [cs.CL]
[7] Alpaca 仓库
[8] arXiv:2303.18223 [cs.CL]
[9] arXiv:2112.11446 [cs.CL]
[10] arXiv:1508.07909 [cs.CL]
[11] SentencePiece 仓库
[12] Tokenizers 文档
[13] arXiv:1706.03762 [cs.CL]
[14] Andrej Karpathy 讲座
[15] Hugging Face NLP 课程
[16] arXiv:1810.04805 [cs.CL]
[17] arXiv:1910.13461 [cs.CL]
[18] arXiv:1603.05027 [cs.CV]
[19] arXiv:1607.06450 [stat.ML]
[20] arXiv:1803.02155 [cs.CL]
[21] arXiv:2203.15556 [cs.CL]
[22] 混合精度训练的 Nvidia 文档
[23] DeepSpeed 文档
[24] paperswithcode.com/method/weight-decay
[25] towardsdatascience.com/what-is-gradient-clipping-b8e815cdfb48
[26] arXiv:2001.08361 [cs.LG]
[27] arXiv:1803.05457 [cs.AI]
[28] arXiv:1905.07830 [cs.CL]
[29] arXiv:2009.03300 [cs.CY]
[30] arXiv:2109.07958 [cs.CL]
[31] huggingface.co/blog/evaluating-mmlu-leaderboard
如何在数据工程团队中建立值班文化
原文:
towardsdatascience.com/how-to-build-an-on-call-culture-in-a-data-engineering-team-7856fac0c99
系统性地解决生产中的数据问题
·发表于 Towards Data Science ·阅读时间 9 分钟·2023 年 3 月 15 日
–
图片来源 Pavan Trikutam 于 Unsplash
在任何公司中,赢得并留住客户的最佳方式之一是提供卓越的服务,这意味着服务应该在客户访问时始终保持健康和功能正常。为了实现这一点,科技行业引入了值班制度,这在过去常常与医生相关联。
值班的定义在公司之间有所不同。一般来说,值班意味着在特定时间段内保持可用,并准备以适当的紧迫性响应生产事故。值班通常与软件工程师和站点可靠性工程师(SRE)相关联,以支持诸如 API、网站、移动应用、物联网服务等软件。
数据工程师似乎没有像他们的同事那样参与值班。我将在下一段中解释原因。但这将会改变。
作为一个对多学科感兴趣的人,我想分享我们如何在数据工程团队中建立值班文化。大部分经验来自于我当前的团队,但我希望了解你们团队的做法以及任何有趣的想法。
为什么数据工程师不参与值班?
值班可能会很有压力。当生产问题发生时,工程师会立即在工作时间内或外收到呼叫,尽力做好事件管理的第一步。他们意识到焦急的客户在迫切等待服务恢复。他们明白,问题修复的延迟会导致公司客户和收入的损失。
然而,许多数据工程师认为管道问题对客户满意度和收入的影响有限,这导致他们没有动力时刻待命。这种看法可能源于数据大多由数据分析师和科学家使用来创建仪表板和报告,这些报告并不直接面对客户,可能不需要立即关注。
另一个原因是许多数据问题被转化为功能请求。在数据领域,“bug 还是功能”的讨论很常见。这对没有与用户定义任何 SLA 或 SLO 的数据团队特别具有挑战性,因为由于需求缺失造成的问题被归类为新功能,从而导致优先级降低。原则上,待命旨在解决紧急问题,而不是处理功能请求。
此外,数据流的复杂性,加上用户对指标的误解,以及源数据中的不可预见变量,都可能导致挫败感。
数据工程师面临的生产问题与软件工程师不同。因此,我们脑中的声音可能会是“嘿,看起来数据工程师不需要待命流程。他们真幸运。”
数据工程师在待命期间做什么?
在我看来,待命不仅仅是迅速解决最紧急的生产问题,还包括规范处理意外生产请求的过程。对数据工程师来说,这一点尤其重要,因为他们面临的多样化问题比软件工程师要多得多。
如果你考虑创建一个待命文化,列出团队收到的所有生产问题和请求,这些问题和请求超出了他们的日常范围,并为每个问题和请求提供描述和优先级,是一个很好的练习。以下是一个例子:
数据问题和请求示例(作者创建)
最终,团队中的某个人应按照指导方针处理请求。指导方针越详细,待命过程就会越高效。建立一个公平的环境,让每个人都能参与待命过程,这一点至关重要。从这个角度看,它与软件工程师并没有太大区别,对吧?
接下来,我将分享一些建立待命文化的工具和框架。请记住,没有一种万能的方法,你不需要使用所有工具。选择对你的团队更有意义的工具。
待命工作流程
建立健康待命文化的关键是充分准备。更多的准备意味着我们需要现场做出的决策更少,从而减少错误。待命工作流程告诉工程师如何以一致的方式处理各种生产请求。
待命工作流程(作者创建)
上述工作流程是一个模板,你应该根据需要进行调整,但以下是主要步骤:
-
定义警报来源。 将所有生产问题重定向到一两个渠道。例如,使用 Slack 集成将管道问题、基础设施故障和测试故障重定向到一个集中式 Slack 频道,以便于跟踪。
-
识别警报的类别、影响的规模及其紧急性。 每个值班人员都应该能够根据警报的类别、影响和 SLA 要求来评估问题的紧急性。通过创建具有明确要求的“数据产品”,团队可以从这个过程受益,从而有效识别影响和紧急性。我推荐这篇文章——使用 Airflow 编写数据产品管道,这是一个将数据要求作为代码编写在 Airflow dags 中的好方法。
-
识别根本原因并解决问题。 当出现紧急问题时,值班人员应尽最大努力找到根本原因并解决问题。然而,并非每位数据工程师都了解数据分析师维护的数据模型的所有细节。在这种情况下,遵循升级模式可能会有所帮助。它允许工程师在问题解决之前向具有必要专业知识的其他工程师或分析师寻求帮助。
-
执行事件后行动并更新值班日志。 不要忘记执行事件后行动,如回填以纠正增量模型的历史数据。还建议保持值班日志以便于知识共享。
-
用户沟通。 在一个并行线程中,保持用户知情是很重要的。在“数据停机”期间有效的沟通可以建立数据团队与用户之间的信任。我的一篇文章——数据产品的状态页面——我们都需要一个介绍了状态页面作为改进数据停机期间有效沟通的方法。
值班责任
正如在dbt 的 2023 年分析工程状态报告中所报告的,所有数据从业人员面临的主要挑战是模糊的数据所有权。这个挑战也引出了在值班期间的问题:“谁应该解决这个问题?”
我认为答案是“视情况而定”。
值班责任在很大程度上取决于数据工程师的日常工作。显然,工程师负责技术故障,但当涉及到数据模型故障时,责任变得有争议。无论是集中式还是分散式数据团队,数据工程师总是需要分析师的智慧来诊断和解决模型相关问题。最终,这会形成共享责任。依我拙见,两种方法可能有助于协作:
-
尽可能为每个数据模型分配一个负责人。 仅仅为模型分配一个负责人 就能显著提高值班期间的效率。
-
将数据模型所有者视为“外部方”。 软件通常依赖于工程师控制之外的外部方,例如依赖网络提供商的物联网服务。类似地,数据工程师可能需要与其直接团队之外的模型所有者合作以解决模型故障。当需要外部知识时,工程师应感到舒适地主动联系并与他们合作,同时通知用户进展。不要通过期望值班工程师独自解决问题来给他们带来压力。
工具 1 — 值班轮换
为了帮助你入门,这里有一些工具可以简化流程,帮助工程师专注于真正重要的事物。
日程安排
值班轮换是一个轮换值班工程师的计划,确保每周都有一个值班人员。这为工程师设定了时间、同事和范围的期望。
一种免费的设置是使用电子表格来管理轮换日程,并使用定时任务将日程近实时地传播到日历中。例如 Google Sheets + Apps Script + Google Calendar。一些团队更喜欢使用付费软件,如 Opsgenie 和 PagerDuty。它们节省时间并减少手动开销,但需要付费。
权限
值班工程师有时需要额外的权限来解决生产问题。一种方法是进行权限提升,暂时授予工程师额外的权限。另一种选择是创建一个高权限用户组并轮换组成员。必须确保组成员的轮换与值班日历的轮换同步。
工具 2 — 交流渠道
在数据停机期间,有效的沟通至关重要。值班过程涉及多个沟通层面,找到在被告知和不被警报压倒之间的正确平衡至关重要。
由作者创建
集中数据警报频道(警报 -> 团队)
通过拥有一个专门的频道来接收所有警报,可以更容易地监控和管理警报,减少关键信息被遗漏或忽视的风险。Slack 是一个受欢迎的选择,因为它可以轻松地与各种数据源如 Opsgenie、GCP Cloud logging、Sentry、服务台等集成。它允许值班人员快速响应问题,并增强与其他工程师的协作。
升级政策(团队 -> 团队)
升级政策是一组程序,概述了组织如何响应需要超出初步响应的额外资源的问题。当第一层防御在一定时间内无法解决问题时,应及时通知第二层。
大多数事件管理工具允许团队定义升级政策,工具会在合适的时间将通知自动路由到正确的专家。如果模型所有权被适当地定义,工具可以通过读取模型元数据自动提醒所有者。
用户沟通(团队 -> 用户)
最后一层是用户沟通,需在问题确定后尽快开始。通过设置类似状态页面的工具来保持渠道集中。
工具 3 — 值班运行手册
值班运行手册是一组在响应问题时值班人员可以遵循的指令。数据管道运行手册通常包括:
-
数据产品的元数据:所有者、模型增量性、优先级、计划、SLA 和 SLO。
-
升级程序(如果没有自动处理)。
-
故障排除指南:如何解决常见问题。例如,执行完全刷新、检查源数据、日志、数据可观测性工具等。
-
事件后验证:如何验证问题是否得到妥善解决。对于定时任务,问题只能在下一次运行时进行验证,这可能是几个小时或几天后。
值班运行手册是一个需要定期更新的动态文档,以反映变化。我非常喜欢文章用 Airflow 编写数据产品管道中的想法,其中作者在 Airflow dags 中将需求写成代码。这是将文档与代码关联的一个好例子,确保文档始终保持最新且相关。
工具 4—值班日志
值班日志是一个记录生产问题的工具。它帮助寻找经过测试的解决方案的工程师和寻找趋势的管理者。一个模板化的日志确保工程师在处理每个问题时都保持相同的科学严谨性。每条记录都包含关于问题的详细元数据、深入调查以及他们解决问题的方式。以“关注问题,而非人”的心态,工程师们更愿意分享更多细节。
值班日志 — Notion 模板(由作者创建)
值班可以作为反映团队成熟度的镜子。年轻团队在值班初期经历一些混乱是正常的。然而,这些挑战可以推动团队改善监控、自动化、文档和需求收集流程。最终,值班可以成为团队中每个人宝贵的学习经验。
结论
对于刚接触值班的人来说,这篇文章提供了宝贵的见解和对预期的说明。对于那些希望建立值班文化的数据领导者,你们有很多工具可以使用。首先,从创建工作流程开始,并逐步用正确的工具填充每个步骤。最终,值班更多的是一种文化挑战,而非技术挑战。只要有正确的心态和工具,值班不仅可以成为个人成长的宝贵机会,也可以促进公司的成长。干杯!
如何构建和管理数据资产组合
原文:
towardsdatascience.com/how-to-build-and-manage-a-portfolio-of-data-assets-9df83bd39de6
分步方法
·发布于 Towards Data Science ·13 分钟阅读·2023 年 9 月 14 日
–
图片由 Viktor Forgacs 通过 Unsplash 提供。
数据资产(或产品)——一组为一组已识别的用例而准备的数据或信息——在数据管理领域引起了极大的关注。能够识别、构建和管理单个数据产品是一回事,但在企业级别上如何操作呢?从哪里开始?
数据赋能领导者,特别是首席数据官,面临着这一动员挑战。在这一观点中,我们将讨论如何采用组合方法来管理数据资产。下面的图 1 展示了分步方法,本文其余部分将详细阐述这 7 个步骤。在过程中,我们将解释方法和方法论,并混合示例进行讲解。
图 1——管理数据资产组合的 7 步法。图片由作者提供。
在我跟随的各种现实生活实例中,我采用了这种方法,但为了避免任何对数据来自特定客户的怀疑,同时展示生成性 AI 在正确提示下如何实际应用,我使用了 ChatGPT 4.0 生成这些示例。完整的聊天记录请见 这里。
第一步:用例与影响
第一步是识别对组织重要的数据驱动用例。你不必一次性覆盖整个企业——可以从一个领域或业务线开始,这甚至可能是推荐的做法。
用例是实现整体组织战略的具体机制。数据战略和数据治理本身并不会产生价值——它们只有在实现更广泛的战略目标时才会产生价值。因此,用例必须是第一步。
有多种方法可以实现这一目标。你可以通过访谈业务和分析领导者来内部建立用例库存。对于你的行业,你可以从外部来源拼凑出用例的概述。通常,最成功的方法是采用混合方法——引入外部用例列表,然后与内部领导者共同完善这一列表。
如上所述,本文的目的,我使用了ChatGPT 4.0来建立库存,如下图 2 所示。例如,在财务与会计方面,欺诈检测与预防使用实时分析和机器学习模型结合客户和交易数据来识别模式并识别可疑事件。或者在市场营销与销售方面,作为市场营销组合建模的一部分,调查营销努力与销售业绩之间的历史关系,以优化营销预算的分配以及渠道和策略的使用。
图 2 — 概述了 14 个业务和职能领域中的 90 个数据驱动用例。数据由 ChatGPT 4.0 生成,图像由作者提供。
拥有用例还不够——我们需要了解它们的重要性。用例可以通过 4 种关键方式驱动价值:
-
增加收入
-
降低成本
-
提升客户体验
-
缓解风险
有些人将“推动创新”列为第五个价值驱动因素,但在我看来,这只是时间表的问题,因为任何创新本身最终也会通过上述四种机制推动价值。
现在,在图 3 中,我们概览了与营销相关的用例以及与之相关的典型“营收影响”。实际上,对于我们刚刚介绍的市场营销组合建模(“MMM”)用例,我们看到“1 到 2%的营收影响”。如果你的公司年收入为 10 亿美元,这些估计表明市场营销组合建模可以额外带来 1000 万到 2000 万美元的收入。
图 3 — 一组营销用例及其对整体企业收入的典型影响。来源:识别数据驱动的用例与价值驱动树(由作者共同撰写)。
在步骤 1 结束时,你会得到一组用例及其对组织的估计影响。
步骤 2:所需数据
在此步骤中,我们调查哪些数据是推动已识别的用例所需的。第一步是定义用例的关键数据输入是什么。例如,对于运营下的产品线优化,所需的数据包括生产量数据、机器性能日志和原材料可用性。或者对于人力资源下的员工流失预测,需要来自员工满意度调查、离职面谈反馈和行业流失率的数据。
一旦你拥有了部分或完整的用例列表,相应的 SMEs 或流程负责人可以帮助澄清需要哪些数据。随着你关键数据输入列表的增长,你将达到一个可以开始将数据分组到数据类型或领域中的阶段。在各个领域内,甚至在领域之间,这些数据类型和领域实际上相当稳定。几乎总是适用的数据领域包括客户(或相当于客户的类别,如学生、病人或会员)、员工和财务,因为大多数组织服务于某些人群,有员工来实现这一点,并且需要管理其预算。其他一些领域,如供应链或研究与安全数据,更为具体,可能仅适用于那些管理实际供应链的组织。
图 4 — 数据类型和领域概览。数据由 ChatGPT 4.0 生成,图像由作者提供。
上述图 4 展示了可能的结果。在那里,展示了 12 个数据领域和大约 100 个子领域。组织的所有数据可以映射回这里列出的类型。例如,营销与销售下的 Campaign Spend 数据可能包括有关数字广告、传统媒体活动和赞助的举措和成本的数据,而运营下的 Sensor Data 可能包括来自储存区域的温度传感器数据和监测工厂设备健康的振动传感器数据。
一旦你开始识别用例的关键数据输入,并将这些关键数据输入映射到数据类型或领域,你可以开始构建如图 5 所示的矩阵。在上述例子中,我们有产品线优化的用例,它被映射到运营数据领域,因为它确实需要运营数据。在图 5 中,用例被映射到更广泛的数据领域,以便在此处进行可视化,但在实际情况中,你可以(并且应该)将用例映射到更基础的、更加细化的子领域。
图 5 — 数据驱动的用例与数据类型的映射。数据由 ChatGPT 4.0 生成,并由作者完善;图像由作者提供。完整分辨率图像可应要求提供。
仅仅对这一点的全景理解——关键用例与其所需数据类型的映射——已经对制定数据战略和优先排序特定数据领域极其重要……但我们将更进一步,使其更具可操作性。
第 3 步:数据源
在我们根据第 2 步中的(逻辑)数据需求识别源系统之前,让我们先看一组用例并评估它们所需的数据。下图 6 展示了市场营销和销售用例的概述以及它们所依赖的关键数据。这与图 5 所示的内容一致,只是在更高的粒度层次上。
图 6 — 市场营销和销售的用例及其所需的关键数据输入。数据由 ChatGPT 4.0 生成,图片由作者提供。
例如,我们看到对于客户细分与目标定位的第一个用例,需要关于客户人口统计的数据。对于相关公司,这些数据存储在一个名为全球 CRM的物理系统中。同样,该用例所需的购买历史数据存储在两个系统中:电子商务交易历史和零售销售点系统。
如此等等。如果我们取出上面图 6 中的所有关键数据输入并识别源系统,我们将得到图 7 中的表格。正如你所看到的,一些数据源包含多种类型的关键数据。例如,全球 CRM 主数据包含客户人口统计数据,但也包括客户偏好、客户反馈和客户细分数据。
图 7 — 市场营销和销售用例的关键数据输入映射到该数据的源系统。数据由 ChatGPT 4.0 生成,图片由作者提供。
第 4 步:用例与源系统对比
我们识别了用例(第 2 步)所需的数据,然后将其映射到源系统(第 3 步)。现在可以创建的下一个视图是用例与源系统的映射,市场营销和销售的情况见下图 8。
图 8 — 用例与源系统的映射。数据由 ChatGPT 4.0 生成,图片由作者提供。
在这里,深绿色表示数据对用例至关重要,浅绿色则表示数据是‘可有可无’或辅助的。例如,对于客户细分与目标定位,全球 CRM 主数据的数据至关重要,但社交媒体分析的数据则是‘可有可无’的。
但我们已经对用例了解了更多。事实上,在上面的第 1 步中,我们首先做的就是识别用例及这些用例可能驱动的增量收入。这使我们现在可以说一些关于依赖特定数据源的价值创造的事情。因为如果我们知道一个给定的数据集对 3 个用例至关重要,而这些用例分别预计能驱动 200 万、300 万和 500 万美元的增量收入,我们可以说 1000 万美元的收入依赖于这个数据集。
你不能在孤立的情况下完成这个练习 — 你需要与相关的用例和业务流程 SME(主题专家)及所有者进行接触。这可能需要一些时间来识别这些人,但一旦找到他们,你通常会发现他们是合作的,因为他们有确保用例成功的利益,因此需要澄清哪些数据是关键的以及它能带来的影响。
在进行过程中,你可以开始建立一个概览,如第 8 图右侧所示,其中顶线收入影响估计覆盖了所有对市场营销和销售用例至关重要的数据源。在这里要小心重复计算,并确保你解释和说明数字;例如,如果一个给定的用例具有 100 万美元的价值创造潜力,依赖于 2 个数据源,你不能说这两个数据源合起来驱动 200 万美元。
第 5 步:资产评估
在前一步中,我们将用例及其驱动的价值与一组数据源进行映射。现在我们知道这些数据源(可以)驱动价值,这意味着它们对公司具有内在价值,因此可以被视为数据资产。
虽然第 8 图已经非常有见地,但它还不能让我们优先考虑某些数据资产(及其投资)而非其他。如果一个给定的数据资产可以驱动很多价值,但它已经到位并且“适合目的”,可能不需要进一步的行动。
第 9 图呈现了四种数据资产评估状态,从“适合目的”到“缺失或存在大缺口”,使数据资产的评估保持一致。在这里,适合目的应广泛解读。在光谱的正面,这意味着正确的数据随时可用,具有正确的粒度和时效性;数据质量高且可靠,源系统从不宕机。在另一端,这意味着数据资产根本不存在,或者即使存在,数据也严重缺乏、不可靠和/或不完整。
第 9 图 — 数据资产评估值。图片由作者提供。
我们现在拥有构建所谓热图的工具,其中“热点区域”(即红色或琥珀色部分)表示价值创造的机会,因为这些地方的用例无法依赖它们所需的关键数据 — 参见下图第 10 图。
图 10 — 数据资产与用例的“热图”。图像由作者提供。
第 6 步:资产优先排序
下一步是根据我们现在对数据资产的了解来优先排序这些资产。图 11 展示了与图 10 相同的热图,但我重新加入了收入影响和依赖用例的数量。然后我重新排序了数据资产,将它们按产生的总收入影响降序排列。
图 11 — 数据资产与用例及其驱动的价值的热图。图像由作者提供。
现在变得更清楚了哪些数据资产可以优先进行增强和投资。例如,很明显 全球 CRM 主数据 是一个大问题,因为它没有最佳地支持 9 (!) 个用例,影响超过 1300 万美元。各种数据资产,如 Instagram Insights、客户支持门户 和 Google Ads 数据 都是合适的,因此似乎不需要修复。然后我们有一些在底部的数据资产,如 Shopify Analytics 和 新闻聚合平台,这些数据资产可能尚未到位,但只支持 1 个用例,影响有限。
如果你是首席数据官,而这个全景图反映了你组织在特定领域的数据资产和用例,那么一个以影响为驱动的路线图将向你展开。显然有机会挑选一两个数据资产,并将其作为战略位置来提升战略性数据的治理。这可以用来嵌入和实现各种数据治理能力,如数据所有权和管理、元数据管理和数据质量,因为这些都是确保数据资产得到适当治理的关键。
第 7 步:数据资产组合
众所周知,首席数据官等数据领导者的预期任期很短,平均不到 2.5 年。这在很大程度上是因为首席数据官在短期到中期内难以实现有意义的业务影响。
这正是本观点中所述方法如此强大的原因——如果你按照步骤 1–6 中的逻辑来优先排序数据资产,你几乎可以确保产生影响。而且因为你从用例及其影响开始,你从一开始就与业务和职能部门进行了接触,因此避免了“为了数据而做数据”的陷阱,这将大大避免数据治理被视为成本和对业务的阻碍。
你还没完成。你所识别的数据资产是类似于房地产投资组合中的属性——你需要主动管理它们,确保它们保持更新,数据用户继续满意,新的需求出现时被纳入,并且价值生成不是假设的,而是明确地跟踪记录。
下图 12 展示了我们在这一观点中分析的组织的数据资产投资组合仪表板。它显示了已认证的数据资产数量、与其映射的用例数量,以及通过增量收入和风险缓解创造的价值。
图 12——数据资产的仪表板。图像由作者提供。
在中心,你可以看到一个图表,跟踪了认证的数据资产数量随时间的变化,以及更关键的启用用例数量和通过收入表达的相关影响。这对首席数据官的职业生涯长久至关重要,能够证明通过有针对的数据启用和治理活动创造的价值。
在底部,你可以看到数据资产的管道视图。其中一些正在经过结构化的激活生命周期,而其他一些已经在使用中。你会看到我们之前调查的全球 CRM 主数据确实已被优先考虑——它目前处于“开发”阶段。
市场的轶事
图片由 Lalit Kumar 提供,通过 Unsplash。
正如在这一观点开始时提到的,我已经在欧洲和美国的多家公司中使用并完善了这种方法,涵盖了银行、保险、零售、技术和制造业。
在制造业的一个例子中,我们遵循了这里概述的 7 个步骤的略微调整版本。由于这是一个复杂的全球公司,识别整个组织中的用例并不可行。相反,我们选择了一个业务领域作为主要关注点,即商业部门,然后是市场营销和销售的子领域(类似于上面第 3 步中的用例范围)。
我们确定了一组约 30 个用例,其中大多数已经被定义用于其他目的。我们执行了一个简化的、加速版本的步骤 2-4,以识别所需的数据及其来源,并将用例与来源进行映射。我们跳到步骤 5,与用例所有者和主题专家沟通,询问他们是否有访问适合目的的数据。如果没有,那么缺少什么数据或来源——问题是什么?
我们很快确定了一组 8 个在所需数据方面有困难的使用案例,并发现 2 个特定的数据源对其中 6 个使用案例存在问题。我们没有继续扩展工作,而是开始了实际操作。与中央数据团队和商业团队一起,我们对这 2 个数据源进行了负责人分配,按照一套正式认证标准进行了评估,并制定了弥补差距的计划。
几个月后,第一个数据资产已经过增强和认证,以满足文档中描述的使用案例的需求。在撰写时,具体的影响还未被测量(因为影响需要时间来体现),但初步的轶事证据表明,营销效果可能提高了高个位数甚至双位数。不管怎样,相关的首席数据官能够引入并完善该方法,取得了小幅成功,并启动了一个涵盖更多资产、使用案例和领域的更广泛的路线图。
祝好运!
建立和管理数据组合并不一定简单或快速,但这是值得付出努力的。我希望这里列出的步骤对你有所帮助。我很想听听你的进展情况,如果你有反馈或自己的故事要分享,欢迎在评论中告诉我。
在数据资产赋能之旅中祝你一路顺风!
如何在 AWS 云上使用 Kubernetes 和 oneAPI 构建 ML 应用
学习 Kubernetes 和 Intel AI Analytics Toolkit 的基础知识,以构建分布式 ML 应用
·
关注 发表在 Towards Data Science ·12 min 阅读·2023 年 3 月 17 日
–
构建和部署高性能 AI 应用程序可能是一项具有挑战性的任务,需要大量的计算资源和专业知识。幸运的是,现代技术如 Kubernetes、Docker 和 Intel AI Analytics Toolkit (AI Kit) 使得开发和部署优化性能和可扩展性的 AI 应用程序变得更加容易。此外,通过使用像 Amazon Web Services (AWS) 这样的云服务,开发人员可以进一步简化流程,利用云提供的灵活和可扩展的基础设施。
在本文中,我们将探讨如何使用 Kubernetes、Docker 和 Intel AI Analytics Toolkit 在 AWS 云上构建和部署 AI 应用程序。具体而言,我们将重点关注第一个 Intel 云优化模块,它作为一个模板,包含各种 AI 工作负载的 Intel 加速方案。我们还将介绍在过程中使用的 AWS 服务,包括 Amazon Elastic Kubernetes Service (EKS)、Amazon Elastic Container Registry (ECR)、Amazon Elastic Compute Cloud (EC2) 和 Elastic Load Balancer (ELB)。
图 1. 该架构设计用于 AI 生产场景,其中需要训练许多离散模型,并且计算需求较低至中等。 — 作者提供的图片
我们将部署的示例应用程序聚焦于贷款违约预测,这是金融行业中的一个常见问题。我们将使用 daal4Py 库来加速 XGBoost 分类器的推理,使我们能够在减少训练和部署模型所需时间的同时实现高性能。
图 2. 一个简化的 Intel® oneAPI 数据分析库 API,允许数据科学家或机器学习用户快速使用该框架。旨在帮助提供对 Intel® oneAPI 数据分析库的抽象,以便直接使用或集成到自己的框架中。 — 图片来源
在本文结束时,读者将对如何使用 Kubernetes、Docker 和 Intel AI Analytics Toolkit 在 AWS 云上构建和部署高性能 AI 应用程序有基本的了解。此外,他们还将获得一个实际示例,展示如何利用这些技术加速贷款违约预测模型的推理。
你可以在我们的公共 GitHub 仓库中找到本教程的所有源代码。
准备你的开发环境
安装 AWS CLI — AWS CLI(命令行界面)工具是一个用于管理各种 Amazon Web Services (AWS) 资源和服务的命令行工具。
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
sudo apt install unzip
unzip awscliv2.zip
sudo ./aws/install
使用aws configure
配置 AWS 凭证 — 了解更多有关使用 aws cli 设置凭证的信息,请点击这里。
安装 eksctl — eksctl 是一个用于在 EKS 上创建、管理和操作 Kubernetes 集群的命令行工具。
curl --silent --location "https://github.com/weaveworks/eksctl/releases/latest/download/eksctl_$(uname -s)_amd64.tar.gz" | tar xz -C /tmp
sudo mv /tmp/eksctl /usr/local/bin
eksctl version
安装 aws-iam-configurator — AWS IAM Authenticator 是一个命令行工具,使用户能够使用其 AWS IAM 凭证与 EKS 上的 Kubernetes 集群进行身份验证。
curl -Lo aws-iam-authenticator https://github.com/kubernetes-sigs/aws-iam-authenticator/releases/download/v0.5.9/aws-iam-authenticator_0.5.9_linux_amd64
chmod +x ./aws-iam-authenticator
mkdir -p $HOME/bin && cp ./aws-iam-authenticator $HOME/bin/aws-iam-authenticator && export PATH=$PATH:$HOME/bin
echo 'export PATH=$PATH:$HOME/bin' >> ~/.bashrc
aws-iam-authenticator help
安装 kubectl — Kubectl 是一个命令行工具,用于与 Kubernetes 集群进行交互。它允许用户部署、检查和管理 Kubernetes 集群上运行的应用程序和服务,并执行各种管理任务,如扩展、更新和删除资源。
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
curl -LO "https://dl.k8s.io/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl.sha256"
echo "$(cat kubectl.sha256) kubectl" | sha256sum --check
sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
我们的贷款违约预测应用程序
我们将要部署的应用程序基于贷款违约风险预测 AI 参考套件。
我们将参考解决方案中的代码进行了重构,使其更加模块化,以支持我们的三个主要 API:
-
数据处理 — 该端点预处理数据并将其存储在数据湖或其他结构化格式中。此代码库还处理用于基准测试的数据集扩展。
-
模型训练 — 该端点训练一个 XGBoost 分类器,并将其转换为推理优化的 daal4py 格式。
-
推理 — 该端点接收一个包含原始数据的负载,并返回每个样本的贷款违约分类。
下面的目录树概述了代码库的各种脚本、资产和配置文件。大多数 ML 应用程序代码位于app/文件夹。该文件夹包含loan_default和utils包 — loan_default 包包含支持我们三个主要 API 的服务器端 Python 模块。server.py脚本包含 FastAPI 端点配置、负载数据模型和启动 uvicorn 服务器的命令。
├───app/
| ├───loan_default/
| | ├───__init__.py
| | ├───data.py
| | ├───model.py
| | └───predict.py
| ├───utils/
| | ├───__init__.py
| | ├───base_model.py
| | ├───logger.py
| | └───storage.py
| ├───logs/
| ├───server.py
| └───requirements.txt
|
├───kubernetes/
| ├───cluster.yaml
| ├───deployment.yaml
| ├───service.yaml
| └───serviceaccount.yaml
|
├─README.md
├─Dockerfile
├─SECURITY.md
深入代码库超出了本教程的范围。然而,值得指出的是,我们在哪里利用 daal4py 来提高推理性能。在 model.py 文件中,你会找到“train”方法,该方法处理模型训练并使用 d4p.get_gbt_model_from_xgboost()
函数将模型转换为 daal4py 格式。
def train(self):
# define model
params = {
"objective": "binary:logistic",
"eval_metric": "logloss",
"nthread": 4, # flags.num_cpu
"tree_method": "hist",
"learning_rate": 0.02,
"max_depth": 10,
"min_child_weight": 6,
"n_jobs": 4, # flags.num_cpu,
"verbosity": 0,
"silent": 1,
}
log.info("Training XGBoost model")
self.clf = xgb.train(params, self.DMatrix, num_boost_round=500)
self.clf = d4p.get_gbt_model_from_xgboost(self.clf)
在原始参考工具包的性能测试中,这一简单转换导致了大约 4.44 倍的性能提升(图 3)。
图 3. 对于大小为 1M 的批量推理,Intel® v1.4.2 提供了比标准 XGBoost v0.81 高达 1.34 倍的加速,使用 Intel® oneDAL 时,高达 4.44 倍的加速。— 图片由作者提供
配置和启动 Elastic Kubernetes Service 集群
Elastic Kubernetes Service 是一种完全托管的服务,它使得在 Amazon Web Services (AWS) 上使用 Kubernetes 部署、管理和扩展容器化应用变得容易。它消除了在自己的基础设施上安装、操作和扩展 Kubernetes 集群的需要。
要启动我们的 EKS 集群,我们必须首先创建我们的 集群配置文件。
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig
metadata:
name: "eks-cluster-loanDefault"
version: "1.23"
region: "us-east-1"
managedNodeGroups:
- name: "eks-cluster-loanDefault-mng"
desiredCapacity: 3
instanceType: "m6i.large"
我们可以在“metadata”部分配置集群部署的名称和区域,以及我们希望运行的 EKS 版本。最重要的是,我们可以在“managedNodeGroups”部分配置计算资源的基本需求:
-
desiredCapacity — 创建堆栈时要扩展到的节点数量。在本教程中,我们将其设置为 3。
-
instanceType — 节点的实例类型。本教程使用 m6i.large 实例,即第三代 Xeon(2vCPU 和 8GiB)。一旦开放使用,我们建议尝试 r7iz 实例系列 以利用 Intel 高级矩阵扩展 (AMX) —— 这是专为深度学习工作负载设计的加速器,内置于 Intel 第四代 Xeon CPUs 中。
我们执行 eksctl create cluster -f cluster.yaml
以创建 Cloud Formation 堆栈并配置所有相关资源。根据当前配置,此过程应需要 10 到 15 分钟。你应该会看到类似图 4 的日志。
图 4. EKS 集群配置工作流的 Cloud Formation 日志 — 图片由作者提供
你应该运行一个快速测试以确保你的集群已正确配置。运行 eksctl get cluster
以获取可用集群的名称,运行 eksctl get nodegroup --cluster <cluster name>
以检查集群的节点组。
设置所有 Kubernetes 应用程序资源
让我们深入了解如何启动您的 Kubernetes 应用程序。此过程包括创建命名空间、部署清单和 Kubernetes 服务。所有这些文件都可以在 教程的代码库 中找到。
在继续本部分教程之前,请:
作者提供的图像
Kubernetes 命名空间是一个虚拟集群,将物理集群中的资源划分和隔离。我们来创建一个名为“loan-default-app”的命名空间。
kubectl create namespace loan-default-app
现在,让我们配置我们的 Kubernetes 部署清单。Kubernetes 部署是一种 Kubernetes 资源,允许您声明性地管理给定应用程序的一组副本 pod,确保所需数量的副本始终运行并可用,同时启用如扩展、滚动更新和回滚等功能。它还提供了对 pod 的抽象层,允许您定义应用程序的期望状态,而无需担心底层基础设施。
apiVersion: apps/v1
kind: Deployment
metadata:
name: "eks-loan-default-app"
namespace: "loan-default-app"
labels:
app: "loan-default"
spec:
replicas: 3
selector:
matchLabels:
app: "loan-default"
template:
metadata:
labels:
app: "loan-default"
spec:
serviceAccountName: "loan-default-service-account"
topologySpreadConstraints:
- maxSkew: 1
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: ScheduleAnyway
labelSelector:
matchLabels:
app: "loan-default"
containers:
- name: "loan-app-image"
image: <insert image uri>
ports:
- containerPort: 80
imagePullPolicy: "Always"
上面的 Kubernetes 部署清单(deployment.yaml)定义了以下内容:
-
kind: Deployment — Kubernetes 资源的类型
-
name: “eks-loan-default-app” — 我们的部署名称
-
namespace: “loan-default-app” — 此部署应分配的命名空间
-
app: “loan-default” — 我们为应用程序分配的名称
-
replicas: 3 — 要创建并始终维持的 pod 复制品数量。
-
serviceAccountName: “loan-default-service-account” — 确保这与您之前创建的服务账户匹配。
-
topologySpreadConstraints: — 帮助定义 pod 应如何在集群中分布。当前配置将保持 pod 在可用节点上的均匀分布。
-
containers: name/image — 在这里提供应用程序容器镜像的 URI,并为镜像分配一个名称。
运行 kubectl apply -f deployment.yaml
以创建您的 Kubernetes 部署。
现在让我们配置我们的 Kubernetes 服务。Kubernetes 服务是一个抽象层,为运行相同应用程序的一组 pods 提供稳定的 IP 地址和 DNS 名称,使客户端可以访问该应用程序,而无需知道单个 pods 的具体 IP 地址。它还提供了一种在多个应用程序副本之间负载均衡流量的方法,并可用于定义外部访问的入口规则。
apiVersion: v1
kind: Service
metadata:
name: "loan-default-service"
namespace: "loan-default-app"
spec:
ports:
- port: 8080
targetPort: 5000
selector:
app: "loan-default"
type: "LoadBalancer"
上面的 Kubernetes 服务清单(service.yaml)定义了以下内容:
-
kind: Service — Kubernetes 资源的类型。
-
name: “loan-default-service” — 我们部署的名称。
-
namespace: “loan-default-app” — 该服务应分配到的命名空间。
-
port: 8080 — 服务将监听的端口。
-
targetPort: 5000 — 服务与 pod 之间通信的端口。
-
app: “loan-default” — 我们为应用程序指定的名称。
-
type: “LoadBalancer” — 我们选择的服务类型。
运行kubectl apply -f service.yaml
以创建你的 Kubernetes 服务。
这将自动启动一个 Elastic Load Balancer — 一项云服务,它将传入的网络流量分配到多个目标,如 EC2 实例、容器和 IP 地址,以提高应用程序的可用性和容错性。我们可以使用 ELB 的公共 DNS 从全球任何地方向我们的 API 端点发起请求。
在继续之前,这里有一些提示:
-
运行
kubectl get all -n loan-default-app
以获取你所配置的 Kubernetes 资源的全面概述。你应该能看到你的 pods、服务和副本组。 -
运行
kubectl -n loan-default-app describe pod <pod-id>
以获取有关你的 pod 的详细描述。 -
如果你需要诊断特定 pod 的行为,可以通过运行
kubectl exec -it <pod-id> -n loan-default-app -- bash
在 pod 内启动一个 bash shell — 输入 exit 并按回车键退出 shell。
测试我们的贷款违约预测 Kubernetes 应用程序
现在我们的基础设施已经到位,我们可以设置应用程序的数据组件并测试我们的端点。
我们将开始 从 Kaggle 下载数据集。用于本演示的数据集是一个包含 32581 个模拟贷款的数据集。它有 11 个特征,包括客户和贷款特征,以及一个标签,即贷款的结果。一旦我们在工作目录中获得了 .csv 文件,我们可以创建一个 S3 桶并上传我们的 Kaggle 数据集。
# create S3 Bucket for data
aws s3api create-bucket --bucket loan-default --region us-east-1
# upload dataset
aws s3api put-object --bucket loan-default --key data/credit_risk_dataset.csv --body <local path to data
向我们的 API 端点发起 HTTP 请求
我们将使用 Curl 来向我们的服务器发送 HTTP 请求。Curl 允许你通过提供一个命令行接口来发送 HTTP 请求,在这个接口中,你可以指定 URL、请求方法、头部信息和数据。然后,它处理建立连接、发送请求和接收响应的底层细节,使得自动化 HTTP 交互变得容易。
我们将从向我们的数据处理端点发送请求开始。这将创建测试/训练文件,并将我们的预处理管道保存为 .sav 文件到 S3。请求的主体需要以下参数:
-
bucket: S3 桶的名称
-
key: 你的原始数据在 S3 中保存的路径
-
size: 你想处理的样本总数
-
backend: 选项包括“local”或“s3” — 代码库支持在本地运行整个应用程序以进行调试。当使用“s3”后端时,“local_path”和“target_path”参数可以设置为“None”。
curl -X POST <loadbalancerdns>:8080/data -H 'Content-Type: application/json' -d '{"bucket":"loan-default","backend":"s3","key":"data/credit_risk_dataset.csv","target_path":"None","local_path":"None","size":400000}'
你可以在 AWS 控制台中导航到你的 S3 桶,以验证所有文件是否已正确生成(图 5)。
图 5. S3 桶包含由我们 /data 端点生成的输出 — 图片由作者提供
现在我们准备训练我们的 XGBoost 分类器模型。我们将向我们的 /train 端点发出请求,这将训练我们的模型,将其转换为 daal4py 格式,并保存到 S3。请求的主体需要以下参数:
-
bucket: S3 桶的名称
-
data_key: 包含由我们数据处理 API 创建的处理数据的文件夹路径
-
model_key: 我们希望存储训练模型的文件夹
-
model_name: 我们希望给训练模型起的名字
-
backend: 选项包括“local”或“s3” — 代码库支持在本地运行整个应用程序以进行调试。当使用“s3”后端时,“local_model_path”和“local_data_path”参数可以设置为“None”。
curl -X POST <loadbalancerdns>:8080/train -H 'Content-Type: application/json' -d '{"bucket":"loan-default","backend":"s3","local_model_path":"None","data_key":"data","model_key":"model","model_name":"model.joblib","local_data_path":"None"}'
你可以在 AWS 控制台中导航到你的 S3 桶,以验证你的模型文件是否已创建(图 6)。
图 6. S3 桶包含由我们 /train 端点生成的输出 — 图片由作者提供
现在我们已经有了一个训练过的 daal4py 优化的 XGBoost 分类器,我们可以向我们的 API 发出推断请求。/predict 端点将返回一个二元分类,True 表示高违约可能性,False 表示低违约可能性。响应还包括分类器生成的概率。在代码库中,我们将任何超过 50% 的概率标记为高违约可能性。这可以调整为返回更离散的标签,如低、中和高违约可能性。请求的主体需要以下参数:
-
bucket: S3 桶的名称
-
model_name: 训练模型的名称是 S3
-
data_key: 包含 .sav 处理管道文件的文件夹路径(应与处理数据的文件夹相同)
-
model_key: 你训练的模型在 S3 中保存的文件夹
-
示例:将你的模型输入作为字典列表
-
后端:选项包括“local”或“s3” — 代码库支持在本地运行整个应用程序以进行调试。当使用“s3”后端时,可以将“local_model_path”和“preprocessor_path”参数设置为“None”。
curl -X POST <loadbalancerdns>:8080/predict -H 'Content-Type: application/json' -d '{"backend":"s3","model_name":"model.joblib","data_key":"data","bucket":"loan-default","model_key":"model","sample":[{"person_age":22,"person_income":59000,"person_home_ownership":"RENT","person_emp_length":123,"loan_intent":"PERSONAL","loan_grade":"D","loan_amnt":35000,"loan_int_rate":16.02,"loan_percent_income":0.59,"cb_person_default_on_file":"Y","cb_person_cred_hist_length":3},{"person_age":22,"person_income":59000,"person_home_ownership":"RENT","person_emp_length":123,"loan_intent":"PERSONAL","loan_grade":"D","loan_amnt":35000,"loan_int_rate":55.02,"loan_percent_income":0.59,"cb_person_default_on_file":"Y","cb_person_cred_hist_length":0}],"local_model_path":"None","preprocessor_path":"None"}'
你可以很快收到服务器的响应(见图 7)。
图 7. /predict 端点的有效载荷和响应 — 作者提供的图像
你可以在我们的公共 GitHub 仓库 找到本教程的所有源代码。如果你有任何问题,欢迎留言或 在 LinkedIn 上联系我。
总结与讨论
在本教程中,我们展示了如何在 AWS 云上基于高可用性解决方案架构构建 Kubernetes 应用程序。我们重点介绍了使用英特尔 Xeon 处理器和 AI Kit 组件来提高性能,同时实现与 Kubernetes 的扩展。
我们鼓励读者关注即将举办的研讨会和未来的英特尔云优化模块(ICOMs),因为利用这些模块中的英特尔优化可以使他们的应用程序获得“由英特尔加速”徽章。
我们的 ICOMs 目标是帮助开发人员通过英特尔的软件和硬件提升应用程序的性能和可扩展性。随着对高性能云应用程序的需求增加,开发人员需要保持信息更新,利用最新的技术和工具。
别忘了关注 我的个人资料以获取更多类似文章 !
如何培养数据科学家的良好习惯
·
关注 发表在 数据科学走向 · 作为 新闻简报 发送 · 3 分钟阅读 · 2023 年 2 月 23 日
–
现在快到三月了,这意味着大多数在仅仅两个月前许下庄严新年决心的人很可能已经放弃了。(无论如何,谷歌和 ChatGPT 都这样告诉我们。)
这是否值得绝望?恰恰相反——在没有基于日历的(即外部强加的和随意的)目标期望的情况下,现在是反思我们真正想要成长的领域的最佳时机。然后我们可以采取小而具体的步骤,稳步前进。
为了帮助你在这个自我引导的旅程中,我们精选了四篇优秀的文章,这些文章从各种数据科学和机器学习的背景下探讨了强大习惯的话题。它们的共同点在于致力于可持续、渐进的改进,而非快速、短暂的解决方案。
-
使你的数据始终可靠是一个过程。Barr Moses(及合著者 Will Robins)观察到数百个数据团队在维持数据质量标准方面的挣扎。他们将所学的经验提炼成一个六步的长期流程(如果你愿意,可以称之为“数据可靠性马拉松”)——这一流程可以激励个体从业者以及整个组织进行变革。
-
领导力在于细节。在与优秀和效果较差的经理共事过之后,并在自己领导过几次机器学习项目后,Aliaksei Mikhailiuk 对成功的原则有了深刻的理解。他分享了关于沟通、基础设施和文档的见解,以及可以在这些领域中改进的实际步骤。
图片由 Eva Wilcock 提供,来源于 Unsplash。
-
如何高效运作数据科学项目。无论你是独立顾问还是大型资源丰富的数据团队成员,你都可以并且应该拒绝让混乱主导你的工作流程。Alexandre Rosseto Lemos 最近发布了一份实用指南,适用于任何希望提升组织能力的人;其中充满了专门针对数据专业人士需求的建议。
-
跟踪你自己的进步和成就。无论你的绩效评审即将到来,还是你在寻找新的职位,拥有强有力的成就记录都是关键。Semi Koen 的最新帖子强调了详细、实时记录工作亮点的重要性,以及根据扎实的自我评估培养为自己代言的习惯。
如果你已经读到这里,说明你显然拥有了强大的阅读习惯;为什么不继续培养它,通过一些最近的杰出文章呢?
-
你该如何选择合适的相似度度量来为你的推荐算法服务?Jiahui Wang的简明介绍涵盖了四种基本类型。
-
对于初学者友好的偏差-方差权衡入门,请前往Cassie Kozyrkov的轻松三部分系列。
-
比较模型的性能是任何机器学习项目中的关键部分;这就是为什么,根据Joris Guerin,设计稳健的机器学习实验如此重要。
-
深入探讨强化学习的数学基础,Shailey Dash 解释了马尔可夫决策模型 (MDP) 中的随机理论。
-
Jorge Martín Lasaosa 分享了一份关于 XGBoost 算法的全面指南,从原始论文到完整的 Python 实现。
我们希望你考虑本周成为 Medium 会员——这是支持我们发布工作的最直接和有效的方式。
直到下一个变量,
TDS 编辑
如何构建具有 O(N) 复杂度的图 Transformer
大图网络 Transformer 教程
·
关注 发表在 Towards Data Science ·7 分钟阅读·2023 年 4 月 19 日
–
图片: Unsplash。
构建强大的图 Transformer 已成为图机器学习社区的热门话题,因为最近的研究表明,纯 Transformer 基础的模型在许多 GNN 基准测试中表现出色,甚至优于其他模型(可以参见一些典型的工作 [1, 2, 3])。
然而,挑战在于 Transformers 的关键设计[4],即注意力机制,通常需要相对于输入标记的二次复杂度。在图学习的背景下,Transformers 的输入标记是图中的节点,旨在捕捉节点间长距离交互的全局注意力对于具有任意数量节点的图而言难以扩展。例如,在常见的节点分类数据集 Pubmed(约 10K 节点)上,在 16GB 内存的 GPU 上运行一个单层单头 Transformer 并进行全对全注意力计算是不可行的。
本教程将介绍两个最近的可扩展图 Transformer[5, 6],它们设计了具有相对于标记(节点)数量的线性复杂度的特殊全局注意力机制。本教程的目标是提供关于:
-
如何在保留全对全注意力的情况下实现线性复杂度;
-
如何使用 Pytorch 代码实现新的注意力函数。
这些与专注于高层次思想描述的已发表科学论文是互补的。
O(N²) 从哪里来?
Transformers 可以被视为图神经网络(GNNs)的推广,其中 GNNs 中的固定邻接矩阵扩展为 Transformers 中的可变注意力矩阵。从图的角度来看,GNNs 在固定观察图(通常具有稀疏连接)上进行消息传递,而 Transformers 的消息传递则基于密集连接的潜在图(其边权由成对注意力分数生成)。
GNNs 和 Transformers 在不同结构上的消息传递比较:GNNs 在稀疏观察图上传播信号,而 Transformers 可以被视为在具有层次边权的密集连接图上传播信号。后者需要对 N*N 注意力矩阵进行估计,并在如此密集的矩阵上进行特征传播。
接下来我们将总结原始 Transformer[4] 中的标准注意力计算。当前层的嵌入首先映射到查询、键和值向量,然后计算全对全注意力以进行特征聚合:
我们使用 z 表示节点嵌入,q、k 和 v 分别表示查询、键和值向量。W_Q、W_K 和 W_V 是第 k 层的可学习权重。
由于上述更新的计算需要 O(N),因此在一层中更新 N 个节点的总复杂度将需要 O(N²)。从矩阵视角看 O(N²) 复杂度的一个更直观的方式是,它在实际应用中使用深度学习工具(如 Pytorch、Tensorflow 等)时被考虑。具体而言,我们可以在下面说明一个注意力层的计算流程。
左侧部分展示了从矩阵视角看待的全局注意力层,右侧部分展示了对应的数据流,其中红色标记的矩阵乘积引入了 O(N²)的复杂度。
上述注意力层可以通过 PyTorch 轻松实现(在这里我们使用“einsum”函数,这是一个广义矩阵乘积实现,详细信息请参见这里):
# qs: [N, H, D], ks: [L, H, D], vs: [L, H, D]
attn = torch.einsum("nhd,lhd->nlh", qs, ks) # [N, L, H]
attn = torch.softmax(attn, dim=1) # [N, L, H]
z_next = torch.einsum("nlh,lhd->nhd", attn, vs) # [N, H, D]
尽管二次复杂度很麻烦,我们接下来介绍两种有效的方法,可以严格地将 O(N²)减少到 O(N),更重要的是,仍然保持了对所有对之间影响的明确建模的表达能力。
NodeFormer: 核化 Softmax 消息传递
最近的工作 NodeFormer [5] (一种用于节点分类的可扩展图结构学习 Transformer)利用随机傅里叶特征[8, 9]通过核近似将点积然后指数操作转换为映射然后点积替代方案:
这里的\phi 函数是一个非参数随机特征映射,其中特征维度 m 控制了对原始指数项的近似能力。有关随机特征映射及其理论属性的更多介绍,请参见参考文献[8]。
通过这种方式,原始的 Softmax 注意力可以被转化为一种高效的版本:
从左侧到右侧的推导是依据矩阵乘积的基本关联规则,即改变矩阵乘积的顺序。
注意,在右侧,N 个节点上的两个求和项与节点 u 无关,这意味着它们在计算一次后可以被所有节点重复使用。因此,对于每一层更新 N 个节点,可以先花费 O(N)来计算这两个求和项,然后基于此,计算所有 N 个节点的下一层嵌入只需 O(N),从而总复杂度为 O(N)。
为了更好地理解如何实现线性复杂度,我们可以将矩阵形式的计算流程写成如下。
左侧部分展示了从矩阵视角看待的 NodeFormer 的全局注意力层,右侧部分展示了对应的数据流,其中红色标记的矩阵乘积是计算瓶颈,需要 O(Nmd)。
注意,矩阵乘积的顺序在减少复杂度中发挥了重要作用。在上述计算中,尽管我们成功实现了全对全注意力聚合,但避免了 N*N 的注意力矩阵。一层的确切复杂度是 O(Nmd)。由于对于大图,N 通常比 m 和 d 大几个数量级,因此在实际应用中计算效率可以显著提高。例如,具有三层 Transformer 的 NodeFormer 仅需 4GB GPU 内存即可计算 0.1M 节点之间的全对全注意力。以下是实现上述高效全对全注意力的 Pytorch 代码。完整的开源模型实现公开可用,地址为GitHub。
# qs: [N, H, D], ks: [L, H, D], vs: [L, H, D]
qs = softmax_kernel(qs) # [N, H, M]
ks = softmax_kernel(ks) # [L, H, M]
# numerator
kvs = torch.einsum("lhm,lhd->hmd", ks, vs)
attn_num = torch.einsum("nhm,hmd->nhd", qs, kvs) # [N, H, D]
# denominator
all_ones = torch.ones([ks.shape[0]])
ks_sum = torch.einsum("lhm,l->hm", ks, all_ones)
attn_den = torch.einsum("nhm,hm->nh", qs, ks_sum) # [N, H]
# attentive aggregated results
z_next = attn_num / attn_den # [N, H, D]
DIFFormer: 简化的注意力计算
我们可以从 NodeFormer 中学到的教训是,复杂性减少的关键在于矩阵乘积相对于注意力聚合的顺序。接下来,我们可以利用这个思想设计另一种高效的注意力函数,而无需任何随机近似,即DIFFormer中提到的简单注意力(在原始论文中也称为简单扩散模型,灵感来自于潜在结构上的扩散)。
我们的观察来源于指数函数的泰勒展开,这可以用来激发一个新的注意力函数:
注意,尽管新的注意力函数是从 e^x 的一级泰勒展开中激发出来的,但它并不要求是对原始 Softmax 注意力的良好近似。也就是说,我们发现它在实际应用中通过广泛的实验表现稳定良好。
由于我们可以继承重新排序矩阵乘积的技巧,这个新的注意力层可以通过线性复杂度高效计算:
再次强调,右侧的两个求和项被所有节点共享,因此只需要计算一次。为了清楚地看到 O(N)复杂度,我们可以用矩阵视图写出计算流程。
矩阵乘积的计算瓶颈在右侧的红色部分标记,导致 O(Nd²)复杂度。再次注意,d 在实际应用中通常比 N 小几个数量级:例如,d 的范围可能从 32 到 256,而 N 可以达到百万甚至十亿。
以下是单层 DIFFormer 简单注意力的 Pytorch 实现,完整的模型实现公开可用,地址为GitHub。特别是,当配备简单注意力时,DIFFormer(在原始论文中也称为 DIFFormer-s)可以扩展到具有百万节点的大规模图。
# qs: [N, H, D], ks: [L, H, D], vs: [L, H, D]
qs = qs / torch.norm(qs, p=2) # [N, H, D]
ks = ks / torch.norm(ks, p=2) # [L, H, D]
N = qs.shape[0]
# numerator
kvs = torch.einsum("lhm,lhd->hmd", ks, vs)
attn_num = torch.einsum("nhm,hmd->nhd", qs, kvs) # [N, H, D]
all_ones = torch.ones([vs.shape[0]])
vs_sum = torch.einsum("l,lhd->hd", all_ones, vs) # [H, D]
attn_num += vs_sum.unsqueeze(0).repeat(vs.shape[0], 1, 1) # [N, H, D]
# denominator
all_ones = torch.ones([ks.shape[0]])
ks_sum = torch.einsum("lhm,l->hm", ks, all_ones)
attn_den = torch.einsum("nhm,hm->nh", qs, ks_sum) # [N, H]
# attentive aggregated results
attn_den = torch.unsqueeze(attn_den, len(attn_den.shape)) # [N, H, 1]
attn_den += torch.ones_like(attn_den) * N
z_next = attn_num / attn_den # [N, H, D]
参考文献
[1] 邢成轩等人, 变换器在图表示中真的表现不好吗?, NeurIPS 2021.
[2] 拉迪斯拉夫·兰帕塞克等人, 通用、强大、可扩展的图形变换器的配方, NeurIPS 2022.
[3] 金宇等人, 纯变换器是强大的图学习者, NeurIPS 2022.
[4] 阿什希什·瓦斯瓦尼等人, Attention is All you Need, NeurIPS 2017.
[5] 吴启天等人, NodeFormer: 一种可扩展的图结构学习 Transformer 用于节点分类, NeurIPS 2022. 本文提出了一种用于大规模节点分类图的高效 Transformer。关键设计是具有线性复杂度的核化 Softmax 消息传递,并且作者进一步将核技巧扩展到 Gumbel-Softmax,从可能的全对连接图中学习稀疏潜在结构。
[6] 吴启天等人, DIFFormer: 由能量约束扩散引发的可扩展(图形)变换器, ICLR 2023. 本工作设计了一种可扩展的图形 Transformer,其注意力函数来源于对潜在结构扩散的扩散性估计。在模型架构方面,DIFFormer 将 NodeFormer 中用于实现 O(N) 复杂度的关键思想进行了泛化,因此可以被视为 NodeFormer 的 2.0 版本。
[7] 线性变换器综述 本博客介绍了最近高效变换器中成功将注意力复杂度降低到 O(N) 的几种典型策略,例如低秩近似、局部-全局注意力以及将 softmax 用作核函数。
[8] 阿里·拉希米和本杰明·雷赫特. 大规模核机器的随机特征, NeurIPS 2007. 本早期工作介绍了随机特征图作为处理大量数据点的有效近似技术,以及其理论性质。
[9] 刘方辉等人, 核近似中的随机特征- 算法、理论及其应用的综述, IEEE TPAMI 2022. 本综述总结了不同随机特征在核近似中的全面集合,并讨论了它们的不同特性和适用性。
除非另有说明,否则所有图片均由作者提供。
如何使用 Polars 构建基于人气的推荐系统
原文:
towardsdatascience.com/how-to-build-popularity-based-recommenders-with-polars-cc7920ad3f68
推荐系统
基本的推荐系统易于理解和实现,且训练速度快
·发布于 Towards Data Science ·阅读时间 6 分钟·2023 年 4 月 28 日
–
由我在 dreamstudio.ai 创建
推荐系统是旨在根据用户的过去行为、偏好和互动提供推荐的算法。它们已成为各种行业(包括电子商务、娱乐和广告)的重要组成部分,提升用户体验、增加客户保留率并推动销售。
虽然存在各种高级推荐系统,但今天我想向你展示其中一种最简单的——但往往难以超越——推荐系统:基于人气的推荐系统。它是一个优秀的基线推荐系统,除了更高级的模型(如矩阵分解)外,你应该始终尝试一下。
学习如何在 TensorFlow 中构建一个简单的矩阵分解推荐系统
towardsdatascience.com
我们将在本文中使用 polars 创建两种不同风格的基于人气的推荐系统。如果你之前没有使用过快速的 pandas 替代品 polars,不必担心;这篇文章是学习它的绝佳机会。让我们开始吧!
初步想法
基于人气的推荐系统通过向客户推荐最常购买的产品来工作。这一模糊的概念可以转化为至少两种具体的实现:
-
检查哪些文章在所有客户中最常被购买。将这些文章推荐给每位客户。
-
检查哪些文章在每位客户中最常被购买。将这些每位客户的文章推荐给对应的客户。
现在我们将展示如何使用我们自己创建的数据集具体实现这些。
如果你想跟随一个真实的数据集,Kaggle 上的H&M 个性化时尚推荐挑战为你提供了一个很好的例子。由于版权原因,我不会在这篇文章中使用这个可爱的数据显示集。
数据
首先,我们将创建自己的数据集。如果你还没有安装 polars,请确保安装:
pip install polars
然后,让我们创建一个随机数据集,包括**(customer_id, article_id)对**,你应该将其理解为“拥有此 ID 的客户购买了拥有该 ID 的商品。”我们将使用 1,000,000 名可以购买 50,000 种产品的客户。
import numpy as np
np.random.seed(0)
N_CUSTOMERS = 1_000_000
N_PRODUCTS = 50_000
N_PURCHASES_MEAN = 100 # customers buy 100 articles on average
with open("transactions.csv", "w") as file:
file.write(f"customer_id,article_id\n") # header
for customer_id in range(N_CUSTOMERS):
n_purchases = np.random.poisson(lam=N_PURCHASES_MEAN)
articles = np.random.randint(low=0, high=N_PRODUCTS, size=n_purchases)
for article_id in articles:
file.write(f"{customer_id},{article_id}\n") # transaction as a row
图片由作者提供。
这个中等大小的数据集有超过 100,000,000 行(交易),这是你在商业环境中可能会遇到的数量。
任务
我们现在想构建推荐系统来扫描这个数据集,以推荐受欢迎的项目。我们将阐明两种解释这个问题的变体:
-
在所有客户中最受欢迎的产品
-
每位客户最受欢迎的产品
我们的推荐系统应该为每位客户推荐十篇文章。
注意: 我们将 不会 在这里评估推荐系统的质量。不过,如果你对这个话题感兴趣,可以给我发消息,因为这值得另写一篇文章。
在所有客户中最受欢迎的产品
在这个推荐系统中,我们甚至不关心谁购买了这些文章——我们所需的所有信息仅在article_id列中。
高层次地,它的工作原理是这样的:
-
加载数据。
-
计算每篇文章在article_id列中出现的频率。
-
将出现频率最高的十种产品作为每位客户的推荐。
熟悉的 Pandas 版本
作为一个温和的开始,让我们看看你如何在 pandas 中完成这个任务。
import pandas as pd
data = pd.read_csv("transactions.csv", usecols=["article_id"])
purchase_counts = data["article_id"].value_counts()
most_popular_articles = purchase_counts.head(10).index.tolist()
在我的机器上,这大约需要31 秒。这听起来有点少,但数据集仍然只是一个中等大小;对于更大的数据集情况会变得很糟糕。公平地说,10 秒是用来加载 CSV 文件的。使用更好的格式,例如parquet,可以减少加载时间。
注意: 我使用的是最新和最优化的版本 pandas 2.0.1。
但为了进一步准备 polars 版本,让我们使用方法链,这是一种我逐渐喜爱的技术,来完成 pandas 版本。
most_popular_articles = (
pd.read_csv("transactions.csv", usecols=["article_id"])
.squeeze() # turn the dataframe with one column into a series
.value_counts()
.head(10)
.index
.tolist()
)
这很棒,因为你可以从上到下阅读发生了什么,无需很多通常很难命名的中间变量(df_raw → df_filtered → df_filtered_copy → … → df_final,怎么样?)。不过运行时间还是一样。
更快的 Polars 版本
让我们使用方法链在 polars 中实现相同的逻辑。
import polars as pl
most_popular_articles = (
pl.read_csv("transactions.csv", columns=["article_id"])
.get_column("article_id")
.value_counts()
.sort("counts", descending=True) # value_counts does not sort automatically
.head(10)
.get_column("article_id") # there are no indices in polars
.to_list()
)
除了运行时间:3 秒 替代 31 秒,这点令人印象深刻外,其他方面看起来相似!
Polars 真的比 pandas 快得多。
不可否认,这也是 polars 相较于 pandas 的主要优势之一。除此之外,polars 还有一个 创建复杂操作的便捷语法,这是 pandas 所没有的。我们将在创建其他基于受欢迎程度的推荐器时看到更多。
同样重要的是,pandas 和 polars 产生的输出如预期一致。
每个客户的最受欢迎产品
与我们第一个推荐器不同,我们现在希望按客户切片数据框,并获取每个客户的最受欢迎的产品。这意味着我们现在需要 customer_id 和 article_id。
我们通过一个仅包含三位客户 A、B 和 C 购买四个文章 1、2、3 和 4 的十个交易的小数据框来说明逻辑。我们希望获取 每个客户的前两篇文章。我们可以通过以下步骤实现:
图片由作者提供。
-
我们从原始数据框开始。
-
然后我们按 customer_id 和 article_id 分组,并通过计数进行聚合。
-
然后我们再次对 customer_id 进行聚合,并将 article_id 写入列表中,就像在我们上一个推荐器中一样。不同的是我们 按照计数列对这个列表进行排序。
这样,我们最终得到的正是我们想要的。
-
A 最常购买的产品是 1 和 2。
-
B 最常购买的产品是 4 和 2。产品 4 和 1 也会是正确的解决方案,但内部排序刚好把产品 2 推入了推荐中。
-
C 只购买了产品 3,所以就只有这些了。
这个过程的第 3 步听起来特别困难,但 polars 让我们可以方便地处理它。
most_popular_articles_per_user = (
pl.read_csv("transactions.csv")
.group_by(["customer_id", "article_id"]) # first arrow from the picture
.agg(pl.count()) # first arrow from the picture
.group_by("customer_id") # second arrow
.agg(pl.col("article_id").sort_by("count", descending=True).head(10)) # second arrow
)
顺便提一下: 这个版本在我的机器上 运行大约一分钟。我没有为此创建 pandas 版本,而且我绝对害怕这样做并让它运行。如果你勇敢的话,可以试试看!
小改进
到目前为止,一些用户可能收到的推荐少于十个,甚至有些没有。一个简单的做法是将每个客户的推荐补充到十个文章。例如,
-
使用随机文章,或者
-
使用我们第一个基于受欢迎程度的推荐器中所有客户的最受欢迎文章。
我们可以这样实现第二个版本:
improved_recommendations = (
most_popular_articles_per_user
.with_columns([
pl.col("article_id").fill_null([]).alias("personal_top_<=10"),
pl.Series([most_popular_articles]).alias("global_top_10")
])
.with_columns(
pl.col("personal_top_<=10").list.concat(pl.col("global_top_10")).list.head(10).alias("padded_recommendations")
)
.select(["customer_id", "padded_recommendations"])
)
结论
基于受欢迎程度的推荐系统在推荐系统领域占据了重要地位,因为它们的简单性、易于实现以及作为初始方法和难以超越的基准的有效性。
在这篇文章中,我们学会了如何使用出色的 polars 库将基于流行度的简单推荐思想转化为代码。
主要缺点,特别是个性化的基于流行度的推荐系统,是推荐内容没有启发性。人们之前都见过推荐的所有内容,这意味着他们陷入了一个极端的回声室。
缓解这一问题的一个方法是使用其他方法,例如协同过滤或混合方法,如下所示:
当协作和基于内容的推荐系统融合时
towardsdatascience.com
希望你今天学到了新的、有趣的和值得的东西。感谢阅读!
如果你有任何问题,可以通过 LinkedIn联系我!
如果你想深入了解算法的世界,可以试试我新的出版物**《算法全解》**!我仍在寻找作者!
从直观解释到深入分析,算法通过实例、代码和精彩内容展现生命力……
medium.com](https://medium.com/all-about-algorithms?source=post_page-----cc7920ad3f68--------------------------------)
如何使用 Plotly 图形对象构建瀑布图
原文:
towardsdatascience.com/how-to-build-waterfall-charts-with-plotly-graph-objects-a8354543c42e
Plotly Express 不支持瀑布图,但我们可以创建一个利用 Plotly 图形对象的辅助函数
·发表于 Towards Data Science ·阅读时间 8 分钟·2023 年 9 月 14 日
–
作者提供的图片
Plotly 提供了两种绘制图表的方法:图形对象和 Plotly Express。前者是一组低级函数,为创建图表提供最大的灵活性,而 Plotly Express 则提供了一组易于使用的方法,来实现最常用的图表。
Plotly Express 函数本质上是对 Plotly 图形对象的封装。
但 Plotly Express 中没有瀑布图方法,因此我们将介绍一个简单易用的瀑布图函数,它适用于最常见的用例,并且具有应对更复杂用法的灵活性。
瀑布图
瀑布图有点像被分成多列的条形图。它们通常用于显示一个值随时间的增加和减少。例如,考虑以下数据。
labels = ["Start balance", "Consulting", "Net revenue",
"Purchases", "Other expenses", "Profit before tax"]
data = [20, 80, 10, -40, -20, 0 ]
标签表示不同类别中已接收或已支出的现金金额,数据则是实际金额(以美元、百元、千元…等为单位)。
我们可以将这些数据有效地表示为瀑布图,其中第一列是起点,最后一列是终点,中间的列展示了导致最终结果的现金流。
作者提供的图片
通常,瀑布图通过颜色区分正负金额——在本例中,正数为绿色,负数为红色。最终一列使用第三种颜色,因为这代表的是最终结果,而不是正变或负变。
这是一个典型的用例,尽管更复杂的图表也是可能的。
在她的书《数据讲故事》[1]中,Cole Nussbaumer Knaflic (CNK) 将瀑布图视为她的 12 个必备图表之一,并给出了如何用它描述随时间变化的就业情况的示例。这是我对她图表的版本。
作者提供的图像
你可以看到,我们从 100 开始,这个数字因各种原因增加和减少,直到最终人数为 116。
CNK 偏好所有列使用单一颜色,严格来说,前面图表中的颜色确实是多余的,因为从标签和列的方向(向上或向下)可以清楚地看出变化是正向还是负向。
我理解 CNK 的观点,用她的风格呈现的图表可能比多彩的图表更好看,但我也看到,尤其是在更复杂的图表中,颜色可能会很有帮助。这是一个人数图表的变体,其中正负变化混合在一起,你可能会同意红绿版本稍微更清晰(如果,也许,不如多彩版本那么美观)。
作者提供的图像
作者提供的图像
我们将开发的解决方案默认为多彩版本,但如果你愿意,也可以更改颜色方案。
使用函数
我在一个单独的文件plotlyhelper.py
中实现了瀑布图功能,以便可以作为库函数使用。导入库后,简单用法如下:
fig = ph.waterfall(labels,data, title)
我们可以在任何可以渲染 Plotly 图表的环境中使用这个函数,例如,在 Flask 应用程序、Jupyter Notebook 或 Streamlit 应用程序中。我们稍后会查看实现,但这是在 Streamlit 应用程序中使用它的方法。
import streamlit as st
import plotlyhelper as ph
st.set_page_config(layout='wide')
st.title("Waterfall graphs with Plotly")
col1, col2 = st.columns(2)
labels = ["Beginning HC", "Hires", "Transfers in", "Transfers out",
"Exits", "Ending HC"]
data = [100, 30, 8, -12, -10, 0 ]
title = "Headcount"
fig = ph.waterfall(labels,data, title)
col1.plotly_chart(fig)
fig = ph.waterfall(labels,data, title, color = 'blue')
col2.plotly_chart(fig)
这将给你两个“人数”图表版本,分为两列。
作者提供的图像
必须的参数是标签和数据,在上述示例中,我们还指定了一个标题(如果不设置,默认为空字符串)。使用这些参数,我们将得到默认的——多彩——版本的图表。
更改颜色方案
在第二个示例中,我们还设置了color
参数,它定义了图表中所有条形的颜色。这可以是 Plotly 接受的任何颜色值。
我们还可以使用参数bicolor, dcolor, tcolor,
和 ccolor
来改变每个条形的颜色,这些参数分别定义了递增条形、递减条形、最终条形和条形之间连接线的颜色。它们的默认颜色分别为“绿色”、“红色”、“蓝色”和“深灰色”。
如果你设置了color
参数,它将覆盖你可能设置的任何其他颜色。
这是如何设置单个颜色的示例。
fig = ph.waterfall(labels,data, title, icolor = 'orange',
dcolor = 'pink',
tcolor = 'yellow',
ccolor='red')
st.plotly_chart(fig)
这将绘制出这个。
作者提供的图像
也许我们可以举办最炫目颜色方案的比赛。
我们还可以探索其他几个参数。
注释
单个条形图上的标签默认为数据,但可以使用 annotation
参数进行自定义。这个数组可以是字符串或数字值,将显示在条形图上。例如,这里只有第一个和最后一个条形图被标记。
annotation = ["Start", "", "", "", "", "End"]
labels = ["Start balance", "Consulting", "Net revenue", "Purchases", "Other expenses", "Profit before tax"]
data = [20, 80, 10, -40, -20, 0 ]
title = "Sales revenue"
fig = ph.waterfall(labels,data, title, annotation=annotation)
图片由作者提供
如果不需要标签,可以将 annotation
设置为空列表。
多个时间段
有时我们想用中间总计表示一系列时间段。我们可以通过指定每个条形图的类型来实现这一点。在默认图表中,除了最后一个条形图之外,所有条形图都是“相对”的,这意味着它们会相对于当前的累计总值显示为正值或负值。最后一个条形图是“总计”类型,这意味着它会显示当前的累计总值。
为了表示多个时间段,我们使用中间的“总计”条形图。看这个例子。
图片由作者提供
在这里,我们展示了两个季度的利润和亏损金额,其中“Q1”有一个中间总计,“Q2”有一个最终总计。
为了实现这一点,我们指定一个条形图类型的列表,并将其作为参数 measure
传递。
labels = ["Year beginning", "Profit1", "Loss1", "Q1", "Profit2", "Loss2", "Q2"]
data = [100, 50, -20, 0, 40, -10, 0 ]
annotation = []
measure = ['relative','relative', 'relative','total',
'relative','relative','total']
title = "Profit/Loss"
fig = ph.waterfall(labels,data, title,
annotation = annotation,
measure=measure)
st.plotly_chart(fig)
你应该注意到,映射到中间总计的数据数组元素被赋予了正确的值 130,但是,与其他条形图不同的是,这个值不会用于计算条形图的长度;条形图的长度是根据先前的值自动计算的,这个条形图的数据值仅作为注释使用。
瀑布图辅助函数
这些都引出了实际的实现。
虽然 Plotly Express 没有实现瀑布图,但 Graph Objects (GO) 包含这样的功能。使用起来有点繁琐——这也是我开发这个简单封装器的原因。如下面的代码所示,GO 瀑布图功能要求你设置许多参数。辅助函数通过设置默认值和/或计算值消除了这一需求——用户只需设置两个或三个基本参数。
import plotly.graph_objects as go
def waterfall(labels, data, title="", annotation=None,
icolor="Green", dcolor="Red",
tcolor="Blue", ccolor='Dark Grey',
color=None, measure=None):
"""
Create a waterfall chart using Plotly.
Parameters:
labels (list): A list of labels for the data points.
data (list): A list of numerical values representing the data points.
title (str, optional): The title of the chart. Defaults to an empty string.
annotation (list, optional): A list of annotations for each data point. Defaults to None.
icolor (str, optional): Color for increasing values. Defaults to "Green".
dcolor (str, optional): Color for decreasing values. Defaults to "Red".
tcolor (str, optional): Color for the total value. Defaults to "Blue".
ccolor (str, optional): Connector line color. Defaults to 'Dark Grey'.
color (str, optional): Common color for all elements. Defaults to None.
measure (list, optional): A list specifying whether each data point is 'relative' or 'total'. Defaults to None.
Returns:
plotly.graph_objs._figure.Figure: A Plotly Figure containing the waterfall chart.
"""
# Set default measure values if not provided
if measure is None:
measure = ['relative'] * (len(labels) - 1)
measure.append('total')
# Set default annotation values if not provided
if annotation is None:
annotation = data[:-1]
annotation.append(sum(data))
# Create the waterfall chart figure
fig = go.Figure(go.Waterfall(
orientation="v",
measure=measure,
textposition="outside",
text=annotation,
y=data,
x=labels,
connector={"line": {"color": ccolor}},
decreasing={"marker": {"color": dcolor}},
increasing={"marker": {"color": icolor}},
totals={"marker": {"color": tcolor}}
)).update_layout(
title=title
)
return fig
你可以将这段代码剪切并粘贴到自己的代码中,或者访问我的网站下载这个函数和一个实现了上述所有示例的 Streamlit 应用程序。作为额外奖励,下载的 Streamlit 代码还将包括一个在 Matplotlib 中实现的瀑布图版本。
我希望你觉得这个关于瀑布图及其在 Plotly Graph Objects 中实现的介绍有用。如果你在辅助库中包含这样的功能,Plotly Express 缺少瀑布图并不重要,它在多个项目中使用时会使工作变得简单得多。
感谢阅读,请访问我的网站,在这里你可以找到其他文章和代码的链接。你也可以订阅我的偶尔发布的通讯,我会在上面发布一些完整的文章以及我在 Medium 上发布的内容的链接。
注意事项
-
用数据讲故事:商业专业人士的数据可视化指南,Cole Nussbaumer Knaflic,Wiley,2015(附属链接)
-
英式拼写——我完全意识到我在这篇文章中混用了英式和美式拼写,但我保持了一致——老实说,我确实是这样。我在文本中使用‘colour’的英式拼写,因为……好吧,我是英国人。但是在我的代码中使用‘color’的美式拼写,因为我是程序员——我习惯于大多数编程语言使用美式英语。
如何使用大型语言模型与任何 PDF 和图像文件进行聊天 — 带代码
完整指南,教你如何构建一个可以回答任何文件问题的 AI 助手
·发表于 Towards Data Science ·9 分钟阅读·2023 年 8 月 5 日
–
介绍
PDF 和图像文件中困藏着如此宝贵的信息。幸运的是,我们有这些强大的大脑,能够处理这些文件以找到特定信息,这实际上非常棒。
但我们中有多少人,内心深处并不希望拥有一个能回答关于给定文档的任何问题的工具呢?
这就是本文的全部目的。我将逐步解释如何构建一个能够与任何 PDF 和图像文件聊天的系统。
如果你更愿意观看视频,请查看下面的链接:
文章的视频格式
项目的总体工作流程
清楚了解系统的主要组件总是好的。那么,让我们开始吧。
整个聊天系统的端到端工作流程(作者提供的图像)
-
首先,用户提交需要处理的文档,可以是 PDF 或图像格式。
-
第二个模块用于检测文件格式,以便应用相关的内容提取功能。
-
然后,文档的内容使用
Data Splitter
模块被拆分成多个块。 -
这些块最终通过
Chunk Transformer
转换为嵌入,然后存储在向量存储中。 -
在处理结束时,用户的查询被用来找到包含该查询答案的相关块,结果以 JSON 格式返回给用户。
1. 检测文档类型
对于每个输入文档,根据其类型应用特定的处理,无论是PDF
还是image.
这可以通过结合使用detect_document_type
的辅助函数和内置 Python 模块中的guess
函数来实现。
def detect_document_type(document_path):
guess_file = guess(document_path)
file_type = ""
image_types = ['jpg', 'jpeg', 'png', 'gif']
if(guess_file.extension.lower() == "pdf"):
file_type = "pdf"
elif(guess_file.extension.lower() in image_types):
file_type = "image"
else:
file_type = "unkown"
return file_type
现在我们可以在两种类型的文档上测试这个功能:
-
transformer_paper.pdf
是 Transformers 研究论文 来自 Arxiv。 -
zoumana_article_information.png
是包含有关我在 Medium 上所涵盖的主要主题信息的图像文档。
research_paper_path = "./data/transformer_paper.pdf"
article_information_path = "./data/zoumana_article_information.png"
print(f"Research Paper Type: {detect_document_type(research_paper_path)}")
print(f"Article Information Document Type: {detect_document_type(article_information_path)}")
输出:
文件类型成功检测(图片由作者提供)
detect_document_type
函数成功检测了这两种文件类型。
2. 基于文档类型提取内容
[langchain](https://python.langchain.com/docs/get_started/introduction.html)
库提供了不同的模块来提取特定类型文档的内容。
-
UnstructuredImageLoader
提取图像内容。 -
UnstructuredFileLoader
提取任何 pdf 和 Txt 文件的内容。
我们可以将这些模块与上述detect_document_type
函数结合起来,实现文本提取逻辑。
这些模块可以用于在extract_file_content
函数中实现端到端的文本提取逻辑。
让我们看看它们的实际效果! 🔥
from langchain.document_loaders.image import UnstructuredImageLoader
from langchain.document_loaders import UnstructuredFileLoader
def extract_file_content(file_path):
file_type = detect_document_type(file_path)
if(file_type == "pdf"):
loader = UnstructuredFileLoader(file_path)
elif(file_type == "image"):
loader = UnstructuredImageLoader(file_path)
documents = loader.load()
documents_content = '\n'.join(doc.page_content for doc in documents)
return documents_content
现在,让我们打印每个文件内容的前 400
个字符。
research_paper_content = extract_file_content(research_paper_path)
article_information_content = extract_file_content(article_information_path)
nb_characters = 400
print(f"First {nb_characters} Characters of the Paper: \n{research_paper_content[:nb_characters]} ...")
print("---"*5)
print(f"First {nb_characters} Characters of Article Information Document :\n {research_paper_content[:nb_characters]} ...")
输出:
以上每个文档的前 400 个字符如下:
-
研究论文的内容以
Provided proper attribution is provided
开始,以Jacod Uszkoreit* Google Research usz@google.com.
结束。 -
图像文档的内容以
This document provides a quick summary
开始,以Data Science section covers basic to advance concepts.
结束。
Transformers 论文和文章信息文档的前 400 个字符(图片由作者提供)
3. 聊天实现
输入文档被分成块,然后为每个块创建嵌入,之后实现问答逻辑。
a. 文档分块
这些块代表了较大文本的一小段。这一过程对于确保内容尽可能少的噪音,并保持语义相关性至关重要。
可以应用多种分块策略。例如,我们有 NLTKTextSplitter
、SpacyTextSplitter
、RecursiveCharacterTextSplitter
、CharacterTextSplitter
等。
这些策略各有优缺点。
本文的重点是 CharacterTextSplitter
,它根据 \n\n
从输入文档中创建块,并通过字符数量(length_function
)来衡量每个块的长度。
text_splitter = CharacterTextSplitter(
separator = "\n\n",
chunk_size = 1000,
chunk_overlap = 200,
length_function = len,
)
chunk_size
指定我们希望每个块最多包含 1000 个字符,而较小的值将导致更多的块,而较大的值将生成更少的块。
需要注意的是,chunk_size
的选择方式会影响整体结果。因此,一个好的方法是尝试不同的值,选择最适合自己用例的那个。
此外,chunk_overlap
表示我们希望连续块之间有最多 200 个重叠字符。
例如,假设我们有一个包含文本 Chat with your documents using LLMs
的文档,并想使用 Chunk Size = 10
和 Chunk overlap = 5
来应用块化。
该过程在下面的图像中进行了说明:
文档块化示例(作者提供的图片)
我们可以看到,对于一个包含 35 个字符(包括空格)的输入文档,我们最终得到了 7 个块。
但是,我们为什么要使用这些重叠部分呢?
包括这些重叠部分,CharacterTextSplitter
确保在块之间保持底层上下文,这在处理长文档时特别有用。
类似于 chunk_size
,chunk_overlap
没有固定值。需要测试不同的值以选择效果更好的值。
现在,让我们看看它们在我们的场景中的应用:
research_paper_chunks = text_splitter.split_text(research_paper_content)
article_information_chunks = text_splitter.split_text(article_information_content)
print(f"# Chunks in Research Paper: {len(research_paper_chunks)}")
print(f"# Chunks in Article Document: {len(article_information_chunks)}")
输出:
每个文档中的块数(作者提供的图片)
对于像研究论文这样的较大文档,我们有更多的块(51 个),而一页文章文档只有 2 个块。
b. 创建块的嵌入
我们可以使用 OpenAIEmbeddings
模块,该模块默认使用 text-embedding-ada-002
模型来创建块的嵌入。
可以通过更改以下参数,使用不同的模型(例如 gpt-3.5-turbo-0301
)来代替 text-embedding-ada-002
:
-
model = “
gpt-3.5-turbo-0301
” -
deployment = "
<DEPLOYMENT-NAME>
",这对应于在模型部署期间给出的名称。默认值也是text-embedding-ada-002
为了简单起见,在本教程中我们将坚持使用默认参数值。但在此之前,我们需要获取 OpenAI 凭据,所有步骤在 以下文章 中提供。
from langchain.embeddings.openai import OpenAIEmbeddings
import os
os.environ["OPENAI_API_KEY"] = "<YOUR_KEY>"
embeddings = OpenAIEmbeddings()
c. 创建文档搜索
要回答给定的查询,我们需要创建一个向量存储,以找到与该查询最匹配的块。
这样的向量存储可以使用 FAISS
模块中的 from_texts
函数创建,该函数需要两个主要参数:text_splitter
和 embeddings
,这两者都已定义。
from langchain.vectorstores import FAISS
def get_doc_search(text_splitter):
return FAISS.from_texts(text_splitter, embeddings)
通过在研究论文块上运行 get_doc_search
,我们可以看到结果是 vectorstores
。如果我们使用 article_information_chunks,结果也会相同。
doc_search_paper = get_doc_search(research_paper_chunks)
print(doc_search_paper)
输出:
研究论文的向量存储(作者提供的图片)
d. 开始与你的文档聊天
恭喜你走到这一步! 🎉
chat_with_file
函数用于实现聊天的端到端逻辑,将所有上述函数与 similarity_search
函数结合使用。
最终函数需要两个参数:
-
我们想要聊天的文件,以及
-
用户提供的查询
from langchain.llms import OpenAI
from langchain.chains.question_answering import load_qa_chain
chain = load_qa_chain(OpenAI(), chain_type = "map_rerank",
return_intermediate_steps=True)
def chat_with_file(file_path, query):
file_content = extract_file_content(file_path)
text_splitter = text_splitter.split_text(file_content)
document_search = get_doc_search(text_splitter)
documents = document_search.similarity_search(query)
results = chain({
"input_documents":documents,
"question": query
},
return_only_outputs=True)
answers = results['intermediate_steps'][0]
return answers
让我们退一步,以正确理解上述代码块中发生的事情。
-
load_qa_chain
提供了一个接口,用于在一组文档上执行问答。在这个特定的案例中,我们使用的是默认的OpenAI GPT-3
大型语言模型。 -
chain_type
是map_rerank
。通过这样做,load_qa_chain
函数根据链提供的置信度分数返回答案。还有其他可以使用的chain_type
,如map_reduce
、stuff
、refine
等。每种都有其优缺点。 -
通过设置
return_intermediate_steps=True
,我们可以访问诸如上述置信度分数等元数据。
它的输出是一个包含两个键的字典:查询的 答案 和置信度 分数。
我们终于可以开始与我们的文件聊天,从图像文档开始:
- 与图像文档聊天
要与图像文档聊天,我们提供文档路径和我们希望模型回答的问题。
query = "What is the document about"
results = chat_with_file(article_information_path, query)
answer = results["answer"]
confidence_score = results["score"]
print(f"Answer: {answer}\n\nConfidence Score: {confidence_score}")
输出:
对图像文档的查询结果(图像来源:作者)
模型对其响应有 100% 的信心。通过查看下面的原始文档的第一段,我们可以看到模型的响应确实是正确的。
原始文章图像文档的前两段(图像来源:作者)
最有趣的部分之一是它提供了文档中主要主题的简要总结(统计、模型评估指标、SQL 查询等)。
- 与 PDF 文件聊天
PDF 文件的处理过程类似于上述部分。
query = "Why is the self-attention approach used in this document?"
results = chat_with_file(research_paper_path, query)
answer = results["answer"]
confidence_score = results["score"]
print(f"Answer: {answer}\n\nConfidence Score: {confidence_score}")
输出:
我们再次从模型中获得了 100% 的置信度分数。问题的答案看起来非常正确!
对 PDF 文档的查询结果(图像来源:作者)
在这两种情况下,模型都能够在几秒钟内提供类似人类的响应。让一个人经历相同的过程将需要几分钟,甚至几小时,具体取决于文档的长度。
结论
恭喜!!!🎉
我希望这篇文章提供了足够的工具来帮助你提升知识水平。代码可在 我的 GitHub 上获取。
在我的下一篇文章中,我将解释如何将这个系统集成到一个漂亮的用户界面中。敬请期待!
如果你喜欢阅读我的故事并希望支持我的写作,考虑成为 Medium 会员。每月 $5,你将获得对成千上万的 Python 指南和数据科学文章的无限访问。
通过使用 我的链接,我将获得少量佣金,而你无需额外支付。
[## 通过我的推荐链接加入 Medium - Zoumana Keita]
作为 Medium 会员,你的会员费用的一部分会用于支持你阅读的作者,同时你可以完全访问每个故事……
欢迎通过 Twitter 和 YouTube 关注我,或者在 LinkedIn 上打个招呼。
离开之前,下面还有更多你可能感兴趣的优质资源!
如何选择大学的 AI 项目/课程
原文:
towardsdatascience.com/how-to-choose-an-ai-program-course-at-university-19bbb4588ed4
生活和职业决定的推理框架
·发表于Towards Data Science ·阅读时长 13 分钟·2023 年 9 月 25 日
–
如果选择合适的学位课程或项目来学习人工智能(AI)是简单明了的,本文也就到此为止。但事实并非如此。
这意味着不仅仅是决定在大学学习人工智能,特别是当目标是在几年后成为一名 AI 专业人士时,事情会更复杂。
AI 相关课程中常见关键词的词云 — 作者提供的图片。
上述图片展示了英国各大学的硕士、博士、文凭和学士学位课程标题中的关键词和主题。我分析的每个课程在其相应的模块中还有更多的关键词。
通过学术路线成为 AI 专业人士并非完全直截了当。
假设你没有认真考虑你的大学课程选择,你可能会发现自己在一个以数据为中心的课程中,而你的兴趣在于 AI 的硬件方面,这意味着你本来可能更适合一个涉及机器人或机械的课程。
在这篇文章中,我揭示了一个实用的框架,提供了一种灵活的方法来选择大多数高等教育机构中适当的 AI 相关课程。这个框架可以用于你自己,也可以与年轻的 AI 爱好者分享。
什么、为什么、怎么做以及在哪里
你如何决定在大学选择哪个 AI 课程?
上述问题没有具体的答案。选择大学 AI 课程的实际方法是利用不同的推理方法,考虑你的愿望(什么和为什么)、能力(怎么做)和环境(在哪里)。
'什么’和’为什么’考虑了驱使你追求特定目标的内部和外部动机。更具体地说,'什么’过程确保你不仅仅是在追逐一个任意目标;相反,你了解你希望在人工智能领域的 30 到 50 年职业生涯中获得什么,并考虑到里程碑式的目标。
'如何’使你进入自我反思的状态,这需要对自己、自己的局限性和能力有清晰的了解。'哪里’考虑外部因素对你决策的影响。
让我们进入推理框架。
选择大学 AI 课程时的三步推理:
-
从后向前工作(归纳推理)
-
预先思考(演绎推理)
-
考虑你的能力和兴趣(实践推理)
这篇文章重点关注归纳推理。
从后向前工作:归纳推理
从后向前工作是一项活动,涉及你在已经取得期望结果的位置上开始投射自己的能力。
这项活动紧接着制定周密步骤和行动计划,以帮助你从一个目标达到下一个目标。
这就是我的做法。
想一个榜样,一个现在在 AI 领域中处于你想要的职位的人。
不,你不能选择埃隆·马斯克。
对于这个思维实验,我们以詹姆斯·曼伊卡,目前是谷歌(Alphabet)技术与社会高级副总裁为例。
詹姆斯将他高度技术化的学术背景转化为全球客户的影响力和价值,通过战略领导和决策。他最近被列入《时代》100 位最具影响力的人工智能(AI)人物。
在一个倾向于技术理解的领域,早期对领导力素质的重视能让你在同龄人中脱颖而出。
你可以特别考虑詹姆斯作为一个榜样,基于他将技术专长扩展到指导企业、初创公司和国家在采纳 AI 技术时的能力。前美国总统巴拉克·奥巴马任命他为全球发展委员会副主席。詹姆斯还担任了诸如可汗学院、麦克阿瑟基金会、阿斯彭研究所等公司的董事会成员。
让我们从詹姆斯·曼伊卡所处的理想位置开始,思考哪些与 AI 相关的主题和学科使他走上了同样的成功道路?
花五分钟考虑上述问题,我得出了以下三个主要主题领域:人工智能、计算机科学(CS)和机器人技术。
人工智能和计算机科学是涵盖大量话题的宏观学科。在人工智能课程中,你将接触到深度学习、机器学习、自动化、数据科学等。计算机科学研究包括软件和网络架构、数据库和基础设施设计以及软件原理。作为 AI 和计算机科学的学习者,你会获得关于 AI 和技术相关的各种主题的高级信息。
这种学习方式对于个人来说是必需的,以便负责规划和开发技术战略,这些战略将被公司、组织和国家采用——一个能够在不断变化的 AI 领域中航行,并对各种话题提供见解的通才。
我还选择了机器人学作为重点课程领域,因为硬件考虑在整个 AI 行业中至关重要。从某种意义上说,AI 涉及硬件和软件之间的持续协同,因此,理解边缘设备运行 AI 解决方案的方式或半导体对技术的影响,对于长期在 AI 和技术领域中的领导者来说是一个优势。
让我们看看我规划的学术路径与詹姆斯的匹配程度。快速查看他的LinkedIn 个人资料将足以进行这个思想实验。
詹姆斯在津巴布韦大学获得的电气工程理学士学位,与考虑可能涉及 AI 的硬件组件的方法相吻合。
电气工程以及电子学是与 AI 话题密切相关的主题。我的想法是拥有一个对 AI 和计算机科学中所有领域和话题具有高层次概述的个人,是准确的。
詹姆斯拥有数学和计算机科学的硕士学位,以及人工智能和机器人技术的博士学位。他的学术生涯始于并以硬件的考虑结束,但詹姆斯的教育背景涵盖了 AI 的整体视角,包括该领域的软件和硬件方面。
反思
在反思我的学术和职业道路时,我在职业初期优先考虑了软件。我有选择计算机科学或软件工程作为本科专业的选项,我选择了后者,因为软件在技术中的相关性非常重要,不可忽视对软件设计、实施和架构的深入理解。
探索我从全职工作转变为人工智能硕士生的过程。
我的硕士学位没有广泛涵盖人工智能,但明确专注于计算机视觉、深度学习和机器学习。我当时这样选择的理由是,相机变得越来越小巧和强大;机器学习模型在移动和边缘设备中也变得越来越普遍。因此,理解如何设计、开发和实施解决计算机视觉问题的机器学习模型将长期有益,并且也能让我在多个实际情况中成为解决问题的人。计算机视觉的一个显著特点是,许多手动任务非常适合计算机视觉解决方案。目前,我正在开发MiniPT,一个配备计算机视觉的移动应用程序,为你提供虚拟个人教练。
在撰写时,人工智能研究和关注的重点已经转向自然语言处理问题。随着像 BERT 和 GPT3 这样的大型语言模型的出现,对新学习者来说,在学术层面专注于 NLP 主题更具优势。
在硕士学习之外的前两年,我专注于在人工智能领域发展我的技术技能。我的主要职业是在伦敦的一家初创公司担任计算机视觉工程师。我还在 Medium 上撰写了许多文章,在 O’Reilly 在线学习平台上教授计算机视觉课程,并在帝国理工商学院每周讲授数据科学和统计学课程。
倒推不仅适用于学术场景。你可以将这种思维方式应用于其他领域,如金融、健康和健身。
拆解
本部分总结了迄今为止的内容,将其转化为可在任何时候执行的可操作步骤,以便你能对在高等教育机构(如大学)追求哪些人工智能相关主题形成深思熟虑的理解。
归纳推理方法选择人工智能课程——图像作者
定义你的终极目标
一切都关乎目的地
在生活中的许多事情中,通往目的地的旅程是你回顾并从中获得最多的部分。然而,理解目标、你期望的结果,会激励你首先开始这段旅程。将自己想象成你想成为的人工智能从业者。
- 识别一个已经处于该位置的人;这就是你的榜样。LinkedIn 是执行这一步骤最合适的平台。
拆解他们的路径
-
分析并研究你选择的榜样的教育和职业决策,以达到期望的位置。
-
查找他们创建或参与的出版物、文章、视频和论文。
-
更重要的是,考虑你的榜样在任何教育机构所学的学科的相关性,以及这些学科如何可能有助于他们当前的角色,以及你所期望的角色。
识别主要和嵌入的学科
要了解达到你期望职位的教育路径,你不仅需要了解你的榜样所选择的整体学科,如计算机科学或软件工程。你还必须了解你选择的学术机构中这些学科所涵盖的模块。
记住,这些嵌入式主题塑造了你对整体主题的理解,并且在许多情况下,决定了你对人工智能实际应用的兴趣程度。根据我的经验,尽管我选择了机器人学这一整体主题,但我很快意识到机器人学中的嵌入式主题不适合我的技能或最终目标。
-
理解你榜样的学术和职业路径中的核心学科和主题。
-
探索并理解你可能考虑的机构中的人工智能相关课程的内容。
专业化与泛化
在人工智能领域,成为专家或通才各有其优势。早期选择成为专家或通才,可以让你了解你希望参与的与人工智能相关的行业。选择成为专家可能使你赚取大量的收入,但此类角色的竞争可能很激烈,甚至专家角色的数量可能较少。
- 了解在你选择的领域内,专家或通才的人工智能角色是什么样的。
重新审视你的选择
没有什么是不可更改的。
在进行这项活动时,你所做的选择是灵活的;即使你选择了你心仪的大学,转向你感兴趣的人工智能其他领域可能相对容易;有时,这需要与大学教职工进行一次谈话。
就我而言,我开始本科学位时选择了计算研究,这是计算领域非常通用的学科。在第一年后意识到软件在未来几十年中的重要作用后,我申请将课程更改为软件工程;这只是与系主任的 30 分钟讨论,转学的关键要求是我的编程技能评估以及确保我在第一年获得了及格分数。
-
经常重新审视你做出的学术选择,并根据人工智能和研究的最新发展调整你的方向。
-
早期理解人工智能的根基在于周期,某些人工智能主题会在几年或几十年内受到关注,之后被取代。生成式人工智能是当前的热门人工智能话题。
整合实践经验
应用或实践的人工智能场景使你接触到许多从业者、专业人士甚至公司在构建人工智能产品时遇到的实际问题。数据隐私、用户界面设计以及伦理和社会考虑是可以研究的主题。然而,早期接触这些实际问题会让你在学术道路上领先于竞争对手。
我最初在通用电气进行了为期一年的 IT 业务分析师实习。但我很快就与通用电气内部的软件项目和计划对齐。不久之后,我开始编写移动应用程序来优化库存记录。这导致我和通用电气的库存记录员一起在路上待了一个月,了解他们的日常流程,并将技术应用于某些需要创新和优化的流程领域。
在我本科毕业时,我在通用电气工作了 1.5 年,并了解了你必须克服的障碍,以确保你构建的移动应用程序被最终用户使用——这是我至今仍在使用的经验教训。
-
寻找实习、学徒、跟随以及在你偶像曾工作过的公司或类似公司的研究机会。
-
作为人工智能学生,你的角色是尽早学习并参与专业活动,比如写作、教学和工作经验。
选择项目/大学
学生可以选择的大学种类繁多,而对于那些寻求出国留学的人来说,选择的范围更广。
我不能告诉你应该去哪个具体的大学和选择哪个具体的人工智能课程/项目。我会为你提供一个框架和推理方法,帮助你选择最适合你职业发展路径的课程。既然你已经走到这一步,那么这个目标就正在实现。
但我可以在这一部分提供一些重要的考虑因素,你在选择课程时应该考虑这些因素。让我们从上到下的方法来提供一个选择人工智能课程和大学的框架。
我是否必须去顶级大学学习人工智能?
以我自己为例。
我在萨里大学攻读硕士学位,如前所述,我主要学习了计算机视觉和深度学习。我在大学里接受了优质的教育,并且有机会使用 GPU、与博士生和讲师接触。萨里大学是一所了不起的大学,在某些情况下也是顶级大学。但在人工智能研究的大学排名中,萨里大学在欧洲排名第 59 位和全球排名第 209 位。
你不必去顶级大学学习人工智能才能获得一流的教育,并为你的职业 AI 生涯提供良好的起点。有些人甚至认为你根本不需要上大学,这主要是由于培训营、在线认证和免费的学习资源的普及。但那是另一个话题。
好吧,我不需要去顶级大学,那么在选择人工智能课程时,我应该注意什么呢?
-
师资力量:没有什么比有一位多年未更新幻灯片的讲师更糟糕的了。相信我,我曾经遇到过。我总是说,“人工智能的进步速度与创新的速度相匹配。”目前,AI 监管与创新的步伐存在挑战。而更重要的是,AI 教育不应滞后太久。了解一下你所选课程中讲师的背景。参加一些试听课程,以了解你可能要面对的内容。问问自己:讲师是否了解现代 AI 的现状?他们在过去两年内是否发布过任何出版物?
-
课程深度:如果你选择的是硕士项目,你必须确保你想作为专业追求的 AI 领域是具体的。假设你打算成为自然语言处理(NLP)工程师,那么必须确保你所选的项目涵盖了诸如马尔可夫链、传统语音识别技术以及现代方法如变压器等相关基础知识。如果你选择的是本科项目,确保前几年会让你接触到各种相关的 AI/ML/数据主题,并且在最后几年有专业方向的选择。
-
资源可用性:近年来,GPU 已经成为一种商品;确保你的大学能够使用现场或云端 GPU 基础设施,可以让你进行实验、研究、模型推断和训练。参加你考虑的大学的开放日,并询问有关 GPU 基础设施和计算资源投资的情况,如果有的话,了解一下学院的计划。
-
研究机会:有些情况下,AI 项目中的学生认为更长的学术生涯是有益的,并继续攻读几年的博士学位。
-
费用:课程或项目的价格是否在你的财务能力范围内?查看大学可能提供的其他融资选项,如奖学金、付款计划等。
结论
归纳推理,在应用于 AI 课程选择并由你期望的 AI 角色结果引导时,使你能够提出战术、策略和步骤,以实现你期望的结果。
这并不意味着保证成功,但通过确保更周到地选择 AI 课程来增加成功的机会,考虑到你的志向、环境、能力和其他几个因素。
这总比仅仅选择第一个呈现给你的 AI 课程要好。
正如之前提到的,没有任何路径是固定不变的。这意味着归纳推理及其产物(通向理想 AI 角色的学术路线图)需要适应。AI 领域和行业在不断发展。因此,持续的自我反思以及整合不断变化的技术动态,使得你的蓝图能够适应变化。
在未来的文章中,我将探讨选择高等教育机构的 AI 课程时可以采用的另外两种推理框架。
在那之前,请保持好奇。