跳至主要内容

微调 Google Gemma:用自定义指令增强大型语言模型

了解如何在 GPU/TPU 上运行推理,并在角色扮演数据集上微调最新的 Gemma 7b-it 模型。
· 12分钟 阅读

使用 AI 探索

当下是 AI 领域令人振奋的时刻。Google、Meta 和 Twitter 等大型公司正大力推动其大型语言模型(LLM)的开源化。近期,Google DeepMind 团队发布了 Gemma——一个轻量级、开源的 LLM 家族,基于与 Google Gemini 模型相同的研究与技术构建。

Gemma 标志

图片来源

本文将介绍 Gemma 模型、如何通过云端 GPU 与 TPU 访问它们,以及如何在角色扮演数据集上训练最新的 Gemma 7b-it 模型。

了解 Google 的 Gemma

Gemma(拉丁语意为“宝石”)是一系列文本到文本、仅解码器的开放模型,由Google 多个团队(尤其是 Google DeepMind)共同开发。它受 Gemini 模型启发,设计轻量,并与各大主流框架兼容。

Google 已发布两种规模的 Gemma 模型权重,即 Gemma 2B 和 Gemma 7B,并提供预训练与指令微调变体,如 Gemma 2B-it 和 Gemma 7B-it。

众所周知,Gemma 与 Gemini 在技术组件上有许多共通之处,就同量级而言,相比 Meta 的 Llama-2 等其他开源模型,它实现了同级最佳的性能。在所有 LLM 基准上均优于 Llama-2。

Gemma 基准。Gemma 对比 Llama-2

图片来源

Gemma 支持多种工具与系统,包括 Keras 3.0、原生 PyTorch、JAX 以及 Hugging Face Transformers 等多框架工具。它也可在笔记本、台式机、物联网、移动端与云端等常见设备类型上运行。

您现在可以使用您喜爱的机器学习框架(如 Keras 3.0)在免费的 Cloud TPU 上运行推理和有监督微调(SFT)。

Google 还随 Gemma 一同推出了负责式生成式 AI 工具包,为开发者提供指南、关键工具与安全分类方法,帮助打造更安全的 AI 应用。

如果您是 AI 与 LLM 的新手,建议先学习 AI Fundamentals 技能路径。它将帮助您掌握 ChatGPT、大型语言模型、生成式 AI 等热门主题的实用知识。

如何访问 Google 的 Gemma 模型

访问 Gemma 非常简单;您可以在 HuggingChat 与 Poe 上免费开始使用。您也可以通过从 Hugging Face 下载模型权重,并配合 GPT4ALL 或 LMStudio 在本地使用它。

本节将介绍如何加载 Gemma 模型,并利用 Kaggle 平台提供的免费 GPU 与 TPU 运行推理。

在 TPU 上运行 Gemma 推理

前往 Keras/Gemma,向下滚动,选择“gemma_instruct_2b_en”模型变体,并点击“New Notebook”按钮。它将启动一个 Cloud Notebook,输入目录中已包含 Gemma 模型。

Gemma 模型的 Keras 实现

在右侧面板向下滚动,将加速器选择为“TPU VM v3-8”。

在 Kaggle 中访问 Keras Gemma v2 模型

确保已安装并更新所有必要的 Python 库。

!pip install -q tensorflow-cpu
!pip install -q -U keras-nlp tensorflow-hub
!pip install -q -U keras>=3
!pip install -q -U tensorflow-text

要检查可用 TPU 的数量,您可以使用 `jax` 库的 `device` 函数来显示 TPU 设备。此处我们可使用 8 个 TPU。

import jax

jax.devices()
[TpuDevice(id=0, process_index=0, coords=(0,0,0), core_on_chip=0),
 TpuDevice(id=1, process_index=0, coords=(0,0,0), core_on_chip=1),
 TpuDevice(id=2, process_index=0, coords=(1,0,0), core_on_chip=0),
 TpuDevice(id=3, process_index=0, coords=(1,0,0), core_on_chip=1),
 TpuDevice(id=4, process_index=0, coords=(0,1,0), core_on_chip=0),
 TpuDevice(id=5, process_index=0, coords=(0,1,0), core_on_chip=1),
 TpuDevice(id=6, process_index=0, coords=(1,1,0), core_on_chip=0),
 TpuDevice(id=7, process_index=0, coords=(1,1,0), core_on_chip=1)]

