DSPy入门:告别指令提示,拥抱编程之旅!

原文:intro-to-dspy-goodbye-prompting-hello-programming

2024 年 2 月 27 日

DSPy框架如何通过用编程和编译代替提示来解决基于LLM的应用程序中的脆弱性问题。

目前,使用大型语言模型(LLMs)构建应用程序不仅复杂而且脆弱。典型的pipelines通常使用prompts来实现,这些prompts是通过反复试验手工制作的,因为LLMs对prompts的方式很敏感。因此,当您更改pipelines中的某个部分(例如LLM或数据)时,可能会削弱其性能—除非您调整prompts(或微调步骤)。

当您更改pipeline中的一部分时,例如LLM或数据,您可能会削弱其性能……

DSPy[1]是一个框架,旨在通过优先编程而不是prompt来解决基于语言模型(LM)的应用程序中的脆弱性问题。它允许您在更改组件时重新编译整个管道,以根据您的特定任务对其进行优化,而不是重复手动轮次的prompt工程。

虽然关于该框架的论文[1]早在2023年10月就已经发表了,但我是最近才知道的。在看了Connor Shorten的一个视频“DSPy解释!” 之后,我已经可以理解为什么开发者社区对DSPy如此兴奋了!

本文简要介绍了DSPy框架,涵盖了以下主题:

  • 什么是DSPy(包括关于DSPy vs. LangChain vs. LlamaIndex和DSPy vs. PyTorch的讨论)
  • DSPy编程模型:签名,模块,和提词器
  • DSPy编译器
  • DSPy示例:Naive RAG Pipeline

    什么是DSPy

DSPy(“D declarative S self - improved Language P programs (in Python)”,发音为“dee-es-pie”)[1]是一个由斯坦福NLP研究人员开发的“基于基础模型的编程”框架。它强调编程而不是提示,并使构建基于lm的管道远离操作提示而更接近编程。因此,它旨在解决构建基于lm的应用程序中的脆弱性问题。

DSPy还通过将程序的信息流与每个步骤的参数(prompt和LM权重)分离,为构建基于LM的应用程序提供了一种更加系统化的方法。然后,DSPy将使用您的程序并自动优化如何为您的特定任务prompt(或微调)lm。

为此,DSPy引入了以下一系列概念:

  • 手写的prompt和fine-tune被抽象并替换为签名(Signature)
  • 更高级的prompt技术,如Chain of Thought或ReAct,被抽象并替换为Modules。
  • 手动prompt工程是自动化的提示器(teleprompters)和DSPy编译器

使用DSPy构建基于lm的应用程序的工作流程,在DSPy入门手册中进行了讨论,如下所示。它会让你想起训练神经网络的工作流程:

1. Collect data, 2. Write DSpy program using Signatures and modules, 3. Define validation logic using teleprompter, 4. Compile DSpy program with DSPy compiler, 5. Iterate

使用DSPy构建基于llm的应用程序的工作流程

  1. 收集数据集: 收集程序输入和输出的一些示例(例如,问题和答案对),这将用于优化您的pipelines。
  2. 编写DSPy程序: 用SignatureModules定义程序的逻辑以及组件之间的信息流来解决你的任务。
  3. 定义验证逻辑: 定义一个逻辑来使用验证度量和优化器(提词器)来优化你的程序。
  4. 编译DSPy程序: DSPy编译器将训练数据、程序、优化器和验证度量考虑在内,以优化您的程序(例如,prompt或fine-tune)。
  5. 迭代: 通过改进数据、程序或验证来重复这个过程,直到您对pipelines的性能感到满意为止。

以下是与DSPy相关的所有重要链接的简短列表:

  • DSPy论文:DSPy:编译声明式语言模型调用到自改进管道 [1]
  • DSPy GitHub: GitHub - stanfordnlp/dspy: DSPy: The framework for programming—not prompting—foundation models
  • 通过关注Omar Khattab来了解DSPy的最新情况。

DSPy与LangChain或LlamaIndex有何不同?

