TowardsDataScience 2023 博客中文翻译(二百零六)

原文:TowardsDataScience

协议:CC BY-NC-SA 4.0

🦜🔗LangChain:允许 LLMs 与你的代码互动

原文:towardsdatascience.com/langchain-allow-llms-to-interact-with-your-code-55d5751aa8a2

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片由David Clode拍摄,发布在Unsplash

学习如何使用工具为你的 LLM 实现自定义功能

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 Marcello Politi

·发表于Towards Data Science ·5 分钟阅读·2023 年 7 月 5 日

介绍

生成模型受到了大家的关注。许多 AI 应用现在不再需要领域内的机器学习专家,而只需知道如何实现 API 调用。

最近,例如,我参加了一次黑客马拉松,我需要实现一个自定义命名实体识别,但我直接使用了 LLM,并利用了其少样本学习能力来获得我想要的结果,这对于赢得黑客马拉松来说已经足够了!(如果你想,你可以在这里查看项目)。

因此,对于许多现实世界的应用,重点更多地转向如何与这些 LLM 进行互动和使用,而不是创建模型。LangChain 是一个允许你做到这一点的库,我最近写了几篇关于它的文章。

LangChain 工具

工具是 LLM 可以用来增强其能力的工具。工具可以在链或代理中实例化。

例如,LLM 可能会在回应之前进行维基百科搜索,以确保响应是最新的。

当然,一个代理可以使用多个工具,因此,通常会定义一个工具列表。

现在我们来看看工具的结构。工具不过是由几个字段组成的类

  • name (str):定义工具的唯一名称

  • description (str):工具在自然语言中的用途描述。LLM 能够读取此描述,并判断是否需要该工具来回答查询。

  • return_direct(bool):例如,工具可能会返回自定义函数的输出。我们是否希望将该输出直接呈现给用户(True),还是由 LLM 预处理(False)?

  • args_schema(Pydantic BaseModel):例如,工具可能会使用一个自定义函数,其输入参数必须从用户的查询中提取。我们可以提供更多关于每个参数的信息,以便 LLM 可以更容易地完成这一步骤。

如何定义工具

多种方法定义工具,我们将在这篇文章中探讨。首先,我们导入必要的库并实例化一个 OpenAI 模型。

要做到这一点,你需要一个令牌,你可以在我之前的文章中看到如何获得它。

!pip install langchain
!pip install openai

from langchain import LLMMathChain, SerpAPIWrapper
from langchain.agents import AgentType, initialize_agent
from langchain.chat_models import ChatOpenAI
from langchain.tools import BaseTool, StructuredTool, Tool, tool
import os

os.environ["OPENAI_API_KEY"] = ... # insert your API_TOKEN here

llm = ChatOpenAI(temperature=0)

实例化工具的第一种方法是使用 Tool 类。

假设我们想给工具增加搜索网络信息的能力,为此我们将使用一个叫 SerpAPI 的 Google API,你可以在这里注册并获得 API:serpapi.com/

让我们实例化一个 SerpAPIWrapper 类,并用 from_function 方法定义工具。

在 func 字段中,我们需要放置一个指向我们希望使用该工具启动的方法的指针,即 SerpAPI 的 run 方法。正如我们所见,我们给工具起了一个名字和描述。这样做比解释要简单。

search = SerpAPIWrapper()
tools = [
    Tool.from_function(
        func=search.run,
        name="Search",
        description="useful for when you need to answer questions about current events"
    ),
]

现在我们可以提供给我们的代理创建的工具列表,这里只有一个。

agent = initialize_agent(
    tools, llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True
)

agent.run(
    "Who is Bob Dylan's girlfriend?
)

自定义工具

在我看来,创建自定义工具最清晰的方法是继承 BaseTool 类。

class CustomTool(BaseTool):
    name = "custom_tool"
    description = "useful for when you need to answer questions about medium articles"

    def _run(
        self, query: str, run_manager: Optional[CallbackManagerForToolRun] = None
    ) -> str:
        """Use the tool."""
        return "I am not a Medium expert, but I know that Marcello is pretty good! :I)"

    async def _arun(
        self, query: str, run_manager: Optional[AsyncCallbackManagerForToolRun] = None
    ) -> str:
        """Use the tool asynchronously."""
        raise NotImplementedError("custom_search does not support async")

你可以看到这是一个自定义工具的实现,每当用户询问关于 Medium 的问题时,它就会被使用。然而,返回的字符串不会完全是我设置的内容,因为它会被大型语言模型进一步处理。

如果我们想直接返回某些内容,只需添加一个“return_direct”字段,如下所示。

class CustomTool(BaseTool):
    name = "custom_tool"
    description = "useful for when you need to answer questions about medium articles"
    return_direct=True

    def _run(
        self, query: str, run_manager: Optional[CallbackManagerForToolRun] = None
    ) -> str:
        """Use the tool."""
        return "I am not a Medium expert, but I know that Marcello is pretty good! :I)"

    async def _arun(
        self, query: str, run_manager: Optional[AsyncCallbackManagerForToolRun] = None
    ) -> str:
        """Use the tool asynchronously."""
        raise NotImplementedError("custom_search does not support async")

即使我们不使用 _arun 方法(它对异步调用很有用),我们仍然需要实现它,因为 BaseTool 是一个抽象类,如果我们不实现所有的抽象方法,将会出现错误。

实际案例

有一天,一个朋友对我说:“嘿 Marcello,既然你做 AI 这类的东西,为什么不帮我做一个聊天机器人,当需要时返回医生的工作时间,并预约?”

我解决这个问题的第一个想法是使用 LangChain,并让 LLM 与用户互动,然后只要模型明白用户要求查看工作时间,它就会返回一个 CSV 文件(或者如果你愿意的话是数据框)。

所以同样的东西也可以用于这个用例。假设我们有一个叫做 work_time.csv 的 CSV 文件。

import pandas as pd

class WorkingHours(BaseTool):
    name = "working_hours"
    description = "useful for when you need to answer questions about working hours of the medical staff"
    return_direct=True+

    def _run(
        self, query: str, run_manager: Optional[CallbackManagerForToolRun] = None
    ) -> str:
        """Use the tool."""
        df = pd.read_csv("working_hours.csv") #maybe you need to retieve some real time data from a DB
        return df

    async def _arun(
        self, query: str, run_manager: Optional[AsyncCallbackManagerForToolRun] = None
    ) -> str:
        """Use the tool asynchronously."""
        raise NotImplementedError("custom_search does not support async")

就这样,我朋友想要的应用程序原型只用了几行代码就准备好了!显然,和一个好的前端开发人员合作,让它看起来更好!

最终思考

LangChain 是一个最近的库,它允许我们在不同的环境中使用 LLM 的强大功能。

我发现能够使用 LLM 来理解上下文,理解用户的请求,然后运行我自己的自定义函数以实际解决任务是非常有用的。

这将使你能够编写灵活的代码。要为你的应用程序添加功能,你只需编写一个函数并告诉模型在认为需要时使用这个函数,这样就完成了!

如果你对这篇文章感兴趣,请在 Medium 上关注我!

💼 Linkedin ️| 🐦 Twitter | 💻 网站

🦜🔗LangChain:通过记忆容量提升性能

原文:towardsdatascience.com/langchain-enhancing-performance-with-memory-capacity-c7168e097f81

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片由 Milad Fakurian 提供,来源于 Unsplash

LangChain 通过记忆扩展技术提升性能

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 Marcello Politi

·发布于 Towards Data Science ·4 分钟阅读·2023 年 6 月 21 日

我之前已经发布过关于 LangChain 的文章,介绍了这个库及其所有功能。现在我想集中讨论一个关键方面,即如何在智能聊天机器人中管理记忆。

聊天机器人或代理程序也需要一种信息存储机制,这可以采取不同的形式并执行不同的功能。在聊天机器人中实现记忆系统不仅有助于使它们更加聪明,还能让它们对用户更自然、更有用

幸运的是,LangChain 提供了使开发人员能够轻松实现应用程序中记忆的 API。在本文中,我们将更详细地探讨这一方面。

在 LangChain 中使用记忆

开发聊天机器人的最佳实践之一是保存聊天机器人与用户的所有互动。这是因为LLM 的状态可能会根据过去的对话而变化,实际上,LLM 对两个用户提出的相同问题会给出不同的回答,因为他们与聊天机器人有不同的过去对话,因此它处于不同的状态。

因此,聊天机器人记忆创建的内容无非就是旧消息的列表,这些消息在提出新问题之前会反馈给它。当然,LLM 有有限的上下文,因此你需要稍微发挥创造力,选择如何将这些历史记录反馈给 LLM。最常见的方法是返回旧消息的摘要或仅返回最近的 N 条消息,这些消息可能是最具信息性的。

从 ChatMessageHistory 的基础开始

这是允许我们管理聊天机器人(AI)与用户(Human)之间消息的主要类。此类提供了两个主要方法,如下所示。

  • add_user_message: 允许我们将消息添加到聊天机器人的记忆中,并将该消息标记为“用户”

  • add_ai_message: 允许我们将消息添加到聊天机器人的记忆中,并将该消息标记为“AI”

!pip install langchain
from langchain.memory import ChatMessageHistory

history = ChatMessageHistory()

history.add_user_message("Hi!")
history.add_ai_message("Hey, how can I help you today?")

#print messages
history.messages

这个类允许你做各种事情,但在最简单的使用情况下,你可以将其视为不时将各种消息保存到列表中。然后,你也可以通过以下方式遍历历史记录,简单地查看你添加的所有消息。

for message in history.messages:
    print(message.content)

使用 ConversationBufferMemory 进行高级记忆管理

ConversationBufferMemory 类在消息存储方面的行为有点类似于 ChatMessageHistory 类,但它提供了聪明的方法来检索旧消息

例如,我们可以以消息列表或一个大字符串的形式检索旧消息,这取决于我们的需求。如果我们想让 LLM 对过去的对话进行总结,将过去的对话作为一个大字符串可能会很有用。如果我们想对过去的对话进行详细分析,我们可以通过提取列表来逐条阅读消息。

使用 ConversationBufferMemory 类,我们还可以通过 add_user_message 和 add_user_message 方法将消息添加到历史记录中。

另一方面,load_memory_variables 方法用于提取旧消息,可以是列表或字典形式,具体取决于指定的内容,让我们看一个示例。

from langchain.memory import ConversationBufferMemory

memory = ConversationBufferMemory()

memory.chat_memory.add_user_message("Hi, how are you?")
memory.chat_memory.add_ai_message("hey,I am fine! How are you?")

memory_variables = memory.load_memory_variables({})
print(memory_variables['history'])

管理多个对话的记忆

我们已经看到了如何通过保存和检索消息来管理记忆的简单示例。但在实际应用中,你可能需要管理多个对话的记忆。LangChain 允许你通过使用所谓的来管理这种情况。

链不过是实现某个目标的一系列简单或复杂步骤的工作流。

例如,一个 LLM 查找维基百科上的一条信息,因为它不知道如何回答某个问题,这就是一个链。

要处理各种对话,只需将一个 ConversationBufferMemory 实例与每个创建的链关联即可,这些链是通过 ConversationChain 类的实例化来创建的。

这样,当调用模型的 predict 方法时,链中的所有步骤都会运行,因此模型会读取对话中的过去消息。

让我们看一个简单的例子。

from langchain.llms import OpenAI
from langchain.chains import ConversationChain
from langchain.memory import ConversationBufferMemory

memory = ConversationBufferMemory()
conversation = ConversationChain(llm= OpenAI(), memory=memory)

conversation.predict(input="Hey! how are you?")

结束语

总结一下,记忆是聊天机器人的一个关键组成部分, LangChain 提供了多个框架和工具来有效管理记忆。通过使用如ChatMessageHistory 和 ConversationBufferMemory 等类,你可以捕捉并存储用户与 AI 的互动,并利用这些信息指导未来的 AI 响应。我希望这些信息能帮助你构建更智能、更强大的聊天机器人!

在下一篇文章中,我将向你展示如何使用 LangChain 工具。

如果你觉得这篇文章有用,可以在 Medium 上关注我!😉

结束

马塞洛·波利提

LinkedinTwitterWebsite

LangChain 增加了 Cypher 搜索功能

原文:towardsdatascience.com/langchain-has-added-cypher-search-cb9d821120d5?source=collection_archive---------1-----------------------#2023-05-24

使用 LangChain 库,你可以方便地生成 Cypher 查询,从而高效地从 Neo4j 中检索信息。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 Tomaz Bratanic

·

关注 发布于 Towards Data Science ·8 分钟阅读·2023 年 5 月 24 日

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图像由 Midjourney 付费订阅生成。 Midjourney 服务条款

如果你开发了或计划实施任何使用大型语言模型的解决方案,你很可能听说过 LangChain 库。 LangChain 库是最广泛使用的 Python 库,用于开发在不同能力下使用 LLM 的应用程序。它设计为模块化的,允许我们在任何可用模块中使用任何 LLM,例如链、工具、内存或代理。

一个月前,我花了一周时间研究并实现了一种解决方案,使任何人都可以直接从Neo4j数据库中检索信息,并在他们的 LLM 应用程序中使用。我了解了很多关于 LangChain 库内部的知识,并在博客文章中记录了我的经历。

我的一个同事向我展示了一个 LangChain 的功能请求,用户请求将我实现的从 Neo4j 数据库中检索信息的选项作为一个模块直接添加到 LangChain 库中,以便不需要额外的代码或外部模块就能将 Neo4j 集成到 LangChain 应用中。由于我已经熟悉 LangChain 的内部工作原理,我决定自己尝试实现 Cypher 搜索功能。我花了一个周末研究和编码解决方案,并确保其符合贡献标准以便添加到库中。幸运的是,LangChain 的维护者们非常响应并且开放新想法,Cypher 搜索功能已经在 LangChain 库的最新版本中添加了。感谢Harrison Chase维护如此出色的库,并且对新想法非常响应。

在这篇博客文章中,我将展示如何使用 LangChain 库中新添加的 Cypher 搜索功能从 Neo4j 数据库中检索信息。

代码可在GitHub上获取。

知识图谱是什么

LangChain 已经与 Vector 和 SQL 数据库集成,那么为什么我们还需要与像 Neo4j 这样的图形数据库集成呢?

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

WikiData 知识图谱。图片许可协议:CC BY-SA 4.0。

知识图谱非常适合存储异质且高度关联的数据。例如,上面的图像包含了关于人物、组织、电影、网站等的信息。虽然能够直观地建模和存储多样化的数据集非常惊人,但我认为使用图谱的主要好处在于通过其关系分析数据点的能力。图谱使我们能够发现那些在传统数据库和分析方法中可能会被忽视的联系和关联,因为这些方法常常忽视个别数据点的上下文。

当处理复杂系统时,图形数据库的强大之处真正显现出来,因为相互依赖和互动对于理解系统至关重要。

这些功能使我们能够超越单个数据点,深入探讨定义其上下文的复杂关系。这提供了数据的更深层次、更全面的视图,有助于更好的决策和知识发现。

设置 Neo4j 环境

如果你有一个现有的 Neo4j 数据库,你可以用它来尝试新添加的 Cypher 查询模块。Cypher 查询模块使用图谱模式信息生成 Cypher 语句,意味着你可以将其插件化到任何 Neo4j 数据库中。

如果你还没有 Neo4j 数据库,你可以使用 Neo4j Sandbox,它提供了一个免费的 Neo4j 数据库云实例。你需要注册并实例化任何一个现有的预填充数据库。在这篇博客中,我将使用 ICIJ Paradise Papers 数据集,但如果你愿意,可以使用其他任何数据集。该数据集由 国际调查记者联盟 提供,作为他们 离岸泄露数据库 的一部分。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Paradise Papers 数据集图谱模式。图片由作者提供。

图谱包含四种类型的节点:

  • **Entity** - 离岸法律实体。它可以是公司、信托、基金会或其他在低税区创建的法律实体。

  • **Officer** - 在离岸实体中扮演角色的个人或公司,例如受益人、董事或股东。图中的关系只是所有现有关系的一部分。

  • **Intermediary** - 寻找离岸公司和离岸服务提供商之间的中介——通常是一个律师事务所或要求离岸服务提供商创建离岸公司的中介。

  • **Address** - 在 ICIJ 获取的原始数据库中出现的注册地址。

知识图谱 Cypher 查询

Cypher 查询的名称源自 Cypher,它是一种用于与像 Neo4j 这样的图数据库互动的查询语言。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