接下来,我们将通过将 `jax` 设置为 Keras 后端,为 Keras 3 启用 TPU。

import os

os.environ["KERAS_BACKEND"] = "jax"

完成初始设置后,访问 Gemma 模型并生成响应就很容易了。我们将使用 `keras_nlp` 库从 Kaggle 加载模型,然后将提示传给 `generate` 函数。

import keras
import keras_nlp

model_name = "/kaggle/input/gemma/keras/gemma_instruct_2b_en/2"
gemma_lm = keras_nlp.models.GemmaCausalLM.from_preset(model_name)
prompt = "Can you share an interesting fact about Leonardo da Vinci?"

gemma_lm.generate(prompt, max_length=100)

结果如下:

"Can you share an interesting fact about Leonardo da Vinci?\n\nSure, here's an interesting fact about Leonardo da Vinci:\n\nLeonardo da Vinci was born in a village called Vinci, Italy, which is now part of the city of Florence."

您可以直接运行 Kaggle 笔记本(Gemma-2B-V2 Simple Inference on TPU),使用免费的 TPU 开始生成回答。

在 GPU 上运行 Gemma 推理

现在,我们将学习如何使用 GPU,并采用 transformer 框架而非 Keras 来生成响应。

前往 google/gemma,向下滚动,选择 transformers,再选择“7b-it”模型变体,并点击“New Notebook”按钮。这样将启动一个 Cloud Notebook,输入目录中包含正确版本的 Gemma 模型。

注意:您还可以继续向下滚动到推理部分。在那里,您可以通过输入提示来测试各种 Gemma 变体并生成响应,快速且便捷。

在新建的笔记本中,先修改标题,然后将加速器改为 GPT T4 x2。

访问 Gemma 模型的 transformers 实现

安装并更新所有必要的 Python 包。

%%capture
%pip install -U bitsandbytes
%pip install -U transformers
%pip install -U accelerate

由于显存受限,我们无法在 Kaggle 的 GPU 上加载完整的 Gemma 7b-it 模型。为解决该问题,我们将使用 BitsAndBytes 以 NF4 配置进行 4 比特量化来加载模型。同时加载分词器。

import torch
from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig, AutoConfig

modelName = "/kaggle/input/gemma/transformers/7b-it/2"

bnbConfig = BitsAndBytesConfig(
    load_in_4bit = True,
    bnb_4bit_quant_type="nf4",
    bnb_4bit_compute_dtype=torch.bfloat16,
)

model = AutoModelForCausalLM.from_pretrained(
    modelName,
    device_map = "auto",
    quantization_config=bnbConfig
)

tokenizer = AutoTokenizer.from_pretrained(modelName)

构建一个包含 System、User 与 AI 的简易提示模板。我们让模型用 Python 生成星形图案的代码。

将最终提示传入分词器,再传入模型生成预测。随后对预测结果进行解码并转为字符串。最后使用 Markdown 函数以 Markdown 样式展示响应。

from IPython.display import Markdown, display
system =  "You are a skilled software engineer who consistently produces high-quality Python code."
user = "Write a Python code to display text in a star pattern."

prompt = f"System: {system} \n User: {user} \n AI: "
    
inputs = tokenizer(prompt, return_tensors='pt', padding=True, truncation=True).to("cuda")

outputs = model.generate(**inputs, max_length=500, num_return_sequences=1)

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

Markdown(text.split("AI:")[1])

可以看到,Gemma 7b-it 表现相当不错。

针对代码生成提示的 Gemma 模型输出

您可以克隆 Kaggle 笔记本 Gemma-7B Simple Inference on GPU 自行运行代码。

如何微调 Google 的 Gemma:一步步实操

