Meta AI 在本周二發(fā)布了最新一代開源大模型 Llama 2。對比于今年 2 月發(fā)布的 Llama 1,訓(xùn)練所用的 token 翻了一倍,已經(jīng)達(dá)到了 2 萬億,對于使用大模型最重要的上下文長度限制,Llama 2 也翻了一倍。
在本文,我們將緊跟趨勢介紹如何在本地CPU推理上運(yùn)行量化版本的開源Llama 2。
量化快速入門
我們首先簡單介紹一下量化的概念:
量化是一種減少用于表示數(shù)字或值的比特?cái)?shù)的技術(shù)。由于量化減少了模型大小,因此它有利于在cpu或嵌入式系統(tǒng)等資源受限的設(shè)備上部署模型。
一種常用的方法是將模型權(quán)重從原始的16位浮點(diǎn)值量化為精度較低的8位整數(shù)值。
llm已經(jīng)展示了出色的能力,但是它需要大量的CPU和內(nèi)存,所以我們可以使用量化來壓縮這些模型,以減少內(nèi)存占用并加速計(jì)算推理,并且保持模型性能。我們將通過將權(quán)重存儲在低精度數(shù)據(jù)類型中來降低模型參數(shù)的精度。
工具和數(shù)據(jù)
下圖是我們將在這個(gè)項(xiàng)目中構(gòu)建的文檔知識問答應(yīng)用程序的體系結(jié)構(gòu)。
我們的測試文件是177頁的曼聯(lián)足球俱樂部2022年年報(bào)。
為了演示這個(gè)項(xiàng)目的量化結(jié)果,我們使用一個(gè)AMD Ryzen 5 5600X 6核處理器和16GB RAM (DDR4 3600)。
下面是構(gòu)建這個(gè)應(yīng)用程序時(shí)將使用的軟件工具:
1、LangChain
LangChain是一個(gè)提供了一組廣泛的集成和數(shù)據(jù)連接器,允許我們鏈接和編排不同的模塊。可以常見聊天機(jī)器人、數(shù)據(jù)分析和文檔問答等應(yīng)用。
2、C Transformers
C transformer是一個(gè)Python庫,它為使用GGML庫并在C/ c++中實(shí)現(xiàn)了Transformers模型。
為了解釋這個(gè)事情我們首先要了解GGML:
GGML庫是一個(gè)為機(jī)器學(xué)習(xí)設(shè)計(jì)的張量庫,它的目標(biāo)是使大型模型能夠在高性能的消費(fèi)級硬件上運(yùn)行。這是通過整數(shù)量化支持和內(nèi)置優(yōu)化算法實(shí)現(xiàn)的。
也就是說,llm的GGML版本(二進(jìn)制格式的量化模型)可以在cpu上高性能地運(yùn)行。因?yàn)槲覀冏罱K是使用Python的,所以還需要C Transformers庫,它其實(shí)就是為GGML模型提供了Python API。
C transformer支持一組選定的開源模型,包括像Llama、GPT4All-J、MPT和Falcon等的流行模型。
3、sentence-transformer
sentence-transformer提供了簡單的方法來計(jì)算句子、文本和圖像的嵌入。它能夠計(jì)算100多種語言的嵌入。我們將在這個(gè)項(xiàng)目中使用開源的all-MiniLM-L6-v2模型。
4、FAISS
Facebook AI相似度搜索(FAISS)是一個(gè)為高效相似度搜索和密集向量聚類而設(shè)計(jì)的庫。
給定一組嵌入,我們可以使用FAISS對它們進(jìn)行索引,然后利用其強(qiáng)大的語義搜索算法在索引中搜索最相似的向量。
雖然它不是傳統(tǒng)意義上的成熟的向量存儲(如數(shù)據(jù)庫管理系統(tǒng)),但它以一種優(yōu)化的方式處理向量的存儲,以實(shí)現(xiàn)有效的最近鄰搜索。
5、Poetry
Poetry用于設(shè)置虛擬環(huán)境和處理Python包管理。相比于venv,Poetry使依賴管理更加高效和無縫。這個(gè)不是只做參考,因?yàn)閏onda也可以。
開源LLM
開源LLM領(lǐng)域已經(jīng)取得了巨大的進(jìn)步,在HuggingFace的開放LLM排行榜上可以找到模型。為了緊跟時(shí)代,我們選擇了最新的開源Llama-2-70B-Chat模型(GGML 8位):
1、Llama 2
它是C Transformers庫支持的開源模型。根據(jù)LLM排行榜排名(截至2023年7月),在多個(gè)指標(biāo)中表現(xiàn)最佳。在原來的Llama 模型設(shè)定的基準(zhǔn)上有了巨大的改進(jìn)。
2、模型尺寸:7B
LLM將主要用于總結(jié)文檔塊這一相對簡單的任務(wù)。因此選擇了7B模型,因?yàn)槲覀冊诩夹g(shù)上不需要過大的模型(例如65B及以上)來完成這項(xiàng)任務(wù)。
3、微調(diào)版:Llama-2-7B-Chat
lama-2- 7b基本模型是為文本補(bǔ)全而構(gòu)建的,因此它缺乏在文檔問答用例中實(shí)現(xiàn)最佳性能所需的微調(diào)。而lama-2 - 7b - chat模型是我們的理想候選,因?yàn)樗菫閷υ捄蛦柎鸲O(shè)計(jì)的。該模型被許可(部分)用于商業(yè)用途。這是因?yàn)榻?jīng)過微調(diào)的模型lama-2- chat模型利用了公開可用的指令數(shù)據(jù)集和超過100萬個(gè)人工注釋。
4、8位量化
考慮到RAM被限制為16GB, 8位GGML版本是合適的,因?yàn)樗恍枰?.6GB的內(nèi)存而原始的非量化16位模型需要約15gb的內(nèi)存
8位格式也提供了與16位相當(dāng)?shù)捻憫?yīng)質(zhì)量,而其他更小的量化格式(即4位和5位)是可用的,但它們是以準(zhǔn)確性和響應(yīng)質(zhì)量為代價(jià)的。
構(gòu)建步驟指導(dǎo)
我們已經(jīng)了解了各種組件,接下來讓逐步介紹如何構(gòu)建文檔問答應(yīng)用程序。
由于已經(jīng)有許多教程了,所以我們不會深入到復(fù)雜和一般的文檔問答組件的細(xì)節(jié)(例如,文本分塊,矢量存儲設(shè)置)。在本文中,我們將把重點(diǎn)放在開源LLM和CPU推理方面。
1、數(shù)據(jù)處理和矢量存儲
這一步的任務(wù)是:將文本分割成塊,加載嵌入模型,然后通過FAISS 進(jìn)行向量的存儲
from langchain.vectorstores import FAISS
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.document_loaders import PyPDFLoader, DirectoryLoader
from langchain.embeddings import HuggingFaceEmbeddings
# Load PDF file from data path
loader = DirectoryLoader('data/',
glob="*.pdf",
loader_cls=PyPDFLoader)
documents = loader.load()
# Split text from PDF into chunks
text_splitter = RecursiveCharacterTextSplitter(chunk_size=500,
chunk_overlap=50)
texts = text_splitter.split_documents(documents)
# Load embeddings model
embeddings = HuggingFaceEmbeddings(model_name='sentence-transformers/all-MiniLM-L6-v2',
model_kwargs={'device': 'cpu'})
# Build and persist FAISS vector store
vectorstore = FAISS.from_documents(texts, embeddings)
vectorstore.save_local('vectorstore/db_faiss')
運(yùn)行上面的Python腳本后,向量存儲將被生成并保存在名為’vectorstore/db_faiss’的本地目錄中,并為語義搜索和檢索做好準(zhǔn)備。
2、設(shè)置提示模板
我們使用lama-2 - 7b - chat模型,所以需要使用的提示模板。
一些chat的模板在這里不起作用,因?yàn)槲覀兊腖lama 2模型沒有針對這種會話界面進(jìn)行專門優(yōu)化。所以我們需要使用更加直接的模板,例如:
qa_template = """Use the following pieces of information to answer the user's question.
If you don't know the answer, just say that you don't know, don't try to make up an answer.
Context: {context}
Question: {question}
Only return the helpful answer below and nothing else.
Helpful answer:
"""
需要注意的是,相對較小的LLM(如7B),對格式特別敏感。當(dāng)改變提示模板的空白和縮進(jìn)時(shí),可能得到了稍微不同的輸出。
3、下載lama-2 - 7b - chat GGML二進(jìn)制文件
由于我們將在本地運(yùn)行LLM,所以需要下載量化的lama-2 - 7b - chat模型的二進(jìn)制文件。
我們可以通過訪問TheBloke的Llama-2-7B-Chat GGML頁面來實(shí)現(xiàn),然后下載名為Llama-2-7B-Chat .ggmlv3.q8_0.bin的GGML 8位量化文件。
下載的是8位量化模型的bin文件可以保存在合適的項(xiàng)目子文件夾中,如/models。
這個(gè)頁面還顯示了每種量化格式的更多信息和詳細(xì)信息:
4、LangChain集成
我們將利用C transformer和LangChain進(jìn)行集成。也就是說將在LangChain中使用CTransformers LLM包裝器,它為GGML模型提供了一個(gè)統(tǒng)一的接口。
from langchain.llms import CTransformers
# Local CTransformers wrapper for Llama-2-7B-Chat
llm = CTransformers(model='models/llama-2-7b-chat.ggmlv3.q8_0.bin', # Location of downloaded GGML model
model_type='llama', # Model type Llama
config={'max_new_tokens': 256,
'temperature': 0.01})
這里就可以為LLM定義大量配置設(shè)置,例如最大令牌、最高k值、溫度和重復(fù)懲罰等等,這些參數(shù)在我們以前的文章已經(jīng)介紹過了。
這里我將溫度設(shè)置為0.01而不是0,因?yàn)樵O(shè)置成0時(shí),得到了奇怪的響應(yīng)。
5、構(gòu)建并初始化RetrievalQA
準(zhǔn)備好提示模板和C Transformers LLM后,我們還需要編寫了三個(gè)函數(shù)來構(gòu)建LangChain RetrievalQA對象,該對象使我們能夠執(zhí)行文檔問答。
from langchain import PromptTemplate
from langchain.chains import RetrievalQA
from langchain.embeddings import HuggingFaceEmbeddings
from langchain.vectorstores import FAISS
# Wrap prompt template in a PromptTemplate object
def set_qa_prompt():
prompt = PromptTemplate(template=qa_template,
input_variables=['context', 'question'])
return prompt
# Build RetrievalQA object
def build_retrieval_qa(llm, prompt, vectordb):
dbqa = RetrievalQA.from_chain_type(llm=llm,
chain_type='stuff',
retriever=vectordb.as_retriever(search_kwargs={'k':2}),
return_source_documents=True,
chain_type_kwargs={'prompt': prompt})
return dbqa
# Instantiate QA object
def setup_dbqa():
embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2",
model_kwargs={'device': 'cpu'})
vectordb = FAISS.load_local('vectorstore/db_faiss', embeddings)
qa_prompt = set_qa_prompt()
dbqa = build_retrieval_qa(llm, qa_prompt, vectordb)
return dbqa
6、代碼整合
最后一步就是是將前面的組件組合到main.py腳本中。使用argparse模塊是因?yàn)槲覀儗拿钚袑⒂脩舨樵儌鬟f到應(yīng)用程序中。
這里為了評估CPU推理的速度,還使用了timeit模塊。
import argparse
import timeit
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument('input', type=str)
args = parser.parse_args()
start = timeit.default_timer() # Start timer
# Setup QA object
dbqa = setup_dbqa()
# Parse input from argparse into QA object
response = dbqa({'query': args.input})
end = timeit.default_timer() # End timer
# Print document QA response
print(f'\nAnswer: {response["result"]}')
print('='*50) # Formatting separator
# Process source documents for better display
source_docs = response['source_documents']
for i, doc in enumerate(source_docs):
print(f'\nSource Document {i+1}\n')
print(f'Source Text: {doc.page_content}')
print(f'Document Name: {doc.metadata["source"]}')
print(f'Page Number: {doc.metadata["page"]}\n')
print('='* 50) # Formatting separator
# Display time taken for CPU inference
print(f"Time to retrieve response: {end - start}")
示例查詢
現(xiàn)在是時(shí)候?qū)ξ覀兊膽?yīng)用程序進(jìn)行測試了。我們用以下命令詢問阿迪達(dá)斯(曼聯(lián)的全球技術(shù)贊助商)應(yīng)支付的最低保證金額:
python main.py "How much is the minimum guarantee payable by adidas?"
結(jié)果如下:
我們成功地獲得了正確響應(yīng)(即£7.5億),以及語義上與查詢相似的相關(guān)文檔塊。
從啟動應(yīng)用程序并生成響應(yīng)的總時(shí)間為31秒,這是相當(dāng)不錯(cuò)的,因?yàn)檫@只是在AMD Ryzen 5600X(中低檔的消費(fèi)級CPU)上本地運(yùn)行它。并且在gpu上運(yùn)行LLM推理(例如,直接在HuggingFace上運(yùn)行)也需要兩位數(shù)的時(shí)間,所以在CPU上量化運(yùn)行的結(jié)果是非常不錯(cuò)的。
作者:Kenneth Leung
相關(guān)資源文章來源:http://www.zghlxwxcb.cn/news/detail-600048.html
https://avoid.overfit.cn/post/9df8822ed2854176b68585226485ee0f文章來源地址http://www.zghlxwxcb.cn/news/detail-600048.html
到了這里,關(guān)于使用GGML和LangChain在CPU上運(yùn)行量化的llama2的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!