精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

大語言模型推理框架llama.cpp開發實戰 原創

發布于 2025-1-20 07:53
瀏覽
0收藏

本文首先探索當前熱門的大語言模型推理框架llama.cpp的內部架構,然后使用此框架實現了一個基本形式的聊天程序。

簡介

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

本文旨在讓讀者詳細了解如何使用直接來自llama.cpp的低級函數執行LLM推理。具體地講,我們將詳細探討llama.cpp框架開發程序的詳細流程、llama.cpp框架的架構,最后實現一個簡單的聊天應用程序。

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

另外,本文將分析的代碼實現可以在??鏈接??處找到。

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

關于llama.cpp

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

llama.cpp使用機器學習的??張量庫ggml???,這是一個低級框架,提供深度學習模型所需的原始函數,并從用戶那里抽象后端實現細節。??Georgi Gerganov??是ggml庫和llama.cpp框架的創建者。

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

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

llama.cpp從一開始就強調ML模型的推理,而??PyTorch??? 和??TensorFlow?? 是端到端解決方案,通過一個安裝包的形式來提供數據處理、模型訓練/驗證和高效推理。

注意:PyTorch和TensorFlow也有各自的輕量級推理擴展,即??ExecuTorch???和??TensorFlowLite??。

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

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

設置

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

首先,我們創建一個項目目錄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是我們定義構建項目方案的文件,通過引用來自externals/llama.cpp的標準頭文件和共享庫,允許CMake使用默認工具鏈(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
)

加載模型

現在,我們已經定義了如何通過CMake構建我們的項目。接下來,我們創建一個頭文件LLMInference.h,它聲明了一個包含高級函數的類,用于與LLM交互。llama.cpp提供了一個C樣式的API,因此將其嵌入到類中將有助于我們抽象/隱藏內部工作細節。

#ifndef LLMINFERENCE_H
#define LLMINFERENCE_H

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

class LLMInference {

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

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

// 存儲給定查詢的完整響應
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

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

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

void LLMInference::loadModel(const std::string& model_path, float min_p, float temperature) {
//創建一個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");
}

//創建 llama_context 實例
llama_context_params ctx_params = llama_context_default_params();
ctx_params.n_ctx = 0;               // 從模型 GGUF 文件中獲取上下文大小
ctx_params.no_perf = true;          // 禁用性能指標
_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;      // 禁用性能指標
_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從文件內部讀取模型,并使用給定的llama_model_params填充llama_model實例。用戶可以提供參數,但我們可以使用llama_model_default_params獲取預初始化的默認結構。

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

llama_sampler決定了我們如何從模型(特別是LLM的解碼器)的輸出(logits)得出概率分布中的采樣/選擇標記。LLM為詞匯表中存在的每個標記分配一個概率,表示該標記出現在序列中的下一個概率。我們使用llama_sampler_init_temp和llama_sampler_init_min_p設置的溫度和min-p是控制標記采樣過程的兩個參數。

執行推理

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

1. 將聊天模板應用于查詢

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

<example>

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

2. 標記化

標記化是將給定文本劃分為較小部分(標記)的過程。我們為每個部分/標記分配一個唯一的整數ID,從而將輸入文本轉換為整數序列,形成LLM的輸入。llama.cpp提供common_tokenize或llama_tokenize函數來執行標記化,其中common_tokenize將標記序列作為std::vector<llama_token>返回。

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

// 應用聊天模板 
int new_len = llama_chat_apply_template(
_model,
nullptr,
_messages.data(),
_messages.size(),
true,
_formattedMessages.data(),
_formattedMessages.size()
);
if (new_len > (int)_formattedMessages.size()) {
//調整輸出緩沖區 `_formattedMessages`的大小并重新應用聊天模板
_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);

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

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

在上面代碼中,我們應用聊天模板并在LLMInference::startCompletion方法中執行標記化,然后創建一個llama_batch實例來保存模型的最終輸入。

3. 解碼、采樣和KV緩存

如前所述,LLM通過連續預測給定序列中的下一個標記來生成響應。LLM還經過訓練以預測特殊的生成結束(EOG)標記,指示預測標記序列的結束。completion_loop函數返回序列中的下一個標記,并不斷被調用,直到它返回的標記是EOG標記。