知识图谱 Cypher 链工作流。图片由作者提供。

为了让 LangChain 从图数据库中检索信息,我实现了一个可以将自然语言转换为 Cypher 语句的模块,使用它从 Neo4j 中检索数据,并以自然语言形式将检索到的信息返回给用户。这种自然语言和数据库语言之间的双向转换过程不仅提高了数据检索的整体可访问性,还大大改善了用户体验。

LangChain 库的美在于其简洁性。我们只需几行代码即可使用自然语言从 Neo4j 中检索信息。

from langchain.chat_models import ChatOpenAI
from langchain.chains import GraphCypherQAChain
from langchain.graphs import Neo4jGraph

graph = Neo4jGraph(
    url="bolt://54.172.172.36:7687", 
    username="neo4j", 
    password="steel-foreheads-examples"
)

chain = GraphCypherQAChain.from_llm(
    ChatOpenAI(temperature=0), graph=graph, verbose=True,
)

在这里,我们使用gpt-3.5-turbo模型来生成 Cypher 语句。Cypher 语句是根据图形模式生成的,这意味着理论上,你可以将 Cypher 链插入任何 Neo4j 实例,它应该能够回答自然语言问题。不幸的是,我还没有测试其他 LLM 提供商生成 Cypher 语句的能力,因为我没有任何它们的访问权限。尽管如此,如果你愿意尝试,我很想听听你对其他 LLM 生成 Cypher 语句的评估。当然,如果你想摆脱对 LLM 云提供商的依赖,你可以随时微调一个开源 LLM 以生成 Cypher 语句。

让我们从一个简单的测试开始。

chain.run("""
Which intermediary is connected to most entites?
""")

结果

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

生成的答案。图片由作者提供。

我们可以观察生成的 Cypher 语句和从 Neo4j 中检索的信息,这些信息用来形成答案。这是最简单的设置了。让我们继续下一个例子。

chain.run("""
Who are the officers of ZZZ-MILI COMPANY LTD.?
""")

结果

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

生成的答案。图片由作者提供。

由于我们使用的是图形,让我们构造一个可以利用图形数据库优势的问题。

chain.run("""
How are entities SOUTHWEST LAND DEVELOPMENT LTD. and 
Dragon Capital Markets Limited related?
""")
# Generated Cypher statement
# MATCH (e1:Entity {name: 'SOUTHWEST LAND DEVELOPMENT LTD.'})-
# [:CONNECTED_TO|OFFICER_OF|INTERMEDIARY_OF|SAME_NAME_AS*]-(e2:Entity {name: 'Dragon Capital Markets Limited'})

生成的 Cypher 语句乍看之下没有问题。然而,存在一个问题,因为 Cypher 语句使用了可变长度路径查找语法,并且将关系视为无向的。因此,这种类型的查询高度未优化,会导致行数爆炸。

gpt-3.5-turbo的一个优点是它遵循我们在输入中留下的提示和指示。例如,我们可以要求它仅查找最短路径。

chain.run("""
How are entities SOUTHWEST LAND DEVELOPMENT LTD. and 
Dragon Capital Markets Limited connected?
Find a shortest path.
""")

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

生成的答案。图片由作者提供。

现在我们给出了一个只应检索最短路径的提示,我们不再遇到基数爆炸的问题。然而,我注意到的一件事是,如果返回的是路径对象,LLM 有时不会提供最佳结果。生成的 Cypher 语句在 Neo4j 浏览器中返回以下可视化结果。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

答案的图形可视化。图片由作者提供。

生成的自然语言响应并没有真正提到这两家公司注册在同一个地址,而是根据节点属性生成了自己的最短路径。然而,我们也可以通过指导模型使用哪些信息来解决这个问题。

chain.run("""
How are entities SOUTHWEST LAND DEVELOPMENT LTD. and Dragon Capital Markets Limited connected?
Find a shortest path.
Return only name properties of nodes and relationship types
""")

结果

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

生成的答案。图片由作者提供。

现在我们可以得到更好的响应和更合适的响应。你给 LLM 的提示越多,期望得到的结果就越好。例如,你还可以指导它可以遍历哪些关系。

chain.run("""
How are entities SOUTHWEST LAND DEVELOPMENT LTD. and Dragon Capital Markets Limited connected?
Find a shortest path and use only officer, intermediary, and connected relationships.
Return only name properties of nodes and relationship types
""")

结果

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

生成的答案。图片由作者提供。

你可以看到,生成的 Cypher 语句仅允许遍历OFFICER_OFINTERMEDIARY_OFCONNECTED_TO关系。相同的 Cypher 语句生成了以下图形化展示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

答案的图形化展示。图像由作者提供。

总结

图形数据库是检索或分析各种实体之间的连接(如人员和组织)的绝佳工具。在这篇博客文章中,我们查看了一个简单的最短路径用例,其中关系数量和关系类型的顺序事先是未知的。这些类型的查询在向量数据库中几乎是不可能的,并且在 SQL 数据库中也可能相当复杂。

我对将 Cypher Search 添加到 LangChain 库中感到非常兴奋。请试用一下,并告诉我它对你是否有效,特别是如果你在其他 LLM 模型上进行测试或有有趣的用例。同时,记得订阅,因为我还有几篇博客文章将探讨 LangChain 库中的 Cypher Search。

一如既往,代码可以在GitHub上找到。

🦜🔗 LangChain:文档上的问答代理

原文:towardsdatascience.com/langchain-question-answering-agent-over-docs-18e5585bdbd3

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Mike Alonzo 提供的照片,来自 Unsplash

了解嵌入和代理以构建问答应用

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 Marcello Politi

·发表于 Towards Data Science ·6 分钟阅读·2023 年 6 月 4 日

介绍

在自然语言处理领域,最常见的用例之一是与文档相关的问答。例如,想象一下将一个或多个 PDF 文件输入到机器中,然后询问与这些文件相关的问题。这可能很有用,比如当你需要为大学考试做准备时,并且想要向机器询问你不理解的内容。实际上,一个更高级的用例是让机器向你提问,进行一种模拟审问。

为了解决这个任务,已经做了大量研究并开发了许多工具,但今天我们可以利用大型语言模型(LLMs)的力量,例如 OpenAI 的 GPT-3 及更高版本。

LangChain 是一个非常新的库,它允许我们管理和创建基于 LLM 的应用程序。实际上,LLM 只是一个更复杂的 AI 架构中的一部分。当我们创建这样一个系统时,我们不仅需要向 OpenAI 模型提出查询并获得响应,还需要例如保存这个响应、正确结构化提示等。

在这篇文章中,我们将看到如何使用 LangChain 和 OpenAI 构建一个简单的文档问答应用。

嵌入

在这个应用中,我们将使用一个叫做 ChromaDB 的库。这是一个开源库,允许我们保存嵌入。这里可能会出现一个问题:那么什么是嵌入?

嵌入不过是词(或文本)在向量空间中的投影

我尝试用更简单的方式来解释自己。假设我们有以下几个词可用:“king”,“queen”,“man”和“woman”。

我们根据经验直观地理解这些词之间的距离。例如,“man”在概念上比“queen”更接近“king”。但机器不具备直观能力,它们需要数据和指标来工作。所以我们做的是将这些词转化为笛卡尔空间中的数据,以便准确表示这种直观的距离概念。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

嵌入示例(图片由作者提供)

在上面的图像中,我们有一个嵌入(虚拟)的示例。我们看到“Man”比其他单词更接近“King”,同样“woman”和“queen”也是如此。

另一个有趣的事情是**“man”和“king”之间的距离与“woman”和“queen”之间的距离是相同的**。所以某种程度上,这个嵌入确实捕捉到了这些词的本质。

另一个需要说明的事情是度量标准,即如何测量距离。在大多数情况下,这是使用余弦相似度来测量的,即使用两个嵌入之间角度的余弦值。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

余弦相似度(图片由作者提供)

我在示例中的嵌入只有两个维度,两条轴。但现代算法如 BERT 创建的嵌入有数百或数千条轴,所以很难理解算法为什么将文本放置在空间中的特定位置。

在这个演示中,你可以在 3 维空间中导航真实的嵌入,并查看单词彼此之间的距离。

让我们开始编程吧!

首先,我们需要安装一些库。我们肯定需要 Langchain 和 OpenAI 来实例化和管理 LLM。

然后我们将安装 ChromaDB 和 TikToken(后者是成功安装 ChromaDB 所必需的)

!pip install langchain
!pip install openai
!pip install chromadb
!pip install tiktoken

现在我们需要一个我们要处理的文本文件。事实上,我们的目的是向 LLM 提问有关这个文件的内容。用 Python 下载文件非常简单,可以使用以下命令完成。

import requests

text_url = 'https://raw.githubusercontent.com/hwchase17/chat-your-data/master/state_of_the_union.txt'
response = requests.get(text_url)

#let'extract only the text from the response
data = response.text

现在我们导入所有需要的类。

from langchain.embeddings.openai import OpenAIEmbeddings
from langchain.embeddings.cohere import CohereEmbeddings
from langchain.text_splitter import CharacterTextSplitter
from langchain.vectorstores.elastic_vector_search import ElasticVectorSearch
from langchain.vectorstores import Chroma

显然,要使用 OpenAI 的模板,你必须输入你的个人 API KEY。如果你不知道怎么做,可以查看我关于 Langchain 的上一篇文章

import os
os.environ["OPENAI_API_KEY"] = "your_open_ai_key"

在实际应用中,你可能会有很多文本文件,你希望 LLM 找出这些文本中哪个包含你问题的答案。在这个简单的例子中,我们将单个文本文件分成多个部分(块),并将每个部分视为不同的文档。模型需要找出哪个部分包含我们问题的答案。我们通过使用下面的命令将文本分成多个部分,每部分分配一个最大长度。

text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
texts = text_splitter.split_text(data)
len(texts)

我们看到从原始文本创建了 64 个部分。

我们可以逐个打印不同的部分,因为它们被包含在一个列表中。

texts[0],texts[1]

现在我们创建一个对象,用于保存创建的文本各个部分的嵌入。

embeddings = OpenAIEmbeddings()

但我们希望将嵌入保存到一个持久化的数据库中,因为每次打开应用程序时重新创建它们会浪费资源。这就是 ChromaDB 帮助我们的地方。我们可以使用文本片段创建和保存嵌入,并为每个片段添加元数据。在这里,元数据将是命名每个文本片段的字符串。

persist_directory = 'db'
docsearch = Chroma.from_texts(
    texts, 
    embeddings,
    persist_directory = persist_directory,
    metadatas=[{"source": f"{i}-pl"} for i in range(len(texts))]
    )
from langchain.chains import RetrievalQAWithSourcesChain

现在我们希望将 docsearch 转变为检索,因为这将是它的目的。

from langchain import OpenAI

#convert the vectorstore to a retriever
retriever=docsearch.as_retriever()

我们还可以查看检索器使用的距离度量,在这种情况下,默认的度量是相似度,如嵌入部分所解释的。

retriever.search_type

最后,我们可以要求检索器选择最能回答我们查询的文档。如果有必要,检索器也可以选择多于一份文档。

docs = retriever.get_relevant_documents("What did the president say about Justice Breyer")

现在我们来看一下他提取了多少文档以及这些文档的内容。

len(docs)
docs

现在我们可以创建一个代理。 代理能够执行一系列步骤来独立完成用户的任务。我们的代理需要去查看可用的文档,找出回答问题的文档,并返回该文档。

#create the chain to answer questions
chain = RetrievalQAWithSourcesChain.from_chain_type(
    llm = OpenAI(temperature=0), 
    chain_type="stuff", 
    retriever=retriever,
    return_source_documents = True
    )

如果需要,我们还可以创建一个函数来后处理代理的输出,以使其更易读。

def process_result(result):
  print(result['answer'])
  print("\n\n Sources : ",result['sources'] )
  print(result['sources'])

现在一切终于准备好了,我们可以使用我们的代理来回答我们的查询!

question = "What did the president say about Justice Breyer"
result = chain({"question": question})
process_result(result)

结束语

在这篇文章中,我们介绍了 LangChain、ChromaDB 以及一些关于嵌入的解释。我们通过一个简单的例子展示了如何将多个文档或文档的部分的嵌入保存到持久化数据库中,并检索所需的部分来回答用户查询。

如果你觉得这篇文章有用,可以在 Medium 上关注我! 😉

结束

马切洛·波利提

LinkedinTwitterWebsite

语言模型及其相关:Gorilla、HuggingGPT、TaskMatrix 及更多

原文:towardsdatascience.com/language-models-and-friends-gorilla-hugginggpt-taskmatrix-and-more-b88c1200afd3

当我们给 LLMs 访问成千上万的深度学习模型时,会发生什么?

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 Cameron R. Wolfe, Ph.D.

·发表于 Towards Data Science ·阅读时间 18 分钟·2023 年 9 月 4 日

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

