如何替別人建網(wǎng)站掙錢seo優(yōu)化的主要任務包括
vLLM 是一個簡單易用的 LLM 推理服務庫。加州大學伯克利分校于 2024 年 7 月將 vLLM 作為孵化項目正式捐贈給 LF AI & Data Foundation 基金會。歡迎 vLLM 加入 LF AI & Data 大家庭!🎉
在主流的 AI 應用架構中,大語言模型(LLM)通常與向量數(shù)據(jù)庫配套使用,用于構建檢索增強生成(RAG)應用,從而解決 AI 幻覺問題。本文將介紹如何使用 Milvus、vLLM 和 Llama 3.1 構建并運行RAG 應用。我們將詳細展示如何將文本信息轉換為 Embedding 向量并存儲到 Milvus 向量數(shù)據(jù)庫中、如何將 Milvus 作為知識庫有效檢索與用戶問題相關的文本塊。最后,我們將通過 vLLM 使用 Meta的Llama 3.1-8B 模型生成答案。
01
Milvus、vLLM 和 Llama 3.1 簡介
Milvus 向量數(shù)據(jù)庫
Milvus 是一款開源的分布式向量數(shù)據(jù)庫,可用于存儲、索引和搜索向量數(shù)據(jù),適用于生成式 AI(GenAI)應用。Milvus 支持 hybrid search、元數(shù)據(jù)過濾、重排(Reranking),能夠高效處理萬億規(guī)模的向量,助力開發(fā)者搭建 AI 和 ML 應用。您可以在本地運行 Milvus standalone 或 cluster 版本,或者使用全托管的 Milvus 服務——Zilliz Cloud。
vLLM
vLLM 是加州大學伯克利分校 SkyLab 推出的一個開源項目,專注于優(yōu)化 LLM 服務性能。通過高效的內(nèi)存管理技術,如 PagedAttention、持續(xù)批處理和優(yōu)化 CUDA 內(nèi)核,vLLm 與傳統(tǒng)方法相比將服務性能提高了多達 24 倍,同時將 GPU 內(nèi)存用量減少了一半。
根據(jù)論文《Efficient Memory Management for Large Language Model Serving with PagedAttention》,KV 緩存使用約 30% 的 GPU 內(nèi)存,可能會導致內(nèi)存問題。KV 緩存存儲在連續(xù)內(nèi)存(contiguous memory)中,但內(nèi)存變化可能導致內(nèi)存碎片化,不利于計算效率。
通過使用虛擬內(nèi)存緩存 KV,vLLM 只需要在必要時分配物理 GPU 內(nèi)存,有效避免了內(nèi)存碎片化和內(nèi)存預分配。在測試中,vLLM 的吞吐量比 HuggingFace Transformers (HF) 高出多達 24 倍,比基于NVIDIA A10G 和 A100 GPU 的 Text Generation Inference (TGI) 高出 3.5 倍。
Meta Llama 3.1
Meta 于 2024 年 7 月 23 日宣布推出 Llama 3.1,允許用于多種商業(yè)用途。其 405B 模型(4050 億參數(shù))在多個公開的性能測試中均展示出了最出色的性能,并支持 128,000 個輸入 Token 的上下文窗口。除了 405B 模型外,Meta 還發(fā)布了 Llama3.1 70B(700 億參數(shù))和 8B(80 億參數(shù))模型。您可以通過 Meta 官網(wǎng)下載模型權重(model weight)。
需要注意微調(diào)生成的數(shù)據(jù)可以提高模型性能,但低質量的數(shù)據(jù)可能會降低模型性能。Llama 團隊已不斷識別和去除這些低質量的數(shù)據(jù),使用模型本身及其他輔助模型和工具,進一步優(yōu)化模型。
02
使用 Milvus 搭建 RAG-Retrieval部分
準備數(shù)據(jù)
本教程將使用 Milvus 文檔作為數(shù)據(jù)集。我們需要先下載并本地保存 Milvus 文檔。
from langchain.document_loaders import DirectoryLoader# Load HTML files already saved in a local directorypath = "../../RAG/rtdocs_new/"global_pattern = '*.html'loader = DirectoryLoader(path=path, glob=global_pattern)docs = loader.load()# Print num documents and a preview.print(f"loaded {len(docs)} documents")print(docs[0].page_content)pprint.pprint(docs[0].metadata)
下載 Embedding 模型
接著,從 HuggingFace 上下載一個免費的開源 Embedding 模型。
import torchfrom sentence_transformers import SentenceTransformer# Initialize torch settings for device-agnostic code.N_GPU = torch.cuda.device_count()DEVICE = torch.device('cuda:N_GPU' if torch.cuda.is_available() else 'cpu')# Download the model from huggingface model hub.model_name = "BAAI/bge-large-en-v1.5"encoder = SentenceTransformer(model_name, device=DEVICE)# Get the model parameters and save for later.EMBEDDING_DIM = encoder.get_sentence_embedding_dimension()MAX_SEQ_LENGTH_IN_TOKENS = encoder.get_max_seq_length()# Inspect model parameters.print(f"model_name: {model_name}")print(f"EMBEDDING_DIM: {EMBEDDING_DIM}")print(f"MAX_SEQ_LENGTH: {MAX_SEQ_LENGTH}")
切分數(shù)據(jù)并編碼為向量
將文檔數(shù)據(jù)切分成固定長度(512 個字符)的文本塊,并將切分 overlap 設置為 10%。
from langchain.text_splitter import RecursiveCharacterTextSplitterCHUNK_SIZE = 512chunk_overlap = np.round(CHUNK_SIZE * 0.10, 0)print(f"chunk_size: {CHUNK_SIZE}, chunk_overlap: {chunk_overlap}")# Define the splitter.child_splitter = RecursiveCharacterTextSplitter(chunk_size=CHUNK_SIZE,chunk_overlap=chunk_overlap)# Chunk the docs.chunks = child_splitter.split_documents(docs)print(f"{len(docs)} docs split into {len(chunks)} child documents.")# Encoder input is doc.page_content as strings.list_of_strings = [doc.page_content for doc in chunks if hasattr(doc, 'page_content')]# Embedding inference using HuggingFace encoder.embeddings = torch.tensor(encoder.encode(list_of_strings))# Normalize the embeddings.embeddings = np.array(embeddings / np.linalg.norm(embeddings))# Milvus expects a list of `numpy.ndarray` of `numpy.float32` numbers.converted_values = list(map(np.float32, embeddings))# Create dict_list for Milvus insertion.dict_list = []for chunk, vector in zip(chunks, converted_values):# Assemble embedding vector, original text chunk, metadata.chunk_dict = {'chunk': chunk.page_content,'source': chunk.metadata.get('source', ""),'vector': vector,}dict_list.append(chunk_dict)
將向量數(shù)據(jù)存儲在 Milvus 中
將向量存儲到 Milvus 向量數(shù)據(jù)庫中。
# Connect a client to the Milvus Lite server.from pymilvus import MilvusClientmc = MilvusClient("milvus_demo.db")# Create a collection with flexible schema and AUTOINDEX.COLLECTION_NAME = "MilvusDocs"mc.create_collection(COLLECTION_NAME,EMBEDDING_DIM,consistency_level="Eventually",auto_id=True, overwrite=True)# Insert data into the Milvus collection.print("Start inserting entities")start_time = time.time()mc.insert(COLLECTION_NAME,data=dict_list,progress_bar=True)end_time = time.time()print(f"Milvus insert time for {len(dict_list)} vectors: ", end="")print(f"{round(end_time - start_time, 2)} seconds")
進行向量搜索
輸入問題,并在 Milvus 知識庫中搜索與問題最相似的文本塊。
SAMPLE_QUESTION = "What do the parameters for HNSW mean?"# Embed the question using the same encoder.query_embeddings = torch.tensor(encoder.encode(SAMPLE_QUESTION))# Normalize embeddings to unit length.query_embeddings = F.normalize(query_embeddings, p=2, dim=1)# Convert the embeddings to list of list of np.float32.query_embeddings = list(map(np.float32, query_embeddings))# Define metadata fields you can filter on.OUTPUT_FIELDS = list(dict_list[0].keys())OUTPUT_FIELDS.remove('vector')# Define how many top-k results you want to retrieve.TOP_K = 2# Run semantic vector search using your query and the vector database.results = mc.search(COLLECTION_NAME,data=query_embeddings,output_fields=OUTPUT_FIELDS,limit=TOP_K,consistency_level="Eventually")
搜索結果如下所示:
03
使用 vLLM 和 Llama 3.1-8B 搭建 RAG-Generation 部分
安裝 vLLM 與 HuggingFace 模型
vLLM 默認從 HuggingFace 下載大語言模型。通常情況下,如果您想使用 HuggingFace 上的新模型,需要執(zhí)行 pip install --update 或 -U。此外,我們還需要 GPU 通過 vLLM 來運行 Meta 的 Llama 3.1 推理模型。
# (Recommended) Create a new conda environment.conda create -n myenv python=3.11 -yconda activate myenv# Install vLLM with CUDA 12.1.pip install -U vllm transformers torch
import?vllm,?torchfrom vllm import LLM, SamplingParams# Clear the GPU memory cache.torch.cuda.empty_cache()# Check the GPU.!nvidia-smi
獲取 HuggingFace token
HuggingFace 上的部分模型(如 Meta Llama 3.1)要求用戶在下載前接受其許可證。因此,您必須先創(chuàng)建一個 HuggingFace 帳戶,接受模型的許可證,并生成一個 Token。
在 HuggingFace 的 Llama3.1 頁上,您會收到一條消息要求您同意條款。單擊"Accept License"以接受 Meta 條款,然后再下載模型權重。審批流程通常可以在一天內(nèi)完成。
審批通過后,需要生成一個新的 HuggingFace token。舊 Token 無法使用。
在安裝 vLLM 之前,請使用您的新 Token 登錄 HuggingFace。以下示例代碼中使用 Colab Secrets 來存儲 Token。
# Login to HuggingFace using your new token.from huggingface_hub import loginfrom google.colab import userdatahf_token = userdata.get('HF_TOKEN')login(token = hf_token, add_to_git_credential=True)
運行 RAG-Generation 部分
我們需要 GPU 和較大的內(nèi)存來運行 Llama-3.1-8B 模型。以下示例是在 Google Colab Pro上使用 A100 GPU 運行的。
# 1. Choose a modelMODELTORUN = "meta-llama/Meta-Llama-3.1-8B-Instruct"# 2. Clear the GPU memory cache, you're going to need it all!torch.cuda.empty_cache()# 3. Instantiate a vLLM model instance.llm = LLM(model=MODELTORUN,enforce_eager=True,dtype=torch.bfloat16,gpu_memory_utilization=0.5,max_model_len=1000,seed=415,max_num_batched_tokens=3000)
# Separate all the context together by space.contexts_combined = ' '.join(contexts)# Lance Martin, LangChain, says put the best contexts at the end.contexts_combined = ' '.join(reversed(contexts))# Separate all the unique sources together by comma.source_combined = ' '.join(reversed(list(dict.fromkeys(sources))))SYSTEM_PROMPT = f"""First, check if the provided Context is relevant tothe user's question. Second, only if the provided Context is strongly relevant, answer the question using the Context. Otherwise, if the Context is not strongly relevant, answer the question without using the Context. Be clear, concise, relevant. Answer clearly, in fewer than 2 sentences.Grounding sources: {source_combined}Context: {contexts_combined}User's question: {SAMPLE_QUESTION}"""prompts = [SYSTEM_PROMPT]
使用從 Milvus 中檢索獲得的上下文和原始提問來編寫提示,并生成回答。
# Sampling parameterssampling_params = SamplingParams(temperature=0.2, top_p=0.95)# Invoke the vLLM model.outputs = llm.generate(prompts, sampling_params)# Print the outputs.for output in outputs:prompt = output.promptgenerated_text = output.outputs[0].text# !r calls repr(), which prints a string inside quotes.print()print(f"Question: {SAMPLE_QUESTION!r}")pprint.pprint(f"Generated text: {generated_text!r}")
答案十分準確!
如果您對文本內(nèi)容感興趣,歡迎上手親自嘗試和實踐。同時,我們歡迎您加入 Milvus 社區(qū),與所有 GenAI 開發(fā)者共同交流。
參考
vLLM 官方文檔及模型頁面
https://docs.vllm.ai/en/latest/getting_started/installation.html
https://docs.vllm.ai/en/latest/models/supported_models.html#supported-models
2023 vLLM 論文
https://arxiv.org/pdf/2309.06180
2023 Ray Summit vLLM 相關演講
https://www.youtube.com/watch?v=80bIUggRJf4
vLLM 博客: vLLM: Easy, Fast, and Cheap LLM Serving with PagedAttention
https://blog.vllm.ai/2023/06/20/vllm.html
介紹如何運行 vLLM server 的博客文章: Deploying vLLM: a Step-by-Step Guide
https://ploomber.io/blog/vllm-deploy/
The Llama 3 Herd of Models | Research - AI at Meta
https://ai.meta.com/research/publications/the-llama-3-herd-of-models/
推薦閱讀