{ "cells": [ { "cell_type": "markdown", "id": "347c39eb-0974-4880-b6dd-0cbfc33d7145", "metadata": {}, "source": [ "# 简介\n", "\n", "> 指导文章:[14. PEFT:在大模型中快速应用 LoRA](https://github.com/Hoper-J/AI-Guide-and-Demos-zh_CN/blob/master/Guide/14.%20PEFT:在大模型中快速应用%20LoRA.md)\n", "\n", "在线链接:[Kaggle](https://www.kaggle.com/code/aidemos/12-lora-peft) | [Colab](https://colab.research.google.com/drive/119kODbfSnPhqgP5Oq3jE2g59Hxd9Fmx0?usp=sharing)\n" ] }, { "cell_type": "markdown", "id": "07c339a9-af32-494f-88f0-1a5859da483d", "metadata": {}, "source": [ "## 安装必要的库" ] }, { "cell_type": "code", "execution_count": null, "id": "64c27f94-265c-49f3-a624-7f089f426577", "metadata": { "scrolled": true }, "outputs": [], "source": [ "%pip install \\\n", " \"transformers==4.56.2\" \\\n", " \"peft==0.17.1\" \\\n", " \"datasets==4.0.0\"" ] }, { "cell_type": "markdown", "id": "2006b231-0d05-444a-bdf8-4dcfed09f1c0", "metadata": {}, "source": [ "## 加载预训练模型" ] }, { "cell_type": "code", "execution_count": 2, "id": "8899fbab-45d1-43be-b198-403903d36900", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "GPT2LMHeadModel(\n", " (transformer): GPT2Model(\n", " (wte): Embedding(50257, 768)\n", " (wpe): Embedding(1024, 768)\n", " (drop): Dropout(p=0.1, inplace=False)\n", " (h): ModuleList(\n", " (0-11): 12 x GPT2Block(\n", " (ln_1): LayerNorm((768,), eps=1e-05, elementwise_affine=True)\n", " (attn): GPT2Attention(\n", " (c_attn): Conv1D(nf=2304, nx=768)\n", " (c_proj): Conv1D(nf=768, nx=768)\n", " (attn_dropout): Dropout(p=0.1, inplace=False)\n", " (resid_dropout): Dropout(p=0.1, inplace=False)\n", " )\n", " (ln_2): LayerNorm((768,), eps=1e-05, elementwise_affine=True)\n", " (mlp): GPT2MLP(\n", " (c_fc): Conv1D(nf=3072, nx=768)\n", " (c_proj): Conv1D(nf=768, nx=3072)\n", " (act): NewGELUActivation()\n", " (dropout): Dropout(p=0.1, inplace=False)\n", " )\n", " )\n", " )\n", " (ln_f): LayerNorm((768,), eps=1e-05, elementwise_affine=True)\n", " )\n", " (lm_head): Linear(in_features=768, out_features=50257, bias=False)\n", ")" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import os\n", "# 设置模型下载镜像\n", "os.environ['HF_ENDPOINT'] = 'https://hf-mirror.com'\n", "\n", "from transformers import AutoTokenizer, AutoModelForCausalLM\n", "\n", "# 加载预训练的 GPT-2 模型和分词器\n", "tokenizer = AutoTokenizer.from_pretrained('gpt2')\n", "model = AutoModelForCausalLM.from_pretrained('gpt2')\n", "\n", "# 使用eos_token作为pad_token\n", "tokenizer.pad_token = tokenizer.eos_token\n", "\n", "model" ] }, { "cell_type": "markdown", "id": "d9c18030-1a96-4ba9-a157-bc4bf9293352", "metadata": {}, "source": [ "## 使用 PEFT 应用 LoRA" ] }, { "cell_type": "code", "execution_count": 3, "id": "1dd0f0a4-f692-47c1-b153-3eb5f38aded4", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n" ] }, { "data": { "text/html": [ "
" ], "text/plain": [] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "WARN Python GIL is enabled: Multi-gpu quant acceleration for MoE models is sub-optimal and multi-core accelerated cpu packing is also disabled. We recommend Python >= 3.13.3t with Pytorch > 2.8 for mult-gpu quantization and multi-cpu packing with env `PYTHON_GIL=0`.\n" ] }, { "data": { "text/html": [ "" ], "text/plain": [] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "" ], "text/plain": [] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "WARN Feature `utils/Perplexity` requires python GIL or Python >= 3.13.3T (T for Threading-Free edition of Python) plus Torch 2.8. Feature is currently skipped/disabled.\n" ] }, { "data": { "text/html": [ "" ], "text/plain": [] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "" ], "text/plain": [] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "INFO ENV: Auto setting PYTORCH_CUDA_ALLOC_CONF='expandable_segments:True' for memory saving.\n" ] }, { "data": { "text/html": [ "" ], "text/plain": [] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "" ], "text/plain": [] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "INFO ENV: Auto setting CUDA_DEVICE_ORDER=PCI_BUS_ID for correctness. \n" ] }, { "data": { "text/html": [ "" ], "text/plain": [] }, "metadata": {}, "output_type": "display_data" }, { "name": "stderr", "output_type": "stream", "text": [ "/root/autodl-tmp/AI-Guide-and-Demos-zh_CN/.venv/lib/python3.12/site-packages/peft/tuners/lora/layer.py:2174: UserWarning: fan_in_fan_out is set to False but the target module is `Conv1D`. Setting fan_in_fan_out to True.\n", " warnings.warn(\n" ] } ], "source": [ "from peft import get_peft_model, LoraConfig, TaskType\n", "\n", "# 配置 LoRA\n", "lora_config = LoraConfig(\n", " task_type=TaskType.CAUSAL_LM, # 任务类型:因果语言模型\n", " inference_mode=False, # 推理模式关闭,以进行训练\n", " r=8, # 低秩值 r\n", " lora_alpha=32, # LoRA 的缩放因子\n", " lora_dropout=0.1, # Dropout 概率\n", ")\n", "\n", "# 将 LoRA 应用到模型中\n", "model = get_peft_model(model, lora_config)" ] }, { "cell_type": "markdown", "id": "2658099e-7627-4950-b9ce-31167a9f6b3c", "metadata": {}, "source": [ "## 查看当前模型架构" ] }, { "cell_type": "code", "execution_count": 4, "id": "2b200673-a8e1-42bf-ad23-a6944ee3f5c1", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "PeftModelForCausalLM(\n", " (base_model): LoraModel(\n", " (model): GPT2LMHeadModel(\n", " (transformer): GPT2Model(\n", " (wte): Embedding(50257, 768)\n", " (wpe): Embedding(1024, 768)\n", " (drop): Dropout(p=0.1, inplace=False)\n", " (h): ModuleList(\n", " (0-11): 12 x GPT2Block(\n", " (ln_1): LayerNorm((768,), eps=1e-05, elementwise_affine=True)\n", " (attn): GPT2Attention(\n", " (c_attn): lora.Linear(\n", " (base_layer): Conv1D(nf=2304, nx=768)\n", " (lora_dropout): ModuleDict(\n", " (default): Dropout(p=0.1, inplace=False)\n", " )\n", " (lora_A): ModuleDict(\n", " (default): Linear(in_features=768, out_features=8, bias=False)\n", " )\n", " (lora_B): ModuleDict(\n", " (default): Linear(in_features=8, out_features=2304, bias=False)\n", " )\n", " (lora_embedding_A): ParameterDict()\n", " (lora_embedding_B): ParameterDict()\n", " (lora_magnitude_vector): ModuleDict()\n", " )\n", " (c_proj): Conv1D(nf=768, nx=768)\n", " (attn_dropout): Dropout(p=0.1, inplace=False)\n", " (resid_dropout): Dropout(p=0.1, inplace=False)\n", " )\n", " (ln_2): LayerNorm((768,), eps=1e-05, elementwise_affine=True)\n", " (mlp): GPT2MLP(\n", " (c_fc): Conv1D(nf=3072, nx=768)\n", " (c_proj): Conv1D(nf=768, nx=3072)\n", " (act): NewGELUActivation()\n", " (dropout): Dropout(p=0.1, inplace=False)\n", " )\n", " )\n", " )\n", " (ln_f): LayerNorm((768,), eps=1e-05, elementwise_affine=True)\n", " )\n", " (lm_head): Linear(in_features=768, out_features=50257, bias=False)\n", " )\n", " )\n", ")\n" ] } ], "source": [ "print(model)" ] }, { "cell_type": "markdown", "id": "e1a89d20-f03d-4938-94c8-42c79dae4fc8", "metadata": {}, "source": [ "## 查看增加的参数量\n", "\n", "应用 LoRA 后,我们一般都希望了解模型参数量的变化,它的计算其实很简单。\n", "\n", "### 理论计算\n", "\n", "对于每个应用了 LoRA 的层,增加的参数量为:\n", "\n", "$$\n", "\\text{增加的参数量} = r \\times (\\text{输入维度} + \\text{输出维度})\n", "$$\n", "\n", "- **`r`**:LoRA 的低秩值。\n", "- **输入维度**:层的输入特征数。\n", "- **输出维度**:层的输出特征数。\n", "\n", "### 使用 PEFT 查看参数\n", "\n", "`peft` 提供了查看模型参数的便捷方法:" ] }, { "cell_type": "code", "execution_count": 5, "id": "db8ddcf3-1ea0-4bfc-989e-890608e65e69", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "trainable params: 294,912 || all params: 124,734,720 || trainable%: 0.2364\n" ] } ], "source": [ "# 查看 LoRA 模块\n", "model.print_trainable_parameters()" ] }, { "cell_type": "code", "execution_count": 6, "id": "f6f2a584-f2f3-49c3-a010-0dbe3962fe41", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "可训练参数量: 294912\n", "总参数量: 124734720\n", "可训练参数占比: 0.24%\n" ] } ], "source": [ "def print_trainable_parameters(model):\n", " \"\"\"\n", " 打印模型的可训练参数信息。\n", " \n", " 参数:\n", " model: 要分析的模型\n", " \"\"\"\n", " trainable_params = 0\n", " all_params = 0\n", " for _, param in model.named_parameters():\n", " num_params = param.numel()\n", " all_params += num_params\n", " if param.requires_grad:\n", " trainable_params += num_params\n", " print(f\"可训练参数量: {trainable_params}\")\n", " print(f\"总参数量: {all_params}\")\n", " print(f\"可训练参数占比: {100 * trainable_params / all_params:.2f}%\")\n", " \n", "print_trainable_parameters(model)" ] }, { "cell_type": "markdown", "id": "91fe2425-7bf6-4fb3-be8e-a7f66257828e", "metadata": {}, "source": [ "## 准备数据\n", "\n", "下面使用公开数据集进行演示。" ] }, { "cell_type": "code", "execution_count": 7, "id": "56f45ce2-6997-4208-8e3d-39f841e82bb8", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "数据集大小: 500\n", "数据集列名: ['text', 'label']\n", "示例数据: {'text': 'I rented I AM CURIOUS-YELLOW from my video store because of all the controversy that surrounded it when it was first released in 1967. I also heard that at first it was seized by U.S. customs if it ever tried to enter this country, therefore being a fan of films considered \"controversial\" I really had to see this for myself.| Step | \n", "Training Loss | \n", "
|---|---|
| 10 | \n", "4.027700 | \n", "
| 20 | \n", "3.888200 | \n", "
| 30 | \n", "3.802300 | \n", "
| 40 | \n", "3.803300 | \n", "
| 50 | \n", "3.823900 | \n", "
| 60 | \n", "3.833800 | \n", "
| 70 | \n", "3.808600 | \n", "
| 80 | \n", "3.873400 | \n", "
| 90 | \n", "3.762800 | \n", "
| 100 | \n", "3.767300 | \n", "
| 110 | \n", "3.926900 | \n", "
| 120 | \n", "3.858500 | \n", "
| 130 | \n", "3.888100 | \n", "
| 140 | \n", "3.733600 | \n", "
| 150 | \n", "3.806600 | \n", "
| 160 | \n", "3.789900 | \n", "
| 170 | \n", "3.837800 | \n", "
| 180 | \n", "3.737900 | \n", "
| 190 | \n", "3.746900 | \n", "
| 200 | \n", "3.749100 | \n", "
| 210 | \n", "3.843600 | \n", "
| 220 | \n", "3.766800 | \n", "
| 230 | \n", "3.836800 | \n", "
| 240 | \n", "3.897300 | \n", "
| 250 | \n", "3.822000 | \n", "
| 260 | \n", "3.697600 | \n", "
| 270 | \n", "3.778200 | \n", "
| 280 | \n", "3.782400 | \n", "
| 290 | \n", "3.785100 | \n", "
| 300 | \n", "3.724600 | \n", "
| 310 | \n", "3.794300 | \n", "
| 320 | \n", "3.953600 | \n", "
| 330 | \n", "3.731600 | \n", "
| 340 | \n", "3.688700 | \n", "
| 350 | \n", "3.711000 | \n", "
| 360 | \n", "3.870800 | \n", "
| 370 | \n", "3.949500 | \n", "
"
],
"text/plain": [
"