(图片由 Mike Arney 提供,来自 Unsplash

最近,我们见证了基础模型在深度学习研究中日益流行。预训练的大型语言模型(LLMs)引领了一个新范式,在这种范式中,一个模型可以用来——以令人惊讶的成功——解决许多不同的问题。然而,尽管通用 LLMs 很受欢迎,但任务特定的微调模型往往比利用基础模型的方法表现更佳。简单来说,专业化模型仍然很难被超越!话虽如此,我们可能会开始想知道,基础模型和专业深度学习模型的能力是否可以结合起来。在这次概述中,我们将研究近期的研究,这些研究通过学习调用其关联的 API,将 LLMs 与其他专业化深度学习模型结合起来。结果框架将语言模型作为一个集中控制器,用于制定解决复杂 AI 相关任务的计划,并将解决方案过程中的专业部分委派给更合适的模型。

“通过仅提供模型描述,HuggingGPT 能够持续且方便地整合来自 AI 社区的各种专家模型,而无需改变任何结构或提示设置。这种开放和持续的方式使我们离实现人工通用智能更进一步。” — 引自 [2]

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

(引自 [2, 3])

背景

在探索语言模型如何与其他深度学习模型集成之前,我们需要涵盖一些背景概念,如 LLM 工具、信息检索和自我指导 [11]。有关语言模型的更多通用背景信息,请查看以下资源。

  • 语言建模基础(GPT 和 GPT-2) [link]

  • 语言模型规模的重要性(GPT-3) [link]

  • 现代 [link] 和专业 [link] LLMs

  • 基础的 [link] 和高级的 [link] 提示工程

使用工具与 LLMs

“通过赋予 LLMs 使用工具的能力,我们可以访问更广泛且不断变化的知识库,并完成复杂的计算任务。” — 摘自[3]

尽管语言模型拥有许多令人印象深刻的能力,但它们并不完美,不能独立完成所有任务。在许多情况下,将现有模型与工具(例如搜索引擎、计算器、日历等)结合使用,可以大幅扩展它们的能力范围。在之前的综述中,我们探讨了 Toolformer [1]——一种用于教会 LLMs 使用一小组简单文本 API 的微调技术——以及如何在不费太大力气的情况下使用工具来提高 LLMs 的表现;更多细节请见这里

尽管像 Toolformer 这样的模型很有效,但它们只考虑了一小组非常简单的 API。这些 API 仅仅触及了可以提供给 LLMs 的工具总数的表面。例如,想象一下,如果我们能够将 LLM 与任何通过互联网提供的 API 集成——我们可能会解锁一个全新的应用和可能性的领域

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

ChatGPT Plus 插件商店中的热门应用

(几乎)任何事都有可能! 这种将语言模型与各种在线 API 广泛接入的趋势正在通过 ChatGPT 插件商店进行探索;见上文。通过利用这些 API,我们可以做的不仅仅是为 LLMs 提供简单的工具,如计算器!我们可以轻松想到几个通过这种方法变得可能的高影响力应用。例如,我们可以使用集成工具的语言模型进行:

  • 制定假期行程并预订所有必要的票和预订

  • 策划并购买本周的食品杂货清单以便路边取货

  • 查找并预订即将到来的周末餐厅的桌子

  • 在任何电子商务商店发现并购买相关产品

可能性范围几乎是无限的!通过将语言作为一种标准化的交流媒介,我们可以与基础模型如 ChatGPT 合作,完成令人惊讶的复杂任务。我们所要做的就是提示模型生成与我们请求相关的 API 调用。

深度学习 API。 在本概述中,我们将考虑将 LLMs 与一种特定类型的 API 集成——这些 API 提供对平台如HuggingFace上的开源深度学习模型的访问。AI/ML 社区对开源软件给予了高度重视,这意味着许多最强大的深度学习模型在线上免费提供。通常,这些模型附带有良好撰写的描述,称为模型卡,可以用来为 LLM 提供任何模型所需的所有信息。然后,这些模型可以通过基本的提示技术轻松与 LLM 集成。

自我指令框架

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

(来自[11])

自我指令框架,在[11]中提出,开创了利用大型语言模型(LLMs)通过生成合成的指令调优数据来进行自我训练的想法。这些数据可以用于微调。从与特定任务或指令相关的单一输入-输出对开始,自我指令会提示一个现成的 LLM 生成新的任务,以及与每个任务相关的有效指令和响应。在进行过滤以去除低质量数据后,我们可以在生成的指令调优数据集上对任何语言模型进行微调。有趣的是,我们发现,基于这些数据进行微调的模型往往能达到与那些在人工策划数据集上训练的模型相匹配的性能。尽管自我指令效果良好,Alpaca [12]也提出了一些对整体框架的改进;详情见这里

信息检索

正如我们在之前的概述中看到的,基础语言模型的质量往往随着规模的增加而提升——大型预训练数据集和模型会带来最佳结果。然而,我们只能在语言模型中固定的权重集合中存储有限的信息。即使是大规模模型也有有限数量的参数。此外,现代 LLM 的有限上下文窗口限制了我们只能将少量信息注入到模型的提示中。那么,如果我们想让 LLM 访问大量的信息库,该怎么办?我们需要采用某种形式的信息检索。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

(来自[13])

向量数据库。 一种流行的信息检索形式可以通过将 LLM 与存储大量文本信息的向量数据库集成来完成。在高级别上,这种与向量数据库(例如,PineconeMilvusWeaviateRedis等)的集成包括:

  1. 将文本分块成小部分。

  2. 为每个文本片段生成嵌入

  3. 将这些嵌入存储在向量数据库中。

  4. 执行向量相似性搜索(基于这些嵌入)来查找相关的文本片段以包含在提示中。

最终结果是,我们可以快速找到相关的文本信息,作为提示中的额外上下文,使 LLM 能够利用超出其上下文窗口的额外信息。尽管我们仍然无法将所有信息提供给模型,但我们可以使用向量相似性搜索快速识别最相关的部分。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

(来自[14])

这就是唯一的方法吗? 许多其他方法已被提出用于信息检索——这方面有一个专门的(非常活跃的)研究领域。我们甚至可以使用 LLMs 生成相关信息(而不是检索)通过生成知识提示;见上文。文章这里很好地总结了现有的信息检索技术。总体而言,存在许多不同的技术,我们有很多选择来决定如何用外部信息源来增强 LLM。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

(来自[3])

我们为什么要关心这个问题? 信息检索非常重要,但我们可能会想知道这与将 LLMs 与其他深度学习模型整合的主题有何相关。好吧,如果我们想要提供对任何在线可用模型的访问呢? 在像 HuggingFace 这样的 ML 社区中,有成千上万的模型!因此,我们不能为所有这些模型提供描述给 LLM。相反,我们需要使用某种形式的信息检索来确定我们应该包含在 LLM 提示中的最相关的模型子集;见上文。

将 LLMs 与其他模型集成

现在我们已经掌握了一些相关背景信息,我们将查看最近的出版物,这些出版物增强了 LLMs 与其他深度学习模型的结合。虽然每种方法有所不同 [2, 3],但所有这些技术的目标都是教会 LLM 如何调用与其他专业模型相关的 API。然后,LLM 可以作为一个控制器(或大脑),通过规划和将子任务委派给不同的 API 来协调问题的解决。

HuggingGPT: 用 ChatGPT 及其在 Hugging Face 的朋友解决 AI 任务 [2]

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

(来自 [2])

最近 LLMs 变得流行,但近年来深度学习研究已经产生了多种非常有用的模型,用于解决特定任务,如图像识别、视频动作检测、文本分类等等。这些模型不同于语言模型,它们是狭义的专家,这意味着它们可以在固定的输入输出格式下准确地解决特定任务。但它们对于超出其训练解决的特定任务范围的内容没有用处。如果我们想将这些模型重新利用作为解决更多开放式 AI 相关任务的组件呢?

“LLMs [可以] 作为一个控制器来管理现有的 AI 模型以解决复杂的 AI 任务,而语言可以是一个通用接口来实现这一点。” — 来自 [2]

在 [2] 中,作者探索了将 LLMs 用作连接深度学习模型的通用接口。HuggingGPT [2] 的灵感来自于允许 LLM 与具有不同专业能力的外部模型进行协调的想法。简单来说,LLM 作为问题解决系统的“大脑”,计划如何解决问题,并协调不同深度学习模型之间的努力,这些模型解决了该问题所需的子任务。为了教会 LLM 如何做到这一点,我们需要每个模型的高质量描述。幸运的是,我们不需要进行任何提示工程来创建这些描述——它们通过像 HuggingFace 这样的 ML 社区 广泛提供

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

(来自 [2])

这怎么运作? HuggingGPT [2] 将问题分解为四个部分:

  • 任务规划:使用 LLM 将用户请求分解为可解决的任务。

  • 模型选择:从 HuggingFace 中选择用于解决任务的模型。

  • 任务执行:运行每个选定的模型并将结果返回给 LLM。

  • 响应生成:使用 LLM 为用户生成最终响应。

正如我们可能预期的那样,利用在线模型的能力赋予了 HuggingGPT 解决各种复杂问题的能力!

“HuggingGPT 可以根据用户请求自动生成计划,并使用外部模型,因此可以整合多模态感知能力并处理多个复杂的 AI 任务。” — 来自 [2]

相当令人印象深刻的是,HuggingGPT 完全不需要微调就能学习如何协调和使用这些模型!相反,它利用了 少量学习指令提示 来执行解决问题所需的每一个任务;见下文。为了使这些提示发挥良好效果,我们需要一个 可调节 的 LLM(例如 ChatGPT 或 GPT-4),它能够严格遵守指令并执行严格的输出格式(例如,将问题分解为 json 格式的任务)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

(来源 [2])

值得注意的是,我们应当观察到,供 HuggingGPT 使用的可用模型集直接注入到任务规划提示中;见上例。显然,网上有太多模型可用,无法将它们全部包含在提示中。为了决定应将哪些模型作为选项包含在提示中,HuggingGPT 根据任务类型(即,它们是否解决与当前问题相关的任务)选择一组模型,根据下载量(即,在 HuggingFace 上下载或使用该模型的用户数量)对它们进行排名,然后将排名前 K 的模型提供给 LLM 作为选项。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

(来源 [2])

资源依赖。 在 HuggingGPT 将用户请求分解为几个解决步骤后,我们需要在指定的计划中执行每个模型。然而,当我们执行 HuggingGPT 指定的每个模型时,一些模型可能依赖于其他模型的输出,这在 [2] 中被称为“资源依赖”。为了处理这些情况,具有依赖关系的模型会等待它们所依赖的模型的输出后再执行。没有依赖关系的模型可以并行执行,从而加快 HuggingGPT 的任务执行步骤。有趣的是,LLM 生成的任务规划结构不仅改变了每个模型的执行顺序,还改变了我们评估 HuggingGPT 输出的方式。例如,[2] 中的作者使用 GPT-4 来评估更复杂任务计划的质量;见上文。

它表现得好吗? 在 [2] 中对 HuggingGPT 的评估专注于评估几个不同 LLM 的任务规划能力,因为任务规划的质量在很大程度上决定了 HuggingGPT 整体问题解决框架的成功。如下面的图所示,像 GPT-3.5 这样的 LLM(以及在一定程度上较弱的模型)似乎能够有效地将用户请求分解为有效的任务计划。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

(来源 [2])

需要大量工作来改进对这些技术的评估 — [2] 中提供的分析远非全面。此外,尽管 HuggingGPT 表现良好,但它只考虑了一小部分直接注入 LLM 提示中的、文档完善的模型 API。与微调相比,这一框架需要大量的提示工程来有效运作。尽管我们避免了对微调数据集的需求,但这一框架在很大程度上依赖于基础模型的能力。因此,我们可能会想:我们如何将这种方法推广到更多模型中以更可靠地工作?

猩猩:与大量 API 连接的大型语言模型 [3]

“支持可能数百万个不断变化的 API 的网络规模集合需要重新思考我们整合工具的方法。” — 引自 [3]

将 LLM 与一组较小且固定的其他模型进行整合是很酷的,但如果我们能够教会 LLM 使用任何在线可用的模型 API 呢? 为此,我们可以使用检索技术 i) 识别相关模型 API 和 ii) 将它们的文档提供给 LLM。通过这种方法,LLM 将能够访问比少量精心挑选的工具更多的资源!而是,模型可以访问云中不断变化的大量 API。然而,尽管如此,即便是强大的 LLM(例如,GPT-4Claude)也难以以这种方式利用 API,因为它们倾向于传递不正确的参数或虚构调用不存在的 API;见下文。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

(引自 [3])

在 [3] 中,作者采用了基于自我指导 [11] 框架的微调方法,以使 LLM 更有能力利用大量外部深度学习 API。超越像 HuggingGPT [2] 这样的提案, [3] 中的作者考虑了超过 1,600 个不同的模型 API。这些模型 API 的集合比之前工作的模型 API 要大得多,功能重叠(即,许多模型执行类似的任务),甚至包括一些文档不完美的模型。为了学习如何利用这些 API, [3] 的工作在一个有效 API 调用的大型数据集上对 LLaMA-7B [5] 模型进行了微调。最终的模型,能够有效利用这些 API,被称为猩猩。

创建数据集。 为了微调 Gorilla,我们利用 HuggingFace HubPyTorch HubTensorFlow Hub 创建了一个大规模的 API 调用语料库。在所有三个中心中,选择了总共 1,645 个模型 API,涵盖了从计算机视觉到音频、强化学习等多个领域。在将每个 API 的相关信息存储在一个 json 对象中(即包含领域、框架、功能描述和 API 签名等信息)后,我们可以通过使用 GPT-4 生成十个用户问题提示和相关回答来遵循自我指导的方法。经过过滤错误的 API 调用后,结果就是一个大数据集,涵盖了利用不同模型 API 解决各种问题的实际用例。这个数据集非常适合微调 LLM;见下文。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

(来源 [3])

检索感知的微调。 不同于执行“普通”的监督微调,Gorilla 利用了一种“检索感知”的微调变体。这听起来可能很高端,但实际实现非常简单!对于微调数据集中的每次模型 API 调用,我们在数据中添加了最新的 API 文档。然后,我们在测试时采取类似的方法,将 API 文档附加到我们的提示中,这教会 LLM 动态确定每个 API 的正确使用方法;见下文。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

(来源 [3])

检索感知微调是一种技术,教会 LLM 在确定如何解决问题时更好地利用 API 文档。这种动态方法允许 LLM:

  • 在测试时适应 API 文档中的实时变化

  • 发展改进的 上下文学习 能力以进行 API 调用

  • 通过更好地关注 API 文档中的信息来减少幻觉

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

(来源 [3])

检索感知的微调使 Gorilla 成为利用各种不同深度学习模型的极其强大的接口——生成的 LLM 可以使用大量不同的 API 来解决问题。此外,模型实际上可以适应任何 API 的文档变化! 请参见上图以获取适应 API 文档变化的示例。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

(来源 [3])

使用 Gorilla。 尽管我们知道在构建微调数据集时应该在提示中包含哪些 API,但当我们在推理过程中接收到用户的任意提示时,并不知道应该使用哪个合适的 API。为了确定正确的 API,我们可以采用信息检索技术,i) 嵌入用户的提示(或其他相关信息),以及 ii) 执行向量相似性搜索以找到最相关的 API 文档。通过这种方式,我们可以轻松高效地确定用于解决问题的最佳 API。或者,我们可以通过将用户的提示直接传递给模型,而无需任何信息检索或额外信息,以零-shot 方式使用 Gorilla。无论哪种方式,Gorilla 的目标都是生成准确的调用,以使用最合适的 API 来解决用户的提示;详见上文。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

(来自 [3])

如上实验结果所示,Gorilla 是一个极其有能力的深度学习 API 接口。与更大、更强大的模型(例如 GPT-3.5、Claude 和 GPT-4)相比,我们发现 Gorilla 在生成准确的 API 调用方面更具能力,这意味着模型产生虚假的 API 调用的情况较少,并且更倾向于传递正确的输入参数!

其他值得注意的技术……

HuggingGPT [2] 和 Gorilla [3] 在过去几个月中获得了大量公众认可和讨论,但也有许多其他技术被提出,考虑使用 LLMs 来协调多个不同深度学习模型的工作。下面概述了一些其他有趣的技术。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

(来自 [7])

TaskMatrix [7] 是一篇立场论文——这意味着它对一个显著问题提出了立场或观点——考虑了将基础模型(例如,像 ChatGPT 这样的 LLMs)与数百万种不同的 API 进行集成。值得注意的是,这项工作认为基础模型缺乏解决专业任务所需的领域知识,但已有许多现有的、任务特定的模型可以以令人印象深刻的准确性解决指定的任务。由于兼容性问题,将这些专业/专家模型与 LLM 集成可能会很困难,但[7]中的作者广泛讨论并考虑了这一想法。在许多方面,HuggingGPT 和 Gorilla 是[7]中讨论的想法的实际实现。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

(来自 [8])

API Bank [8] 提供了一个更好的基准来评估工具增强的 LLM。特别是,该基准考虑了 50 多个通常与 LLM 集成的 API 和 264 个标注对话——包括总计 568 次 API 调用——以配合这些工具。该基准旨在评估 LLM 创建任务计划(即,逐步指南,说明要执行哪些 API 调用)、确定正确的 API 以及执行 API 调用以回答提供的问题的能力。毫无意外,初步实验显示,GPT-4 在利用外部工具回答用户提供的问题方面具有最强的能力。尽管这项工作没有特别考虑深度学习模型 API,但所使用的任务框架与本综述中看到的方法相似。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

(来自 [9])

ToolkenGPT [9] 尝试通过为每个工具分配一个特定的令牌——以及相关的token embedding——来减轻工具跟随基础模型的微调要求,使 LLM 能够以类似生成普通词令牌的方式生成工具请求。这种方法被发现对于利用各种外部工具非常灵活。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

(来自 [10])

使用开源 LLM 的工具操作 [10]。 在大多数情况下,我们发现闭源 LLM(例如,GPT-4)更具可操控性,因此能够更好地操作外部工具。然而,在 [10] 中,作者分析了开源 LLM 是否可以通过微调来匹配强大闭源 LLM 在这一特定技能上的表现。各种开源 LLM 通过人类反馈和监督进行优化,以提升其工具跟随能力。有趣的是,我们看到在充分微调的情况下,若干开源模型可以与 GPT-4 达到竞争性表现。在本综述中,我们看到像 Gorilla 这样的模型表明,给定正确的微调程序,开源 LLM(例如,LLaMA)可以非常强大。

结束语

“目前迫切需要一种机制,可以利用基础模型提出任务解决方案的框架,然后自动将框架中的一些子任务与具有特殊功能的现成模型和系统进行匹配,以完成这些任务。” — 来自 [7]

在这个概述中,我们已经看到,LLM 能够通过其 API 与其他深度学习模型集成。以 HuggingGPT [2] 为例,这可以通过一种上下文学习方法实现,其中我们向 LLM 提供现有模型及其功能的描述。然而,值得注意的是,HuggingGPT 最适合与强大的闭源模型如 ChatGPT 一起使用。如果我们想要教会开源模型(例如,LLaMA)在解决复杂问题时调用深度学习模型 API,我们需要采用 Gorilla [3] 提出的微调方法。无论如何,这些技术都非常强大,因为它们在狭窄专家模型和基础模型的优势之间取得了平衡。我们可以通过依赖 LLM 进行高级推理和形成问题解决计划,同时将某些子任务委派给更可靠和准确的专业模型,从而发挥两者的优势。

与我联系!

非常感谢您阅读这篇文章。我是 Cameron R. WolfeRebuy 的 AI 总监。我研究深度学习的经验和理论基础。如果您喜欢这个概述,请订阅我的 Deep (Learning) Focus newsletter,在这里我通过从基础上概述相关主题来帮助读者理解 AI 研究。您还可以在 XLinkedIn 上关注我,或者查看我在 Medium 上的 其他文章

