深度學習模型的開發和佈署流程通常涉及多個框架和平臺,這使得模型的轉換和佈署變得複雜。ONNX 作為一種開放的模型交換格式,能有效解決這個問題。它允許開發者將訓練好的模型從一個框架(例如 PyTorch)轉換到另一個框架(例如 TensorFlow),並在不同的平臺上佈署。同時,結合 LangChain 和 MLOps 等工具,可以進一步簡化模型開發、佈署和管理流程,提高效率並降低成本。本文將詳細介紹 ONNX 的使用方法,並結合 LangChain 和 MLOps 的應用,提供一個更全面的模型開發和佈署。
實作細節
以下是實作微調轉換器的細節:
from datasets import load_dataset
from transformers import AutoTokenizer, AutoModelForSequenceClassification
# 載入資料集
dataset = load_dataset('rotten_tomatoes')
# 載入預訓練模型
tokenizer = AutoTokenizer.from_pretrained('distilbert-base-uncased')
model = AutoModelForSequenceClassification.from_pretrained('distilbert-base-uncased')
# 建立資料集類別
tok_dataset = dataset.map(
lambda x: tokenizer(
text=x['text'],
padding='max_length',
truncation=True
),
batched=True
)
# 定義訓練迴圈
def train(model, dataset, epochs):
for epoch in range(epochs):
# 前向傳播
outputs = model(**dataset)
# 反向傳播
loss = outputs.loss
# 最佳化器更新
optimizer = torch.optim.Adam(model.parameters(), lr=1e-5)
optimizer.zero_grad()
loss.backward()
optimizer.step()
# 訓練模型
train(model, tok_dataset, epochs=5)
這個程式碼載入了資料集和預訓練模型,建立了資料集類別,定義了訓練迴圈,然後訓練了模型。
使用 Transformers 進行文字分類別
在本文中,我們將使用 Transformers 進行文字分類別任務。首先,我們需要載入 DistilBERT 的組態,並為二元分類別任務設定模型頭。這個組態適合我們的任務,因為我們需要將電影評論分類別為兩個類別。
初始化 TrainingArguments
接下來,我們需要初始化 TrainingArguments 來指定模型預測和檢查點的輸出位置。我們還會在每個 epoch 後進行評估。
from transformers import TrainingArguments
training_args = TrainingArguments(
output_dir='test_trainer',
evaluation_strategy='epoch'
)
初始化準確度評估指標
然後,我們需要初始化準確度評估指標。
import evaluate
accuracy = evaluate.load('accuracy')
初始化 Trainer
現在,我們可以初始化 Trainer 並傳入所有必要的元件,包括模型、訓練資料集、評估資料集和 TrainingArguments。
from transformers import Trainer
import numpy as np
trainer = Trainer(
model=model,
train_dataset=tok_dataset['train'],
eval_dataset=tok_dataset['test'],
args=training_args,
compute_metrics=lambda x: {'accuracy': accuracy.compute(
predictions=np.argmax(x.predictions, axis=-1),
references=x.label_ids
)},
preprocess_logits_for_metrics=lambda x, _: np.argmax(x.cpu(), axis=-1)
)
執行訓練
最後,我們可以執行訓練。
trainer.train()
這個模型在三個 epoch 後可以達到大約 85% 的準確度。
圖表翻譯:
flowchart TD A[載入 DistilBERT 組態] --> B[設定模型頭] B --> C[初始化 TrainingArguments] C --> D[初始化準確度評估指標] D --> E[初始化 Trainer] E --> F[執行訓練] F --> G[模型達到 85% 準確度]
此圖表展示了使用 Transformers 進行文字分類別的流程,從載入 DistilBERT 組態到執行訓練,並最終達到 85% 的準確度。
Harnessing the Power of LLMs with LangChain
LangChain是一個強大的框架,能夠幫助我們克服LLM的限制,例如上下文視窗長度和知識更新問題。它提供了多個模組,包括Model I/O、Retrieval、Chains、Memory、Agents和Callbacks。
Model I/O
Model I/O模組提供了幫助器提示範本,讓我們可以輕鬆地與LLM互動。它支援兩種型別的模型:經典LLM和聊天模型。經典LLM可以使用單個提示生成回應,而聊天模型則需要與人類進行互動式對話。
Retrieval
Retrieval模組可以從外部資料源中檢索資料,並將其餵入LLM的輸入序列中。它支援多種資料格式,包括CSV和JSON,並可以將大檔案分割成小塊以適應上下文視窗大小。
Chains
Chains模組允許我們組合多個LangChain元件,建立一個單一的應用程式。例如,我們可以建立一個鏈條,接收使用者輸入,格式化它,然後餵入LLM,然後解析LLM的輸出為JSON。
Memory
Memory模組維護輸入令牌序列在鏈條中的步驟或模型與外部世界的互動中。它可以動態地修改和擴充套件序列,並使用LLM的新興能力建立序列的摘要。
Agents
Agents模組允許我們建立可以與環境互動的實體。LLM作為代理的推理引擎,決定代理採取哪些行動和順序。代理可以使用特殊功能,例如API呼叫或其他鏈條。
Callbacks
Callbacks模組允許我們在LLM應用程式的各個點插入程式碼,例如日誌記錄、監控或流式傳輸。
實踐中的LangChain
讓我們使用LangChain解答一個問題:地球上最深的海洋部分和最高的山峰的海拔之和是多少?我們將使用LangChain的API包裝器、搜尋工具和計算器工具來解答這個問題。
首先,我們初始化LangChain的API包裝器,然後定義搜尋工具和計算器工具。搜尋工具使用SerpAPI進行Google搜尋,而計算器工具使用特殊的幾次學習LangChain提示範本來查詢LLM計算數學方程式。
from langchain.chat_models import ChatOpenAI
from langchain.agents.tools import Tool
from langchain import SerpAPIWrapper
model = ChatOpenAI(temperature=0)
search = Tool(
name='Search',
func=SerpAPIWrapper().run,
description='Google search tool'
)
calculator = Tool(
name='Calculator',
func=lambda x: eval(x),
description='Calculator tool'
)
圖表翻譯:
此圖示為LangChain的架構圖,展示了其各個模組之間的關係。Model I/O模組負責與LLM互動,Retrieval模組負責從外部資料源中檢索資料,Chains模組允許組合多個元件,Memory模組維護輸入令牌序列,Agents模組允許建立可以與環境互動的實體,Callbacks模組允許在LLM應用程式的各個點插入程式碼。
flowchart TD A[Model I/O] --> B[Retrieval] B --> C[Chains] C --> D[Memory] D --> E[Agents] E --> F[Callbacks]
LangChain與LLM的應用
LangChain是一個強大的工具,能夠與大語言模型(LLM)合作,實作複雜任務的自動化。以下是使用LangChain和LLM解答問題的步驟:
初始化LLM和工具
首先,需要初始化LLM和工具,例如計算器和搜尋引擎。這些工具可以用來執行特定的任務,例如計算和搜尋。
from langchain import LLMMathChain
llm_math_chain = LLMMathChain.from_llm(
llm=model,
verbose=True)
calculator = Tool(
name='Calculator',
func=llm_math_chain.run,
description='Calculator tool')
初始化PlanAndExecute代理
接下來,需要初始化PlanAndExecute代理。這個代理接受LLM、工具、計劃器和執行器代理作為引數。
from langchain_experimental.plan_and_execute import PlanAndExecute, load_agent_executor, load_chat_planner
agent = PlanAndExecute(
planner=load_chat_planner(
llm=model),
executor=load_agent_executor(
llm=model,
tools=[search, calculator],
verbose=True),
verbose=True)
執行代理
最後,可以執行代理,傳入需要解答的問題。
agent.run('What is the sum of the elevations of the deepest section of the ocean and the highest peak on Earth? Use metric units only.')
分析結果
代理會將問題分解為子任務,然後執行這些子任務,最終得出答案。例如,代理可能會將問題分解為以下步驟:
- 搜尋最深海洋的深度
- 搜尋地球最高峰的高度
- 使用計算器計算這兩個值的總和
代理會執行這些步驟,最終得出答案。
內容解密:
以上程式碼展示瞭如何使用LangChain和LLM解答問題。首先,需要初始化LLM和工具,然後初始化PlanAndExecute代理,最後執行代理。代理會將問題分解為子任務,然後執行這些子任務,最終得出答案。
圖表翻譯:
以下是代理執行過程的Mermaid圖表:
flowchart TD A[問題] --> B[分解為子任務] B --> C[執行子任務] C --> D[得出答案] D --> E[輸出答案]
這個圖表展示了代理執行過程的流程,從問題分解為子任務,到執行子任務,最終得出答案。
深度學習模型的開發和佈署
在深度學習的應用中,開發和佈署模型是一個非常重要的步驟。這個步驟不僅需要對模型進行精細的調整和最佳化,也需要考慮到模型的實用性和可擴充套件性。
LangChain 的應用
在前面的章節中,我們介紹了 LangChain 的基本概念和應用。LangChain 是一個根據大語言模型(LLM)的框架,允許使用者建立複雜的任務流程和工作流程。透過 LangChain,我們可以將複雜的任務分解為更小的子任務,並使用 LLM 來執行每個子任務。
模型開發和佈署的挑戰
在開發和佈署深度學習模型的過程中,會遇到許多挑戰。其中包括:
- 模型複雜性:深度學習模型通常具有大量的引數和複雜的結構,使得模型的訓練和最佳化變得困難。
- 資料品質:資料的品質對模型的效能有著重要的影響。資料中的噪音、缺失值和偏差都可能對模型的效能產生負面影響。
- 計算資源:深度學習模型的訓練需要大量的計算資源,包括 GPU、CPU 和記憶體。
- 模型佈署:模型的佈署需要考慮到模型的實用性、可擴充套件性和安全性。
MLOps 的應用
MLOps(Machine Learning Operations)是一個集合了機器學習和 DevOps 的方法論,旨在提高機器學習模型的開發和佈署效率。MLOps 的主要目標是自動化機器學習模型的開發、測試和佈署,從而提高模型的品質和可靠性。
MLOps 的關鍵組成部分
MLOps 的關鍵組成部分包括:
- 資料管理:資料管理是 MLOps 的基礎,包括資料的收集、儲存、處理和分析。
- 模型開發:模型開發是 MLOps 的核心,包括模型的設計、訓練和最佳化。
- 模型佈署:模型佈署是 MLOps 的最終目標,包括模型的佈署、監控和維護。
- 自動化:自動化是 MLOps 的關鍵,包括模型的自動訓練、自動最佳化和自動佈署。
MLOps 的工具和技術
MLOps 的工具和技術包括:
- TensorFlow:TensorFlow 是一個流行的深度學習框架,提供了強大的模型開發和佈署功能。
- PyTorch:PyTorch 是另一個流行的深度學習框架,提供了動態的模型開發和佈署功能。
- Kubernetes:Kubernetes 是一個容器化的佈署工具,提供了強大的模型佈署和管理功能。
- Docker:Docker 是一個容器化的佈署工具,提供了輕量級的模型佈署和管理功能。
機器學習營運(MLOps)
在本章中,我們已經探討了神經網路(NNs)的理論、各種NN架構,以及可以用它們解決的任務。本章將著重於NN開發的實際方面。NN模型(尤其是NN)的開發和生產佈署具有獨特的挑戰。這個過程可以分為三個步驟:
- 訓練資料集建立:資料收集、清理、儲存、轉換和特徵工程。
- 模型開發:實驗不同的模型和訓練演算法,並評估它們。
- 佈署:將訓練好的模型佈署在生產環境中,並監控其計算和準確性的表現。
這個多步驟的複雜管道預設了一些解決機器學習任務的挑戰:
- 多樣的軟體工具包:每一步都有多個競爭工具。
- 模型開發很困難:每個訓練例項都有大量的變數。這些變數可能是NN架構的修改、訓練超引數的變化(例如學習率或動量)或不同的訓練資料分佈。此外,NN有隨機的來源,例如權重初始化或資料增強。因此,如果我們無法重現早期的結果,很難找出原因。即使我們在程式碼中有錯誤,也可能不會導致容易被檢測到的執行時異常。相反,它可能只會稍微降低模型的準確性。因此,我們需要一個強大的追蹤和監控系統,以避免失去所有實驗的軌跡。
機器學習營運(MLOps)
在本章中,我們將涵蓋以下主要主題:
- 瞭解模型開發
- 探索模型佈署
技術要求 我們將使用Python、PyTorch、TensorFlow(TF)和Hugging Face(HF)Transformers等工具實作本章的例子。如果您沒有設定好這些工具的環境,不要擔心 – 示例可在Google Colab上找到作為Jupyter Notebooks。
瞭解模型開發
在本文中,我們將討論各種工具,以幫助我們管理模型開發階段的機器學習解決方案生命週期。讓我們從最重要的問題開始 – 我們應該選擇哪個NN框架?
選擇NN框架 在本章中,我們主要使用PyTorch和TensorFlow。這些框架是整個NN軟體堆積堆疊的基礎。它們作為其他ML NN生態系統元件(例如Keras或HF Transformers)的基礎,這些元件可以使用它們作為後端。另外,它們支援GPU加速的NumPy運算和Autograd。其他流行的函式庫如scikit-learn不在此書中討論,因為它們與NN無直接關係。由於基礎函式庫的重要性,它們是我們工具箱中的第一個和最重要的選擇。但是,如果我們從頭開始一個專案,應該選擇哪一個?
PyTorch與TensorFlow與JAX 讓我們檢視這些函式庫的社群採用程度。首先,我們來看看Papers with Code網站。根據該網站,PyTorch是最受歡迎的函式庫,佔比為95%。TensorFlow和JAX分別排名第二和第三,佔比為3%和2%。這種趨勢並不新鮮 – PyTorch在2016年發布,但它已經在2019年超越了TensorFlow。這個特定的資料點表明PyTorch主導了最先進的研究,因此,如果您想始終使用最新和最好的技術,堅持使用PyTorch是一個好主意。
Open Neural Network Exchange(ONNX)
ONNX是一個開源格式,允許我們將NN模型從一個函式庫轉換為另一個函式庫。它定義了一個可擴充套件的計算圖模型、內建運運算元和標準資料型別。簡單地說,ONNX提供了一種通用的NN表示格式,允許我們將用一個函式庫實作的模型(例如PyTorch)轉換為另一個函式庫(例如TensorFlow),只要源函式庫和目標函式庫都支援ONNX。這樣,我們可以用一個函式庫訓練模型,然後在佈署到生產環境時將其轉換為另一個函式庫。
ONNX將NN表示為一個計算圖的運算,節點是運算(或ONNX運運算元),而邊是輸入/輸出連線(或ONNX變數)。此外,它實作了一個Python執行時環境,用於評估ONNX模型和運算。其目的是闡明ONNX的語義,幫助瞭解和除錯ONNX工具和轉換器,但它不適合生產環境,也未針對效能進行最佳化。
import onnx
import numpy as np
# 定義一個簡單的線性迴歸模型
X = np.array([[1], [2], [3]])
A = np.array([[2]])
B = np.array([[3]])
# 建立一個ONNX模型
model = onnx.ModelProto()
model.ir_version = 6
# 定義模型的輸入和輸出
input_tensor = onnx.ValueInfoProto(
name='X',
type=onnx.TypeProto(
tensor_type=onnx.TypeProto.Tensor(
elem_type=onnx.TensorProto.DataType.FLOAT,
shape=[-1, 1]
)
)
)
output_tensor = onnx.ValueInfoProto(
name='Y',
type=onnx.TypeProto(
tensor_type=onnx.TypeProto.Tensor(
elem_type=onnx.TensorProto.DataType.FLOAT,
shape=[-1, 1]
)
)
)
# 定義模型的運算
node = onnx.NodeProto(
op_type='MatMul',
inputs=['X', 'A'],
outputs=['Y']
)
# 將模型的運算增加到模型中
model.graph.node.append(node)
# 將模型儲存為ONNX檔案
with open('model.onnx', 'wb') as f:
f.write(model.SerializeToString())
內容解密:
在上面的程式碼中,我們定義了一個簡單的線性迴歸模型,並使用ONNX建立了一個模型。然後,我們定義了模型的輸入和輸出,包括輸入張量X
和輸出張量Y
。接下來,我們定義了一個運算,將輸入張量X
和權重A
相乘,得到輸出張量Y
。最後,我們將模型儲存為ONNX檔案。
圖表翻譯:
此圖示為ONNX模型的計算圖,顯示了輸入張量X
、權重A
和輸出張量Y
之間的關係。
graph LR X -->|MatMul|> Y A -->|MatMul|> Y
在這個圖中,X
和A
是輸入,Y
是輸出。MatMul
運運算元代表矩陣乘法運算。這個圖表闡明瞭ONNX模型的結構和運算過程。
根據ONNX的模型開發
在這個章節中,我們將探討如何使用ONNX(Open Neural Network Exchange)來開發和佈署神經網路模型。ONNX是一個開源的格式,允許使用者將訓練好的模型從一個框架轉換到另一個框架,從而實作跨平臺和跨框架的模型佈署。
定義圖表輸入和輸出變數
首先,我們需要定義圖表的輸入和輸出變數。這可以透過使用ONNX的make_tensor_value_info
函式來完成。以下是定義輸入變數X和輸出變數Y的示例程式碼:
import numpy as np
from onnx import TensorProto, numpy_helper
from onnx.helper import make_tensor_value_info
X = make_tensor_value_info(
name='X',
elem_type=TensorProto.FLOAT,
shape=[None, None]
)
Y = make_tensor_value_info(
name='Y',
elem_type=TensorProto.FLOAT,
shape=[None]
)
在這裡,make_tensor_value_info
函式用於定義圖表的輸入和輸出變數。name
引數指定變數的名稱,elem_type
引數指定變數的資料型別,shape
引數指定變數的形狀。
定義圖表引數
接下來,我們需要定義圖表的引數。這可以透過使用ONNX的numpy_helper
函式來完成。以下是定義引數A和B的示例程式碼:
A = numpy_helper.from_array(
np.array([0.5, -0.6], dtype=np.float32),
name='A'
)
B = numpy_helper.from_array(
np.array([0.4], dtype=np.float32),
name='B'
)
在這裡,numpy_helper
函式用於定義圖表的引數。from_array
方法用於從NumPy陣列中建立一個ONNX張量。
定義圖表操作
最後,我們需要定義圖表的操作。這可以透過使用ONNX的make_node
函式來完成。以下是定義矩陣乘法和加法操作的示例程式碼:
from onnx.helper import make_node
mat_mul = make_node(
op_type='MatMul',
inputs=['X', 'A'],
outputs=['XA']
)
addition = make_node(
op_type='Add',
inputs=['XA', 'B'],
outputs=['Y']
)
在這裡,make_node
函式用於定義圖表的操作。op_type
引數指定操作的型別,inputs
引數指定操作的輸入,outputs
引數指定操作的輸出。
內容解密:
在這個章節中,我們探討瞭如何使用ONNX來開發和佈署神經網路模型。ONNX是一個開源的格式,允許使用者將訓練好的模型從一個框架轉換到另一個框架,從而實作跨平臺和跨框架的模型佈署。透過使用ONNX的make_tensor_value_info
、numpy_helper
和make_node
函式,我們可以定義圖表的輸入和輸出變數、引數和操作。
圖表翻譯:
graph LR X -->|MatMul|> XA XA -->|Add|> Y A -->|MatMul|> XA B -->|Add|> Y
在這個圖表中,我們可以看到圖表的輸入和輸出變數、引數和操作。矩陣乘法操作用於計算X和A的乘法,然後加法操作用於計算XA和B的和。最終的輸出是Y。
ONNX 運運算元與模型建立
ONNX(Open Neural Network Exchange)是一個開源格式,允許使用者在不同的深度學習框架之間交換神經網路模型。ONNX 支援多種神經網路構建塊,包括啟用函式、卷積、池化、張量運運算元(例如 concat、pad、reshape 和 flatten)等。此外,ONNX 還支援控制流運運算元,可以建立動態計算圖。例如,if 運運算元可以根據布林值執行不同的子圖。
ONNX 運運算元的使用
ONNX 本身不實作運運算元,而是由支援 ONNX 的函式庫(如 PyTorch)實作自己的運運算元。相反,如果您的函式庫模型包含不被 ONNX 支援的運運算元,則 ONNX 轉換將失敗。
建立計算圖
現在,我們有了定義計算圖的所需成分:
from onnx.helper import make_graph
graph = make_graph(
nodes=[mat_mul, addition],
name='Linear regression',
inputs=[X],
outputs=[Y],
initializer=[A, B]
)
我們可以看到計算圖,如下圖所示: 圖 10.1 – 線性迴歸 ONNX 計算圖
建立 ONNX 模型
使用圖來建立一個 ONNX 模型例項。模型允許您向圖增加額外的元資料,例如 docstring、版本、作者和許可證等:
from onnx.helper import make_model
onnx_model = make_model(graph)
onnx_model.doc_string = '測試模型'
onnx_model.model_version = 1
模型一致性檢查
檢查模型的一致性,以驗證輸入型別或形狀是否在模型元件之間匹配:
from onnx.checker import check_model
check_model(onnx_model)
print(onnx_model)
計算模型輸出
最後,我們可以使用 ReferenceEvaluator 例項計算模型對兩個隨機輸入樣本的輸出:
from onnx.reference import ReferenceEvaluator
sess = ReferenceEvaluator(onnx_model)
內容解密:
在這個例子中,我們使用 ONNX 建立了一個簡單的線性迴歸模型。首先,我們定義了計算圖,然後建立了 ONNX 模型例項。接下來,我們檢查模型的一致性,最後,我們計算模型對隨機輸入樣本的輸出。
圖表翻譯:
graph TD A[計算圖] --> B[ONNX 模型] B --> C[模型一致性檢查] C --> D[計算模型輸出]
在這個圖表中,我們展示了 ONNX 模型的建立和計算過程。首先,我們定義計算圖,然後建立 ONNX 模型例項。接下來,我們檢查模型的一致性,最後,我們計算模型對隨機輸入樣本的輸出。
使用ONNX進行模型序列化和反序列化
ONNX(Open Neural Network Exchange)是一個開源格式,允許使用者將神經網路模型從一個框架序列化為ONNX格式,然後在另一個框架中反序列化。這使得不同框架之間的模型分享和轉換成為可能。
從技術架構視角來看,本文深入淺出地介紹了使用Transformers和LangChain進行深度學習模型開發和佈署的流程,並特別強調了ONNX在模型轉換和最佳化中的關鍵作用。藉由程式碼範例和圖表,我們清晰地理解了從資料集載入、模型訓練、評估到最終佈署的完整流程。其中,LangChain框架的應用,有效地解決了LLM應用中的上下文視窗和知識更新等限制,展現了其在構建複雜AI應用程式方面的強大潛力。ONNX的引入則有效簡化了跨平臺模型佈署的複雜性,提升了模型開發效率。然而,模型的訓練和佈署仍面臨諸多挑戰,例如模型複雜性、資料品質、計算資源限制等。對於追求高效能和跨平臺佈署的開發者而言,需要更深入地研究模型最佳化策略和MLOps最佳實務。玄貓認為,掌握這些核心技術和工具,將成為未來AI工程師的必備技能,並在推動AI技術的產業落地中扮演至關重要的角色。