LangChain, LlamaIndex和DSPy都是帮助开发人员轻松构建基于lm的应用程序的框架。使用LangChain和LlamaIndex的典型pipelines通常使用prompts模板实现,这使得整个pipelines对组件更改非常敏感。相比之下,DSPy使构建基于LLM的pipelines远离操作prompts,更接近于编程。

DSPy中新引入的编译器在更改基于LLM的应用程序(如LLM或数据)中的部分时,消除了任何额外的prompt工程或fine-tuning。相反,开发人员可以简单地重新编译程序来优化pipelines以适应新添加的更改。因此,DSPy可以帮助开发人员以比LangChain或LlamaIndex更少的努力获得pipelines的性能。

虽然LangChain和LlamaIndex已经在开发者社区中被广泛采用,但DSPy作为一种新的替代方案已经在同一社区中引起了相当大的兴趣。

DSPy是如何与PyTorch相关的?

如果你有数据科学背景,当你开始使用DSPy时,你会很快注意到它的语法与PyTorch相似。DSPy论文[1]的作者明确指出PyTorch是一个灵感来源。

与PyTorch类似,在PyTorch中,通用层可以在任何模型体系结构中组合,在DSPy中,通用模块可以在任何基于lm的应用程序中组合。此外,编译DSPy程序(其中DSPy模块中的参数是自动优化的)类似于在PyTorch中训练神经网络,其中使用优化器训练模型权重。

下表总结了PyTorch和DSPy之间的相似之处:

Comparison: PyTorch vs. DSPy, Training neural network vs. optimizing LM-based application

比较:PyTorch与DSPy

DSPy规划模型

本节讨论DSPy编程模型引入的以下三个核心概念:

  • 签名:抽象prompt和fine-tune
  • 模块:抽象prompt技术
  • Teleprompters:自动提示任意pipelines

签名(Signatures):抽象prompt和fine-tune

DSPy程序中对LM的每个调用都必须具有自然语言签名(signature),以取代传统的手写prompt。签名是一个简短的函数,它指定一个转换做什么,而不是如何提示LM去做(例如,“使用问题和上下文并返回答案”)。

DSPy signatures replace hand-written prompts.

DSPy签名取代手写prompt。

签名是最小形式的输入和输出字段的元组。

Structure of a minimal DSPy signature consists of one or more input and output fields

最小DSPy签名的结构

下面,您可以看到一些简写语法签名的示例。

1
2
3
4
5
"question -> answer"

"long-document -> summary"

"context, question -> answer"

在许多情况下,这些速记语法签名就足够了。但是,在需要更多控制的情况下,还可以使用以下表示法定义签名。在这种情况下,签名由三个元素组成:

  • LLM要解决的子任务的最小描述,
  • 输入字段的描述
  • 输出字段的描述。

下面,您可以看到签名上下文的完整符号, context, question -> answer:

1
2
3
4
5
class GenerateAnswer(dspy.Signature):
    """Answer questions with short factoid answers."""
    context = dspy.InputField(desc="may contain relevant facts")
    question = dspy.InputField()
    answer = dspy.OutputField(desc="often between 1 and 5 words")

与手写提示相比,签名可以通过为每个签名引导示例编译成自完善和自适应管道的prompt或fine-tune。

模块(Module):抽象提示技术

您可能熟悉几种不同的提示技巧,例如添加Your task is to ...之类的句子。或“You are a ...”在提示开头,思维链(“让我们一步一步地思考”),或者在提示结尾添加 "Don't make anything up" 或“Only use the provided context”这样的句子。

对DSPy中的模块进行模板化和参数化,以抽象这些提示技术。这意味着它们用于通过应用提示、微调、增强和推理技术使DSPy签名适应任务。

下面,您可以看到如何将签名传递给ChainOfThought模块,然后使用输入字段contextquestion的值进行调用。

1
2
3
4
5
6
7
8
9
# Option 1: Pass minimal signature to ChainOfThought module
generate_answer = dspy.ChainOfThought("context, question -> answer")

# Option 2: Or pass full notation signature to ChainOfThought module
generate_answer = dspy.ChainOfThought(GenerateAnswer)

# Call the module on a particular input.
pred = generate_answer(context = "Which meant learning Lisp, since in those days Lisp was regarded as the language of AI.",
                       question = "What programming language did the author learn in college?")

