AI_Gemma实践笔记

我的个人项目需要满足这些需求:

  • 只有一台普通办公电脑:i7-12700K + 16GB RAM + RTX 3060

  • 没有专门的推理服务器

  • 不能占用太多资源,还要能干其他活

  • 中文问答能力要好

  • 推理响应时间要控制在 3 秒内

  • 支持长文本(至少 4K tokens)

  • 成本要低(最好免费)

缘起:为什么写这篇文章

最近在做一个个人项目,需要用到本地化的大语言模型。本来打算直接用 llama.cpp 搭个 Llama 2,结果发现推理速度实在太慢,CPU 都跑到了 100%,生成个百来字要等半天。

这时候 Google 开源了 Gemma 系列模型,说是轻量级但效果不错。我就想着试试看,到底能不能跑起来,效果如何,能不能真的用在生产环境里。

写这篇文章的目的很明确:记录我从零开始部署和使用 Gemma 的完整过程,分享踩过的坑和真实的性能数据,给同样想尝试开源模型的开发者一个参考。

背景:Gemma 是什么

Gemma 是 Google 2024 年开源的一系列轻量级大语言模型,基于 Google 的 Gemini 技术栈。和 Llama 这种动辄 70B 参数的模型不同,Gemma 主打"小而精",主要有两个版本:

  • Gemma 2B:20 亿参数,适合端侧部署
  • Gemma 7B:70 亿参数,平衡性能和资源消耗

更重要的是,Gemma 提供了多格式支持:

  • 原始 PyTorch 权重
  • GGUF 格式(llama.cpp 兼容)
  • TensorFlow/Flax 格式
  • ONNX 格式

这意味着你可以在不同硬件平台上运行,从高端 GPU 到普通 CPU 都能玩。

需求:我要解决的问题

我的个人项目需要满足这些需求:

硬件限制

  • 只有一台普通办公电脑:i7-12700K + 16GB RAM + RTX 3060
  • 没有专门的推理服务器
  • 不能占用太多资源,还要能干其他活

功能需求

  • 中文问答能力要好
  • 推理响应时间要控制在 3 秒内
  • 支持长文本(至少 4K tokens)
  • 成本要低(最好免费)

可维护性

  • 部署简单,别太折腾
  • 有社区支持,遇到问题能找到答案
  • 模型更新要有规律

基于这些需求,Gemma 2B 看起来是个不错的起点:参数少、资源占用小,而且 Google 的技术栈应该不会差。

实现:一步步部署 Gemma

1. 环境准备

先说说我的系统环境:

# 操作系统
Ubuntu 22.04 LTS

# Python 环境
Python 3.10.12
conda 环境

# 硬件
CPU: Intel i7-12700K
RAM: 16GB DDR5
GPU: NVIDIA RTX 3060 12GB

首先安装基础依赖:

# 创建 conda 环境
conda create -n gemma python=3.10 -y
conda activate gemma

# 安装 PyTorch(带 CUDA 支持)
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118

# 安装 transformers 和相关库
pip install transformers accelerate bitsandbytes sentencepiece

这里踩了个坑:bitsandbytes 的版本要和 PyTorch CUDA 版本匹配,不然会报错。我是通过试错才知道要装 CUDA 11.8 版本的 PyTorch。

2. 获取模型权重

Gemma 的模型权重需要先到 Hugging Face 申请权限。步骤如下:

  1. 访问 https://huggingface.co/google/gemma-2b
  2. 点击 “Agree and access repository”
  3. 创建 Hugging Face token(Settings -> Access Tokens)
  4. 在本地登录:
pip install huggingface_hub
huggingface-cli login
# 输入你的 token

然后下载模型:

from transformers import AutoTokenizer, AutoModelForCausalLM
import torch

model_id = "google/gemma-2b"

# 加载 tokenizer
tokenizer = AutoTokenizer.from_pretrained(model_id)

# 加载模型(使用 4-bit 量化节省显存)
model = AutoModelForCausalLM.from_pretrained(
    model_id,
    device_map="auto",
    load_in_4bit=True,
    torch_dtype=torch.float16
)

这里又踩了个坑:第一次下载的时候网络很慢,速度只有几百 KB/s。后来发现国内可以镜像:

export HF_ENDPOINT=https://hf-mirror.com
# 然后再下载就快多了

3. 基础推理测试

先来个简单的推理测试:

def generate_response(prompt, max_length=512):
    input_ids = tokenizer(prompt, return_tensors="pt").input_ids.to("cuda")

    with torch.no_grad():
        outputs = model.generate(
            input_ids,
            max_length=max_length,
            do_sample=True,
            top_k=50,
            top_p=0.95,
            temperature=0.7,
            repetition_penalty=1.1
        )

    response = tokenizer.decode(outputs[0], skip_special_tokens=True)
    return response

