自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

大語言模型推理框架llama.cpp開發(fā)實戰(zhàn)

譯文 精選
人工智能
本文旨在讓讀者詳細(xì)了解如何使用直接來自llama.cpp的低級函數(shù)執(zhí)行LLM推理。具體地講,我們將詳細(xì)探討llama.cpp框架開發(fā)程序的詳細(xì)流程、llama.cpp框架的架構(gòu),最后實現(xiàn)一個簡單的聊天應(yīng)用程序。

譯者 | 朱先忠

審校 | 重樓

本文首先探索當(dāng)前熱門的大語言模型推理框架llama.cpp的內(nèi)部架構(gòu),然后使用此框架實現(xiàn)了一個基本形式的聊天程序。

簡介

當(dāng)前,llama.cpp框架以其簡單性被業(yè)界廣泛采用,徹底改變了LLM推理領(lǐng)域。它支持企業(yè)和個人開發(fā)人員能夠在從SBC到多GPU集群的各類型設(shè)備上部署機(jī)器學(xué)習(xí)大型語言模型。盡管llama.cpp的語言綁定方式使其使用方式變得容易,但是對于性能敏感或資源受限的情況,使用C/C++編程方案可能是一個更為可行的選擇。

本文旨在讓讀者詳細(xì)了解如何使用直接來自llama.cpp的低級函數(shù)執(zhí)行LLM推理。具體地講,我們將詳細(xì)探討llama.cpp框架開發(fā)程序的詳細(xì)流程、llama.cpp框架的架構(gòu),最后實現(xiàn)一個簡單的聊天應(yīng)用程序。

請注意,我們將在本文中編寫的C++代碼也用于SmolChat應(yīng)用程序中,這是一個原生Android應(yīng)用程序,它允許用戶在聊天界面中與LLM/SLM實現(xiàn)完全在設(shè)備上的交互。具體來說,我們將使用文章前面將定義的LLMInference類與JNI綁定一起使用,從而實現(xiàn)共同執(zhí)行GGUF模型。

另外,本文將分析的代碼實現(xiàn)可以在鏈接處找到。

還有,上述代碼也派生自llama.cpp的官方簡單聊天示例程序。

關(guān)于llama.cpp

llama.cpp是一個C/C++框架,用于在多個執(zhí)行后端推斷以GGUF格式定義的機(jī)器學(xué)習(xí)模型。這個框架最初是Meta著名的Llama系列LLM的純C/C++實現(xiàn),可以在蘋果公司自研的Silicon處理器、AVX/AVX-512、CUDA和基于Arm Neon的環(huán)境中推斷。此外,這個框架還包括一個基于CLI的工具llama-cli來運行GGUF LLM模型,還提供一個llama-server(OpenAI兼容服務(wù)器)通過HTTP請求方式執(zhí)行模型。

llama.cpp使用機(jī)器學(xué)習(xí)的張量庫ggml,這是一個低級框架,提供深度學(xué)習(xí)模型所需的原始函數(shù),并從用戶那里抽象后端實現(xiàn)細(xì)節(jié)。Georgi Gerganov是ggml庫和llama.cpp框架的創(chuàng)建者。

此外,llama.cpp框架存儲庫的README文件還列出了其他編程語言中基于llama.cpp構(gòu)建的包裝器。Ollama和LM Studio等流行工具也使用llama.cpp上的綁定來增強(qiáng)用戶友好性。該項目不依賴其他第三方庫。

llama.cpp與PyTorch/TensorFlow有何不同?

llama.cpp從一開始就強(qiáng)調(diào)ML模型的推理,而PyTorch 和TensorFlow 是端到端解決方案,通過一個安裝包的形式來提供數(shù)據(jù)處理、模型訓(xùn)練/驗證和高效推理。

注意:PyTorch和TensorFlow也有各自的輕量級推理擴(kuò)展,即ExecuTorchTensorFlowLite。

