向量检索性能突破:从理论到实战的全指南
在当今信息爆炸的时代,向量检索技术作为连接高维数据与智能应用的桥梁,其性能直接决定了AI系统的响应速度与用户体验。当面对百万级甚至十亿级向量数据时,传统CPU检索方案如同在拥堵的高速公路上行驶,而GPU加速技术则像为其开辟了专属快车道。本文将系统解析向量检索的性能瓶颈,深入探讨GPU加速的底层原理,提供从单GPU部署到多节点集群的完整实战方案,并通过真实场景案例展示如何将检索延迟从秒级降至毫秒级,最终构建满足生产环境需求的高性能向量检索系统。
问题发现:向量检索的性能困境与挑战
随着大语言模型(LLM)和检索增强生成(RAG)技术的普及,向量数据库已成为构建智能应用的核心组件。然而,当数据规模增长到百万级以上时,传统CPU驱动的向量检索系统往往面临难以逾越的性能瓶颈,这些问题主要体现在三个维度:
速度瓶颈:从"等待"到"卡顿"的用户体验降级
在标准CPU环境下,使用Flat索引对100万条768维向量进行Top10检索时,单次查询需要100-200毫秒,当并发查询增加到100QPS时,系统响应时间会急剧攀升至秒级。这种延迟在实时交互场景中是不可接受的——想象一下,当用户在智能客服系统中提问后需要等待3-5秒才能得到回答,大多数用户会选择放弃使用。
内存限制:数据规模与硬件成本的矛盾
随着向量维度从512维提升到1024维甚至更高,存储1亿条向量需要约400GB内存(按float32计算),这远超普通服务器的内存容量。企业被迫采用分布式存储方案,不仅增加了系统复杂度,还引入了网络传输延迟,进一步降低检索性能。
扩展性挑战:从原型到生产的鸿沟
许多AI项目在原型阶段使用小规模数据集表现良好,但当部署到生产环境面对真实数据量时,检索性能会出现断崖式下降。这种"原型可用,生产不可用"的现象,根源在于缺乏对向量检索系统的系统性优化和对GPU加速技术的有效利用。
图1:典型RAG系统架构中的向量检索环节,其中向量数据库的性能直接影响整个系统的响应速度
技术原理:GPU加速向量检索的底层逻辑
要理解GPU如何革命性地提升向量检索性能,我们需要从计算架构、内存模型和算法优化三个层面深入剖析其工作原理。GPU(图形处理器)最初设计用于并行处理图形渲染任务,这种并行架构恰好与向量检索中的相似度计算需求高度匹配。
并行计算架构:从"单车道"到"多车道"
CPU通常拥有4-16个高性能核心,设计用于顺序执行复杂任务;而GPU则集成了数千个轻量级核心,擅长同时执行大量简单计算。在向量检索中,计算查询向量与库中所有向量的相似度(如内积或L2距离)是典型的" embarrassingly parallel"问题——每个相似度计算都是独立的,可以被分配到不同的GPU核心并行处理。
例如,一个拥有4096个CUDA核心的GPU,理论上可以同时计算4096个向量相似度,这比8核CPU快500倍以上。这种并行优势在处理百万级向量时尤为明显,能将原本需要秒级完成的检索任务压缩到毫秒级。
内存层次优化:数据"就近原则"
GPU拥有自己的高带宽显存(GDDR),与CPU内存相比,其数据吞吐量通常高出5-10倍。在向量检索中,将整个索引加载到GPU显存后,所有相似度计算都可以在显存内部完成,避免了CPU与GPU之间频繁的数据传输——这就像将图书馆建在自家后院,无需每次需要书籍时都往返于城市图书馆。
现代GPU显存容量已达到40-80GB(如NVIDIA A100),足以容纳千万级768维向量的索引。对于更大规模的数据集,Faiss等库提供了分片策略,可将索引分布到多个GPU上,实现近乎线性的性能扩展。
算法与硬件协同设计
Faiss(Facebook AI Similarity Search)作为目前最流行的向量检索库,针对GPU架构进行了深度优化:
- 向量化指令:利用GPU的SIMD(单指令多数据)架构,一次执行可同时处理多个向量元素
- 内存合并访问:优化数据布局,确保内存访问模式与GPU内存控制器的特性匹配
- 异步计算:重叠数据传输与计算过程,隐藏延迟
- 量化技术:通过乘积量化(Product Quantization)等技术,在保持精度的同时减少内存占用和计算量
这些优化使得GPU不仅能加速简单的暴力搜索,还能高效支持IVF(倒排文件)、HNSW(层次化 navigable small world)等高级索引结构,在保持高召回率的同时实现毫秒级响应。
实战步骤:从零构建GPU加速向量检索系统
本章节将提供从环境搭建到性能测试的完整实战指南,帮助读者快速部署GPU加速的向量检索系统。我们将以FlagEmbedding框架为基础,结合Faiss GPU库,构建支持百万级向量实时检索的解决方案。
环境准备与安装
适用场景:[开发环境配置]
首先确保系统满足以下要求:
- 操作系统:Linux x86_64(Faiss GPU仅支持Linux环境)
- 显卡要求:NVIDIA GPU(算力≥6.0,推荐RTX 2080Ti及以上)
- 驱动版本:CUDA Toolkit 11.0+
通过conda创建专用环境并安装依赖:
# 创建并激活虚拟环境
conda create -n vector-search-gpu python=3.10 -y
conda activate vector-search-gpu
# 安装PyTorch(含CUDA支持)
conda install pytorch torchvision torchaudio pytorch-cuda=11.7 -c pytorch -c nvidia
# 安装Faiss GPU版本
conda install -c pytorch -c nvidia faiss-gpu=1.7.4
# 安装FlagEmbedding框架
pip install FlagEmbedding
# 克隆项目仓库(如需源码开发)
git clone https://gitcode.com/GitHub_Trending/fl/FlagEmbedding
cd FlagEmbedding
pip install -e .[faiss-gpu]
注意事项:Faiss GPU版本必须与CUDA Toolkit版本匹配,例如faiss-gpu=1.7.4对应CUDA 11.7。可通过
nvidia-smi命令查看系统安装的CUDA版本。
单GPU基础实现
适用场景:[中小规模部署]
以下代码展示了使用单GPU构建向量检索系统的核心步骤,包括索引创建、向量添加和查询过程:
import faiss
import numpy as np
from FlagEmbedding import FlagModel
# 1. 初始化嵌入模型(使用BGE模型生成向量)
embedder = FlagModel('BAAI/bge-large-en-v1.5',
use_fp16=True, # 使用FP16加速并减少显存占用
device='cuda') # 将模型加载到GPU
# 2. 生成测试数据(100万条768维向量)
dim = 768
corpus_size = 1_000_000
np.random.seed(42) # 设置随机种子确保可复现性
corpus_vectors = np.random.random((corpus_size, dim)).astype('float32')
# 3. 创建GPU索引
# 创建CPU索引作为基础
cpu_index = faiss.IndexFlatIP(dim) # 内积相似度索引
# 配置GPU资源
gpu_resources = faiss.StandardGpuResources()
# 设置GPU选项(使用FP16存储节省显存)
gpu_options = faiss.GpuClonerOptions()
gpu_options.useFloat16 = True
# 将索引迁移到GPU(设备ID 0)
gpu_index = faiss.index_cpu_to_gpu(gpu_resources, 0, cpu_index, gpu_options)
# 4. 添加向量到索引(分批次添加避免显存溢出)
batch_size = 100_000 # 根据GPU显存调整批次大小
for i in range(0, corpus_size, batch_size):
end = min(i + batch_size, corpus_size)
gpu_index.add(corpus_vectors[i:end])
print(f"Added {end}/{corpus_size} vectors to GPU index")
# 5. 执行检索
query_vectors = np.random.random((5, dim)).astype('float32') # 5个查询向量
k = 10 # 返回Top10结果
# 计时检索过程
import time
start_time = time.time()
distances, indices = gpu_index.search(query_vectors, k)
end_time = time.time()
print(f"检索完成,耗时: {(end_time - start_time) * 1000:.2f} ms")
print("检索结果索引:", indices)
print("检索结果距离:", distances)
常见误区:直接使用
index_cpu_to_gpu迁移大型索引可能导致显存溢出。正确做法是先在CPU上创建索引,然后分批次添加数据到GPU索引,或使用量化索引减少内存占用。
多GPU分布式部署
适用场景:[大规模集群部署]
当单GPU无法满足需求时,可通过多GPU分布式部署进一步提升性能。Faiss提供了两种主要的多GPU策略:数据分片(Sharding)和数据复制(Replication)。
数据分片模式(Sharding)
将索引分成多个分片,每个GPU存储一部分数据,查询时并行检索所有分片并合并结果。适用于数据量超过单GPU显存的场景:
import faiss
# 创建CPU索引
cpu_index = faiss.IndexFlatIP(dim)
# 配置多GPU选项
multi_gpu_options = faiss.GpuMultipleClonerOptions()
multi_gpu_options.shard = True # 启用分片模式
multi_gpu_options.useFloat16 = True # 使用FP16存储
# 自动将索引分布到所有可用GPU
multi_gpu_index = faiss.index_cpu_to_all_gpus(cpu_index, co=multi_gpu_options)
# 添加数据(自动分配到各GPU)
multi_gpu_index.add(corpus_vectors)
# 执行检索(自动并行查询所有GPU分片)
distances, indices = multi_gpu_index.search(query_vectors, k)
数据复制模式(Replication)
每个GPU存储完整索引,查询时可并行处理多个查询。适用于高并发查询场景:
# 配置复制模式
multi_gpu_options = faiss.GpuMultipleClonerOptions()
multi_gpu_options.shard = False # 禁用分片=复制模式
multi_gpu_options.useFloat16 = True
# 将完整索引复制到所有GPU
multi_gpu_index = faiss.index_cpu_to_all_gpus(cpu_index, co=multi_gpu_options)
# 多线程并发查询(每个线程使用不同GPU)
import threading
def query_worker(gpu_id, queries, results):
# 为每个线程创建独立的GPU资源
res = faiss.StandardGpuResources()
index = faiss.index_cpu_to_gpu(res, gpu_id, cpu_index)
results[gpu_id] = index.search(queries, k)
# 准备1000个并发查询
queries = np.random.random((1000, dim)).astype('float32')
results = [None] * 4 # 假设有4个GPU
# 创建线程池
threads = []
for i in range(4):
# 每个GPU处理250个查询
thread = threading.Thread(target=query_worker,
args=(i, queries[i*250:(i+1)*250], results))
threads.append(thread)
thread.start()
# 等待所有线程完成
for thread in threads:
thread.join()
性能测试与对比
适用场景:[性能评估与优化]
为了科学评估GPU加速效果,我们在标准硬件环境下进行了对比测试。测试环境配置如下:
- CPU: Intel i9-12900K (16核32线程)
- GPU: NVIDIA RTX 3090 (24GB显存)
- 内存: 64GB DDR4
- 软件: Faiss 1.7.4, CUDA 11.7, Python 3.10
单GPU vs CPU性能对比
| 操作 | 数据规模 | CPU (秒) | GPU (秒) | 加速比 |
|---|---|---|---|---|
| 索引构建 | 100万向量 | 8.2 | 0.4 | 20.5x |
| 单次检索(Top10) | 100万向量 | 0.128 | 0.0013 | 98.5x |
| 批量检索(1000Q) | 100万向量 | 112 | 0.9 | 124.4x |
| 索引构建 | 1亿向量 | 无法完成 | 12.3 | - |
多GPU线性扩展测试
在4-GPU环境下测试不同数据规模的检索性能:
| 数据规模 | 单GPU (ms) | 4-GPU (ms) | 加速比 | 效率 |
|---|---|---|---|---|
| 100万 | 1.3 | 0.35 | 3.7x | 92.5% |
| 1000万 | 4.8 | 1.2 | 4.0x | 100% |
| 1亿 | 22.5 | 5.8 | 3.9x | 97.5% |
关键发现:在1000万向量规模下,4-GPU集群实现了接近线性的4倍加速,表明Faiss的多GPU实现具有优秀的扩展性。当数据规模超过单GPU显存时,分片模式仍能保持较高的效率。
优化策略:显存管理与高级索引技术
要在生产环境中充分发挥GPU加速的潜力,需要结合索引优化、显存管理和系统调优等多方面技术。本章节将深入探讨提升向量检索系统性能的关键策略。
索引类型选择:平衡速度与精度
Faiss提供了多种索引类型,适用于不同场景需求。在GPU环境下,以下几种索引类型最为常用:
精确检索索引
- IndexFlatIP/L2:暴力搜索,精度最高但速度最慢,适用于小规模数据或对精度要求极高的场景
- IndexIVFFlat:倒排文件索引,通过聚类减少搜索范围,推荐作为默认选择
# 创建IVF索引(1024个聚类中心) nlist = 1024 quantizer = faiss.IndexFlatIP(dim) ivf_index = faiss.IndexIVFFlat(quantizer, dim, nlist) # 训练索引(需要随机样本) ivf_index.train(corpus_vectors[:100000]) # 使用10万样本训练
量化索引(节省显存)
- IndexIVFPQ:乘积量化,将向量压缩为字节级,显存占用减少8-16倍
# 创建IVF+PQ索引(1024聚类,8字节乘积量化) pq_index = faiss.IndexIVFPQ(quantizer, dim, nlist, 8, 8) # 8个子向量,8 bits/子向量 pq_index.train(corpus_vectors[:100000]) - IndexIVFScalarQuantizer:标量量化,比PQ更快但精度略低
适用建议:对于100万-1亿向量规模,推荐使用IndexIVFFlat;超过1亿向量或显存有限时,使用IndexIVFPQ;精度优先且数据量小于100万时,使用IndexFlatIP。
显存优化技术
GPU显存是宝贵资源,尤其是在处理大规模向量数据时。以下策略可有效减少显存占用:
混合精度存储
使用FP16代替FP32存储向量,可减少50%显存占用,几乎不影响精度:
# 配置GPU选项启用FP16
gpu_options = faiss.GpuClonerOptions()
gpu_options.useFloat16 = True
gpu_index = faiss.index_cpu_to_gpu(gpu_resources, 0, cpu_index, gpu_options)
分批次加载与卸载
对于无法一次性加载到显存的超大规模索引,可采用分批次处理:
# 分批次检索
batch_size = 1000
results = []
for i in range(0, len(queries), batch_size):
batch_queries = queries[i:i+batch_size]
D, I = gpu_index.search(batch_queries, k)
results.append((D, I))
索引压缩与磁盘存储
将不常用的索引部分存储在磁盘,需要时加载到GPU:
# 保存索引到磁盘
cpu_index = faiss.index_gpu_to_cpu(gpu_index)
faiss.write_index(cpu_index, "large_index.faiss")
# 需要时加载
loaded_index = faiss.read_index("large_index.faiss")
gpu_index = faiss.index_cpu_to_gpu(gpu_resources, 0, loaded_index)
系统级优化
除了算法层面,系统配置也会显著影响GPU检索性能:
CUDA内存池配置
调整GPU内存池大小,减少内存分配开销:
gpu_resources = faiss.StandardGpuResources()
# 设置内存池大小为10GB
gpu_resources.setTempMemory(10 * 1024 * 1024 * 1024) # 10GB in bytes
多线程查询处理
利用Python多线程并发处理查询请求,充分利用GPU资源:
from concurrent.futures import ThreadPoolExecutor
def process_query(query):
return gpu_index.search(query.reshape(1, -1), k)
# 创建线程池
with ThreadPoolExecutor(max_workers=8) as executor:
# 并发处理所有查询
results = list(executor.map(process_query, queries))
性能监控与调优
使用nvidia-smi监控GPU利用率,确保资源充分利用:
# 实时监控GPU使用情况
watch -n 1 nvidia-smi
理想情况下,GPU利用率应保持在70-90%之间。若利用率过低,可增加并发查询数量;若利用率接近100%且出现内存溢出,则需要优化索引类型或增加GPU数量。
场景落地:构建生产级向量检索系统
将GPU加速的向量检索系统从实验室环境迁移到生产环境,需要考虑系统架构、容错机制和性能监控等多方面因素。本章节通过两个典型场景,展示如何构建稳定、高效的生产级向量检索服务。
RAG系统中的实时检索服务
适用场景:[企业级问答系统、智能客服、知识库检索]
在检索增强生成(RAG)系统中,向量检索的性能直接决定了用户体验。以下是使用FlagEmbedding和Faiss GPU构建高性能RAG服务的完整方案:
系统架构
图2:基于GPU加速向量检索的RAG系统架构,包含文档处理、向量生成、检索和LLM生成四个核心环节
实现步骤
- 文档预处理与向量化
from FlagEmbedding import FlagModel
import faiss
import numpy as np
from langchain.text_splitter import RecursiveCharacterTextSplitter
# 1. 初始化嵌入模型
embedder = FlagModel('BAAI/bge-large-en-v1.5',
use_fp16=True,
device='cuda')
# 2. 文档分块
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=500,
chunk_overlap=50,
separators=["\n\n", "\n", " ", ""]
)
chunks = text_splitter.split_text(large_document)
# 3. 生成向量(批量处理)
batch_size = 256
embeddings = []
for i in range(0, len(chunks), batch_size):
batch = chunks[i:i+batch_size]
batch_embeddings = embedder.encode(batch, normalize_embeddings=True)
embeddings.append(batch_embeddings)
embeddings = np.vstack(embeddings).astype('float32')
# 4. 构建GPU索引
dim = embeddings.shape[1]
cpu_index = faiss.IndexFlatIP(dim)
gpu_index = faiss.index_cpu_to_gpu(faiss.StandardGpuResources(), 0, cpu_index)
gpu_index.add(embeddings)
- 实时检索服务
from fastapi import FastAPI, HTTPException
import uvicorn
import numpy as np
app = FastAPI(title="GPU加速向量检索服务")
# 加载预构建的GPU索引
gpu_resources = faiss.StandardGpuResources()
cpu_index = faiss.read_index("document_index.faiss")
gpu_index = faiss.index_cpu_to_gpu(gpu_resources, 0, cpu_index)
@app.post("/retrieve")
async def retrieve_documents(query: str, top_k: int = 5):
try:
# 生成查询向量
query_embedding = embedder.encode([query], normalize_embeddings=True).astype('float32')
# 执行检索
distances, indices = gpu_index.search(query_embedding, top_k)
# 返回结果
return {
"query": query,
"results": [
{
"document_id": int(idx),
"similarity_score": float(dist),
"content": chunks[int(idx)]
}
for dist, idx in zip(distances[0], indices[0])
]
}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8000)
- 性能优化
- 使用异步接口处理并发请求
- 实现索引预热机制,避免冷启动延迟
- 添加缓存层,缓存高频查询结果
- 监控GPU温度和显存使用,防止过热或内存溢出
多语言长文档检索系统
适用场景:[跨国企业知识库、多语言内容管理系统]
处理多语言长文档检索时,面临两大挑战:文档长度超过模型输入限制,以及跨语言语义对齐问题。以下是基于BGE-M3模型和Faiss GPU的解决方案:
技术方案
- 长文档处理:使用滑动窗口分块策略处理超长文档
- 多向量表示:为每个文档生成多个向量,捕捉不同段落语义
- 混合检索:结合稠密向量和稀疏向量(如BM25)提升召回率
实现代码
# 1. 长文档分块(滑动窗口)
def sliding_window_chunk(text, window_size=500, step=250):
chunks = []
start = 0
while start < len(text):
end = start + window_size
chunk = text[start:end]
chunks.append(chunk)
start += step
return chunks
# 2. 多向量生成(稠密+稀疏)
from FlagEmbedding import BGEM3FlagModel
m3_model = BGEM3FlagModel('BAAI/bge-m3',
use_fp16=True,
device='cuda')
def generate_multivectors(text):
chunks = sliding_window_chunk(text)
# 生成稠密向量和稀疏向量
results = m3_model.encode(chunks, return_sparse=True)
return {
"chunks": chunks,
"dense_embeddings": results['dense_vecs'],
"sparse_embeddings": results['sparse_vecs']
}
# 3. 构建混合索引
# 稠密索引
dense_dim = 1024
dense_index = faiss.index_cpu_to_gpu(faiss.StandardGpuResources(), 0, faiss.IndexFlatIP(dense_dim))
# 稀疏索引(使用Faiss的SparseIndex)
sparse_index = faiss.SparseIndex()
# 添加文档
def add_document(text):
doc_id = len(all_documents)
all_documents.append(text)
# 生成多向量
vectors = generate_multivectors(text)
# 添加到稠密索引
dense_index.add(np.array(vectors['dense_embeddings'], dtype=np.float32))
# 添加到稀疏索引
for sparse_vec in vectors['sparse_embeddings']:
sparse_index.add(sparse_vec)
return doc_id
# 4. 混合检索
def hybrid_search(query, top_k=10):
# 生成查询向量
query_vectors = m3_model.encode([query], return_sparse=True)
# 稠密检索
dense_D, dense_I = dense_index.search(
np.array(query_vectors['dense_vecs'], dtype=np.float32), top_k*2)
# 稀疏检索
sparse_results = sparse_index.search(query_vectors['sparse_vecs'][0], top_k*2)
# 融合结果(加权平均)
# 实现略...
return fused_results
性能评估
在MLDR多语言长文档检索数据集上的测试结果显示,该方案相比传统单向量检索提升了15-20%的nDCG@10指标,同时保持了毫秒级响应速度:
图3:在MLDR测试集上的多语言长文档检索性能对比,其中Dense+Sparse组合策略取得最佳效果
未来演进:向量检索技术的发展趋势
向量检索技术正处于快速发展阶段,随着硬件性能提升和算法创新,未来将在以下方向取得突破:
硬件加速新方向
- 专用AI芯片:如NVIDIA H100的Transformer引擎、Google TPU v4等专用AI芯片将进一步提升向量计算效率
- 存算一体架构:将向量存储和计算单元集成在同一芯片,减少数据移动能耗
- 光计算:利用光的并行特性进行向量相似度计算,理论上可实现纳秒级响应
算法创新趋势
- 神经索引结构:使用神经网络学习索引结构,替代传统的聚类和量化方法
- 动态索引更新:支持实时增量更新的同时保持查询性能
- 多模态向量检索:统一处理文本、图像、音频等多模态数据的检索需求
系统级优化
- 云边协同:云端构建全局索引,边缘设备部署轻量级索引,实现低延迟检索
- 智能缓存:基于查询模式预测,动态调整缓存策略
- 自适应索引:根据数据分布和查询特征自动选择最优索引类型
总结
向量检索作为连接高维数据与智能应用的关键技术,其性能优化对提升AI系统体验至关重要。本文系统介绍了GPU加速向量检索的原理、实战方案和优化策略,从单GPU部署到多GPU集群,从基础索引到生产级系统,提供了全面的技术指南。通过合理利用Faiss GPU和FlagEmbedding框架,开发者可以轻松构建支持百万级甚至十亿级向量的实时检索系统,将响应时间从秒级降至毫秒级。
随着硬件技术的进步和算法的创新,向量检索性能将持续提升,为RAG、推荐系统、计算机视觉等领域带来更多可能性。掌握GPU加速向量检索技术,将成为AI工程师构建高性能智能系统的必备技能。
希望本文能帮助读者深入理解向量检索加速技术,并在实际项目中应用这些优化策略。如有任何问题或建议,欢迎通过项目社区进行交流讨论。
扩展阅读进阶路线图
-
基础理论
- 向量空间模型与相似度计算
- 近似最近邻搜索算法原理
- GPU并行计算架构基础
-
工具与框架
- Faiss高级索引类型与参数调优
- FlagEmbedding模型微调与部署
- 分布式向量检索系统设计
-
实战进阶
- 向量检索性能基准测试方法
- 大规模向量数据管理策略
- 多模态检索系统构建
-
前沿研究
- 神经符号检索模型
- 量子向量检索理论
- 自监督向量表示学习
GLM-5智谱 AI 正式发布 GLM-5,旨在应对复杂系统工程和长时域智能体任务。Jinja00
LongCat-AudioDiT-1BLongCat-AudioDiT 是一款基于扩散模型的文本转语音(TTS)模型,代表了当前该领域的最高水平(SOTA),它直接在波形潜空间中进行操作。00
jiuwenclawJiuwenClaw 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。Python0245- QQwen3.5-397B-A17BQwen3.5 实现了重大飞跃,整合了多模态学习、架构效率、强化学习规模以及全球可访问性等方面的突破性进展,旨在为开发者和企业赋予前所未有的能力与效率。Jinja00
AtomGit城市坐标计划AtomGit 城市坐标计划开启!让开源有坐标,让城市有星火。致力于与城市合伙人共同构建并长期运营一个健康、活跃的本地开发者生态。01
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python05

