Gemma2–2B 在 Colab 上的微调完整指南
简介
直到去年,开源大型语言模型的能力和效果主要都逊于其闭源的同类模型。目前,开源正在推动向一个新时代的转型。
谷歌于2024年6月发布了最新的顶级开源模型Gemma 2。这些模型提供270亿(27B)和90亿(9B)参数两种版本。自发布以来,27B版本迅速成为LMSYS Chatbot Arena排行榜上最突出的开源模型之一。事实上,它在实际对话中已经超过了参数量是其两倍多的流行模型。
Gemma 2 2B 是 Gemma 家族中一种新的 20 亿参数模型变体。它兼具强大的性能和效率,并且内置了安全改进。
在本文中,我们将使用 unsloth 并进行微调以提取合并收购信息。我们已经使用类似的方法与 Llama 3 进行了尝试。
未进行微调的结果
### 安装 Unsloth、Xformers(Flash Attention)和其他所有包! !pip install "unsloth[colab-new] @ git+https://github.com/unslothai/unsloth.git" !pip install --no-deps "xformers<0.0.27" "trl<0.9.0" peft accelerate bitsandbytes ### 安装 Flash Attention 2 以支持软上限 import torch if torch.cuda.get_device_capability()[0] >= 8: !pip install --no-deps packaging ninja einops "flash-attn>=2.6.3" ### 加载模型和分词器 from unsloth import FastLanguageModel import torch max_seq_length = 2048 # 选择任何值!我们内部自动支持 RoPE Scaling! dtype = None # None 用于自动检测。Float16 用于 Tesla T4,V100,Bfloat16 用于 Ampere+ load_in_4bit = True # 使用 4bit 量化以减少内存使用。可以设为 False。 model, tokenizer = FastLanguageModel.from_pretrained( model_name = "unsloth/gemma-2-2b-bnb-4bit", max_seq_length = max_seq_length, dtype = dtype, load_in_4bit = load_in_4bit, ) ### 指令格式 alpaca_prompt = """下面是一个描述任务的指令,附带一个提供更多上下文的输入。编写一个适当完成请求的响应。 ### 指令: {} ### 输入: {} ### 响应: {}""" EOS_TOKEN = tokenizer.eos_token # 必须添加 EOS_TOKEN def formatting_prompts_func(examples): instructions = examples["instruction"] inputs = examples["input"] outputs = examples["output"] texts = [] for instruction, input, output in zip(instructions, inputs, outputs): # 必须添加 EOS_TOKEN,否则生成将无限进行! text = alpaca_prompt.format(instruction, input, output) + EOS_TOKEN texts.append(text) return { "text" : texts, } pass ### mna 新闻和指令 mna_news_input = """HCL Technologies 已完成对德国 IT 咨询公司 Gesellschaft für Banksysteme GmbH(“GBS”)51% 股权的收购。收购于 2022 年 1 月 5 日完成。""" mna_news_instruction1 = """收购日期是什么。请精确回答""" mna_news_instruction2 = """哪个公司是收购方。请精确回答""" FastLanguageModel.for_inference(model) # 启用原生 2 倍更快的推理 inputs = tokenizer( [ alpaca_prompt.format( mna_news_instruction1, mna_news_input, "", # 输出 - 生成时留空! ) ], return_tensors = "pt").to("cuda") outputs = model.generate(**inputs, max_new_tokens = 64, use_cache = True) tokenizer.batch_decode(outputs)[0].split("\n\n### 响应:\n")[1].split("\n\n### 解释:\n")[0] ### 输出:收购日期是 2022 年 1 月 5 日。<eos> inputs = tokenizer( [ alpaca_prompt.format( mna_news_instruction2, mna_news_input, "", # 输出 - 生成时留空! ) ], return_tensors = "pt").to("cuda") outputs = model.generate(**inputs, max_new_tokens = 64, use_cache = True) tokenizer.batch_decode(outputs)[0].split("\n\n### 响应:\n")[1].split("\n\n### 解释:\n")[0] ### 输出:HCL Technologies<eos>
结果非常令人印象深刻,但正如我们在第一次输出中看到的,“收购日期是2022年01月05日。”,我们只想提取日期。有多种方法可以做到这一点,但我们将借助微调来完成。
微调后的结果
### 数据集替换为自己的数据集 import pandas as pd from pprint import pprint list_ds =[ {"instruction":"获取收购日期", "input":"Peak Performance Corporation 收购 Power Forward Corporation 的日期为 28/Jul/2022", "output":"28/Jul/2022"}, {"instruction":"获取收购日期", "input":"纽约 - Empire Innovations Inc,一家领先的科技集团,宣布计划于 01MARCH2025 收购 Unique Ventures LLC,一家专注于颠覆性创业公司的知名风险投资公司", "output":"01MARCH2025"}, {"instruction":"哪一家公司是收购方", "input":"Peak Performance Corporation 收购 Power Forward Corporation 的日期为 28/Jul/2022", "output":"Peak Performance Corporation"}, {"instruction":"哪一家公司是收购方", "input":"Prime Solutions Group 通过战略合并收购 Dynamic Solutions Inc", "output":"Prime Solutions Group"}, ] pprint(list_ds) # 安装 Unsloth、Xformers(Flash Attention)和其他所有包 !pip install "unsloth[colab-new] @ git+https://github.com/unslothai/unsloth.git" !pip install --no-deps "xformers<0.0.27" "trl<0.9.0" peft accelerate bitsandbytes # 安装 Flash Attention 2 以支持软上限 import torch if torch.cuda.get_device_capability()[0] >= 8: !pip install --no-deps packaging ninja einops "flash-attn>=2.6.3" ### 微调 from unsloth import FastLanguageModel import torch max_seq_length = 1024 # 选择任何值!我们内部自动支持 RoPE Scaling dtype = None # None 表示自动检测。Float16 适用于 Tesla T4,V100,Bfloat16 适用于 Ampere+ load_in_4bit = True # 使用 4bit 量化以减少内存使用。可以设置为 False model, tokenizer = FastLanguageModel.from_pretrained( model_name = "unsloth/gemma-2-2b-bnb-4bit", max_seq_length = max_seq_length, dtype = dtype, load_in_4bit = load_in_4bit, # token = "hf_...", # 如果使用受保护的模型如 meta-llama/Llama-2-7b-hf,请使用 token ) model = FastLanguageModel.get_peft_model( model, r = 16, # 选择任何大于 0 的数字!建议 8, 16, 32, 64, 128 target_modules = ["q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj",], lora_alpha = 16, lora_dropout = 0, # 支持任何值,但 = 0 是优化的 bias = "none", # 支持任何值,但 = "none" 是优化的 # [NEW] "unsloth" 使用 30% 更少的 VRAM,适合 2 倍更大的批处理大小! use_gradient_checkpointing = "unsloth", # True 或 "unsloth" 用于非常长的上下文 random_state = 3407, use_rslora = False, # 我们支持秩稳定的 LoRA loftq_config = None, # 以及 LoftQ ) alpaca_prompt = """下面是一个描述任务的指令,以及提供进一步上下文的输入。请编写一个适当完成请求的响应。 ### 指令: {} ### 输入: {} ### 响应: {}""" EOS_TOKEN = tokenizer.eos_token # 必须添加 EOS_TOKEN def formatting_prompts_func(examples): instructions = examples["instruction"] inputs = examples["input"] outputs = examples["output"] texts = [] for instruction, input, output in zip(instructions, inputs, outputs): # 必须添加 EOS_TOKEN,否则生成将无限进行! text = alpaca_prompt.format(instruction, input, output) + EOS_TOKEN texts.append(text) return { "text" : texts, } pass import datasets import pandas as pd # 从字典数组创建数据集 df = pd.DataFrame(list_ds) dataset = datasets.Dataset.from_pandas(df) # 打印数据集 print(dataset) dataset = dataset.map(formatting_prompts_func, batched = True,) print(dataset) from trl import SFTTrainer from transformers import TrainingArguments from unsloth import is_bfloat16_supported trainer = SFTTrainer( model = model, tokenizer = tokenizer, train_dataset = dataset, dataset_text_field = "text", max_seq_length = max_seq_length, dataset_num_proc = 2, packing = False, # 可以使短序列的训练速度提高 5 倍 args = TrainingArguments( per_device_train_batch_size = 2, gradient_accumulation_steps = 4, warmup_steps = 5, # num_train_epochs = 1, # 设置此值以进行一次完整的训练 max_steps = 60, learning_rate = 2e-4, fp16 = not is_bfloat16_supported(), bf16 = is_bfloat16_supported(), logging_steps = 1, optim = "adamw_8bit", weight_decay = 0.01, lr_scheduler_type = "linear", seed = 3407, output_dir = "outputs", ), ) #### 实际训练 trainer_stats = trainer.train() ##### 结果 FastLanguageModel.for_inference(model) mna_news_input = """HCL Technologies 已完成对德国 IT 咨询公司 Gesellschaft für Banksysteme GmbH (“GBS”) 51% 股权的收购。收购日期为 2022 年 1 月 5 日。""" mna_news_instruction1 = """获取收购日期。请精确回答""" mna_news_instruction2 = """哪一家公司是收购方。请精确回答""" inputs = tokenizer( [ alpaca_prompt.format( mna_news_instruction1, mna_news_input, "", # 输出 - 生成时留空! ) ], return_tensors = "pt").to("cuda") outputs = model.generate(**inputs, max_new_tokens = 64, use_cache = True) tokenizer.batch_decode(outputs)[0].split("\n\n### 响应:\n")[1].split("\n\n### 解释:\n")[0] ### 输出 : January 05, 2022<eos> ### 上面的结果非常好,正是我们想要的 inputs = tokenizer( [ alpaca_prompt.format( mna_news_instruction2, mna_news_input, "", # 输出 - 生成时留空! ) ], return_tensors = "pt").to("cuda") outputs = model.generate(**inputs, max_new_tokens = 64, use_cache = True) tokenizer.batch_decode(outputs)[0].split("\n\n### 响应:\n")[1].split("\n\n### 解释:\n")[0] ### 输出 : HCL Technologies<eos>
结论
我们通过微调得到了精确的结果。太棒了。使用T4和仅20亿参数的模型,效果更令人惊叹。
Colab ::COLAB:: 翻译为
COLAB::
这里保持了原始的双冒号格式,但由于直接翻译会有些不自然,建议直接保留原始格式或根据具体使用场景调整。如果必须翻译,可以理解为“谷歌协同”或“谷歌协作”,但根据上下文,这里可能更适合保留原始格式。
Google ColabEdit 描述colab.research.google.com Google ColabEdit 描述colab.research.google.com