本节我们将把 Gemma 7b-it 模型微调到 hieunguyenminh/roleplay 数据集上。我们将使用 Kaggle 的 P100 GPU 作为加速器。

阅读我们的指南 LLM 微调入门指南,深入了解每个步骤。

环境准备

务必安装并更新所有必要的 Python 包,以避免出错。

%%capture 
%pip install -U bitsandbytes 
%pip install -U transformers 
%pip install -U peft 
%pip install -U accelerate 
%pip install -U trl
%pip install -U datasets

加载我们将用于加载数据集、模型与分词器、执行有监督微调(SFT)与推理的所有包。

from transformers import (
    AutoModelForCausalLM,
    AutoTokenizer,
    BitsAndBytesConfig,
    HfArgumentParser,
    TrainingArguments,
    pipeline,
    logging,
)
from peft import (
    LoraConfig,
    PeftModel,
    prepare_model_for_kbit_training,
    get_peft_model,
)
import os, torch, wandb
from datasets import load_dataset
from trl import SFTTrainer

定义基础模型与数据集的名称,以及之后将上传至 Hugging Face Hub 的微调模型名称。

这些变量会在加载数据集与模型、分词、训练与保存模型等多个阶段使用。

base_model = "/kaggle/input/gemma/transformers/7b-it/2"
dataset_name = "hieunguyenminh/roleplay"
new_model = "gemma-7b-it-v2-role-play"

登录 Hugging Face CLI

我们将从 Kaggle secrets(环境变量)中加载 Hugging Face API 密钥。

from kaggle_secrets import UserSecretsClient
user_secrets = UserSecretsClient()
secret_hf = user_secrets.get_secret("HUGGINGFACE_TOKEN")

使用该 API 密钥登录 Hugging Face CLI。这样我们既能访问模型,也能将其保存到 Hugging Face Hub。

!huggingface-cli login --token $secret_hf

初始化 W&B 工作区

使用 W&B API 密钥启动 Weights & Biases(W&B)工作区。我们将用此工作区跟踪模型训练。

secret_wandb = user_secrets.get_secret("wandb")

# Monitoring the LLM
wandb.login(key = secret_wandb)
run = wandb.init(
    project='Fine tuning Gemma 7B', 
    job_type="training", 
    anonymous="allow"
)

加载数据集

从 Hugging Face 上的角色扮演数据集中取前 1000 行数据,并展示 `text` 列的一个样本。

#Loading the dataset
dataset = load_dataset(dataset_name, split="train[0:1000]")
dataset["text"][100]

我们的数据集由基于名人风格的用户与助手之间的连续对话构成,即角色扮演。

角色扮演数据集第 100 行

加载模型与分词器

为避免内存问题,我们将使用 BitsAndBytesConfig 以 4 比特精度加载模型。它会直接从 Kaggle 加载,无需下载。

# Load base model(Gemma 7B-it)
bnbConfig = BitsAndBytesConfig(
    load_in_4bit = True,
    bnb_4bit_quant_type="nf4",
    bnb_4bit_compute_dtype=torch.bfloat16,
)

model = AutoModelForCausalLM.from_pretrained(
        base_model,
        quantization_config=bnbConfig,
        device_map="auto"
)

model.config.use_cache = False # silence the warnings. Please re-enable for inference!
model.config.pretraining_tp = 1
model.gradient_checkpointing_enable()

加载分词器,并配置 pad token 以修复 fp16 相关问题。

# Load tokenizer
tokenizer = AutoTokenizer.from_pretrained(base_model)
tokenizer.padding_side = 'right'
tokenizer.pad_token = tokenizer.eos_token
tokenizer.add_eos_token = True
tokenizer.add_bos_token, tokenizer.add_eos_token

添加适配器层

通过给模型添加适配器层,我们可以更高效地进行微调。无需训练整个模型,只更新适配器层的参数即可,从而加速训练过程。

我们的目标模块为“o_proj”、“q_proj”、“up_proj”、“v_proj”、“k_proj”、“down_proj”和“gate_proj”。