参考文献

[1] Schick, Timo, 等. “Toolformer: Language models can teach themselves to use tools.” arXiv preprint arXiv:2302.04761 (2023).

[2] Shen, Yongliang, 等. “Hugginggpt: Solving ai tasks with chatgpt and its friends in huggingface.” arXiv preprint arXiv:2303.17580 (2023).

[3] Patil, Shishir G., 等. “Gorilla: Large Language Model Connected with Massive APIs.” arXiv preprint arXiv:2305.15334 (2023).

[4] Wei, Jason, 等. “Chain of thought prompting elicits reasoning in large language models.” arXiv preprint arXiv:2201.11903 (2022).

[5] Touvron, Hugo, 等. “Llama: Open and efficient foundation language models.” arXiv preprint arXiv:2302.13971 (2023).

[6] Wang, Yizhong, 等. “Self-Instruct: Aligning Language Model with Self Generated Instructions.” arXiv preprint arXiv:2212.10560 (2022).

[7] Liang, Yaobo, 等. “Taskmatrix. ai: Completing tasks by connecting foundation models with millions of apis.” arXiv preprint arXiv:2303.16434 (2023).

[8] Li, Minghao, 等. “Api-bank: A benchmark for tool-augmented llms.” arXiv preprint arXiv:2304.08244 (2023).

[9] Hao, Shibo, 等. “ToolkenGPT: Augmenting Frozen Language Models with Massive Tools via Tool Embeddings.” arXiv preprint arXiv:2305.11554 (2023).

[10] Xu, Qiantong, 等. “On the Tool Manipulation Capability of Open-source Large Language Models.” arXiv preprint arXiv:2305.16504 (2023).

[11] 王一中等人. “Self-Instruct: 将语言模型与自生成指令对齐.” arXiv 预印本 arXiv:2212.10560 (2022)。

[12] 塔奥里等人. “斯坦福 Alpaca: 一种跟随指令的 LLaMA 模型.” (2023)。

[13] 特里维迪等人. “将检索与思维链推理交替用于知识密集型多步骤问题.” arXiv 预印本 arXiv:2212.10509 (2022)。

[14] 刘嘉诚等人. “生成知识提示用于常识推理.” arXiv 预印本 arXiv:2110.08387 (2021)。

用于句子补全的语言模型

原文:towardsdatascience.com/language-models-for-sentence-completion-6a5298a85e43?source=collection_archive---------5-----------------------#2023-09-15

语言模型的实际应用,选择最可能的单词来扩展一个英文句子

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 Dhruv Matani

·

关注 发表在Towards Data Science ·13 分钟阅读·2023 年 9 月 15 日

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片由Brett Jordan拍摄,来源于Unsplash

Naresh Singh共同撰写。

目录

介绍

问题陈述

头脑风暴解决方案

  • 算法与数据结构

  • NLP(自然语言处理)

  • 深度学习(神经网络)

LSTM 模型

  • 分词

  • PyTorch 模型

  • 使用模型修剪无效建议

  • 计算下一个单词的概率

变换器模型

结论

介绍

语言模型如 GPT 最近变得非常流行,并被用于各种文本生成任务,例如在 ChatGPT 或其他对话式 AI 系统中。这些语言模型非常庞大,通常超过数十亿个参数,需要大量计算资源和金钱来运行。

在英语语言模型的背景下,这些大型模型是过度参数化的,因为它们使用模型的参数来记忆和学习我们世界的各个方面,而不仅仅是建模英语语言。如果我们有一个仅需理解语言及其结构的应用,我们很可能可以使用一个更小的模型。

运行训练模型推理的完整代码可以在这个笔记本中找到

问题陈述

假设我们正在构建一个滑动键盘系统,尝试预测你在手机上输入的下一个词。根据滑动模式的轨迹,用户的意图词有很多可能性。然而,这些可能的词中许多不是英语中的实际单词,可以被排除。即使在这个初步修剪和排除步骤之后,仍然有许多候选词,我们需要选择一个作为对用户的建议。

为进一步修剪候选列表,我们可以使用基于深度学习的语言模型,查看提供的上下文,并告诉我们哪个候选词最有可能完成这个句子。

例如,如果用户输入了句子*“我已经安排好了”*,然后划出如下面所示的模式

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

然后,用户可能意图的英语单词包括:

  1. 混乱

  2. 会议

然而,如果我们考虑一下,用户可能更可能意图“会议”而不是“混乱”,因为句子前面的单词是“安排”。

根据我们目前所知道的一切,我们有哪些选项可以通过编程方式进行修剪?让我们在下面的章节中头脑风暴一些解决方案。

头脑风暴解决方案

算法与数据结构

基于第一原则,似乎合理从数据语料库开始,找到一对一对出现的单词,并训练一个马尔可夫模型来预测这一对在句子中出现的概率。你会发现这种方法有两个显著的问题。

  1. 空间利用:英语中有25 万到 100 万词,这还不包括不断增长的众多专有名词。因此,任何传统的软件解决方案在建模词对同时出现的概率时,必须维护一个 250k*250k = 625 亿词对的查找表,这显得有些过于庞大。许多词对可能出现的频率并不高,可以被修剪。即使在修剪之后,也有很多词对需要关注。

  2. 完整性:仅仅编码一对词的概率并不能解决眼前的问题。例如,当你只查看最近的一对词时,之前的句子上下文完全丧失。在句子*“你今天怎么样”*中,如果你想查看“coming”之后的词,你会有很多以“coming”开头的词对。这会忽略该词之前的整个句子上下文。可以想象使用词三元组等,但这会加剧上述提到的空间利用问题。

让我们将注意力转移到一种利用英语语言特性的解决方案上,看看这是否能帮到我们。

NLP(自然语言处理)

历史上,NLP(自然语言处理)领域涉及理解句子的词性(POS),并利用这些信息来进行修剪和预测决策。可以想象使用与每个词相关的 POS 标签来确定句子中的下一个词是否有效。

然而,计算句子的词性是一个复杂的过程,需要对语言有专门的理解,这在NLTK 词性标注的页面中有所体现。

接下来,我们来看看一种基于深度学习的方法,这种方法需要大量标记数据,但构建时不需要太多语言专业知识。

深度学习(神经网络)

随着深度学习的出现,NLP(自然语言处理)领域发生了翻天覆地的变化。随着 LSTM 和基于 Transformer 的语言模型的发明,解决方案往往涉及将一些高质量的数据投入到模型中,并训练其预测下一个词。

本质上,这就是 GPT 模型正在做的。GPT(生成预训练变换器)模型被训练来预测给定句子前缀后的下一个词(标记)。

给定句子前缀*“这真是太棒了”*,模型很可能会提供以下作为该句子后续词的高概率预测。

  1. 经验

  2. 世界

  3. 生活

同样,后续词完成句子前缀的概率可能较低。

  1. 红色

  2. 鼠标

Transformer 模型架构是像 ChatGPT 这样的系统的核心。然而,对于学习英语语言语义的更受限的用例,我们可以使用一种更便宜的模型架构,如LSTM(长短期记忆)模型。

LSTM 模型

让我们构建一个简单的 LSTM 模型,并训练它根据标记的前缀预测下一个标记。现在,你可能会问什么是标记。

标记化

对于语言模型,标记通常可以意味着

  1. 单个字符(或单个字节)

  2. 目标语言中的整个单词

  3. 介于 1 和 2 之间。这通常被称为子词

将单个字符(或字节)映射到一个标记上是非常有限制的,因为我们把这个标记过度负荷到包含大量关于它出现的上下文的信息。这是因为字符“c”例如,出现在许多不同的单词中,要预测在看到字符“c”后下一个字符,需要仔细查看前面的上下文。

将单个单词映射到一个标记上也是有问题的,因为英语本身有大约 25 万到 100 万个单词。此外,当语言中添加了一个新单词时会发生什么呢?我们是否需要回去重新训练整个模型以考虑这个新单词?

子词标记化被认为是 2023 年的行业标准。它将经常一起出现的字节子串分配给唯一的标记。通常,语言模型有几千(比如 4,000)到几十万(比如 60,000)个唯一标记。确定什么构成标记的算法由BPE(字节对编码)算法m 决定。

选择我们词汇表中的唯一标记数量(称为词汇大小)时,我们需要注意以下几点:

  1. 如果我们选择的标记太少,我们就回到了每个字符一个标记的情况,模型很难学到有用的东西。

  2. 如果我们选择的标记太多,我们会遇到模型的嵌入表超越模型其他部分的权重,从而使模型在受限环境中部署变得困难。嵌入表的大小将取决于我们为每个标记使用的维度。使用 256、512、786 等大小并不罕见。如果我们使用 512 的标记嵌入维度,并且有 100k 个标记,我们会得到一个在内存中使用 200MiB 的嵌入表。

因此,在选择词汇大小时我们需要找到一个平衡点。在这个例子中,我们选择了 6600 个标记,并用 6600 的词汇大小训练了我们的标记器。接下来,让我们看看模型定义本身。

PyTorch 模型

模型本身是相当简单的。我们有以下层:

  1. 词汇嵌入(词汇表大小=6600,嵌入维度=512),总大小约为 15MiB(假设嵌入表的数据类型为 4 字节 float32)

  2. LSTM(层数=1,隐藏维度=786)总大小约为 16MiB

  3. 多层感知器(786 到 3144 到 6600 维)总大小约为 93MiB

完整的模型大约有 31M 可训练参数,总大小约为 120MiB。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这是模型的 PyTorch 代码。

class WordPredictionLSTMModel(nn.Module):
    def __init__(self, num_embed, embed_dim, pad_idx, lstm_hidden_dim, lstm_num_layers, output_dim, dropout):
        super().__init__()
        self.vocab_size = num_embed
        self.embed = nn.Embedding(num_embed, embed_dim, pad_idx)
        self.lstm = nn.LSTM(embed_dim, lstm_hidden_dim, lstm_num_layers, batch_first=True, dropout=dropout)
        self.fc = nn.Sequential(
            nn.Linear(lstm_hidden_dim, lstm_hidden_dim * 4),
            nn.LayerNorm(lstm_hidden_dim * 4),
            nn.LeakyReLU(),
            nn.Dropout(p=dropout),

            nn.Linear(lstm_hidden_dim * 4, output_dim),
        )
    #

    def forward(self, x):
        x = self.embed(x)
        x, _ = self.lstm(x)
        x = self.fc(x)
        x = x.permute(0, 2, 1)
        return x
    #
#

这是使用 torchinfo 的模型摘要。

LSTM 模型摘要

=================================================================
Layer (type:depth-idx) Param #
=================================================================
WordPredictionLSTMModel - 
├─Embedding: 11 3,379,200
├─LSTM: 12 4,087,200
├─Sequential: 13 - 
│ └─Linear: 21 2,474,328
│ └─LayerNorm: 22 6,288
│ └─LeakyReLU: 23 - 
│ └─Dropout: 24 - 
│ └─Linear: 25 20,757,000
=================================================================
Total params: 30,704,016
Trainable params: 30,704,016
Non-trainable params: 0
=================================================================

解读准确率:在 P100 GPU 上对 1200 万句英语句子进行大约 8 小时训练后,我们达到了 4.03 的损失值,top-1 准确率为 29%,top-5 准确率为 49%。这意味着模型在 29%的情况下能够正确预测下一个词汇,在 49%的情况下,训练集中下一个词汇是模型前五个预测中的一个。

我们的成功指标应该是什么? 虽然我们模型的 top-1 和 top-5 准确率数字并不令人印象深刻,但对于我们的问题,它们并不那么重要。我们的候选词是一个适合滑动模式的小词汇集合。我们希望模型能够选择一个理想的候选词来完成句子,使其在语法和语义上都连贯。由于我们的模型通过训练数据学习语言的本质,我们期望它对连贯的句子赋予更高的概率。例如,如果我们有句子 “棒球运动员” 和可能的补全候选词(“跑了”、“游泳”、“躲藏”),那么“跑了”是比其他两个更好的后续词。因此,如果我们的模型以比其他词更高的概率预测“跑了”,那么它就能满足我们的需求。

解读损失值:4.03 的损失值意味着预测的负对数似然值为 4.03,这意味着正确预测下一个词汇的概率为 e^-4.03 = 0.0178 或 1/56。一个随机初始化的模型通常有大约 8.8 的损失值,这是-log_e(1/6600),因为模型随机预测 1/6600 个词汇(6600 是词汇表的大小)。虽然 4.03 的损失值可能看起来并不理想,但重要的是要记住,训练后的模型比未训练(或随机初始化)的模型要好约 120 倍。

接下来,让我们看看如何利用这个模型来改进我们的滑动键盘的建议功能。

使用模型来修剪无效的建议

我们来看一个实际的例子。假设我们有一个部分句子 “我认为”,用户做出如下图中蓝色的滑动模式,从“o”开始,经过“c”和“v”之间,结束于“e”和“v”之间。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这个滑动模式可能表示的一些词汇是

  1. 结束

  2. 十月(October 的缩写)

  3. 我已经(省略了撇号)

在这些建议中,最可能的一个可能是*“I’ve”*。让我们将这些建议输入到我们的模型中,看看它输出什么。