僅考慮模型的推理階段,llama.cpp的實現(xiàn)是輕量的,因為它沒有第三方依賴項,并且自動支持大量可用的運算符或模型格式。此外,顧名思義,該項目最初是一個用于推斷LLM(來自Meta的Llama模型)的高效庫,并繼續(xù)支持廣泛的開源LLM架構(gòu)。

如果把PyTorch/TensorFlow比作是豪華、耗電的游輪的話,那么llama.cpp就是小型、快速的摩托艇。PyTorch/TF和llama.cpp都有各自的使用場景。

設(shè)置

我們在基于Linux的環(huán)境(本機(jī)或WSL環(huán)境)中進(jìn)行開發(fā);為此,需要安裝cmake和GNU/clang工具鏈。我們將從源代碼編譯llama.cpp,并將其作為共享庫添加到我們的可執(zhí)行聊天程序中。

首先,我們創(chuàng)建一個項目目錄smol_chat,并使用一個externals目錄來存儲克隆自原項目的llama.cpp存儲庫。

mkdir smol_chat
cd smol_chat

mkdir src
mkdir externals
touch CMakeLists.txt

cd externals
git clone --depth=1 https://github.com/ggerganov/llama.cpp

CMakeLists.txt是我們定義構(gòu)建項目方案的文件,通過引用來自externals/llama.cpp的標(biāo)準(zhǔn)頭文件和共享庫,允許CMake使用默認(rèn)工具鏈(GNU/clang)編譯我們的C/C++代碼。

cmake_minimum_required(VERSION 3.10)
project(llama_inference)

set(CMAKE_CXX_STANDARD 17)
set(LLAMA_BUILD_COMMON On)
add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/externals/llama.cpp")

add_executable(
chat
src/LLMInference.cpp src/main.cpp
)
target_link_libraries(
chat 
PRIVATE
common llama ggml
)

加載模型

現(xiàn)在,我們已經(jīng)定義了如何通過CMake構(gòu)建我們的項目。接下來,我們創(chuàng)建一個頭文件LLMInference.h,它聲明了一個包含高級函數(shù)的類,用于與LLM交互。llama.cpp提供了一個C樣式的API,因此將其嵌入到類中將有助于我們抽象/隱藏內(nèi)部工作細(xì)節(jié)。

#ifndef LLMINFERENCE_H
#define LLMINFERENCE_H

#include "common.h"
#include "llama.h"
#include <string>
#include <vector>

class LLMInference {

// llama.cpp特定的數(shù)據(jù)類型
llama_context* _ctx;
llama_model* _model;
llama_sampler* _sampler;
llama_batch _batch;
llama_token _currToken;

// 用于在聊天程序中存儲用戶/助手信息的容器
std::vector<llama_chat_message> _messages;
//將聊天模板應(yīng)用于所有消息后生成的字符串存儲在“_messages”中
std::vector<char> _formattedMessages;
// 將最后查詢的標(biāo)記存儲到“_messages”中
std::vector<llama_token> _promptTokens;
int _prevLen = 0;

// 存儲給定查詢的完整響應(yīng)
std::string _response = "";

public:

void loadModel(const std::string& modelPath, float minP, float temperature);

void addChatMessage(const std::string& message, const std::string& role);

void startCompletion(const std::string& query);

std::string completionLoop();

void stopCompletion();

~LLMInference();
};

#endif

上面頭文件中聲明的私有成員將用于實現(xiàn)本文后續(xù)部分中描述的公共成員函數(shù)。首先,讓我們在LLMInference.cpp中定義每個成員函數(shù)。

#include "LLMInference.h"
#include <cstring>
#include <iostream>