model = prepare_model_for_kbit_training(model)
peft_config = LoraConfig(
    lora_alpha=16,
    lora_dropout=0.1,
    r=64,
    bias="none",
    task_type="CAUSAL_LM",
    target_modules=['o_proj', 'q_proj', 'up_proj', 'v_proj', 'k_proj', 'down_proj', 'gate_proj']
)
model = get_peft_model(model, peft_config)

训练模型

开始训练前,我们需要指定超参数。这些参数至关重要,可以调整以优化训练过程并提升模型性能。

如需更好地理解每个超参数,建议阅读微调 LLaMA 2 教程。

training_arguments = TrainingArguments(
    output_dir="./gemma-7b-v2-role-play",
    num_train_epochs=1,
    per_device_train_batch_size=2,
    gradient_accumulation_steps=1,
    optim="paged_adamw_32bit",
    save_strategy="epoch",
    logging_steps=100,
    logging_strategy="steps",
    learning_rate=2e-4,
    fp16=False,
    bf16=False,
    group_by_length=True,
    report_to="wandb"
)

要设置有监督微调(SFT)训练器,需要将模型、数据集、LoRA 配置、分词器和训练参数作为参数传入。

trainer = SFTTrainer(
    model=model,
    train_dataset=dataset,
    peft_config=peft_config,
    max_seq_length= 512,
    dataset_text_field="text",
    tokenizer=tokenizer,
    args=training_arguments,
    packing= False,
)

现在我们使用 `.train` 函数启动训练。微调耗时约 1 小时 1 分钟。训练损失逐步下降,您也可以通过增加 epoch 数来进一步降低损失。

trainer.train()

训练步数与训练损失

结束 W&B 会话,并将模型配置为用于推理。

wandb.finish()
model.config.use_cache = True

W&B 运行历史

我们在两种 GPU 加速器上训练了模型。结果显示,P100 的速度大约是 T4 2X 的两倍。

W&B 在线模型指标

保存模型

我们现在将本地保存模型适配器,并将模型上传到 Hugging Face Hub。`push_to_hub` 命令会创建仓库并将适配器配置与适配器权重推送到 Hub。

# Save the fine-tuned model
trainer.model.save_pretrained(new_model)
trainer.model.push_to_hub(new_model, use_temp_dir=False)

注意:这里只是适配器;如果保存完整模型,大小大约为 18 GB。

将模型适配器上传至 Hugging Face

我们可以进入 Hugging Face 的个人主页查看新模型。

在 Hugging Face 上的微调 Gemma 模型

图片来源

模型推理

要用微调后的模型生成响应,需要按以下步骤进行。

首先,以角色扮演数据集的格式创建提示。然后将提示传入分词器,再传入模型生成预测。

最后通过分词器对预测输出进行解码,得到可读文本。

prompt = '''<|system|>Harry Potter is a wizard known for his distinctive lightningshaped scar and his remarkable journey through magic and battles against the dark wizard Voldemort.
<|user|> What is the meaning of hate? 
<|assistant|>'''
    
inputs = tokenizer(prompt, return_tensors='pt', padding=True, truncation=True).to("cuda")

outputs = model.generate(**inputs, max_length=500, num_return_sequences=1)

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

print(text)

表现不错。它还会提出相关的追问。

微调后 Gemma 模型输出 1

再换一个新角色试试:迈克尔·乔丹。

prompt = '''<|system|>Michael Jordan an NBA legend known for his competitive drive six championship wins with the Chicago Bulls.
<|user|> What motivates you in the life? 
<|assistant|>'''
    
inputs = tokenizer(prompt, return_tensors='pt', padding=True, truncation=True).to("cuda")

outputs = model.generate(**inputs, max_length=500, num_return_sequences=1)

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

print(text)

我认为我们已很好地将基础模型微调为能够理解新的回复风格。

微调后 Gemma 模型输出 2

如果您在将模型微调到自己的数据集时遇到困难,请查看 Kaggle 笔记本 Gemma-7B 4-bit QLoRA Fine-tuning。

您还可以通过 微调 OpenAI 的 GPT-4 教程,学习如何微调顶尖模型。

使用角色扮演适配器进行 Gemma 7B 推理

