Mamba复现与代码解读

文章目录

  • 环境配置
  • demo推理
  • 源码解析
    • 参数解读
    • Mamba块(Mamba Block)
      • 状态空间模型(SSM)
      • 选择性扫描算法(selective_scan)
      • 前向传播(forward)
    • 均方根归一化 (RMSNorm)
    • 残差块(ResidualBlock)
    • Mamba架构

🐍 在阅读代码前,建议先去了解下Mamba的原理~ Mamba 基础讲解【SSM,LSSL,S4,S5,Mamba】

环境配置

环境说明

Linux
cuda 11.8
torch==2.1.1 
torchvision==0.16.1
causal-conv1d==1.1.1
mamba-ssm==1.1.1

查看gcc版本(要保证gcc版本不得低于9)
在这里插入图片描述


创建一个名为mamba的虚拟环境

conda create -n mamba python=3.10.13
conda activate mamba

安装cudatoolkit

conda install cudatoolkit==11.8 -c nvidia

在这里插入图片描述
安装pytorch和torchvision

pip install torch==2.1.1 torchvision==0.16.1 torchaudio==2.1.1 --index-url https://download.pytorch.org/whl/cu118

在这里插入图片描述

conda install -c "nvidia/label/cuda-11.8.0" cuda-nvcc

在这里插入图片描述

conda install packaging

在这里插入图片描述
安装conv1d和mamba-ssm

pip install causal-conv1d==1.1.1
pip install mamba-ssm==1.1.1

这里的conv1d 和mamba-ssm的版本一定要对应上,不然会报错。

demo推理

  • 安装Transformers

方法1:直接git后安装

pip install git+https://github.com/huggingface/transformers@main

方法2:从源码安装
从官网上下载https://github.com/huggingface/transformers到本地,解压后,进入到主目录中,然后输入如下命令

pip install -v -e .

方法3: pip安装

pip install transformers
  • 下载mamba的权重文件

Mamba 预训练权重下载地址:Mama- Pretrained models on Hugging Face
在这里插入图片描述
将上面红框中的文件下载后放入到一个文件夹中,文件名为mamba-130m-hf

  • 测试demo
    新建一个demo.py文件内容如下:
from transformers import MambaConfig, MambaForCausalLM, AutoTokenizer
import torch
path="./path/to/mamba-130m-hf" # 修改这里的路径
# 加载模型
tokenizer = AutoTokenizer.from_pretrained(path,local_files_only=True)
model = MambaForCausalLM.from_pretrained(path,local_files_only=True)
input_ids = tokenizer("Hey how are you doing?", return_tensors="pt")["input_ids"]
# 生成输出结果
out = model.generate(input_ids, max_new_tokens=10)
print(tokenizer.batch_decode(out))

然后运行demo.py, 得到如下输出结果。
在这里插入图片描述

源码解析

这里讲解的是github上的一个关于mamba最小实现的仓库,重点在于理解Mamba架构的实现。https://github.com/johnma2006/mamba-minimal

参数解读

  • b: 批量大小(batch size), 对应Mamba论文中algorithm 2中的B
  • l : 序列长度,对应Mamba论文中algorithm 2中的L
  • d或者d_model: 隐藏层的维度大小
  • n或者d_state: 状态维度,对应Mamba论文中algorithm 2中的N
  • expand : 扩张系数,Mamba论文3.4节的E
  • d_in或者d_inner : d*expand, 对应Mamba论文中algorithm 2中的D
  • A,B,C,D对应的是状态空间模型的参数。其中B,C是依赖于输入的,A,D并不是。
  • Δ 或者 delta : 依赖于输入的时间步长。
  • dt_rank: Δ的秩,对应Mamba论文中3.6节的“parameterization of Δ”

在这里插入图片描述

Mamba块(Mamba Block)

状态空间模型(SSM)


