在 Julia 中使用 MS SQL Server
是时候提升你的数据分析工作流程了
·
关注 发布于 Towards Data Science ·6 分钟阅读·2023 年 7 月 17 日
–
照片由 Venti Views 提供,来源于 Unsplash
SQL 数据库是全球最广泛部署的软件之一。它们构成了众多应用程序的核心,从业务数据分析到天气预报等。当前存在多种客户端-服务器实现,微软的 SQL Server 就是其中之一。功能齐全的 开发者版 可以免费获取。它可以在 Windows、Linux 和 Docker 上运行。
数据科学家常常需要与存储在 SQL 数据库中的数据进行交互。虽然很容易找到关于如何使用 Python 进行此操作的指南,但 Julia 的教程则非常稀少。因此,在本文中,我将专注于如何使用 Julia 与 SQL Server 进行工作。示例代码是使用Pluto notebook生成的,Julia 1.9.1 在 Linux(Elementary OS)上运行。
前提条件
- SQL Server 2022
你需要在本地运行 SQL 服务器。最简单的设置方式是通过 Docker。SQL Server 2022 的说明在这里。要验证 docker 容器是否正在运行,请使用以下命令:
watch -n 2 sudo docker ps -a
这将每 2 秒更新一次,STATUS 列应显示类似于“Up X minutes”的内容,其中 X 是从容器启动以来经过的时间。
2. Linux 版 Microsoft ODBC 驱动程序 17
说明在这里。我无法使用更新的驱动程序 18 连接到数据库,因此不能推荐使用该驱动程序。
3. sqlcmd 实用程序(可选)
sqlcmd 实用程序允许你输入 Transact-SQL 语句,非常适合测试一切是否正常工作。详细说明在这里
加载包
将需要以下 Julia 包。当使用 Pluto notebook 时,其内置的包管理器将自动下载和安装它们。
using ODBC, DBInterface, DataFrames
检查驱动程序
开放数据库连接(ODBC)驱动程序允许我们与 SQL 服务器建立连接。使用 ODBC.jl 包,我们可以检查系统上当前可用的驱动程序:
作者提供的图片
也可以在知道驱动程序位置后安装它。
作者提供的图片
要移除驱动程序,请使用:
作者提供的图片
添加连接
使用完整的连接字符串,我们现在可以连接到之前设置的本地运行 SQL 服务器。需要 IP 地址、端口、现有数据库名称、用户 ID 和密码。请注意,如果数据库名称未知,我们可以连接到‘master’,因为这个名称默认始终存在。
作者提供的图片
列出所有现有数据库
使用conn_master对象,我们现在可以在服务器上执行查询。让我们列出所有数据库。
作者提供的图片
创建新数据库
为了创建新数据库,我们应首先使用 list_db 函数检查名称是否已存在。如果没有,则按照下面的示例创建它,以‘FruitsDB’为例。
作者提供的图片
再次列出所有数据库,我们可以验证‘FruitsDB’现在已经创建。
作者提供的图片
创建新表
SQL Server 数据库可以包含多个表,这些表只是数据的有序集合。表本身是一系列行的集合,也称为记录。在我们开始填充表格之前,我们首先需要在现有数据库中创建它。作为示例,让我们在‘FruitsDB’中创建一个名为‘Price_and_Origin’的表。该表将包含三列——名称(String)、价格(Float)和来源(String)。请注意,VARCHAR(50) 用于表示 可变长度字符串 数据。50 是字节大小,对于单字节编码,它也表示字符串的长度。
添加到新表
一旦表格存在,我们可以向其中添加数据。最简单的方法是使用 DataFrame 作为数据源。请记住,我们的表格‘Price_and_Origin’期望有三列:名称、价格和来源。因此,我们可以使用一些示例数据,如下所示:
作者提供的图片
要插入值,我们可以使用 DBInterface.executemany 函数,它允许按顺序传递多个值。如下所示可以完成此操作。最终子句确保使用 DBInterface.close! 函数关闭数据库连接。这通常是一种良好的实践,有助于避免意外地将相同的连接用于其他用途。
作者提供的图片
让我们验证数据库是否按预期填充。我们首先建立一个连接‘conn_fruit’,以连接到 SQL Server 上的‘FruitsDB’。然后,我们可以从表‘Price_and_Origin’中选择所有条目,并将其传递给 DataFrame 接收器。
作者提供的图片
更新表格
按照前一节中显示的相同顺序,数据库现在可以使用新数据进行更新。
添加新水果(图像来自作者)
让我们验证新数据是否确实存在于数据库中。
请注意,现在行数为 7(图像来自作者)
移除重复项
再次执行上面的 add_to_fruit_table 函数会向表中添加重复的行。
“荔枝”和“梨”出现了两次(图像来自作者)
使用 公共表表达式 (CTE),我们可以从给定的表中删除重复的行。以下函数帮助我们实现这一点:
删除重复条目(图片来自作者)
检查行是否唯一。
重复的条目已被删除(图片来自作者)
删除记录
在数据库中,通常需要从表中删除条目(符合某些条件)。例如,我们可以删除所有价格 > 95 的水果,如下所示:
价格超过 95 的水果已被删除(图片来自作者)
删除表
使用 DBInterface.execute 函数中的 DROP 语句,可以删除一个表。其余功能将保持与 delete_rows 相同。
DBInterface.execute(conn_db,
"DROP TABLE $table_name")
结论
DBInterface.execute 函数接受有效的 SQL 语句作为输入。因此,除了已展示的内容外,还可以执行所有种类的查询,详见 此处。如前所示,查询的结果可以轻松传递给 Julia DataFrame 接收器,然后可以用来执行其他操作。
ODBC.jl 和 DBInterface.jl 这两个包正在积极维护,并且与现有工作流(尤其是涉及 DataFrames 的工作流)集成良好。这为使用 Julia 进行数据分析和可视化开辟了令人兴奋的新可能性。希望你觉得这次练习有用。感谢你的时间!通过 LinkedIn 与我联系或访问我的 Web 3.0 网站。
参考文献
从人工智能的视角看世界历史
原文:
towardsdatascience.com/world-history-through-the-lens-of-ai-340df6241fbf
语言模型编码了什么历史知识?
·发布于 Towards Data Science ·11 分钟阅读·2023 年 7 月 7 日
–
探讨 OpenAI 的 GPT-4、Anthropic 的 Claude 和 TII 的 Falcon 40B Instruct 对 1910 年重大历史事件的分析(以 6 种不同语言提示)。由作者创作。
本文 最初发布在我的博客上
人工智能的进步,尤其是大型语言模型,为 历史研究 和 教育 开辟了令人兴奋的可能性。然而,重要的是审视这些模型如何解读和回忆过去。它们是否反映了它们对历史理解中的任何固有偏见?
我非常清楚历史的主观性(我在本科时主修历史!)。我们记住的事件和我们对过去形成的叙事受到撰写这些叙事的历史学家和我们所处社会的强烈影响。例如,我的高中世界历史课程将超过 75%的课程内容集中在欧洲历史上,从而偏颇了我对世界事件的理解。
在这篇文章中,我探讨了人类历史如何通过人工智能的视角被记忆和解释。我考察了多个大型语言模型对关键历史事件的解释,以揭示:
-
这些模型是否对事件表现出西方或美国的偏见?
-
模型的历史解释是否根据提示的语言(如韩语或法语提示)有所不同,例如韩语提示可能更强调韩国事件,而法语提示则更强调法国事件?
带着这些问题,让我们深入探讨吧!
示例:1910
作为一个例子,我询问了三个不同的大型语言模型(LLMs)1910 年的主要历史事件是什么。(每个 LLM 的更多细节在下一节。)
OpenAI 的 GPT-4、Anthropic 的 Claude 和 Technology Innovation Institute 的 Falcon 40B Instruct 在关于 1910 年主要历史事件的英文提示下作出回应。由作者创建。
我提出的问题故意没有客观答案。1910 年的重要性因文化视角的不同而大相径庭。在韩国历史中,它标志着日本占领的开始,这是一个显著影响该国发展轨迹的转折点(见1910 年日韩条约)。
然而,日本对韩国的吞并在任何回应中都没有出现。我想知道如果用不同的语言——比如韩语——来提示这些模型,它们是否会有不同的解读。
OpenAI 的 GPT-4、Anthropic 的 Claude 和 Technology Innovation Institute 的 Falcon 40B Instruct 在关于 1910 年主要历史事件的韩语提示下作出回应。韩语回答已由我翻译成英文(红色)。由作者创建。
在韩语提示下,Claude 确实将日本对韩国的吞并列为主要事件之一。然而,我发现有趣的是,GPT-4 提到的五个重要事件中有两个是以美国为中心(童子军和曼-埃尔金斯法案),而忽略了提到韩国吞并。更不用说,即使在韩语提示下,Falcon 也用英语回应。
实验
实验设置如下:
-
3 个模型:OpenAI 的 GPT-4、Anthropic 的 Claude和 TII 的Falcon-40B-Instruct
-
6 种语言:英语、法语、西班牙语、韩语、日语、中文
-
3 年(610 年,1848 年,1910 年)
-
每次运行 5 个历史事件
-
10 次运行
-
= 2700 个总事件
语言和提示
我选择的语言大多是随意的,基于我最熟悉的语言(英语、韩语)以及一些我最亲近的朋友讲的语言,这些朋友可以为我翻译(中文、日语、法语、西班牙语)。翻译可以在文章末尾找到。我请他们为我翻译英文内容:
“列出 1910 年五大历史事件,按重要性排序。简要说明,仅提供事件名称。”
模型
-
OpenAI 的 GPT-4是 ChatGPT 的更新版本,是最受欢迎的 AI 聊天机器人之一(每月活跃用户超过 1 亿)
-
Anthropic 的 Claude 是一个与 ChatGPT 竞争的模型,采用称为 Constitutional AI 的方法进行训练,以实现无害和有帮助。
-
技术创新研究所的 Falcon-40B-Instruct 是最好的开源语言模型,根据 HuggingFace 的开放 LLM 排行榜。
规范化事件
即使一个模型在每次运行时生成相同的事件,它描述同一事件的方式也存在很大差异。
例如,以下所有表述都指代同一事件:
-
“日本对朝鲜的吞并”
-
“日本对朝鲜的吞并”
-
“日本吞并朝鲜”
-
“日韩吞并条约”
我需要一种方法来使用相同的词汇(称为 规范化)来指代单一事件(日本对朝鲜的吞并)。更不用说同一事件可以用六种不同的语言来描述!
我使用了手动规则、Google 翻译和 GPT-4 的组合来协助规范化。起初我希望使用一个 LLM 来规范化另一个 LLM 的事件(例如使用 GPT-4 来规范化 Claude 的事件;Claude 来规范化 Falcon 的事件等),以减少偏见。然而,Claude 和 Falcon 在规范化方面并不擅长,GPT-4 成为了最适合的模型。
我承认使用模型来规范化其自身事件会带来偏见。然而,由于我使用不同的 GPT-4 会话来生成历史事件并规范化这些事件,因此在上下文上没有重叠。未来,可以使用更客观的方法来进行规范化。
结果
总体而言,我对不同模型对历史的理解感到惊讶。
-
GPT-4 更可能生成相同的事件,无论用什么语言提示。
-
Anthropic 更可能生成与其提示语言相关的历史事件。
-
Falcon(不幸的是)更可能编造虚假的事件。
-
所有三个模型都表现出对西方或美国事件的偏见,但方式并不是我所预期的。当用非英语语言提示时,模型会生成美国或英国的历史事件(即使在用英语提示时模型不会生成那个事件)。这种情况发生在所有三个模型中。
1. 比较每个模型的语言(1910 年)
每个模型 x 语言组合生成了“前 5 个历史事件” 10 次(= 总共 50 个事件)。我选择了至少有一种语言生成了 5 次或更多次的事件。这是因为模型有时预测了一个一次性事件,而之后再也没有预测过。值为 10 的单元表示模型每次我提示时都预测了那个事件。
在本节中,我展示了 1910 年每个模型预测的主要事件,按语言分类。有关 610 年和 1848 年的类似图表可以在GitHub 页面找到,在那里我分享了所有代码和分析。
GPT-4 (OpenAI)
-
墨西哥革命:在所有语言中,墨西哥革命始终是一个重要的世界事件——即使在我没预料到的语言中,如韩语或日语
-
日本对韩国的吞并:在用西班牙语或法语提问时没有提到。用日语提问时,比用韩语提问时更可能提到这一事件(9 次对比 6 次),这让我觉得既奇怪又有趣
-
美国童子军成立:GPT-4 在用日语提问时(7 次)几乎是用英语提问时(4 次)的两倍。这似乎是一些美国信息被编码进了对 1910 年的日语理解中
-
冰川国家公园的建立:更奇怪的是,GPT-4 在用西班牙语和法语提问时预测了这一事件,但在英语中却没有
GPT-4 为 1910 年生成的主要事件,按语言对比。由作者创建。
Claude (Anthropic)
总体而言:与 GPT-4 不同,没有任何单一事件被所有语言认为是“重要历史事件”。
-
墨西哥革命:虽然在法语、西班牙语和(莫名其妙的)韩语中经常生成,但在英语中并不像 GPT-4 中那样重要
-
日本对韩国的吞并:对韩语和日语比其他语言更重要(这两个国家参与了这一事件)
-
爱德华七世的去世:对英语和法语更重要(对其他语言则不然)。爱德华七世是英国国王,显然与法国关系良好。
-
南极洲探险:这一事件实际上是英国南极探险,一位英国人首次到达南极。然而,由于某些未知原因,Claude 仅在用中文或日语提问时生成这一事件(而不是英语)。
Claude 为 1910 年生成的主要事件,按语言对比。由作者创建。
Falcon 40B Instruct (Open Source; TII)
总体而言,Falcon 在一致性和准确性方面不如其他两个模型。图表中显示的事件较少,是因为没有其他事件被 Falcon 预测 5 次或更多次!这意味着 Falcon 的预测有些不稳定。
-
泰坦尼克号沉没:这实际上发生在 1912 年
-
第一次世界大战爆发:这实际上发生在 1914 年
-
Falcon 在预测方面历史上不准确。但至少它对年代是正确的?
按语言对比的 Falcon 生成的 1910 年主要事件。由作者创建。
2. 对每种语言的模型相关性进行比较(1910 年)
接下来,我量化了一个模型的整体预测与其他模型的相似程度。我使用了一种数学方法(余弦相似度)来确定两个预测分布的相似性。值越接近 1 表示预测越相同;值越接近 0 表示两个预测集没有任何共同点。
再次展示 1910 年的例子。其他年份可以在GitHub 页面找到。
在大多数语言中,GPT-4 和 Claude 的相关性值较高——这意味着尽管使用了不同的语言,这两个模型预测了大量相似的事件。
相比之下,Falcon 的相关性较低,这意味着它对历史的理解与 GPT-4 和 Claude 有所不同。
针对 1910 年预测的事件模型相关性。由作者创建。
3. 对每一年的模型进行比较
接下来,我对每一年进行了不同语言模型的比较。我将所有语言预测的事件进行了汇总,并考虑了模型预测的整体事件,不论语言如何。我选取了至少有一个模型预测10 次或更多的事件。
与上述部分发现的趋势类似,GPT-4 和 Claude 倾向于预测每年的主要历史事件——610 年的穆罕默德的首次启示和赫拉克勒斯皇帝登基拜占庭王朝;1848 年的欧洲革命;以及 1910 年的墨西哥革命。
有些事件是某个模型相比其他模型预测得不成比例的。例如,在 1848 年,GPT-4 预测了“《共产党宣言》的发表”42 次,而 Claude 预测了 15 次。在 1910 年,Claude 预测了“爱德华七世的去世”26 次,而 GPT-4 仅预测了 1 次。
Falcon 在理解历史事件方面通常最差。Falcon 错过了所有三个年份的主要事件。在 610 年,Falcon 未能预测赫拉克勒斯皇帝的登基。在 1910 年,它未能预测诸如日本吞并朝鲜、南非联盟的形成和葡萄牙革命(这些都是非美洲的全球事件),而是预测了一些美国中心的事件,如三角工厂火灾(发生在 1911 年,而非 1910 年)。有趣的是,Falcon 能够预测大部分 1848 年的事件,这与其他两个模型相似——也许是因为 1848 年的事件更具西方中心(例如欧洲革命)?
较久远的事件(例如 610 年)使得历史稍显模糊。唐朝成立于 618 年,而非 610 年,而隋炀帝下的运河建设 实际上是在较长的时间段内完成的(604 到 609 年)。
610
比较各个模型生成的 610 年的主要事件,涵盖所有语言。由作者创建。
1848
比较各个模型生成的 1848 年的主要事件,涵盖所有语言。由作者创建。
1910
比较各个模型生成的 1910 年的主要事件,涵盖所有语言。由作者创建。
讨论
那么,这一切为什么重要呢?
随着教育公司越来越多地将大型语言模型(LLM)纳入其产品——例如,Duolingo 利用 GPT-4 进行语言学习,Khan Academy 推出 AI 教学助手‘Khanmigo’,以及哈佛大学计划将 AI 整合到计算机科学课程中——了解这些模型的潜在偏见变得至关重要。如果学生使用 LLM 学习历史,他们可能会无意中吸收哪些偏见?
在这篇文章中,我展示了一些流行的语言模型,例如 GPT-4,无论提示语言是什么,都会一致地预测“重要事件”。其他模型,如 Claude,显示出更多语言特定的预测。封闭源模型通常表现出比领先的开源替代品更高的一致性和准确性。在本文测试的所有模型中,普遍存在倾向于预测西方或美国事件(即使是冷僻事件),而忽视其他全球事件。
未来的工作可能包括:
-
扩展分析以涵盖更多语言和年份
-
对模型输出的历史准确性进行更深入的分析
-
对历史事件排名进行更深入的分析
-
发展更客观的事件标准化方法
这篇文章的目的是不是为了抨击大型语言模型(LLMs)或建议将其从教育环境中移除。相反,我希望提出一种批判性和谨慎的方法,认识到并减轻这些模型的偏见。大型语言模型在负责任的使用下,可以成为学生和教师在各学科中的宝贵资源。然而,我们也必须理解它们可能存在的偏见,例如西方中心主义,并相应地调整它们的使用。
用大型语言模型替代你的历史教授或教科书,可能会导致对历史的扭曲和片面解读。最终,我们必须审慎地利用这些工具,意识到它们固有的偏见,确保它们是补充而非主导我们对世界的理解。
感谢阅读!
这篇文章最初发布在我的博客上:欢迎关注以获取最新的其他写作内容!
失误
我尝试了几个不同的开源模型。以下是一些我发现模型生成的奇怪输出(全部是韩语)中的几处失误!
Falcon 40B 指令
Pythia 12B
该模型似乎陷入了一个由袋鼠、航空邮件以及 торговать(俄语中意为贸易)的变体组成的循环中。
翻译
English: 'Top five historical events in the year {}, ranked by importance. Be brief and only give the name of the event.'Korean: '{}년에 일어난 중대한 역사적인 사건 다섯가지는 무엇인가? 간단히 그 사건의 명칭들을 열거하시오.'Chinese: '按重要性顺序列出 {} 年的前五个历史事件。 简短一点,只给出事件的名称。'French: 'Les cinque événements historiques les plus importants de {}, en ordre d’importance. Seulement donnez leurs noms.'Japanese: '{}年にあったトップの出来事を五つイベント名のみで簡潔に記載してください。最も重要な出来事から。'Spanish: 'Una lista de los cinco eventos historicos que paso en el ano {}. Solo de el nombre del evento.'
你会成为数据策略师吗?
原文:
towardsdatascience.com/would-you-become-a-data-strategist-59c0a179df44
了解数据行业中的另一个职位名称
·发表于 Towards Data Science ·6 分钟阅读·2023 年 11 月 1 日
–
你会成为数据策略师吗?(照片由 Dan Burton 提供,来源于 Unsplash)
数据分析师、数据工程师、数据科学家……如果你对各种数据角色有所了解,可能已经听说过这些角色。几年前,随着像 dbt 这样的转型工具的兴起,出现了一种新角色:分析工程师。2021 年 1 月,Atlan 还预测了数据平台领导者的出现。无论这些预测是时尚还是趋势,我的感觉是数据角色的范围将继续扩展。
我在数据领域工作了超过三年,因此我认为数据行业中出现了一种新角色:数据策略师。从 2022 年 10 月起我便担任这个职位。我猜测这种职位在组织内部会变得越来越重要。原因很简单:数据策略师处于数据个人贡献者、战略顾问和团队经理的交汇点。
根据TechCrunch列出的信息,自 2023 年初以来,科技行业的裁员情况有所增加。随着分配给数据团队的预算减少,数据团队的规模趋于缩小。然而,他们仍然被期望交付相似数量的工作。领导者必须在数据分析、数据工程、数据科学和团队管理角色之间进行投资权衡。因此,在这种新背景下,能够掌握数据角色多个方面的人将具有战略优势。
如果你已经阅读到这篇文章,你可能已经有了上述提到的工作。你是否知道你下一步的职业发展方向是什么?**你是否可能在未曾意识到的情况下就是数据战略师?**你想成为一名吗?在这篇文章中,我希望解释什么是数据战略师,并帮助你更好地理解这个职位是否对你感兴趣。
成为数据战略师意味着什么?
根据我自己的经验以及在招聘网站上的一些研究,数据战略师履行三种角色:数据顾问、数据主管和数据团队负责人。 根据上下文,某一角色可能会比其他角色花费更多时间。同样,组织结构和数据战略师的背景也会影响他们的实际职位描述。
数据战略师的定位(作者提供的图片)
首先,与数据工作是你想称自己为数据战略师的必要要求。无论是在分析还是工程角色中,了解数据基础设施、数据管道、使用 SQL 或 Python 的临时分析以及数据可视化技术都是在数据角色中可信工作的基础。
第二,能够定义、验证和实施战略是这个职位的核心——毕竟我们在谈论的是数据战略师。这意味着对组织在数据相关事务上的长期愿景。接着,必须能够从长期目标中导出具体行动并建立一致的路线图。在我看来,短期执行与长期愿景的切换正是数据战略师角色如此令人兴奋的原因。
第三,涉及团队管理部分。与外部顾问不同,数据战略师是组织的一部分。因此,他们在引导数据团队成员朝着既定战略方向前进方面发挥作用。实际上,具体在组织图中的位置将根据组织的管理结构而有所不同。
成为数据战略师需要具备什么条件?
如果我参考我自己的经验,促使我成为数据战略家的原因是我之前作为战略顾问和后来的数据分析师的工作经历。通过这些经历,我能够发展出一系列技能,从掌握高级 SQL 函数到能够向执行委员会展示关键财务数据。
更普遍地说,数据战略家的角色包括以下任务:
-
为组织的数据战略定义长期愿景
-
制定和实施路线图
-
支持每个公司部门的数据使用
-
管理数据团队
请注意,这个列表并不详尽,主要反映了我作为数据战略家的个人经验和研究。例如,Boyan Angelov 在这篇文章中描述了他作为数据战略家的日常工作。尽管我们背景不同、工作环境不同,但我发现我们两个职位之间有许多相似之处。
为了完成这些任务,需要硬技能和软技能的混合。特别是软技能对于成功地向各方传达你的愿景和制定的路线图至关重要。良好的沟通技巧和总结能力有助于他人遵循制定的策略。至于硬技能,拥有作为数据团队个人贡献者的先前工作经验可以使所采取的行动更加贴近数据工作的现实。
一份典型的“数据战略家”职位发布(作者提供的图片)
数据战略家的职位是否在上升?
从我的角度来看,数据战略家的职位仍然是一个相对不常用的术语。当我去年获得这个头衔时,我很难找到带有这个职位名称的工作机会。与我的雇主和我所称的“数据战略家”类似的职位可能是“数据团队主管”或在其他组织中某种程度上的“数据负责人”。但正如前面提到的,我的日常工作包含更广泛的任务,包括一些需要更多咨询方法而非企业执行的方法。对我来说,我们只是发明了一个新的职位名称来描述我为公司做的工作:以战略方式处理数据。
然而,经过进一步研究,我发现“数据战略家”这个术语已经存在了一段时间。例如,一篇名为“数据战略家的崛起”的文章早在 2019 年就提到了这个职位的出现。在查看 Google Trends 时,确实没有明显的搜索趋势上升。
虽然这不是我发明的新职位名称,但我认为数据战略师的职位空缺在未来几年将会增加。正如我之前提到的,寻找能够同时掌握数据硬技能和战略软技能的人将变得更加普遍,因为对数据团队的预算将被越来越严格地监控。
结合战略、管理和数据相关技能对任何希望在技术领域和/或数据相关职位上发展其职业的人都是有帮助的。从数据战略师的职位开始,可以向公司数据主管或咨询公司数据顾问等角色发展,或者成为组织中的战略团队的一员。
结论
总之,数据战略师的角色是一个多面向的角色,要求具备数据能力、战略眼光和团队领导力。这使得它从我个人的角度来看非常有趣——也解释了它为何可能在未来变得更加流行。
你怎么看? 数据战略师的工作是否会在未来几年变得越来越受欢迎?你是否曾与数据战略师合作?你自己是否是数据战略师?
使用部分和 Pydantic 编写 DRY 数据模型
构建干净的嵌套数据模型,用于数据工程管道
·
关注 发布于 Towards Data Science ·7 min 阅读·2023 年 2 月 14 日
–
介绍
Pydantic 是一个功能极其强大的数据建模和验证库,应该成为你数据管道的标准部分。
使它们如此强大的部分原因在于,它们可以轻松地容纳嵌套的数据文件,例如 JSON。
简单回顾一下,Pydantic 是一个 Python 库,让你以 Pythonic 的方式定义数据模型,并使用该模型验证数据输入,主要通过类型提示。
Pydantic 的类型提示比标准库的更强大,更具自定义性。
另一方面,Partial 允许你预加载带有特定参数和关键字参数的函数调用,这在你多次调用相同参数的同一函数时特别有用。
在之前的文章中,我讨论了使用枚举来定义用于验证的有效字符串输入。
我们可以进一步通过将 Pydantic 数据模型与其他 Pydantic 数据模型结合来推进。
数据
我使用各种随机名称生成器创建了我们的示例数据。该数据集表示一个 Dungeons and Dragons 类型游戏中的角色。
让我们开始检查我们的数据:
作者提供的图像,由 Carbon 生成
如我们所见,与其扁平数据结构,我们现在有了数据中的数据。
检查我们之前的数据模型,我们可以看到现在必须进行一些更改以适应嵌套的数据结构:
import pydantic
class RpgCharacterModel(pydantic.BaseModel):
CREATION_DATE: datetime
NAME: str = pydantic.Field(...)
GENDER: GenderEnum
RACE: RaceEnum = pydantic.Field(...)
CLASS: ClassEnum = pydantic.Field(...)
HOME: str
GUILD: str
PAY: int = pydantic.Field(..., ge=1, le=500)
视觉化问题
我发现一个有用的工具是 JSONCrack,它提供了 JSON 数据的精彩可视化:
图像从 JSON Crack 下载,使用 GNU 通用公共许可证 v3.0
我们可以看到它下面的 4 个其他模型支持我们的顶级模型。
DRY 定义我们的模型:
使用我们可以从 JSON Crack 轻松查看的字段,我们可以像这样对模型进行第一次处理。
import pydantic
class RpgRaceModelBasic(pydantic.BaseModel):
RACE_ID: int = pydantic.Field(..., ge=10, le=99)
RACE: RaceEnum = pydantic.Field(...)
HP_MODIFIER_PER_LEVEL: int = pydantic.Field(..., ge=-6, le=6)
STR_MODIFIER: int = pydantic.Field(..., ge=-6, le=6, description="Character's strength")
CON_MODIFIER: int = pydantic.Field(..., ge=-6, le=6, description="Character's strength")
DEX_MODIFIER: int = pydantic.Field(..., ge=-6, le=6, description="Character's strength")
INT_MODIFIER: int = pydantic.Field(..., ge=-6, le=6, description="Character's strength")
WIS_MODIFIER: int = pydantic.Field(..., ge=-6, le=6, description="Character's strength")
CHR_MODIFIER: int = pydantic.Field(..., ge=-6, le=6, description="Character's strength")
pydantic.Field()
允许我们为模型指定超出类型提示的额外参数。
-
...
表示这是一个必填字段。 -
ge
表示字段必须大于或等于此值。 -
le
表示字段必须小于或等于此值。
但是,字段定义我们的属性修饰符中也有很多重复的代码。我们的 7 个修饰符必须在 -6 和 6 之间。 因此,在未来的更改中,我们必须更改 7 行代码。
我们可以使用来自 functools
库的 partial
函数来简化我们的定义。partial 函数允许我们为函数固定参数,非常适合这种多次调用相同参数的情况:
import functools
import pydantic
id_partial = functools.partial(pydantic.Field, ..., ge=10, le=99)
attribute_partial = functools.partial(pydantic.Field, ..., ge=-6, le=6)
class RpgRaceModelDry(pydantic.BaseModel):
RACE_ID: int = id_partial(..., ge=10, le=99)
RACE: RaceEnum = pydantic.Field(...)
HP_MODIFIER_PER_LEVEL: int = attribute_partial()
STR_MODIFIER: int = attribute_partial(description="Character's strength")
CON_MODIFIER: int = attribute_partial(description="Character's constitution")
DEX_MODIFIER: int = attribute_partial(description="Character's dexterity")
INT_MODIFIER: int = attribute_partial(description="Character's intelligence")
WIS_MODIFIER: int = attribute_partial(description="Character's wisdom")
CHR_MODIFIER: int = attribute_partial(description="Character's charisma")
现在,我们有一个可以在需要更改属性修饰符范围时修改代码的单一位置。这是一种更干净且更 DRY 的编程方式。
另外,请注意我们仍然可以将其他参数传递给 partial 函数,在这种情况下是 description
部分函数还很灵活,可以覆盖你已经传递给它们的关键字参数。
完善模型:
现在我们还需要定义其他三个模型以及几个与之配套的枚举:
import enum
import pydantic
class AttributeEnum(enum.Enum):
STR = 'STR'
DEX = 'DEX'
CON = 'CON'
INT = 'INT'
WIS = 'WIS'
CHR = 'CHR'
class AlignmentEnum(enum.Enum):
LAWFUL_GOOD = 'Lawful Good'
LAWFUL_NEUTRAL = 'Lawful Neutral'
LAWFUL_EVIL = 'Lawful Evil'
NEUTRAL_GOOD = 'Neutral Good'
TRUE_NEUTRAL = 'True Neutral'
NEUTRAL_EVIL = 'Neutral Evil'
CHAOTIC_GOOD = 'Chaotic Good'
CHAOTIC_NEUTRAL = 'Chaotic Neutral'
CHAOTIC_EVIL = 'Chaotic Evil'
class RpgClassModel(pydantic.BaseModel):
CLASS_ID: int = id_partial()
CLASS: ClassEnum = pydantic.Field(...)
PRIMARY_CLASS_ATTRIBUTE: AttributeEnum = pydantic.Field(...)
SPELLCASTER: bool = pydantic.Field(...)
class RpgPolityModel(pydantic.BaseModel):
KINGDOM_ID: int = id_partial(ge=100, le=999)
POLITY: str = pydantic.Field(...)
TYPE: str = pydantic.Field(...)
class RpgGuildModel(pydantic.BaseModel):
GUILD_ID: int = id_partial(ge=100, le=999)
GUILD: str = pydantic.Field(...)
ALIGNMENT: AlignmentEnum
WEEKLY_DUES: int = pydantic.Field(..., ge=10, le=100)
特别注意 KINGDOM_ID
和 GUILD_ID
。我们在部分函数中覆盖了 ge
和 le
参数,这没有问题。它仍然保留了 ...
,这表明它是一个必填字段。
通过对我们的 ID 列调用部分函数,我们不必担心忘记将它们设置为必填字段。
定义我们的顶层模型
现在所有支持模型都已构建完成,我们可以定义顶层模型,其样子如下:
import pydantic
class RpgCharacterModel(pydantic.BaseModel):
CREATION_DATE: datetime
NAME: str = pydantic.Field(...)
GENDER: GenderEnum
RACE_NESTED: RpgRaceModelDry = pydantic.Field(...)
CLASS_NESTED: RpgClassModel = pydantic.Field(...)
HOME_NESTED: RpgPolityModel
GUILD_NESTED: RpgGuildModel
PAY: int = pydantic.Field(..., ge=1, le=500)
关注 HOME_NESTED
和 GUILD_NESTED
:
注意这些模型在顶层模型中不是必需的,但这些模型内部包含的字段是必需的。这意味着,如果你向字段传递数据,它必须符合模型要求,但如果你没有向字段传递数据,它仍然被视为有效。
这实际上意味着你可以传递一个有效的模型或什么都不传。
结论
将 functools.partial()
与 Pydantic 数据模型结合使用,可以使你的代码更加简洁、易于理解,并确保以可扩展的方式正确处理无效数据。
在我们的示例中,我们只构建了一个嵌套层级,但你可以重复嵌套以管理遇到的任何复杂 JSON 对象。
同样,一个构建良好的数据模型可以让下游消费者相信你发送给他们的数据正是他们所期望的。
你认为可以如何将这些技术应用到你的数据管道中?
关于
Charles Mendelson 是 PitchBook 数据公司的数据工程师。 如果你想联系他,最好的方式是在 LinkedIn 上。
所有代码:
# Standard Library imports
from datetime import datetime
import enum
import functools
# 3rd Party package imports
import pydantic
# Enums for limiting string data in our model
class GenderEnum(enum.Enum):
M = 'M'
F = 'F'
NB = 'NB'
class ClassEnum(enum.Enum):
Druid = 'Druid'
Fighter = 'Fighter'
Warlock = 'Warlock'
Ranger = 'Ranger'
Bard = 'Bard'
Sorcerer = 'Sorcerer'
Paladin = 'Paladin'
Rogue = 'Rogue'
Wizard = 'Wizard'
Monk = 'Monk'
Barbarian = 'Barbarian'
Cleric = 'Cleric'
class RaceEnum(enum.Enum):
Human = 'Human'
Dwarf = 'Dwarf'
Halfling = 'Halfling'
Elf = 'Elf'
Dragonborn = 'Dragonborn'
Tiefling = 'Tiefling'
Half_Orc = 'Half-Orc'
Gnome = 'Gnome'
Half_Elf = 'Half-Elf'
class AttributeEnum(enum.Enum):
STR = 'STR'
DEX = 'DEX'
CON = 'CON'
INT = 'INT'
WIS = 'WIS'
CHR = 'CHR'
class AlignmentEnum(enum.Enum):
LAWFUL_GOOD = 'Lawful Good'
LAWFUL_NEUTRAL = 'Lawful Neutral'
LAWFUL_EVIL = 'Lawful Evil'
NEUTRAL_GOOD = 'Neutral Good'
TRUE_NEUTRAL = 'True Neutral'
NEUTRAL_EVIL = 'Neutral Evil'
CHAOTIC_GOOD = 'Chaotic Good'
CHAOTIC_NEUTRAL = 'Chaotic Neutral'
CHAOTIC_EVIL = 'Chaotic Evil'
# partial function for siloing our logic in one place:
id_partial = functools.partial(pydantic.Field, ..., ge=10, le=99))
attribute_partial = functools.partial(pydantic.Field, ..., ge=-6, le=6)
# models that make up our main model
class RpgRaceModelDry(pydantic.BaseModel):
RACE_ID: int = id_partial()
RACE: RaceEnum = pydantic.Field(...)
HP_MODIFIER_PER_LEVEL: int = attribute_partial()
STR_MODIFIER: int = attribute_partial()
CON_MODIFIER: int = attribute_partial()
DEX_MODIFIER: int = attribute_partial()
INT_MODIFIER: int = attribute_partial()
WIS_MODIFIER: int = attribute_partial()
CHR_MODIFIER: int = attribute_partial()
class RpgClassModel(pydantic.BaseModel):
CLASS_ID: int = id_partial()
CLASS: ClassEnum = pydantic.Field(...)
PRIMARY_CLASS_ATTRIBUTE: AttributeEnum = pydantic.Field(...)
SPELLCASTER: bool = pydantic.Field(...)
class RpgPolityModel(pydantic.BaseModel):
KINGDOM_ID: int = id_partial(ge=100, le=999)
POLITY: str = pydantic.Field(...)
TYPE: str = pydantic.Field(...)
class RpgGuildModel(pydantic.BaseModel):
GUILD_ID: int = id_partial(ge=100, le=999)
GUILD: str = pydantic.Field(...)
ALIGNMENT: AlignmentEnum
WEEKLY_DUES: int = pydantic.Field(..., ge=10, le=100)
# Our top level model:
class RpgCharacterModel(pydantic.BaseModel):
CREATION_DATE: datetime
NAME: str = pydantic.Field(...)
GENDER: GenderEnum
RACE_NESTED: RpgRaceModelDry = pydantic.Field(...)
CLASS_NESTED: RpgClassModel = pydantic.Field(...)
HOME_NESTED: RpgPolityModel
GUILD_NESTED: RpgGuildModel
PAY: int = pydantic.Field(..., ge=1, le=500)
# We didn't talk about this one, but from a previous article,
# this validates each row of data
def validate_data(list_o_dicts, model: pydantic.BaseModel, index_offset: int = 0):
list_of_dicts_copy = list_o_dicts.copy()
#capturing our good data and our bad data
good_data = []
bad_data = []
for index, row in enumerate(list_of_dicts_copy):
try:
model(**row) #unpacks our dictionary into our keyword arguments
good_data.append(row) #appends valid data to a new list of dictionaries
except pydantic.ValidationError as e:
# Adds all validation error messages associated with the error
# and adds them to the dictionary
row['Errors'] = [error_message for error_message in e.errors()]
row['Error_row_num'] = index + index_offset
#appends bad data to a different list of dictionaries
bad_data.append(row)
return (good_data, bad_data)
最初发布于 https://charlesmendelson.com 2023 年 2 月 23 日。
使用 Behave 编写可读的机器学习模型测试
使用自然语言测试你的机器学习模型的行为
·发表于数据科学的未来 ·阅读时间 9 分钟·2023 年 3 月 11 日
–
动机
想象一下,你创建了一个机器学习模型来预测基于评论的客户情感。在部署后,你意识到模型错误地将某些积极评论标记为负面,当这些评论使用负面词汇重新表述时。
作者提供的图片
这只是一个极其准确的机器学习模型在没有适当测试时可能失败的例子。因此,在部署前测试模型的准确性和可靠性至关重要。
但你如何测试你的机器学习模型呢?一种简单的方法是使用单元测试:
from textblob import TextBlob
def test_sentiment_the_same_after_paraphrasing():
sent = "The hotel room was great! It was spacious, clean and had a nice view of the city."
sent_paraphrased = "The hotel room wasn't bad. It wasn't cramped, dirty, and had a decent view of the city."
sentiment_original = TextBlob(sent).sentiment.polarity
sentiment_paraphrased = TextBlob(sent_paraphrased).sentiment.polarity
both_positive = (sentiment_original > 0) and (sentiment_paraphrased > 0)
both_negative = (sentiment_original < 0) and (sentiment_paraphrased < 0)
assert both_positive or both_negative
这种方法有效,但可能对非技术或业务参与者来说较为挑战。如果你可以将项目目标和愿景融入到测试中,并用自然语言表达出来,那将会非常好。
作者提供的图片
这时,behave 就派上用场了。
随意在此处玩耍并分叉本文的源代码:
[## Data-science/data_science_tools/behave_examples at master · khuyentran1401/Data-science
你现在无法执行该操作。你已经在另一个标签页或窗口中登录。你在另一个标签页或窗口中注销了…
什么是 behave?
behave是一个用于行为驱动开发(BDD)的 Python 框架。BDD 是一种软件开发方法论:
-
强调利益相关者之间的协作(如业务分析师、开发人员和测试人员)
-
使用户能够定义软件应用的需求和规格
由于 behave 提供了用于表达需求和规范的通用语言和格式,它可以理想地用于定义和验证机器学习模型的行为。
要安装 behave,请输入:
pip install behave
让我们使用 behave 对机器学习模型进行各种测试。
不变性测试
不变性测试测试的是机器学习模型在不同条件下是否产生一致的结果。
不变性测试的一个示例是验证模型是否对意译不变。如果模型对意译有变化,它可能会将正面评论误分类为负面评论,当评论使用负面词语重新表述时。
作者提供的图片
功能文件
要使用 behave 进行不变性测试,请创建一个名为features
的目录。在该目录下,创建一个名为invariant_test_sentiment.feature
的文件。
└── features/
└─── invariant_test_sentiment.feature
在invariant_test_sentiment.feature
文件中,我们将指定项目需求:
作者提供的图片
本文件的“Given”、“When”和“Then”部分展示了在测试过程中 behave 将执行的实际步骤。
Python 步骤实现
要使用 Python 实现场景中的步骤,请首先创建features/steps
目录,并在其中创建一个名为invariant_test_sentiment.py
的文件:
└── features/
├──── invariant_test_sentiment.feature
└──── steps/
└──── invariant_test_sentiment.py
invariant_test_sentiment.py
文件包含以下代码,用于测试由TextBlob模型生成的情感在原始文本和其意译版本之间是否一致。
from behave import given, then, when
from textblob import TextBlob
@given("a text")
def step_given_positive_sentiment(context):
context.sent = "The hotel room was great! It was spacious, clean and had a nice view of the city."
@when("the text is paraphrased")
def step_when_paraphrased(context):
context.sent_paraphrased = "The hotel room wasn't bad. It wasn't cramped, dirty, and had a decent view of the city."
@then("both text should have the same sentiment")
def step_then_sentiment_analysis(context):
# Get sentiment of each sentence
sentiment_original = TextBlob(context.sent).sentiment.polarity
sentiment_paraphrased = TextBlob(context.sent_paraphrased).sentiment.polarity
# Print sentiment
print(f"Sentiment of the original text: {sentiment_original:.2f}")
print(f"Sentiment of the paraphrased sentence: {sentiment_paraphrased:.2f}")
# Assert that both sentences have the same sentiment
both_positive = (sentiment_original > 0) and (sentiment_paraphrased > 0)
both_negative = (sentiment_original < 0) and (sentiment_paraphrased < 0)
assert both_positive or both_negative
上述代码的解释:
-
使用装饰器识别步骤,这些装饰器匹配功能的谓词:
given
、when
和then
。 -
装饰器接受一个字符串,其中包含匹配场景步骤的其余短语。
-
context
变量允许在步骤之间共享值。
运行测试
要运行invariant_test_sentiment.feature
测试,请输入以下命令:
behave features/invariant_test_sentiment.feature
输出:
Feature: Sentiment Analysis # features/invariant_test_sentiment.feature:1
As a data scientist
I want to ensure that my model is invariant to paraphrasing
So that my model can produce consistent results in real-world scenarios.
Scenario: Paraphrased text
Given a text
When the text is paraphrased
Then both text should have the same sentiment
Traceback (most recent call last):
assert both_positive or both_negative
AssertionError
Captured stdout:
Sentiment of the original text: 0.66
Sentiment of the paraphrased sentence: -0.38
Failing scenarios:
features/invariant_test_sentiment.feature:6 Paraphrased text
0 features passed, 1 failed, 0 skipped
0 scenarios passed, 1 failed, 0 skipped
2 steps passed, 1 failed, 0 skipped, 0 undefined
输出显示前两个步骤通过了,最后一步失败了,这表明模型受到了意译的影响。
方向性测试
方向性测试是一种统计方法,用于评估自变量对因变量的影响是否朝着特定方向,即正面或负面。
方向性测试的一个示例是检查特定单词的存在是否对给定文本的情感评分有正面或负面的影响。
作者提供的图片
要使用 behave 进行方向性测试,我们将创建两个文件directional_test_sentiment.feature
和directional_test_sentiment.py
。
└── features/
├──── directional_test_sentiment.feature
└──── steps/
└──── directional_test_sentiment.py
功能文件
directional_test_sentiment.feature
文件中的代码指定了项目的要求如下:
作者提供的图片
请注意,“And”被添加到文本中。由于前一步以“Given”开头,behave 将把“And”重命名为“Given”。
Python 步骤实现
directional_test_sentiment.py
文件中的代码实现了一个测试场景,该场景检查“awesome”一词的出现是否对 TextBlob 模型生成的情感分数产生积极影响。
from behave import given, then, when
from textblob import TextBlob
@given("a sentence")
def step_given_positive_word(context):
context.sent = "I love this product"
@given("the same sentence with the addition of the word '{word}'")
def step_given_a_positive_word(context, word):
context.new_sent = f"I love this {word} product"
@when("I input the new sentence into the model")
def step_when_use_model(context):
context.sentiment_score = TextBlob(context.sent).sentiment.polarity
context.adjusted_score = TextBlob(context.new_sent).sentiment.polarity
@then("the sentiment score should increase")
def step_then_positive(context):
assert context.adjusted_score > context.sentiment_score
第二步使用参数语法 {word}
。当运行 .feature
文件时,场景中为 {word}
指定的值会自动传递给相应的步骤函数。
这意味着如果场景中指出相同的句子应包含“awesome”一词,behave 将自动用“awesome”替换 {word}
。
这种转换在你想使用不同的
{word}
参数值而不需要更改.feature
文件和.py
文件时非常有用。
运行测试
behave features/directional_test_sentiment.feature
输出:
Feature: Sentiment Analysis with Specific Word
As a data scientist
I want to ensure that the presence of a specific word has a positive or negative effect on the sentiment score of a text
Scenario: Sentiment analysis with specific word
Given a sentence
And the same sentence with the addition of the word 'awesome'
When I input the new sentence into the model
Then the sentiment score should increase
1 feature passed, 0 failed, 0 skipped
1 scenario passed, 0 failed, 0 skipped
4 steps passed, 0 failed, 0 skipped, 0 undefined
由于所有步骤都通过了,我们可以推断情感分数因新词的出现而增加。
最小功能测试
最小功能测试是一种验证系统或产品是否符合最低要求并在其预期用途上可用的测试类型。
最小功能测试的一个例子是检查模型是否能处理不同类型的输入,例如数值型、类别型或文本数据。
作者提供的图片
要进行最小功能测试以验证输入,请创建两个文件 minimum_func_test_input.feature
和 minimum_func_test_input.py
。
└── features/
├──── minimum_func_test_input.feature
└──── steps/
└──── minimum_func_test_input.py
特性文件
minimum_func_test_input.feature
文件中的代码将项目要求指定如下:
作者提供的图片
Python 步骤实现
minimum_func_test_input.py
文件中的代码实现了这些要求,检查 predict
对特定输入类型生成的输出是否符合预期。
from behave import given, then, when
import numpy as np
from sklearn.linear_model import LinearRegression
from typing import Union
def predict(input_data: Union[int, float, str, list]):
"""Create a model to predict input data"""
# Reshape the input data
if isinstance(input_data, (int, float, list)):
input_array = np.array(input_data).reshape(-1, 1)
else:
raise ValueError("Input type not supported")
# Create a linear regression model
model = LinearRegression()
# Train the model on a sample dataset
X = np.array([[1], [2], [3], [4], [5]])
y = np.array([2, 4, 6, 8, 10])
model.fit(X, y)
# Predict the output using the input array
return model.predict(input_array)
@given("I have an integer input of {input_value}")
def step_given_integer_input(context, input_value):
context.input_value = int(input_value)
@given("I have a float input of {input_value}")
def step_given_float_input(context, input_value):
context.input_value = float(input_value)
@given("I have a list input of {input_value}")
def step_given_list_input(context, input_value):
context.input_value = eval(input_value)
@when("I run the model")
def step_when_run_model(context):
context.output = predict(context.input_value)
@then("the output should be an array of one number")
def step_then_check_output(context):
assert isinstance(context.output, np.ndarray)
assert all(isinstance(x, (int, float)) for x in context.output)
assert len(context.output) == 1
@then("the output should be an array of three numbers")
def step_then_check_output(context):
assert isinstance(context.output, np.ndarray)
assert all(isinstance(x, (int, float)) for x in context.output)
assert len(context.output) == 3
运行测试
behave features/minimum_func_test_input.feature
输出:
Feature: Test my_ml_model
Scenario: Test integer input
Given I have an integer input of 42
When I run the model
Then the output should be an array of one number
Scenario: Test float input
Given I have a float input of 3.14
When I run the model
Then the output should be an array of one number
Scenario: Test list input
Given I have a list input of [1, 2, 3]
When I run the model
Then the output should be an array of three numbers
1 feature passed, 0 failed, 0 skipped
3 scenarios passed, 0 failed, 0 skipped
9 steps passed, 0 failed, 0 skipped, 0 undefined
由于所有步骤都通过了,我们可以得出结论,模型输出符合我们的预期。
behave 的缺点及其使用理由
本节将概述使用 behave 相较于 pytest 的一些缺点,并解释为什么仍然值得考虑该工具。
学习曲线
在行为驱动开发(BDD)中使用行为可能导致比 pytest 使用的传统测试方法更陡峭的学习曲线。
反驳观点: BDD 对协作的关注可以导致业务需求与软件开发之间的更好对齐,从而使整体开发过程更高效。
作者提供的图片
性能较慢
behave 测试可能比 pytest 测试更慢,因为 behave 需要解析特性文件并将其映射到步骤定义,然后才能运行测试。
反驳观点: behave 对明确步骤的关注可以导致更易理解和修改的测试,从而减少测试维护所需的总体工作量。
作者提供的图片
灵活性较差
behave 的语法更为严格,而 pytest 在定义测试和夹具方面提供了更多灵活性。
反驳观点: behave 的严格结构有助于确保测试的一致性和可读性,使其更易于理解和维护。
作者提供的图片
总结
尽管 behave 相比 pytest 存在一些缺点,但其对协作、明确步骤和结构化方法的关注仍能使其成为开发团队的重要工具。
结论
恭喜!你刚刚学会了如何使用 behave 测试机器学习模型。我希望这些知识能帮助你创建更易理解的测试。
我喜欢写关于数据科学的概念和玩弄不同的数据科学工具。你可以通过 LinkedIn 和 Twitter 与我联系。
如果你想查看我写的文章的代码,请给 这个仓库 点个星。关注我在 Medium 上,及时获取我最新的数据科学文章:
Pytest 数据科学项目的综合指南
towardsdatascience.com ## 伟大的期望:总是了解你的数据期望
确保你的数据按预期工作,使用 Python
towardsdatascience.com ## 使用 Pandera 验证你的 pandas DataFrame
确保你的数据符合预期
towardsdatascience.com ## 通过验证和通知早期检测数据管道中的缺陷
使用 Deepchecks 和 Prefect 在 Python 中构建稳健的数据管道
towardsdatascience.com
编写关于自然语言处理的书籍有点像解决一个复杂的数据科学项目
对刘易斯·坦斯特尔的访谈,他是《自然语言处理与变压器》一书的合著者
·发表于Towards Data Science ·7 分钟阅读·2023 年 2 月 6 日
–
一系列访谈,突显数据科学领域作家的非凡工作及其写作历程。
图片由刘易斯·坦斯特尔提供
“在小说中,语言和引发的感官体验很重要,而在技术写作中,内容和传达的信息才是重要的。”
― 克里斯塔·范·兰,《技术写作内幕指南》
最后编辑于 2023 年 2 月 6 日
作为一名作家,我对揭示我们阅读的书籍背后的故事充满了浓厚的兴趣,特别是在机器学习领域。这些作家具有将人工智能的复杂性转化为既信息丰富又引人入胜的文字的非凡能力,实在是令人惊叹。我的目标是通过一系列访谈,把他们的故事展现出来,揭示一些在人工智能领域的知名作者的故事。
认识作者:刘易斯·坦斯特尔
刘易斯·坦斯特尔 是一位杰出的机器学习工程师,目前在 Hugging Face 工作。他在为初创企业和大型企业构建机器学习应用方面拥有丰富的经验,专注于自然语言处理、拓扑数据分析和时间序列等领域。拥有理论物理学博士学位的刘易斯曾有机会在澳大利亚、美国和瑞士等多个国家担任研究职位。他目前的工作集中在为自然语言处理社区开发创新工具,并赋予个人有效使用这些工具的知识和技能。
刘易斯是书籍《自然语言处理与 Transformers》的合著者之一,与Leandro von Werra和Thomas Wolf合作。这本书是该领域最新进展的全面指南,是任何希望深入理解自然语言处理以及如何将其应用于现实世界问题的人的绝佳资源。
自 2017 年引入以来,transformers 已迅速成为实现…
问: 这本书的构思是如何产生的?
刘易斯: 尽管我们在 2020 年开始了这本书,但它的起源故事实际上可以追溯到 2019 年,当时 Leandro 和我首次开始使用 Transformer 模型。当时,Jay Alammar 的精彩博客文章和 Sasha Rush 的《注释 Transformer》是理解这些模型如何工作的为数不多的书面资源。这些文章(并且仍然是!)非常有助于理解,但我们觉得在指导人们如何将 Transformer 应用于工业用例方面存在一个空白。因此,在 2020 年,我们有了一个有些冒失的想法,将我们从工作中学到的知识结合成一本书。我的妻子建议我们联系 Thomas 看他是否有兴趣成为合著者,令我们惊讶的是,他同意了!
问: 能否为读者总结一下书中涵盖的主要内容?
刘易斯: 正如标题所示,这本书是关于将 Transformer 模型应用于自然语言处理任务的。大多数章节围绕着你在行业中可能遇到的单一用例进行结构化。书中涵盖了文本分类、命名实体识别和问答等核心应用。我们从精彩的fast.ai课程中汲取了很多灵感(这也是我开始深度学习的途径!),因此本书采用了动手实践的风格,强调通过代码解决现实世界的问题。在早期章节中,我们介绍了自注意力机制和迁移学习的概念,这些概念是 Transformer 成功的基础。
我对新作者的主要建议是找到可以深度批评你的想法和写作的合著者或同事。
书的后半部分深入探讨了更高级的主题,如为生产环境优化 Transformers 和处理标注数据稀少的场景(即每个数据科学家的噩梦 😃)。我最喜欢的章节之一是关于从头开始训练一个 GPT-2 规模模型,包括如何创建一个大规模语料库并在分布式基础设施上进行训练!书的结尾着眼于未来,通过突出一些涉及 Transformers 和其他模式(如图像和音频)的激动人心的最新进展来作结。
问:你与 Leandro von Werra 和 Thomas Wolf 共同编写了这本书。与多位作者一起编写书籍是什么感觉?
写一本关于 NLP 的书有点像解决一个复杂的数据科学项目。在各种挑战中,你需要为每个章节设计用例和故事,找到合适的数据和模型,并确保代码复杂性保持在最低限度,因为阅读长块代码一点也不有趣。而且就像任何数据科学项目一样,一些章节涉及到进行几十次实验。面对这些挑战,我发现与 Leandro 和 Thomas 一起写书是一个极其宝贵的经历!特别是,与能够头脑风暴或检查代码的合著者一起工作尤其有帮助。当然,多位作者面临的一个挑战是保持全书的写作风格一致,我们很幸运能有 O’Reilly 的优秀编辑帮助我们实现这一点。
问:你认为这本书的目标读者是谁?
我们写这本书是为了数据科学家和机器学习/软件工程师,他们可能听说过最近涉及 Transformers 的突破,但仍需要一个深入的指南来帮助他们将这些模型适应到自己的用例中。换句话说,就是像我自己大约 1-2 年前一样的人!我们设想这本书对行业从业者或希望从相关领域(例如,想要构建机器学习驱动应用的工程师)转向自然语言处理(NLP)的人会最有帮助。
问:你认为怎样才能最大化利用这本书——先读后写代码,还是边读边写代码?
我们实际上使用 Jupyter notebooks 和一个名为 fastdoc 的工具写了整本书,因此每一行代码都可以在我们提供的 GitHub 附带的 notebooks 中执行。我建议将书的章节和附带的代码放在一起,这样你可以在阅读时快速实验输入和输出。我们还计划在书发布时举办一些直播活动,请关注 书籍官网 以了解这些活动的时间。
问:你会给刚开始写作的新作者什么建议?
呵呵,我的第一条建议是问自己是否真的确定想写一本书。我的第二条建议是不要在刚刚有了宝宝之后……在疫情期间写书 😃
写一本关于 NLP 的书有点像解决一个复杂的数据科学项目。在各种挑战中,你需要为每一章设计用例和故事,找到合适的数据和模型,并确保代码复杂性保持在最低,因为阅读长篇代码一点也不有趣。
说正经的,我给新作者的主要建议是找到可以深入批评你想法和写作的合著者或同事。我们很幸运地有像 Aurélien Geron 和 Hamel Husain 这样的经验丰富的作者提供了详细的评论,他们的反馈显著提高了书籍质量。这种反馈非常宝贵,因为作为一个作者,你有时会忘记最初学习一个主题时哪些方面很难掌握。巧合的是,Aurélien 为我们的书写了前言!
问:你最喜欢的书和作者是谁(技术或非技术领域)?
哦,这是个棘手的问题!我是科幻小说的忠实读者,《三体》 由刘慈欣 编写,是我最喜欢的系列之一,因为它提供了对费米悖论的一个全新解决方案——即为什么没有可观察到的外星文明证据,尽管有大量类地行星的恒星?我也喜欢阅读关于物理学和计算机科学等科学领域历史的书籍和传记。我最近的一个最爱是 《未来之人》由 Ananyo Bhattacharya 编写,这本书讲述了杰出的约翰·冯·诺依曼的生活。虽然作为物理学学生我遇到过冯·诺依曼的一些工作(他写了关于量子力学的杰作),但我没有完全意识到他对数学和科学领域的广泛贡献。这本书非常出色地描述了他的工作及其迷人的历史——强烈推荐!
👉 你想与 Lewis 建立联系吗?请关注他的 Twitter.
👉 阅读本系列的其他访谈:
一次与 Alexey Grigorev 的访谈,他是《机器学习书营》的作者。
不要只是做笔记,把它们转化为文章并与他人分享 [## 你并不会通过使用花哨的技巧变得更好,而是通过专注于基础
与 Radek Osmulski 的访谈,他是《Meta Learning: How To Learn Deep Learning And Thrive In The…》一书的作者
你并不会通过使用花哨的技巧变得更好,而是通过专注于基础 [## 发布是强大的,因为它作为范围和写作决策的催化剂
与 Christoph Molnar 的访谈,他是《Interpretable Machine Learning》一书的作者
为数据管道编写设计文档
探索数据组件设计文档的内容、意义和方法——以及它们为何重要。
·
关注 发表在 Towards Data Science ·8 分钟阅读·2023 年 5 月 22 日
–
图片来源:Mike Kononov 在 Unsplash
近年来,采纳软件工程最佳实践已成为数据工程领域的一个共同主题。从 dbt 的软件工程灵感功能到数据可观察性的兴起,数据工程师们正越来越习惯于软件工程师的工具集和原则。
这种转变对我们设计和构建数据管道的方式产生了重大影响。它使数据管道更加健壮(因为我们从硬编码的业务逻辑和复杂的 SQL 查询转向了模块化的 dbt 模型和宏),并大幅减少了“嘿,你能检查一下这个表吗?”这种 Slack 消息(通过自动化的数据质量监控和警报)。
这些变化帮助我们将行业导向正确的方向——但我们仍然有很多领域需要向软件工程同行学习。
根据dbt Labs 最近发布的数据,大约 20%的 dbt 项目有超过 1,000 个模型(5%有超过 5,000 个)。这些数据突出了我们数据管道中的一个根本问题:我们在设计它们时不够有意图。我们在临时模型和特定用例的转换层层叠加,最终得到十个表示相同逻辑实体的模型,“仅有细微差别”。
在本文中,我们将讨论一个可以帮助我们为数据平台设计(和构建)稳健基础的文档:设计文档。
什么是设计文档?
在软件工程领域,通常会在软件组件的设计阶段创建两个主要文档,以帮助工程师进行协作和记录决策:
-
**设计文档或请求评论(RFC)**应包含与当前状态相关的所有信息,包括为什么需要做某事以及可能的设计/解决方案。内容随后会根据来自不同人员/团队的反馈和输入不断演变,直到达成共识。
-
**架构决策记录(ADR)**记录了一个具体的决策。这个文档更多的是一个书面快照,包含了形成技术决策的核心因素以及决策/设计本身的不同方面。
公司通常有一个内部模板用于这类文档(或其变体),以便不同团队可以利用它来标准化技术决策的制定方式。Gergely Orosz 写了一篇很好的文章提供了多个示例,我也推荐查看谷歌设计文档流程的公开概述。
为什么我们需要数据管道的设计文档?
基于 dbt 的方法构建数据管道的一个意外后果是,它使得向图中添加更多节点/模型变得过于容易。这让数据工程团队沉溺于构建临时数据管道的循环:数据管道没有经过适当的设计阶段或统一的整体规划,而是直接构建,导致了这种非常常见的 dbt 谱系图:
一个带有临时方法的示例 dbt 图:复杂性的增加以及缺乏治理的基础层(图片由作者提供)
这种方法的主要问题是节点不断被添加到图中,而没有太多的监督。这导致了复杂性的无尽螺旋,造成不必要的成本,并使找到正确的消费表变成了不可能的任务。
为了应对这种反模式,我的建议是始终以软件工程团队对复杂软件组件的严格要求来对待数据流水线。这意味着在编写 dbt 模型之前,我们应定义(并达成一致)一些基础块:
-
流水线/数据资产的范围
-
对全球消费层的变化
-
将要交付的资产特征
-
流水线本身的设计
如你所见,我的建议是将这些信息(及更多)汇总到设计文档中,并确保所有相关利益相关者在开始实施之前达成一致。
流水线与组件
在开始讨论设计文档的细节之前,需要注意的是,范围的概念、数据平台的整体设计以及数据工程团队的组织方式会因公司而异(基于众多因素)。这意味着本文介绍的概念应根据你自己的数据平台进行调整。例如,在 Zendesk,我们将数据资产划分为数据域,因此设计文档的范围将是一个特定的数据域(从其数据源到基础且高度治理的消费层)。
这同样适用于“数据流水线”的定义;本文中使用了这个术语,因为它是数据工程领域中的一个常见逻辑组件,但更准确的统称应为“数据组件”(这可以是一组数据产品:流水线、表格或其他工件)。
我的设计文档应该是什么样的?
既然我们了解了设计文档的重要性,接下来的问题是如何将这一概念应用于数据流水线(或者更准确地说:数据组件)——那么你的数据组件的设计文档应包含哪些主要部分?
1. 设计元数据
设计文档是捕捉特定组件所有相关元数据的黄金机会。这些元数据可能包括以下内容:
-
所有权:组件应有不同的所有者(技术、业务等),他们对设计和实施负责。
-
高层次描述:重要的是要有一个非常简洁的组件描述,说明我们为什么想要(或更好,必须)构建它,以及它解决了哪些业务问题或用例。这使得来自不同团队的潜在贡献者在进一步阅读之前能够获得必要的背景信息。
-
技术元数据:这将根据你的平台而有所不同,但必须包括开始日期(数据何时开始可用?)和建议的历史回填(最早可用的日期是什么?)
-
审阅者及审阅状态(可选):这些信息可以在设计文档之外进行管理(例如通过单独的 ADR 文档),但为了简化流程并使其更为顺畅,本节还可以包括审阅者的信息(最好是中央团队的一部分,能够评估组件如何适应整体设计)以及设计的当前状态(无论是已批准还是处于中间状态)。
这个部分不能有“过多”的元数据。如果有值得记录的信息,那么它肯定有其存在的必要。
2. 现有资源
本节旨在捕捉与此组件相关的所有相关资源。这些资源可以包括现有设计的文档,或与此组件将解决的业务用例或问题的链接。
这里的想法是,任何阅读设计文档的人都应该掌握与此组件相关的完整背景和相关资源。
3. 核心下游指标和用例
关键问题在于临时数据管道是没有明确目标的。相反,表格是为了回答模糊且定义不清的用例而添加的,然后被遗忘。
因此,我建议在开始考虑实际管道之前,专注于指标和下游用例。本节应提供以下项目的详细背景:
-
主要依赖于此数据组件的用例是什么?
-
使用此组件中表格计算的主要核心指标是什么?
4. 消费数据模型(或它将如何变化)
既然我们已经讨论了我们为之设计这个组件的核心指标和用例,让我们决定消费层应如何设计。
既然已经列出了下游指标,数据建模阶段变得不那么棘手,因为它将包括定义可以服务于所有下游使用场景的基础数据模型。在这里,具体设计将取决于设计文档本身之外的因素——你可以利用维度数据建模或其他技术,只要保持各组件之间的一致性,并避免创建孤立或重复的实体。
新的数据组件将如何更新全球消费数据模型(图由作者提供)
直到目前为止,我们还没有讨论数据管道或 dbt 模型。相反,重点在于定义我们希望如何呈现能够满足所有预期下游用例和指标的数据资产。
5. 表级(和列级)的元数据
在定义逻辑数据模型之后,理想情况下,我们还应在不同层次上提供关于将要构建的消费资产的背景:
-
每个表将包含什么信息?(表级描述)
-
对于每个表,我们计划提供哪些列?每列将包含哪些信息?我们是否做出任何数据质量承诺?
-
对于每个表,数据更新的频率是多少?我们是否承诺任何服务水平协议(SLA)?
-
对于每个表,初始回填和每次执行的成本估算是多少?
我们的目标是确保所有利益相关者对将要构建的资产(表)以及不同的承诺达成一致。根据你的数据开发标准,这一部分还可能包括其他信息,例如每个表的业务重要性或其认证情况。
6. 管道设计
最后一部分是我建议最终关注数据管道的地方。经过识别所有核心下游使用案例和预期承诺后,我们现在可以更清晰地设计如何实现目标。
本节将包含我们希望作为数据组件的一部分使用的所有源/原始表的列表(以及这些表是否已是平台的一部分,或者我们是否需要通过提取-加载过程引入数据),以及我们希望构建的 dbt 模型(或数据管道)以达到消费层的期望状态。
数据管道(或 dbt 模型)的示例设计,作为数据组件的一部分(图片作者提供)
但它能扩展吗?
对这种方法的初步反应可能是认为它难以扩展——但只有在我们对扩展性的定义偏颇时才会这样。
扩展性不应包括用一千个 dbt 模型来回答一千个使用案例(因为这种方法最终不会可扩展)。相反,我们寻求的扩展性是高效地回答一万种使用案例而不陷入无尽的复杂性循环。在这方面,这种方法(专注于构建为核心下游使用案例精细调整的稳健基础,并且有所有相关利益相关者的输入)绝对是可扩展的。
在这个基础的高度治理层的下游,你可以采用不同的方法来处理特定的使用案例或定制场景:可以通过使用“自动化”语义层或者打开由基础层构建的去规范化度量导向表的大门。
结论
在本文中,我们涵盖了设计文档的概念,以及它们如何成为有价值的文档,让我们能够设计和构建更稳健的数据平台和可扩展的数据组件。
本文介绍的部分并不一定需要出现在你自己版本的设计文档中。相反,最重要的是记住在构建数据管道和组件时要有意识。
如果你想获取更多数据工程内容,可以订阅我的新闻简报《数据浓缩》,我在其中讨论了与数据工程和技术相关的各种主题:
[## 数据浓缩 | Mahdi Karabiben | Substack
数据工程更新和评论,伴随你的下午浓缩咖啡。点击阅读 Mahdi 的《数据浓缩》……
dataespresso.substack.com](https://dataespresso.substack.com/?source=post_page-----d49550f95580--------------------------------)
使用 GPT-4 写歌曲:第一部分,歌词
原文:
towardsdatascience.com/writing-songs-with-gpt-4-part-1-lyrics-3728da678482
如何使用 OpenAI 最新的语言模型来帮助创作原创歌曲的歌词
·发布于 数据科学 ·阅读时长 16 分钟·2023 年 4 月 18 日
–
“年轻的说唱歌手在工作室里对着麦克风唱歌,耳机佩戴着,背景有电脑屏幕,” 图像由 AI 图像创作程序 Midjourney 创建,并由作者编辑
过去三年,我一直在撰写关于 OpenAI 大型语言模型的各种迭代,包括使用 GPT-3 [1] 创作音乐 和 ChatGPT [2],也就是 GPT-3.5,来写诗。在对最新语言模型 GPT-4 [3] 进行实验后,我发现它能够创作讲述连贯故事并押韵的歌词。
在这篇文章中,作为三部分系列中的第一部分,我将讨论 GPT-4 的背景,并将其写歌词和音乐的能力与 GPT-3 进行比较。接下来,我将展示 GPT-4 如何从当前乐队的歌词中阅读并创作他们风格的歌曲。最后,我将进行关于使用 AI 写音乐的一般讨论,并提出一些后续实验步骤。
在第二部分中,我将探讨 GPT-4 如何为歌曲创作和弦,在第三部分中,我将使用该系统创作伴随歌词的新旋律。
介绍 GPT-4
3 月 14 日,我收到了一封来自 OpenAI 的电子邮件,通知我可以使用他们的新语言模型 GPT-4。以下是他们在技术报告中对模型的描述。
我们报告了 GPT-4 的发展情况,这是一个大规模的多模态模型,能够接受图像和文本输入并生成文本输出。虽然在许多现实世界的场景中不如人类,但 GPT-4 在各种专业和学术基准上表现出人类级别的性能,包括在模拟律师考试中得分接近前 10% 的考生。GPT-4 是一个基于 Transformer 的模型,经过预训练以预测文档中的下一个标记。后期训练对齐过程导致在事实性和遵循期望行为的衡量标准上表现有所提高。OpenAI,GPT-4 技术报告 [3]
报告还讨论了 OpenAI 在改进 GPT-4 模型的安全性和对齐性方面所采取的步骤,以使系统“遵循人类价值观和人类意图。”他们强调了使用超过 50 名领域专家进行对抗性测试,如何建立了一个模型辅助的安全管道,以及如何在之前的模型上改进了安全指标 [3]。
新模型不是免费的。OpenAI 收取每月 20 美元的 ChatGPT Plus 费用,这样可以使用新的 GPT-4 聊天机器人。当我注册并登录后,我可以看到三个聊天模型的选项。
ChatGPT 三种模型选项的描述,来自 OpenAI 的截图
你可以看到 OpenAI 如何提升了 GPT-4 的“推理”和“简洁”水平。
请注意,默认情况下,OpenAI 将保留用户的输入和生成的响应“以改进模型性能”,正如他们在数据政策文档中所述。这意味着他们可以使用这些数据来训练他们的模型。我选择通过使用此处的表单来选择不参与他们的数据收集。
比较编写歌词的模型
在使用新的 GPT-4 系统进行实验后,我发现与原始的 GPT-3 模型相比,响应质量有了显著提高,尤其是在押韵词方面。
使用 OG 模型 GPT-3 编写歌词
这是我使用原始 GPT-3 模型编写歌曲的尝试。我使用了“副歌”这个词,指的是两行押韵的歌词。
RobG: 为一首关于狗和猫的摇滚歌曲的第一节写歌词,每对副歌的结尾要押韵。
GPT-3:
狗和猫一起生活
完美和谐地交融
奔跑和玩耍
直到上床睡觉的时候
侧身蜷缩在一起
在一个毛茸茸的小球中
我们最爱的宠物
使我们的家变得温馨
好吧,这些歌词描绘了一个可爱的小故事。然而,没有任何副歌押韵,而且歌词的节奏也不太匹配。
使用新模型编写歌词
以下是新的 GPT-4 模型如何回应相同提示的结果。
RobG: 为一首关于狗和猫的摇滚歌曲的第一段写歌词,每对押韵的句子结尾处押韵。
GPT-4:
狗和猫,它们在街上游荡
毛茸茸的朋友,心跳不已
爪子和爪垫,他们主宰这片土地
摇摆的尾巴,他们心领神会
彼此并肩,追逐风的脚步
紧密相连,最好的朋友
他们在月光下摇滚
狗和猫,它们超出了视线
啊,好多了!大部分押韵不错。将“wind”与“friends”押韵有点勉强。但措辞很稳,每行的节拍也很一致。
以你的乐队风格创作音乐
为了看看 GPT-4 是否能以特定风格创作音乐,我联系了几支本地乐队,询问是否可以用他们的歌词作为参考来创作歌曲。他们都同意了。
我开始让 GPT-4 创作风格类似于Rhode Iceland的歌词,这是一支来自麻省洛厄尔的另类摇滚乐队,Hi Fi Monk,一家位于波士顿的嘻哈/放克/雷鬼乐队,以及The Agents,一家位于普罗维登斯的 ska 乐队。
分析歌词
为了使 GPT-4 能够分析这三支乐队的歌曲,我编写了一些代码,利用两个开源项目从音频文件中获取歌词的转录。我使用了Whisper,这是 OpenAI 的语音转文本 AI 模型[4],来转录歌词。然后,我将转录后的歌词输入 GPT-4,以标示歌曲的部分,即,段落、副歌等。你可以在我的 Google Colab 上运行我的代码,这里。
Rhode Iceland,图片使用已获许可
欢迎来到 Rhode Iceland
首先,我让 GPT-4 分析了 Rhode Iceland 的歌曲《Bloody Brain》,通过输入歌词进行分析。请注意,新模型能够处理比以前更多的文本。GPT-3.5 只能处理 4,000 个标记,相当于 3,125 个词。但 GPT-4 有两个版本,一个处理 8,000 个标记,另一个处理 32,000 个标记,相当于惊人的 25,000 个词。这是我的提示。
RobG: 分析 Rhode Iceland 乐队的歌曲《Bloody Brain》的歌词。
[第一段]
沿着隐秘的上游行走
朝着血腥消失的大脑
我想要的什么都不属于我
我想要一切
让它燃烧
我想要一切
让它成为我的
希望能忘掉我的美好时光
但已经太晚了*
[副歌]
继续前行
继续前行和离开
让我离开你的脑海
让我离开你的心
走出我的脑海
走出我的心*
[副歌]
继续前行和离开
让我离开你的脑海
继续前行和离开
让我离开你的心
继续前行
继续前行*
[结束曲]
让我离开你的脑海
走出我的心
走出我的脑海
让我离开你的心*
GPT-4: Rhode Iceland 的“Bloody Brain”似乎是一首充满内省和情感的歌曲,涉及脱离、控制和放下过去关系的挣扎等主题。
第一段的歌词传达了一种矛盾感,讲述者既渴望掌控某些生活的方面,又希望放手控制。重复的副歌强调了继续前行和脱离造成困扰的情感联系的必要性。歌词中的“把我从你的脑海中移出来”和“把我从你的心中移出来”表现出对讲述者和对象释放过去关系的持续束缚的恳求,展示了想要坚持和需要自由之间的内心挣扎。歌曲的结尾重申了副歌,突出了放手和前进的重要性。
总的来说,“Bloody Brain”展现了情感的复杂性和在关系中放弃控制的困难,为艺术家和听众提供了情感的释放。
这个分析非常准确。如果你听听 Bloody Brain,确实会觉得它充满了内省和情感。然而,它没有注意到第一段副歌中的视角转换,所以我问了一下。
RobG: 你怎么看第一段副歌中的这些歌词。
把我从你的脑海中移出来
把我从你的心中移出来
走出我的脑海
走出我的心*
ChatGPT: 在“Bloody Brain”的第一段副歌中,歌词似乎传达了情感纠葛和渴望摆脱的感觉。歌词中的“把我从你的脑海中移出来”和“把我从你的心中移出来”表明歌者希望从他人的思想和情感中抽离。这可能是因为他们的存在给对方带来了痛苦或使对方的生活变得复杂。
另一方面,歌词“走出我的脑海”和“走出我的心”表明歌者也在与与对方相关的思想和情感作斗争。他们希望从这种心理和情感的依附中解放出来,以获得清晰、疗愈并继续前行。
这看起来已经很清楚了。改变代词确实对短语的意义产生了很大影响。在 GPT-4 提供歌词分析后,我让它创作了一首相似风格的歌曲。
RobG: 按照相同风格写一首接续“Bloody Brain”的歌曲。
GPT-4:
标题:“渐逝的回声”
[第一段]
漂浮在阴影中,未被看见
追逐像破碎梦一样的回忆
在空白处寻求安慰
留在迷茫中
我想打破束缚我的链条
不再被束缚
我尝试过疗愈,但依然盲目
迷失在迷宫中
[副歌]
继续前行
继续前行
从你的掌握中解放我
从你的灵魂中解放我
从我的掌握中解放出来
从我的灵魂中解放出来
[副歌] …
[桥段]
随着回声慢慢消逝
我们展开翅膀飞翔
拥抱未知
一段我们独自面对的旅程
[第二段]
迈入全新的一天
我们的幽灵开始崩溃
我想呼吸如此清新的空气
让它愈合
我想画一个如此明亮的世界
爱与痛苦可以重聚
我已找到赢得这场战斗的力量
我正在学习去感受
[副歌 x 2] …
歌词看起来不错。稍显平淡,还有不少陈词滥调。但我确实喜欢那些作为抽象小插曲呈现的视觉效果。GPT-4 列出了所有副歌,但我省略了重复部分。我注意到系统在新歌中大多数情况下押韵了每对对句。押韵很扎实,但风格与“Bloody Brain”有所不同,后者几乎没有押韵。不过,我确实喜欢段落中的复杂 AAAB-CCCB 押韵结构。
Hi Fi Monk,图片使用许可
向 Hi Fi Monk 打个招呼
Hi Fi Monk 有一个 很棒的视频 展示了他们的曲目《Break》的录制过程,带有深刻的放克节奏。
首先,我从 Whisper 那里获得了转录。这里是左侧的原歌词和右侧的自动转录的比较。转录错误用黄色标记。
(左) 《Break》歌词由 Hi Fi Monk 提供,(右) 歌词由 Whisper 转录,图片由作者提供
考虑到音乐在声乐下播放,转录的质量还不错。但确实漏掉了一些关键短语,比如“棕色皮肤的血”。
我请 GPT-4 分析了这首歌。我这里只展示了歌词的摘录版本,但我将所有 1,000 个字输入系统进行分析。
RobG: 分析 Hi Fi Monk 的歌曲《Break》的歌词和押韵风格。
[前奏]
圣约翰,无畏者,来打破所有这些枷锁。
但你必须说实话,孩子。
你必须说实话。*
[副歌] 这才是真实的。这才是交易。
不再有棕色皮肤的血可以流淌
不再有红色土地可以盗窃
不知怎么地找到疗愈的方法
破除链条。突破重围。
在他们打破你之前,先挣脱束缚。
事情是真的。保持真实。自由呼喊。第二次尝试。
GPT-4: Hi Fi Monk 的《Break》歌词围绕边缘化社区,特别是非裔美国人所面临的斗争、压迫和韧性主题展开。歌词触及了种族主义、文化挪用、警察暴行、大规模监禁,以及突破社会约束的渴望。
歌词中的押韵风格可以被描述为结尾押韵和内部押韵的混合,使用这两种方式来创造节奏感和流畅感。结尾押韵是指句子的最后音节押韵,而内部押韵是指在句子内部发生的押韵。歌曲的押韵模式不一致,这增加了其原始和自然的感觉。
这是对歌曲的良好分析。它捕捉到了歌词中围绕社会不公影响的关键主题。它迅速分解了歌曲中的押韵风格,并在过程中定义了一些术语。
这次,当我要求 GPT-4 写一首新歌时,我明确告诉它要匹配押韵风格。
RobG: 按照相同风格,写一首《Break》的续集,包括押韵模式。标记歌曲部分。
GPT-4 “战场声音”
[第 1 段]
破裂的人行道,孩子们玩耍,
在阳光下,又是一天,
街道的心跳,梦想无拘,
在混乱中,声音获得。
破碎的瓶子,未说出的故事,
勇敢和大胆的故事,
角落的预言者,讲述真相,
背景是我们的青春。
[合唱]
崛起,昂首
不再有锁链,我们将打破它们
撕碎墙壁,拆掉它们
我们的声音将震撼这片战场
崛起,昂首
不再有锁链,我们将打破它们
撕碎墙壁,拆掉它们
我们的声音将震撼这片战场
[第 2 段]
崩溃的墙壁,涂鸦斑驳,
嵌入的希望信息,
消防通道,临时舞台,
为已打响和脱离的战斗。
警报的闪光,母亲的哭泣,
从疲惫的眼中落下的泪水,
在黑暗中,一道火花点燃,
星光黯淡的夜晚中的希望闪烁。
[合唱] …
[桥段]
在阴影中,我们找到力量
通过裂缝,我们将铺就道路
手牵手,我们将超越
我们团结一心,爱的力量
[第 3 段]
街灯闪烁,随着黄昏,
夜幕降临,静默,
生命的节拍,城市的歌,
在节奏中,我们归属。
共享的欢笑,打破面包,
爱与善良,心灵得到滋养,
我们团结一致,面对战斗,
张开双臂,拥抱光明。
[合唱] …
[结尾]
在寂静中,回响,
我们带来的希望故事,
并肩作战,我们将塑造我们的命运,
一起,我们将照亮。
这也似乎合理。歌曲的基调类似于“Break”,有着充满力量和振奋的合唱。我喜欢歌词中描绘城市生活的文字和桥段中“在阴影中,我们找到力量。通过裂缝,我们将铺就道路。”的巧妙词句。
大多数对句都有结尾押韵,还有一些内部押韵,比如“黑暗”和“火花”在“在黑暗中,一道火花点燃。星光黯淡的夜晚中的希望闪烁。”中。
总体来看,这些歌词似乎经过深思熟虑并精心制作,但有点基础,没有“Break”中的那种细腻。
特工,图片使用经许可
特工:发号施令
我的第三个也是最后一个项目是写一首风格类似于特工乐队的 ska 风格的歌。我开始让系统分析特工的歌曲“Grow。”
RobG: 分析特工乐队的歌曲《Grow》的歌词和和弦。
*[第 1 段]
在 D 调的起点,我第一次遇见你
我第一次握住你的手
我第一次看进你的眼睛
我告诉过你我爱你*
*[第 2 段]
从那一天起,直到永远
那些困扰的时光,悲伤与笑声
手牵手,现在我们一起走
现在无法想象更好的事情*
*[合唱]
成长,让你的爱成长,成长
让你的爱来,崛起,崛起
播下种子,让你的爱成长
更高更高*
GPT-4
“Grow”由 ska 乐队 The Agents 演唱,是一首反映浪漫关系各个阶段和时刻的情歌。歌词描绘了爱的初期感受、关系的成长以及两人之间的深厚纽带。歌曲的整体信息是培育爱情,让其充分成长。
歌词强调了爱情和伴侣关系的重要性,如“第一次见到你女孩”,“手牵手,我们现在一起走”,“现在无法想象更好的事物。”重复的“成长,让你的爱成长,成长”突显了歌曲关于爱情成长和发展的中心主题。
系统提供了对这首歌的出色和简洁的分析。它捕捉到了歌曲的核心主题,即关系的成长,并提炼了歌词中的几句关键台词以强调这一点。
与上述前两个实验不同,这次我给 GPT-4 一个新的主题,并让它写出五个可能的歌曲标题及描述。
RobG: 为五首关于克服恐惧的歌曲创建标题。每首歌附带一句描述其含义的句子。
GPT-4:
“突破阴影”
这首歌讲述了找到内在力量和勇气,走出舒适区,面对未知。
“无畏心跳”
一首强有力的颂歌,庆祝人类精神的韧性,鼓励听众拥抱恐惧,将其转化为个人成长的驱动力。
“超越风暴”
这首歌讲述了克服逆境和挑战的故事,阐明了面对恐惧如何带来新的力量和自我发现。
“解放勇气”
一首激励歌曲,强调摆脱恐惧和自我怀疑的束缚,敦促个人以不懈的决心追求梦想。
“与恐惧共舞”
一首鼓舞人心的曲目,鼓励听众接受并承认他们的恐惧,将其作为个人成长和转变的催化剂。
这些都不错,尽管读起来像是励志海报。但总体来说,我认为“与恐惧共舞”是这批中最好的。而且我知道 ska 风格的音乐非常适合跳舞。
正如我在上面的例子中所做的,我让 GPT-4 为这首新歌写了歌词。
RobG: 写出“与恐惧共舞”的歌词。
GPT-4:
[第一部分]
醒来迎接崭新的一天,
感受到恐惧却不转身,
面对未知,这就是我们开始的地方,
以开放的心态和无畏的心。
[前副歌]
不再隐藏,不再怀疑,
是时候让我们的勇气释放出来了。
[副歌]
与恐惧共舞,不要逃避,
拥抱挑战,无论发生什么。
找到你的节奏,面对未知,
随着每一步,你的力量在增长。
[第二部分]
在黑暗中,我们将找到光明,
在梦想的引导下腾飞。
不再颤抖,不再害怕,
我们将一起飞向新的高度。
[前副歌] …
[副歌] …
[桥段]
当恐惧敲你的门时,
高高站立,再次面对它。
旅程漫长,但你将发现,
你比你意识到的更强大。
[副歌] …
[尾声]
所以与恐惧共舞,让勇气引领,
我们一起征服,一起成功。
跨出这一步,你将看到,
你会找到你的力量,你会自由。
哇,这非常好!虽然有点老套,因为充满了激励性声明。而且,它再次让所有的对句押韵,这对歌曲来说是好的。我注意到桥段中的最后一对句子并没有完全押韵。
旅程漫长,但你将发现,
你比你意识到的更强大。
所以我问 GPT-4 看看它是否能修复它。
RobG: 重新编写桥段的最后两行,使词语押韵。
GPT-4:
旅程漫长,但要记住这一点,
你比你将要发现的恐惧更强大。
这是一个很好的、富有创意的修复。如果你不喜欢它写的东西,给它一些建设性的反馈;它通常能很好地做出积极的改变。这与我将 AI 系统视为写作伙伴的观点一致。
总结
我展示了 GPT-4 如何写新的歌词,结合了不同的押韵方案。我展示了如何让系统参与讨论现有歌词的风格和意义,然后再让它写新歌词,作为一种预处理方式。
下一步
下一步可能包括对系统在平衡良好的散文写作和遵循定义好的押韵结构方面的优缺点进行更严格的探索。下一步还可能包括通过图表分析歌词中的音节和重音模式来检查韵律。请查看本系列的第二部分和第三部分,了解如何使用 GPT-4 为歌曲编写和旋律。
讨论
虽然 GPT-4 在写歌词方面比早期的语言模型更好,但它远非完美。充其量,它只是一个还算可以的词曲创作者和有帮助的写作伙伴。然而,AI/ML 在自然语言处理中的进展趋势目前正呈指数级提升。这对词曲创作者和音乐爱好者意味着什么呢?
从我所见,词曲创作者和音乐家对新技术的使用有着不同的看法;有些人接受它,有些人否定它,但大多数人最终会使用它,如果它有帮助的话。我认为这对使用 AI 模型也适用。这就像使用在线押韵词典来完成一段歌词。它可能有帮助,也可能没有,但词曲创作者会尝试一下,并做出决定。
大部分情况下,我认为观众并不太在意歌曲创作者和音乐家使用了什么工具来创作他们的歌曲。例如,我们知道 Auto-Tune 在幕后经常被用来修正歌唱表现。当用于正常设置时,大多数人无法察觉,也可能不在意。直到谢尔在《Believe》中将其调到硬调模式,以及T-Pain将其作为音乐的明显效果时,这才引起公众注意。我认为语言模型也会经历相同的周期。随着模型的改进,大多数粉丝不会察觉它们的使用,也可能不在意。如果歌曲好,他们会喜欢它们。
源代码
本项目的源代码可以在 GitHub 上找到。
知识共享 署名-相同方式共享
致谢
我想感谢来自罗德岛的 Jon Gryckiewicz,来自 Hi Fi Monk 的 Fez Aswat,以及来自 The Agents 的 Pete Fayan 对本项目的参与。我还想感谢 Jennifer Lim 审阅本文并提供反馈。
更多关于使用 GPT-4 创作歌曲的信息
这是本系列的第二篇和第三篇文章。
使用 GPT-4 创作歌曲:第二部分,和弦
如何使用 OpenAI 最新的大型语言模型来帮助创作原创歌曲的和弦
使用 GPT-4 创作歌曲:第二部分,和弦 ## 使用 GPT-4 创作歌曲:第三部分,旋律
如何使用 OpenAI 最新的语言模型来帮助创作新歌曲的旋律
使用 GPT-4 创作歌曲:第三部分,旋律
参考文献
[1] T. Brown 等,语言模型是少样本学习者 (2020) NeurIPS 2020
[2] J. Schulman 等,介绍 ChatGPT (2022)
[3] OpenAI, GPT-4 技术报告 (2023)
[4] A, Radford 等,大规模弱监督下的鲁棒语音识别 (2022)
使用 GPT-4 创作歌曲:第二部分,和弦
原文:
towardsdatascience.com/writing-songs-with-gpt-4-part-2-chords-173cfda0e5a1
如何使用 OpenAI 最新的大型语言模型帮助创作原创歌曲的和弦
·发表于Towards Data Science ·15 分钟阅读·2023 年 5 月 10 日
–
“一位音乐家在专业录音室里弹奏原声吉他,戴着耳机,旁边有电脑屏幕,” 我使用 AI 图像生成程序 Midjourney 创建的图像,并由作者编辑。
这是关于使用 OpenAI 新款 GPT-4 语言模型[1]作曲的三部分系列文章中的第二篇。在第一篇文章中,我探讨了使用该模型为歌曲创作歌词。这一篇中,我使用系统为歌曲编写和弦。我将在第三篇文章中探讨如何创作旋律。
GPT-4 背景
GPT-4 是 OpenAI 最新的大型语言模型。可以通过他们的ChatGPT用户界面使用,并通过他们的API访问。新模型作为付费 ChatGPT Plus 订阅的一部分提供,每月费用为 20 美元。正如我在上一篇文章中提到的,OpenAI 会捕捉你的输入和回应,这些数据可能会用于训练未来版本的模型。这是默认启用的,但你可以通过他们的表单在这里选择退出数据收集。
GPT-4 的响应显著优于之前的 GPT-3.5 模型。根据 OpenAI 的技术报告,新模型在 SAT 考试中获得了 1600 分中的 1400 分(语言 710 分,数学 690 分),而早期模型获得了 1260 分(语言 670 分,数学 590 分)。
尽管测试分数优秀,OpenAI 报告称系统输出并不总是可靠的,并且可能展示从训练数据中学到的偏见。
尽管 GPT-4 具有一定的能力,但它与早期的 GPT 模型有类似的局限性:它并不完全可靠(例如可能出现“幻觉”),有一个有限的上下文窗口,并且不会学习。在使用 GPT-4 的输出时应小心,特别是在可靠性很重要的上下文中。……GPT-4 可能生成潜在有害的内容……它可能表现出各种社会偏见和世界观,这些可能不代表用户的意图或广泛共享的价值观。—— OpenAI [1]
这听起来令人害怕且不祥。但是对于我在这个项目中做的事情,即为歌曲生成和弦,风险要小得多。
使用 GPT-4 为歌曲创建和弦
在我之前的文章中,我让 GPT-4 为一首关于猫和狗的摇滚歌曲创作歌词。这是我第一次尝试让模型为这首歌创建和弦。
RobG: 为这首摇滚歌曲的第一段写和弦。
*狗和猫,它们漫游在街头
有心跳的毛茸茸的朋友
爪子和脚掌,它们统治着这片土地
尾巴摇摆,它们懂得*
*并肩追逐着风
牢牢相依,最好的朋友
它们在月光下摇滚
狗和猫,它们不见了*
GPT-4: 这是这首歌第一段的和弦:
G C
狗和猫,它们漫游在街头
Em D
有心跳的毛茸茸的朋友
G C
爪子和脚掌,它们统治着这片土地
Em D
尾巴摇摆,它们懂得
Am C
并肩追逐着风
G D
牢牢相依,最好的朋友
G C
它们在月光下摇滚
Em D
狗和猫,它们不见了
和弦看起来相当不错,尽管有些基础。像大多数大型语言模型一样,GPT-4 在大量书籍和互联网文本上进行训练,它似乎从讨论和弦中学到了足够的内容来生成不错的和弦序列。我喜欢进程的 AABA 结构:G — C — Em — D,G — C — Em — D,Am — C — G — D, G — C — Em — D。
然而,文本格式存在问题。和弦与歌词的配合不一致,即,“D”和弦应该与最后一行的“they’re”或“out”对齐。我找到了一种效果不错的替代方法:将和弦与歌词对齐。我只是想问问。
RobG: 以方括号中带有空格的形式显示和弦与歌词对齐。
GPT-4:
[G] 狗和猫,它们 [C] 漫游在街头
[Em] 有心跳的毛茸茸的朋友 [D]
[G] 爪子和脚掌,它们 [C] 统治着这片土地
[Em] 尾巴摇摆,[D] 它们懂得
[Am] 并肩追逐着风 [C]
[G] 牢牢相依,[D] 最好的朋友
[G] 它们在月光下摇滚 [C]
[Em] 狗和猫,它们 [D] 不见了
啊,好得多了。因为“they’re”用作下一个和弦开始之前的起始音符,所以在最后一行的“out”之前开始 D 和弦是有意义的。
除了生成和弦进行,GPT-4 还解释了与音乐理论相关的内容。因此,我偶尔会向它询问我正在处理的歌曲的问题,比如这样的问题。
RobG: 这是什么调的?
GPT-4: 为这首摇滚歌曲提供的和弦是在 G 大调中。G 大调包括以下和弦:G(I)、Am(ii)、Bm(iii)、C(IV)、D(V)、Em(vi)和 F#dim(vii°)。
这看起来是正确的。我很感激对 G 大调中使用的和弦进行了详细解释。注意,它既使用了和弦的字母名称,又使用了罗马数字符号,其中大调和弦用大写字母表示,例如(I),而小调和弦用小写字母表示,例如(ii)。我喜欢它使用‘°’字符来表示减和弦的方式。
我使用了来自PG Music的商业应用 Band-in-a-Box(BiaB),以听和弦的声音。我输入和弦名称,粘贴了相应的歌词,选择了“摇滚”风格,然后它渲染了歌曲。请注意,这里没有旋律,因此可以随意跟着你的旋律唱。
猫与狗,歌词和和弦由 GPT-4 提供,制作人:作者
听起来不错。和弦序列很好,BiaB 在吉他、贝斯和鼓部分做得很出色。没有声乐旋律,旋律最好的部分是每个短语结尾的吉他填充。
接下来,我将展示如何使用 AI 从歌曲录音中提取歌词和和弦。
使用 AI 从歌曲中提取歌词和和弦
在上一篇文章中,我展示了如何使用 OpenAI 的 Whisper 模型[2]从音频文件中转录歌词。对于这个项目,我编写了一些代码,使用另一个神经网络 Autochord 提取和弦并将它们拼接在一起。
Autochord 模型由软件工程师和机器学习爱好者 C. J. Bayron 创建和训练。它运行良好。你将一个音频文件输入其中,几秒钟后,你会得到一个开始时间、结束时间和和弦的列表。这里是他在线应用中模型结果的一个可视化示例。你可以按照这里的说明生成一个标签文件。
自动和弦可视化,图片由作者提供
它只找到大调和小调和弦,但这对我的目的来说已经足够了。然后,我用 Whisper 的输出和单词时间,编写了一些 Python 代码,将和弦与歌词整合在一起。例如,下面是一个非常著名的歌曲的渲染效果。
生日快乐,由 Patty Hill 和 Mildred J. Hill 创作,录音由作者提供
这里是使用 Whisper 和 Autochord 分别转录的歌词和和弦。
[C] 祝你生日快乐,[G] 祝你生日快乐,[C] 祝你生日快乐,[G] 祝你生日快乐!
[C] 祝你生日快乐,[F] 亲爱的读者,[C] 祝你生日快乐,[G] 祝你生日快乐!
这看起来相当不错。所有的和弦都预测得很准确。它甚至捕捉到了最后三个词的快速转换。F 大调和弦的变化应该在“亲爱的”一词之后,但这只是唯一的错误。
不过,请注意短语没有被正确拆分。这是基于 Whisper 模型计算的短语分割。为了解决这个问题,我将转录文本输入到 GPT-4 中,使用了以下提示。
RobG: 这里是歌曲的和弦和歌词。
*[C] 生日快乐 [G] 你,生日快乐 [C] 你,
[C] 生日快乐 [F] 亲爱的读者,生日 [C] 快乐 [G] 祝 [C] 你!
在逗号处将歌曲拆分成较短的行,并在行首显示当前和弦。
GPT-4:
[C] 生日快乐 [G] 你
[G] 生日快乐 [C] 你
[C] 生日快乐 [F] 亲爱的读者
[F] 生日 [C] 快乐 [G] 祝 [C] 你!
好的,这样更容易阅读。系统将能够以这种格式分析和生成歌词及和弦,如你将在下一部分看到的那样。
为新歌曲编写和弦
在我编写代码提取歌曲歌词和和弦后,我的下一步是请求 GPT-4 分析现有曲调中的和弦。我选择了由来自罗德岛普罗维登斯的 ska 乐队 The Agents 创作和演唱的歌曲“Grow”。他们同意让我使用 AI 分析他们的歌曲,并利用分析结果创作一首类似风格的新歌。
The Agents,照片经许可使用
我运行了 Python 代码从录音中获取歌词和和弦,并使用 GPT-4 按照我上面描述的技术格式化文本。这里是我用来获取和弦分析的提示。我只展示了一个片段,但我将完整的歌词输入了 GPT-4。
RobG: 分析这首歌“Grow”中的和弦。
[第一部分]
[Em] 是的!在那一天,我第一次 [C] 遇见
[C] 你女孩,我第一次 [G] 握住
[G] 你的手,我第一次 [B] 看向
[B] 你的眼睛,我告诉你我爱你
[Em] 从那天起直到永远
[C] 困扰的时光,悲伤,
[C] 笑声
[G] 手牵手,我们现在一起走
[B] 现在无法想象更好的东西了*
[副歌]
[Em] 成长,让你的爱
[G] 成长,[C] 成长
[C] 让你的爱来临
[G] 振作起来,振作起来
[G] 播下种子,让 [B] 你的
[B] 爱情成长,越来越高* . . .
GPT-4: 在 The Agents 的歌曲“Grow”中,有几个不同的和弦进程出现在歌曲的不同部分。这些进程赋予了歌曲结构和情感内容。以下是对每个部分和弦进程的分析:
主歌:主歌的和弦进行是 Em — C — G — B。这个进行包含了大调和小调和弦,创造了张力与释放的平衡。Em(小调)到 C(大调)的过渡带来了一种渴望感,而从 G(大调)到 B(大调)的转移则增加了振奋感。
副歌:副歌的和弦进行是 Em — G — C — G — B。这个进行以与主歌相同的 Em — G — C 开始,但将最后的 B 和弦替换为 G,然后再到 B。这种轻微的变化保持了主歌的振奋感,但在转到 B 之前增加了额外的张力和释放。
桥段:桥段有不同的和弦进行:Bm — G — B — Em — C — G。它以 Bm(小调)和弦开始,增加了一种更阴暗、更内省的质量。接着,进行通过 G(大调)、B(大调)和 Em(小调)和弦,创造出一种积累和期待感,然后返回到主歌和副歌中熟悉的 C — G 和弦。
间奏:间奏的和弦进行较为简单:C — B — Eb — C — Em — G。这个进行为主歌和副歌中的主要和弦进程提供了一个休息,增加了变化,并保持了听众的参与感。
总结来说,《Grow》由 The Agents 创作,使用了大调和小调和弦的组合,在整首歌中创造了张力与释放的平衡。副歌和主歌共享类似的和弦进行,而桥段和间奏则提供了对比和变化,以保持听众的兴趣。
哇,那是对和弦进行的全面分析。看来 GPT-4 对音乐理论了解得很好,并且总结了听众如何反应歌曲的不同部分。
在同一个聊天会话中,我让模型使用类似风格为歌曲创建和弦。我使用 GPT-4 在这一系列的第一部分中创作了这些歌词。
RobG: 为这首歌创建类似风格的和弦。
标题:“与恐惧共舞”*
[第一段]
醒来迎接全新的一天,
感受恐惧但不退缩,
面对未知,这就是我们的起点,
带着开放的心态和无畏的心。*
[前副歌]
不再隐藏,不再怀疑,
是时候释放我们的勇气了。*
[副歌]
与恐惧共舞,不要逃跑,
拥抱挑战,无论发生什么。
找到你的节奏,面对未知,
每一步,你的力量在增长。*
[第二段]
在黑暗中,我们会找到光明,
在梦想的引领下起飞。
不再颤抖,不再恐惧,
一起飞向新的高度。*
*[前副歌] …
[副歌] …*
[桥段]
当恐惧敲你的门时,
站直,面对它。
旅途漫长,但你会发现,
你比你意识到的更强大。*
[副歌] …
[尾声]
与恐惧共舞
与恐惧共舞
与恐惧共舞
与恐惧共舞*
GPT-4:
标题:“与恐惧共舞”
[主歌]
[Em] 醒来迎接一个[G]崭新的一天,
[D] 感受到恐惧却[A]不退缩,
[Em] 面对未知,[G] 就是我们的起点,
[D] 心怀开放和[A]无畏的心。
[Pre-Chorus]
[Am] 不再隐藏,[C] 不再怀疑,
[G] 是时候释放我们的[D]勇气了。
[Chorus]
[Bm] 与恐惧共舞,[C] 不要逃跑,
[G] 拥抱挑战,[D] 无论发生什么。
[Bm] 找到你的节奏,[C] 面对未知,
[G] 每一步,你的[D]力量都在增长。
[Verse 2]
[Em] 在黑暗中,[G] 我们将找到光明,
[D] 被梦引导,[A]展翅高飞。
[Em] 不再颤抖,[G] 不再害怕,
[D] 一起飞向[A]新的高度。
[Pre-Chorus] …
[Chorus] …
[Bridge]
[Am] 当恐惧在你门前敲击[Em],
[C] 高昂地站立,再次面对[D]。
[Am] 旅程漫长,但[Em]你会发现,
[C] 你比你[D]意识到的更强大。
[Chorus] …
[Outro]
[Em] [G] 与恐惧共舞
[D] [A] 与恐惧共舞
[Em] [G] 与恐惧共舞
[D] [A] 与恐惧共舞
我首先注意到它将生成的和弦放在方括号中,与歌词对齐,这很不错。它从我之前的互动中采纳了这种标记风格。其次我注意到它也在 G 大调,就像分析的歌曲“Grow”一样。
这里是和弦进行的对比。
和弦进行比较,图片由作者提供
你可以看到,虽然和弦进行有一些相似之处,但也有一些明显的不同。例如,“Grow”有一些使用 4、5 和 6 和弦的段落,而“与恐惧共舞”始终使用四个和弦进行。
两首歌都大量使用了 Em、G 和 C 和弦。“Grow”混合了 B 和 Bm,而“与恐惧共舞”则混合了 A、Am 和 D。参考一下 GPT-4 之前关于 G 大调的说法。
G 大调由以下和弦组成:G (I)、Am (ii)、Bm (iii)、C (IV)、D (V)、Em (vi) 和 F#dim (vii°)。
“Grow”偶尔使用调外的 B 和弦,而“与恐惧共舞”使用了调外的 A 和弦。我特别喜欢从副歌到前副歌的 A 到 Am 过渡。为了了解更多关于这个过渡的内容,我问了 GPT-4。
RobG:如果一首歌的和弦从 A 变为 Am,而这首歌是 G 大调的,那这叫什么?
GPT-4:在音乐理论中,使用一个与调性不一致的和弦称为“色彩和弦”或“色彩化”。在 G 大调中从 A 大调到 A 小调,A 大调和弦不是调性和弦,因此产生了张力或不和谐的感觉。当和弦变为 A 小调时,音乐回到调性和弦,产生了解决或放松的感觉。
好了,就是这样。我想我喜欢这种和弦变化,因为它回到了大调和弦。这里是带有歌词和和弦的歌曲,你可以自己听听。再次说明,伴奏轨道由 Band-in-a-Box 提供。
与恐惧共舞,歌词和和弦由 GPT-4 提供,制作人:作者
Band-in-a-Box 应用没有为 ska 音乐设置选项,所以我选择了雷鬼风格,并将节奏从每分钟 85 拓展到 150。我还将第二段中的贝斯和鼓去掉,雷鬼音乐中称为“节奏”,并在桥段中去掉了铜管乐器,以增加歌曲的趣味性。总体而言,我认为这首歌相当不错,和弦进行也很奏效。当然,缺少的部分是人声旋律,但我将在这一系列的第三篇也是最后一篇文章中解决这个问题。
查看附录中的另外两首风格为另类摇滚和嘻哈的曲子。
总结与下一步
在这篇文章中,我提供了一些关于 OpenAI 的新 GPT-4 模型的背景信息。我展示了如何使用 Whisper 和 Autochord AI 模型从歌曲中提取歌词和和弦,并使用我在 Google Colab 上的 Python 代码将二者合并。我接着展示了 GPT-4 如何分析现有作品的和弦进行,并为各种风格的新歌曲建议和弦。
我的下一步是使用 GPT-4 为歌曲创作旋律,根据歌词和和弦。我将在系列的最终文章中对此进行详细介绍。
讨论
在没有特定引导的情况下,GPT-4 在创作歌曲时似乎是按照一定的公式进行的。例如,它倾向于使用*(A) 诗句, (B) 副歌, (A) 诗句, (B) 副歌, © 桥段, (B) 副歌, 和 (A) 尾声*的形式来创作歌曲。而且它总是使用四和弦模式来构建歌曲部分。
默认情况下,它会使用调式中的常见和弦,但正如你上面所见,你可以引导它使用半音和弦。一般来说,它生成的和弦模式听起来不错。我完全没有使用“再生成”命令。而且这些模式似乎是独特的,偶尔会有创新的火花。
在我上一篇文章的讨论中,我假设大多数音乐爱好者不会太在意他们发现词曲作者使用 AI 系统来帮助创作歌曲歌词。这对于和弦创作也很可能是如此。如果最终歌曲质量很好,那么粉丝们会喜欢这些歌曲,无论使用了什么工具。
源代码
该项目的源代码可以在 GitHub 上找到。
知识共享署名-相同方式共享 4.0 国际许可协议
致谢
我想感谢 Agents 的 Pete Fayan 对这个项目的投入。我还感谢来自 Rhode Iceland 的 Jon Gryckiewicz 和 Hi Fi Monk 的 Fez Aswat 给予的贡献。我感谢 Jennifer Lim、Néstor Nápoles 和 Oliver Strimpel 评审文章并提供反馈。
关于使用 GPT-4 写歌曲的更多信息
这是本系列的第一篇和第三篇文章。
如何使用 OpenAI 的最新语言模型来帮助创作原创歌曲的歌词
towardsdatascience.com ## 使用 GPT-4 创作歌曲:第三部分,旋律
如何使用 OpenAI 的最新语言模型来帮助创作新歌曲的旋律
towardsdatascience.com
参考文献
[1] OpenAI,GPT-4 技术报告(2023)
[2] A, Radford 等,通过大规模弱监督进行鲁棒语音识别(2022)
[4] C. J. Bayron,Autochord - 自动和弦识别库和和弦可视化应用(2021),第 22 届国际音乐信息检索会议
附录
这里有两首我在 GPT-4 的帮助下创作的不同风格的歌曲。你可以在第一篇文章中阅读有关歌词创作的过程。乐队同意让我使用 AI 分析他们的歌曲,并利用这些分析创作出具有类似风格的新歌曲。
消逝的回声
第一首歌基于Rhode Iceland,一支来自马萨诸塞州洛威尔的另类摇滚乐队的《Bloody Brain》。
消逝的回声,歌词和和弦由 GPT-4 提供,作者制作
战场之声
第二首歌基于Hi Fi Monk,一支位于马萨诸塞州波士顿的嘻哈/放克/雷鬼乐队的《Break》。
战场之声,歌词和和弦由 GPT-4 提供,作者制作