要生成响应,我们不能只加载已保存的适配器。需要将微调好的适配器与基础模型(Gemma 7b-it)合并。

本节将介绍如何加载基础模型与适配器,并将它们合并以生成响应。

1. 安装所有必要的 Python 库。

%%capture
%pip install -U bitsandbytes
%pip install -U transformers
%pip install -U accelerate
%pip install -U peft

2. 从 Kaggle secrets 加载 API 密钥,并登录 Hugging Face CLI。

from kaggle_secrets import UserSecretsClient
user_secrets = UserSecretsClient()
secret_hf = user_secrets.get_secret("HUGGINGFACE_TOKEN")
!huggingface-cli login --token $secret_hf

3. 指定基础模型与适配器的位置。

base_model = "/kaggle/input/gemma/transformers/7b-it/2"
new_model = "kingabzpro/gemma-7b-it-v2-role-play"

4. 加载基础模型。

from transformers import AutoModelForCausalLM, AutoTokenizer, pipeline
from peft import PeftModel
import torch



base_model_reload = AutoModelForCausalLM.from_pretrained(
        base_model,
        return_dict=True,
        low_cpu_mem_usage=True,
        torch_dtype=torch.float16,
        device_map="auto",
        trust_remote_code=True,
)

5. 加载适配器并与基础模型合并

model = PeftModel.from_pretrained(base_model_reload, new_model)

从 Hugging Face Hub 加载微调适配器

6. 加载分词器

tokenizer = AutoTokenizer.from_pretrained(base_model, trust_remote_code=True)
tokenizer.pad_token = tokenizer.eos_token
tokenizer.padding_side = "right"

7. 将提示传入分词器与模型以生成响应。

prompt = '''<|system|> Alan Watts's colorful journey explored the depths of philosophy and religion, weaving together Eastern wisdom and Western insights.
<|user|> What does the self actually amount to? 
<|assistant|>'''
    
inputs = tokenizer(prompt, return_tensors='pt', padding=True, truncation=True).to("cuda")

outputs = model.generate(**inputs, max_length=500, num_return_sequences=1)

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

print(text)

Alan Watts 对“自我”的含义阐释得非常到位。

微调后 Gemma 模型输出 3

将基础模型与适配器合并的代码来源见 Gemma 7B Inference with Role Play Adopter。

注册参加“微调您的自有 Llama 2 模型”网络研讨会,观看行业专家的视频教程。

结语

多年前,Google 率先掀起了大型语言模型的浪潮,但未能及时把握机遇。如今,公司正对其战略做出必要调整,力图重回行业领先地位。

随着开源模型 Gemma 的推出,Google 向促进 AI 研究迈出了重要一步,并有望因此在未来构建出更优秀的模型。

公司终于认识到开源社区的力量以及自身如何从中受益。借助云平台、原生框架,以及 Kaggle、Colab、Vertex AI 等平台,Google 旨在最大化利用开源社区的优势,保持竞争领先。

本教程介绍了 Gemma 模型以及如何通过云端 GPU 与 TPU 访问它们,并涵盖了使用角色扮演数据集微调最新 Gemma 7b-it 模型的流程。

下一步,开启您的 AI 之旅,创建基于 LLM 的应用。查阅如何使用 LangChain 构建 LLM 应用的教程,了解如何利用强大的 Python 框架开发前沿 AI 应用。

Abid Ali Awan

作者

Abid Ali Awan

作为一名持证的数据科学家,我热衷于利用前沿技术打造创新的机器学习应用。凭借在语音识别、数据分析与报告、MLOps、对话式人工智能以及自然语言处理方面的扎实背景,我不断打磨构建智能系统的能力,力求带来切实影响。除技术专长外,我也擅长沟通,能够将复杂概念提炼为清晰、简明的表述。因此,我成为数据科学领域备受关注的博主,与不断壮大的数据专业人士社区分享洞见与实践经验。目前,我专注于内容创作与编辑,借助大语言模型打造有力且吸引人的内容,帮助企业与个人更好地发挥数据价值。

主题