大型語言模型(llm)是指能夠生成與人類語言非常相似的文本并以自然方式理解提示的機器學習模型。這些模型使用廣泛的數(shù)據(jù)集進行訓練,這些數(shù)據(jù)集包括書籍、文章、網(wǎng)站和其他來源。通過分析數(shù)據(jù)中的統(tǒng)計模式,LLM可以預測給定輸入后最可能出現(xiàn)的單詞或短語。
在本文中,我將演示如何利用LLaMA 7b和Langchain從頭開始創(chuàng)建自己的Document Assistant。
在這篇文章中,我將展示從頭開始創(chuàng)建自己的文檔助手的過程,利用LLaMA 7b和Langchain,一個專門為與LLM無縫集成而開發(fā)的開源庫。
以下是該博客的結構概述,概述了具體的章節(jié),將詳細介紹該過程:
LangChain是一個令人印象深刻且免費的框架,它徹底改變了廣泛應用的開發(fā)過程,包括聊天機器人、生成式問答(GQA)和摘要。通過將來自多個模塊的組件無縫鏈接,LangChain能夠使用大部分的llm來創(chuàng)建應用程序。
LangChain徹底改變了各種應用的開發(fā)過程,包括聊天機器人、生成性問題回答(GQA)和總結。通過將來自多個模塊的組件無縫連接在一起,LangChain可以圍繞LLM的力量創(chuàng)建特殊的應用程序。
LLaMA是由Facebook的母公司Meta AI設計的一個新的大型語言模型。LLaMA擁有70億到650億個參數(shù)的模型集合,是目前最全面的語言模型之一。2023年2月24日,Meta向公眾發(fā)布了LLaMA模型,展示了他們對開放科學的奉獻精神(雖然我們現(xiàn)在用的都是泄露版)。
考慮到LLaMA的卓越能力,我們選擇利用這個強大的語言模型來達到我們的目的。具體來說,我們將采用最小的LLaMA版本,稱為LLaMA 7B。即使在這個縮小的版本中,LLaMA 7B也提供了重要的語言處理能力,使我們能夠有效地實現(xiàn)我們的預期結果。
官方研究論文:LLaMA: Open and Efficient Foundation Language Models
為了在本地CPU上執(zhí)行LLM,我們需要一個GGML格式的本地模型。有幾種方法可以實現(xiàn)這一點,但最簡單的方法是直接從Hugging Face Models資源庫??下載bin文件。在我們的案例中,我們將下載Llama 7B模型。這些模型是開源的,可以免費下載。這里強烈推薦關注@公眾號:數(shù)據(jù)STUDIO ,每日定時推送經(jīng)典好文。
GGML是一個用于機器學習的張量庫,它只是一個c++庫,允許你在CPU或CPU + GPU上運行l(wèi)lm。它定義了用于分發(fā)大型語言模型(llm)的二進制格式。GGML使用了一種稱為量化的技術,該技術允許大型語言模型在消費者硬件上運行。
我們都知道,模型的權重是浮點數(shù)。就像表示大整數(shù)(例如1000)比表示小整數(shù)(例如1)需要更多的空間一樣,表示高精度浮點數(shù)(例如0.0001)比表示低精度浮點數(shù)(例如0.1)需要更多的空間。量化大型語言模型的過程涉及降低表示權重的精度,以減少使用模型所需的資源。GGML支持許多不同的量化策略(例如4位、5位和8位量化),每種策略在效率和性能之間提供不同的權衡。
下面是量化后模型大小的對比:
Streamlit 是一個用于構建數(shù)據(jù)科學和機器學習應用程序的開源 Python 庫。它旨在使開發(fā)人員能夠以簡單快速的方式構建交互式應用程序,無需繁瑣的前端開發(fā)。Streamlit 提供了一組簡單的 API,可用于創(chuàng)建具有數(shù)據(jù)探索、可視化和交互功能的應用程序。只需要通過簡單的 Python 腳本就可以創(chuàng)建一個 Web 應用程序??梢岳?Streamlit 的豐富組件庫來構建用戶界面,例如文本框、滑塊、下拉菜單和按鈕,以及可視化組件,例如圖表和地圖。
在模型的文件夾中,將存儲將下載的LLM,而pip文件將位于根目錄中。
設置虛擬環(huán)境為運行應用程序提供了一個受控和隔離的環(huán)境,確保其依賴關系與其他系統(tǒng)范圍的包分離。這種方法簡化了依賴關系的管理,并有助于維護不同環(huán)境之間的一致性。
然后就是創(chuàng)建我們的項目,一個好的結構會加速我們的開發(fā),如下圖所示
在models的文件夾中,我們要存儲下載的llm,setup_env.bat將從pipfile中安裝所有依賴項。而run_app.bat則是直接運行我們的app。(以上2個文件都是windows環(huán)境下的腳本)
為了有效地使用模型,必須考慮內存和磁盤。由于模型需要完全加載到內存中,因此不僅需要有足夠的磁盤空間來存儲它們,還需要足夠的RAM在執(zhí)行期間加載它們。比如65B模型,即使在量化之后,也需要40gb的RAM。
所以為了在本地運行,我們將使用最小版本的LLaMA,也就是LLaMA 7B。雖然它是最小的版本,但是LLaMA 7B也提供了很好的語言處理能力,我們能夠高效地實現(xiàn)預期的結果。
為了在本地CPU上執(zhí)行LLM,我們使用GGML格式的本地模型。這里直接從Hugging Face Models存儲庫直接下載bin文件,然后將文件移動到根目錄下的models目錄中。
上面我們已經(jīng)是說了,GGML是c++庫,所以還需要使用Python調用C++的接口,好在這一步很簡單,我們將使用llama-cpp-python,這是LLaMA .cpp的Python綁定,它在純C/ c++中充當LLaMA模型的推理。cpp的主要目標是使用4位整數(shù)量化來運行LLaMA模型。這樣可以可以有效地利用LLaMA模型,充分利用C/ c++的速度優(yōu)勢和4位整數(shù)量化??的優(yōu)勢。
llama.cpp還支持很多其他模型,下圖是列表:
準備好GGML模型和所有依賴項之后,就可以開始LangChain進行集成了。但是在開始之前,我們還需要做一下測試,保證我們的LLaMA在本地使可用的:
看樣子沒有任何問題,并且程序是完全脫機并以完全隨機的方式(可以使用溫度超參數(shù))運行的。這里強烈推薦關注@公眾號:數(shù)據(jù)STUDIO ,每日定時推送經(jīng)典好文。
現(xiàn)在我們可以利用LangChain框架來開發(fā)使用llm的應用程序。
為了提供與llm的無縫交互,LangChain提供了幾個類和函數(shù),可以使用提示模板輕松構建和使用提示。它包含一個文本字符串模板,可以接受來自最終用戶的一組參數(shù)并生成提示符。讓我們先看幾個例子。
下面我們可以使用LangChain進行集成了
繼續(xù)對LLM進行提示
目前我們使用了單獨的組件,通過提示模板對其進行格式化,然后使用llm,在llm中傳遞這些參數(shù)以生成答案。對于簡單的應用程序,單獨使用LLM是可以的,但是更復雜的應用程序需要將LLM鏈接起來——要么相互鏈接,要么與其他組件鏈接。
LangChain為這種鏈接??應用程序提供了Chain接口。我們可以將Chain定義為對組件的調用序列,其中可以包含其他Chain。Chain允許我們將多個組件組合在一起,以創(chuàng)建一個單一的、一致的應用程序。例如,可以創(chuàng)建一個Chain,它接受用戶輸入,使用Prompt Template對其進行格式化,然后將格式化后的響應傳遞給LLM。我們可以通過將多個Chain組合在一起,或者與其他組件組合在一起,來構建更復雜的Chain。這其實就和我們一般數(shù)據(jù)處理中的pipeline是類似的。
創(chuàng)建一個非常簡單的Chain??,它將接受用戶輸入,用它格式化提示符,然后使用我們已經(jīng)創(chuàng)建的上述各個組件將其發(fā)送到LLM。
在許多LLM應用程序中,需要特定于用戶的數(shù)據(jù),這些數(shù)據(jù)不包括在模型的訓練集中。LangChain提供了加載、轉換、存儲和查詢數(shù)據(jù)的基本組件,我們這里可以直接使用
上圖包含了5個組件:
我們將實現(xiàn)這五個步驟,流程圖如所提供的下圖所示。
我們這里使用維基百科上復制的一段關于一些DC超級英雄的文本作為開發(fā)測試使用。原文如下:
使用文本加載器創(chuàng)建一個文檔對象(Lang chain提供了對多個文檔的支持,可以根據(jù)文檔使用不同的加載器),使用load方法檢索數(shù)據(jù),并將其作為文檔從預配置的源加載。
加載文檔之后,通過將其分解為更小的塊來繼續(xù)轉換過程。使用TextSplitter(默認情況下,拆分器以' \n\n '分隔符分隔文檔)。如果將分隔符設置為null并定義特定的塊大小,則每個塊將具有指定的長度。這樣就得到了列表長度將等于文檔的長度除以塊大小的一個塊列表。
詞嵌入只是一個詞的向量表示,向量包含實數(shù)。詞嵌入通過在低維向量空間中提供詞的密集表示來解決簡單的二進制單詞向量由于維數(shù)高的問題。
LangChain中的基Embeddings類公開了兩個方法:一個用于嵌入文檔,另一個用于嵌入查詢。前者接受多個文本作為輸入,后者接受單個文本作為輸入。
因為后面的檢索也是檢索嵌入在相同潛在空間中最相似的向量,所以詞向量必須使用相同的方法(模型)生成。
矢量存儲有效地管理嵌入數(shù)據(jù)的存儲,并加速矢量搜索操作。我們將使用Chroma,一個專門用于簡化包含嵌入的人工智能應用程序的開發(fā)的矢量數(shù)據(jù)庫。它提供了一套全面的內置工具和函數(shù),我們只需要使用 pip install chromadb 命令將它安裝在本地。
現(xiàn)在我們可以存儲和檢索向量了,下面就是與LLM來整合了。
到這一步,已經(jīng)可以使用本地運行的LLM構建問答機器人了,這個結果還不錯,但是我們還有更好的要求,就是一個GUI界面。
如果你只喜歡命令行的方式運行,則這一節(jié)是完全可選的。因為在這里我們將創(chuàng)建一個允許用戶上傳任何文本文檔的WEB程序。可以通過文本輸入提出問題,來對文檔進行分析。
因為涉及到文件上傳,所以為了防止?jié)撛诘膬却娌蛔沐e誤,這里只將簡單地讀取文檔并將其寫入臨時文件夾中并重命名為raw.txt。這樣無論文檔的原始名稱是什么,Textloader都將在將來無縫地處理它(我們這里假設:單用戶同時只處理一個文件)。
我們也只處理txt文件,代碼如下:
import streamlit as st
from langchain.llms import LlamaCpp
from langchain.embeddings import LlamaCppEmbeddings
from langchain.prompts import PromptTemplate
from langchain.chains import LLMChain
from langchain.document_loaders import TextLoader
from langchain.text_splitter import CharacterTextSplitter
from langchain.vectorstores import Chroma
# 強烈推薦關注@公眾號:數(shù)據(jù)STUDIO
# 每日好文準時推送
# Customize the layout
st.set_page_config(page_title='DOCAI', page_icon='??', layout='wide', )
st.markdown(f'''
<style>
.stApp {{background-image: url('https://images.unsplash.com/photo-1509537257950-20f875b03669?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1469&q=80');
background-attachment: fixed;
background-size: cover}}
</style>
''', unsafe_allow_html=True)
# function for writing uploaded file in temp
def write_text_file(content, file_path):
try:
with open(file_path, 'w') as file:
file.write(content)
return True
except Exception as e:
print(f'Error occurred while writing the file: {e}')
return False
# set prompt template
prompt_template = '''Use the following pieces of context to answer the question at the end. If you don't know the answer, just say that you don't know, don't try to make up an answer.
{context}
Question: {question}
Answer:'''
prompt = PromptTemplate(template=prompt_template, input_variables=['context', 'question'])
# initialize hte LLM & Embeddings
llm = LlamaCpp(model_path='./models/llama-7b.ggmlv3.q4_0.bin')
embeddings = LlamaCppEmbeddings(model_path='models/llama-7b.ggmlv3.q4_0.bin')
llm_chain = LLMChain(llm=llm, prompt=prompt)
st.title('?? Document Conversation ??')
uploaded_file = st.file_uploader('Upload an article', type='txt')
if uploaded_file is not None:
content = uploaded_file.read().decode('utf-8')
# st.write(content)
file_path = 'temp/file.txt'
write_text_file(content, file_path)
loader = TextLoader(file_path)
docs = loader.load()
text_splitter = CharacterTextSplitter(chunk_size=100, chunk_overlap=0)
texts = text_splitter.split_documents(docs)
db = Chroma.from_documents(texts, embeddings)
st.success('File Loaded Successfully!!')
# Query through LLM
question = st.text_input('Ask something from the file', placeholder='Find something similar to: ....this.... in the text?', disabled=not uploaded_file,)
if question:
similar_doc = db.similarity_search(question, k=1)
context = similar_doc[0].page_content
query_llm = LLMChain(llm=llm, prompt=prompt)
response = query_llm.run({'context': context, 'question': question})
st.write(response)
看看我們的界面:
這樣一個簡單的并且可以使用的程序就完成了。
通過LangChain和Streamlit我們可以方便的整合任何的LLM模型,并且通過GGML我們可以將大模型運行在消費級的硬件中,這對我們個人研究來說使非常有幫助的。
作者:Afaque Umer
聯(lián)系客服