Rust高性能LLM推理库llama-cpp-2的使用,支持高效本地运行大语言模型并优化GPU加速

Rust高性能LLM推理库llama-cpp-2的使用

llama-cpp-2是一个Rust语言对llama.cpp库的封装,支持高效在本地运行大语言模型并优化GPU加速。它是utilityai项目中用于支持所有LLM的核心部分。

基本信息

这个库与llama.cpp紧密耦合,并尽可能模仿其API,同时保持安全性以便更新。

依赖要求

使用bindgen来构建与llama.cpp的绑定,因此需要在系统上安装clang。如果这有问题,可以创建issue讨论包含绑定的可能性。

免责声明

这个crate不安全。存在滥用llama.cpp提供的API创建未定义行为(UB)的方法,如果发现任何问题请创建issue。不要在对UB不可接受的任务中使用此代码。

这不是一个简单的库。理想情况下,应该在这个crate之上编写一个良好的抽象层来提供符合人体工学的API - 这个crate相对于原始绑定的优势是安全性(并不多)而不是其他。

安装

在项目目录中运行以下Cargo命令:

cargo add llama-cpp-2

或在Cargo.toml中添加:

llama-cpp-2 = "0.1.113"

示例代码

以下是一个基本使用示例:

use llama_cpp_2::{LlamaModel, LlamaContext, LlamaParams};

fn main() {
    // 初始化模型参数
    let params = LlamaParams {
        model_path: "path/to/model.bin".to_string(),
        n_ctx: 2048,  // 上下文长度
        n_threads: 4,  // 使用的线程数
        use_gpu: true, // 启用GPU加速
        ..Default::default()
    };

    // 加载模型
    let model = LlamaModel::load_from_file(&params.model_path).expect("Failed to load model");
    
    // 创建推理上下文
    let mut ctx = LlamaContext::new(&model, params).expect("Failed to create context");

    // 准备输入
    let prompt = "Rust is a programming language that";
    
    // 运行推理
    let output = ctx.generate(prompt, 100).expect("Generation failed");
    
    println!("Generated text: {}", output);
}

完整示例代码

use llama_cpp_2::{LlamaModel, LlamaContext, LlamaParams};
use std::path::PathBuf;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 设置模型路径 - 请替换为实际的模型路径
    let model_path = PathBuf::from("path/to/model.bin");
    
    // 初始化模型参数
    let params = LlamaParams {
        model_path: model_path.to_str().unwrap().to_string(),
        n_ctx: 2048,       // 上下文token数量
        n_threads: 8,      // 使用CPU线程数
        use_gpu: true,     // 启用GPU加速
        n_gpu_layers: 20,  // 使用GPU的层数
        seed: 1234,        // 随机种子
        ..Default::default()
    };

    // 加载模型
    let model = LlamaModel::load_from_file(&params.model_path)
        .expect("Failed to load model");
    
    // 创建推理上下文
    let mut ctx = LlamaContext::new(&model, params)
        .expect("Failed to create context");

    // 准备输入文本
    let prompt = "Rust is a programming language that";
    
    println!("Starting generation with prompt: {}", prompt);
    
    // 运行推理,生成100个token
    let output = ctx.generate(prompt, 100)
        .expect("Generation failed");
    
    println!("\nGenerated text:\n{}", output);
    
    // 高级用法示例:交互式生成
    println!("\nStarting interactive generation...");
    
    let mut interactive_ctx = ctx; // 复用之前的context
    
    let mut input = String::new();
    loop {
        println!("\nEnter your prompt (or 'quit' to exit):");
        std::io::stdin().read_line(&mut input)?;
        
        input = input.trim().to_string();
        if input == "quit" {
            break;
        }
        
        let generated = interactive_ctx.generate(&input, 50)
            .expect("Interactive generation failed");
        
        println!("Response:\n{}", generated);
        
        input.clear(); // 清空输入缓冲区
    }

    Ok(())
}

贡献指南

欢迎贡献。请在开始非平凡的PR工作之前创建issue。

许可证

MIT OR Apache-2.0


1 回复

Rust高性能LLM推理库llama-cpp-2使用指南

简介

llama-cpp-2是一个Rust语言实现的高性能大语言模型(LLM)推理库,支持在本地高效运行各种大语言模型。该库特别优化了GPU加速能力,让开发者能够在普通硬件上运行大型语言模型。

主要特性

  • 纯Rust实现,安全高效
  • 支持多种量化模型格式
  • 优化的GPU加速支持
  • 低内存占用
  • 跨平台支持(Windows/Linux/macOS)

安装方法

在Cargo.toml中添加依赖:

[dependencies]
llama-cpp-2 = "0.1"  # 请使用最新版本号

或者直接运行:

cargo add llama-cpp-2

基本使用方法

1. 加载模型

use llama_cpp_2::{
    Model, ModelParams, 
    Context, ContextParams
};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 设置模型参数
    let model_params = ModelParams {
        n_gpu_layers: 20,  // 使用20层GPU加速
        ..Default::default()
    };
    
    // 加载模型文件
    let model = Model::load_from_file(
        "path/to/your/model.bin", 
        model_params
    )?;
    
    // 创建上下文
    let ctx_params = ContextParams::default();
    let mut ctx = model.create_context(ctx_params)?;
    
    Ok(())
}