# 测试
question = "什么是机器学习?"
answer = generate_response(question)
print(answer)

运行结果还不错,中文回答挺流畅的。但速度…第一遍推理花了 4.2 秒,有点慢。

4. 性能优化

为了提升推理速度,我尝试了几种优化方法:

方法 1:使用 vLLM

vLLM 是个专门优化 LLM 推理速度的框架:

pip install vllm
from vllm import LLM, SamplingParams

llm = LLM(model="google/gemma-2b", trust_remote_code=True)
sampling_params = SamplingParams(temperature=0.7, top_p=0.95, max_tokens=512)

outputs = llm.generate(["什么是机器学习?"], sampling_params)
print(outputs[0].outputs[0].text)

结果:推理时间降到了 1.8 秒,提升明显!

方法 2:使用 GGUF 格式和 llama.cpp

如果想在 CPU 上跑,可以转换为 GGUF 格式:

# 安装转换工具
pip install llama-cpp-python[server]

# 下载转换脚本
wget https://raw.githubusercontent.com/ggerganov/llama.cpp/master/convert-hf-to-gguf.py

# 转换模型
python convert-hf-to-gguf.py /path/to/gemma-2b --outfile gemma-2b.gguf

然后用 llama.cpp 推理:

from llama_cpp import Llama

llm = Llama(
    model_path="gemma-2b.gguf",
    n_ctx=4096,
    n_gpu_layers=-1,  # 使用所有 GPU 层
    verbose=False
)

output = llm("什么是机器学习?", max_tokens=512)
print(output['choices'][0]['text'])

这个方法在我这台机器上推理时间是 2.3 秒,比原始 PyTorch 快,但比 vLLM 慢。

方法 3:KV Cache 优化

在多轮对话中,可以复用之前的 KV cache:

class ChatSession:
    def __init__(self, model, tokenizer):
        self.model = model
        self.tokenizer = tokenizer
        self.past_key_values = None
        self.history = []

    def chat(self, message):
        self.history.append({"role": "user", "content": message})
        prompt = self.tokenizer.apply_chat_template(
            self.history,
            tokenize=False,
            add_generation_prompt=True
        )

        inputs = self.tokenizer(prompt, return_tensors="pt").to("cuda")

        with torch.no_grad():
            outputs = self.model.generate(
                **inputs,
                past_key_values=self.past_key_values,
                max_length=inputs.input_ids.shape[1] + 512,
                do_sample=True,
                temperature=0.7,
                top_p=0.95
            )

        response = tokenizer.decode(outputs[0][inputs.input_ids.shape[1]:], skip_special_tokens=True)
        self.history.append({"role": "assistant", "content": response})

        # 保存 KV cache 用于下一轮
        self.past_key_values = outputs.past_key_values

        return response

这样多轮对话的速度能提升 30-40%。

踩坑记录

坑 1:显存不够

一开始我直接加载原始模型,16GB 显存直接爆了。后来才知道要用 4-bit 量化:

model = AutoModelForCausalLM.from_pretrained(
    model_id,
    load_in_4bit=True,  # 关键!
    device_map="auto"
)

如果还是不够,可以用 8-bit 或者 CPU 推理:

# 8-bit 量化
model = AutoModelForCausalLM.from_pretrained(
    model_id,
    load_in_8bit=True,
    device_map="auto"
)

# 或者纯 CPU
model = AutoModelForCausalLM.from_pretrained(
    model_id,
    device_map="cpu"
)

坑 2:中文效果不好

刚开始发现中文回答很生硬,像是机翻的。后来查了资料才知道要指定正确的 tokenizer 配置:

tokenizer = AutoTokenizer.from_pretrained(
    model_id,
    use_fast=True,
    trust_remote_code=True
)

# 或者用专门训练中文的变体
model_id = "THUDM/chatglm3-6b"  # 这个中文效果更好

坑 3:生成重复内容

有时候模型会一直重复某个短语。这个可以通过 repetition_penalty 参数解决:

outputs = model.generate(
    input_ids,
    repetition_penalty=1.1,  # 防止重复
    # 其他参数...
)

坑 4:长文本截断

超过 2048 tokens 的输入会被截断。解决方案:

# 使用支持长文本的版本
model_id = "google/gemma-2b-it"  # "it" 表示 instruction-tuned 版本

# 或者增加 context window
model = AutoModelForCausalLM.from_pretrained(
    model_id,
    max_position_embeddings=8192,  # 扩展到 8K
    # ...
)

