本地部署開源大模型的完整教程:LangChain - Streamlit- Llama

在過去的幾個月裏,大型語言模型 (llm) 獲得了極大的關注,這些模型創造了令人興奮的前景,特別是對於從事聊天機器人、個人助理和內容創作的開發人員。

大型語言模型 (llm) 是指能夠生成與人類語言非常相似的文本並以自然方式理解提示的機器學習模型。這些模型使用廣泛的數據集進行訓練,這些數據集包括書籍、文章、網站和其他來源。通過分析數據中的統計模式,LLM 可以預測給定輸入後最可能出現的單詞或短語。

目前的 LLM 的一個全景圖

在本文中,我將演示如何利用 LLaMA 7b 和 Langchain 從頭開始創建自己的 Document Assistant。

背景知識

在這篇文章中,我將展示從頭開始創建自己的文檔助手的過程,利用 LLaMA 7b 和 Langchain,一個專門爲與 LLM 無縫集成而開發的開源庫。

以下是該博客的結構概述,概述了具體的章節,將詳細介紹該過程:

  1. 設置虛擬環境和創建文件結構

  2. 在你的本地機器上設置 LLM

  3. 將 LLM 與 LangChain 整合並定製 PromptTemplate

  4. 文件檢索和答案生成

  5. 使用 Streamlit 建立應用程序

1、LangChain 🔗

LangChain 是一個令人印象深刻且免費的框架,它徹底改變了廣泛應用的開發過程,包括聊天機器人、生成式問答 (GQA) 和摘要。通過將來自多個模塊的組件無縫鏈接,LangChain 能夠使用大部分的 llm 來創建應用程序。

LangChain 徹底改變了各種應用的開發過程,包括聊天機器人、生成性問題回答(GQA)和總結。通過將來自多個模塊的組件無縫連接在一起,LangChain 可以圍繞 LLM 的力量創建特殊的應用程序。

2、LLaMA 🦙

LLaMA 是由 Facebook 的母公司 Meta AI 設計的一個新的大型語言模型。LLaMA 擁有 70 億到 650 億個參數的模型集合,是目前最全面的語言模型之一。2023 年 2 月 24 日,Meta 向公衆發佈了 LLaMA 模型,展示了他們對開放科學的奉獻精神(雖然我們現在用的都是泄露版)。

考慮到 LLaMA 的卓越能力,我們選擇利用這個強大的語言模型來達到我們的目的。具體來說,我們將採用最小的 LLaMA 版本,稱爲 LLaMA 7B。即使在這個縮小的版本中,LLaMA 7B 也提供了重要的語言處理能力,使我們能夠有效地實現我們的預期結果。

官方研究論文:LLaMA: Open and Efficient Foundation Language Models

爲了在本地 CPU 上執行 LLM,我們需要一個 GGML 格式的本地模型。有幾種方法可以實現這一點,但最簡單的方法是直接從 Hugging Face Models 資源庫🤗下載 bin 文件。在我們的案例中,我們將下載 Llama 7B 模型。這些模型是開源的,可以免費下載。這裏強烈推薦關注 @公衆號:數據 STUDIO ,每日定時推送經典好文。

3、什麼是 GGML

GGML 是一個用於機器學習的張量庫,它只是一個 c++ 庫,允許你在 CPU 或 CPU + GPU 上運行 llm。它定義了用於分發大型語言模型 (llm) 的二進制格式。GGML 使用了一種稱爲量化的技術,該技術允許大型語言模型在消費者硬件上運行。

4、量化

我們都知道,模型的權重是浮點數。就像表示大整數 (例如 1000) 比表示小整數 (例如 1) 需要更多的空間一樣,表示高精度浮點數 (例如 0.0001) 比表示低精度浮點數 (例如 0.1) 需要更多的空間。量化大型語言模型的過程涉及降低表示權重的精度,以減少使用模型所需的資源。GGML 支持許多不同的量化策略(例如 4 位、5 位和 8 位量化),每種策略在效率和性能之間提供不同的權衡。

‍下面是量化後模型大小的對比:

5、Streamlit🔥

Streamlit 是一個用於構建數據科學和機器學習應用程序的開源 Python  庫。它旨在使開發人員能夠以簡單快速的方式構建交互式應用程序,無需繁瑣的前端開發。Streamlit 提供了一組簡單的  API,可用於創建具有數據探索、可視化和交互功能的應用程序。只需要通過簡單的 Python 腳本就可以創建一個 Web 應用程序。可以利用 Streamlit 的豐富組件庫來構建用戶界面,例如文本框、滑塊、下拉菜單和按鈕,以及可視化組件,例如圖表和地圖。

1、建立虛擬環境和項目結構

在模型的文件夾中,將存儲將下載的 LLM,而 pip 文件將位於根目錄中。

設置虛擬環境爲運行應用程序提供了一個受控和隔離的環境,確保其依賴關係與其他系統範圍的包分離。這種方法簡化了依賴關係的管理,並有助於維護不同環境之間的一致性。

然後就是創建我們的項目,一個好的結構會加速我們的開發,如下圖所示

文件結構

在 models 的文件夾中,我們要存儲下載的 llm,setup_env.bat 將從 pipfile 中安裝所有依賴項。而 run_app.bat 則是直接運行我們的 app。(以上 2 個文件都是 windows 環境下的腳本)

2、在本地機器上安裝 LLaMA

爲了有效地使用模型,必須考慮內存和磁盤。由於模型需要完全加載到內存中,因此不僅需要有足夠的磁盤空間來存儲它們,還需要足夠的 RAM 在執行期間加載它們。比如 65B 模型,即使在量化之後,也需要 40gb 的 RAM。