2. 运行推理

// 接上面的代码

// 准备输入
let prompt = "Rust是一种";
let tokens = model.tokenize(prompt, true)?;

// 开始推理
ctx.eval(&tokens, tokens.len(), 0)?;

// 获取输出
let n_vocab = model.n_vocab() as i32;
let logits = ctx.get_logits();
let next_token = logits
    .iter()
    .enumerate()
    .max_by(|(_, a), (_, b)| a.partial_cmp(b).unwrap())
    .map(|(idx, _)| idx)
    .unwrap();

// 将token转换回文本
let next_word = model.detokenize(&[next_token as i32])?;
println!("下一个词: {}", next_word);

3. 完整文本生成示例

use llama_cpp_2::{Model, ModelParams};

fn generate_text(model_path: &str, prompt: &str, max_tokens: usize) {
    let model = Model::load_from_file(
        model_path,
        ModelParams {
            n_gpu_layers: 20,
            ..Default::default()
        }
    ).unwrap();
    
    let mut ctx = model.create_context(Default::default()).unwrap();
    let tokens = model.tokenize(prompt, true).unwrap();
    
    ctx.eval(&tokens, tokens.len(), 0).unwrap();
    
    let mut output = prompt.to_string();
    for _ in 0::max_tokens {
        let logits = ctx.get_logits();
        let next_token = logits
            .iter()
            .enumerate()
            .max_by(|(_, a), (_, b)| a.partial_cmp(b).unwrap())
            .map(|(idx, _)| idx)
            .unwrap();
            
        let word = model.detokenize(&[next_token as i32]).unwrap();
        output.push_str(&word);
        
        ctx.eval(&[next_token as i32], 1, 0).unwrap();
    }
    
    println!("生成结果: {}", output);
}

高级功能

1. 使用GPU加速

let model_params = ModelParams {
    n_gpu_layers: 40,  // 增加GPU加速层数
    main_gpu: 0,       // 使用第一个GPU
    tensor_split: None, // 不使用多GPU分片
    ..Default::default()
};

2. 控制生成参数

use llama_cpp_2::SamplingParams;

let sampling_params = SamplingParams {
    temperature: 0.7,   // 控制随机性
    top_p: 0.9,         // 核采样
    repeat_penalty: 1.1,// 重复惩罚
    ..Default::default()
};

ctx.set_sampling_params(sampling_params);

3. 流式输出

use std::io::{self, Write};

fn stream_output(model: &Model, ctx: &mut Context, max_tokens: usize) {
    for _ in 0..max_tokens {
        let logits = ctx.get_logits();
        let next_token = /* 选择token的逻辑 */;
        
        let word = model.detokenize(&[next_token]).unwrap();
        print!("{}", word);
        io::stdout().flush().unwrap();
        
        ctx.eval(&[next_token], 1, 0).unwrap();
    }
}

完整示例代码

use llama_cpp_2::{Model, ModelParams, SamplingParams};
use std::io::{self, Write};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 1. 加载模型
    let model = Model::load_from_file(
        "path/to/model.bin",
        ModelParams {
            n_gpu_layers: 20,
            ..Default::default()
        }
    )?;
    
    // 2. 创建上下文
    let mut ctx = model.create_context(Default::default())?;
    
    // 3. 设置采样参数
    ctx.set_sampling_params(SamplingParams {
        temperature: 0.7,
        top_p: 0.9,
        ..Default::default()
    });
    
    // 4. 准备输入
    let prompt = "Rust是一种";
    let tokens = model.tokenize(prompt, true)?;
    
    // 5. 运行初始推理
    ctx.eval(&tokens, tokens.len(), 0)?;
    
    // 6. 流式生成输出
    print!("{}", prompt);
    io::stdout().flush()?;
    
    for _ in 0..100 {  // 生成100个token
        let logits = ctx.get_logits();
        let next_token = logits
            .iter()
            .enumerate()
            .max_by(|(_, a), (_, b)| a.partial_cmp(b).unwrap())
            .map(|(idx, _)| idx)
            .unwrap();
            
        let word = model.detokenize(&[next_token as i32])?;
        print!("{}", word);
        io::stdout().flush()?;
        
        ctx.eval(&[next_token as i32], 1, 0)?;
    }
    
    println!();
    Ok(())
}

性能优化建议

  1. 使用量化模型(如GGUF格式)减少内存占用
  2. 根据GPU显存大小调整n_gpu_layers参数
  3. 适当增加上下文窗口大小(n_ctx)但注意内存消耗
  4. 批处理推理请求以提高吞吐量

常见问题

  1. 模型从哪里获取?

    • 可以从HuggingFace等平台下载兼容的GGML或GGUF格式模型
  2. 如何选择GPU层数?

    • 从较小值开始测试,逐步增加直到显存占满
  3. 内存不足怎么办?

    • 使用量化程度更高的模型(如4-bit量化)
    • 减少上下文窗口大小
  4. 支持哪些硬件加速?

    • 支持CUDA(NVIDIA GPU)和Metal(Apple GPU)
    • 也支持纯CPU推理

llama-cpp-2为Rust开发者提供了高效运行大语言模型的能力,结合Rust的安全性和性能优势,是本地AI应用的理想选择。

回到顶部