[I think] [I've] = 0.00087
[I think] [over] = 0.00051
[I think] [ice] = 0.00001
[I think] [Oct] = 0.00000

等号后的值是词作为句子前缀有效完成的概率。在这种情况下,我们看到词“I’ve”被分配了最高的概率。因此,它是最可能跟随句子前缀“I think”的词。

接下来你可能会问,我们如何计算这些下一个词的概率。让我们来看看。

计算下一个词的概率

为了计算一个词是否为句子前缀的有效完成,我们以评估(推理)模式运行模型,并输入标记化的句子前缀。我们还在词前添加一个空格前缀来标记化词。这是因为 HuggingFace 预标记器在词的开头用空格拆分词,所以我们希望确保我们的输入与 HuggingFace 标记器使用的标记化策略一致。

假设候选词由 3 个标记 T0、T1 和 T2 组成。

  1. 我们首先用原始标记化的句子前缀运行模型。对于最后一个标记,我们检查预测 T0 标记的概率。我们将其添加到“probs”列表中。

  2. 接下来,我们对前缀+T0 进行预测,并检查 T1 的概率。我们将此概率添加到“probs”列表中。

  3. 接下来,我们对前缀+T0+T1 进行预测,并检查 T2 的概率。我们将此概率添加到“probs”列表中。

“probs”列表包含生成 T0、T1 和 T2 标记的单独概率。由于这些标记对应于候选词的标记化,我们可以将这些概率相乘,以获得候选词作为句子前缀的完成的组合概率。

计算完成概率的代码如下所示。

 def get_completion_probability(self, input, completion, tok):
      self.model.eval()
      ids = tok.encode(input).ids
      ids = torch.tensor(ids, device=self.device).unsqueeze(0)
      completion_ids = torch.tensor(tok.encode(completion).ids, device=self.device).unsqueeze(0)
      probs = []
      for i in range(completion_ids.size(1)):
          y = self.model(ids)
          y = y[0,:,-1].softmax(dim=0)
          # prob is the probability of this completion.
          prob = y[completion_ids[0,i]]
          probs.append(prob)
          ids = torch.cat([ids, completion_ids[:,i:i+1]], dim=1)
      #
      return torch.tensor(probs)
  #

下面我们可以看到更多示例。

[That ice-cream looks] [really] = 0.00709
[That ice-cream looks] [delicious] = 0.00264
[That ice-cream looks] [absolutely] = 0.00122
[That ice-cream looks] [real] = 0.00031
[That ice-cream looks] [fish] = 0.00004
[That ice-cream looks] [paper] = 0.00001
[That ice-cream looks] [atrocious] = 0.00000

[Since we're heading] [toward] = 0.01052
[Since we're heading] [away] = 0.00344
[Since we're heading] [against] = 0.00035
[Since we're heading] [both] = 0.00009
[Since we're heading] [death] = 0.00000
[Since we're heading] [bubble] = 0.00000
[Since we're heading] [birth] = 0.00000

[Did I make] [a] = 0.22704
[Did I make] [the] = 0.06622
[Did I make] [good] = 0.00190
[Did I make] [food] = 0.00020
[Did I make] [color] = 0.00007
[Did I make] [house] = 0.00006
[Did I make] [colour] = 0.00002
[Did I make] [pencil] = 0.00001
[Did I make] [flower] = 0.00000

[We want a candidate] [with] = 0.03209
[We want a candidate] [that] = 0.02145
[We want a candidate] [experience] = 0.00097
[We want a candidate] [which] = 0.00094
[We want a candidate] [more] = 0.00010
[We want a candidate] [less] = 0.00007
[We want a candidate] [school] = 0.00003

[This is the definitive guide to the] [the] = 0.00089
[This is the definitive guide to the] [complete] = 0.00047
[This is the definitive guide to the] [sentence] = 0.00006
[This is the definitive guide to the] [rapper] = 0.00001
[This is the definitive guide to the] [illustrated] = 0.00001
[This is the definitive guide to the] [extravagant] = 0.00000
[This is the definitive guide to the] [wrapper] = 0.00000
[This is the definitive guide to the] [miniscule] = 0.00000

[Please can you] [check] = 0.00502
[Please can you] [confirm] = 0.00488
[Please can you] [cease] = 0.00002
[Please can you] [cradle] = 0.00000
[Please can you] [laptop] = 0.00000
[Please can you] [envelope] = 0.00000
[Please can you] [options] = 0.00000
[Please can you] [cordon] = 0.00000
[Please can you] [corolla] = 0.00000

[I think] [I've] = 0.00087
[I think] [over] = 0.00051
[I think] [ice] = 0.00001
[I think] [Oct] = 0.00000

[Please] [can] = 0.00428
[Please] [cab] = 0.00000

[I've scheduled this] [meeting] = 0.00077
[I've scheduled this] [messing] = 0.00000

这些示例展示了词在句子中的前面完成的概率。候选词按概率降序排列。

由于 Transformer 模型正逐渐取代 LSTM 和 RNN 模型用于基于序列的任务,让我们看看一个用于相同目标的 Transformer 模型会是什么样的。

Transformer 模型

基于 Transformer 的模型是一种非常流行的架构,用于训练语言模型以预测句子中的下一个词。我们将使用的具体技术是因果注意力机制。我们将仅使用因果注意力训练PyTorch 中的 Transformer 编码器层。因果注意力意味着我们允许序列中的每个标记仅查看它之前的标记。这类似于单向 LSTM 层在仅向前训练时所使用的信息。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们将看到的 Transformer 模型直接基于 PyTorch 中的 nn.TransformerEncodernn.TransformerEncoderLayer

import math

def generate_src_mask(sz, device):
    return torch.triu(torch.full((sz, sz), True, device=device), diagonal=1)
#

class PositionalEmbedding(nn.Module):
    def __init__(self, sequence_length, embed_dim):
        super().__init__()
        self.sqrt_embed_dim = math.sqrt(embed_dim)
        self.pos_embed = nn.Parameter(torch.empty((1, sequence_length, embed_dim)))
        nn.init.uniform_(self.pos_embed, -1.0, 1.0)
    #

    def forward(self, x):
        return x * self.sqrt_embed_dim + self.pos_embed[:,:x.size(1)]
    #
#

class WordPredictionTransformerModel(nn.Module):
    def __init__(self, sequence_length, num_embed, embed_dim, pad_idx, num_heads, num_layers, output_dim, dropout, norm_first, activation):
        super().__init__()
        self.vocab_size = num_embed
        self.sequence_length = sequence_length
        self.embed_dim = embed_dim
        self.sqrt_embed_dim = math.sqrt(embed_dim)
        self.embed = nn.Sequential(
            nn.Embedding(num_embed, embed_dim, pad_idx),
            PositionalEmbedding(sequence_length, embed_dim),
            nn.LayerNorm(embed_dim),
            nn.Dropout(p=0.1),
        )

        encoder_layer = nn.TransformerEncoderLayer(
            d_model=embed_dim, nhead=num_heads, dropout=dropout, batch_first=True, norm_first=norm_first, activation=activation,
        )
        self.encoder = nn.TransformerEncoder(encoder_layer, num_layers=num_layers)
        self.fc = nn.Sequential(
            nn.Linear(embed_dim, embed_dim * 4),
            nn.LayerNorm(embed_dim * 4),
            nn.LeakyReLU(),
            nn.Dropout(p=dropout),

            nn.Linear(embed_dim * 4, output_dim),
        )
    #

    def forward(self, x):
        src_attention_mask = generate_src_mask(x.size(1), x.device)
        x = self.embed(x)
        x = self.encoder(x, is_causal=True, mask=src_attention_mask)
        x = self.fc(x)
        x = x.permute(0, 2, 1)
        return x
    #
#

我们可以用这个模型代替之前使用的 LSTM 模型,因为它的 API 是兼容的。这个模型在训练相同数量的数据时需要更长的时间,但性能相当。

Transformer 模型更适合长序列。在我们的例子中,序列长度为 256。完成下一个单词所需的大部分上下文通常是局部的,因此我们这里并不需要 Transformers 的强大能力。

结论

我们看到如何使用基于 LSTM(RNN)和 Transformer 模型的深度学习技术解决非常实际的 NLP 问题。并非所有语言任务都需要使用拥有数十亿参数的模型。对于需要建模语言本身而不是记忆大量信息的专业应用,可以使用更小的模型,这些模型比我们现在常见的大型语言模型更容易部署和更高效。

除了第一张图片外,所有的图片都是由作者创建的。

PageRank 的可视化解释

原文:towardsdatascience.com/large-graph-analysis-with-pagerank-e571e3dec8ed?source=collection_archive---------9-----------------------#2023-08-09

了解 Google 搜索引擎如何根据链接结构对文档进行排名

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 Vyacheslav Efimov

·

关注 发表在 Towards Data Science ·14 分钟阅读·2023 年 8 月 9 日

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

排名是机器学习中的一个重要问题。给定一组文档,目标是根据特定标准对它们进行排序。排名在信息检索系统中广泛使用,用于排序搜索结果,或在推荐系统中筛选出可能对特定用户感兴趣的内容。

根据具体问题和目标,存在大量的排名算法。我们将在本文中研究的算法名为PageRank。它的主要目标是通过利用关于连接性的信息对一组文档(网页)进行排名。分配给每个网页的排名表示它的重要性:排名越高,重要性越高。该算法基于两个假设,我们将在下一节中讨论。

假设

我们可以通过做出两个假设来定义网页的“重要性”一词。

如果有许多其他网页指向某个网页,那么该网页的重要性就会很高。

假设我们有一篇热门的研究论文以及许多其他文章通过引用或结果链接到它。主要是,这使得给这篇文章赋予较大重要性是有意义的。另一方面,如果有一个未知的网页没有其他资源的链接,似乎将低重要性分配给该页面是合乎逻辑的。

实际上,我们还应该关注入站链接的质量。

一个网页的重要性与指向它的网页的重要性成正比。

如果一个页面最初被维基百科上的高质量文章引用,那么这样的链接应该具有更大的权重。相反,当一个完全不知名的资源指向另一个网页时,它通常不会有高的重要性。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

来自官方论文的 PageRank 算法的重要性分布示例。得分被标准化为总和为 100。具有 38.4 值的节点由于有大量其他节点指向它而具有如此高的重要性。另一方面,重要性为 34.3 的节点只有一个入站链接,但由于其唯一的输入链接来自另一个有影响力的节点,它的重要性仍然相对较高。重要性为 1.6 的节点没有任何入站链接。

正式定义

假设一个节点的重要性等于所有入站链接权重的总和。

想象一个重要性为rᵢ的节点i,它有k 个出站链接。我们如何确定每个链接的权重?最直接的方法是将节点的重要性平均分配给所有出站链接。这样,每个出站链接将获得rᵢ / k的权重。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

节点排名计算示例

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

节点的排名等于入站节点的排名总和除以它们的总出度。

给定一个 n 个网页的图,我们可以创建一个 n 个线性方程的系统来找到图的权重。然而,这样的系统可能有无限多个解。这就是为什么我们应该添加另一个约束条件以强加唯一解。顺便说一下,PageRank 添加了归一化条件,即所有节点的重要性之和等于 1。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

寻找描述图结构的线性方程组的解

我们已经提出了一个解决方案,但它不可扩展。即使使用高斯消元法,我们的复杂度也达到了 O(n³)。考虑到分析的网页数量 n 可以达到数十亿,我们需要想出一种更高效的方法。

首先,让我们简化表示法。为此,我们引入了邻接方阵 G,它将包含每对链接网页的链接权重(如果两个网页没有链接,我们将在相应的矩阵元素中放置 0)。更正式地:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

矩阵元素 G[j][i] 的定义

矩阵 G 被称为随机矩阵,因为它的每一列的总和为 1。

接下来,我们定义排名向量 r,其 i -th 元素等于页面 i 的排名(重要性)。该向量所有元素的总和也等于 1。我们的最终目标是找到这个向量 r 的值。

PageRank 方程

让我们看看如果将矩阵 G 乘以向量 r 会发生什么。根据上一节的图示,我们可以看到结果仍然是相同的向量 r

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

将矩阵 G 乘以向量 r 再次得到向量 r

为什么会这样?这只是巧合吗?请记住,矩阵 Gi -th 行包含所有输入链接到页面 i 的权重。当我们将 i -th 行的 j -th 元素乘以 r[j] 时,我们实际上得到的是组件 rj / d[j]out —— 从节点 j 流向 i 的重要性。如果节点 ij 之间没有链接,则相应的组件设置为 0。逻辑上,i -th 行与向量 r 的乘积的最终结果将等于从图的任何连接节点流向节点 i 的所有重要性的总和。根据定义,这个值等于节点 i 的排名。一般来说,我们可以写出以下方程:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

PageRank 方程

因此,我们的目标是找到一个向量 r,使其在与输入矩阵 G 相乘时保持不变。

特征向量

我们可以通过回顾线性代数中关于特征向量的理论来找到上述方程的解。给定一个矩阵 A,如果存在一个数 α 使得下列方程成立,则向量 v 被称为特征向量

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

特征值定义

数字 α 被称为 特征值。我们可以注意到,PageRank 方程对应于特征值方程,其中 A = G, v = rα = 1。通常,任何方阵都有多个特征值和特征向量,但由于我们的矩阵 G 是随机的,理论上它的最大特征值等于 1。

幂迭代

寻找矩阵特征向量的最流行的方法之一是 幂迭代 方法。它包括用一些值(我们将使用 1 / n,其中 n 是网页数量)初始化初始向量 r,然后不断计算 G * r 的值,并将该值重新分配给 r。如果在任何迭代中,向量 rG * r 之间的距离小于某个阈值 ε,我们就停止算法,因为它已经成功收敛。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

PageRank 算法

在上述示例中,我们可以看到,通过将 ε 设置为 0.0005,算法在仅 9 次迭代中正确收敛:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

显然,这只是一个玩具示例,但在实际中,这种方法对于更多变量也能很好地工作。

随机游走

想象一个游览者(行走者)在时刻 t 位于图的任何节点上。我们用 p(t) 表示一个向量,其中 i 位置的分量等于游览者在时刻 t 出现在节点 i 的概率。然后,游览者随机(以相等的概率)选择另一个链接到当前节点的节点,并在时刻 t + 1 移动到那里。最终,我们希望找到时刻 t + 1 的分布向量 p(t + 1)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

游览者的随机游走

我们可以注意到,游览者在时刻 t + 1 出现于节点 i 的概率是游览者之前在相邻节点 j 的概率总和(所有链接到 i 的节点)乘以从节点 j 移动到 i 的概率。

  • 我们已经知道游览者在时刻 t 出现在节点 j 的概率:p(t)[j]

  • 从节点 ji 的移动概率等于 G[j][i]

通过汇总这些概率,我们得到 p(t + 1)[i] 的值。为了找到所有图节点的 p(t + 1) 值,我们可以将相同的方程写成矩阵形式:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这个方程的形式与我们之前为 PageRank 得到的完全相同!这意味着这两个问题有相同的解决方案和解释。

在某个时刻,分布向量 p(t) 会收敛:p(t + 1) = M * p(t) = p(t)。在这种情况下,收敛后的向量 p(t) 被称为 平稳分布。在所有后续时刻,驻留在任何给定节点的概率不会改变。

节点的 PageRank 得分等于游览者通过随机游走图后,未来会出现在该节点的概率。

收敛

描述的图遍历过程通常被称为“马尔可夫链”。在马尔可夫链理论中存在一个定理,指出:

在图结构的某些条件下,稳态分布是唯一的,并且可以通过任意初始概率分布在 t = 0 时到达。

在以下部分中,我们将更深入地探讨实现唯一收敛所需满足的条件。结果表明,并非所有图都能实现唯一收敛。

原则上,我们希望避免两种情况。

死胡同

没有出链接的节点称为死胡同。这种节点的问题在于它们会使总权重从网络中泄漏。以下是一个示例:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

死胡同问题。在时刻 t = 2,权重泄漏。在时刻 t = 3,排名向量收敛。

蜘蛛陷阱

如果一组节点没有指向该组外其他节点的出链接,则该组节点形成蜘蛛陷阱。基本上,一旦进入这些节点,就无法离开这个节点组。蜘蛛陷阱会导致以下两个问题:

  • 算法从不收敛。

  • 形成蜘蛛陷阱的节点组吸收了所有图的权重。结果,这些节点的权重非常高,而其他节点的权重为 0。

第一个问题如下面的图所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

蜘蛛陷阱问题。从时刻 t = 0 开始,1 和 0 的排名在两个节点之间无限交替。结果,算法从不收敛。

权重的吸收在下图中展示。虽然在下面的玩具示例中可能看起来不是一个严重的问题,但想象一个有数百万网页的网络,其中几个网页形成了蜘蛛陷阱。因此,这几个页面将分配所有可用的权重,而所有其他网页的权重将被设置为 0。显然,这不是我们在现实中通常期望的情况。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

节点 b 和 d 形成了一个蜘蛛陷阱。结果,在时刻 t = 18 时,它们已经吸收了所有的权重,而其他节点的权重为零。从此时开始,权重在节点 b 和 d 之间交替,使得算法发散。

传送

Google 提出的一个解决方案是在每次移动前添加以下条件:

  • 以概率 β,移动到另一个链接的节点。

  • 以概率 (1 — β),通过传送移动到一个随机节点。

参数 β 被称为 衰减因子。原始 PageRank 算法的作者建议选择 β = 0.85,这意味着平均来说,冲浪者在 5 次过渡后会随机跳到另一个节点。这个想法是,如果冲浪者陷入了蜘蛛陷阱,那么经过一段时间,它最终会通过传送门离开那里。

下图显示了传送门如何帮助处理蜘蛛陷阱问题。如果冲浪者走到节点 c,那么它将永远停留在那里。引入传送门(蓝线)有助于消除这个问题,确保在一段时间后,冲浪者将不得不移动到另一个随机节点。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

传送门(蓝线)消除了蜘蛛陷阱问题

然而,对于死胡同节点,我们需要稍微修改方法。从上述一个例子中,我们知道死胡同会导致图中的重要性泄漏。这种现象可以在幂迭代方法中观察到,当秩向量因为初始矩阵 G 中的零列而变成全零。最终,我们可以做的是:

每当冲浪者到达一个死胡同节点时,它应该立即跳到图中的一个随机节点(概率相等)。

实际上,我们可以修改初始矩阵 G 来满足这一声明:我们只需将所有死胡同节点的列中的所有元素的零替换为 1 / n。下面的示例演示了这一原理。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

节点 c 是一个死胡同节点,在矩阵 G 中对应一列全零的列。将 n = 3 个传送门从 c 添加到图中的所有节点,会使从 c 到任何节点的移动概率 p = 1 / 3。为了考虑这一点,我们用 1 / 3 填充矩阵 G 中与节点 c 对应的列。

我们可以注意到,添加传送门后,所有矩阵列的和现在等于 1。换句话说,矩阵 G 变成了随机链。这是一个重要的属性,我们将在后面使用。

收敛条件

马尔可夫链理论中存在一个关键定理定义了收敛条件。

对于任何起始向量,转移矩阵 G 会收敛到一个唯一的正定平稳分布向量 r,如果对应于 G 的链是随机的、非周期性的和不可约的。

让我们回顾一下这个定理中的最后三个属性,并检查引入的传送门是否解决了上述问题。

一个链 G 被称为随机链,如果其每一列的和等于 1。

如上所述,将传送门添加到死胡同节点消除了矩阵中的零列,使所有列的和等于 1。这个条件已经满足。

一个链 G 被称为周期链,如果存在一个数字 k > 1,使得任何一对节点之间的路径长度总是 k 的倍数。否则,链被称为非周期链。

这个条件意味着返回到同一状态的次数必须是 k 的倍数。在非周期性的情况下,返回会在不规则的时间发生。基本上,这个条件涉及到蜘蛛陷阱问题。由于我们已经通过添加传送门解决了蜘蛛陷阱问题,因此链 G 是非周期的。

如果从任意一个节点到任何其他节点的过渡概率始终大于 0,则链 G 被称为不可约的。

这个条件意味着任意两个节点之间总是存在一个链接,因此不可能卡在任何一个节点上。换句话说,矩阵 G 需要包含所有非零元素。我们将在下一节中看到如何通过连接图中的所有节点来满足这个条件。

修改算法

Google 提出的 PageRank 算法以初始矩阵 G 为基础,通过将死胡同的传送门添加到其他节点来调整它。这确保了随机性。为了保证非周期性和不可约性,它然后对每个节点添加之前描述的条件:

  • β 的概率,移动到另一个链接节点。

  • (1 — β) 的概率,移动到一个随机节点。

在数学上,这导致每个节点的以下等级方程:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

PageRank 的向量方程

我们可以将这个方程转换成矩阵形式:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Google 的 PageRank 矩阵方程

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

矩阵 R 必须满足唯一平稳分布 r 存在的必要条件,而这个分布需要被找到。

让我们绘制修改后的图和上面某个示例的相应转移矩阵 R:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

从原始链接矩阵 G 和传送门矩阵组成的矩阵 R。在这个例子中 β = 0.9

提高效率

我们唯一剩下的问题是如何存储转移矩阵 R。记住 R 是一个大小为 n x n 的方阵,其中 n 是网页的数量。目前,Google 拥有超过 250 亿个网页!矩阵 R 不含任何零,因此它是密集的,这意味着我们必须完全存储它。假设每个矩阵元素需要 4 字节存储。存储矩阵 R 所需的总内存大小等于 (25 * 10⁹)² * 4(字节)~ 3 * 10²¹(字节)。这是一个巨大的内存大小!我们需要想出另一种方法,将其至少减少几个数量级。

首先,我们可以简单地注意到,添加传送门等同于将初始矩阵 G 的元素减少 (1 — β)% 并均匀分配到每个节点。牢记这一点,我们可以将 PageRank 的矩阵方程转换成另一种格式:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

转换 PageRank 方程

让我们看一下最后得到的方程。G是初始链接矩阵,大多数元素都等于 0。为什么会这样?实际上,如果你查看任何网页,它可能只包含最多几十个指向其他网页的链接。考虑到有超过 250 亿个网页,我们得到的总链接数相对于网页数量是极其少的。因此,G中有很多零,G是稀疏的。

存储稀疏矩阵所需的内存远远少于密集矩阵。假设每个网页平均链接到其他 40 个网页。现在存储矩阵 G 所需的总字节数变为25 * 10⁹ * 40(字节)* = 10¹²*(字节)* = 1*(TB)。结果是,我们只需要 1TB 来存储G。与之前相比,这是一个巨大的改进!

实际上,在每次迭代中,我们只需计算矩阵G与向量r的乘积,将其乘以β,并在结果向量的每个元素中加上常数*(1 — β) / n*。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

结果 PageRank 方程

还要记住,如果初始链G包含死节点,那么每次迭代时向量r的总和将小于 1。为了解决这个问题,只需对其进行重新归一化,使得所有向量组件的总和为 1。

完整算法

在下图中,我们可以看到 PageRank 算法的完整版本。在每次迭代中,排名更新分为两个阶段。第一阶段仅根据初始矩阵G进行更新。然后我们将排名向量的组件汇总到变量s中。这样,(1 — s)的值就是单个节点的总输入排名减少的值。为了弥补这一点,在第二阶段,我们考虑了传送,并将它们从一个节点添加到所有节点中,值为(1 — s) / n

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

完整的 PageRank 算法

结论

在本文中,我们探讨了 PageRank 算法的不同公式,以最终得出其优化版本。尽管存在并发展了其他用于排名搜索结果的方法,PageRank 仍然是 Google 搜索引擎背后最有效的算法之一。

参考文献

本文的逻辑结构基于斯坦福大学关于大图的讲座。

除非另有说明,否则所有图片均由作者提供

大型语言模型和向量数据库在新闻推荐中的应用

原文:towardsdatascience.com/large-language-models-and-vector-databases-for-news-recommendations-6f9348fd4030?source=collection_archive---------1-----------------------#2023-12-14

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片由 Roman Kraft 提供,来自 Unsplash

将 LLMs 应用到生产环境中,使用 Sentence Transformers 和 Qdrant

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 João Felipe Guedes

·

关注 发表在 Towards Data Science ·8 分钟阅读·2023 年 12 月 14 日

大型语言模型(LLMs)随着最近生成 AI 工具如 Chat-GPT、Bard 等的发布,引起了机器学习社区的全球关注。这些解决方案的核心思想之一是计算非结构化数据(如文本和图像)的数值表示,并在这些表示之间找到相似性。

然而,将所有这些概念应用到生产环境中有其自身的一系列机器学习工程挑战:

  • 如何快速生成这些表示?

  • 如何将它们存储在合适的数据库中?

  • 如何在生产环境中快速计算相似性?

在本文中,我介绍了两种旨在解决这些问题的开源解决方案:

  • Sentence Transformers [1]:一种基于文本信息的嵌入生成技术;

  • Qdrant:一个能够存储嵌入并提供易于查询接口的向量数据库。

这些工具应用于 NPR [2],一个新闻门户推荐数据集(在 Kaggle 上公开可用),该数据集旨在支持学术界开发推荐算法。在文章结束时,你将看到如何:

  • 使用 Sentence Transformers 生成新闻嵌入

  • 使用 Qdrant 存储嵌入

  • 查询嵌入以推荐新闻文章

本文的所有代码均可在 Github 上获取。

1. 使用 Sentence Transformers 生成嵌入

首先,我们需要找到一种将输入数据转换为向量的方法,我们称之为嵌入(如果你想深入了解嵌入的概念,我推荐阅读 Boykis 的文章 What Are Embeddings? [3])。

那么让我们来看看我们可以使用 NPR 数据集处理什么样的数据:

import pandas as pd

df = pd.read_parquet("articles.parquet")
df.tail()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

来自 NPR 的示例数据(作者生成的图像)

我们可以看到 NPR 拥有一些有趣的文本数据,如文章的 标题正文 内容。我们可以在嵌入生成过程中使用它们,如下图所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

嵌入生成过程(作者提供的图像)

一旦我们定义了输入数据的文本特征,我们需要建立一个嵌入模型来生成我们的数值表示。幸运的是,我们可以在 HuggingFace 等网站上寻找适合特定语言或任务的预训练模型。在我们的示例中,我们可以使用 neuralmind/bert-base-portuguese-cased 模型,该模型为以下任务在巴西葡萄牙语上进行过训练:

  • 命名实体识别

  • 句子文本相似性

  • 识别文本蕴含

从代码方面来看,我们如何翻译嵌入生成过程:

from sentence_transformers import SentenceTransformer

model_name = "neuralmind/bert-base-portuguese-cased"
encoder = SentenceTransformer(model_name_or_path=model_name)

title = """
  Paraguaios vão às urnas neste domingo (30) para escolher novo presidente
"""

sentence = title

sentence_embedding = encoder.encode(sentence)
print (sentence_embedding)
# output: np.array([-0.2875876, 0.0356041, 0.31462672, 0.06252239, ...])

所以,给定一个示例输入数据,我们可以将titletags内容连接成一个文本,并传递给编码器生成文本嵌入。

我们可以对 NPR 数据集中所有其他文章应用相同的过程:

def generate_item_sentence(item: pd.Series, text_columns=["title"]) -> str:
    return ' '.join([item[column] for column in text_columns])

df["sentence"] = df.apply(generate_item_sentence, axis=1)
df["sentence_embedding"] = df["sentence"].apply(encoder.encode)

注意:请注意,根据你机器的处理能力,这个过程可能会花费更多时间。

一旦我们获得了所有新闻文章的嵌入,我们需要定义一种策略来存储它们。

2. 存储嵌入

由于生成嵌入可能是一个耗费资源的过程,我们可以使用向量数据库来存储这些嵌入,并根据不同的策略执行查询。

有几种向量数据库软件可以实现这个任务,但本文将使用Qdrant,这是一款开源解决方案,提供了适用于流行编程语言的 API,如PythonGoTypescript。要对这些向量数据库进行更好的比较,请查看这篇文章[4]。

设置 Qdrant

为了处理所有 Qdrant 操作,我们需要创建一个指向向量数据库的客户端对象。Qdrant 允许你创建一个免费的服务层级来测试与数据库的远程连接,但为了简便起见,我将创建并本地保存数据库:

from qdrant_client import QdrantClient
client = QdrantClient(path="./qdrant_data")

一旦建立了这个连接,我们可以在数据库中创建一个集合,以存储新闻文章的嵌入:

from qdrant_client import models
from qdrant_client.http.models import Distance, VectorParams

client.create_collection(
    collection_name = "news-articles",
    vectors_config = models.VectorParams(
        size = encoder.get_sentence_embedding_dimension(),
        distance = models.Distance.COSINE,
    ),
)

print (client.get_collections())
# output: CollectionsResponse(collections=[CollectionDescription(name='news-articles')])

请注意,向量配置参数用于创建集合。这些参数告诉 Qdrant 向量的一些属性,如它们的size和比较向量时使用的distance度量(我将使用余弦相似度,但你也可以使用其他策略,如内积或欧氏距离)。

生成向量点

在最终填充数据库之前,我们需要创建适当的对象以进行上传。在 Qdrant 中,向量可以使用PointStruct类进行存储,你可以使用这个类定义以下属性:

  • id:向量的 ID(在 NPR 的情况下,是newsId

  • vector:表示向量的 1 维数组(由嵌入模型生成)

  • payload:包含任何其他相关元数据的字典,这些数据后来可以用于在集合中查询向量(在 NPR 的情况下,文章的titlebodytags

from qdrant_client.http.models import PointStruct

metadata_columns = df.drop(["newsId", "sentence", "sentence_embedding"], axis=1).columns

def create_vector_point(item:pd.Series) -> PointStruct:
    """Turn vectors into PointStruct"""
    return PointStruct(
        id = item["newsId"],
        vector = item["sentence_embedding"].tolist(),
        payload = {
            field: item[field]
            for field in metadata_columns
            if (str(item[field]) not in ['None', 'nan'])
        }
    )

points = df.apply(create_vector_point, axis=1).tolist()

上传向量

最后,在所有项目都转换为点结构后,我们可以将它们分批上传到数据库:

CHUNK_SIZE = 500
n_chunks = np.ceil(len(points)/CHUNK_SIZE)

for i, points_chunk in enumerate(np.array_split(points, n_chunks)):
    client.upsert(
        collection_name="news-articles",
        wait=True,
        points=points_chunk.tolist()
    )

3. 查询向量

现在,集合已经填充了向量,我们可以开始查询数据库。我们可以用多种方式输入信息来查询数据库,但我认为有 2 种非常有用的输入方式:

  • 输入文本

  • 输入向量 ID

3.1 使用输入向量查询向量

假设我们建立了这个向量数据库以供搜索引擎使用。在这种情况下,我们期望用户输入的是一个文本输入,我们必须返回最相关的项目。

由于向量数据库中的所有操作都是用……向量来完成的,因此我们首先需要将用户输入的文本转换为向量,以便我们可以根据该输入找到相似的项目。回顾一下,我们使用了句子变换器将文本数据编码成嵌入,因此我们可以使用同样的编码器为用户的输入文本生成数值表示。

由于 NPR 包含新闻文章,我们假设用户输入了*“唐纳德·特朗普”*以了解美国选举:

query_text = "Donald Trump"
query_vector = encoder.encode(query_text).tolist()
print (query_vector)
# output: [-0.048, -0.120, 0.695, ...]

一旦计算出输入查询向量,我们可以在集合中搜索最接近的向量,并定义我们希望从这些向量中获得什么样的输出,如其newsId标题主题:

from qdrant_client.models import Filter
from qdrant_client.http import models

client.search(
    collection_name="news-articles",
    query_vector=query_vector,
    with_payload=["newsId", "title", "topics"],
    query_filter=None
)

注意:默认情况下,Qdrant 使用近似最近邻搜索快速扫描嵌入,但你也可以进行全面扫描并获取准确的最近邻——只是请注意,这是一项成本更高的操作。

执行此操作后,以下是生成的输出标题(为更好理解已翻译成英文):

  • 输入句子唐纳德·特朗普

  • 输出 1巴拉圭人在本周日(30 日)去投票选举新总统

  • 输出 2选民表示拜登和特朗普不应在 2024 年竞选,路透/益普索民调显示

  • 输出 3记者指控特朗普在 1990 年代对她进行性虐待

  • 输出 4迈克·彭斯,特朗普的前副总统,法院作证可能使前总统陷入困境

看起来除了带来与特朗普本人相关的新闻外,嵌入模型还成功地表示了与总统选举相关的主题。注意在第一个输出中,除了总统选举,没有直接提到输入词“唐纳德·特朗普”。

此外,我遗漏了一个query_filter参数。如果你想指定输出必须满足某些条件,这个工具非常有用。例如,在新闻门户中,通常重要的是仅筛选出最新的文章(例如过去 7 天内)。因此,你可以查询符合最低发布时间戳的新闻文章。

注意: 在新闻推荐的背景下,有多个值得关注的方面,如公平性和多样性。这是一个开放的话题,但如果你对此领域感兴趣,可以查看NORMalize Workshop上的文章。

3.2 使用输入向量 ID 查询向量

最后,我们可以让向量数据库“推荐”更接近某些期望的向量 ID,但远离不希望的向量 ID。期望的和不希望的 ID 分别称为正例负例,它们被视为推荐的种子。

例如,假设我们有以下正 ID:

seed_id = '8bc22460-532c-449b-ad71-28dd86790ca2'
# title (translated): 'Learn why Joe Biden launched his bid for re-election this Tuesday'

然后我们可以请求类似于这个示例的项目:

client.recommend(
    collection_name="news-articles",
    positive=[seed_id],
    negative=None,
    with_payload=["newsId", "title", "topics"]
)

在运行此操作后,以下是翻译后的输出标题:

  • 输入项: 了解乔·拜登为什么在本周二宣布竞选连任

  • 输出 1: 拜登宣布他将竞选连任

  • 输出 2: 美国:拜登竞选连任的 4 个原因

  • 输出 3: 选民表示拜登和特朗普不应该在 2024 年参选,路透社/艾普索斯民调显示

  • 输出 4: 拜登顾问的失言引发对选举后可能出现第二届政府的疑虑

结论

本文展示了如何将 LLM 和向量数据库结合起来以提供推荐。特别是使用了句子变换器来生成来自 NPR 数据集的文本新闻文章的数值表示(嵌入)。一旦这些嵌入被计算出来,它们可以填充像 Qdrant 这样的向量数据库,从而根据多种策略方便地查询向量。

在本文中的示例之后可以进行大量改进,例如:

  • 测试其他嵌入模型

  • 测试其他距离度量

  • 测试其他向量数据库

  • 使用基于编译的编程语言如 Go 来提高性能

  • 创建一个 API 以提供推荐

换句话说,可能会出现许多想法来改善 LLM 的推荐机器学习工程。因此,如果你想分享你对这些改进的想法,请随时通过这里给我发消息 😃

关于我

我是Globo的高级数据科学家,这是一家巴西媒体技术公司。作为公司推荐团队的一员,我身边有一个令人惊叹和才华横溢的团队,他们付出了很多努力,通过数字产品如G1GEGloboplay等为数百万用户提供个性化内容。如果没有他们不可或缺的知识,这篇文章是不可能完成的。

参考文献

[1] N. reimers 和 I. Gurevych, Sentence-BERT: 使用 Siamese BERT 网络的句子嵌入 (2019), 计算语言学协会。

[2] J. Pinho, J. Silva 和 L. Figueiredo, NPR: 新闻门户推荐数据集 (2023), ACM 推荐系统会议

[3] V. Boykis, 什么是嵌入?,个人博客

[4] M. Ali, 前 5 大向量数据库 (2023), DataCamp 博客

大型语言模型作为零-shot 标注者

原文:towardsdatascience.com/large-language-models-as-zero-shot-labelers-d26aa2642c88

使用 LLMs 为监督模型获取标签

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 Devin Soni

·发布于 Towards Data Science ·5 分钟阅读·2023 年 3 月 20 日

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片由 h heyerlein 提供,来源于 Unsplash

介绍

数据标注是构建监督式机器学习模型中的一个关键步骤,因为标签的数量和质量通常是决定模型性能的主要因素。

然而,数据标注可能非常耗时且昂贵,特别是对于涉及领域知识或阅读大量数据的复杂任务。

近年来,大型语言模型(LLMs)作为获取文本数据标签的强大解决方案出现。通过零-shot 学习,我们可以仅使用 LLM 的输出来获取未标记数据的标签,而不必让人类来获取这些标签。这可以显著降低获取标签的成本,并使过程变得更加可扩展。

在这篇文章中,我们将进一步探讨零-shot 学习的概念以及 LLMs 如何用于这一目的。

什么是零-shot 学习?

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片由 Alex Knight 提供,来源于 Unsplash

零-shot 学习(ZSL)是机器学习中的一种问题设置,其中模型被要求解决一个它没有经过训练的预测任务。这通常涉及将数据识别或分类为训练时未明确见过的概念。

在传统的监督学习中,这是不可能的,因为模型只能对其训练过的任务(即有标签的任务)进行预测。然而,在 ZSL 范式中,模型可以推广到任意未见的任务,并在合理的水平上表现。请注意,在大多数情况下,针对特定任务训练的监督模型仍将优于使用 ZSL 的模型,因此 ZSL 更常在监督标签尚不可用时使用。

ZSL 最有前景的应用之一是在数据标记中,它可以显著降低获取标签的成本。如果一个模型能够自动将数据分类到类别中,而无需在该任务上进行训练,它可以用于为下游监督模型生成标签。这些标签可以用于引导一个监督模型,这种方式类似于主动学习或人机交互式机器学习。

大语言模型的零样本学习

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Arseny Togulev拍摄,图片来源于Unsplash

像 GPT-3 这样的 LLM 是 ZSL 的强大工具,因为它们的稳健预训练过程使它们对自然语言有全面的理解,这种理解并不依赖于某个特定监督任务的标签。

嵌入搜索

LLM 的上下文嵌入能够捕捉给定文本中的语义概念,这使得它们在 ZSL 中非常有用。

句子转换器这样的库提供了经过训练的 LLM,这些 LLM 使得语义相似的文本具有彼此距离很小的嵌入。

[## GitHub - UKPLab/sentence-transformers: 多语言句子与图像嵌入与 BERT

这个框架提供了一种计算句子、段落和图像的稠密向量表示的简单方法……

github.com](https://github.com/UKPLab/sentence-transformers?source=post_page-----d26aa2642c88--------------------------------)

如果我们有一些标记数据的嵌入,我们可以使用最近邻搜索来找到具有相似嵌入的未标记数据。

如果两个文本在嵌入空间中非常接近,那么它们很可能具有相同的标签。

上下文学习

上下文学习是 LLM 的一种新兴能力,它使它们能够仅通过查看输入-输出对来学习解决新任务。模型无需更新参数即可学习任意新任务。

[## 上下文学习如何运作?理解与传统学习的差异框架…

在这篇文章中,我们提供了一个关于大语言模型如 GPT-3 的上下文学习的贝叶斯推理框架。

ai.stanford.edu](http://ai.stanford.edu/blog/understanding-incontext/?source=post_page-----d26aa2642c88--------------------------------)

我们可以利用这种能力,通过仅提供几个输入-输出对来获得标签,并让模型为未标记的数据点提供标签。

在零样本学习的背景下,这意味着我们可以提供一些手工制作的文本示例及其相关的监督标签,让模型实时学习标注功能。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在这个简单的案例中,我们训练 ChatGPT 通过上下文学习来分类一个句子是否与青蛙相关。

生成模型

最近,生成 LLMs 中的对齐方法,如RLHF(来自人类反馈的强化学习)的进展,使得只需要求模型为你标注数据成为可能。

[## 说明来自人类反馈的强化学习(RLHF)

本文已翻译成中文简体。对翻译成其他语言感兴趣?请联系 nathan…

huggingface.co](https://huggingface.co/blog/rlhf?source=post_page-----d26aa2642c88--------------------------------)

如 ChatGPT 这样的模型能够通过简单地(用语言)回复所需标签来为输入数据提供标签。它们通过在如此大量的数据上进行预训练获得的丰富世界知识,使这些模型能够仅凭语义理解来解决新任务。

这个过程可以通过使用开源模型如FLAN-T5来自动化,只需要求模型仅用你的标签集中的项回应(例如,“回应‘是’或‘否’”),然后在询问模型标签后检查哪个选项的输出概率最高。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

ChatGPT 不仅能提供标签,还能解释其获得该标签的逻辑。

结论

数据标注是监督机器学习中的关键步骤,但获取大量标注数据可能很昂贵。

使用零样本学习和 LLMs,我们可以显著降低标签获取的成本。

LLMs 在大量数据上进行预训练,编码了对世界信息的语义理解,使它们在任意未见任务上表现出色。这些模型可以高准确度地自动标注数据,使我们可以以低成本启动监督模型。

大语言模型:DeBERTa — 解码增强型 BERT 与解耦注意力

原文:towardsdatascience.com/large-language-models-deberta-decoding-enhanced-bert-with-disentangled-attention-90016668db4b?source=collection_archive---------2-----------------------#2023-11-28

探索 Transformers 中注意力机制的高级版本

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 Vyacheslav Efimov

·

关注 发表在 Towards Data Science ·9 分钟阅读·2023 年 11 月 28 日

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

介绍

近年来,BERT 已成为许多自然语言处理任务中的首选工具。它在处理、理解信息和构建高精度词嵌入方面的卓越能力达到了最先进的水平。

众所周知,BERT 基于从 Transformer 架构中衍生出的注意力机制。注意力是现在大多数大语言模型的关键组成部分。

## 大型语言模型:BERT — 基于 Transformer 的双向编码表示

了解 BERT 如何构建最先进的嵌入

towardsdatascience.com

然而,在机器学习领域,新的思想和方法不断发展。2021 年,BERT 类模型中出现了一种创新技术,称为“解耦注意力”。这一概念的实现催生了 DeBERTa——一种融合了解耦注意力的模型。虽然 DeBERTa 只引入了一对新的架构原则,但与其他大型模型相比,其在顶级 NLP 基准测试中的改进是显著的。

在本文中,我们将参考原始的 DeBERTa 论文,并覆盖理解其工作原理所需的所有细节。

1. 解耦注意力

在原始的 Transformer 块中,每个 token 都由一个单一的向量表示,该向量以逐元素嵌入和的形式包含关于 token 内容和位置的信息。这种方法的缺点是潜在的信息丢失:模型可能无法区分一个词本身还是它的位置对某个嵌入向量分量的重要性。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

BERT 和 DeBERTa 中的嵌入构造。与将所有信息存储在一个向量中的方法不同,DeBERTa 使用两个独立的向量来存储词和位置的嵌入。

DeBERTa 提出了一个新颖的机制,其中相同的信息存储在两个不同的向量中。此外,注意力计算算法也被修改,以显式考虑 token 内容和位置之间的关系。例如,词汇 “research”“paper” 在彼此接近时的相关性远大于它们在不同文本部分出现时的相关性。这个例子清楚地说明了为什么也需要考虑内容到位置的关系。

解耦注意力的引入需要修改注意力分数的计算。事实证明,这一过程非常简单。计算两个嵌入之间的交叉注意力分数,每个嵌入由两个向量组成,可以简单地分解为四个子向量的成对乘积之和:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

计算两个嵌入向量之间的交叉注意力分数。

相同的方法可以推广到矩阵形式。从图中,我们可以观察到四种不同类型的矩阵(向量),每种矩阵代表内容和位置信息的某种组合:

  • 内容到内容 矩阵;

  • 内容到位置 矩阵;

  • 位置到内容 矩阵;

  • 位置到位置 矩阵。

可以观察到位置到位置的矩阵没有存储任何有价值的信息,因为它没有关于单词内容的细节。这就是为什么在解耦注意力中会忽略这个术语的原因。

对于其余三个术语,最终输出的注意力矩阵计算方式与原始 Transformer 相似。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

DeBERTa 中输出解耦注意力的计算

尽管计算过程看起来类似,但有一对细微差别需要考虑。

从上面的图示中,我们可以注意到用于表示查询内容 Qc 和键位置 Krᵀ 矩阵键内容 Kc 和查询位置 Qrᵀ 矩阵之间乘法的符号*与普通矩阵乘法符号x不同。实际上,这并非偶然,因为在 DeBERTa 中提到的矩阵对的乘法方式略有不同,以考虑到令牌的相对位置。

  • 根据普通矩阵乘法规则,如果 C = A x B,则元素 C[i][j] 通过 A 的第 i 行与 B 的第 j 列的逐元素乘法来计算。

  • 在 DeBERTa 的特殊情况下,如果 C = A * B,则 C[i][j] 计算为 A 的第 i 行与 Bδ(i, j) 列的乘积,其中 δ 表示索引 ij 之间的相对距离函数,其定义如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

索引 i 和 j 之间的相对距离定义。k 是一个超参数,用于控制最大可能的相对距离。图片由作者采用。

k 可以被视为一个超参数,用于控制索引 ij 之间的最大可能相对距离。在 DeBERTa 中,k 被设置为 512。为了更好地理解公式,我们可以绘制一个热图,展示不同索引的 ij 的相对距离(k = 6)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

例如,如果 k = 6i = 15j = 13,则 ij 之间的相对距离 δ 等于 8。为了获得索引 i = 15j = 13 的内容到位置评分,在查询内容 Qc 和键位置 Kr 矩阵的乘法中,Qc 的第 15 行应乘以 Krᵀ 的第 8 列。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

内容到位置的评分计算用于令牌 ij

然而,对于位置到内容的评分,算法的工作方式稍有不同:这次算法在矩阵乘法中使用的是 δ(j, i) 的值,而不是 δ(i, j)。正如论文的作者所解释的:“这是因为 对于给定的位置 i,位置到内容计算的是键内容在 j 的注意力权重相对于位置 i 的查询,因此相对距离是 δ(j, i)”。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

位置到内容的得分计算对于令牌 i 和 j

δ(i, j) ≠ δ(j, i),即 δ 不是对称函数,这意味着 i 和 j 之间的距离与 j 和 i 之间的距离不同。

在应用 softmax 转换之前,注意力得分会被一个常数 √(3d) 除以,以便更稳定地训练。这个缩放因子不同于原始 Transformer 中使用的(√d)。这个 3 倍的差异由 DeBERTa 注意力机制中 3 个矩阵的求和导致的较大幅度(而不是 Transformer 中的单个矩阵)所证明。

2. 增强的掩码解码器

解耦注意力仅考虑内容和相对位置。然而,没有关于绝对位置的信息被考虑,这可能在最终预测中扮演重要角色。DeBERTa 论文的作者给出了一个具体的例子:句子“a new store opened beside the new mall”被送入 BERT,掩盖的单词是“store”和“mall”用于预测。虽然掩盖的单词具有相似的含义和局部上下文(形容词“new”),但它们在句子中代表完全不同的角色。如果没有关于掩盖单词的起始和结束位置的完整信息,正确恢复原始句子变得更加困难。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

来自 DeBERTa 论文 的文本示例。仅使用解耦注意力,模型无法正确恢复原始短语。

为了更好地理解这个问题,假设你知道实际上是商场先开了,商店在它之后开张。然后你需要填入句子 a new ___ store opened beside the new ___。作为一个英语使用者,你知道任何在 opened beside 后面的词语,从语法上看意味着它先开张。同时,任何在这些词之前的词则晚开张。因此,你自信地分别填入 storemall。为什么对你来说这很容易做到?因为作为人类,你自然会考虑被掩盖单词的绝对位置。

现在假设你对掩盖单词的绝对位置一无所知。因此,你将无法使用关于 opened beside 构造周围的语法词序的提示。结果是,尽管有单词的语义含义和局部上下文,你仍然无法给出正确的答案。这对于模型而言是类似的情况,当它无法访问绝对位置时。

在语言中可以有许多类似的例子,这就是为什么将 绝对位置 纳入模型中至关重要。

在 BERT 中,输入嵌入考虑了绝对位置。谈到 DeBERTa,它在所有 Transformer 层之后但在应用 softmax 层之前纳入了绝对位置。实验表明,在所有 Transformer 层中捕捉相对位置,并且只有在引入绝对位置后,模型性能有所提升。研究人员表示,反向处理可能会阻止模型学习足够的相对位置信息。

架构

根据 论文,增强掩码解码器(EMD)有两个输入块:

  • H — 来自前一层 Transformer 的隐藏状态。

  • I — 解码所需的任何信息(例如,隐藏状态 H、绝对位置嵌入或来自前一层 EMD 的输出)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

DeBERTa 中的增强掩码解码器。图片由作者提供。

通常,一个模型中可以有多个 n EMD 块。如果是这样,它们会按照以下规则构建:

  • 每个 EMD 层的输出是下一层 EMD 层的输入 I

  • 最后一层 EMD 层的输出被送入语言模型头。

对于 DeBERTa,EMD 层的数量设置为 n = 2,位置嵌入用于第一层 EMD 层中的 I

NLP 中另一个常用技术是跨不同层共享权重,目的是减少模型复杂度(例如,ALBERT)。这一思想也在 DeBERTa 的 EMD 块中得到实现。

## 大型语言模型,ALBERT — 用于自监督学习的轻量级 BERT

理解 BERT 架构选择背后的基本技术,以产生紧凑且高效的模型

[towardsdatascience.com

当 I = H 且 n = 1 时,EMD 等同于 BERT 解码器层。

DeBERTa 设置

消融研究

实验表明,DeBERTa 中引入的所有组件(位置到内容的注意力、内容到位置的注意力和增强掩码解码器)都提高了性能。去除任何一个组件都会导致指标降低。

尺度不变的精细调优

此外,作者提出了一种新的对抗算法,称为“尺度不变精细调优”,以提高模型的泛化能力。其思想是对输入序列加入小的扰动,使模型对对抗样本更具弹性。在 DeBERTa 中,扰动应用于标准化的输入词嵌入。对于更大的精细调优 DeBERTa 模型,这种技术效果更佳。

DeBERTa 变体

DeBERTa 的论文展示了三种模型。它们之间的比较见下图。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

DeBERTa 变体

数据

对于预训练,DeBERTa 的基础版和大型版使用了以下数据集的组合:

  • English Wikipedia + BookCorpus (16 GB)

  • OpenWebText(公开 Reddit 内容:38 GB)

  • Stories (31 GB)

数据去重后,结果数据集的大小减少到 78 GB。对于 DeBERTa 1.5B,作者使用了两倍以上的数据(160 GB),且词汇量达到了 128K。

相比之下,其他大型模型如 RoBERTa、XLNet 和 ELECTRA 在 160 GB 数据上进行预训练。同时,DeBERTa 在各种 NLP 任务中展现了与这些模型相当或更优的性能。

说到训练,DeBERTa 在每一步使用 2K 样本进行了一百万步的预训练。

Conclusion

我们已经深入探讨了 DeBERTa 架构的主要方面。凭借解耦的注意力机制和增强的掩码编码算法,DeBERTa 已成为许多数据科学家在 NLP 流水线中的极受欢迎的选择,也是许多 Kaggle 竞赛中的获胜要素。另一个关于 DeBERTa 的令人惊讶的事实是,它是首批在 SuperGLUE 基准测试中超越人类的 NLP 模型之一。这一单一证据足以得出结论:DeBERTa 将在 LLM 历史上长时间存在。

Resources

除非另有说明,否则所有图片均由作者提供

大型语言模型揭示了国家社会工作执照考试中的额外缺陷

原文:towardsdatascience.com/large-language-models-expose-additional-flaws-in-the-national-social-work-licensing-exams-d5d2ca426fec?source=collection_archive---------12-----------------------#2023-04-11

变革的需求

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 Brian Perron, PhD

·

关注 发表在 Towards Data Science ·14 分钟阅读·2023 年 4 月 11 日

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片来自作者通过 Midjourney 创建。

作为一名以数据为驱动的社会工作教授,我正在为人工智能技术对我们领域的变革性影响做准备。虽然人工智能不会取代社会工作者,但它将显著重塑研究、实践和教育。

普林斯顿大学经济学家埃德·费尔滕及其同事开发了一种独特的度量指标,称为 AI 职业暴露度。该度量通过将十种 AI 应用(如阅读理解、语言建模和翻译)与 52 种人类能力(包括口头理解和归纳推理)联系起来,突显了 AI 对特定职业的影响。该团队将这一指标应用于美国劳动部创建的职业信息网络数据库中的 800 多个职业,以确定大型语言模型对各个领域的潜在影响。费尔滕的完整报告可以在arXiv上找到。“高等教育社会工作教师”在所有职业中的 AI 暴露度排名第 11 位。AI 对该领域的影响将取决于社会工作领域如何迅速适应这一技术,并应对这些进步所带来的挑战。

生成性 AI 的潜在影响引起了我的关注,尤其是有报告显示 ChatGPT 在法律、商业和医学考试中表现出色。我和我的同事决定在社会工作背景下评估 ChatGPT,因此我们准备了全国社会工作执业考试的模拟测试。ChatGPT 在某些考试版本中轻松超越了合格门槛(更多内容见下文)。评估还揭示了考试中存在的重要有效性问题,超出了以往研究结果的范围。

我们的评估紧随社会工作委员会 2022 年报告之后,该组织负责管理考试,报告强调了按种族、年龄和主要语言划分的显著通过率差异。以下是一些硕士级考试的差异:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

由作者根据 2022 年 ASWB 考试通过率分析重新制作的图表 — 最终报告。 “最终通过率”指的是在第一次尝试时通过考试,或在多次尝试后通过考试,直到获得合格分数为止。有关首次尝试通过率差异的更多信息,请参阅最终报告。

这些差异提出了重要的社会公正和伦理问题,因为社会工作执照对于进入劳动力市场至关重要。请注意,临床级和学士级考试也存在显著差异。

在这篇文章中,我通过直接比较四种语言模型:ChatGPT-3.5、ChatGPT-4、Bard 和 Bing,更新了我们最初的评估。这篇文章评估了所有模型在考试中的表现,但也——更重要的是——揭示了考试本身的额外有效性问题。这些有效性问题在现实世界中有严重的影响,因为它们削弱了不同群体考生的就业机会,主要基于种族、年龄和母语。

请注意,本文包含一些敏感内容,包括涉及性犯罪者的场景。我理解这些话题可能不适合所有观众,并鼓励读者在继续之前使用他们的判断。

原始评估背景

我们无法仅通过 ChatGPT-3.5 访问实际的执业许可考试。因此,我们使用了由考试开发者,即社会工作委员会(ASWB)构建的测试题库来准备考试模拟。我们的评估发现,ChatGPT-3.5 在硕士级别的考试中表现非常出色,正确回答了 80% 的问题。这个分数超过了约 70% 的及格线。ChatGPT-3.5 在本科和临床考试中也表现良好(分别为 76% 和 64%)。

对于那些不在该行业中的人,每道 ASWB 考试题都呈现一个与社会工作相关的场景,并附有四个多项选择答案。原始问题受版权保护,因此我不能直接分享它们。相反,我提供了一个由 ChatGPT-3.5 编写的示例。我给模型提供了问题的示例以及一个提示,以模仿测试题的写作风格、内容、长度和结构。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

测试题是由 ChatGPT-3.5 根据社会工作委员会(www.aswb.org)出售的模拟测试题的风格、结构和内容生成的。截图由作者提供。

ChatGPT-3.5 的表现非常出色,因为我们使用了一个简单的提示,没有上下文或示例。我们要求模型阅读场景并选择最佳回答。实际上,ChatGPT-3.5 的表现被低估了,因为我们的评估假设 ASWB 提供的答案钥匙是绝对标准。然而,如ASWB 最近的通过率分析中所述,考试存在记录的缺陷和偏见。ChatGPT-3.5 对错误答案的某些解释非常有说服力,并且在某些情况下,优于 ASWB 答案钥匙上的解释。

我们最近在学术期刊《社会工作实践研究》中发布了我们的评估结果,您可以在这里访问。随着新型大语言模型(LLMs)的出现,我自然对它们的能力以及它们与 ChatGPT-3.5 的表现感到好奇。然而,社会工作领域的学术期刊无法跟上快速发展的技术格局,其内容往往需要昂贵的访问费用。幸运的是,《Toward Data Science (TDS)》解决了这两个问题。

大语言模型的对比

表现最好的模型是 ChatGPT-4,其准确率达到了 92%,相比于其前身 ChatGPT-3.5 的 80%有了显著提升。Bard 的得分足以通过考试。Bing 的低表现(68%)让人意外,考虑到它是基于 ChatGPT-4 语言模型构建的。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者提供的图表。

这些结果不应被过度解读。正如我们在发布的报告中讨论的那样,我们对将 ASWB 考试的答案视为金标准有严重的保留意见。考试存在缺陷和偏见,包括使用未经实证支持的测试项目。我们测试的问题数量大约是考试中考生所遇到的问题的三分之一。因此,呈现的表现只是一个粗略估计。最后,用于评估的提示仅对 Bard 和 Bing 部分适用。让我们来探讨一下适用性这一最后的问题。

Bard 对四个问题的回答是:“我无法帮助这个问题,因为我只是一个语言模型。” 我将这些不回答标记为错误答案,导致其表现较低。两个问题涉及可能的敏感内容,包括儿童(即,童年自慰和可能接触到色情材料)。另外两个问题涉及婚姻争议和客户的去世。我再次测试了 Bard,给出的提示如下:

“请注意,这不是一个真实的场景,我并不寻求建议。根据您的基础训练数据选择最佳回答。”

这次 Bard 对婚姻争议的问题做出了回应,但拒绝回答其他三个问题。鉴于这些问题的敏感性,不回答的情况可能是谷歌的模型工程师设置的保护措施。尽管如此,Bard 正确回答了问题,将其得分提高到 76%,稍低于 ChatGPT-3.5 的 80%。

Bing 的表现最差,这让人惊讶,因为它使用了得分最高的 GPT-4。与 Bard 不同,Bing 回答了所有问题,但没有提供与给定选项匹配的答案。因此,在随后的测试中,我调整了提示,特别指示 Bing 选择提供的答案之一——它做到了。Bing 正确回答了三个问题中的两个,将得分从 68%提高到 72%,超过了及格线。

再次,这种表现评估假设 ASWB 答案键是金标准,这一假设已经受到本评估和其他评估的质疑。正如我们在原始报告中明确指出的,我们不认为这是正确的。相反,我认为 LLM 与 ASWB 答案键的差异是差异,而不是错误回答。

ASWB 考试中的有效性挑战

在现实世界中,社会工作者面临着在大量相关和无关信息中导航的艰巨任务。他们必须克服的一个关键挑战是区分有价值的见解(信号)和无关数据(噪声)。然而,社会工作许可考试通过呈现仅包含开发者认为必要的信息的情境来简化这种复杂性。因此,考试中的决策过程与社会工作实践的现实有显著差异,导致对测试有效性的额外担忧。

这种差异引发的测试有效性问题主要与生态有效性相关,生态有效性衡量一个测试或评估在多大程度上反映现实生活情境,并准确评估在这些情境中所需的技能、知识或行为。通过人为去除在噪声中识别相关信息的挑战,考试可能无法有效评估社会工作实践中的一个关键方面,从而损害其生态有效性。

在本节中,我将讨论与生态有效性相关的两种有效性挑战:构念无关方差和构念不足表现。这些挑战可能会对测试者能力的评估精度产生负面影响,从而导致不准确和不完整的结果。

构念无关方差

构念无关方差发生在测试测量与其预期目的无关的因素时。在 ASWB 考试的情况下,目标是评估社会工作者在伦理和安全方面的实践能力。然而,构念无关方差的一个例子是,当具有强大考试技巧的个人在标准化测试中表现更好时,无论他们在社会工作方面的知识或能力如何。

几乎十年前,一项研究发现了 ASWB 考试中构念无关方差的证据。研究人员David Albright 和 Bruce Thyer给一年级 MSW 学生进行了修改后的 ASWB 实践考试。他们移除了所有问题,只留下了四个选择项。在随机猜测的假设下,考生应该能正确回答 25%的问题。令人惊讶的是,他们在没有问题的情况下准确猜测了 52%的选项。这一结果表明,参与者可能是根据答案选择中的语言模式做出推测的。

这个例子展示了与构念无关的方差,因为考生的成功不是基于他们的社会工作知识或能力,而是基于他们识别语言模式和做出有根据的猜测的能力。因此,ASWB 考试无意中测量了他们的考试技能,而这些与评估伦理和安全社会工作实践的预期构念无关。

我使用一种特定策略来最小化潜在偏差并提高标准化多项选择测试的准确性。首先,我遮住答案选项,根据我对主题的理解来制定回应。接下来,我揭示答案选项,选择与我最初回应最接近的选项。

我在 LLM 评估期间在几个问题上使用了这个策略。例如,一个问题要求确定社会工作者用来帮助经历婚姻困境的夫妇的治疗框架。最初,我想到的是“家庭系统理论”,但这不在可选项中。然而,“结构性家庭疗法”是一个选项。家庭治疗不在我的专业领域内。我对家庭系统理论了解甚少,对结构性家庭疗法知之更少。鉴于语言模式的相似性,我选择了结构性家庭疗法,这也是正确的。我的考试策略使我能够猜测出正确答案。

这个情境展示了与构念无关的方差,因为我回答问题的成功并不是基于我的社会工作知识或特定的治疗框架。相反,它依赖于我的考试策略和识别语言模式的能力。因此,测试无意中测量了我的考试技能,而不是评估社会工作实践能力的预期构念。

我想知道 LLMs 在回答多项选择题时是否使用了类似的策略。我进行了一项小型实验,将它们对开放性问题的回答与对多项选择题的回答进行比较。如果 LLMs 对两种问题格式的回答有所不同,那么这些模型可能使用了类似于我所描述的策略。不同的回答也可能表明问题本身存在问题。

我向 Bard 展示了有关婚姻冲突的情境。这是一个需要迅速重构问题才能让 Bard 作出回应的问题之一。最终,Bard 选择了“结构性家庭”疗法。当以开放性问题的形式呈现相同情境时,Bard 回应了“家庭系统理论”,同时承认“结构性家庭疗法”可能也是一个答案。以下是 Bard 的完整回答:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Bard 的回应。作者截图。

Bing 对这个场景的首次回应是“家庭系统理论”,这不是多项选择中的选项之一。当明确指示从可用的多项选择中选择时,Bing 选择了“结构家庭”治疗。我也以类似的方式回答了这个问题。再次,我最初想到的答案是“家庭系统理论”,然后从多项选择中选择了“结构家庭”治疗。当将场景呈现为开放式问题时,Bing 说“系统理论”,这是一个包含“家庭系统理论”的类别。换句话说,家庭系统理论是系统理论的一种。以下是 Bing 的完整回应:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Bing 的回应。截图由作者提供。

ChatGPT4 和 ChatGPT3.5 在多项选择格式中选择了“结构家庭”治疗。作为开放式问题,ChatGPT-4 识别了“系统理论”,回应与 Bing 类似。然而,这种相似性不应令人惊讶,因为 Bing 使用了 ChatGPT-4。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

ChatGPT-4 的回应。截图由作者提供。

最终,ChatGPT-3.5 识别了“生态系统理论”,一种系统理论。我认为特别有趣的是,ChatGPT-3.5 明确承认根据提供的场景确定准确的框架是困难的。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

ChatGPT-3.5 的回应。作者的回应。

构念缺失

构念缺失发生在测试或评估未能充分捕捉与测量构念相关的技能、知识或行为的全范围时。构念缺失导致对测试者能力的评估不完整或狭窄,可能导致对其能力或表现的不准确结论。我将使用 LLM 来展示这个问题如何存在于各种考试问题中。

一道测试题涉及一个单句场景——即要求一名社会工作者分析将影响社区的新社会福利政策。社会工作者应该首先做什么?这就是整个场景。ChatGPT-4 错误回答了四个问题,这其中之一就是这个。以下是 ChatGPT-4 的回应:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

ChatGPT-4 的回应。截图由作者提供。

这个回答是合理的,并符合安全和伦理实践。然而,ASWB 的答案键指出,社会工作者“必须首先了解政策的历史背景……然后再进行分析阶段。”ASWB 假设只有一种正确的方法来全面理解新政策。这一问题是构念缺失的一个例子,因为问题需要考虑也安全和伦理的替代路径。

我将问题从多项选择改为开放性问题,以更全面地调查问题。这种修改允许更好地理解 ChatGPT-4 分析政策的步骤,而不受限于预定的选项。如你所见,ChatGPT-4 建议的初步步骤是彻底审查新政策,包括检查所有相关文件和背景信息,以提供变化的背景。我也赞赏 ChatGPT-4 对脆弱群体潜在影响的认可。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

ChatGPT-4 的回应。作者截图。

再次,ChatGPT-4 错误地回答了多项选择题。然而,当被要求详细说明回应时,它表现出了专业判断和对伦理及安全实践的遵守。这个例子突显了考试如何由于构造不良的多项选择题限制,可能阻碍个人获得执照。

我将通过一个涉及在社区心理健康中心工作的社会工作者的情境来说明构建不足的问题,该工作者与成年性犯罪者合作。这位社会工作者对一个客户感到厌恶,并告诉他的主管他无法对这个人产生同情或共鸣。尽管讨论了一个月,但他们没有取得任何进展。这个情境促使测试者识别社会工作者应该采取的下一步行动。

在多项选择格式中,ChatGPT-4 选择了(所谓的)正确答案:“将客户转移给另一位社会工作者。”我给 ChatGPT-4 相同的情境,但修改了提示,允许它在回答前提出澄清问题。

请阅读以下情境并确定最佳回应。在回答之前,请提出任何你需要的额外问题以做出决定。

ChatGPT-4 提出了三个澄清问题:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

ChatGPT-4 的回应。作者截图。

我以应该影响答案的方式作出了回应。以下是我的回应和 ChatGPT-4 的答案。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

ChatGPT-4 的回应。作者截图。

这个例子说明了如果测试者在题目中加入额外信息可能会遇到的困难。换句话说,测试者应当以不将问题与实际生活经历联系的方式来解答每一个问题。这种考试题目与现实情境之间的脱节是有问题的。从有效性的角度来看,忽视现实生活经历来回答问题可能不能准确地反映测试者在实际情况中应用社会工作知识的能力。忽略实际操作的复杂性和背景,使得考试不能充分评估社会工作者的能力。

ChatGPT 对有效性的看法是什么?

在性犯罪者的相同场景中,我修改了问题提示,并要求 ChatGPT-4 识别任何潜在的有效性问题。令我惊讶的是,ChatGPT-4 超出了我的期望,提供了高质量的回应,特别是在标准有效性方面。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

ChatGPT-4 的回应。作者截图。

考试旨在促进安全、称职和伦理的实践,从而增强公众保护。然而,目前没有证据明确证明社会工作者在现实世界中执行伦理和安全工作的能力与其在此特定考试中的表现之间存在直接联系。如果考试未能准确测量其声称测量的构念,则很难——也许是不可能——基于考试结果得出可靠和有效的结论。

下一步

社会工作执照考试应设计以确保社会工作者能够提供安全和伦理的服务。然而,考试有效性长期以来的担忧以及最近发布的 ASWB 通过率突显的种族和年龄差异,强调了需要更多公平和充分的保障措施。

ASWB 的垄断地位以及考试对有志成为社会工作者的财务负担进一步加剧了变革的紧迫性。随着生成性 AI 技术提供了全新的机会,现在是超越对话,采取行动解决长期存在的问题的时候了。我将重申我们初步评估中的建议,即州立法者应暂时暂停执照要求,以促使注意力转向更公平的方法。在未来的发展中,该领域需要优先考虑真正的创新,而不仅仅是重新修订一个有缺陷的设计。

致谢

我想对布莱恩·维克多博士(Bryan Victor, PhD)、谢丽尔·库比亚克博士(Sheryl Kubiak, PhD)(来自韦恩州立大学),以及来自密歇根大学的贝斯·安杰尔博士(Beth Angell, PhD)表示感谢,我们之前在这一主题上的合作工作对本文中的观点产生了重要影响。我感谢维克多博士和巴布·希尔茨对本文的详细反馈;任何剩余的错误均由我本人负责。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值