坑 5:vLLM 兼容性问题

某些版本的 vLLM 和 Gemma 不兼容。我最后用的是:

pip install vllm==0.2.5
pip install flash-attn==2.3.3

太新或者太老的版本都会出问题。

结果:性能对比和实际应用

经过一番折腾,我做了个性能对比测试:

import time

def benchmark(model, test_questions):
    results = []
    for question in test_questions:
        start = time.time()
        answer = generate_response(question)
        end = time.time()
        results.append({
            "question": question,
            "time": end - start,
            "tokens": len(answer)
        })
    return results

test_questions = [
    "什么是机器学习?",
    "解释一下神经网络的工作原理",
    "如何优化深度学习模型的性能?",
    "什么是 Transformer 架构?",
    "对比一下 CNN 和 RNN 的优缺点"
]

性能对比表

方法平均推理时间GPU 占用RAM 占用优点缺点
原始 PyTorch4.2s8GB6GB简单直接慢、资源占用大
vLLM1.8s6GB4GB最快需要额外依赖
GGUF+llama.cpp2.3s4GB8GB兼容性好比较麻烦
CPU 推理12.5s0GB10GB不需要 GPU太慢

实际应用场景

基于测试结果,我最终选择了 vLLM + Gemma 2B 的方案,用在以下几个场景:

场景 1:个人知识库问答

把我的笔记和文档索引起来,用 Gemma 做问答:

from langchain.embeddings import HuggingFaceEmbeddings
from langchain.vectorstores import Chroma
from langchain.chains import RetrievalQA

# 加载文档
embeddings = HuggingFaceEmbeddings(model_name="BAAI/bge-base-zh")
vectorstore = Chroma.from_documents(documents, embeddings)

# 创建问答链
qa_chain = RetrievalQA.from_chain_type(
    llm=gemma_llm,
    chain_type="stuff",
    retriever=vectorstore.as_retriever()
)

# 查询
answer = qa_chain.run("我在哪篇文章里写过关于多线程的内容?")

响应时间约 2 秒,准确率 80% 左右。

场景 2:代码助手

用 Gemma 帮我写点简单的代码:

code_prompt = """
用 Python 写一个函数,判断一个字符串是否是回文。
要考虑大小写和空格。
"""

code = generate_response(code_prompt, max_length=256)
print(code)

效果还不错,能写出可用的代码,但复杂一点的逻辑还是有问题。

场景 3:自动摘要

写长文的时候用 Gemma 帮我生成摘要:

def summarize(text, max_length=200):
    prompt = f"请用中文总结以下内容的要点:\n\n{text}\n\n总结:"
    summary = generate_response(prompt, max_length=max_length)
    return summary

这个功能用得最多,确实能节省不少时间。

踩坑后的反思

折腾完 Gemma,我有一些反思:

1. 开源模型已经能用,但还不够好

Gemma 的表现已经超出我的预期了,在个人项目里完全够用。但和 GPT-4 比起来,还是有明显差距,特别是在逻辑推理和长文本理解上。

2. 部署成本不低

虽然模型免费,但要跑起来还是需要一定的硬件投入。RTX 3060 这张卡花了 2000 多,对于个人用户来说不算小数目。

3. 优化是个无底洞

性能优化可以一直做下去,从量化到框架选择,再到具体的参数调整。投入产出比需要自己权衡。

4. 社区支持很重要

很多坑都是靠社区的经验解决的。Gemar 的社区虽然不如 Llama 活跃,但好歹还有。

结语

从零开始部署 Gemma 到实际应用,大概花了两周时间。踩了不少坑,但也学到了很多。

总的来说,Gemma 是个不错的开源模型选择,特别适合个人项目和中小型应用。虽然不如商业模型强大,但胜在自由可控,而且不需要 API 调用成本。

如果你的需求和我类似,可以考虑试试 Gemma。记住几个关键点:

  1. 根据硬件选择合适的模型版本和量化方案
  2. vLLM 是提升推理速度的好选择
  3. 遇到问题先查社区,大概率别人也遇到过
  4. 性能优化要权衡投入产出比

开源大模型的时代已经到来,虽然还不够完美,但至少给了我们更多选择。希望这篇文章能帮助到同样在折腾开源模型的你。

如果在这个过程中遇到问题,或者有更好的优化方案,欢迎交流。

版权声明: 本文首发于 指尖魔法屋-AI_Gemma实践笔记https://blog.thinkmoon.cn/post/403-ai-gemma-google-open-source-practice/) 转载或引用必须申明原指尖魔法屋来源及源地址!