下面,您可以看到ChainOfThought模块最初如何实现签名"context, question -> answer"。如果您想自己尝试一下,可以使用lm.inspect_history(n=1)来打印最后一个提示符。

Initial implementation of the signature “context, question -> answer” with a ChainOfThought module

使用ChainOfThought初步实施签名“context, question -> answer”

在撰写本文时,DSPy实现了以下六个Module:

  • dspy.Predict:处理输入和输出字段,生成指令,并为指定的signature创建模板。
  • dspy.ChainOfThought:继承了Predict模块,并增加了“ Chain of Thought “处理的功能。
  • dspy.ChainOfThoughtWithHint:继承了Predict模块,并增强了ChainOfThought模块,增加了提供推理提示的选项。
  • dspy.MultiChainComparison:继承了Predict模块,并增加了多链比较的功能。
  • dspy.Retrieve:从检索器模块检索段落。
  • dspy.ReAct:旨在组成思想,行动和观察的交错步骤。

您可以将这些模块从 dspy.Module继承的类串联起来。这些类还提供了两个方法。你可能已经注意到与PyTorch的语法相似:

  • __init__(): 声明使用的子模块。
  • forward(): 描述已定义的子模块之间的控制流。
1
2
3
4
5
6
7
8
9
10
11
class RAG(dspy.Module):
    def __init__(self, num_passages=3):
        super().__init__()

        self.retrieve = dspy.Retrieve(k=num_passages)
        self.generate_answer = dspy.ChainOfThought(GenerateAnswer)
    
    def forward(self, question):
        context = self.retrieve(question).passages
        prediction = self.generate_answer(context=context, question=question)
        return dspy.Prediction(context=context, answer=prediction.answer)

上面的代码段在RAG()类中定义的模块之间创建了以下信息流:

img

简单的RAG管道示例代码和模块之间产生的信息流。

提词器(Teleprompters):自动提示任意管道

提词器(Teleprompters)作为DSPy程序的优化器。它们采用一个度量,并与DSPy编译器一起学习引导并为DSPy程序的模块选择有效的提示。

1
2
3
4
from dspy.teleprompt import BootstrapFewShot

# Simple teleprompter example
teleprompter = BootstrapFewShot(metric=dspy.evaluate.answer_exact_match)

在撰写本文时,DSPy实现了以下五个提词器:

  • dspy.LabeledFewShot:定义预测器使用的k个样本数。
  • dspy.BootstrapFewShot:引导Few-Shot。
  • dspy.BootstrapFewShotWithRandomSearch:继承了BootstrapFewShot提词器,并为随机搜索过程引入了额外的属性。
  • dspy.BootstrapFinetune:t将提词器定义为用于微调编译的BootstrapFewShot实例。
  • dspy.Ensemble:创建多个程序的集成版本,将不同程序的各种输出减少到单个输出。

还有SignatureOptimizerBayesianSignatureOptimizer,它们在zero/few-shot 设置中改善模块中签名的输出前缀和指令。

不同的提词器在优化成本和质量等方面提供了不同的权衡。

DSPy Compiler

DSPy编译器将在内部跟踪您的程序,然后使用优化器(提词器)对其进行优化,以最大化给定的指标(例如,提高质量或成本)。优化取决于你使用的LM类型:

  • LLMs:构建高质量的few-shot prompt
  • 用于较小的lm:训练自动fine-tune

这意味着DSPy编译器会自动将模块映射到prompt、调优、推理和增强的高质量组合。[1]在内部,编译器在输入上模拟各种版本的程序,并引导每个模块的示例跟踪以进行自我改进,以优化到您的任务的管道。这个过程类似于神经网络的训练过程。

例如,虽然初始提示前面创建的ChainOfThought模块可能是任何LM理解任务的良好起点,但它可能不是最佳提示。如下图所示,DSPy编译器优化了初始提示,从而消除了手动提示调优的需要。

Compiling the initial prompt to an optimized prompt with bootstrapped examples in DSPy