  • 通過llama_n_ctx和llama_get_kv_cached_used_cells,我們可以確定用于存儲輸入的上下文的長度。目前,如果標記化輸入的長度超過上下文大小的話,我們會拋出一個錯誤。
  • llama_decode根據變量_batch中的輸入信息對模型進行前向傳遞。
  • 通過在LLMInference::loadModel中初始化的_sampler,我們抽樣或選擇一個標記作為我們的預測并將其存儲在_currToken中。我們檢查該標記是否為EOG標記,然后返回“EOG”,表示應終止調用LLMInference::completionLoop的文本生成循環。終止時,我們將一條新消息附加到_messages,這是具有角色assistant的LLM給出的完整響應信息。
  • _currToken仍然是一個整數,它由common_token_to_piece函數轉換為字符串標記片段。此字符串標記從finishLoop方法返回。
  • 我們需要重新初始化_batch以確保它現在僅包含_currToken而不是整個輸入序列,即_promptTokens。這是因為所有先前標記的“鍵”和“值”都已緩存。通過避免計算_promptTokens中所有標記的所有“鍵”和“值”,可以減少推理時間。

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");
}

// 采樣一個標記并檢查它是否是EOG(生成結束標記)
// 將整數標記轉換為其對應的單詞片段
_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);


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

return piece;
}
  • 此外,對于用戶的每個查詢,LLM將整個標記化對話(存儲在_messages中的所有消息)作為輸入。如果我們每次都在startCompletion方法中標記整個對話,那么隨著對話變長,預處理時間和總體推理時間將會增加。
  • 為了避免這種計算,我們只需要標記添加到_messages的最新消息/查詢。_formattedMessages中消息被標記的長度存儲在_prevLen中。在響應生成結束時,即在LLMInference::stopCompletion中,我們通過將LLM的響應附加到_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");
}
}

編寫析構函數

我們在_messages和llama.cpp內部實現了一個析構函數方法來釋放動態分配的對象。

LLMInference::~LLMInference() {
//釋放消息中消息文本所占用的內存(因為我們已使用strdup()創建了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應用程序

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

#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;
}

運行示例程序

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

mkdir build
cd build
cmake ..
make
./chat

輸出結果如下:

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

結論

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

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

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

譯者介紹

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

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