所以爲了在本地運行,我們將使用最小版本的 LLaMA,也就是 LLaMA 7B。雖然它是最小的版本,但是 LLaMA 7B 也提供了很好的語言處理能力,我們能夠高效地實現預期的結果。

爲了在本地 CPU 上執行 LLM,我們使用 GGML 格式的本地模型。這裏直接從 Hugging Face Models 存儲庫直接下載 bin 文件,然後將文件移動到根目錄下的 models 目錄中。

上面我們已經是說了,GGML 是 c++ 庫,所以還需要使用 Python 調用 C++ 的接口,好在這一步很簡單,我們將使用 llama-cpp-python,這是 LLaMA .cpp 的 Python 綁定,它在純 C/ c++ 中充當 LLaMA 模型的推理。cpp 的主要目標是使用 4 位整數量化來運行 LLaMA 模型。這樣可以可以有效地利用 LLaMA 模型,充分利用 C/ c++ 的速度優勢和 4 位整數量化🚀的優勢。

llama.cpp 還支持很多其他模型,下圖是列表:

準備好 GGML 模型和所有依賴項之後,就可以開始 LangChain 進行集成了。但是在開始之前,我們還需要做一下測試,保證我們的 LLaMA 在本地使可用的:

看樣子沒有任何問題,並且程序是完全脫機並以完全隨機的方式 (可以使用溫度超參數) 運行的。這裏強烈推薦關注 @公衆號:數據 STUDIO ,每日定時推送經典好文。

3、LangChain 集成 LLM

現在我們可以利用 LangChain 框架來開發使用 llm 的應用程序。

爲了提供與 llm 的無縫交互,LangChain 提供了幾個類和函數,可以使用提示模板輕鬆構建和使用提示。它包含一個文本字符串模板,可以接受來自最終用戶的一組參數並生成提示符。讓我們先看幾個例子。

沒有輸入參數的模板多個參數的模板

下面我們可以使用 LangChain 進行集成了

繼續對 LLM 進行提示

目前我們使用了單獨的組件,通過提示模板對其進行格式化,然後使用 llm,在 llm 中傳遞這些參數以生成答案。對於簡單的應用程序,單獨使用 LLM 是可以的,但是更復雜的應用程序需要將 LLM 鏈接起來——要麼相互鏈接,要麼與其他組件鏈接。

LangChain 爲這種鏈接🔗應用程序提供了 Chain 接口。我們可以將 Chain 定義爲對組件的調用序列,其中可以包含其他 Chain。Chain 允許我們將多個組件組合在一起,以創建一個單一的、一致的應用程序。例如,可以創建一個 Chain,它接受用戶輸入,使用 Prompt Template 對其進行格式化,然後將格式化後的響應傳遞給 LLM。我們可以通過將多個 Chain 組合在一起,或者與其他組件組合在一起,來構建更復雜的 Chain。這其實就和我們一般數據處理中的 pipeline 是類似的。

創建一個非常簡單的 Chain🔗,它將接受用戶輸入,用它格式化提示符,然後使用我們已經創建的上述各個組件將其發送到 LLM。

4、生成嵌入和向量庫

在許多 LLM 應用程序中,需要特定於用戶的數據,這些數據不包括在模型的訓練集中。LangChain 提供了加載、轉換、存儲和查詢數據的基本組件,我們這裏可以直接使用

上圖包含了 5 個組件:

我們將實現這五個步驟,流程圖如所提供的下圖所示。

我們這裏使用維基百科上覆制的一段關於一些 DC 超級英雄的文本作爲開發測試使用。原文如下:

a. 加載和轉換文檔

使用文本加載器創建一個文檔對象(Lang chain 提供了對多個文檔的支持,可以根據文檔使用不同的加載器),使用 load 方法檢索數據,並將其作爲文檔從預配置的源加載。

加載文檔之後,通過將其分解爲更小的塊來繼續轉換過程。使用 TextSplitter(默認情況下,拆分器以'\n\n'分隔符分隔文檔)。如果將分隔符設置爲 null 並定義特定的塊大小,則每個塊將具有指定的長度。這樣就得到了列表長度將等於文檔的長度除以塊大小的一個塊列表。

b.Embeddings

詞嵌入只是一個詞的向量表示,向量包含實數。詞嵌入通過在低維向量空間中提供詞的密集表示來解決簡單的二進制單詞向量由於維數高的問題。

LangChain 中的基 Embeddings 類公開了兩個方法: 一個用於嵌入文檔,另一個用於嵌入查詢。前者接受多個文本作爲輸入,後者接受單個文本作爲輸入。

因爲後面的檢索也是檢索嵌入在相同潛在空間中最相似的向量,所以詞向量必須使用相同的方法(模型)生成。

c. 創建存儲和檢索文檔

矢量存儲有效地管理嵌入數據的存儲,並加速矢量搜索操作。我們將使用 Chroma,一個專門用於簡化包含嵌入的人工智能應用程序的開發的矢量數據庫。它提供了一套全面的內置工具和函數,我們只需要使用 pip install chromadb 命令將它安裝在本地。

現在我們可以存儲和檢索向量了,下面就是與 LLM 來整合了。

到這一步,已經可以使用本地運行的 LLM 構建問答機器人了,這個結果還不錯,但是我們還有更好的要求,就是一個 GUI 界面。

5、Streamlit

如果你只喜歡命令行的方式運行,則這一節是完全可選的。因爲在這裏我們將創建一個允許用戶上傳任何文本文檔的 WEB 程序。可以通過文本輸入提出問題,來對文檔進行分析。

因爲涉及到文件上傳,所以爲了防止潛在的內存不足錯誤,這裏只將簡單地讀取文檔並將其寫入臨時文件夾中並重命名爲 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
 
 # 強烈推薦關注@公衆號:數據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

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/7HiGfXY9Cfb6K6b3_XEiIQ