编译器接受以下输入,如下面的代码和图像所示:

  • 程序,
  • 提词器,包括定义的验证度量,以及
  • 一些训练样本。
1
2
3
4
5
6
7
8
9
10
11
12
13
from dspy.teleprompt import BootstrapFewShot

# Small training set with question and answer pairs
trainset = [dspy.Example(question="What were the two main things the author worked on before college?", 
                         answer="Writing and programming").with_inputs('question'),
            dspy.Example(question="What kind of writing did the author do before college?", 
                         answer="Short stories").with_inputs('question'),
            ...
            ]

# The teleprompter will bootstrap missing labels: reasoning chains and retrieval contexts
teleprompter = BootstrapFewShot(metric=dspy.evaluate.answer_exact_match)
compiled_rag = teleprompter.compile(RAG(), trainset=trainset)

img

DSPy Example: 朴素的RAG pipeline

现在您已经熟悉了DSPy中的所有基本概念,让我们将它们放在您的第一个DSPy pipeline中。

检索增强生成(retrieve -augmented generation, RAG)目前在生成式人工智能领域非常流行。所以,我们搭配一个快速、简单的RAG管道开始学习DSPy才有意义。

对于Jupyter Notebook形式的端到端管道,我建议查看DSPy GitHub存储库中的Intro Notebook或Connor Shorten的Getting Started with RAG in DSPy Notebook。

前提条件:安装DSPy

要安装dspy-ai Python包,可以简单地 pip安装它。

1
pip install dspy-ai

Step 1: 安装

首先,您需要设置LLM和检索模型(RM):

  • LLM: 我们将使用OpenAI的gpt-3.5 turbo,你将需要一个OpenAI API密钥。要获得一个,您需要一个OpenAI帐户,然后在API密钥下“创建新的秘密密钥”。
  • RM: 我们将使用Weaviate,一个开源的矢量数据库,我们将填充额外的数据。

让我们从使用来自LlamaIndex GitHub存储库 (MIT许可)的一些示例数据填充外部数据库开始。您可以用您自己的数据替换这部分。

1
2
!mkdir -p 'data'
!wget 'https://raw.githubusercontent.com/run-llama/llama_index/main/docs/examples/data/paul_graham/paul_graham_essay.txt' -O 'data/paul_graham_essay.txt'

接下来,我们将把文档拆分为单个句子,并将其摄取到数据库中。为了简单起见,我们将使用本文中嵌入的Weaviate,您可以免费使用它,而无需注册API密钥。请注意,在使用Weaviate时,使用一个名为”content“的属性来摄取数据是很重要的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import weaviate
from weaviate.embedded import EmbeddedOptions
import re

# Connect to Weaviate client in embedded mode
client = weaviate.Client(embedded_options=EmbeddedOptions(),
                             additional_headers={
                                "X-OpenAI-Api-Key": "sk-<YOUR-OPENAI-API-KEY>",
                             }
                         )

# Create Weaviate schema
# DSPy assumes the collection has a text key 'content'
schema = {
   "classes": [
       {
           "class": "MyExampleIndex",
           "vectorizer": "text2vec-openai",
            "moduleConfig": {"text2vec-openai": {}},
           "properties": [{"name": "content", "dataType": ["text"]}]
       }      
   ]
}
    
client.schema.create(schema)

# Split document into single sentences
chunks = []
with open("./data/paul_graham_essay.txt", 'r', encoding='utf-8') as file:
    text = file.read()
    sentences = re.split(r'(?<!\w\.\w.)(?<![A-Z][a-z]\.)(?<=\.|\?)\s', text)
    sentences = [sentence.strip() for sentence in sentences if sentence.strip()]
    chunks.extend(sentences)

# Populate vector database in batches
client.batch.configure(batch_size=100)  # Configure batch

with client.batch as batch:  # Initialize a batch process
    for i, d in enumerate(chunks):  # Batch import data
        properties = {
            "content": d,
        }
        batch.add_data_object(
            data_object=properties,
            class_name="MyExampleIndex"
        )

现在,您可以在全局设置中配置LM和RM。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import dspy
import openai
from dspy.retrieve.weaviate_rm import WeaviateRM