void LLMInference::loadModel(const std::string& model_path, float min_p, float temperature) {
//創(chuàng)建一個llama_model的實例
llama_model_params model_params = llama_model_default_params();
_model = llama_load_model_from_file(model_path.data(), model_params);

if (!_model) {
throw std::runtime_error("load_model() failed");
}

//創(chuàng)建 llama_context 實例
llama_context_params ctx_params = llama_context_default_params();
ctx_params.n_ctx = 0;               // 從模型 GGUF 文件中獲取上下文大小
ctx_params.no_perf = true;          // 禁用性能指標(biāo)
_ctx = llama_new_context_with_model(_model, ctx_params);

if (!_ctx) {
throw std::runtime_error("llama_new_context_with_model() returned null");
}

//初始化采樣器
llama_sampler_chain_params sampler_params = llama_sampler_chain_default_params();
sampler_params.no_perf = true;      // 禁用性能指標(biāo)
_sampler = llama_sampler_chain_init(sampler_params);
llama_sampler_chain_add(_sampler, llama_sampler_init_min_p(min_p, 1));
llama_sampler_chain_add(_sampler, llama_sampler_init_temp(temperature));
llama_sampler_chain_add(_sampler, llama_sampler_init_dist(LLAMA_DEFAULT_SEED));

_formattedMessages = std::vector<char>(llama_n_ctx(_ctx));
_messages.clear();
}

上述代碼中,llama_load_model_from_file使用llama_load_model從文件內(nèi)部讀取模型,并使用給定的llama_model_params填充llama_model實例。用戶可以提供參數(shù),但我們可以使用llama_model_default_params獲取預(yù)初始化的默認(rèn)結(jié)構(gòu)。

llama_context表示加載的GGUF模型的執(zhí)行環(huán)境。llama_new_context_with_model實例化新的llama_context,并通過讀取llama_model_params或自動檢測可用的后端來準(zhǔn)備執(zhí)行的后端。它還初始化K-V緩存,這在解碼或推理步驟中是很重要的。管理跨多個后端的計算的后端調(diào)度程序也被初始化。

llama_sampler決定了我們?nèi)绾螐哪P停ㄌ貏e是LLM的解碼器)的輸出(logits)得出概率分布中的采樣/選擇標(biāo)記。LLM為詞匯表中存在的每個標(biāo)記分配一個概率,表示該標(biāo)記出現(xiàn)在序列中的下一個概率。我們使用llama_sampler_init_temp和llama_sampler_init_min_p設(shè)置的溫度和min-p是控制標(biāo)記采樣過程的兩個參數(shù)。

執(zhí)行推理

推理過程涉及多個步驟,該過程將用戶的文本查詢作為輸入并返回LLM的響應(yīng)。

1. 將聊天模板應(yīng)用于查詢

對于LLM,傳入消息被歸類為屬于三個角色,即用戶、助手和系統(tǒng)。其中,用戶和助手消息分別由用戶和LLM給出,而系統(tǒng)表示整個對話中遵循的系統(tǒng)范圍提示。每條消息都由角色和內(nèi)容組成,其中內(nèi)容是實際文本,角色是三個角色中的任何一個。

<example>

系統(tǒng)提示是對話的第一條消息。在我們的代碼中,消息存儲為名為_messages的std::vector<llama_chat_message>。其中,llama_chat_message是具有角色和內(nèi)容屬性的llama.cpp結(jié)構(gòu)。我們使用llama.cpp中的llama_chat_apply_template函數(shù)將存儲在GGUF文件中的聊天模板應(yīng)用為元數(shù)據(jù)。我們將應(yīng)用聊天模板后獲得的字符串或std::vector<char>存儲在_formattedMessages中。

2. 標(biāo)記化

標(biāo)記化是將給定文本劃分為較小部分(標(biāo)記)的過程。我們?yōu)槊總€部分/標(biāo)記分配一個唯一的整數(shù)ID,從而將輸入文本轉(zhuǎn)換為整數(shù)序列,形成LLM的輸入。llama.cpp提供common_tokenize或llama_tokenize函數(shù)來執(zhí)行標(biāo)記化,其中common_tokenize將標(biāo)記序列作為std::vector<llama_token>返回。

