使用 MinIO、Langchain 和 Ray Data 构建分布式嵌入式子系统

news2024/11/22 7:10:46

嵌入子系统是实现检索增强生成所需的四个子系统之一。它将您的自定义语料库转换为可以搜索语义含义的向量数据库。其他子系统是用于创建自定义语料库的数据管道,用于查询向量数据库以向用户查询添加更多上下文的检索器,最后是托管大型语言模型 (LLM) 的服务子系统,并将根据用户的查询和在向量数据库中找到的上下文生成答案。下图显示了这四个子系统在检索增强生成过程中如何协同工作。

在这篇文章中,我想重点介绍嵌入子系统。在此子系统中,构成组织自定义语料库的文档从其原始格式转换为文本,分解为较小的块,然后为每个块创建一个嵌入(这是一个向量,通常具有数百个维度)。创建嵌入后,原始块和向量都将存储在向量数据库中。 嵌入子系统在概念上易于理解,并且实现嵌入简单文本文件的简单脚本非常简单。但是,如果您必须为您的组织实施嵌入子系统,那么您如何为您的组织做出正确的设计决策,以及您如何应对不断增长的需求带来的复杂性?下面列出了一些设计决策和实际复杂性:

  • 如何高效地运行多个实验来测试不同的配置选项?

  • 如何处理文档中的表格和图像?

  • 如何将嵌入子系统部署到生产环境中?

  • 如何处理需要嵌入的大量文档?

  • 什么是最好的载体数据库?

  • 文档、嵌入模型和LLMs的最佳存储选项是什么?

解决这些问题的第一步是使用能够在工程工作站以及生产环境中运行的现代工具。具体来说,我们将使用 MinIO 进行所有存储,使用 Langchain 作为低代码解决方案来进行文档解析(我还将提供一些比 Langchain 更好地处理图像和表的选项),并使用 Ray Data 将分块和嵌入函数分发到集群中。毫不奇怪,分布式技术是我们解决方案的基础。您不仅可以使用商用硬件设置进行并行处理来获得高吞吐量,而且该解决方案是云原生的,使其可以跨云移植,并且还能够在本地运行。让我们从为我们的实验设置一个自定义语料库开始。

在 MinIO 中设置自定义语料库

如上所述,自定义语料库由数据管道创建,该数据管道将可能位于组织中多个门户的文档聚合到 MinIO 中。创建文档管道是另一篇文章的主题 - 所以现在,我们将手动将一些文档暂存到 MinIO 桶中。我在这里也只会使用文本文档来保持简单。但是,这里有一些处理文档中多种文件格式和非文本的提示。首先,查看 Unstructured 的库,用于分区、清理和提取。其次,如果您专门处理 PDF,请查看 Open-Parse 库。我们在之前的博客文章《使用 Open-Parse 智能分块提高 RAG 性能》中介绍了 Open-Parse。下面的屏幕截图显示了我们的自定义语料库。我从古腾堡计划中下载了四本被认为是经典的流行书籍的文本版本。

  • 人性论——大卫·休谟

  • 孙子兵法 - 孙子

  • 杰基尔博士和海德先生的奇案 - 罗伯特·路易斯·史蒂文森

  • 《海底两万里》——儒勒·凡尔纳

现在我们有了一个自定义语料库,我们可以设置一个向量数据库来保存嵌入。

设置 MinIO 和矢量数据库

我将使用的向量数据库是 Pgvector。Pgvector 是 PostgreSQL 的开源扩展,允许用户在数据库中存储、搜索和分析矢量数据。这篇文章的代码下载有一个 docker-compose 文件,其中包含 MinIO、Pgvector 和 pgAdmin。在与 docker-compose fill 相同的目录中运行以下命令会将这三个服务作为容器显示出来。

docker-compose up -d

还有一个init.sql文件(如下所示)。docker-compose 文件将此文件映射到容器的启动目录。这会导致文件中的 SQL 运行,从而在 Postgres 中创建向量扩展和一个“嵌入”表,其中包含下面 SQL 文件中显示的字段。