代码解析: ssm模型实现了Algorithm 2的整个步骤。其中第5,6步调用的是selective_scan函数实现的选择性扫描算法。

    def ssm(self, x):"""Runs the SSM. See:- Algorithm 2 in Section 3.2 in the Mamba paper [1]- run_SSM(A, B, C, u) in The Annotated S4 [2]Args:x: shape (b, l, d_in)Returns:output: shape (b, l, d_in)Official Implementation:mamba_inner_ref(), https://github.com/state-spaces/mamba/blob/main/mamba_ssm/ops/selective_scan_interface.py#L311"""(d_in, n) = self.A_log.shape# Compute ∆ A B C D, the state space parameters.#     A, D 是独立于输入的 (see Mamba paper [1] Section 3.5.2 "Interpretation of A" for why A isn't selective)#     ∆, B, C 是依赖于输入的 (这是Mamba模型和 linear time invariant S4 的主要区别,这也是为什么Mamba被称为selective state spacesA = -torch.exp(self.A_log.float())  # shape (d_in, n)D = self.D.float() # (d_in,)x_dbl = self.x_proj(x)  # (b, l, dt_rank + 2*n)   (delta, B, C) = x_dbl.split(split_size=[self.args.dt_rank, n, n], dim=-1)# delta: (b, l, dt_rank) # B, C: (b, l, n)  delta = F.softplus(self.dt_proj(delta))  # (b, l, d_in)y = self.selective_scan(x, delta, A, B, C, D)  # 选择性扫描算法return y

delta = F.softplus(self.dt_proj(delta))参考论文中描述的:
在这里插入图片描述
Δ \Delta Δ 在SSM中的作用,类似于RNN中的门控机制。

选择性扫描算法(selective_scan)


Selective SSM 原理介绍
下图是Mamba论文中的算法介绍:
上图中算法的核心是第5步和第6步:

  • 第5步是对连续的矩阵A,B进行离散化得到离散化后的矩阵 A ˉ \bar A Aˉ B ˉ \bar B Bˉ, 离散化的方法有欧拉方法和零阶保持(Zero-order hold, ZOH)方法。
    下面的公式是ZOH算法:
    A ˉ = exp ⁡ ( Δ A ) B ˉ = ( Δ A ) − 1 ( exp ⁡ ( Δ A ) − I ) ⋅ Δ B \bar{A}=\exp (\Delta A) \quad \bar{B}=(\Delta A)^{-1}(\exp (\Delta A)-I) \cdot \Delta B Aˉ=exp(ΔA)Bˉ=(ΔA)1(exp(ΔA)I)ΔB

  • 第6步是对离散化后的矩阵 A ˉ \bar A Aˉ B ˉ \bar B Bˉ以及C执行SSM算法,其中离散的SSM方程如下
    x ( t + 1 ) = A ˉ x ( t ) + B ˉ u ( t ) y ( t ) = C x ( t ) + D u ( t ) x(t + 1) = \bar A x(t) + \bar B u(t) \\ y(t) = Cx(t) + Du(t) x(t+1)=Aˉx(t)+Bˉu(t)y(t)=Cx(t)+Du(t)
    其中 x x x表示的隐藏状态, u u u表示的输入, y y y表示的是输出。