# Set OpenAI API key
openai.api_key = "sk-<YOUR-OPENAI-API-KEY>"

# Configure LLM
lm = dspy.OpenAI(model="gpt-3.5-turbo")

# Configure Retriever
rm = WeaviateRM("MyExampleIndex", 
                weaviate_client = client)

# Configure DSPy to use the following language model and retrieval model by default
dspy.settings.configure(lm = lm, 
                        rm = rm)

Step 2: 数据收集

接下来,我们将收集一些训练示例(在本例中是手工注释的)。与训练神经网络相比,你只需要几个例子。

1
2
3
4
5
6
7
8
9
10
11
# Small training set with question and answer pairs
trainset = [dspy.Example(question="What were the two main things the author worked on before college?", 
                         answer="Writing and programming").with_inputs('question'),
            dspy.Example(question="What kind of writing did the author do before college?", 
                         answer="Short stories").with_inputs('question'),
            dspy.Example(question="What was the first computer language the author learned?", 
                         answer="Fortran").with_inputs('question'),
            dspy.Example(question="What kind of computer did the author's father buy?", 
                         answer="TRS-80").with_inputs('question'),
            dspy.Example(question="What was the author's original plan for college?", 
                         answer="Study philosophy").with_inputs('question'),]

Step 3: 编写DSPy程序

现在,您已经准备好编写第一个DSPy程序了。这将是一个RAG系统。首先,您需要定义签名context, question -> answer ,如Signatures所示,称为GenerateAnswer :

1
2
3
4
5
6
class GenerateAnswer(dspy.Signature):
    """Answer questions with short factoid answers."""

    context = dspy.InputField(desc="may contain relevant facts")
    question = dspy.InputField()
    answer = dspy.OutputField(desc="often between 1 and 5 words")

在定义了签名之后,您需要编写一个自定义的RAG类,它继承自dspy.Module。在__init__():方法中,您声明相关模块,在forward()方法中,您描述模块之间的信息流。

1
2
3
4
5
6
7
8
9
10
11
class RAG(dspy.Module):
    def __init__(self, num_passages=3):
        super().__init__()

        self.retrieve = dspy.Retrieve(k=num_passages)
        self.generate_answer = dspy.ChainOfThought(GenerateAnswer)
    
    def forward(self, question):
        context = self.retrieve(question).passages
        prediction = self.generate_answer(context=context, question=question)
        return dspy.Prediction(context=context, answer=prediction.answer)

Step 4: 编译DSPy程序

最后,您可以定义提词器并编译DSPy程序。这将更新ChainOfThought模块中使用的提示符。在这个例子中,我们将使用一个简单的BootstrapFewShot提词器。

1
2
3
4
5
6
7
from dspy.teleprompt import BootstrapFewShot

# Set up a basic teleprompter, which will compile our RAG program.
teleprompter = BootstrapFewShot(metric=dspy.evaluate.answer_exact_match)

# Compile!
compiled_rag = teleprompter.compile(RAG(), trainset=trainset)

现在你可以调用你的RAG管道了,如下所示:

1
pred = compiled_rag(question = "What programming language did the author learn in college?")

从这里开始,您可以评估结果并迭代过程,直到您对管道的性能感到满意为止。关于评估的详细说明,我建议查看DSPy GitHub存储库中的Intro Notebook或Connor Shorten的Getting Started with RAG in DSPy Notebook。

总结

本文简要介绍了DSPy框架[1],这是目前生成人工智能社区感到兴奋的。DSPy框架引入了一组概念,将构建基于lm的应用程序从手工提示工程转移到编程。