CREATE EXTENSION IF NOT EXISTS vector;

CREATE TABLE IF NOT EXISTS embeddings (
 id SERIAL PRIMARY KEY,
 embedding vector,
 text text,
 created_at timestamptz DEFAULT now()
);

将嵌入模型保存到 MinIO

我们将使用的嵌入模型是 Hugging Face 的开源模型。详细信息如下所示。在运行实验时指定特定版本始终是一个好主意。模型名称:intfloat/multilingual-e5-small修订版:ffdcc22a9a5c973ef0470385cef91e1ecb461d9f

不要被模型的名字所迷惑。它一点也不小。它是 1.4GB。我们需要下载这个模型并上传到 MinIO。这是一项一次性设置任务,用于在分布式环境中暂存此模型以进行实验。遗憾的是,我们需要的 Hugging Face 函数(snapshot_download)没有 S3 接口,所以我们会使用 MinIO Python SDK 将模型上传到 MinIO。更复杂的是,Hugging Face 模型不是单个文件。它是下载到指定目录中的文件集合。我们必须将整个目录上传到 MinIO,并使用 MinIO 路径保留文件夹结构。这是使用如下所示的“upload_model_to_minio”函数完成的。

from huggingface_hub import snapshot_download

def upload_model_to_minio(bucket_name: str, full_model_name: str, revision: str) -> None:
   '''
   Download a model from Hugging Face and upload it to MinIO. This function will use
   the current systems temp directory to temporarily save the model.
   '
''

   # Create a local directory for the model.
   #home = str(Path.home())
   temp_dir = tempfile.gettempdir()
   base_path = f'{temp_dir}{os.sep}hf-models'
   os.makedirs(base_path, exist_ok=True)

   # Get the user name and the model name.
   tmp = full_model_name.split('/')
   user_name = tmp[0]
   model_name = tmp[1]

   # The snapshot_download will use this pattern for the path name.
   model_path_name=f'models--{user_name}--{model_name}'
   # The full path on the local drive.
   full_model_local_path = base_path + os.sep + model_path_name + os.sep + 'snapshots' + 
                           os.sep + revision
   # The path used by MinIO.
   full_model_object_path = model_path_name + '/snapshots/' + revision

   print(f'Starting download from HF to {full_model_local_path}.')
   snapshot_download(repo_id=full_model_name, revision=revision, cache_dir=base_path)

   print('Uploading to MinIO.')
   upload_local_directory_to_minio(full_model_local_path, bucket_name, 
                                   full_model_object_path)
   shutil.rmtree(full_model_local_path)

运行以下命令将使用此函数将我们的模型上传到名为“hf-models”的存储桶中。

MODELS_BUCKET = 'hf-models'
EMBEDDING_MODEL = 'intfloat/multilingual-e5-small'
EMBEDDING_MODEL_REVISION = 'ffdcc22a9a5c973ef0470385cef91e1ecb461d9f'

upload_model_to_minio(MODELS_BUCKET, EMBEDDING_MODEL, EMBEDDING_MODEL_REVISION)

嵌入函数库

当你使用像 Ray Data 这样的库来分发数据处理时——在本例中是文本的分块和每个块的嵌入生成——你真正要做的就是编排简单的函数调用,这些函数调用在此过程中执行一项任务。下面列出了从 MinIO 存储桶中的文档列表创建嵌入所需的所有函数,以及它们的参数和返回值。如您所见,我们拥有嵌入文档集合所需的一切。

create_logger() -> logging.Logger

创建一个 Python 记录器,用于将调试、信息、错误、警告和关键消息发送到日志记录存储库。

download_model_from_minio(bucket_name: str, full_model_name: str, revision: str) -> str

将模型从 MinIO 下载到当前系统临时目录。一旦它被加载到内存中,它将删除它。

get_document_from_minio(bucket_name: str, object_name: str) -> str:

从 MinIO 下载单个文档,并将其保存到当前系统临时目录中。

get_object_list(bucket_name: str) -> List[str]:

返回指定存储桶中的对象列表。此列表将发送到 Ray Data,后者将其均匀分布在集群中的所有 Ray actor 中。

save_embeddings_to_vectordb(chunks, embeddings) -> None:

将嵌入和文本块一起保存到向量数据库中。

upload_local_directory_to_minio(local_path:str, bucket_name:str , minio_path:str) -> None

将指定本地目录的内容上传到 MinIO,将文件夹结构保留为指定存储桶内的路径。

upload_model_to_minio(bucket_name: str, full_model_name: str, revision: str) -> None:

从Hugging Face下载模型到当前系统临时目录,然后将模型上传到指定的Bucket,同时保留文件夹结构作为指定Bucket内的路径。

一个简单的嵌入子系统

让我们使用上述函数并创建一个简单的非分布式脚本。下面的代码将为 Robert Louis Stevenson 的“The Strange Case of Dr Jekyll and Mr Hyde”创建嵌入。首先,我们需要下载我们希望使用的嵌入模型,并将其保存到 MinIO 中。这是一项一次性任务;您无需在每次想要嵌入新一批模型或运行实验时都这样做。

MODELS_BUCKET = 'hf-models'
EMBEDDING_MODEL = 'intfloat/multilingual-e5-small' # Embedding model to use for converting text chunks to vector embeddings.
EMBEDDING_MODEL_REVISION = 'ffdcc22a9a5c973ef0470385cef91e1ecb461d9f'

eu.upload_model_to_minio(MODELS_BUCKET, EMBEDDING_MODEL, EMBEDDING_MODEL_REVISION)

接下来,我们需要从 MinIO 下载我们的模型,实例化它,创建一个分块器(或拆分器),创建嵌入并将它们保存到我们的 pgvector 数据库中。

CHUNK_SIZE = 1000         # Text chunk sizes which will be converted to vector embeddings
CHUNK_OVERLAP = 10
DIMENSION = 384           # Embeddings size

model_path = eu.download_model_from_minio(MODELS_BUCKET, EMBEDDING_MODEL, 

                                          EMBEDDING_MODEL_REVISION)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
embedding_model = SentenceTransformer(model_path, device=device)
chunker = RecursiveCharacterTextSplitter(chunk_size=CHUNK_SIZE, 

                                         chunk_overlap=CHUNK_OVERLAP, length_function=len)

temp_file = eu.get_document_from_minio(BUCKET_NAME, 

                                       'The Strange Case of Dr Jekyll and Mr Hyde.txt')
file = open(temp_file, 'r')
data = file.read()
chunks = chunker.split_text(data)
print('Number of chunks:', len(chunks))
print('Length of the first chunk:', len(chunks[0]))

embeddings = embedding_model.encode(chunks, batch_size=BATCH_SIZE).tolist()
print('Number of embeddings:', len(embeddings))
print('Length of the first embedding:', len(embeddings[0]))

eu.save_embeddings_to_vectordb(chunks, embeddings)

请注意,如果我们可以访问 GPU,则我们正在使用 GPU。此外,一切都是配置驱动的,因此运行不同的实验就是更改配置以反映您希望运行的实验的问题。这包括根据需要更改嵌入模型。

下面是 pgAdmin 的屏幕截图,显示了我们新创建的嵌入。

现在我们有了一个简单的脚本,可以为单个文档创建嵌入,下一步是将此代码迁移到在集群中运行的框架。这将允许并行嵌入整个文档语料库。我们将使用 Ray Data 来执行此操作。

分发嵌入子系统

分发嵌入子系统的第一步是将所有工作放入一个行为类似于函数的类中。这是使用 Python 的“__call__”内置方法完成的。(这是光线数据的要求。我们的班级如下所示。

class Embed:

   def __init__(self):
       device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
      
       model_path = eu.download_model_from_minio(MODELS_BUCKET, EMBEDDING_MODEL, 

                                                 EMBEDDING_MODEL_REVISION)
       self.embedding_model = SentenceTransformer(model_path, device=device)
       self.splitter = RecursiveCharacterTextSplitter(chunk_size=CHUNK_SIZE, 

                                                      chunk_overlap=CHUNK_OVERLAP, 

                                                      length_function=len)

   def __call__(self, batch_list: List[str]) -> None:
       document_list = batch_list["item"]

       timings = []
       documents = []
       for document_data in document_list:
           start_time = time()
           bucket_name = document_data[0]
           object_name = document_data[1]
           temp_file = eu.get_document_from_minio(bucket_name, object_name)
           file = open(temp_file, 'r')
           data = file.read()

           chunks = self.splitter.split_text(data)
           embeddings = self.embedding_model.encode(chunks, batch_size=BATCH_SIZE).tolist()
           eu.save_embeddings_to_vectordb(chunks, embeddings)
          
           total_time_sec = time() - start_time
           documents.append(object_name)
           timings.append(total_time_sec)

       return {'timings': timings, 'documents': documents}

Ray Data 将为我们将很快创建的 Ray 集群中的每个 actor 实例化一次此类。此对象将保持活动状态,并接收多个批次进行处理。请注意,“__init__”函数正在下载我们的嵌入模型,并使用它创建一个 SentenceTransformer。SentenceTransformer 类使使用嵌入模型变得容易。此外,我们还使用 LangChain 的 RecursiveCharacterTextSplitter 来分割或分块我们的文档。它根据字符列表(我们使用其默认列表)递归拆分文本,从列表中的第一个字符开始,如果第一个拆分太大,则继续到下一个字符。目标是将相关的文本片段保持在一起,保留它们的语义关系。所有这些设置工作仅在创建 Embed 对象时发生一次。我们本可以使用一个简单的函数来分配工作,但是必须为每个批次完成此设置工作,当您要进行设置工作时,这不是正确的设计。

接下来,我们需要初始化 Ray 集群。


ray.init(
   #address="ray://ray-cluster-kuberay-head-svc:10001",
   runtime_env={
       "env_vars": {
           "MINIO_URL": MINIO_URL,
           "MINIO_ACCESS_KEY": MINIO_ACCESS_KEY,
           "MINIO_SECRET_KEY": MINIO_SECRET_KEY,
           "MINIO_SECURE": str(MINIO_SECURE),
           "PGVECTOR_HOST": os.environ['PGVECTOR_HOST'],
           "PGVECTOR_DATABASE": os.environ['PGVECTOR_DATABASE'],
           "PGVECTOR_USER": os.environ['PGVECTOR_USER'],
           "PGVECTOR_PASSWORD": os.environ['PGVECTOR_PASSWORD'],
           "PGVECTOR_PORT": os.environ['PGVECTOR_PORT'],
       },
       "pip": [              
           "datasets==2.19.0",
           "huggingface_hub==0.22.2",
           "minio==7.2.7",
           "psycopg2-binary==2.9.9",
           "pyarrow==16.0.0",
           "sentence-transformers==3.0.1",
           "torch==2.3.0",
           "transformers==4.40.1",
       ]
   }
)

在我们的演示中,我们将创建一个本地 Ray 实例。我没有使用 Kubernetes 集群。这是在移动到真实集群之前让代码正常工作的最佳方法。我们还没有创建任何 Ray actor - 但我们正在发送 Ray 配置信息,告诉 Ray 每个 actor 需要的环境变量和库。接下来,我们创建一个 Ray 数据集来保存我们想要发送到将在每个 Ray actor 中运行的 Embed 类实例的所有数据。在我们的例子中,每个 Ray actor 都将收到一个存储在 MinIO 中的对象引用列表(文档的路径)。我们将使用上述函数库中的“get_object_list”函数。从 “ray.data.from_items() 返回的 Ray 数据集包含的逻辑,当我们启动分布式嵌入过程时,该逻辑会将此列表转换为每个 actor 的较小批次。


# The embedding class expects bucket_name and document_name pairs - so add bucket name to each entry in the list.
document_list = eu.get_object_list(BUCKET_NAME)
list_for_ray = [[BUCKET_NAME, doc] for doc in document_list]

ray_ds = ray.data.from_items(list_for_ray)
print(type(ray_ds))
print(ray_ds.schema)

我们几乎已经准备好进行一些分布式计算,但我们还有一个编码任务要完成。我们需要将 Ray 数据集映射到我们的 Embed 类,并告诉 Ray 如何设置我们之前为此工作负载初始化的集群。这是使用 Ray 数据集的“map_batches”方法完成的。您可以将函数或可调用类发送到“map_batches”。如果发送函数,Ray Data 将使用无状态 Ray 任务。对于类,Ray Data 使用有状态的 Ray actor。

ds_embed = ray_ds.map_batches(
   Embed,
   concurrency=ACTOR_POOL_SIZE,
   batch_size=BATCH_SIZE,  # Large batch size to maximize GPU utilization.
   #num_gpus=1,            # 1 GPU for each actor.
   num_cpus=1,             # 1 CPU for each actor.
)

请注意,我们正在传入需要为每个 actor 实例化的 Embed 类。我们还指定了 actor 的数量、每次调用 actor 的批量大小,最后指定了每个 actor 可访问的 GPU 和 CPU 数量。map_batches 方法返回另一个 Ray 数据集 (ds_embed),其中包含所有 actor 的所有返回值。这是 Embedded 中“__call__”方法的返回值的集合。

最后,我们准备开始我们的分布式嵌入工作。您可能已经注意到,上一个命令运行得非常快。那是因为还没有进行任何计算。Ray 中的转换(map_batch被认为是转换)是“惰性”。在通过循环访问数据集、保存数据集或检查数据集的属性来触发数据使用之前,不会执行它们。因此,我们需要向ds_embed请求 actor 的返回值。这是在下面完成的。下面的代码片段需要一些时间才能运行。

def ray_data_task(ds_embed):
   results = []
   for row in ds_embed.iter_rows():
       documents = row['documents']
       timings = row['timings']
       results.append((documents, timings))
   return results

results = ray_data_task(ds_embed)

results


就是这样。大功告成。完成上述代码后,您将看到类似于下面显示的输出。

[('A Treatise of Human Nature.txt', 75.08733916282654),
 ('The Art of War.txt', 21.960258722305298),
 ('The Strange Case of Dr Jekyll and Mr Hyde.txt', 10.052802085876465),
 ('Twenty Thousand Leagues under the Sea.txt', 39.24100613594055)]

总结

在这篇文章中,我们构建了一个分布式嵌入子系统,可以在工程工作站和完全分布式的云原生生产环境中运行。所介绍的代码具有以下优点,可直接解决我们简介中确定的复杂性和实际问题。

  • 实验可以高效运行,从而可以对不同的配置选项进行彻底测试。

  • 除了配置选项之外,还应尝试使用解析选项。这将允许您处理多种文件类型并处理文档中的非文本数据。

  • 使用此处显示的代码时,您的生产环境将运行工程师用于测试和试验的相同代码。

  • 分布式嵌入子系统可以在集群中运行。集群可以快速扩展,以处理需要批量处理的大量文档,也可以针对实时工作负载进行扩展。

  • 本文中介绍的代码封装了向量数据库调用,使工程师可以交换不同的产品。

  • MinIO 是生成式 AI 的最佳存储解决方案。正如我们在这篇文章中看到的,嵌入模型和文档必须存储在高速、可扩展的存储解决方案中。

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

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

相关文章

Stream 33

package Array.collection;import java.util.*; import java.util.stream.Stream;public class stream1 {public static void main(String[] args) {//、如何茯取List集合的Stream流?List<String> names new ArrayList<>();Collections. addAll(names,"方法…

超声波眼镜清洗机哪个品牌好?四款高性能超声波清洗机测评剖析

对于追求高生活质量的用户来说&#xff0c;眼镜的清洁绝对不能马虎。如果不定期清洁眼镜&#xff0c;时间久了&#xff0c;镜片的缝隙中会积累大量的灰尘和细菌&#xff0c;眼镜靠近眼部&#xff0c;对眼部健康有很大影响。在这种情况下&#xff0c;超声波清洗机显得尤为重要。…

现象:程序没问题,compile成功,在load时,提示prg.dll没找到

现象:程序没问题&#xff0c;compile成功&#xff0c;在load时&#xff0c;提示prg.dll没找到 解决方法&#xff1a;使用新的ATE电脑主机&#xff0c;导致的问题&#xff0c;又换回原来的电脑主机&#xff0c;问题解决。

数据结构与算法--【链表1】力扣练习 || 链表 / 移除链表元素

声明&#xff1a;本文参考代码随想录。 一、链表定义 1、概念 将线性表L(a0,a1,……,an-1)中各元素分布在存储器的不同存储块&#xff0c;称为结点&#xff0c;通过地址或指针建立元素之间的联系。 每一个结点由两部分组成&#xff1a;数据域和指针域。结点的data域存放数据…

第三届Apache Flink 极客挑战赛暨AAIG CUP比赛攻略_大浪813团队

关联比赛: 第三届 Apache Flink 极客挑战赛暨AAIG CUP——电商推荐“抱大腿”攻击识别 第三届Apache Flink 极客挑战赛暨AAIG CUP比赛攻略_大浪813团队 第三届Apache Flink 极客挑战赛暨AAIG CUP 自2021年8月17日上线以来已有 4537 个参赛队伍报名。11月09号&#xff0c;大赛…

Android入门之路 - WebView加载数据的几种方式

之前客户端加载H5时遇到了一些问题&#xff0c;我为了方便解决问题&#xff0c;所以将对应场景复刻到了Demo中&#xff0c;从之前的网络加载模拟为了本地加载Html的方式&#xff0c;但是没想到无意被一个基础知识点卡了一些时间&#xff0c;翻看往昔笔记发现未曾记录这种基础场…

C语言初阶(10)

1.野指针 野指针就是指向未知空间的指针&#xff0c;有以下几种情况 &#xff08;1)指针未初始化 int main() {int a0;int*b;return 0; } 上面指针就是没有初始化&#xff0c;形成一种指向一个随机空间的地址的指针&#xff0c;我们可以修改成 int main() {int a0;int*bNU…

甘肃雀舌面:舌尖上的独特韵味

雀舌面&#xff0c;顾名思义&#xff0c;其面条形状如同雀舌般小巧精致。这一独特的形态并非偶然所得&#xff0c;而是源于精湛的手工技艺。制作雀舌面&#xff0c;对面粉的选择和面团的揉制有着极高的要求。经验丰富的师傅会精心挑选优质面粉&#xff0c;加入适量的水&#xf…

嵌入式学习---DAY17:共用体与位运算

链表剩余的一些内容 一、共用体 union 共用体名 名称首字母大写 { 成员表列&#xff1b; }&#xff1b; union Demo {int i;short s;char c; }; int main(void) {union Demo d;d.i 10;d.s 100;d.c 200;printf("%d\n", sizeof(d)); /…

一起学习LeetCode热题100道(24/100)

24.回文链表(学习) 给你一个单链表的头节点 head &#xff0c;请你判断该链表是否为 回文链表 。如果是&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 示例 1&#xff1a; 输入&#xff1a;head [1,2,2,1] 输出&#xff1a;true 示例 2&#xff1a; …

鸿蒙Scroll布局,横向与纵向

注意&#xff0c;当横向scroll时&#xff0c;直接子元素的宽&#xff0c;不能100%&#xff0c; 当纵向scroll时&#xff0c;直接子元素的高&#xff0c;不能100%​​​​​​​ 1、纵向代码&#xff1a; 方法1&#xff1a;用数值计算&#xff0c;来设置中间的高度&#xff1a; …

Django函数视图和类视图

函数视图 1.全局环境的urls.py引入映入应用的urls&#xff0c;避免后期开发路由过多而导致杂乱 from django.contrib import admin from django.urls import path, includeurlpatterns [path(account/, include(account.urls)),#使用include函数引入&#xff0c;表示account…

搜狗爬虫(www.sogou.com)IP及UA,真实采集数据

一、数据来源&#xff1a; 1、这批搜狗爬虫&#xff08;www.sogou.com&#xff09;IP来源于尚贤达猎头网站采集数据&#xff1b; ​ 2、数据采集时间段&#xff1a;2023年10月-2024年7月&#xff1b; 3、判断标准&#xff1a;主要根据用户代理是否包含“www.sogou.com”和IP核实…

我菜单为什么跟着滑动了?!!—— 固定定位为什么会失效?

背景&#xff1a;最近在写一个H5页面项目&#xff0c;头部有个菜单栏&#xff0c;需要固定在顶部不动&#xff0c;但是滑动之后设置并没有生效&#xff0c;之前开发中也遇到过类似的固定失效的情况&#xff0c;就去详细了解了下有哪些可能导致固定定位失效的情况。希望有些场景…

数据库文件管理

数据库文件与普通文件区别: 1.普通文件对数据管理(增删改查)效率低 2.数据库对数据管理效率高,使用方便 常用数据库: 1.关系型数据库&#xff1a; 将复杂的数据结构简化为二维表格形式 大型:Oracle、DB2 中型:MySql、SQLServer 小型:Sqlite 2.非关…

【传知代码】主动学习实现领域自适应语义分割(论文复现)

在当今计算机视觉和人工智能领域&#xff0c;语义分割技术的发展正日益成为实现智能系统感知和理解复杂场景的关键。然而&#xff0c;传统的语义分割模型往往面临着在新领域或不同环境下适应性不足的挑战。为了解决这一问题&#xff0c;主动学习作为一种强大的技术手段&#xf…

每日学术速递8.2

1.A Scalable Quantum Non-local Neural Network for Image Classification 标题&#xff1a; 用于图像分类的可扩展量子非局部神经网络 作者&#xff1a; Sparsh Gupta, Debanjan Konar, Vaneet Aggarwal 文章链接&#xff1a;https://arxiv.org/abs/2407.18906 摘要&#x…

echarts图表--雷达图(参数详解)

这是官网给出的几种雷达图&#xff1a; Examples - Apache ECharts 雷达图&#xff08;Radar Chart&#xff09;是一种用于展示多维数据的图表&#xff0c;尤其适合于比较不同样本或观测在多个相同变量上的表现。在使用ECharts或PyEcharts等可视化库绘制雷达图时&#xff0c;…

Prometheus 监控 Nginx

作者&#xff1a;琉璃 一、Nginx_exporter安装 下载链接&#xff1a; https://github.com/discordianfish/nginx_exporter 下载nginx_exporter的docker镜像。 ocker pull fish/nginx-exporter先run一下&#xff0c;执行之后&#xff0c;会hold住&#xff0c;先不要关闭窗口…

IP 地址处理模块IPy

IP 地址处理模块IPy 介绍安装基本操作多网络计算方法 介绍 IP 地址规划是网络设计中非常重要的一个环节&#xff0c;规划的好坏会直接影响路由协议算法的效率&#xff0c;包括网络性能、可扩展性等方面&#xff0c;在这个过程当中&#xff0c;免不了要计算大量的 IP 地址&…