?著作權歸作者所有,如需轉載,請注明出處,否則將追究法律責任
已于2025-1-20 07:59:15修改
收藏
回復
舉報
回復
相關推薦
自拍偷拍亚洲一区| 亚洲激情 欧美| 一区二区av在线| 亚洲一级高清| 国产成人无码www免费视频播放| 欧美午夜精品久久久久免费视| 亚洲一级二级三级在线免费观看| av一级久久| 黄色一级大片在线免费观看| 国产精品美女午夜av| 国产欧美日韩不卡免费| 午夜欧美巨大性欧美巨大| 99久久免费看精品国产一区 | 欧洲一区二区三区| 影音先锋资源av| 久久久久国产视频| 成人免费看黄yyy456| av中文资源在线资源免费观看| 久久久久亚洲av无码网站| 欧美成人免费全部观看天天性色| 国产一区二区调教| 男人av在线播放| 国产黄色大片免费看| 国产欧美va欧美va香蕉在| 亚洲欧美日韩国产综合在线| swag国产精品一区二区| av资源免费观看| 欧美日本韩国国产| 欧美日韩在线播放| 国语精品一区| 色视频免费在线观看| 高清av免费看| 97在线观看视频国产| 中文成人av在线| swag国产精品一区二区| 中文天堂在线资源| 成熟丰满熟妇高潮xxxxx视频| 国产亚洲精品成人av久久ww| 国产成人综合视频| 九七电影院97理论片久久tvb| 日本三级黄色大片| 特级毛片在线免费观看| 亚洲欧美综合另类中字| av在线不卡电影| 亚洲日本va| 中文字幕一区二区免费| 成人免费观看视频在线观看| 九九久久久久久久久激情| 国产三级一区二区| 精品一区电影| 国产色a在线| 魔女鞋交玉足榨精调教| 麻豆传媒一区二区| 精品香蕉一区二区三区| 久久亚洲精品国产精品紫薇| 欧美交a欧美精品喷水| 日本黄色一区二区三区| 免费在线观看日韩av| 91在线观看免费观看| 欧美人狂配大交3d怪物一区| 另类的小说在线视频另类成人小视频在线 | 欧美a级片视频| 久操视频在线| 男女免费视频网站| 国产精品333| 国产成人精品综合| 欧美日韩免费观看一区二区三区 | 国内黄色精品| 在线观看黄色av| 91日韩中文字幕| 国产中文字幕二区| 国产精品1234| 日韩三级在线观看| wwwwww.欧美系列| 欧美限制电影| 牛牛在线精品视频| 日韩免费av网站| 免费看的av网站| 日韩精品无码一区二区三区| 欧美超级免费视 在线| 精品久久久视频| 蜜桃视频免费观看一区| 8848成人影院| av在线二区| 日本熟妇一区二区| 在线观看中文av| 欧美一区二区三区四区夜夜大片| 久久伊人精品一区二区三区| 欧美日韩国产中文精品字幕自在自线 | www.com.cn成人| 亚洲福利在线观看视频| 五月婷婷六月香| 日韩中文字幕在线视频观看| 91中文在线视频| 久久精品在线视频| 欧美亚洲丝袜传媒另类| 91网站在线播放| 亚洲私人影院| swag国产精品一区二区| www在线免费观看视频| 中文字幕在线观看免费| 五月天综合视频| 一本大道熟女人妻中文字幕在线| 国产精品久久精品视| 欧美成人剧情片在线观看| 欧美日本在线一区| 综合网在线视频| 免费一级片91| 午夜精品一区二区三区国产 | 国产经典三级在线| 丰满肉嫩西川结衣av| 国产一级做a爰片在线看免费| 在线成人免费av| 国产a级片网站| 鲁丝一区鲁丝二区鲁丝三区| 欧美做爰性生交视频| 亚洲欧美在线播放| 欧美三级资源在线| 亚洲欧美国产三级| 成人永久免费视频| 麻豆精品网站| 中文字幕免费一区二区| 欧美人与动xxxxz0oz| 狠狠久久伊人中文字幕| 欧美黄色视屏| 可以在线观看的黄色| 国产精品-色哟哟| 日本韩国欧美中文字幕| 亚洲天堂精品一区| 日韩aaaaa| 亚洲一二区在线观看| 欧美大片在线播放| 午夜老司机精品| 国产区欧美区日韩区| 国产精品一区二区三区免费视频| 欧美极品xxxx| 超碰91人人草人人干| 亚洲视频免费一区| 欧美v国产在线一区二区三区| 色综合色综合色综合| 亚洲影院理伦片| 中文字幕一区二区三区蜜月| 91免费在线视频观看| 国产精品中文欧美| 麻豆视频一区二区| 免费日韩av片| 性色一区二区三区| 亚洲色诱最新| 亚洲国产精品一区| 亚洲激精日韩激精欧美精品| 一精品久久久| 欧美黄色大片网站| 亚州av乱码久久精品蜜桃| gogogo高清在线观看一区二区| 欧美交a欧美精品喷水| 亚洲精品在线a| jizz性欧美23| 麻豆成人入口| 女一区二区三区| 日本国产精品| 久久超碰99| 手机亚洲手机国产手机日韩| 久久亚洲精品中文字幕蜜潮电影| 黑丝美女一区二区| 91成人免费| 亚洲第一网站| 日日夜夜免费精品视频| 日本不卡视频一二三区| 激情综合色播激情啊| 国产在线精品一区在线观看麻豆| 国产福利精品导航| 91麻豆精品在线观看| 国产肉丝袜一区二区| 中文字幕一区二区日韩精品绯色| 亚洲欧美成人一区二区三区| 亚洲成av人**亚洲成av**| 一本色道久久加勒比精品| 7777精品久久久大香线蕉| 亚洲国产精品字幕| www国产精品视频| 91国产美女在线观看| 成人av.网址在线网站| 国产精品国产亚洲精品看不卡15| 日本一区二区精品| 国产午夜福利100集发布| 国产精品久久久毛片| 日韩www视频| 四虎影院中文字幕| 中文字幕无线码一区| 日韩大片b站免费观看直播| 亚洲第一图区| 国产精品成人**免费视频| 国产a久久精品一区二区三区| 欧美精品观看| 国产一区二区女| 国产精品久久久久久久浪潮网站| 亚洲电影激情视频网站| 日韩一级高清毛片| 久久久国产精品一区| 国产中文字幕日韩| 亚洲不卡1区| 欧美伦理片在线观看| 国产又粗又硬视频| 中文字幕你懂的| 9i精品一二三区| 成人国产精品久久| 欧美a级片一区| 成人中文字幕在线| 欧美日韩中文字幕| 亚洲人成在线电影| 国产成人av网址| 亚洲国产日韩综合一区| 伊人色在线观看| 国产av 一区二区三区| 天天色棕合合合合合合合| 色在线中文字幕| 成人网18免费网站| 国产精品88888| 富二代精品短视频| 一本色道久久88综合亚洲精品ⅰ| 国产精品av在线| www.99riav| 黄色正能量网站| 国产免费av观看| 中文在线最新版地址| 一级欧洲+日本+国产 | 欧美精品色哟哟| 日本韩国一区| av在线播放免费| 粉嫩的18在线观看极品精品| 美女mm1313爽爽久久久蜜臀| 亚洲九九爱视频| 在线观看久久av| 久久99欧美| gogo亚洲国模私拍人体| 91在线视频免费播放| 久久99亚洲网美利坚合众国| 日韩在线综合| 91视频精品在这里| 日韩欧美亚洲另类制服综合在线| 日韩av手机在线观看| 九色自拍视频在线观看| 日韩欧美综合视频| 99riav在线| 成人3d动漫在线观看| 久久久久久久久久久久久久久99 | 日本老熟妇毛茸茸| 亚洲成人第一网站| 天堂а√在线最新版中文在线| 亚洲色图二区| 亚洲精品欧美专区| 久久国产精品99国产精| 正在播放91九色| 任我爽在线视频| 国产在线高潮| 精品成人一区| 五月天激情综合| 欧美自拍大量在线观看| 91九色蝌蚪成人| yjizz视频| 日韩一区二区三区中文字幕| 国产成人高清| 国产精品福利av| 欧美激情亚洲视频| 1024av视频| 一级做a爱片久久毛片| 99精品视频在线免费播放| 国产v日产∨综合v精品视频| 亚洲国产小视频| 一区精品视频| 精品无码久久久久久久久| 亚洲精品成人图区| 激情图片小说一区| 精品粉嫩超白一线天av| 日韩av大全| 久久免费视频99| 国产精成人品2018| 东方aⅴ免费观看久久av| 伊人伊成久久人综合网站| 国产91在线亚洲| 亚洲天堂中文字幕在线| 日韩精品社区| 亚洲综合成人在线视频| 国产成一区二区| 欧美日韩人妻精品一区在线| 日本高清中文字幕在线| 99在线精品视频在线观看| 在线观看欧美日本| 就去色蜜桃综合| 中文字幕第28页| 日韩精品视频中文字幕| 久久精品人人做| 欧美亚洲免费电影| 99久久国产精| a级大胆欧美人体大胆666| 狠狠色丁香婷婷综合| 在线视频国产日韩| 欧美 日韩精品| 每日更新在线观看av| 日韩国产在线一| 亚洲性无码av在线| 韩国日本美国免费毛片| 免费在线观看污视频| 六月婷婷一区| 中文字幕亚洲一区二区三区| 一区二区三区国产免费| av在线中文| 精品中文av资源站在线观看| 久久天天躁狠狠躁夜夜av| 欧美一级小视频| 五月婷婷视频在线观看| 99riav久久精品riav| 国产精品www| 久久精品黄色片| 色天下一区二区三区| 欧美午夜视频网站| 91精品国产毛片武则天| 天天干天天爽天天操| 首页综合国产亚洲丝袜| 日韩在线播放av| 538国产视频| 粉嫩91精品久久久久久久99蜜桃| 亚洲色图在线看| 精品久久久久久亚洲| 亚洲精品一区二区二区| 欧美日本三区| 中日韩午夜理伦电影免费| 国产999免费视频| 男人皇宫亚洲男人2020| 成人免费在线观看入口| 国内一区二区在线视频观看| 中文字幕一区二区三区人妻四季| 欧美精品首页| www欧美日韩| 成人性生交大片免费看无遮挡aⅴ| 日本在线成人| 欧美日韩综合一区| 日本久久久精品视频| 欧美v亚洲v| 亚洲精品中文字幕在线观看| 欧美亚洲一级二级| 亚洲欧洲成人在线| 成人18视频在线播放| 亚洲va欧美va国产综合久久| 姑娘第5集在线观看免费好剧| 99精品国产在热久久| 久久久噜噜噜久噜久久| 毛片a片免费观看| 午夜精品国产| 欧美精品激情blacked18| 青青草国产在线观看| 欧美黄在线观看| 久久久久久久久久国产精品| 亚洲综合视频网站| 欧美日韩日本国产亚洲在线| 欧美成人激情在线| 欧美一级高潮片| 性欧美精品高清| 国产精品美女网站| 国产女人高潮的av毛片| 国产在线精品一区二区| 国产精品一区而去| 免费在线一级视频| 国产精品美女一区二区| 日本a级片在线观看| 国产污视频在线播放| 欧美私模裸体表演在线观看| 精品视频一区二区| 成人在线观看网站| 亚洲激情校园春色| 国产成人久久婷婷精品流白浆| 不卡亚洲精品| 亚洲精品久久久久中文字幕二区| 亚洲欧洲久久久| 亚洲天堂偷拍| 91久久久久久久久| 视频三区在线观看| 亚洲激情在线播放| 日本人69视频| 精品国产99| 午夜免费在线观看精品视频| 亚洲一区中文字幕永久在线| 成年人国产精品| 免费看日b视频| 亚洲伦理一区二区| 亚洲欧洲成视频免费观看| 欧美精品乱码视频一二专区| 免费在线观看精品| 欧美日韩国产三区| segui88久久综合| 日韩欧美黄色影院| 三级影片在线看| 国内成+人亚洲+欧美+综合在线| 欧美一区视久久| 成人欧美一区二区三区的电影| 欧美精品一区二| 精品少妇theporn| thepron国产精品| 欧美在线一区视频| 久久99精品国产自在现线|