在DSPy中,传统的提示工程概念被以下内容所取代:

  • Signatures取代手写提示,
  • Modules取代特定的提示工程技术,以及
  • Teleprompters and the[DSPy Compiler) (https://towardsdatascience.com/intro-to-dspy-goodbye-prompting-hello-programming-4ca1c6ce3eb9#a471)取代手工迭代的提示工程。

在介绍了DSPy概念之后,本文将带您通过一个简单的RAG管道示例,使用OpenAI语言模型和Weaviate矢量数据库作为检索器模型。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/568239.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

解决“找不到MSVCP120.dll”或“MSVCP120.dll丢失”的错误方法

在计算机使用过程中&#xff0c;遇到诸如“找不到MSVCP120.dll”或“MSVCP120.dll丢失”的错误提示并不罕见。这类问题往往会导致某些应用程序无法正常运行&#xff0c;给用户带来困扰。本文旨在详细阐述MSVCP120.dll文件的重要性、其丢失的可能原因&#xff0c;以及解决方法&a…

nginx开启basic认证

basic认证也叫做http基本认证&#xff0c;防止恶意访问 首先用在线网站生成一个叫做htpasswd的账号密码文件。 将生成结果复制到/etc/nginx/htpasswd文件中 在server的location中配置 server { listen 80; server_name a.com;location / { root html;index index.…

2001-2021年上市公司制造业智能制造词频统计数据

2001-2021年上市公司制造业智能制造词频统计数据 1、时间&#xff1a;2001-2021年 2、来源&#xff1a;上市公司年报 3、指标&#xff1a;年份、股票代码、行业名称、行业代码、所属省份、所属城市、智能制造词频、智能制造占比(%) 4、范围&#xff1a;上市公司 5、样本量…

基于TSM模块的打架斗殴识别技术

目 录 1 引言.... 4 1.1 研究背景与意义.... 4 1.2 研究现状综述.... 5 1.3 研究内容.... 6 1.3.1 图像预处理的优化.... 6 1.3.2 TSM模块的应用.... 6 1.3.3 视频分类的设计与实现.... 6 2 关键技术与方法.... 8 2.1 TSM算法与模型选择.... 8 2.1.1 TSM算法原理.... 8 2.1.2 …

深度学习-数据预处理

目录 创建一个人工数据集处理缺失的数据插入对inputs中的类别值或离散值&#xff0c;将NaN视为一个类别对inputs和outputs中的数值类型转换为张量格式 创建一个人工数据集 import os import pandas as pd os.makedirs(os.path.join(.., data), exist_okTrue) data_file os.p…

基于Vue+ElementPlus自定义带历史记录的搜索框组件

前言 基于Vue2.5ElementPlus实现的一个自定义带历史记录的搜索框组件 效果如图&#xff1a; 基本样式&#xff1a; 获取焦点后&#xff1a; 这里的历史记录默认最大存储10条&#xff0c;同时右侧的清空按钮可以清空所有历史记录。 同时搜索记录也支持点击搜索&#xff0c;按…

.NET(C#)连接达梦数据库GUID字段被自动加横线的修复方法

因信创的原因项目需要兼容达梦数据库&#xff0c;今天遇到个比较坑爹的问题&#xff0c;简单记录下解决方案。 数据库存的是这样&#xff1a; 通过DataAdapter.Fill拿出来以后变成了这样 纳尼&#xff1f;谁让你加上这些横杠的&#xff1f;&#xff08;掀桌&#xff09;导致了…

100个实用电气知识

在当今社会&#xff0c;电力作为日常生活和工作中不可或缺的能源&#xff0c;扮演着越来越重要的角色。为了更好地利用电力资源&#xff0c;了解电气知识成为了越来越多人的需求。在电气领域&#xff0c;有很多实用的知识&#xff0c;这些知识对于从事电气工作的人来说是非常重…

Linux系统安全:从面临的攻击和风险到安全加固、安全维护策略(文末有福利)

1. Linux面临的攻击与风险 1.1. Linux系统架构 Linux系统架构解读&#xff1a; 用户之间隔离内核态与用户态之间隔离用户进程一般以低权限用户运行系统服务一般以特权服务运行用户态通过系统调用进入内核态内核对系统资源进行管理和分配 1.2. Linux系统常见安全威胁 1.2.1.…

OSPF认证方式,ISIS简介,ISIS路由器类型

OSPF&#xff1a;转发&#xff0c;泛洪&#xff0c;丢弃

Docker搭建代码托管Gitlab

文章目录 一、简介二、Docker部署三、管理员使用四、用户使用五、用户客户端 一、简介 GitLab是一个基于Git的代码托管和协作平台&#xff0c;类似于GitHub。 它提供了一个完整的工具集&#xff0c;包括代码仓库管理、问题跟踪、CI/CD集成、代码审查等功能。 GitLab的开源版本…

Go语言并发赋值的安全性

struct并发赋值 type Test struct {X intY int }func main() {var g Testfor i : 0; i < 1000000; i {var wg sync.WaitGroup// 协程 1wg.Add(1)go func() {defer wg.Done()g Test{1, 2}}()// 协程 2wg.Add(1)go func() {defer wg.Done()g Test{3, 4}}()wg.Wait()// 赋值…

2024新算法角蜥优化算法(HLOA)和经典灰狼优化器(GWO)进行无人机三维路径规划设计实验

简介&#xff1a; 2024新算法角蜥优化算法&#xff08;HLOA&#xff09;和经典灰狼优化器&#xff08;GWO&#xff09;进行无人机三维路径规划设计实验。 无人机三维路径规划的重要意义在于确保飞行安全、优化飞行路线以节省时间和能源消耗&#xff0c;并使无人机能够适应复杂…

国内首个48小时大模型极限挑战赛落幕,四位“天才程序员”共同夺冠

4月21日晚&#xff0c;第四届ATEC科技精英赛&#xff08;ATEC2023&#xff09;线下赛落幕。本届赛事以大模型为技术基座&#xff0c;围绕“科技助老”命题&#xff0c;是国内首个基于真实场景的大模型全链路应用竞赛。ATEC2023线下赛采用48小时极限挑战的形式&#xff0c;来自东…

Ts支持哪些类型和类型运算(上)

目录 1、元组 2、接口&#xff08;interface&#xff09; 3、枚举&#xff08;Enum&#xff09; 4、字面量类型 5、keyof 6、in keyof 7、类型的装饰 静态类型系统 就是把 类型检查从运行时提前到了编译时&#xff0c;所以ts类型系统中的许多类型与js并无区别 例如&am…

概率图模型在机器学习中的应用:贝叶斯网络与马尔可夫随机场

&#x1f9d1; 作者简介&#xff1a;阿里巴巴嵌入式技术专家&#xff0c;深耕嵌入式人工智能领域&#xff0c;具备多年的嵌入式硬件产品研发管理经验。 &#x1f4d2; 博客介绍&#xff1a;分享嵌入式开发领域的相关知识、经验、思考和感悟&#xff0c;欢迎关注。提供嵌入式方向…

go语言并发实战——日志收集系统(七) etcd的介绍与简单使用

什么是etcd etcd是基于Go语言开发的一个开源且高可用的分布式key-value存储系统&#xff0c;我们可以在上面实现配置共享与服务的注册与发现。 和它比较相似的还有我们之间所提到的Zookeeper以及consul.(注:后面我们学习微服务的时候etcd和consul会有广泛的使用) etcd有以下几…

网络中其他协议

目录 DNS协议 域名简介 ICMP协议 ICMP功能 ICMP协议格式 ping命令 NAT技术 NATP NAT技术的限制 代理服务器 DNS协议 DNS&#xff08;Domain Name System&#xff0c;域名系统&#xff09;协议&#xff0c;是一个用来将域名转化为IP地址的应用层协议。 为什么有这个协…

W801学习笔记十二:掌机进阶V3版本之驱动(PSRAM/SD卡)

本次升级添加了两个模块&#xff0c;现在要把他们驱动起来。 一&#xff1a;PSRAM 使用SDK自带的驱动&#xff0c;我们只需要写一个初始化函数&#xff0c;并在其中添加一些自检代码。 void psram_heap_init(){wm_psram_config(0);//实际使用的psram管脚选择0或者1&#xff…

基于Linux系统命令行安装KingbaseES数据库

人大金仓通用性数据库&#xff08;Kingbase&#xff09;下载网址&#xff1a;人大金仓-成为世界卓越的数据库产品与服务提供商 选择“软件版本-数据库”&#xff0c;筛选条件Linux、完整版。找到需要的版本&#xff0c;点击下载。我下载的是KingbaseES_V008R006C008B0014_Lin6…