void LLMInference::startCompletion(const std::string& query) {
addChatMessage(query, "user");

// 應(yīng)用聊天模板 
int new_len = llama_chat_apply_template(
_model,
nullptr,
_messages.data(),
_messages.size(),
true,
_formattedMessages.data(),
_formattedMessages.size()
);
if (new_len > (int)_formattedMessages.size()) {
//調(diào)整輸出緩沖區(qū) `_formattedMessages`的大小并重新應(yīng)用聊天模板
_formattedMessages.resize(new_len);
new_len = llama_chat_apply_template(_model, nullptr, _messages.data(), _messages.size(), true, _formattedMessages.data(), _formattedMessages.size());
}
if (new_len < 0) {
throw std::runtime_error("llama_chat_apply_template() in LLMInference::start_completion() failed");
}
std::string prompt(_formattedMessages.begin() + _prevLen, _formattedMessages.begin() + new_len);

// 標(biāo)記化
_promptTokens = common_tokenize(_model, prompt, true, true);

// 創(chuàng)建一個包含單個序列的llama_batch
// see llama_batch_init for more details
_batch.token = _promptTokens.data();
_batch.n_tokens = _promptTokens.size();
}

在上面代碼中,我們應(yīng)用聊天模板并在LLMInference::startCompletion方法中執(zhí)行標(biāo)記化,然后創(chuàng)建一個llama_batch實例來保存模型的最終輸入。

3. 解碼、采樣和KV緩存

如前所述,LLM通過連續(xù)預(yù)測給定序列中的下一個標(biāo)記來生成響應(yīng)。LLM還經(jīng)過訓(xùn)練以預(yù)測特殊的生成結(jié)束(EOG)標(biāo)記,指示預(yù)測標(biāo)記序列的結(jié)束。completion_loop函數(shù)返回序列中的下一個標(biāo)記,并不斷被調(diào)用,直到它返回的標(biāo)記是EOG標(biāo)記。

  • 通過llama_n_ctx和llama_get_kv_cached_used_cells,我們可以確定用于存儲輸入的上下文的長度。目前,如果標(biāo)記化輸入的長度超過上下文大小的話,我們會拋出一個錯誤。
  • llama_decode根據(jù)變量_batch中的輸入信息對模型進(jìn)行前向傳遞。
  • 通過在LLMInference::loadModel中初始化的_sampler,我們抽樣或選擇一個標(biāo)記作為我們的預(yù)測并將其存儲在_currToken中。我們檢查該標(biāo)記是否為EOG標(biāo)記,然后返回“EOG”,表示應(yīng)終止調(diào)用LLMInference::completionLoop的文本生成循環(huán)。終止時,我們將一條新消息附加到_messages,這是具有角色assistant的LLM給出的完整響應(yīng)信息。
  •  _currToken仍然是一個整數(shù),它由common_token_to_piece函數(shù)轉(zhuǎn)換為字符串標(biāo)記片段。此字符串標(biāo)記從finishLoop方法返回。
  • 我們需要重新初始化_batch以確保它現(xiàn)在僅包含_currToken而不是整個輸入序列,即_promptTokens。這是因為所有先前標(biāo)記的“鍵”和“值”都已緩存。通過避免計算_promptTokens中所有標(biāo)記的所有“鍵”和“值”,可以減少推理時間。
