Elliot 激活函数:它是什么,它有效吗?
原文:
towardsdatascience.com/elliot-activation-function-what-is-it-and-is-it-effective-59b63ec1fd8a
什么是 Elliot 激活函数,它是否是神经网络中其他激活函数的良好替代方案?
·发表于 Towards Data Science ·阅读时间 7 分钟·2023 年 2 月 4 日
–
Elliot 激活函数(图片来源:作者)
介绍
你是否在创建新的机器学习模型时,不确定应该使用什么激活函数?
但等一下,什么是激活函数?
激活函数使机器学习模型能够理解和解决非线性问题。在神经网络中使用激活函数特别有助于将每个神经元传递给下一个神经元的最重要信息。今天,ReLU 激活函数通常用于神经网络的架构中,但这并不一定意味着它总是最佳选择。(请查看我下面关于 ReLU 和 LReLU 激活函数的文章)。
## Leaky ReLU 与 ReLU 激活函数:哪一个更好?
一项实验调查在使用 ReLU 激活函数时模型性能是否存在明显差异……
towardsdatascience.com
我最近发现了Elliot 激活函数,它被赞誉为可能替代各种激活函数的选择,包括 Sigmoid 和双曲正切函数。今天我们将进行一个实验来测试 Elliot 激活函数的性能。
实验 1: 测试 Elliot 激活函数与 Sigmoid 激活函数和双曲正切激活函数的性能。
实验 2: 测试 Elliot 激活函数与 ReLU 激活函数的性能。
目标是回答这个问题:Elliot 激活函数是否有效?
Elliot 激活函数
Elliot 激活函数将产生一个相对接近 Sigmoid 和双曲正切激活函数的近似结果。有些人发现 Elliot 比 Sigmoid 激活函数快 2 倍 [3]。就像 Sigmoid 激活函数一样,Elliot 激活函数被限制在 0 到 1 之间。
Elliot 激活函数(图像来自作者)
实验
问题: Keras 目前在其库中没有 Elliot 激活函数。
解决方案: 我们可以使用 Keras 后端自行创建它!
def elliot(x):
return ((.5*x) / (1 + K.abs(x)))
elliot = Activation(elliot)
对于这个实验,让我们看看 Elliot 激活函数与类似激活函数以及 ReLU 激活函数的比较,ReLU 是今天神经网络中使用的基本激活函数。
数据集和设置
所有 Python 项目的第一步是导入你的包。
import keras.backend as K
from keras.layers import Layer
from keras.layers import Activation
import pandas as pd
from sklearn.preprocessing import LabelEncoder
from sklearn.model_selection import train_test_split
from keras import layers
from keras import Sequential
今天使用的数据集是鸢尾花数据集,可以在这里找到。这个数据集是公开的,允许公开使用(可以通过sklearn加载到 Python 中)。
iris = pd.read_csv("https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data")
# Preprocess the data
X = iris.iloc[:, :-1].values
y = iris.iloc[:, -1].values
# Encode the categorical output labels
encoder = LabelEncoder()
y = encoder.fit_transform(y)
# Split the data into training and test sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)
接下来,我们创建四个模型。这些将是相当简单的模型。每个模型将有一层 8 个神经元和一个激活函数。最终层将有 3 个神经元并使用 Softmax 激活函数。
#Model 1 (Sigmoid)
#Model 1
model = Sequential()
model.add(layers.Dense(8, input_dim=4, activation='sigmoid'))
model.add(layers.Dense(3, activation='softmax'))
#Model 2 (Tanh)
model = Sequential()
model.add(layers.Dense(8, input_dim=4, activation='tanh'))
model.add(layers.Dense(3, activation='softmax'))
#Model 3 (ReLU)
model = Sequential()
model.add(layers.Dense(8, input_dim=4, activation='relu'))
model.add(layers.Dense(3, activation='softmax'))
#Model 4 (Elliot)
model = Sequential()
model.add(layers.Dense(8, input_dim=4, activation=elliot))
model.add(layers.Dense(3, activation='softmax'))
接下来,简单地训练模型并分析结果。
# Compile the model
model.compile(loss='sparse_categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
# Train the model (Pick the number of epochs)
model.fit(X_train, y_train, epochs=1, batch_size=10)
结果
结果实际上是……令人惊讶的。正如预期的那样,Elliot 激活函数生成的模型在性能上与采用 Sigmoid 和双曲正切激活函数的模型相似。
1 周期
-
Sigmoid @ 1: 准确率: 0.3109 | 损失: 2.0030
-
Elliot @ 1: 准确率: 0.3361 | 损失: 1.0866
在 1 个周期下,Elliot 激活函数模型的准确率比 Sigmoid 激活函数模型高 2.61%,并且损失量减少了近 100%。
10 周期
-
Sigmoid @ 10: 准确率: 0.3529 | 损失: 1.0932
-
Elliot @ 10: 准确率: 0.6891 | 损失: 0.9434
在 10 个周期下,使用 Elliot 激活函数的模型比使用 Sigmoid 激活函数的模型准确率提高了近 30%,同时损失较低。
100 周期
-
Sigmoid @ 100: 准确率: 0.9496 | 损失: 0.4596
-
Elliot @ 100: 准确率: 0.9580 | 损失: 0.5485
虽然 Sigmoid 模型的表现优于 Elliot 模型,但需要注意的是它们的表现几乎完全相同。
1000 周期
-
Sigmoid @ 1000: 准确率: 0.9832 | 损失: 0.0584
-
Elliot @ 1000: 准确率: 0.9832 | 损失: 0.0433
在 1000 个周期下,两种不同模型的表现几乎完全相同。
总体而言,使用 Elliot 激活函数的模型表现略优于使用 Sigmoid 激活函数的模型。
Elliot 与双曲正切
1 个周期
-
tanh @ 1: 准确率: 0.3361 | 损失: 1.1578
-
Elliot @ 1: 准确率: 0.3361 | 损失: 1.0866
在 1 个周期时,Elliot 激活函数模型与双曲正切激活函数模型的表现相同。我原本预期这些函数会产生相似的模型,因为它们都以类似的方式限制了传递到神经网络下一层的值。
10 个周期
-
tanh @ 10: 准确率: 0.3277 | 损失: 0.9981
-
Elliot @ 10: 准确率: 0.6891 | 损失: 0.9434
使用 Elliot 激活函数的模型明显优于使用双曲正切激活函数的模型,就像 Elliot 模型在与 Sigmoid 模型比较时在 10 个周期的表现一样。
100 个周期
-
tanh @ 100: 准确率: 0.9916 | 损失: 0.2325
-
Elliot @ 100: 准确率: 0.9580 | 损失: 0.5485
在 100 个周期时,双曲正切模型的表现明显优于 Elliot 模型。在更高的周期下,Elliot 激活函数似乎表现不如tanh激活函数,但让我们看看在 1000 个周期时它们的表现有何不同。
1000 个周期
-
tanh @ 1000: 准确率: 0.9748 | 损失: 0.0495
-
Elliot @ 1000: 准确率: 0.9832 | 损失: 0.0433
好吧,在 1000 个周期时,Elliot 激活函数模型略微超越了双曲正切激活函数模型。
总的来说,我认为双曲正切和 Elliot 激活函数模型在神经网络的层次中几乎表现相同。训练模型所需的时间可能会有所不同,然而这些模型非常简单,随着数据量的增加以及网络规模的扩大,时间可能会成为一个更重要的因素。
Elliot 与 ReLU
1 个周期
-
ReLU @ 1: 准确率: 0.6639 | 损失: 1.0221
-
Elliot @ 1: 准确率: 0.3361 | 损失: 1.0866
在 1 个周期时,ReLU 激活函数模型的表现更好,这表明 Elliot 激活函数使模型训练速度较慢。
10 个周期
-
ReLU @ 10: 准确率: 0.6471 | 损失: 0.9413
-
Elliot @ 10: 准确率: 0.6891 | 损失: 0.9434
哇!包含 Elliot 激活函数的模型实际上表现更好,准确率高出 4.2%,损失低了 0.21%。
100 个周期
-
ReLU @ 100: 准确率: 0.9160 | 损失: 0.4749
-
Elliot @ 100: 准确率: 0.9580 | 损失: 0.5485
尽管采用 Elliot 激活函数的模型损失较高,但它能够实现 4.2%的更高准确率。这再次展示了 Elliot 激活函数在神经网络中的强大优势。
1000 个周期
-
ReLU @ 1000: 准确率: 0.9916 | 损失: 0.0494
-
Elliot @ 1000: 准确率: 0.9832 | 损失: 0.0433
尽管采用 Elliot 激活函数的模型在准确性方面表现不佳,但损失较低,我对结果仍然感到满意。如 1000 次迭代所示,Elliot 激活函数几乎与 ReLU 激活函数一样好,并且在正确的问题和超参数调整下,Elliot 激活函数可能是更优的选择。
结论
今天,我们探讨了一种较不为人知的激活函数:Elliot 激活函数。为了测试它的性能,我们将其与形状相似的两个激活函数进行比较:Sigmoid 和双曲正切激活函数。结果显示,Elliot 函数的表现与这两个函数相当,甚至更好。接下来,我们将 Elliot 激活函数的性能与现代神经网络中使用的标准 ReLU 激活函数进行了比较。在四次试验中,采用 Elliot 激活函数的模型有 50% 的时间表现更好。在其他试验中,尽管表现不如前者,但其性能与使用 ReLU 激活函数的模型几乎一致。我建议在下一个神经网络中尝试 Elliot 激活函数,因为它可能表现更佳!
如果你喜欢今天的阅读,请关注我,并告诉我是否有其他话题你希望我深入探讨!如果你没有 Medium 账户,可以通过我的链接 这里注册!使用我的链接我将获得少量佣金。此外,也可以在 LinkedIn 添加我,或者随时联系我!感谢阅读!
-
Dubey, Shiv Ram, Satish Kumar Singh, 和 Bidyut Baran Chaudhuri. “深度学习中激活函数的全面调查与性能分析。” arXiv 预印本 arXiv:2109.14545 (2021)。
-
Sharma, Sagar, Simone Sharma, 和 Anidhya Athaiya. “神经网络中的激活函数。” towards data science 6.12 (2017): 310–316。
-
www.gallamine.com/2013/01/a-sigmoid-function-without-exponential_31.html
嵌入技术:ChatGPT 的秘密武器
原文:
towardsdatascience.com/embeddings-chatgpts-secret-weapon-1870e590f32c
嵌入技术,以及它们如何帮助 ChatGPT 预测下一个词
·发表于 Towards Data Science ·阅读时间 5 分钟·2023 年 3 月 6 日
–
(图像由作者提供)
变换器和注意力机制
如果你最近经常浏览网页或阅读技术新闻,你可能在某个时候听说过或读到过 ChatGPT。ChatGPT 是 OpenAI 的新语言变换器模型,就这些模型而言,这个模型相当准确,产生了一些非常引人注目的——有时甚至是病毒式的——结果。在这个上下文中,变换器指的是一种采用自注意力机制的机器学习模型。自注意力机制是一个数据科学术语,简单来说就是这个模型试图模拟人类的认知功能或人类的认知注意力。这个模型的语言部分也很重要;它描述了变换器希望预测的内容,即人类语言。这通常被称为自然语言处理,或NLP,虽然 NLP 通常指的是对语言数据的处理,以将其转换为计算机或神经网络可以理解的数值权重。
变换器具有一些显著的特性,使得它们的定义在讨论语言变换器如 ChatGPT 时特别重要。变换器以及更广泛的注意力模型,拥有一些特征,这些特征并非每种机器学习模型所特有。在正常情况下,机器学习模型适配某些数据并生成权重;我们可以把这看作编程语言编译可执行文件的过程:一旦可执行文件编译完成,它变得静态和不可变——无法更改,我们无法从内部调整代码。另一方面,变换器具有软权重,这更像是使用动态类型编程语言的 REPL,模型权重是可变的,并且可以在运行时进行更改。这是许多不同且有用的模型类型的基础,如长短期记忆(LSTM)模型,以及我们今天讨论的变换器。
这张图展示了变换器模型的架构。 (图片来自维基共享资源)
embeddings
这引出了 embeddings,它们为这些软权重提供了更多的力量和能力。Embeddings 通过创建一个维度低于实际编码稀疏向量的新的维度层来工作。这可以被认为是对这些数据的一种分组,这在模型的最终计算中起到作用。实际上,embeddings 是一个低维空间,为更大的高维向量提供了节奏。我们几乎是在模型中加入了一个新的特征,我们的模型可能将其作为分类来推断数据中的更多细节——这在解释诸如人类语言这样复杂的事物时尤为重要。在这种情况下,维度指的是数据的维度或形状。理解 embeddings 的一种很好的方式是把它想象成一个飞镖靶。
在一个房间里,我们有一个飞镖板。我们希望利用这个飞镖板来预测给定房间内住客的技能水平。我们发现,非常差的飞镖手往往击中飞镖板的底部,而技能稍好的人往往击中顶部,非常有技巧的人则击中中间。实际击中位置将是我们的原始特征,我们将为其构建权重和概率。然而,如果我们给这些区域标记,并将它们与人的技能水平关联,以对这些数据做出更普遍的推断,这可能有助于我们在该上下文中做出更细致的预测,这就是嵌入的概念。嵌入成为一个点,数据本身,在确定其在这个低维空间中与其他嵌入的相似度的轴上。我们可以使用这来预测例如一个飞镖手已经玩了多少年。
一个简化的示意图,展示了这在你的模型中的样子。(图片由作者提供)
从本质上讲,嵌入告诉我们关于一组数据的信息是,这组数据中的数据与该嵌入中的其他数据相似。嵌入本质上只是其他数据上的分类数据。另一个需要注意的点是,这些分类也可以是多维的,意味着可以有多个嵌入,并且权重可能绑定到相同的嵌入上。嵌入也可以从数据中学习,这意味着这可以是神经网络的一部分,而不会添加很多内容,使它们成为许多应用中的简单选择,例如 ChatGPT 等变压器。
OpenAI 有他们自己的嵌入端点,这使得执行自然语言任务、主题建模、分类,甚至聚类变得非常简单。如果你想了解更多关于 OpenAI 嵌入的内容,下面是一个详细讨论此主题的论文链接:
文本嵌入在许多应用中都是有用的特征,例如语义搜索和计算文本相似性……
arxiv.org](https://arxiv.org/abs/2201.10005?source=post_page-----1870e590f32c--------------------------------)
很容易想象这些嵌入在处理文本和创建准确的语言模型预测中所扮演的角色。词语确实可以被分类,当你考虑到英语词汇的宏观图景时,理解词语实际作用可能会非常困难。然而,如果我们将这些词语分解为类别:冠词、名词、动词,那么了解语法如何在我们的语言中实际运作就会容易得多。对于语言模型来说,词嵌入的目标是捕捉词语在向量表示中的意义。我们为词语的意义创建一个通用分类,然后利用我们对该类别的了解来对输出做出推断。此外,ChatGPT 用于表示文本的粒度是子词,而不是整个词。因此,ChatGPT 利用这些类型的嵌入来对词语的某些部分进行分类和描述。
结束
嵌入是许多不同类型机器学习模型的核心概念:推荐算法、语言转换器,甚至分类模型都是从拥有嵌入层中受益的例子。OpenAI 的嵌入实现帮助 ChatGPT 模型根据类别及其与这些类别的数值关系来解释词语,这比尝试从每个单独词语中找出见解要容易得多。如果你想了解更多关于嵌入的内容,并且如何将它们应用到自己的 Tensorflow 网络中,我强烈建议你查看 Google 几年前发布的嵌入教程,这里有一个链接:
嵌入是一个相对低维的空间,你可以将高维向量转换到其中。嵌入…
developers.google.com](https://developers.google.com/machine-learning/crash-course/embeddings/video-lecture?source=post_page-----1870e590f32c--------------------------------)
感谢阅读!
嵌入 + 知识图谱:RAG 系统的终极工具
原文:
towardsdatascience.com/embeddings-knowledge-graphs-the-ultimate-tools-for-rag-systems-cbbcca29f0fd
·发表于 Towards Data Science ·10 分钟阅读·2023 年 11 月 14 日
–
人工智能软件被用来增强本文文本的语法、流畅性和可读性。
大型语言模型(LLM)的出现,经过大量文本数据的训练,是自然语言处理领域最重要的突破之一。这些模型仅凭简短的提示生成流畅且连贯的文本,开辟了对话 AI、创意写作和广泛其他应用的新可能性。
然而,尽管它们表现出色,LLM 仍然有一些关键限制。它们的知识仅限于从训练数据中辨别出的模式,这意味着它们缺乏对世界的真正理解。
他们的推理能力也有限——他们无法进行逻辑推断或从多个来源综合事实。当我们提出更复杂、开放性的问题时,回答开始变得毫无意义或自相矛盾。
为了弥补这些不足,检索增强生成(RAG)系统引起了越来越多的关注。关键思想是从外部来源检索相关知识,为 LLM 提供背景,以做出更有信息量的回答。
目前大多数现有系统通过向量嵌入的语义相似性检索段落。然而,这种方法有其自身的缺陷,如缺乏真正的相关性、无法聚合事实以及没有推理链。
这就是知识图谱发挥作用的地方。知识图谱是对现实世界实体和关系的结构化表示。它们通过编码上下文事实之间的相互连接,克服了纯向量搜索的不足。遍历知识图谱能够在多样的信息源之间进行复杂的多跳推理。
在这篇文章中,我们深入探讨了如何将向量嵌入与知识图谱结合,以解锁 LLM 推理、准确性和解释能力的新层次。这种结合提供了表面语义与结构化知识和逻辑的完美融合。
像我们的思维一样,LLM 需要统计学习和符号表示的结合。
我们首先探讨了单独依赖向量搜索的固有弱点。
然后我们阐明了知识图谱和嵌入如何互相补充,单独使用任何一种技术都不够充分。
原始向量搜索的局限性
介绍
大多数 RAG 系统依赖于对文档集合中的段落进行向量搜索,以找到对 LLM 相关的上下文。此过程包括几个关键步骤:
-
文本编码: 系统使用像 BERT 这样的嵌入模型将语料库中的文本段落编码成向量表示。每个段落都被压缩成一个密集的向量,捕捉语义意义。
-
索引: 这些段落向量在高维向量空间中进行索引,以实现快速相似性搜索。常用的方法包括 ANNOY、Faiss 和 Pinecone。
-
查询编码: 当用户查询到达时,它也会使用相同的嵌入模型编码成向量表示。
-
相似性检索: 通过对索引的段落进行相似性搜索,找到那些与查询向量基于距离度量(如余弦相似性)最接近的段落。
-
段落返回: 返回最相似的段落向量,并提取原始文本以提供 LLM 的上下文。
该管道存在几个关键限制:
-
段落向量可能未能完全捕捉查询的语义意图。重要的上下文可能被忽视,因为嵌入未能表示某些推理连接。
-
在将整个段落压缩为单一向量时,细微之处会丢失。分布在句子中的关键相关细节被掩盖。
-
匹配是针对每个段落独立进行的。没有跨不同段落进行联合分析以连接事实和推导需要聚合的答案。
-
排名和匹配过程不透明,无法提供为何某些段落被认为更相关的透明度。
-
只编码了语义相似性,没有表示内容之间关系、结构、规则和其他多样化连接的表示。
仅关注语义向量相似性会导致检索结果缺乏真实理解。随着查询变得更加复杂,这些局限性在无法跨检索内容进行推理时变得愈加明显。
融入知识图谱
知识图谱将信息表示为一个互联的实体和关系网络,能够在内容中进行更复杂的推理。
下面是它们如何增强检索:
-
显式事实 — 事实作为节点和边直接捕获,而不是压缩成不透明的向量。这保留了关键细节。
-
上下文细节 — 实体包含丰富的属性,如描述、别名和元数据,提供了关键的上下文。
-
网络结构 — 关系建模实体之间的现实世界连接,捕捉规则、层级、时间线等。
-
多跳推理 — 查询可以遍历关系以连接来自不同来源的事实。可以推导出需要多步骤推理的答案。
-
联合推理 — 实体解析将对同一现实世界对象的引用连接起来,允许集体分析。
-
可解释的相关性 — 图的拓扑结构提供了为什么某些事实基于其连接而相关的透明度。
-
个性化 — 捕捉用户属性、上下文和历史交互,以定制结果。
知识图谱使得图遍历过程成为可能,以收集与查询相关的相互连接的上下文事实,而不是孤立的匹配。根据拓扑结构可以实现可解释的排名。丰富的知识表示能力促进了更复杂的推理。
知识图谱通过编码结构化事实、关系和上下文来增强检索,从而实现精准的多步骤推理。与纯向量搜索相比,这提供了更大的相关性和解释力。
结合知识图谱与嵌入和约束
将知识图谱(KGs)嵌入到连续向量空间是当前研究的重点。早期的研究进行了…
知识图谱将实体和关系表示为向量嵌入,以进行数学操作。额外的约束可以使表示更加优化:
-
非负约束 — 将实体嵌入限制在 0 到 1 之间的正值,诱导稀疏性。这仅显式地建模它们的正面属性,并提高可解释性。
-
蕴含约束 — 通过将预期的逻辑规则如对称性、反转、组合直接编码为关系嵌入的约束,强制这些模式。
-
置信度建模 — 通过松弛变量的软约束可以编码基于证据的逻辑规则的不同置信水平。
-
正则化 — 约束施加有用的归纳偏置,而不会使优化显著变得更加复杂。只增加一个投影步骤。
-
可解释性 — 结构化的约束提供了对模型学习到的模式的透明度。这解释了推理过程。
-
准确性 — 约束通过减少假设空间到符合的表示来提高泛化能力。这提高了对未见查询的准确性。
添加简单但通用的约束可以增强知识图谱嵌入,生成更优化、可解释且符合逻辑的表示。这些嵌入获得了模仿现实世界结构和规则的归纳偏差,从而带来更准确且易于解释的推理,而不增加额外的复杂性。
整合多样化的推理框架
## Papers with Code - Graph Agent: Explicit Reasoning Agent for Graphs
尚无可用代码。
知识图谱需要推理来推导新事实、回答查询和进行预测。不同的技术具有互补的优势:
-
逻辑规则 — 将知识表达为逻辑公理和本体。通过定理证明进行可靠和完整的推理。处理不确定性的能力有限。
-
图谱嵌入 — 嵌入知识图谱结构以进行向量空间操作。处理不确定性,但缺乏表达能力。
-
神经证明器 — 可微分的定理证明模块与向量查找结合。自适应但推理不透明。
-
规则学习器 — 通过对图结构和数据的统计分析来引导规则。自动化规则创建但质量不确定。
-
混合管道 — 逻辑规则编码明确的约束。嵌入提供向量空间操作。神经证明器通过联合训练融合了这些优势。
-
可解释建模 — 使用基于案例、模糊或概率逻辑来增加透明度。表达规则中的不确定性和信心。
-
迭代增强 — 通过将推断出的事实和学习到的规则重新呈现到图谱中来扩展知识。提供反馈回路。
关键在于识别所需的推理类型并将其映射到适当的技术上。一个结合逻辑形式、向量表示和神经组件的可组合管道提供了鲁棒性和可解释性。
保持信息流向 LLM
从知识图谱中检索事实以供 LLM 使用会引入信息瓶颈。精心设计保持相关性:
-
分块 — 将内容拆分成小块可以提高隔离性,但会丧失周围的上下文。这阻碍了跨块的推理。
-
总结 — 生成内容块的摘要提供了更简洁的上下文。关键细节被浓缩以突出其重要性。
-
元数据 — 附加摘要、标题、标签等作为元数据以维护源内容的上下文。
-
查询重写 — 将原始查询重写为更详细的版本,提供更符合 LLM 需求的检索结果。
-
关系建模 — 知识图谱遍历保持事实之间的连接,维持上下文。
-
信息排序 — 按时间顺序或相关性排序事实,优化 LLM 的信息结构。
-
显式陈述 — 将隐含知识转换为为 LLM 陈述的显式事实,使推理更容易。
目标是优化检索知识的相关性、上下文、结构和明确性,以最大化推理能力。需要在粒度和连贯性之间取得平衡。知识图谱关系有助于将孤立的事实进行上下文化。
解锁推理能力
知识图谱和嵌入各有优点,相互结合可以弥补对方的不足:
-
知识图谱 — 提供实体和关系的结构化表示。通过图遍历赋能复杂推理。处理多跳推理。
-
嵌入 — 在向量空间中编码信息以进行基于相似性的操作。实现大规模高效的近似搜索。揭示潜在模式。
-
联合编码 — 为知识图谱中的实体和关系生成嵌入。这提炼了统计模式。
-
神经网络 — 图神经网络通过可微分的信息传递在图结构和嵌入元素上操作。这融合了优势。
-
推理流程 — 知识图谱遍历首先收集结构化知识。然后嵌入关注搜索并大规模检索相关内容。
-
可解释性 — 显式的知识图谱关系为推理过程提供了可解释性。嵌入增强了解释能力。
-
迭代改进 — 推断的知识可以扩展图。GNNs 提供持续的表示学习。
这种合作关系使结构化知识表示和推理得到了模式识别能力和神经网络的可扩展性的增强。这是推动语言 AI 的关键,需要统计学习和符号逻辑的结合。
通过协同过滤改进搜索
协同过滤利用实体之间的连接来增强搜索:
-
知识图谱 — 构建一个知识图谱,其中节点表示实体,边表示关系。
-
节点嵌入 — 为特定的关键节点属性(如标题、描述等)生成嵌入向量。
-
向量索引 — 在节点嵌入上构建向量相似性索引。
-
相似性搜索 — 对于搜索查询,找到具有最相似嵌入的节点。
-
协作调整 — 基于节点的连接,使用诸如 PageRank 的算法传播和调整相似性评分。
-
边权重 — 根据边的类型、强度、置信度等调整权重。
-
评分归一化 — 对调整后的评分进行归一化,以保持相对排名。
-
结果重新排序 — 基于调整后的协同评分重新排序初始结果。
-
用户背景 — 根据用户资料、历史和偏好进一步调整。
用飞轮学习推动知识图谱
构建一个高效的检索增强生成(RAG)系统,并不断改进,需要实施…
知识图谱通过提供结构化的世界知识,为语言模型解锁了新的推理能力。然而,构建高质量的图谱仍然具有挑战性。这就是飞轮学习的作用所在——通过分析系统交互持续改进知识图谱。
知识图谱飞轮
-
仪器化 — 记录所有系统查询、响应、评分、用户行为等。提供对知识图谱使用情况的可见性。
-
分析 — 汇总使用数据以显现不佳的响应。对这些响应进行聚类和分析,以识别表明知识缺口的模式。
-
策划 — 手动审查问题响应,并追踪问题到图谱中的缺失或错误的事实。
-
修正 — 直接修改图谱,添加缺失的事实、改进结构、提高清晰度等。修复潜在的数据问题。
-
迭代 — 不断循环上述步骤。每次迭代进一步增强知识图谱。
流数据摄取
-
流媒体数据源,如新闻和社交媒体,提供了持续的信息流,以保持知识图谱的时效性。
-
专用基础设施处理高容量的数据摄取。
主动学习
-
利用查询生成识别并填补关键的知识空白,超越流媒体提供的信息。
-
发现图谱中的漏洞,提出问题,检索缺失的事实,并将其添加。
飞轮效应
每次循环,知识图谱通过分析使用模式和修正数据问题逐步增强。改进的图谱提升了系统性能。
这个飞轮过程使知识图谱和语言模型能够基于来自现实世界使用的反馈共同演化。图谱会根据模型的需求进行积极调整。
总结来说,飞轮学习为知识图谱提供了一个持续、自动化改进的框架,通过分析系统交互来实现。这推动了依赖于图谱的语言模型的准确性、相关性和适应性。
结论:
要达到人类水平的智能,语言 AI 需要结合外部知识和推理。这正是知识图谱发挥作用的地方。知识图谱提供了现实世界实体和关系的结构化表示,编码了关于世界的事实及其之间的连接。这允许通过遍历互联的事实进行复杂的逻辑推理。
然而,知识图谱有其自身的局限性,如稀疏性和缺乏不确定性处理能力。在这里,图嵌入发挥作用——通过将知识图谱元素编码到向量空间中,嵌入允许从大规模语料库中进行统计学习,以揭示潜在模式。它们还支持基于相似性的高效操作。
无论是知识图谱还是嵌入,单独使用都不足以实现类似人类的语言智能。但将它们结合起来,可以提供结构化知识表示、逻辑推理和统计学习的完美融合。知识图谱在神经网络的模式识别能力之上叠加了符号逻辑和关系。
像图神经网络这样的技术通过在图结构和嵌入上进行可微分的消息传递进一步统一了这些方法。这种共生关系使系统能够利用统计学习和符号逻辑的优势——结合了神经网络和结构化知识表示的优点。
这种合作关系为下一代 AI 提供了基础构件,这种 AI 超越了单纯的口才,达到了真正的理解——能够理解上下文和历史的对话代理,能够识别细微偏好的推荐引擎,通过连接事实来合成答案的搜索系统。
构建高质量知识图谱、基准测试、噪声处理等仍然面临挑战。但跨符号和神经方法的混合技术前景光明。随着知识图谱和语言模型的不断进步,它们的整合将开启可解释、智能语言 AI 的新领域。
这张图像是使用 AI 图像生成模型创建的。
迎接自动化重新训练
作者提供的图片
如何从固定节奏(或完全不)重新训练转向动态方法
·
关注 发表在 Towards Data Science ·7 分钟阅读·2023 年 3 月 17 日
–
这篇文章由 Trevor LaViale 联合撰写
尽管行业在了解何时将模型投入生产方面投资了大量的过程和技术,但关于同样重要的任务——了解何时重新训练模型的集体知识却相对较少。事实上,了解何时重新训练模型很困难,因为存在诸如反馈延迟或实时预测标签等因素。在实际操作中,许多模型在生产中没有进行任何重新训练,使用手动重新训练方法,或是在没有优化或研究节奏的情况下进行重新训练。
本文旨在帮助数据科学家和机器学习工程团队采用自动化重新训练。
重新训练的方法
自动化模型重新训练有两种核心方法:
-
固定: 按设定的周期(例如,每天、每周、每月)进行重新训练。
-
动态: 基于模型性能指标的临时触发重新训练。
虽然固定方法实现起来很简单,但也存在一些缺点。计算成本可能比实际需要的要高,频繁的重新训练可能导致模型之间的不一致,而不频繁的重新训练计划可能导致模型过时。
动态方法可以防止模型过时,并优化计算成本。虽然有许多重新训练的方法,但以下是一些推荐的最佳实践,用于动态模型重新训练,以保持模型的健康和高效。
通用重新训练架构
有一系列工具可以用来创建模型重新训练系统。此图示展示了一个 ML 可观测性平台如何集成到一个通用流程中。
针对特定工具的教程非常丰富。以下是一些示例:
对于那些准备跳过的,可以进一步了解一下 Etsy 的见解关于有状态模型重新训练的内容。
重新训练策略
自动化重新训练一个实时机器学习模型可能是一个复杂的任务,但有一些最佳实践可以帮助指导设计。
触发重新训练的指标
触发重新训练的指标将取决于具体的模型和使用案例。每个指标都需要设定一个阈值。该阈值将用于在模型的性能低于阈值时触发重新训练。在这方面,监控工具可以发挥作用。当模型监控平台中的性能监控器触发时,你可以通过编程查询性能和漂移指标,以评估是否需要重新训练。
理想的模型重新训练触发指标:
-
预测(分数或标签)漂移
-
性能指标降级
-
针对特定细分群体/队列的性能指标降级。
-
特征漂移
-
嵌入漂移
漂移是度量两个分布之间距离的指标。它是触发模型重新训练的有意义的指标,因为它表明你的生产数据从基线数据有多少偏移。统计漂移可以通过各种漂移指标来测量。
用于计算漂移的基准数据集可以来源于训练数据集或生产数据的一个窗口。
确保新模型有效
新模型需要在推广到生产环境以替换旧模型之前进行测试或验证。这里有几种推荐的方法:
-
人工审查
-
CI/CD 管道中的自动化指标检查
推广新模型的策略
推广新模型的策略将取决于模型对业务的影响。在某些情况下,可能适合自动用新模型替换旧模型。但在其他情况下,新模型可能需要进行 A/B 测试后再替换旧模型。
一些值得考虑的实时模型测试策略包括:
-
冠军模型与挑战者模型 — 向这两个模型提供生产流量,但在应用中仅使用现有模型(冠军)的预测/响应。挑战者模型的数据将被存储以供分析,但不会被使用。
-
A/B 测试 — 将生产流量分配到两个模型中,进行固定时间段的实验。实验结束时比较关键指标,并决定推广哪个模型。
-
金丝雀发布 — 先将小比例的生产流量重定向到新模型。由于它在生产路径中,这有助于发现新模型的实际问题,但将影响限制在小比例用户中。逐步增加流量直到新模型接收 100%的流量。
重新训练反馈循环数据
一旦确定模型需要保留,下一步是选择合适的数据集进行重新训练。以下是一些建议,以确保新的训练数据将提升模型性能:
-
如果模型总体表现良好,但在某些特定的特征值或人口统计特征等细分段上未能达到最佳性能标准,则新的训练数据集应包含这些表现较差的细分段的额外数据点。可以使用简单的上采样策略来创建一个新的训练数据集,以针对这些低表现的细分段。
-
如果模型在小时间片上训练,训练数据集可能无法准确捕捉和表示所有可能出现在实际生产数据中的模式。为防止这种情况,避免仅在最近数据上训练模型。相反,应使用大量的历史数据,并用最新的数据来增强这些数据,以便模型学习到额外的模式。
-
如果您的模型架构遵循迁移学习设计,则在重新训练期间可以简单地将新数据添加到模型中,而不会丢失模型从之前训练数据中已经学到的模式。
来自模型监控平台的仪表板(例如 Arize——完全披露:我在 Arize 工作)非常适合在这些测试期间跟踪和比较模型的实时性能。无论模型是作为影子部署、实时 A/B 测试还是仅仅是离线比较,这些仪表板都提供了一种简单的方式来查看并排模型比较。这些仪表板还可以轻松地与他人分享,以向利益相关者展示模型性能的改善。
定量 ROI
总体而言,确定自动重新训练实时机器学习模型的最佳方法时,了解业务需求和解决的问题至关重要。同样,持续监控模型性能,并根据需要调整重新训练的频率和指标也很重要。
成本影响测量:
虽然在 AI 领域计算直接 ROI 是具有挑战性的,但优化模型重新训练的价值简单、直观且可以直接计算。模型训练作业的计算和存储成本通常已经作为云计算成本的一部分进行跟踪。通常,模型的商业影响也可以计算。
在优化重新训练时,我们考虑了重新训练成本和模型性能对业务的影响(“AI ROI”)。我们可以权衡这些成本以证明模型重新训练的成本。
在这里,我们提出了每周成本计算,尽管该计算器可以根据模型的目的和维护需求调整为不同的频率,如每日或每月。
图片由作者提供
考虑场景 1,即模型过于频繁地重新训练的情况。
我的模型重新训练成本为$200。我每天训练一次模型。该模型保持了稳定的每周平均准确率为 85%。我设置了一个管道,基于预测分数漂移大于 0.25 PSI 和准确率自动重新训练。根据新规则,我的模型每周只重新训练两次,并保持 85%的准确率。
每周维护成本比较:
旧模型维护成本:7*$200 = $1400
新模型维护成本 2*$200= $400
这相当于模型维护成本减少了 x%。虽然这是一个简单的假设示例,但成本节约的幅度可能会达到这种规模。
考虑场景 2,即模型训练不足的情况。
我的模型训练成本为$200。我每周训练一次模型。该模型保持了稳定的每周平均准确率为 65%。我设置了一个管道,基于预测分数漂移大于 0.25 PSI 自动重新训练。根据新规则,我的模型每周重新训练两次,达到了更好的 85%准确率。
每周维护成本比较:
旧模型维护成本:1*$200 = $200,准确率 65%
新模型维护成本:2*$200= $400,准确率 85%
因此,通过更高的价格,取得了更好的模型性能。如果 AI 投资回报值高于重新训练成本,那么这可以被证明是合理且有利可图的。缺乏频繁的重新训练可能会导致错失收益。
结论
从固定间隔的模型重新训练过渡到由模型性能触发的自动化模型重新训练,为组织提供了众多好处,包括在云成本不断增加的情况下降低计算成本,以及通过改善模型性能实现更好的 AI 投资回报。希望这篇博客为团队提供了一个行动模板。
Embracing Julia: An Invitation Letter
诚挚地向 Python 爱好者、科学计算大师和数据科学家致敬
·
关注 发表在 Towards Data Science ·19 分钟阅读·2023 年 10 月 13 日
–
Julia 是一种通用、动态、高性能和高级别的编程语言,采用即时编译。这是一门相对较新的语言,其主要 1.0 版本直到 2018 年才发布。在这篇文章中,我们旨在展示,如果你对数据科学、科学计算或者是 Python 爱好者,那么将这门语言加入你的工具箱绝对是值得的。也许这确实是你见过的最美的编程语言。
紫色、绿色和红色行星的星系数字艺术 — 由作者使用 DALLE 2 生成
在这个故事中,我们将探讨 Julia 的思想高度及其学习的价值。完成后,我们强烈推荐你查看下一个故事 从 Python 到 Julia:终极指南,以便从 Python 轻松过渡到 Julia。
目录
· Julia 是高级语言
∘ 基本语法
∘ 数学的优雅语法
· Julia 很快
∘ 基准测试
∘ 双语言问题
∘ Julia 是即时编译的
· Julia 解决了表达式问题
∘ 表达式问题
∘ 多重分发
∘ 抽象和具体类型
· Julia 功能全面
∘ 数组支持
∘ 字符串支持
∘ 多线程
∘ 与 C 代码的简单集成
∘ 标准库
· Julia 是通用的
∘ 介绍
∘ 自动化和脚本编写
· Julia 可扩展性广
∘ 介绍
∘ 宏
· 总结
照片由 Daniele Levis Pelusi 提供,来源于 Unsplash
Julia 是高级语言
介绍可能已经让你觉得这将类似于 Python——也是一种通用、动态和高级语言。为了验证这一点,我们来看看基本的 Julia 代码与 Python 的比较。
基本语法
考虑一下下面这个用 Python 编写的猜谜游戏:
import random
def guessing_game(max):
random_number = random.randint(1, max)
print(f"Guess a number between 1 and {max}")
while True:
user_input = input()
guess = int(user_input)
if guess < random_number:
print("Too low")
elif guess > random_number:
print("Too high")
else:
print("That's right!")
break
guessing_game(100)
以下是 Julia 中的等效代码:
function guessing_game(max::Integer)
random_number = rand(1:100)
println("Guess a number between 1 and $max")
while true
user_input::String = readline()
guess = parse(Int, user_input)
if guess < random_number
println("Too low")
elseif guess > random_number
println("Too high")
else
println("That's right!")
break
end
end
end
guessing_game(100)
主要区别在于 Julia 不假设任何缩进或要求使用冒号,而是需要显式的“end”来结束 if 条件、循环和函数等构造的作用域。如果你来自 Matlab 或 Fortran,你应该会觉得很熟悉。
另一个你可能注意到的区别是 Julia 自然支持变量声明、函数参数(和返回类型,尽管很少使用)中的类型注解。它们总是可选的,但通常用于类型断言,允许编译器在方法重载多个类型时选择正确的方法实例,在某些情况下对于变量和结构体声明也有性能优势。
数学的优雅语法
# Elegant Expressions
x = 2
z = 2y + 3x - 5
# Official Unicode Support
α, β, γ = 1, 2, π/2
# one-line functions
f(r) = π*r²
f'(3) # derivative (with Flux.jl package)
# Column vector is literally a column
v₁ = [1
2
3
4]
v₂ = [1 2 3 4]
# transpose
println(v1' == v2)
# This is literally a 3x3 matrix
M⁽ⁱ⁾ = [1 2 3
4 5 7
7 8 9]
# Explicit modeling of missingness
X = [1, 2, missing, 3, missing]
Julia 相对于 Python 的一个重大优势是其对数学语法的支持。* 乘以常量时无需使用 latex 符号,支持变量名称的 latex 符号(可能需要使用 VSCode 插件将 \pi 转换为 π,v_1 转换为 v₁ 等),矩阵一般遵循代码定义中的布局。
例如,如果你要为神经网络实现梯度下降。
在 Python 中,你可能会写:
import numpy as np
# Gradient Descent in a Neural Network
J_del_B_n = [np.zeros(b) for b in B_n]
J_del_W_n = [np.zeros(W) for W in W_n]
for (x, y) in zip(x_batch, y_batch):
J_del_B_n_s, J_del_W_n_s = backprop(x, y)
J_del_B_n = [J_del_b + J_del_b_s for J_del_b,
J_del_b_s in zip(J_del_B_n, J_del_B_n_s)]
J_del_W_n = [J_del_W + J_del_W_s for J_del_W,
J_del_W_s in zip(J_del_W_n, J_del_W_n_s)]
d = len(x_batch)
W_n = [(1 - lambda_val * alpha / d) * W - lambda_val /
d * J_del_W for W, J_del_W in zip(W_n, J_del_W_n)]
B_n = [(1 - lambda_val * alpha / d) * b - lambda_val /
d * J_del_b for b, J_del_b in zip(B_n, J_del_B_n)]
比较一下你用 Julia 编写的代码的可读性:
# Gradient Descent in a NN
მJⳆმBₙ = [zeros(b) for b in Bₙ]
მJⳆმWₙ = [zeros(W) for W in Wₙ]
for (x, y) in zip(x_batch, y_batch)
მJⳆმBₙₛ, მJⳆმWₙₛ = backprop(x, y)
მJⳆმBₙ = [მJⳆმb + მJⳆმbₛ for მJⳆმb, მJⳆმbₛ in zip(მJⳆმBₙ, მJⳆმBₙₛ)]
მJⳆმWₙ = [მJⳆმW + მJⳆმWₛ for მJⳆმW, მJⳆმWₛ in zip(მJⳆმWₙ, მJⳆმWₙₛ)]
d = len(x_batch)
Wₙ = [(1 - λ*α/d)* W - λ/d * მJⳆმW for W, მJⳆმW in zip(Wₙ, მJⳆმWₙ)]
Bₙ = [(1 - λ*α/d)* b - λ/d * მJⳆმb for b, მJⳆმb in zip(Bₙ, მJⳆმBₙ)]
你可以尝试用 Python 编写类似的代码,但编辑器通常会在 Unicode 变量周围加上黄色方块(或无法高亮显示它们),而且你的代码可能无法与诸如 Pickle 的第三方包兼容。
照片由Solaiman Hossen拍摄,来源于Unsplash。
Julia 非常快速。
另一个使 Julia 被认为是 Python 梦想成真的主要原因是,与 Python、Ruby 和其他高级语言不同,它在保持高级的同时不会牺牲速度。实际上,它可以和低级语言如 C 和 C++ 一样快。
基准测试
作为参考,以下报告了 Julia 的性能,以及其他语言在流行性能基准测试中的表现:
Julia 微基准测试:图片来源于 JuliaLang 在 MIT 许可下
双语言问题
Julia 性能的一个推论是它解决了双语言问题:
-
研究代码(例如,一个机器学习模型)通常用高级语言如 Python 编写,因为它的高级和交互性;因此,能更专注于科学(减少代码问题)并允许更多探索。
-
一旦研究代码完成,它必须用低级语言如 C 重写,才能在生产中使用。
问题在于相同的代码必须用多种语言重写。这通常困难且容易出错;考虑到研究代码在发布后进行修改,最坏情况下,它将不得不再次用低级语言重写。
一种解决此问题的方法是将性能关键的库(例如,Numpy)用低级语言如 C 编写,然后可以用 Python 函数包装这些库,这些函数内部调用 C 代码,可以用于研究和生产而不必担心性能。在现实中,这种方法非常有限,因为:
-
这使得新开发者很难为他们编写的新颖科学方法做出贡献或进行合作,因为他们可能需要将这些方法用低级语言如 C 重写以提高性能,然后再在高级库中公开。
-
科学计算领域的高级语言可能会对开发人员施加一些搞笑的限制。例如,写显式的 for 循环可能会被强烈不鼓励。
Julia 通过保持高级、交互性强且非常快速,即使在生产环境中也能解决双语言问题。
Julia 是即时编译的。
有一小段关于 Julia 性能的说明。由于 Julia 是 JIT 编译的,任何 Julia 代码的第一次运行都需要更多时间来完成。在这段时间里,每个函数代码将被转换为特定变量类型的本地代码(即处理器可以解释的代码)。一旦完成,它将缓存编译后的表示,以便如果该函数再次被调用并且输入的类型相同,它将立即被解释。
更详细地说,对于一个有 N 个参数的函数,可能会有指数级数量的本地代码表示;每种可能的参数类型组合都有一个。Julia 会将函数编译成与首次运行代码时推断出的类型对应的表示。一旦完成,进一步调用该函数将变得轻而易举。请注意,在类型推断过程中,它不一定使用类型注释(这些注释是可选的,并且可以有我们提到的其他用途),类型可以从输入的运行时值中推断出来。
这不是问题,因为研究代码或在服务器上运行的代码只需初次编译一次,完成后任何进一步运行(实际 API 调用或进一步实验)的代码都非常快速。
由 Thom Milkovic 在 Unsplash 提供的照片
Julia 解决了表达式问题
表达式问题
表达式问题涉及能够定义一个在其表示(即支持的类型)和行为(即支持的方法)方面都可扩展的数据抽象。也就是说,解决表达式问题的方案允许:
-
添加新类型到现有操作适用的类型中
-
添加新操作到现有类型适用的类型中
而不违反开闭原则(或导致其他问题)。这意味着应该可以在不修改现有操作代码的情况下添加新类型,并且应该可以在不修改现有类型代码的情况下添加新操作。
Python 像许多其他编程语言一样,是面向对象的,未能解决表达式问题。
假设我们有以下数据抽象:
# Base class
class Shape:
def __init__(self, color):
pass
def area(self):
pass
# Child class
class Circle(Shape):
def __init__(self, radius):
super().__init__()
self.radius = radius
def area(self):
return 3.14 * self.radius * self.radius
很容易将新类型添加到现有方法应适用的类型中。只需继承 Shape
基类即可。这不需要修改任何现有代码:
class Rectangle(Shape):
def __init__(self, width, height):
super().__init__()
self.width = width
self.height = height
def area(self):
return self.width * self.height
同时,向现有类型中添加操作并不容易。如果我们想添加一个 perimeter
方法,那么必须修改基础类以及到目前为止实现的每一个子类。
这个问题的一个后果是,如果包x由作者 X 维护,并且最初支持操作集合Sx,而另一个操作集合Sy对另一组开发者 Y 有帮助,他们必须能够修改由 X 维护的包,以添加这些方法。在实践中,开发者 Y 通常会自己创建另一个包,可能会复制包x中的代码以实现该类型,因为开发者 X 可能不愿意维护更多的代码,而Sy可能是一种不同类型的方法,不需要存在于同一个包中。
另一方面,因为添加适用现有操作的新类型很容易,如果开发者 Y 希望定义一个新的类型,该类型实现了 X 实现的类型中的操作,他们可以很容易地做到这一点,而无需修改包x或复制其中的任何代码。只需导入该类型,然后从中继承即可。
多重分发
为了解决表达式问题,这允许不同包之间的大规模集成,Julia 完全摒弃了传统的面向对象编程。Julia 使用抽象类型定义、结构体(抽象类型的自定义类型实例)和方法以及一种称为多重分发的技术,正如我们将看到的,它完美地解决了表达式问题。
要查看我们上面所讨论的等效内容:
### Shape Abstract Type (Interface)
abstract type Shape end
function area(self::Shape) end
### Circle Type (Implements the Interface)
struct Circle <: Shape
radius::Float64
end
function area(circle::Circle)
return 3.14 * circle.radius²
end
在这里,我们定义了一个抽象类型Shape
。它是抽象的,这意味着它不能被实例化;然而,其他类型(类)可以从它中继承(子类化)。之后,我们定义了一个圆形类型,作为Shape
抽象类型的子类型,并定义了area
方法,同时指定输入必须是Circle
类型。这样我们可以进行
c = Circle(3.0)
println(area(c))
这将打印28.26
。虽然c
满足两个area
定义,因为它也是一个Shape
,但第二个定义更具体,因此编译器选择了它来调用。
类似于基于类的面向对象编程,添加另一个类型“rectangle”而不触碰现有代码是很容易的:
struct Rectangle <: Shape
length::Float64
width::Float64
end
function area(rect::Rectangle)
return rect.length * rect.width
end
现在当我们执行
rect = Rectangle(3.0, 6.0)
println(area(rect))
我们得到18.0
。这就是多重分发的作用;area
方法的正确实例是根据运行时参数的类型动态分发的。如果你有 C 或 C++的背景,这一定会让你想起函数重载。不同之处在于函数重载不是动态的,它依赖于编译时发现的类型。因此,你可以设计一些示例,其中它的行为会有所不同。
更重要的是,与基于类的 OOP 不同,我们可以向 Shape
、Circle
或 Rectangle
添加方法,而无需修改它们的文件。如果所有这些文件都在我的包中,而你希望添加一组方法来生成几何形状的动画和 3D 视觉效果(这是我不关心的),那么你只需导入我的包。现在你可以访问 Shape
、Circle
和 Rectangle
类型,你可以编写新的函数,然后将它们导出到你自己的“ShapeVisuals”包中。
### Interface definitions
function animate(self::Shape) end
function ThreeDify(self::Shape) end
### Circle definitions
function animate(self::Circle)
...
end
function ThreeDify(self::Circle)
...
end
### Rectangle defintions
function animate(self::Rectangle)
...
end
function ThreeDify(self::Rectangle)
...
end
你考虑一下,这与你知道的面向对象编程 (OOP) 的主要区别在于它遵循 func(obj, args)
的模式,而不是 obj.func(args)
。作为附加好处,它也使 func(obj1, obj2, args)
等操作变得轻而易举。另一个区别是它不会将方法和数据封装在一起或对它们施加任何保护;也许这在开发人员足够成熟且代码已被审查时是一个无关紧要的措施。
抽象与具体类型
你现在知道抽象类型只是一个你无法实例化值的类型,但其他类型可以从它子类化,这为讨论 Julia 的类型系统铺平了道路。请记住,使用语法 var::type
来注释变量的类型是可选的,无论是在声明时、作为函数参数还是返回值。
Julia 中的任何类型要么是抽象的,如我们上面定义的,要么是具体的。具体类型是那些你可以实例化的,就像我们上面定义的自定义类型一样。
Julia 为数字提供了以下层次化的类型系统:
Julia 微基准测试:图片来自 Julia for Optimization and Learning 根据 MIT 许可协议
如果你的函数接受一个参数并对任何数字进行操作,你将使用 func(x::Number)
。只有当传入非数字值,如字符串时,才会抛出错误。与此同时,如果它仅适用于任何浮点数,那么你将使用 func(x::AbstractFloat)
。如果输入的类型是 BigFloat, Float64, Float32 或 Float16
,则不会抛出错误。由于存在多重分派,你还可以定义另一个函数实例 func(x::Integer)
来处理给定数字为整数的情况。
Julia 也有一个层次化的类型系统用于 其他抽象类型,如 AbstractString
,但它们要简单得多。
图片由 Paul Melki 提供,Unsplash
Julia 功能齐全
如果你考虑一下,Python 开箱即用地只有基本功能。例如,如果你仅使用 Python 而没有像 Numpy 这样的流行软件包,你在数据科学和科学计算方面能做的事情非常有限。该领域的大多数其他软件包也严重依赖 Numpy。它们都使用并假定“ Numpy” 数组类型(而不是默认的 Python 列表类型),就像它是语言的一部分一样。
Julia 并不是这样。它开箱即用地提供了许多重要的特性,包括:
数组支持
Julia 开箱即用地提供了类似于 Numpy 的数组支持,包括广播和矢量化支持。例如,以下比较了流行的 Numpy 操作与如何在 Julia 中原生编写它们:
#> 1\. Creating a NumPy array
### Python
arr = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
### Julia
arr = [1 2 3
4 5 6
7 8 9]
#> 2\. Getting the shape of an array
### Python
shape = arr.shape
### Julia
shape = size(arr)
#> 3\. Reshaping an array
### Python
reshaped_arr = arr.reshape(3, 3)
### Julia
reshaped_arr = reshape(arr, (3, 3))
#> 4\. Accessing elements by index
### Python
element = arr[1, 2]
### Julia
element = arr[1, 2]
#> 5\. Performing element-wise arithmetic operations
### Python
multiplication = arr * 3
### Julia
multiplication = arr .* 3
# 6\. Array concatenation
### Python
arr1 = np.array([[1, 2, 3]])
arr2 = np.array([[4, 5, 6]])
concatenated_arr = np.concatenate((arr1, arr2), axis=0)
### Julia
arr1 = [1 2 3]
arr2 = [4 5 6]
concatenated_arr = vcat(arr1, arr2)
#> 7\. Boolean masking
### Python
mask = arr > 5
masked_arr = arr[mask]
### Julia
mask = arr .> 5
masked_arr = arr[mask]
#> 8\. Calculating the sum of array elements
### Python
mean_value = arr.sum()
### Julia
mean_value = sum(arr)
字符串支持
Julia 还开箱即用地提供了对字符串和正则表达式的广泛支持:
name = "Alice"
age = 13
## concatentation
greeting = "Hello, " * name * "!"
## interpolation
message2 = "Next year, you will be $(age + 1) years old."
## regex
text = "Here are some email addresses: alice123@gmail.com"
# Define a regex for emails
email_pattern = r"[\w.-]+@[\w.-]+\.\w+"
# match emails
email_addresses = match(email_pattern, text)
"aby" > "abc" # true
当字符串被比较时,按字典顺序(一般的字母顺序)靠后的字符串被认为比靠前的字符串大。可以证明,大多数在 Perl 等高级字符串处理语言中可以做的字符串操作,也可以在 Julia 中完成。
多线程
Python 不支持真正的并行多线程是因为它有一个全局解释器锁(GIL)。这禁止了解释器同时运行多个线程,以便通过一种过于简单的解决方案来保证线程安全。只有在多个线程之间切换才是可能的(例如,如果一个服务器线程忙于等待网络请求,解释器可以切换到另一个线程)。
幸运的是,在 Python 调用的 C 程序中释放这个锁并不难,这解释了为什么 Numpy 是可能的。然而,如果你有一个大规模的计算循环,那么你不能编写可以并行执行的 Python 代码来加速计算。Python 的悲惨现实是,大多数应用于大数据结构(如矩阵)的数学操作都是可以并行化的。
与此同时,Julia 原生支持真正的并行多线程,并且只需简单操作即可实现:
# Before multi-threading
for i in eachindex(x)
y[i] = a * x[i] + y[i]
end
# After multi-threading
Threads.@threads for i in eachindex(x)
y[i] = a * x[i] + y[i]
end
运行代码时,你可以指定要使用系统中可用的线程数量。
与 C 代码的轻松集成
从 Julia 调用 C 代码的过程是开箱即用并且比 Python 更高效和更容易。如果你想调用
#include <stdio.h>
int add(int a, int b) {
return a + b;
}
然后主要步骤(在小的设置之后)是在 Julia 中调用此函数就是编写
# specify function, return type, arg types and input. Prefix types with "C"
result = ccall(add, Cint, (Cint, Cint), 5, 3)
在 Python 中做到这一点要复杂得多,效率可能更低。特别是因为将 Julia 类型和结构映射到 C 中的类型和结构要容易得多。
这一个主要的结果是,可以在 Julia 中运行绝大多数能够输出 C 代码的语言。通常,外部的知名软件包存在于这些语言中。例如,要调用 Python 代码,你可以使用 PyCall.jl
软件包,如下所示:
using PyCall
np = pyimport("numpy")
# Create a NumPy array in Python
py_array = np.array([1, 2, 3, 4, 5])
# Perform some operations on the NumPy array
py_mean = np.mean(py_array)
py_sum = np.sum(py_array)
py_max = np.max(py_array)
除了安装包外,几乎不需要任何先期设置。使用类似的包,也可以调用用 Fortran、C++、R、Java、Mathematica、Matlab、Node.js 等编写的函数。
另一方面,可以从 Python 调用 Julia,尽管不如优雅。这可能以前用于加速函数,而不需要用 C 实现它们。
标准库
一组包随 Julia 预安装(但需要显式加载)。这包括Statistics和LinearAlgebra包、用于访问互联网的Downloads包,以及更重要的分布式计算(如 Hadoop)的Distribued包,还有用于性能分析(帮助优化代码)的Profile包,显著的Tests包用于单元测试和Pkg包用于包管理,以及许多其他包。
我必须说,我是一个热衷于 Python 的用户,开发了多个 Python 包。在 Python 中,第三方包“Setuptools”和 Julia 中的Pkg之间没有可比性,后者确实更干净、更易于使用。我一直无法理解为什么 Python 没有自己的包管理和测试工具。这些在编程语言中确实是基本需求。
Julia 是通用的
介绍
如果你曾经遇到过 Julia,那么你会自然地认为 Julia 是一个领域特定的语言,科学计算是这个领域。确实,Julia 经过精心设计,以便在科学计算中具有表现力和效率,但这并不妨碍它成为通用语言。它只是一个以科学计算为重点构建的语言。语言的通用性有一定的程度。例如,Julia 可以用于数据科学和机器学习、网页开发、自动化和脚本编写、机器人技术等,除了科学计算,但目前还没有成熟的包帮助开发者使用 Julia 进行类似于 Python 中 Pygame 的游戏开发。即使 Julia 包Genie.jl
非常接近Flask
,它可能在更全面的框架如Django
方面有所欠缺。总之,即使 Julia 目前不像你期望的那样通用,但它是以此为目标构建的,并预计最终会实现这一点。
自动化和脚本编写
既然提到 Julia 可以用于自动化和脚本编写,值得指出的是,它通过优雅的类似 Shell 的语法帮助实现这一点。
例如,这里是一组你可以在 Julia 中执行的文件系统和进程操作:
# Create a directory
mkdir("my_directory")
# Change the working directory
cd("my_directory")
# List files in the current directory
println(readdir())
# Remove the directory
rm("my_directory"; recursive=true)
# Check if a file exists
if isfile("my_file.txt")
println("File exists.")
else
println("File does not exist.")
end
# Run a simple shell command from Julia
run(`echo "Hello, Julia!"`)
# Capture the output of a shell command
result = read(`ls`, String)
println("Contents of the current directory: $result")
注意你在终端中实际输入的内容的相似性。
星夜数字艺术的替代品 — 作者使用 DALLE 2 生成
Julia 具有广泛的扩展性
介绍
LISP 编程语言中的一个美丽特性是它是同构的。这意味着代码可以像数据一样处理,因此普通开发者可以向语言中添加新特性和语义。Julia 也被构建为同构的。例如,记得我说过 Julia 仅支持多重分发。好吧,看起来有人制作了一个 ObjectOriented.jl
包,允许开发者在 Julia 中编写面向对象编程。另一个例子是,如果你创建任何新类型,很容易重载基函数和操作符(它们只是函数)以适应你的新类型。
宏
Julia 对宏的支持是实现这一点的主要原因。你可以将宏视为一个在程序解析时返回要执行的代码的函数。假设你定义了以下宏:
macro add_seven(x)
quote
$x + 7
end
end
类似于函数,这允许你以这种方式调用它:
x = 5
@add_seven x
这返回 12。发生的事情是,在解析时(编译前),宏执行,返回代码 5 + 7
,在编译时计算为 12
。你可以认为宏只是动态执行 CTRL+H
(查找和替换)操作的一种方式。
对于另一个实际应用场景,假设你有一个包含 10 个有用方法的包,你想向包中添加一个新接口,这意味着你需要为每个方法编写一个结构体,共 10 个。假设根据对应的函数编写这些结构体是有系统的,那么你可以简单地编写一个宏,循环遍历这 10 个函数来生成这 10 个结构体的代码。实际上,你编写的代码将等同于以通用方式编写一个结构体,因此节省了时间。
宏的存在允许更多的魔法。例如,如果你记得上面,我们能够使用 Threads.@threads
宏对一个 for 循环进行多线程。要测量函数调用的执行时间,你只需使用 @time func()
,如果你使用 BenchmarkTools
包,那么 @benchmark func()
会多次调用函数,以返回时间统计数据,甚至生成小图。如果你知道什么是备忘录化,那么也可以通过一个简单的 @memoize
宏将其应用于任何函数,无需以任何方式修改它。还有 @code_native func()
可以显示函数生成的原生代码,以及其他宏可以在编译过程中显示代码的其他表示形式。
总结
事实证明,我们讨论的所有语言特性最初都是 Julia 计划的一部分。正如 Julia 网站上所述,这是该语言的愿景:
“我们想要一种开源的语言,拥有宽松的许可证。我们想要 C 语言的速度,结合Ruby 的动态特性。我们希望这是一种同构的语言,拥有像 Lisp 一样的真正宏,但使用明显的、类似于 Matlab 的数学符号。我们希望它在通用编程方面像 Python 一样好,在统计分析方面像 R 一样简单,在字符串处理方面像 Perl 一样自然,在线性代数方面像 Matlab 一样强大,在将程序连接在一起方面像 Shell 一样出色。我们希望它简单易学,但仍能让最严肃的黑客满意。我们希望它是互动式的,并且我们希望它可以编译。”
阅读了这个故事,你现在应该或多或少能够反思愿景声明中提到的每一个词。
我希望阅读这些内容能够帮助你更多地了解 Julia 语言,并且你会考虑学习这门语言。下次见,再见。
拥抱叙事数据可视化的艺术
通过 NASA 的 TESS 任务进行的数据可视化
·
关注 发表在 Towards Data Science ·8 min read·2023 年 8 月 21 日
–
叙事视觉场景的示例,用于探索系外行星的特点 — 作者
数据可视化是向读者展示复杂数据的强大工具。更进一步,叙事可视化使我们能够构建数据故事,将信息转化为一系列引人入胜的场景。这种方法为观众量身定制了体验。
叙事可视化是关于打造引导观众穿越数据的场景。它以创新的方式呈现数据,通过这些数据讲述一个故事。这个故事强调关键点以增加互动性,使观众能够与图表建立联系。每个视觉元素应被精心编织成一个有意义的故事。这样,这些数据就能在主动引发观众感官的同时,进行有效的传达。这样的数据接触方式允许观众在一段时间内记住重要信息。
本文将探讨叙事可视化的概念及其在数据传达中的应用。由 NASA 的过境系外行星勘测卫星(TESS)任务发现的系外行星将作为我们检视叙事可视化的一个视角。我们还将探讨 D3,这是一款强大的用于创建数据驱动文档的 JavaScript 库。
解码叙事可视化的基础
叙事可视化的核心在于制作视觉吸引人的图表,并带领观众发现数据。数据在开始时被简要介绍;在中间阶段被深入探索,并以揭示关键见解或提供灵活的探索工具作为结尾,从而形成一个互动故事。
这是一个将数据组织成特定结构的过程,打造一个视觉故事,而不是随机呈现事实和数据。因此,数据成为故事中的角色,你作为叙述者的工作是通过视觉效果使这些角色栩栩如生。观众在与数据故事互动的过程中,会建立联系并识别出模式,这些模式容易在长时间内被记住。
叙事可视化有三种主要结构:
-
作者驱动的叙事:作者通过数据提供了特定的路径并决定故事方向,以结构化的方式引导观众穿越数据。作者驱动的可视化在清晰传达见解方面非常有效,例如视频。
-
读者驱动的叙事:这种方法将控制权交给观众。它提供了更具互动性的体验,观众可以按照自己的节奏探索数据并跟随自己的路径。这有助于鼓励参与和探索。例如,互动仪表板就是一个例子。
-
混合叙事:结合了作者驱动和读者驱动叙事的元素。它们通常以作者驱动的介绍开始,随后是读者驱动的探索部分。这在引导讲故事和互动探索之间提供了平衡。例如,Martini Glass 数据表示就是一个例子。
martini glass sketch — 作者提供
在接下来的部分中,我们将使用“马提尼酒杯”结构,这是一种流行的混合叙事方式,来可视化 NASA TESS 任务的数据。该结构提供了一个初步由作者驱动的概述(酒杯的柄),随后是一个由读者驱动的探索空间(酒杯的碗)。这允许我们在让观众深入探索数据之前,带领他们了解数据的关键点。
案例研究:通过 NASA 的 TESS 任务发现系外行星
TESS 任务的概念 — 由NASA 戈达德太空飞行中心提供(许可详情见参考文献)
2018 年,NASA 通过发射凌日系外行星勘测卫星(TESS)任务,开始了探索太阳系之外系外行星的旅程。
TESS 任务已被证明是一个天文学上的宝藏。通过这一任务,NASA 积累了超过 90 个数据点。这些数据点包含关于每个系外行星的宝贵信息,有助于解开宇宙之谜。这些数据包括系外行星的名称、其宿主恒星和发现年份,以及它们的物理特征:大小、形状、偏心率和轨道周期。这些数据集概括了每个系外行星的故事,使 TESS 任务的事实和数据揭示出引人入胜的宇宙故事。
数据样本 — 原始数据包含超过 90 列
我们将使用TESS 数据创建叙事可视化,讲述多年来系外行星发现的故事,并使用最后的灵活工具进行深入分析。
场景 1:已发现系外行星概览 叙事从 2018 年到 2023 年 TESS 发现的系外行星概览开始,重点突出时间趋势,并在高层次上将某些特征与地球范围进行比较。这为我们的故事奠定了基础,提供了有关 TESS 任务范围和规模的背景。第一场景细分为三个具体的可视化,旨在展示数据的独特概览:
-
每年发现的系外行星数量直方图:展示了每年发现的系外行星数量。每根柱子的高度对应于发现的数量。为了提供互动体验,点击柱子会筛选其他图表中的数据,以便集中分析该年发现的系外行星。
-
平衡温度与轨道离心率的散点图:该散点图通过比较系外行星的平衡温度和轨道离心率,提供了系外行星特性的视图。平衡温度在 x 轴上显示,近似于系外行星的平均温度。轨道离心率在 y 轴上显示,表示系外行星轨道与完美圆形的偏差程度。交互式元素使用户能够进一步探索数据:悬停在圆圈上会显示数据概览,而点击则会转到第二个场景进行详细的探索视图。
-
恒星质量与半径的散点图:聚焦于主星,该可视化将恒星质量与半径进行比较,每个都由一个圆圈表示。与之前的可视化一样,交互功能允许用户探索特定的行星特性。
场景 1 — 按年份展示的系外行星概述
场景 2:单个系外行星的深入探索
接下来,我们通过点击单个系外行星来深入探讨,探索它们独特的特性,并将这些特性与地球上的范围进行比较。数值以一系列水平条形图呈现,描述特定参数并将系外行星的值与相应的地球范围进行比较。
本场景提供了对使每个行星独特的属性的更详细了解,如平衡温度、行星半径、轨道半长轴、轨道离心率,以及主星的半径和质量。
场景 2 — 单个系外行星特性与地球范围的比较
场景 3:TESS 数据的交互式探索
最终场景提供了一个交互式探索工具,允许用户更改各种比较范围并选择要比较的特性。在这个场景中,我们允许进行个性化的探索体验。
场景 3 — 交互工具
本案例研究展示了叙事可视化在使复杂数据变得易于访问和有趣方面的力量。在下一部分,我们将探讨实现细节。
使用 D3 进行叙事可视化
D3.js 是一个 javascript 框架,用于在网页上进行交互式数据可视化。在我们开始构建 TESS 叙事可视化之前,让我们先探讨一下 D3 的一些基本功能。
选择元素:
D3 的一个重要功能是 ‘select’ 方法。它允许我们识别 HTML 文档中需要调整的元素。例如:
d3.select("#visualization")
附加和操作元素:
D3 可以使用 append
、attr
和 style
方法构建和管理 SVG 元素。
-
append
方法将新的元素(圆圈、矩形等)引入到 SVG 中,每个元素代表不同的数据点。 -
attr
和style
调整这些元素的属性和样式,如其位置、大小和颜色。
绑定数据:
使用 data
方法,D3 将数据绑定到视觉元素上。这使其在创建数据驱动的可视化方面发挥了优势,允许动态更新。
缩放:
缩放将输入域映射到输出范围,调整数据的绘制区域。例如,d3.scaleLinear()
使用线性缩放,其中输入域中的任何给定数字直接对应输出范围中的一个数字。
构建 TESS 场景
现在我们已经了解了 D3 的基础知识,我们可以使用 TESS 任务数据(可在此处获取)构建引人入胜的叙事。为了简洁起见,本文详细讨论了前两个场景的基础知识。您可以查看 GitHub 仓库 以获取全面的场景实现。
准备 HTML
在头部加载 d3 库
<script src="https://d3js.org/d3.v7.min.js"></script>
然后准备一个容器 div 来绘制图表:
<div id="visualization"></div>
场景 1:发现的系外行星概述
下面是我们创建第一个场景的方式:
-
使用
d3.csv
函数加载并存储 TESS 数据到一个变量中。 -
散点图展示了 TESS 随时间发现的系外行星。
-
添加了互动性,允许用户点击特定的系外行星并导航到场景 2。
加载数据并调用代码以绘制第一个场景:
d3.csv("data/tess_confirmed_plannets.csv").then(function(myData) {
data = myData;
// Scene 1: Overview
drawScene1(myData);
});
让我们通过在散点图中显示系外行星来绘制第一个场景的示例,查看行注释以获取实现细节:
TESS 任务数据探索 — scene1 代码示例,用于绘制概述散点图
场景 2:对单个系外行星的详细探索
我们将按照以下步骤创建第二个场景:
-
创建
drawScene2
函数以使用选定系外行星的数据。 -
创建展示选定系外行星的特征并与地球范围进行比较的视觉元素。
TESS 任务数据探索 — scene2 代码示例,用于将单个系外行星特征与地球范围进行比较
给出的代码是场景 1 和场景 2 的简化版本。完整的代码,包括互动元素和功能,可以从链接的 GitHub 仓库中获取。
您可以查看下面的最终叙事结果:
barqawiz.github.io/NASA_TESS_Narrative/
总之,叙事可视化偏离了单调的数据沟通路径,踏上了一段旅程。数据以结构化但引人入胜的方式呈现,以吸引观众的注意。这些数据故事以个性化的方式吸引观众。然而,这些故事的策展人可以有意选择他们的叙事结构,以实现高效的数据讲述,无论是作者驱动的、读者驱动的还是混合叙事。
NASA 的过境系外行星勘测卫星任务数据被用作案例研究,以展示叙事可视化。这个 TESS 任务发现了超过 90 个特征的系外行星,超出了我们的太阳系。混合的马提尼杯方法用于向观众传达这些数据。叙事从作者驱动的方法开始,然后通过读者驱动的方法过渡到关于系外行星的详细信息,进行互动和个性化的探索。
创作视觉叙事是一门艺术,明确你的最终目标和目标受众,并选择故事结构,对数据的隐含意义和吸引观众至关重要。
参考文献
-
NASA TESS 任务画廊: 链接
-
NASA 系外行星档案: 链接
-
NASA 内容政策: 链接
-
地球事实表: 链接
-
包含完整代码的 Github 仓库: 链接
-
清理后的数据: 链接
-
UIUC 课程 “CS 416: 数据可视化”。
引用:NASA 内容(图像、视频、音频等)通常不受版权保护,可以用于教育或信息目的而不需要明确许可。
人工智能中的涌现能力:我们在追逐一个神话吗?
原文:
towardsdatascience.com/emergent-abilities-in-ai-are-we-chasing-a-myth-fead754a1bf9
观点
对大型语言模型涌现性质的视角转变
·发布在 Towards Data Science ·阅读时间 11 分钟·2023 年 5 月 16 日
–
作者使用 DALL-E 创作的图片
一个模型的涌现性质
涌现性质不仅仅是人工智能领域的概念,它适用于所有学科(从物理学到生物学)。这一概念一直吸引着科学家们,无论是在描述还是试图理解其起源方面。诺贝尔奖获得者物理学家P.W. Anderson用“更多即不同”来综合这一思想。在某种意义上,它可以被定义为涌现性质,即随着系统复杂性的增加而出现的性质,无法预测。
例如,你可以用一个小分子来编码信息,但 DNA(一个大分子)编码的是基因组。或者少量铀并不会导致核反应。
“复杂对称和分形 模式 在雪花中的形成体现了物理系统中的涌现现象”。图片来源:这里
最近,在人工智能模型中观察到了相同的行为,最常见的定义之一是:“如果某种能力在较小的模型中不存在但在较大的模型中存在,那么它就是涌现的。”
这意味着什么?如何观察到?
OpenAI 在一篇文章中声明,模型的性能遵循规模法则:数据和参数越多,性能越好。对于涌现属性,预期是一个特定的模式:随着参数数量的增加,性能几乎是随机的,直到达到某个阈值时,观察到某种属性(性能开始显著改善)。基本上,我们看到曲线的急剧转折(称为相变)。这也被称为涌现,因为通过检查小规模模型无法预测。
大型语言模型的涌现能力。图片来源 (这里)
总之,我们可以说,如果一个属性满足这两个条件,它被认为是涌现的:
-
敏锐性,其过渡在存在或不存在之间是不连续的。
-
不可预测性,随着参数的增加,其出现无法预测。
此外,扩展一个变换器模型主要考虑三个因素:计算量、模型参数数量和训练数据集大小。
这三个因素都使得模型昂贵。另一方面,这些属性特别受到追求,也被用作增加参数数量的理由(尽管模型并未得到最佳训练)。
图片来源:这里
一些研究还集中在为什么这些属性会出现,为什么以这种方式出现,以及为什么在特定阈值下出现。据一些观点,某些属性的出现是可以预测的:
例如,如果一个多步推理任务需要 l 步顺序计算,这可能需要一个至少有 O (l) 层深度的模型。 (source)
也提出了替代解释,如更多的参数有助于记忆。随着数据的增加,模型获得知识,并在某一点达到临界质量,能够支持该属性。
此外,一些作者提出,不同的架构和更好的数据质量可能会导致这些属性在更小的模型中也出现。
在 LLaMA 的研究中,观察到一个比 GPT-3 小得多的模型展示了相似的属性和性能。
META 开源模型将帮助我们理解语言模型的偏见是如何产生的。
medium.com](https://medium.com/mlearning-ai/metas-llama-a-small-language-model-beating-giants-5065948e0b7f?source=post_page-----fead754a1bf9--------------------------------)
无论如何,问题依然存在,为什么这些属性会出现?
Anthropic 在一项研究中指出:
大型生成模型具有矛盾的特性——高可预测性——模型损失与训练所花费的资源有关,且与许多任务的性能改善有松散的相关性——以及高不可预测性——特定的模型能力、输入和输出无法提前预测(来源)
简而言之,对于一个大型语言模型,我们可以预测的事物和无法预测的事物是存在的。例如,扩展规律允许我们预测增加参数数量将提升规模上的性能,但同时,我们无法预测某些属性的涌现,这些属性会随着参数的增加而突然出现。
因此,根据这一原则,我们甚至不应尝试预测这些属性。
扩展规律可靠地预测模型性能。图像来源:这里
三个突发特定能力扩展属性的例子。图像来源:这里
为什么我们如此关注预测这些属性?
第一个原因是纯粹的经济学:如果某个属性只有在特定数量的参数下才会出现,我们就不能使用较小的模型。这显著增加了训练和硬件的成本。另一方面,如果属性无法预测,我们甚至无法估算获得该属性的成本。
其次,这解释了在寻找新属性时参数异常增加的原因,这些新属性会在参数达到万亿级时出现。毕竟,这可能是获得某些属性的唯一途径。
此外,这还带来了安全问题,因为我们无法预测模型在特定规模下会具备什么属性。一个模型可能会发展出问题属性,可能不适合部署。而且,这么大的模型也更难检测偏见和危害。
此外,扩展规律和涌现属性也是推动大型模型快速发展的原因之一。
这开启了一个令人担忧的情景,一方面,我们有开源模型的爆炸性增长、训练成本的降低和聊天机器人的使用增加。但另一方面,我们无法预测这些模型的属性。
开源、数据和注意力:LLM 的未来将如何变化
towardsdatascience.com
如果涌现属性只是海市蜃楼呢?
图片由Nick Fewings提供,来源于 Unsplash
2020 年,谷歌研究人员意识到了 LLMs 的潜力,并预测它们将具有变革性。因此,他们请社区提供既不同又困难的任务示例,然后可以用来测试 LLM 的能力。由此诞生了超越模仿游戏基准(BIG-bench)项目。
这个项目实际上也集中于研究新兴和惊人的属性,并尝试理解它们的起源。
图片来源:这里
确实,该数据集和文章讨论了概率的出现,并试图提供解释。例如,超过十亿参数的模型能够解决三位数加法或两位数乘法问题。
基于这篇文章,斯坦福大学的研究人员在最近的一篇论文中质疑了语言模型的新兴属性这一概念。
最近的研究声称,大型语言模型显示出新兴能力,这些能力在小规模模型中并不存在……
arxiv.org](https://arxiv.org/abs/2304.15004?source=post_page-----fead754a1bf9--------------------------------)
实际上,作者注意到,新兴属性似乎仅在非线性或其他不连续的度量下出现。
作者提供了一个替代假设来解释属性的出现。他们认为这是性能测量的选择。换句话说,错误每个标记随着模型规模的增加平稳、持续和可预测地增长。但随后研究作者使用了不连续的度量来衡量任务性能,因此模型的任务表现看起来是突发性的。
换句话说,一个小模型在某个任务上表现尚可,但我们无法检测到,因为所选择的度量是不连续的,只有在某个错误(在某种模型规模下达到)下,我们才能观察到任务性能。
图片来源:这里
根据作者的说法,测试中样本数量少也导致小模型没有得到适当评估。
为了证明这一点,作者从规模定律开始,根据该定律,性能(或错误)随着度量数量的增加而增加,并且这种现象在不同规模下确实是一致的。正如作者所指出的,许多度量需要序列中的所有标记都正确,尤其是在处理长序列时,错误会显著增加。
他们能够使用 InstructGPT/GPT-3 进行这些实验,因为像 LaMDA、Gopher 和 Chinchilla 这样的模型不幸地无法访问。这阻止了他们对不同模型进行广泛的评估。由于 LLMs 仅在文本上进行训练(而 GPT 则训练于预测下一个词),LLMs 的一个令人惊讶的能力是整数算术任务。正如 GPT-3 介绍文章所显示的那样,这一特性在规模的函数中被定义为突现特性。
不同规模模型在少样本设置下的所有 10 个算术任务的结果。图片来源:这里
如图所示(顶部),当使用非线性度量来测量性能时,我们看到了一种突现特性。而当使用线性度量(底部)时,我们看到性能随规模的变化呈现出连续且可预测的增长。
图片来源:这里
此外,作者指出,通过增加小模型评估的数据,即使使用非线性度量,效果也没有那么明显。换句话说,如果测试数据集较大,即使使用非线性度量,我们也不会观察到如此显著的效果。
实际上,在低分辨率(少量测试数据)下,小模型的零准确率更可能出现,这支持了一个特性仅在达到某个阈值后才会突现的说法。
图片来源:这里
作者随后决定扩展到关于突现特性的元分析,使用 BigBench(因为它是公开的且文档记录完善)。此外,这个数据集提供了多个评估度量。当作者查看非线性度量(精确字符串匹配、选择题评分、ROUGE-L-Sum)时,可以观察到突现特性。另一方面,使用线性度量则没有观察到突现特性。
最令人惊讶的发现是,92%的声称的突现能力来源于使用两个不连续度量:选择题评分和精确字符串匹配。
因此,如果确实是由于不连续度量的使用导致了突现特性,仅仅更改度量就足以使这些特性消失。保持模型和任务不变,只需更改评分度量,突现特性就会消失。在这种情况下,作者只是重复使用了 LaMDA 系列模型的输出,并将度量从不连续的(选择题评分)更改为连续的(Brier 评分)。
最后一个问题是:但如果突现特性是通过选择不连续度量出现的,我们可以使用不连续度量来创造突现特性吗?
作者以手写数字数据集(MNIST 或数据科学家的最爱数据集)的分类能力为例。任何尝试在此数据集上训练卷积网络的人都注意到,即使只有少数几层,也能获得相当好的结果。增加层数可以提高准确率。如果这是一个突现属性,我们会期望一开始准确率接近零,通过将参数增加到某个阈值以上,准确率会显著提高。
作者使用了LeNet家族(多个具有递增参数数量的模型)。他们简单地选择了一种新的度量,称为子集准确率:“如果网络正确分类了 K 个 K(独立)测试数据,则为 1,否则为 0。”
在使用测试准确率时,我们注意到经典的准确率随 S 型趋势增加,使用新的不连续度量时,似乎分类手写数字的能力是一种突现属性。
作者提供了另一个例子:使用自编码器进行图像重建。通过创建一个新的不连续度量,自编码器的重建能力成为了一种突现属性。
作者总结道:
突现能力可能是研究者选择的产物,而不是模型家族在特定任务上的基本属性(source)
换句话说,如果有人想要突现属性,他们所要做的就是选择一个不连续度量,神奇地,他们将看到在某个参数阈值之上出现一个属性。
作者保守地声明:“本文应被解读为声称大型语言模型无法展示突现能力。” 他们只是声称,迄今为止看到的属性是由度量的选择产生的。
现在确实是这样,直到你看到一只黑天鹅之前,所有天鹅都是白色的。然而,下次出现突现属性时,必须检查其出现的条件。此外,这也是再次思考现在可能不适合评估模型质量的基准的呼吁。其次,大型语言模型应该是开源的,因为任何声明都可能仅仅是由于评估的选择。
结束语
长时间以来,突现属性被认为是大型语言模型(LLMs)中最令人惊讶的行为之一。超出一定数量的参数后,能力会出现,这既是一个迷人的概念,又是一个令人恐惧的概念。确实,一方面,它进一步证明了寻找越来越大模型的理由。另一方面,潜在危险能力的突现没有警告是个问题。
这篇文章意外地展示了评价指标的选择如何导致属性的出现。这促使我们重新思考基准测试,并将重点转向评价指标的选择。其次,可能并不存在涌现属性。
更广泛地说,许多作者一直选择让他们的数据脱颖而出的评价指标。因此,只有当模型及其输出对公众开放,供独立的科学研究时,我们才能确信某一主张的真实性。
如果你觉得这很有趣:
你可以查看我的其他文章,你也可以 订阅 以便在我发布文章时获得通知,你还可以 成为 Medium 会员 以访问所有故事(这是平台的附属链接,我会从中获得少量收入,不会给你带来任何费用),你也可以在LinkedIn上与我联系或找到我。
这是我 GitHub 仓库的链接,我计划在这里收集与机器学习、人工智能等相关的代码和许多资源。
[## GitHub - SalvatoreRa/tutorial: 机器学习、人工智能、数据科学的教程…
机器学习、人工智能、数据科学的教程,包含数学解释和可重用的代码(使用 python…
github.com](https://github.com/SalvatoreRa/tutorial?source=post_page-----fead754a1bf9--------------------------------)
或者你可能对我最近的文章之一感兴趣:
一个在医学院(或在知识竞赛之夜)能成为你最佳朋友的小模型
levelup.gitconnected.com](https://levelup.gitconnected.com/pmc-llama-because-googling-symptoms-is-not-enough-e1b875ee4c4a?source=post_page-----fead754a1bf9--------------------------------) [## 欢迎回到 80 年代:卷积可能会打破变形金刚
Hyena 模型展示了卷积如何可能比自注意力更快
levelup.gitconnected.com](https://levelup.gitconnected.com/welcome-back-80s-transformers-could-be-blown-away-by-convolution-21ff15f6d1cc?source=post_page-----fead754a1bf9--------------------------------) [## 注视你的眼睛:谷歌 AI 模型如何通过眼睛预测你的年龄
新模型可以通过分析眼睛照片解锁衰老的秘密
表情符号有助于社交媒体情感分析:不要再清除它们了!
在社交媒体情感分析中利用表情符号来提高准确性。
·
关注 发布于 Towards Data Science ·14 分钟阅读·2023 年 1 月 31 日
–
图片由 Denis Cherkashin 提供,来源于 Unsplash
简明扼要:
-
无论你使用什么模型,或如何在分析中纳入表情符号,将表情符号包括在社交媒体情感分析中都能显著提高情感分类的准确性
-
超过一半的流行 BERT 基础编码器不支持表情符号
-
Twitter-RoBERTa 编码器在情感分析中表现最佳,并且与表情符号协调良好
-
与其清除表情符号,不如将它们转换为文本描述,这可以帮助提高情感分类的准确性并处理词汇表外的问题。
随着社交媒体成为人们生活的重要组成部分,人们在互联网上分享的内容对许多方面都极具价值。许多现代自然语言处理(NLP)技术被应用于理解公众的社交媒体帖子。情感分析是最受欢迎和最关键的 NLP 话题之一,侧重于计算性地分析对书面文本中实体的意见、情感、情绪或态度[1]。因此,社交媒体情感分析(SMSA)是一个理解和学习在短社交媒体帖子中表达情感的领域。
这个项目的另一个重要特征是可爱的文内图形——表情符号😄。这些图形符号在社交媒体通讯中越来越受到欢迎。根据Emojipedia 的统计数据(2021 年),一个著名的表情符号参考网站,现在超过五分之一的推文包含表情符号(21.54%),而超过一半的 Instagram 评论中包含表情符号。表情符号是一种方便且简洁的表达情感和传达意义的方式,这可能解释了它们的巨大受欢迎程度。
尽管表情符号在网络通信中无处不在,但它们在 NLP 和 SMSA 领域并不受青睐。在数据预处理阶段,表情符号通常会与其他非结构化信息如 URL、停用词、特殊字符和图片一起被删除[2]。虽然一些研究人员近年来开始研究在 SMSA 中包含表情符号的潜力,但这仍然是一种小众方法,等待进一步研究。这个项目旨在检验流行的 BERT 编码器对表情符号的兼容性并探索将表情符号融入 SMSA 以提高准确性的方法。
目录
1 背景知识
1.1 SMSA 究竟是什么?
1.2 情感分析方法的发展
2实验2.1 模型设计
2.2 数据准备阶段的经验教训(一个悲伤的故事)
2.3 BERT 家族的表情符号兼容性测试
2.4 实验方法来预处理表情符号
3 结果讨论 4 结论致谢参考文献
1 背景知识
1.1 SMSA 究竟是什么?
这里是一些关于 SMSA 的背景知识,你可能希望在深入实际实验之前了解。到目前为止,不需要技术背景/数学知识。让我首先解释最典型的 SMSA 任务的直觉:
SMSA 示例
如上图所示,给定一个社交媒体帖子,模型(由灰色机器人表示)将输出其情感标签的预测。在这个例子中,模型回应该帖子 57.60% 可能表达正面情感,12.38% 可能是负面,30.02% 可能是中立的。一些研究将帖子分类为二元方式,即正面/负面,但其他研究也考虑了“中立”作为选项。本项目遵循后者。
1.2 情感分析方法的发展
据我了解,研究社交媒体情感的首个定量方法是使用词汇表方法。该模型有一个预定义的词汇表,将每个词元映射到情感分数。因此,给定一个句子,模型查询词汇表,汇总每个词的情感分数,并输出总体情感分数。非常直观,对吧?
基于词汇表的情感分析模型基本图
SentiWordNet 和 VADER 是这种方法的两个范例,受到了业界和学术界的青睐。
随着机器学习的发展,像 SVM、随机森林、多层感知器等分类器在情感分析中获得了立足之地。然而,这些模型不适用于文本输入,因此这些分类器与词嵌入模型结合以执行情感分析任务。词嵌入模型将词语转换为机器可以操作的数值向量。Google 的 word2vec 嵌入模型是文本数据表示学习的重大突破,其后是Pennington 等人的 GloVe和Facebook 的 fasttext。
由于自然语言的顺序特性和深度学习的极大普及,递归神经网络(RNN) 成为了“流行的小子”。RNN 按顺序解码或“读取”词嵌入序列,在循环中保留顺序结构,而词汇表模型和传统机器学习模型未能实现这一点。
现代 SMSA 的典型工作流程
上图解释了演变后的工作流程。词嵌入被传入 RNN 模型,模型输出最后一个隐藏状态(如果你不清楚最后的隐藏状态是什么,直观上它是 RNN 在“读取”完所有文本后“总结”的内容)。最后,我们使用前馈全连接神经网络将高维隐藏状态映射到情感标签上。
我们快完成了!最后一块拼图是Transformer 模型。即使你还没有学习 NLP,你可能也听说过“Attention is All You Need”[3]。在这篇论文中,他们提出了自注意力技术,并开发了 Transformer 模型。这些模型非常强大,以至于在几乎所有 NLP 的子任务中超越了之前的模型。如果你不熟悉 Transformer 模型,我强烈推荐你阅读 Giuliano Giacaglia 的这篇入门文章。
由于预训练 Transformer 模型具有无与伦比的性能,业界和学术界已经开始大规模使用这些模型。多亏了Hugging Face的transformer包,开发者现在可以轻松导入和部署这些大型预训练模型。BERT,即双向编码器表示的 Transformer,是最著名的基于 Transformer 的编码器模型,它为文本学习出色的表示。之后,基于 BERT 开发了 RoBERTa、BERTweet、DeBERTa 等模型。
2 实验
有了这些背景知识,我们现在可以深入到实验和编程部分了!如果你对 NLP 机制感到不自信,我建议你跳过技术细节或阅读一些关于 NLP 的入门博客,例如在 Towards Data Science 上。首先,我们要明确实验目标。我们想知道:
-
目前流行的基于预训练 BERT 模型的兼容性如何与 emoji 数据。
-
如果我们在 SMSA 过程中加入 emoji,性能会受到什么影响。
-
在数据处理阶段,我们应该如何处理以包含 emoji。
2.1 模型设计
我们的模型遵循上述的神经网络范式,由预训练的基于 BERT 的编码器、Bi-LSTM 层和前馈全连接网络组成。图示如下:
模型图
为了清楚,预处理的推文首先通过预训练编码器,变成一个表示向量序列。然后,表示向量通过 Bi-LSTM 层。LSTM 的两个方向的两个最后隐藏状态将由前馈层处理,以输出推文情感的最终预测。
我们改变编码器模型和 emoji 预处理方法,以观察性能的变化。为了控制变量,Bi-LSTM 和前馈层在所有实验中配置相同。在训练过程中,我们只训练 Bi-LSTM 和前馈层。预训练编码器模型的参数被冻结。
该模型的 PyTorch 实现及其他技术细节可以在我的GitHub Repo中找到。
2.2 数据准备阶段的经验教训
数据的可用性是每个数据科学研究者的痛点。起初,我想找一个基准的 Twitter 情感分析数据集,以便将结果与之前的模型进行比较,但我遇到了以下障碍:
-
大多数数据集只有“推文 ID”作为查询键来查找原始内容。要访问带有 ID 的原始推文,我需要Twitter API 访问权限。我和我的教授导师都尝试申请过,但我们都没有获得批准(我们仍然不知道原因)。
-
嗯……另一个问题是大部分推文已经消失!这意味着它们要么被作者删除,要么因为某种原因被 Twitter 服务器删除了。
-
尽管有很少的数据集直接存储推文内容,但存储在***.csv 或*.tsv 格式的数据集无法保留表情符号**。也就是说,原始推文中有表情符号,但我从网上下载的编译数据集完全丢失了所有表情符号。
因此,无论何时你想进行 Twitter 情感分析,确保首先验证数据集是否通过 Tweet ID 存储推文,这需要你额外的努力来检索原始文本。如果数据集是几年前的,推文很容易消失。此外,不要对申请 Twitter API 抱有太高的期望。我的导师是一位美国著名大学的助理教授,但也无法满足他们的要求(原因不明)。最后,为了保留表情符号,千万不要将其保存为 csv 或 tsv 格式。Pickle、xlsx 或 json 可能是你的好选择。
无论如何,找到一个保留表情符号、具有情感标签且大小合适的数据集对我来说非常困难。最终,我发现 Novak 等人的数据集符合所有标准。
2.3 BERT 家族的表情符号兼容性测试
在实现基于 BERT 的编码器之前,我们需要了解它们是否与表情符号兼容,即是否能为表情符号标记生成独特的表示。更具体地说,在将推文传递给编码器之前,它会首先由模型分词器进行分词,这种分词器是特定于编码器的(例如,RoBERTa-base 使用 RoBERTa-base 分词器,而 BERT-base 使用 BERT-base 分词器)。分词器的作用是将长字符串的文本输入拆分为词汇表中的单个词标记(如下图所示)。
spaCy 的基于规则的分词器 (source)
在我们的案例中,如果表情符号不在分词器词汇表中,它们将被全部标记为未知标记(例如“”)。因此,编码器模型将对所有这些未知标记产生相同的向量表示,在这种情况下,清理或不清理表情符号在模型性能上技术上不会有任何区别。
我选择了以下常见的基于 BERT 的编码器列表。
-
ALBERT-base-v2
-
BERT-base, BERT-large
-
BERTweet-base, BERTweet-large
-
DeBERTa-base, DeBERTa-large
-
DistilBERT
-
RoBERTa-base, RoBERTa-large
-
Twitter-RoBERTa
-
XLMRoBERTa-base, XLMRoBERTa-large
可以使用 HuggingFace 的transformers包和emoji包轻松完成测试。我们首先导入它们:
from transformers import AutoTokenizer
import emoji
AutoTokenizer 是一个非常有用的功能,你可以使用模型名称来加载相应的分词器,比如下面这行代码,其中我导入了 BERT-base 分词器。
tokenizer = AutoTokenizer.from_pretrained('bert-base-uncased')
然后,我们使用emoji包来获取完整的表情符号列表,并使用编码和解码功能来检测兼容性。
emoji_list = list(emoji.EMOJI_DATA.keys())
cnt = 0
for e in emoji_list:
tokenized = tokenizer.decode(tokenizer.encode(e)).strip("</s>").strip()
if e not in tokenized:
cnt += 1
print(f"{cnt/len(emoji_list)} of the emojis are not identified by this tokenizer.")
2.4 实验方法来预处理表情符号
我们提出了 5 种数据预处理方法,以利用表情符号信息,而不是从原始推文中删除表情符号 (rm)。
直接编码 (dir) 使用支持表情符号的预训练编码器模型直接将表情符号向量化。这样,表情符号就会被视为普通的词令。这是最直接的方法。
用描述替换表情符号 (emoji2desc) 预训练的编码器并没有专门针对表情符号创建表示。相反,它们是在大量文本上进行训练的。我们推测编码器可能对词语的表示要优于表情符号,因此将表情符号转换为其官方描述可能有助于更好地提取语义信息。例如,“我爱动物 😍”将变成“我爱动物 笑脸带心眼”。下面的 Python 实现展示了如何使用emoji包:
def emoji2description(text):
return emoji.replace_emoji(text, replace=lambda chars, data_dict: ' '.join(data_dict['en'].split('_')).strip(':'))
连接表情符号 (concat-emoji) 本质上,我们将表情符号重新定位到句子的末尾,并执行直接编码方法。由于表情符号不属于句子的语法结构,我们想知道重新定位它们是否有助于更好地区分文本和表情符号信息。例如,“天气太冷了🧊。 不想再工作了😡😭。” 变成 “天气太冷了。 不想再工作了。 🧊😡😭”
def emoji2concat_emoji(text):
emoji_list = emoji.emoji_list(text)
ret = emoji.replace_emoji(text, replace='').strip()
for json in emoji_list:
this_emoji = json['emoji']
ret += ' ' + this_emoji
return ret
连接描述 (concat-desc) 此外,我们还测试了用文本描述替换那些重新定位的表情符号。
def emoji2concat_description(text):
emoji_list = emoji.emoji_list(text)
ret = emoji.replace_emoji(text, replace='').strip()
for json in emoji_list:
this_desc = ' '.join(emoji.EMOJI_DATA[json['emoji']]['en'].split('_')).strip(':')
ret += ' ' + this_desc
return ret
元特征(meta) 除了将表情符号视为句子的一部分外,我们还可以将它们视为高级特征。我们使用表情符号情感排名 [4] 词典来获取积极性、中立性、消极性和情感分数特征。然后,我们将这些特征与表情符号的向量表示连接起来,形成推文的表情符号元特征向量。这个向量包含了推文的表情符号情感信息。纯文本将照常通过编码器和 BiLSTM 层,然后将元特征向量与 BiLSTM 层的最后隐藏状态连接,作为前馈层的输入。这个过程本质上是将表情符号从句子中隔离开来,将它们视为推文的元数据。
结果讨论
经过所有这些技术设计,我们最终进入了结果部分。首先,让我们看看这些常见的 BERT 基础编码器模型的表情符号兼容性。
BERT 基础的表情符号模型的表情符号兼容性
超过一半的这些模型不能识别所有表情符号! RoBERTa(基础版和大版)、DeBERTa(基础版和大版)、BERTweet-large 和 Twitter-RoBERTa 支持所有表情符号。然而,像 BERT(基础版和大版)、DistilBERT 和 ALBERT 这样的常见编码器几乎不支持任何表情符号。
现在,让我们比较不同表情符号兼容编码器和不同方法下的模型性能。下图中的百分比表示情感分类的准确率。每个单元格代表某种预处理方法下的编码器模型的准确率。
(请注意 emoji2vec 是一个于 2015 年开发的基准模型。它不是 BERT 基础的,而是一个预定义的表情符号嵌入模型,也可以生成表情符号的向量表示。它可以看作是 Google 的 Word2vec 模型的扩展)
情感分类准确率
为了比较将表情符号融入 SMSA 过程中的不同方法,我们还展示了不同方法下的准确率及置信区间。
每种预处理方法的平均准确率(带置信区间)
一个重要的发现是,无论如何包含表情符号,都能提升 SMSA 模型的性能。 移除表情符号平均降低了 1.202%的准确率。对于包含表情符号的方法,重叠的置信区间表示出相对模糊的区分。没有“通常最佳”的方法来利用表情符号。
每个编码器模型的平均准确率(带置信区间)
在所有编码模型中进行比较的结果如上方柱状图所示。柱状图顶部也标注了置信区间。小的置信区间表示对排名的统计信心较高。Twitter-RoBERTa 在所有模型中表现最佳,这很可能是由训练领域造成的。emoji2vec,该模型开发于 2015 年并早于变压器模型的兴起,在当前标准下对表情符号的表示相对较差。
既然没有找到“普遍最佳”的方法,我们深入探讨不同模型如何从各种预处理方法中获得不同的收益。下图展示了使用某种预处理方法与一开始移除表情符号相比的百分比改进。
百分比改进热图
首先,所有的改进指标都是正数,这强有力地证明了表情符号在 SMSA 中的有用性。在数据中包含表情符号将提高 SMSA 模型的性能。
通常,对于基于 BERT 的模型,直接编码表情符号似乎是一种足够且有时是最好的方法。 令人惊讶的是,最简单的方法效果与复杂的方法一样好,甚至更好。
表情符号表示学习模型较差的情况可能会从将表情符号转换为文本描述中受益更多。 emoji2vec 模型的改进既出现最大值也出现最小值。很可能 emoji2vec 对表情符号的向量表示较差,但将表情符号转换为文本描述有助于捕捉社交媒体帖子的情感意义。
RoBERTa-large 无论预处理方法如何显示出意外的小改进,这表明它不像其他基于 BERT 的模型那样受益于表情符号。这个结果可能是因为 RoBERTa-large 的架构可能更适合学习纯文本的表示而不是表情符号,但仍需要更严格的论证。
4 结论
从这个项目中,关键的收获是无论你使用什么模型或预处理方法,在 SMSA 过程中包含表情符号都会提高情感分类的准确性。因此,当你面对社交媒体情感分析任务时,一定要仔细考虑是否清除它们!
处理 SMSA 任务并协调表情符号的最佳模型是Twitter-RoBERTa编码器!如果你正在处理 Twitter 数据和分析推文情感,请使用它。
关于如何具体融入表情符号,方法之间并没有显著差异,因此一种直接的方法——将表情符号直接视为普通单词标记——可以完美解决问题。然而,考虑到我们研究中一半的常见 BERT 编码器不支持表情符号,我们建议使用 emoji2desc 方法。也就是说,使用之前提到的一行简单代码将表情符号转换为其官方文本描述,这可以轻松处理词汇表外的表情符号标记。
如果你使用传统的词嵌入如 word2vec,而且你也不想浪费可爱的表情符号,可以考虑使用 emoji2desc 或 concat-emoji 方法,而不是使用 emoji2vec 模型。
希望我们的项目能够指导 SMSA 研究人员和行业工作者如何在过程中包含表情符号。更重要的是,这个项目提供了一种提高 SMSA 准确性的全新视角。深入研究技术细节并不是唯一的进展方式,例如,这些简单却强大的表情符号也可以提供帮助。
脚本、学术报告及更多内容可以在我的GitHub Repo中找到。
关于文章中的图片,除非另有说明,否则均为作者提供。
致谢
我衷心感谢我的研究导师和指导教授马修·劳里埃。他为我提供了深刻的建议,并在这个夏季研究过程中给予指导。能与他一起完成这项研究,并在我生日时收到他的邮件问候,我感到非常荣幸和高兴。
本工作还部分得到了纽约大学 IT 高性能计算资源、服务和员工专业知识的支持。
此外,我真诚地感谢纽约大学及纽约大学上海校区提供的DURF研究机会。
感谢所有在这个夏天帮助我的朋友和家人。没有你们的支持,这项研究是不可能完成的。
参考文献
[1] Liu, B. Sentiment Analysis: Mining Opinions, Sentiments, and Emotions. (2015),剑桥大学出版社,剑桥。
[2] Chakriswaran, P., Vincent, D. R., Srinivasan, K., Sharma, V., Chang, C.-Y., 和 Reina, D. G. Emotion AI-Driven Sentiment Analysis: A Survey, Future Research Directions, and Open Issues. (2019),应用科学。
[3] Vaswani, A., Shazeer, N., Parmar, N., Uszkoreit, J., Jones, L., Gomez, A., Kaiser, u., & Polosukhin, I. Attention is All you Need. (2017), 在 Advances in Neural Information Processing Systems 中。Curran Associates, Inc.
[4] Kralj Novak, P., Smailović, J., Sluban, B., & Mozetič, I. Sentiment of Emojis. (2015),PLOS ONE,10(12),e0144296。
赋能公平:识别与解决生成模型中的偏见
随着人工智能融入我们的日常生活,一个有偏见的模型可能对用户产生严重后果
·发表于Towards Data Science ·阅读时间 6 分钟·2023 年 7 月 6 日
–
图片由Dainis Graveris拍摄,来源于Unsplash
2021 年,普林斯顿大学信息技术政策中心发布了一份报告,发现机器学习算法可能会从训练数据中学习到类似于人类的偏见。其中一个引人注目的例子是关于亚马逊**[1]**的 AI 招聘工具的研究。该工具在之前一年提交给亚马逊的简历上进行了训练,并对不同的候选人进行了排名。由于过去十年科技职位中性别比例严重失衡,该算法学会了将语言与女性相关联,比如女性运动队,并降低了这些简历的排名。这个例子突显了不仅需要公平和准确的模型,还需要公平的数据集,以消除训练中的偏见。在 ChatGPT 等生成模型快速发展的背景下,以及人工智能日益融入我们的日常生活中,一个有偏见的模型可能会带来严重后果,侵蚀用户信任和全球接受度。因此,从商业角度来看,解决这些偏见是必要的,数据科学家(广义上的定义)必须意识到这些偏见,以减轻其影响,并确保其与原则一致。
生成模型中的偏见示例
第一个想到的生成模型广泛使用的任务类型是翻译任务。用户输入一种语言 A 的文本,期望得到语言 B 的翻译。例如,不同语言不一定使用相同类型的性别代词,例如英文中的*“The senator”可以是女性或男性,而法语中则是“La senatrice”或“Le senateur”*。即使在句子中指定了性别(见下例),生成模型在翻译过程中强化性别刻板印象角色也并不罕见。
使用 ChatGPT 的翻译任务示例
类似于翻译任务,字幕生成任务要求模型基于某些输入生成新的文本,即将图像翻译成文本。一项最近的研究**[2]**分析了生成型变换器模型在 Common Objects in Context 数据集上进行字幕生成任务(见下图)的表现。
图源:“理解与评估种族偏见” arxiv.org/pdf/2106.08503.pdf
尽管这些描述符在所有图像中并不适用,但生成模型为字幕分配了各种种族和文化描述。这些描述符仅由更新的生成模型学习,并显示出这些模型的偏见增加。值得注意的是,变换器模型对于这个数据集也表现出性别偏见,例如,通过房屋/房间的背景将某人识别为女性,从而加剧了男女不平衡的比例。
偏差为何会发生?
生成模型的构思阶段为模型中的偏差发展留出了大量空间。偏差可能来自数据本身、标签和注释、内部表示甚至模型(请参见 huggingface.co/blog/ethics-soc-4
以获取针对 Text-to-Image 模型的详细列表)。
生成模型训练所需的数据来自众多来源,通常是在线的。为了确保训练数据的完整性,人工智能公司通常使用知名新闻网站等类似资源来构建其数据库。在这个数据集上训练的模型将由于考虑的群体人口特征限制(通常是白人、中年、上层中产阶级)而延续偏见的联想。
标签偏差 (www.ncbi.nlm.nih.gov/pmc/articles/PMC3994857/
) 可能是更明显的,因为它会导致标签数据中引入偏差,这通常是无意的。生成模型被训练以重现/近似其训练数据集,因此标签中的偏差将对模型的输出表示产生严重影响。幸运的是,使用多个版本的标签并交叉检查它们可以缓解这些偏差。
最后两种偏见类型,即内部表示和模型偏见,都来自建模过程中的特定步骤。第一种在预处理阶段引入,无论是手动还是算法性。这一阶段容易引入偏见和文化细微差别的丧失,特别是当原始数据集缺乏多样性时。模型偏见则简单地来源于基于歧视特征的目标函数以及为提高模型准确性而放大的偏见。
生成模型中的偏见检测
正如本文所强调的,生成模型中的偏见以各种形式和不同条件下的方式存在。检测偏见的方法必须像它们试图检测的偏见一样多样化。
语言模型中偏见的主要衡量方法之一是词嵌入关联测试。该分数测量的是在嵌入空间(内部表示)中,两个词集之间的相似性。高分数表示强关联。更具体地说,它计算的是目标词集与两个输入词集之间相似性的差异,例如将*[home, family]作为目标,将[he, man]/[she, woman]*作为输入。如果分数为 0,则表示模型完全平衡。该指标被用来证明 RoBERTa 是最偏见的生成模型之一 (arxiv.org/pdf/2106.13219.pdf
)。
测量生成模型(反事实评估)偏见的一个创新方法,尤其是性别偏见,是通过交换词汇的性别并观察预测准确性的变化。如果修改后的准确性与原始准确性不同,则表明模型中存在偏见,因为一个公正的生成模型应该在输入的性别独立的情况下具有相同的准确性。这一措施的主要缺陷是它只捕捉到性别偏见,因此需要其他测量方法来全面评估偏见来源。在类似的思路下,可以使用双语评估替代(经典翻译测量)来比较性别交换输入和原始输入产生的输出之间的相似性。
目前的生成模型基于使用一种叫做注意力的特征的变换器模型,以根据输出预测结果。研究已经直接从模型中调查了性别与角色之间的关系 (arxiv.org/abs/2110.15733
)。这允许比较模型中的不同部分,以检测哪个模块对偏见的贡献更大。如果通过这种措施表明生成模型在维基百科数据集上引入了性别偏见,这一措施的一个缺陷是注意力值不代表概念之间的直接效应和相似性,需要深入分析才能得出结论。
如何克服生成模型中的偏见?
研究人员开发了各种技术以提供更少偏见的生成系统。这些技术大多包括在建模中的额外步骤,如设置一个控制变量以基于先前的信息确定性别,或添加另一个模型以提供上下文信息。然而,所有这些步骤不一定解决固有偏见数据集的问题。此外,大多数生成模型基于英文训练数据,极大地限制了这些模型的文化和社会多样性。
完全克服生成模型中的偏见需要建立一个正式的框架和基准,以测试和评估跨多种语言的模型。这将允许检测到在多样化的人工智能模型中以细微方式存在的偏见。
参考文献
-
亚马逊废弃了一个显示出对女性有偏见的秘密 AI 招聘工具, Jeffrey Dastin*,*
www.reuters.com/article/us-amazon-com-jobs-automation-insight-idUSKCN1MK08G
-
理解和评估图像描述中的种族偏见, Dora Zhao, Angelina Wang, Olga Russakovsky,
arxiv.org/pdf/2106.08503.pdf
关注我在 Medium 上,获取更多关于数据科学的内容!
如果你喜欢阅读这样的故事并想支持我作为作者,可以考虑 注册成为 Medium 会员。每月 $5,你将无限制访问 Medium 上的所有故事。如果你 使用我的链接注册,我将获得少量佣金。
[## 使用我的推荐链接加入 Medium - Kevin Berlemont, PhD
作为 Medium 的会员,你的部分会费将用于支持你阅读的作者,并且你可以完全访问每一个故事……
medium.com](https://medium.com/@kevin.berlemont/membership?source=post_page-----1723ce3973aa--------------------------------)
通过对话式数据访问创造信息优势
实现 Text2SQL 以推动数据驱动型组织的指南
·
关注 发表于 Towards Data Science ·19 分钟阅读·2023 年 6 月 11 日
–
图 1:Text2SQL 流程的表示
随着我们的世界变得越来越全球化和动态化,企业对数据的依赖越来越大,以便做出明智、客观和及时的决策。在本文中,我们将探讨如何利用人工智能进行直观的对话数据访问。我们将使用图 2 中显示的心理模型来说明 Text2SQL 系统的实现(有关心理模型的介绍,请参考利用整体心理模型构建人工智能产品)。在考虑市场机会和商业价值之后,我们将解释需要建立的数据、LLM 微调和 UX 设计等额外的“机制”,以便使数据在整个组织中广泛可访问。
图 2:人工智能系统的心理模型
1. 机会
目前,释放组织数据的全部潜力通常是少数数据科学家和分析师的特权。大多数员工不精通传统的数据科学工具(如 SQL、Python、R 等)。为了访问所需的数据,他们通过额外的层次,由分析师或 BI 团队将业务问题的语言“翻译”为数据语言。在这一过程中潜在的摩擦和低效率非常高——例如,数据可能会延迟交付,甚至在问题已经变得过时时才被提供。当需求未被准确翻译成分析查询时,信息可能在传递过程中丢失。此外,生成高质量见解需要一种迭代的方法,而每增加一步都会使这种方法变得更加困难。另一方面,这些临时互动会对昂贵的数据人才造成干扰,使他们无法专注于更具战略性的工作,正如这些数据科学家的“自白”中所描述的那样:
当我在 Square 工作时,团队较小,我们有一个让人畏惧的“分析值班”轮班制度。这是严格按周轮换的,如果轮到你,你就知道那一周你几乎不会有“真正”的工作,而是花大部分时间处理来自公司各个产品和运营团队的临时问题(我们称之为 SQL 猴子工作)。在分析团队中,管理角色的竞争非常激烈,我认为这完全是因为管理人员被免于这种轮班——没有什么荣誉可以与不做值班工作的诱饵相比。[1]
2. 价值
直接与数据对话而不必经历多轮与数据团队互动的过程岂不是很酷吗?这一愿景被对话式界面所接受,这种界面允许人类使用语言与数据互动,这是我们最直观和普遍的沟通渠道。解析问题后,算法将其编码成查询语言(如 SQL)的结构化逻辑形式。因此,非技术用户可以与他们的数据聊天,快速获取具体、相关和及时的信息,而无需通过 BI 团队绕道获取。主要有以下三大好处:
-
业务用户可以以直接和及时的方式访问组织数据。
-
这可以减轻数据科学家和分析师因业务用户的临时请求而产生的负担,使他们能够专注于高级数据挑战。
-
业务可以以更流畅和战略性的方式利用其数据,最终将其转化为决策的坚实基础。
那么,在什么样的产品场景下你可能会考虑使用 Text2SQL 呢?主要有以下三种设置:
-
你提供一个可扩展的数据/BI 产品,并希望以一种非技术性的方式让更多用户访问他们的数据,从而增加使用率和用户基础。例如,ServiceNow 已经将数据查询集成到更大的对话式产品中,而Atlan最近宣布了自然语言数据探索。
-
你希望在数据/AI 领域构建某些东西,以便在公司中普及数据访问,这种情况下你可能会考虑以Text2SQL 为核心的 MVP。像AI2SQL和Text2sql.ai这样的提供商已经开始进入这一领域。
-
你正在开发一个定制 BI 系统,并希望最大化和普及其在个别公司中的使用。
正如我们在接下来的章节中将看到的,Text2SQL 需要一个非凡的前期设置。为了估算投资回报率,考虑一下要支持的决策性质以及可用的数据。Text2SQL 在数据变化迅速并被积极和频繁用于决策的动态环境中,可以带来绝对的收益,如投资、营销、制造和能源行业。在这些环境中,传统的知识管理工具过于静态,更流畅的数据和信息访问方式有助于公司生成竞争优势。在数据方面,Text2SQL 在以下数据库中提供最大的价值:
-
大且不断增长,使得 Text2SQL 可以随着越来越多的数据被利用而逐渐展现其价值。
-
高质量,以便 Text2SQL 算法不必处理数据中的过多噪音(不一致性、空值等)。通常,由应用程序自动生成的数据比由人类创建和维护的数据具有更高的质量和一致性。
-
语义成熟,而不是原始数据,这样人类可以根据其心理模型中存在的核心概念、关系和度量来查询数据。请注意,语义成熟可以通过额外的转换步骤来实现,该步骤将原始数据转化为概念结构(参见“用数据库信息丰富提示”部分)。
3. 数据
任何机器学习工作都从数据开始,因此我们将从澄清在训练和预测过程中使用的输入和目标数据的结构开始。本文中,我们将使用图 1 中的 Text2SQL 流程作为我们的运行表示,并以黄色突出显示当前考虑的组件和关系。
图 3:在此 Text2SQL 表示中,与数据相关的元素和关系用黄色标记。
1.1 数据的格式和结构
通常,原始 Text2SQL 输入-输出对包括一个自然语言问题和相应的 SQL 查询,例如:
问题:“列出每个用户的名字和关注者数量。”
SQL 查询:
select name, followers from user_profiles
在训练数据空间中,问题与 SQL 查询之间的映射是多对多的:
-
一个 SQL 查询可以映射到许多不同的自然语言问题;例如,上述查询语义可以表示为:“展示每个用户的名字和关注者数量”、“每个用户有多少关注者?”等。
-
SQL 语法高度灵活,几乎每个问题都可以用多种方式表示。最简单的例子是 WHERE 子句的不同排序。从更高级的角度来看,每个人做过 SQL 查询优化都会知道,许多途径都可以得到相同的结果,语义上等价的查询可能具有完全不同的语法。
对于 Text2SQL,手动收集训练数据特别繁琐。这不仅要求标注者掌握 SQL,还比情感分析和文本分类等更一般的语言学任务每个示例花费更多时间。为了确保足够的训练示例,可以使用数据增强,例如,LLMs 可以用来生成相同问题的同义句。[3] 提供了对 Text2SQL 数据增强技术的更全面调查。
1.2 用数据库信息丰富提示
Text2SQL 是一种位于非结构化数据和结构化数据之间的算法。为了获得最佳性能,两种类型的数据在训练和预测期间都需要存在。具体而言,算法必须了解查询的数据库,并能够以能够在数据库上执行的方式来制定查询。这些知识可以包括:
-
数据库的列和表
-
表之间的关系(外键)
-
数据库内容
融入数据库知识有两种选择:一方面,训练数据可以限制为针对特定数据库编写的示例,这样,模式可以直接从 SQL 查询及其与问题的映射中学习。这个单数据库设置允许对特定数据库和/或公司优化算法。然而,这会扼杀扩展的任何雄心,因为模型需要为每一个客户或数据库进行微调。另一种选择是,在多数据库设置中,可以将数据库模式作为输入的一部分提供,这样算法就可以“泛化”到新的、未见过的数据库模式。如果你希望在多个不同的数据库上使用 Text2SQL,你绝对需要采用这种方法,但请记住,这需要相当大的提示工程努力。对于任何合理的业务数据库,包括完整的信息在提示中将非常低效,并且由于提示长度限制,可能几乎不可能。因此,负责提示制定的函数应该足够智能,以选择对给定问题最“有用”的数据库信息子集,并对潜在的未见过的数据库进行此操作。
最后,数据库结构起着至关重要的作用。在你对数据库有足够控制的情况下,你可以通过让模型从直观的结构中学习来简化模型的任务。作为经验法则,你的数据库越能反映业务用户谈论业务的方式,你的模型从中学习的速度和效果就越好。因此,考虑对数据应用额外的转换,例如将标准化或以其他方式分散的数据组装成宽表或数据仓库,以明确和无歧义的方式命名表和列等。你可以提前编码的所有业务知识将减少模型的概率学习负担,并帮助你获得更好的结果。
2. 智能
图 4:在这个 Text2SQL 表示中,与算法相关的元素和关系标记为黄色。
Text2SQL 是一种 语义解析 —— 文本到逻辑表示的映射。因此,系统不仅要“学习”自然语言,还要学习目标表示——在我们的案例中是 SQL。具体来说,它需要掌握以下知识:
-
SQL 语法和语义
-
数据库结构
-
自然语言理解(NLU)
-
自然语言与 SQL 查询之间的映射(句法、词汇和语义)
2.1 解决输入中的语言变异性
在输入阶段,Text2SQL 的主要挑战在于语言的灵活性:正如在“数据的格式和结构”部分所描述的,相同的问题可以用许多不同的方式进行表述。此外,在实际的对话上下文中,我们还需要处理拼写和语法错误、不完整和模糊的输入、多语言输入等问题。
图 5: Text2SQL 算法必须处理多种不同形式的问题。
诸如 GPT 模型、T5 和 CodeX 这样的 LLMs 正越来越接近解决这一挑战。通过学习大量多样化的文本,它们学会了处理大量的语言模式和不规则现象。最终,它们能够对在表面形式不同但语义相似的问题进行概括。LLMs 可以直接使用(零样本)或在微调后使用。前者虽然方便,但准确性较低。后者需要更多的技能和工作,但可以显著提高准确性。
在准确性方面,正如预期的那样,表现最好的模型是包括 CodeX 模型在内的最新 GPT 系列模型。2023 年 4 月,GPT-4 在“带值执行”这一指标上相比之前的最先进技术提高了超过 5% 的准确率,达到了 85.3% 的准确率。[4] 在开源阵营中,最初尝试解决 Text2SQL 难题的焦点集中在如 BERT 等自动编码模型,这些模型在 NLU 任务中表现出色。[5, 6, 7] 然而,在生成 AI 的炒作中,最近的方法集中在如 T5 模型等自回归模型上。T5 通过多任务学习进行预训练,因此能够轻松适应新的语言任务,包括不同的语义解析变体。然而,自回归模型在语义解析任务中存在一个固有的缺陷:它们的输出空间不受约束,缺乏语义限制,这意味着它们在行为上可能变得非常有创意。虽然这对生成自由格式内容来说很惊人,但对于像 Text2SQL 这样需要受限、结构良好的目标输出的任务来说,这是一个烦恼。
2.2 查询验证与改进
为了约束 LLM 的输出,我们可以引入额外的机制来验证和改进查询。这可以作为额外的验证步骤来实现,如 PICARD 系统中所提议的。[8] PICARD 使用 SQL 解析器来验证部分 SQL 查询在完成后是否能转化为有效的 SQL 查询。在 LLM 的每个生成步骤中,那些会使查询无效的令牌会被拒绝,而概率最高的有效令牌会被保留。由于该方法是确定性的,只要解析器遵循正确的 SQL 规则,就能确保 100% 的 SQL 有效性。它还将查询验证与生成过程解耦,从而允许两个组件独立维护和升级 LLM。
另一种方法是将结构性和 SQL 知识直接融入 LLM。例如,Graphix [9] 使用图感知层将结构化 SQL 知识注入 T5 模型。由于这种方法的概率特性,它会使系统偏向于正确的查询,但并不能保证成功。
最后,LLM 可以作为一个多步骤的代理,能够自主检查和改进查询。[10] 使用链式思维提示中的多个步骤,代理可以被要求反思自己查询的正确性并改进任何缺陷。如果验证后的查询仍然无法执行,SQL 异常回溯可以作为额外的反馈传递给代理,以供改进。
除了这些在后台发生的自动化方法外,还可以在查询检查过程中涉及用户。我们将在用户体验部分更详细地描述这一点。
2.3 评估
为了评估我们的 Text2SQL 算法,我们需要生成一个测试(验证)数据集,在其上运行我们的算法,并对结果应用相关的评估指标。一个基于问题-查询对的天真的数据集划分,将数据分为训练、开发和验证数据,可能会导致次优结果。验证查询可能会在训练过程中暴露给模型,从而对其泛化能力产生过于乐观的看法。基于查询的划分,即将数据集划分为在训练和验证期间都不会出现相同查询的方式,提供了更真实的结果。
就评估指标而言,我们在 Text2SQL 中关心的不是生成完全与黄金标准相同的查询。这个**“精确字符串匹配”方法过于严格,会生成许多假负例,因为不同的 SQL 查询可以导致相同的返回数据集。相反,我们希望实现高语义准确性**,评估预测查询和“黄金标准”查询是否总是返回相同的数据集。有三种评估指标可以接近这一目标:
-
精确集匹配准确性:将生成的 SQL 查询与目标 SQL 查询拆分为其组成部分,并比较结果集的一致性。[11] 此处的缺点是仅考虑了 SQL 查询中的顺序变化,而未考虑语义上等效查询之间更明显的句法差异。
-
执行准确性:通过比较生成的 SQL 查询与目标 SQL 查询产生的数据集来验证一致性。运气好的话,即使语义不同的查询也可能在特定数据库实例上通过此测试。例如,假设一个数据库中所有用户年龄都超过 30 岁,以下两个查询虽然语义不同,却会返回相同的结果:
select * from user
select * from user where age > 30
-
测试套件准确性:测试套件准确性是执行准确性的一个更高级和更严格的版本。对于每个查询,生成一个(“测试套件”)的数据库集合,这些数据库在查询的变量、条件和值方面具有高度差异化。然后,在这些数据库上测试执行准确性。尽管需要额外的努力来设计测试套件,但此指标也显著减少了评估中的假阳性风险.[12]
3. 用户体验
图 6:在这个 Text2SQL 表示中,UX 相关的元素和关系用黄色标记。
目前,Text2SQL 的最先进技术还不允许完全无缝地集成到生产系统中——相反,必须主动管理用户的期望和行为,用户应始终意识到她正在与 AI 系统交互。
3.1 失败管理
Text2SQL 可能会以两种模式失败,需要以不同的方式捕捉:
-
SQL 错误:生成的查询无效——要么 SQL 无效,要么由于词汇或语义缺陷无法在特定数据库上执行。在这种情况下,无法向用户返回结果。
-
语义错误:生成的查询是有效的,但未能反映问题的语义,从而导致返回错误的数据集。
第二种模式特别棘手,因为“静默失败”——用户未检测到的错误——的风险很高。典型用户既没有时间也没有技术技能来验证查询和/或结果数据的正确性。当数据用于现实世界的决策时,这种失败可能带来严重后果。为避免这种情况,关键在于教育用户并建立 业务层面的保护措施,如对高影响决策的额外数据检查。另一方面,我们也可以利用用户界面来管理人机交互,帮助用户发现和改进有问题的请求。
3.2 人机交互
用户可以以不同的强度参与你的 AI 系统。每次请求的更多互动可能会带来更好的结果,但也会减缓用户体验的流畅度。除了错误查询和结果可能产生的负面影响外,还需要考虑用户提供来回反馈的积极性,以获得更准确的结果,并帮助长期改善产品。
最简单且最少参与的方式是使用置信度评分。虽然将置信度简单地计算为生成标记概率的平均值过于简单,但可以使用更先进的方法,如口头反馈。[13] 置信度可以在界面上显示,并在其危险低时用明确警报突出显示。这样,“现实世界”中适当跟进的责任——无论是拒绝、接受还是对数据进行额外检查——都落在你的用户肩上。虽然对你作为供应商来说这是一种安全的选择,但将这项工作转移给用户也可能减少你的产品价值。
另一种可能性是在低信心、模糊或其他可疑查询的情况下,邀请用户进行澄清对话。例如,你的系统可能会建议对输入进行拼写或语法纠正,并要求澄清特定单词或语法结构。它还可能允许用户主动要求对查询进行纠正:[14]
用户:显示 John 在这次冲刺中的任务。
助手:你想查看 John 创建的任务,还是他正在进行的任务?
用户:John 创建的任务
助手:好的,以下是任务 ID:
用户:谢谢,我还想查看更多关于任务的信息。请按紧急程度排序。
助手:当然,以下是任务及其简短描述、负责人和截止日期,按截止日期排序。
最后,为了便于用户理解查询,你的系统还可以提供查询的明确文本重新表述,并要求用户确认或更正。[15]
4. 非功能性要求
在本节中,我们讨论了 Text2SQL 的特定非功能性要求以及它们之间的权衡。我们将重点关注任务中最重要的六个要求:准确性、可扩展性、速度、可解释性、隐私和时间上的适应性。
4.1 准确性
对于 Text2SQL,准确性的要求很高。首先,Text2SQL 通常应用于对话设置中,其中预测是逐个进行的。因此,“大数法则”通常有助于平衡批量预测中的误差,但在这里无济于事。其次,句法和词汇的有效性是一个“硬”条件:模型必须生成一个结构良好的 SQL 查询,可能具有复杂的语法和语义,否则请求无法在数据库中执行。如果查询成功执行,它仍然可能包含语义错误并导致返回错误的数据集(参见第 3.1 节 失败管理)。
4.2 可扩展性
主要的可扩展性考虑因素是你是否希望将 Text2SQL 应用于一个或多个数据库——如果是后者,那么数据库集是否已知且固定。如果是的话,你会有更轻松的时间,因为你可以在训练过程中包含这些数据库的信息。然而,在可扩展产品的场景中——无论是独立的 Text2SQL 应用程序还是集成到现有的数据产品中——你的算法必须能够即时处理任何新的数据库模式。这个场景也没有给你机会去转换数据库结构,使其对学习更直观(链接)。所有这些都导致了与准确性之间的重大权衡,这也可能解释了为什么目前提供对新数据库进行临时查询的 Text2SQL 供应商尚未取得显著的市场渗透。
4.3 速度
由于 Text2SQL 请求通常会在对话中在线处理,速度方面对用户满意度非常重要。积极的一面是,用户通常意识到数据请求可能需要一定时间,并表现出所需的耐心。然而,这种善意可能会被聊天设置所削弱,因为用户在潜意识中期望类似人类的对话速度。像减少模型大小这样的强力优化方法可能对准确性产生不可接受的影响,因此请考虑推理优化以满足这一期望。
4.4 可解释性和透明度
在理想情况下,用户可以跟踪查询是如何从文本中生成的,查看问题中特定词汇或表达与 SQL 查询之间的映射等。这允许验证查询并在与系统交互时进行任何调整。此外,系统还可以提供查询的明确文本重述,并要求用户确认或更正。
4.5 隐私
Text2SQL 功能可以与查询执行隔离,因此返回的数据库信息可以保持不可见。然而,关键问题是提示中包含了多少数据库信息。三种选项(按隐私级别递减)是:
-
没有关于数据库的信息
-
数据库模式
-
数据库内容
隐私与准确性之间存在权衡——在提示中包含有用信息的限制越少,结果越好。
4.6 随时间的适应性
要以持久的方式使用 Text2SQL,您需要适应数据漂移,即模型应用的数据分布变化。例如,假设用于初始微调的数据反映了用户在开始使用 BI 系统时的简单查询行为。随着时间的推移,用户的信息需求变得更加复杂,要求更复杂的查询,这会让您的简单模型不堪重负。此外,公司的目标或策略的变化也可能导致信息需求向数据库的其他领域转移。最后,Text2SQL 特有的挑战是数据库漂移。随着公司数据库的扩展,新的、未见过的列和表会出现在提示中。虽然设计用于多数据库应用的 Text2SQL 算法可以很好地处理这个问题,但它可能会显著影响单一数据库模型的准确性。所有这些问题最好通过反映当前实际用户行为的微调数据集来解决。因此,记录用户问题和结果,以及从使用中收集的任何相关反馈是至关重要的。此外,例如使用嵌入或主题建模的语义聚类算法,可以用于检测用户行为中的长期变化,并将这些作为完善微调数据集的额外信息来源。
结论
让我们总结一下文章的关键点:
-
Text2SQL 允许在企业中实现直观且民主的数据访问,从而最大化现有数据的价值。
-
Text2SQL 数据包括输入中的问题和输出中的 SQL 查询。问题与 SQL 查询之间是多对多的映射关系。
-
重要的是在提示中提供关于数据库的信息。此外,可以优化数据库结构,使其更容易被算法学习和理解。
-
在输入方面,主要挑战是自然语言问题的语言变异性,这可以通过使用在各种文本风格上进行预训练的 LLMs 来解决。
-
Text2SQL 的输出应该是一个有效的 SQL 查询。可以通过“注入” SQL 知识到算法中来实现这一约束;另外,使用迭代方法,可以在多个步骤中检查和改进查询。
-
由于“静默失败”可能对决策造成错误数据的高影响,故失败管理在用户界面中是一个主要关注点。
-
以“增强”的方式,用户可以积极参与 SQL 查询的迭代验证和改进。虽然这会使应用程序的流畅性降低,但也能减少失败率,使用户以更灵活的方式探索数据,并为进一步学习创造有价值的信号。
-
主要的非功能性需求包括准确性、可扩展性、速度、可解释性、隐私和时间上的适应性。主要的权衡在于准确性与可扩展性、速度和隐私之间。
参考文献
[1] Ken Van Haren. 2023. 用 26 个递归 GPT 提示替代 SQL 分析师
[2] Nitarshan Rajkumar 等. 2022. 评估大型语言模型的文本到 SQL 能力
[3] Naihao Deng 等. 2023. 文本到 SQL 的最新进展:我们拥有的和我们期望的
[4] Mohammadreza Pourreza 等. 2023. DIN-SQL: 分解的上下文学习文本到 SQL 及自我纠正
[5] Victor Zhong 等. 2021. 用于零样本可执行语义解析的基础适应
[6] Xi Victoria Lin 等. 2020. 跨领域文本到 SQL 语义解析中的文本和表格数据桥接
[7] Tong Guo 等. 2019. 内容增强的基于 BERT 的文本到 SQL 生成
[8] Torsten Scholak 等. 2021. PICARD: 从语言模型中逐步解析以进行约束自回归解码
[9] Jinyang Li 等. 2023. Graphix-T5: 混合预训练变换器与图感知层进行文本到 SQL 解析
[10] LangChain. 2023. LLMs 和 SQL
[11] Tao Yu 等. 2018. Spider: 用于复杂和跨领域语义解析及文本到 SQL 任务的大规模人工标注数据集
[12] Ruiqi Zhong 等. 2020. 用于文本到 SQL 的语义评估与提炼测试套件
[13] Katherine Tian 等. 2023. 仅需请求校准:从经过人类反馈微调的语言模型中获取校准信心水平的策略
[14] Braden Hancock 等. 2019. 部署后的对话学习:喂饱自己,聊天机器人!
[15] Ahmed Elgohary 等. 2020. 与解析器对话:带自然语言反馈的互动文本到 SQL
[16] Janna Lipenkova. 2022. 和我聊聊!与你公司数据的 Text2SQL 对话,在纽约自然语言处理会议上的演讲。
所有图片均由作者提供。