selective_scan代码解析
下面的算法主要实现的就是Algorithm2中的第5步和第六步。
在第五步中,代码中采用ZOH对矩阵A进行离散化,但是作者并没有采用ZOH对B进行离散化,而是采用了一种更简化的方式(因为主要的参数是A, 对B进行简化并不会影响实验的性能)
在第六步中,代码中使用for循环的方式执行SSM, 主要是为了说明SSM的核心功能,其并行扫描算法可以参见源码(https://github.com/state-spaces/mamba/blob/main/mamba_ssm/ops/selective_scan_interface.py#L86)

    def selective_scan(self, u, delta, A, B, C, D):'''    Args:u: shape (b, l, d_in)    输入x,(B,L,D)delta: shape (b, l, d_in)  离散步长,(B,L,D)A: shape (d_in, n)  连续的矩阵A,(D,N)B: shape (b, l, n)  连续的矩阵B(B,L,N)C: shape (b, l, n)  (B,L,N)D: shape (d_in,)    (D,)Returns:output: shape (b, l, d_in)   输出:(B,L,D)官方实现版本:selective_scan_ref(), https://github.com/state-spaces/mamba/blob/main/mamba_ssm/ops/selective_scan_interface.py#L86Note: I refactored some parts out of `selective_scan_ref` out, so the functionality doesn't match exactly.'''      (b, l, d_in) = u.shape #(B,L,D)n = A.shape[1] # N'''对连续的参数(A, B)进行离散化A 使用零阶保持法(zero-order hold, ZOH)进行离散化 (see Section 2 Equation 4 in the Mamba paper [1])B 则使用一种简化的Euler方法进行离散化B没有使用ZOH的原因,作者解释如下: "A is the more important term and the performance doesn't change much with the simplification on B"'''# einsum 操作实际上是将 delta 和 A 张量的最后两个维度进行矩阵乘法,并在前面添加了两个维度(b 和 l)# torch.exp 函数对这个张量中的每个元素进行指数化,即将每个元素取指数值。deltaA = torch.exp(einsum(delta, A, 'b l d_in, d_in n -> b l d_in n'))   # (B,L,D) * (D,N) -> (B,L,D,N)# 将 delta、B 和 u 张量的对应位置元素相乘,并在最后一个维度上进行求和,输出一个新的张量。deltaB_u = einsum(delta, B, u, 'b l d_in, b l n, b l d_in -> b l d_in n')  # (B,L,D)*(B,L,N)*(B,L,D)->(B,L,D,N)'''执行 selective scan (see scan_SSM() in The Annotated S4 [2])# 注意,下面的代码是顺序执行的, 然而在官方代码中使用更快的并行扫描算法实现的(类似于FlashAttention,采用硬件感知扫描)。'''x = torch.zeros((b, d_in, n), device=deltaA.device)ys = []    for i in range(l):  # 这里使用for循环的方式只用来说明核心的逻辑,原代码中采用并行扫描算法x = deltaA[:, i] * x + deltaB_u[:, i] # x(t + 1) = Ax(t) + Bu(t)y = einsum(x, C[:, i, :], 'b d_in n, b n -> b d_in') # y(t) = Cx(t)  (B,D,N)*(B,N)->(B,D) ys.append(y)y = torch.stack(ys, dim=1)  # 大小 (b, l, d_in)  (B,L,D)y = y + u * D # y(t) = Cx(t)+Du(t)return y #(B,L,D)

前向传播(forward)


代码解析
在这里插入图片描述
这段代码实现的就是上图的架构。

    def forward(self, x):"""Mamba block forward. This looks the same as Figure 3 in Section 3.4 in the Mamba paper [1].Args:x: shape (b, l, d)    Returns:output: shape (b, l, d)  Official Implementation:class Mamba, https://github.com/state-spaces/mamba/blob/main/mamba_ssm/modules/mamba_simple.py#L119mamba_inner_ref(), https://github.com/state-spaces/mamba/blob/main/mamba_ssm/ops/selective_scan_interface.py#L311"""(b, l, d) = x.shape # shape (b,l,d)x_and_res = self.in_proj(x)  # shape (b, l, 2 * d_in)(x, res) = x_and_res.split(split_size=[self.args.d_inner, self.args.d_inner], dim=-1)# x: (b,l,d_in), res: (b,l,d_in)x = rearrange(x, 'b l d_in -> b d_in l')  # shape (b,l,d_in)->(b,d_in,l)x = self.conv1d(x)[:, :, :l]     # (b,d_in,l)x = rearrange(x, 'b d_in l -> b l d_in') # (b,d_in,l)->(b,l,d_in)x = F.silu(x) # (b,l,d_in)y = self.ssm(x) # (b,l,d_in)y = y * F.silu(res) # (b,l,d_in)output = self.out_proj(y) # (b,l,d_in)-> (b,l,d)return output # (b,l,d)

均方根归一化 (RMSNorm)


RMS Normalization 简介
RMS(Root Mean Square)Normalization(均方根归一化)是一种用于神经网络中的归一化技术,旨在将输入数据的分布调整为更适合训练的状态。它与 Batch Normalization(批归一化)和 Layer Normalization(层归一化)等技术类似,但有一些独特之处。

对于输入张量 X X X 的形状为 ( B , L , D (B, L, D (B,L,D ),其中 B B B 是批量大小 (batch size), L L L 是序列长度, D D D是每个样本的特征维度。RMS归一化的过程如下:

  1. 计算每个样本的均方根值:
    RMS ⁡ ( X b , i ) = 1 D ∑ d = 1 D X b , i , d 2 \operatorname{RMS}\left(X_{b, i}\right)=\sqrt{\frac{1}{D} \sum_{d=1}^D X_{b, i, d}^2} RMS(Xb,i)=D1d=1DXb,i,d2

其中, X b , i X_{b, i} Xb,i 表示输入张量的第 b b b 个样本中的第 i i i 个样本, X b , i , d X_{b, i, d} Xb,i,d 表示该样本的第 d d d 个特征值。

  1. 对每个样本进行归一化:
    RMS ⁡ _ Norm ⁡ ( X b , i ) = X b , i RMS ⁡ ( X b , i ) \operatorname{RMS} \_\operatorname{Norm}\left(X_{b, i}\right)=\frac{X_{b, i}}{\operatorname{RMS}\left(X_{b, i}\right)} RMS_Norm(Xb,i)=RMS(Xb,i)Xb,i
    这里将每个特征值除以其所在样本的均方根值, 从而使得每个样本的均方根值归一化后为 1 。

RMS归一化的优点包括:

  • 适用于小批量数据: RMS归一化对于小批量数据或数据量较少的情况更为适用,因为它只关注单个样本的统计信息。
  • 适用于变长序列: 由于RMS归一化是对每个样本进行归一化,因此对于变长序列的处理更加简便。

RMS归一化也有一些局限性,例如在某些情况下可能会导致梯度爆炸或消失问题,并且对于较大的数据集可能不如Batch Normalization效果好。因此,选择归一化技术时需要根据具体情况进行权衡和选择。


RMSNorm代码解析
RMS归一化的过程如下:

  • 对于输入张量 x x x,首先计算其每个样本在最后一个维度(通常是特征维度)上的平方: x 2 x^2 x2
  • 然后计算每个样本在最后一个维度上的平均值: x 2 . m e a n ( − 1 , k e e p d i m = T r u e ) x^2.mean(-1, keepdim=True) x2.mean(1,keepdim=True)。这里的-1表示最后一个维度,keepdim=True表示保持维度不变。
  • 加上一个很小的常数 ϵ \epsilon ϵ,以防止除以零: x 2 . m e a n ( − 1 , k e e p d i m = T r u e ) + ϵ x^2.mean(-1, keepdim=True) + \epsilon x2.mean(1,keepdim=True)+ϵ
  • x x x除以上述结果的平方根,得到归一化的系数: t o r c h . r s q r t ( x 2 . m e a n ( − 1 , k e e p d i m = T r u e ) + ϵ ) torch.rsqrt(x^2.mean(-1, keepdim=True) + \epsilon) torch.rsqrt(x2.mean(1,keepdim=True)+ϵ)
  • 最后乘以可学习的权重weight,得到最终的归一化结果。
class RMSNorm(nn.Module):'''均方根归一化: RMS normalization'''def __init__(self,d_model: int, # hidden dimeps: float = 1e-5): # 防止除以零的小数值super().__init__()self.eps = eps# weight: 可学习的参数,调整归一化后的值self.weight = nn.Parameter(torch.ones(d_model)) # 初始值为大小为d_model的张量,每个元素的值都是1def forward(self, x):''':param x: 输入张量:return: output 均方根规划化后的值RMS的计算步骤:Step1: 计算每个样本的均方根值Step1.1: 先计算x的平方Step1.2: 沿着最后一个维度(通常是特征维度)计算平均值,并加上一个很小的数epsStep1.3: 最后取平方根Step2: 对每个样本进行归一化Step2.1:每个特征值除以其所在样本的均方根值Step2.2: 最后乘以可以学习的权重weight,得到最终的输出'''output = x * torch.rsqrt(x.pow(2).mean(-1, keepdim=True) + self.eps) * self.weightreturn output

残差块(ResidualBlock)


ResidualBlock代码解析
为Mamba Block 添加 normalization 和 残差连接 (下图红框中的部分)

在这里插入图片描述

class ResidualBlock(nn.Module):def __init__(self, args: ModelArgs):"""Simple block wrapping Mamba block with normalization and residual connection."""super().__init__()self.args = argsself.mixer = MambaBlock(args) # Mamba块self.norm = RMSNorm(args.d_model) # RMS归一化    def forward(self, x):"""Args:x: shape (b, l, d)    (batch size, sequence length, hidden dim)Returns:output: shape (b, l, d)  (batch size, sequence length, hidden dim)    """output = self.mixer(self.norm(x)) + x # [Norm -> Mamba -> Add]  return output

Mamba架构

在这里插入图片描述
下面的代码主要是实现的就是上图中红框标注出的部分

class Mamba(nn.Module):def __init__(self, args: ModelArgs):"""Full Mamba model."""super().__init__()self.args = argsself.embedding = nn.Embedding(args.vocab_size, args.d_model) # 词嵌入,其中包含 `args.vocab_size` 个不同的词或标记,每个词嵌入的维度为 `args.d_model`self.layers = nn.ModuleList([ResidualBlock(args) for _ in range(args.n_layer)])# n_layer个ResidualBlockself.norm_f = RMSNorm(args.d_model) #RMS归一化self.lm_head = nn.Linear(args.d_model, args.vocab_size, bias=False)self.lm_head.weight = self.embedding.weight  # Tie output projection to embedding weights.# See "Weight Tying" paperdef forward(self, input_ids):"""Args:input_ids (long tensor): shape (b, l)Returns:logits: shape (b, l, vocab_size)Official Implementation:class MambaLMHeadModel, https://github.com/state-spaces/mamba/blob/main/mamba_ssm/models/mixer_seq_simple.py#L173"""x = self.embedding(input_ids) # (b,l,d)  生成词嵌入for layer in self.layers:   # 通过n_layer个ResidualBlockx = layer(x)   # (b,l,d)x = self.norm_f(x) # (b,l,d)logits = self.lm_head(x) # (b,l,vocab_size)return logits

其中,nn.Embedding(args.vocab_size, args.d_model) 创建了一个词嵌入层,其中包含 args.vocab_size 个不同的词或标记,每个词嵌入的维度为 args.d_model。这意味着每个词或标记将被表示为一个长度为 args.d_model 的向量。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

集成学习 | 集成学习思想:Boosting

目录 一. Boosting思想1. Adaboost 算法1.1 Adaboost算法构建流程1.2 sklearn库参数说明 2. Gradient Boosting 算法2.1 Gradient Boosting算法构建流程2.2 Gradient Boosting算法的回归与分类问题2.2.1 Gradient Boosting回归算法均方差损失函数绝对误差损失函数 2.2.2 Gradie…

CAS(Compare-And-Swap)机制介绍

一、概念介绍 CAS(Compare-And-Swap)机制在C中是一种用于实现并发编程中同步和互斥的重要技术。CAS机制提供了一种原子操作,允许程序在不使用锁的情况下对共享变量进行读取、修改和写入。这种机制的核心思想是先比较再设置,即在修…

理论学习:ground-truth labels在深度学习中是什么意思

在深度学习中,"ground-truth labels"(真值标签)是指数据集中每个样本的正确答案或真实状态。这些标签是由人类专家提供的,代表了我们希望模型学习预测的准确结果。在训练深度学习模型时,真值标签被用作参照点…

【Linux】进程地址空间详解

前言 在我们学习C语言或者C时肯定都听过老师讲过地址的概念而且老师肯定还会讲栈区、堆区等区域的概念,那么这个地址是指的物理内存地址吗?这里这些区域又是如何划分的呢? 我们在使用C语言的malloc或者C的new函数开辟空间时,开辟…

Median of an Array(贪心策略,编程技巧)

文章目录 题目描述输入格式输出格式样例输入样例输出提交链接提示 解析参考代码 题目描述 给你一个由 n n n 个整数组成的数组 a a a 。 数组 q 1 , q 2 , … , q k q_1,q_2,…,q_k q1​,q2​,…,qk​ 的中位数是 p ⌈ k 2 ⌉ p⌈\frac {k}{2}⌉ p⌈2k​⌉ ,其…

可解释性AI(XAI)

可解释性AI(XAI)旨在提高人工智能系统的透明度和可理解性,使人们更好地理解AI的决策过程和原理。随着AI技术的广泛应用,XAI成为了一个备受关注的重要领域。它不仅有助于建立人们对AI的信任,还可以帮助解决AI伦理和偏见…

解锁隐私计算力量:一站式掌握SecretFlow安装与双模式部署实践

1.SecretFlow的安装 1.SecretFlow运行要求 SecretFlow作为一个隐私保护的数据分析和机器学习框架,其运行要求可能涉及以下方面: 操作系统: 能够支持Docker运行的环境,因为SecretFlow可能通过Docker容器来管理执行环境的一致性和…

Python Flask 自定义404错误

from flask import Flask, abort, make_response, request, render_templateapp Flask(__name__)# 重定向到百度 app.route(/index, methods["GET", "POST"]) def index():if request.method "GET":return render_template("index.html&q…

敏捷开发最佳实践:组织架构实践案例之构建软硬件融合部落

本节所选案例对于软硬件均有的企业具有重要借鉴意义,通过学习某一线制造行业合资企业如何解决软硬件部门之间的技术鸿沟和部门墙,以及全球分布的多支敏捷团队的协作难题,为所在企业在“组织架构”层面进行有效敏捷实践打开思路。 本实践节选…

推荐一款制造执行系统(MES)国内比较好的实施厂家

什么是MES 制造执行系统(MES)是一种用于监控、控制和优化制造过程的软件系统。它通过与企业资源计划(ERP)系统和自动化系统的集成,实现对生产过程的管理和监测,包括生产计划、生产过程和生产数据。 MES可…

小白入门赛8

小白入门赛8 1 #include<bits/stdc.h> using namespace std;int main(){puts("5060");return 0; } 2 只考虑两个字符串a&#xff0c;b的情况下&#xff0c;优先让 a b ab ab 或 b a ba ba 中最小的放前面&#xff0c;据此排序 int n; string s[200010]…

BUG未解之谜01-指针引用之谜

在leetcode里面刷题出现的问题&#xff0c;当我在sortedArrayToBST里面给root赋予初始值NULL之后&#xff0c;问题得到解决&#xff01; 理论上root是未初始化的变量&#xff0c;然后我进入insert函数之后&#xff0c;root引用的内容也是未知值&#xff0c;因此无法给原来的二叉…

鸿蒙开发学习【地图位置服务组件】

简介 移动终端设备已经深入人们日常生活的方方面面&#xff0c;如查看所在城市的天气、新闻轶事、出行打车、旅行导航、运动记录。这些习以为常的活动&#xff0c;都离不开定位用户终端设备的位置。 当用户处于这些丰富的使用场景中时&#xff0c;系统的位置定位能力可以提供…

map 添加 访问 遍历

#include<iostream> #include<vector> #include<set> #include<map> using namespace std; int main() { //创建 map<string, int>m; //添加 m["hello"] 2; m["ijii"] 1; //访问 如果存在返回值,不…

[HackMyVM]靶场 Submissions

kali:192.168.56.104 靶机:192.168.56.131 端口扫描 # nmap 192.168.56.131 Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-03-24 11:32 CST Nmap scan report for 192.168.56.131 Host is up (…

【Python】基础语法(一)

文章目录 1.注释2.关键字与标识符2.1关键字2.2标识符 3.变量4.数据类型4.1数字类型4.2类型转换函数4.3布尔类型 5.输入(input)与输出(print)5.1输入函数(input)5.2输出函数(print) 6.运算符6.1算术运算符6.2比较运算符6.3赋值运算符6.4逻辑运算符6.5运算符优先级 7.字符串7.1字…

JMH微基准测试框架学习笔记

一、简介 JMH&#xff08;Java Microbenchmark Harness&#xff09;是一个用于编写、构建和运行Java微基准测试的框架。它提供了丰富的注解和工具&#xff0c;用于精确控制测试的执行和结果测量&#xff0c;从而帮助我们深入了解代码的性能特性。 二、案例实战 在你的pom文件…

MySQL 排序的那些事儿

书接上回 上次发了几张图&#xff0c;给了几个MySQL Explain的场景&#xff0c;链接在这儿&#xff1a;你是不是MySQL老司机&#xff1f;来看看这些explain结果你能解释吗&#xff1f;MySQL 夺命6连问 我们依次来分析下这6个问题。 在分析之前&#xff0c;我们先来了解一下M…

【C++】学习记录--condition_variable 的使用

condition_variable使用步骤如下&#xff1a;创建一个condition_variable对象创建一个互斥锁mutex对象&#xff0c;用来保护共享资源的访问在需要等待条件变量的地方&#xff0c;使用unique_lock<mutec>对象锁定互斥锁并调用condition_variable::wait()、condition_varia…

大模型: 提示词工程(prompt engineering)

文章目录 一、什么是提示词工程二、提示词应用1、提示技巧一&#xff1a;表达清晰2、提示词技巧2&#xff1a;设置角色 一、什么是提示词工程 提示词工程主要是用于优化与大模型交互的提示或查询操作&#xff0c;其目的在于能够更加准确的获取提问者想要获取的答案&#xff0c…