std::string LLMInference::completionLoop() {
// 檢查模型輸入的長度是否超出了模型的上下文大小
int contextSize = llama_n_ctx(_ctx);
int nCtxUsed = llama_get_kv_cache_used_cells(_ctx);
if (nCtxUsed + _batch.n_tokens > contextSize) {
std::cerr << "context size exceeded" << '\n';
exit(0);
}
//運行模型
if (llama_decode(_ctx, _batch) < 0) {
throw std::runtime_error("llama_decode() failed");
}

// 采樣一個標(biāo)記并檢查它是否是EOG(生成結(jié)束標(biāo)記)
// 將整數(shù)標(biāo)記轉(zhuǎn)換為其對應(yīng)的單詞片段
_currToken = llama_sampler_sample(_sampler, _ctx, -1);
if (llama_token_is_eog(_model, _currToken)) {
addChatMessage(strdup(_response.data()), "assistant");
_response.clear();
return "[EOG]";
}
std::string piece = common_token_to_piece(_ctx, _currToken, true);


// 使用新預(yù)測的標(biāo)記重新初始化批次
// 所有先前標(biāo)記的鍵值對都已緩存在KV緩存中
_batch.token = &_currToken;
_batch.n_tokens = 1;

return piece;
}
  • 此外,對于用戶的每個查詢,LLM將整個標(biāo)記化對話(存儲在_messages中的所有消息)作為輸入。如果我們每次都在startCompletion方法中標(biāo)記整個對話,那么隨著對話變長,預(yù)處理時間和總體推理時間將會增加。
  • 為了避免這種計算,我們只需要標(biāo)記添加到_messages的最新消息/查詢。_formattedMessages中消息被標(biāo)記的長度存儲在_prevLen中。在響應(yīng)生成結(jié)束時,即在LLMInference::stopCompletion中,我們通過將LLM的響應(yīng)附加到_messages并使用llama_chat_apply_template的返回值來更新_prevLen的值。
void LLMInference::stopCompletion() {
_prevLen = llama_chat_apply_template(
_model,
nullptr,
_messages.data(),
_messages.size(),
false,
nullptr,
0
);
if (_prevLen < 0) {
throw std::runtime_error("llama_chat_apply_template() in LLMInference::stop_completion() failed");
}
}

編寫析構(gòu)函數(shù)

我們在_messages和llama.cpp內(nèi)部實現(xiàn)了一個析構(gòu)函數(shù)方法來釋放動態(tài)分配的對象。

LLMInference::~LLMInference() {
//釋放消息中消息文本所占用的內(nèi)存(因為我們已使用strdup()創(chuàng)建了malloc副本)
for (llama_chat_message &message: _messages) {
delete message.content;
}
llama_kv_cache_clear(_ctx);
llama_sampler_free(_sampler);
llama_free(_ctx);
llama_free_model(_model);
}

編寫小型CMD應(yīng)用程序

我們創(chuàng)建了一個小型接口程序,允許我們與LLM進(jìn)行轉(zhuǎn)換。核心工作包括實例化LLMInference類并調(diào)用我們在前面部分中定義的所有方法。

#include "LLMInference.h"
#include <memory>
#include <iostream>

int main(int argc, char* argv[]) {

std::string modelPath = "smollm2-360m-instruct-q8_0.gguf";
float temperature = 1.0f;
float minP = 0.05f;
std::unique_ptr<LLMInference> llmInference = std::make_unique<LLMInference>();
llmInference->loadModel(modelPath, minP, temperature);

llmInference->addChatMessage("You are a helpful assistant", "system");

while (true) {
std::cout << "Enter query:\n";
std::string query;
std::getline(std::cin, query);
if (query == "exit") {
break;
}
llmInference->startCompletion(query);
std::string predictedToken;
while ((predictedToken = llmInference->completionLoop()) != "[EOG]") {
std::cout << predictedToken;
fflush(stdout);
}
std::cout << '\n';
}

return 0;
}

運行示例程序

我們使用前面幾節(jié)中編寫的CMakeLists.txt文件。這個文件用于創(chuàng)建一個Makefile,該文件將編譯代碼并創(chuàng)建一個可供使用的可執(zhí)行文件。

mkdir build
cd build
cmake ..
make
./chat

輸出結(jié)果如下:

register_backend: registered backend CPU (1 devices)
register_device: registered device CPU (11th Gen Intel(R) Core(TM) i3-1115G4 @ 3.00GHz)
llama_model_loader: loaded meta data with 33 key-value pairs and 290 tensors from /home/shubham/CPP_Projects/llama-cpp-inference/models/smollm2-360m-instruct-q8_0.gguf (version GGUF V3 (latest))
llama_model_loader: Dumping metadata keys/values. Note: KV overrides do not apply in this output.
llama_model_loader: - kv   0:                       general.architecture str              = llama
llama_model_loader: - kv   1:                               general.type str              = model
llama_model_loader: - kv   2:                               general.name str              = Smollm2 360M 8k Lc100K Mix1 Ep2
llama_model_loader: - kv   3:                       general.organization str              = Loubnabnl
llama_model_loader: - kv   4:                           general.finetune str              = 8k-lc100k-mix1-ep2
llama_model_loader: - kv   5:                           general.basename str              = smollm2
llama_model_loader: - kv   6:                         general.size_label str              = 360M
llama_model_loader: - kv   7:                            general.license str              = apache-2.0
llama_model_loader: - kv   8:                          general.languages arr[str,1]       = ["en"]
llama_model_loader: - kv   9:                          llama.block_count u32              = 32
llama_model_loader: - kv  10:                       llama.context_length u32              = 8192
llama_model_loader: - kv  11:                     llama.embedding_length u32              = 960
llama_model_loader: - kv  12:                  llama.feed_forward_length u32              = 2560
llama_model_loader: - kv  13:                 llama.attention.head_count u32              = 15
llama_model_loader: - kv  14:              llama.attention.head_count_kv u32              = 5
llama_model_loader: - kv  15:                       llama.rope.freq_base f32              = 100000.000000
llama_model_loader: - kv  16:     llama.attention.layer_norm_rms_epsilon f32              = 0.000010
llama_model_loader: - kv  17:                          general.file_type u32              = 7
llama_model_loader: - kv  18:                           llama.vocab_size u32              = 49152
llama_model_loader: - kv  19:                 llama.rope.dimension_count u32              = 64
llama_model_loader: - kv  20:            tokenizer.ggml.add_space_prefix bool             = false
llama_model_loader: - kv  21:               tokenizer.ggml.add_bos_token bool             = false
llama_model_loader: - kv  22:                       tokenizer.ggml.model str              = gpt2
llama_model_loader: - kv  23:                         tokenizer.ggml.pre str              = smollm
llama_model_loader: - kv  24:                      tokenizer.ggml.tokens arr[str,49152]   = ["<|endoftext|>", "<|im_start|>", "<|...
llama_model_loader: - kv  25:                  tokenizer.ggml.token_type arr[i32,49152]   = [3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, ...
llama_model_loader: - kv  26:                      tokenizer.ggml.merges arr[str,48900]   = ["? t", "? a", "i n", "h e", "? ?...
llama_model_loader: - kv  27:                tokenizer.ggml.bos_token_id u32              = 1
llama_model_loader: - kv  28:                tokenizer.ggml.eos_token_id u32              = 2
llama_model_loader: - kv  29:            tokenizer.ggml.unknown_token_id u32              = 0
llama_model_loader: - kv  30:            tokenizer.ggml.padding_token_id u32              = 2
llama_model_loader: - kv  31:                    tokenizer.chat_template str              = {% for message in messages %}{% if lo...
llama_model_loader: - kv  32:               general.quantization_version u32              = 2
llama_model_loader: - type  f32:   65 tensors
llama_model_loader: - type q8_0:  225 tensors
llm_load_vocab: control token:      7 '<gh_stars>' is not marked as EOG
llm_load_vocab: control token:     13 '<jupyter_code>' is not marked as EOG
llm_load_vocab: control token:     16 '<empty_output>' is not marked as EOG
llm_load_vocab: control token:     11 '<jupyter_start>' is not marked as EOG
llm_load_vocab: control token:     10 '<issue_closed>' is not marked as EOG
llm_load_vocab: control token:      6 '<filename>' is not marked as EOG
llm_load_vocab: control token:      8 '<issue_start>' is not marked as EOG
llm_load_vocab: control token:      3 '<repo_name>' is not marked as EOG
llm_load_vocab: control token:     12 '<jupyter_text>' is not marked as EOG
llm_load_vocab: control token:     15 '<jupyter_script>' is not marked as EOG
llm_load_vocab: control token:      4 '<reponame>' is not marked as EOG
llm_load_vocab: control token:      1 '<|im_start|>' is not marked as EOG
llm_load_vocab: control token:      9 '<issue_comment>' is not marked as EOG
llm_load_vocab: control token:      5 '<file_sep>' is not marked as EOG
llm_load_vocab: control token:     14 '<jupyter_output>' is not marked as EOG
llm_load_vocab: special tokens cache size = 17
llm_load_vocab: token to piece cache size = 0.3170 MB
llm_load_print_meta: format           = GGUF V3 (latest)
llm_load_print_meta: arch             = llama
llm_load_print_meta: vocab type       = BPE
llm_load_print_meta: n_vocab          = 49152
llm_load_print_meta: n_merges         = 48900
llm_load_print_meta: vocab_only       = 0
llm_load_print_meta: n_ctx_train      = 8192
llm_load_print_meta: n_embd           = 960
llm_load_print_meta: n_layer          = 32
llm_load_print_meta: n_head           = 15
llm_load_print_meta: n_head_kv        = 5
llm_load_print_meta: n_rot            = 64
llm_load_print_meta: n_swa            = 0
llm_load_print_meta: n_embd_head_k    = 64
llm_load_print_meta: n_embd_head_v    = 64
llm_load_print_meta: n_gqa            = 3
llm_load_print_meta: n_embd_k_gqa     = 320
llm_load_print_meta: n_embd_v_gqa     = 320
llm_load_print_meta: f_norm_eps       = 0.0e+00
llm_load_print_meta: f_norm_rms_eps   = 1.0e-05
llm_load_print_meta: f_clamp_kqv      = 0.0e+00
llm_load_print_meta: f_max_alibi_bias = 0.0e+00
llm_load_print_meta: f_logit_scale    = 0.0e+00
llm_load_print_meta: n_ff             = 2560
llm_load_print_meta: n_expert         = 0
llm_load_print_meta: n_expert_used    = 0
llm_load_print_meta: causal attn      = 1
llm_load_print_meta: pooling type     = 0
llm_load_print_meta: rope type        = 0
llm_load_print_meta: rope scaling     = linear
llm_load_print_meta: freq_base_train  = 100000.0
llm_load_print_meta: freq_scale_train = 1
llm_load_print_meta: n_ctx_orig_yarn  = 8192
llm_load_print_meta: rope_finetuned   = unknown
llm_load_print_meta: ssm_d_conv       = 0
llm_load_print_meta: ssm_d_inner      = 0
llm_load_print_meta: ssm_d_state      = 0
llm_load_print_meta: ssm_dt_rank      = 0
llm_load_print_meta: ssm_dt_b_c_rms   = 0
llm_load_print_meta: model type       = 3B
llm_load_print_meta: model ftype      = Q8_0
llm_load_print_meta: model params     = 361.82 M
llm_load_print_meta: model size       = 366.80 MiB (8.50 BPW) 
llm_load_print_meta: general.name     = Smollm2 360M 8k Lc100K Mix1 Ep2
llm_load_print_meta: BOS token        = 1 '<|im_start|>'
llm_load_print_meta: EOS token        = 2 '<|im_end|>'
llm_load_print_meta: EOT token        = 0 '<|endoftext|>'
llm_load_print_meta: UNK token        = 0 '<|endoftext|>'
llm_load_print_meta: PAD token        = 2 '<|im_end|>'
llm_load_print_meta: LF token         = 143 '?'
llm_load_print_meta: EOG token        = 0 '<|endoftext|>'
llm_load_print_meta: EOG token        = 2 '<|im_end|>'
llm_load_print_meta: max token length = 162
llm_load_tensors: ggml ctx size =    0.14 MiB
llm_load_tensors:        CPU buffer size =   366.80 MiB
...............................................................................
llama_new_context_with_model: n_ctx      = 8192
llama_new_context_with_model: n_batch    = 2048
llama_new_context_with_model: n_ubatch   = 512
llama_new_context_with_model: flash_attn = 0
llama_new_context_with_model: freq_base  = 100000.0
llama_new_context_with_model: freq_scale = 1
llama_kv_cache_init:        CPU KV buffer size =   320.00 MiB
llama_new_context_with_model: KV self size  =  320.00 MiB, K (f16):  160.00 MiB, V (f16):  160.00 MiB
llama_new_context_with_model:        CPU  output buffer size =     0.19 MiB
ggml_gallocr_reserve_n: reallocating CPU buffer from size 0.00 MiB to 263.51 MiB
llama_new_context_with_model:        CPU compute buffer size =   263.51 MiB
llama_new_context_with_model: graph nodes  = 1030
llama_new_context_with_model: graph splits = 1
Enter query:
How are you?
I'm a text-based AI assistant. I don't have emotions or personal feelings, but I can understand and respond to your requests accordingly. If you have questions or need help with anything, feel free to ask.
Enter query:
Write a one line description on the C++ keyword 'new' 
New C++ keyword represents memory allocation for dynamically allocated memory.
Enter query:
exit

結(jié)論

llama.cpp簡化了大型語言模型的部署,使其可以在各種設(shè)備和使用場景中訪問。本文中,我們通過介紹這個框架的內(nèi)部結(jié)構(gòu)并構(gòu)建一個簡單的C++推理程序,展示了開發(fā)人員應(yīng)該如何利用其低級函數(shù)來實現(xiàn)高性能但資源受限的應(yīng)用程序。本文不僅介紹了llama.cpp框架的核心架構(gòu),還強(qiáng)調(diào)了它在實際項目中的實用性,從而實現(xiàn)了與LLM的高效率設(shè)備交互。

對于有興趣突破LLM部署界限或旨在構(gòu)建強(qiáng)大應(yīng)用程序的開發(fā)人員來說,掌握llama.cpp等工具將打開無限可能的大門。在你進(jìn)一步探索時,請記住,你可以進(jìn)一步擴(kuò)展這些基礎(chǔ)知識,以便集成高級功能、優(yōu)化性能并適應(yīng)不斷發(fā)展的AI應(yīng)用場景。

最后,我希望本文能夠提供一些有用的信息,并讓你對直接在C++環(huán)境中運行LLM感到著迷。

譯者介紹

朱先忠,51CTO社區(qū)編輯,51CTO專家博客、講師,濰坊一所高校計算機(jī)教師,自由編程界老兵一枚。

原文標(biāo)題:llama.cpp: Writing A Simple C++ Inference Program for GGUF LLM Models,作者:Shubham Panchal

責(zé)任編輯:姜華 來源: 51CTO內(nèi)容精選
相關(guān)推薦

2023-08-17 16:07:16

模型優(yōu)化

2023-07-10 13:46:58

PythonLlama.cppLLM

2025-04-29 07:47:27

2024-02-01 08:34:30

大模型推理框架NVIDIA

2024-09-09 08:31:15

2024-10-25 19:32:58

ChatGPT

2023-10-11 12:32:53

AI模型

2023-05-05 13:29:04

模型推理

2023-09-20 08:00:00

大語言模型代碼庫

2024-06-06 09:47:56

2024-04-11 11:35:03

大語言模型LLMs

2025-02-17 12:30:00

2024-07-19 12:48:29

2024-08-13 14:20:00

模型數(shù)據(jù)

2023-09-12 13:43:00

智能技術(shù)

2023-01-05 09:33:37

視覺模型訓(xùn)練

2023-06-08 11:45:50

模型語言

2025-02-25 09:49:12

2025-01-10 08:38:10

2024-03-11 09:50:09

模型開發(fā)
點贊
收藏

51CTO技術(shù)棧公眾號