使用GaLore在本地GPU进行高效的LLM调优

简介: GaLore是一种新的优化策略,它通过梯度低秩投影减少VRAM需求,使得大型语言模型(如70亿参数的模型)能在消费级GPU上进行微调,而不减少参数数量。与LoRA相比,GaLore内存效率更高,且性能相当或更优。它在反向传播期间逐层更新参数,降低了计算负荷。虽然GaLore训练时间较长,但它为个人爱好者提供了在有限资源下训练大模型的可能性。相关代码示例和性能对比显示了其优势。

训练大型语言模型(llm),即使是那些“只有”70亿个参数的模型,也是一项计算密集型的任务。这种水平的训练需要的资源超出了大多数个人爱好者的能力范围。为了弥补这一差距,出现了低秩适应(LoRA)等参数高效方法,可以在消费级gpu上对大量模型进行微调。

GaLore是一种新的方法,它不是通过直接减少参数的数量,而是通过优化这些参数的训练方式来降低VRAM需求,也就是说GaLore是一种新的模型训练策略,可让模型使用全部参数进行学习,并且比LoRA更省内存。

GaLore将这些梯度投影到低秩空间上,显著减少了计算负荷,同时保留了训练所需的基本信息。与传统的优化器在反向传播后同时更新所有层的方法不同,GaLore在反向传播期间实现逐层更新。这种方法进一步减少了整个训练过程中的内存占用。

就像LoRA一样,GaLore可以让我们在具有24 GB VRAM的消费级GPU上微调7B模型。结果模型的性能与全参数微调相当,并且似乎优于LoRA。

优于目前Hugging Face还没有官方代码,我们就来手动使用论文的代码进行训练,并与LoRA进行对比

安装依赖

首先就要安装GaLore

 pip install galore-torch

然后我们还要一下这些库,并且请注意版本

 datasets==2.18.0
 transformers==4.39.1
 trl==0.8.1
 accelerate==0.28.0
 torch==2.2.1

调度器和优化器的类

Galore分层优化器是通过模型权重挂钩激活的。由于我们使用Hugging Face

Trainer

,还需要自己实现一个优化器和调度器的抽象类。这些类的结构不执行任何操作。

 from typing import Optional
 import torch

 # Approach taken from Hugging Face transformers https://github.com/huggingface/transformers/blob/main/src/transformers/optimization.py
 class LayerWiseDummyOptimizer(torch.optim.Optimizer):
     def __init__(self, optimizer_dict=None, *args, **kwargs):
         dummy_tensor = torch.randn(1, 1)
         self.optimizer_dict = optimizer_dict
         super().__init__([dummy_tensor], {"lr": 1e-03})

     def zero_grad(self, set_to_none: bool = True) -> None: 
       pass

     def step(self, closure=None) -> Optional[float]: 
       pass

 class LayerWiseDummyScheduler(torch.optim.lr_scheduler.LRScheduler):
     def __init__(self, *args, **kwargs):
         optimizer = LayerWiseDummyOptimizer()
         last_epoch = -1
         verbose = False
         super().__init__(optimizer, last_epoch, verbose)

     def get_lr(self): 
       return [group["lr"] for group in self.optimizer.param_groups]

     def _get_closed_form_lr(self): 
       return self.base_lrs

加载GaLore优化器

GaLore优化器的目标是特定的参数,主要是那些在线性层中以attn或mlp命名的参数。通过系统地将函数与这些目标参数挂钩,GaLore 8位优化器就会开始工作。

 from transformers import get_constant_schedule
 from functools import partial
 import torch.nn
 import bitsandbytes as bnb

 from galore_torch import GaLoreAdamW8bit

 def load_galore_optimizer(model, lr, galore_config):    
     # function to hook optimizer and scheduler to a given parameter 
     def optimizer_hook(p, optimizer, scheduler):
         if p.grad is not None: 
             optimizer.step()
             optimizer.zero_grad()
             scheduler.step()

     # Parameters to optimize with Galore
     galore_params = [
         (module.weight, module_name) for module_name, module in model.named_modules() 
         if isinstance(module, nn.Linear) and any(target_key in module_name for target_key in galore_config["target_modules_list"])
     ] 
     id_galore_params = {id(p) for p, _ in galore_params}

     # Hook Galore optim to all target params, Adam8bit to all others
     for p in model.parameters():
         if p.requires_grad:
             if id(p) in id_galore_params:
                 optimizer = GaLoreAdamW8bit([dict(params=[p], **galore_config)], lr=lr)
             else:
                 optimizer = bnb.optim.Adam8bit([p], lr = lr)
             scheduler = get_constant_schedule(optimizer)

             p.register_post_accumulate_grad_hook(partial(optimizer_hook, optimizer=optimizer, scheduler=scheduler))

     # return dummies, stepping is done with hooks 
     return LayerWiseDummyOptimizer(), LayerWiseDummyScheduler()

HF Trainer

准备好优化器后,我们开始使用Trainer进行训练。下面是一个简单的例子,使用TRL的SFTTrainer (Trainer的子类)在Open Assistant数据集上微调llama2-7b,并在RTX 3090/4090等24 GB VRAM GPU上运行。

 from transformers import AutoTokenizer, AutoModelForCausalLM, TrainingArguments, set_seed, get_constant_schedule
 from trl import SFTTrainer, setup_chat_format, DataCollatorForCompletionOnlyLM
 from datasets import load_dataset
 import torch, torch.nn as nn, uuid, wandb

 lr = 1e-5

 # GaLore optimizer hyperparameters
 galore_config = dict(
     target_modules_list = ["attn", "mlp"], 
     rank = 1024, 
     update_proj_gap = 200, 
     scale = 2, 
     proj_type="std"
 )

 modelpath = "meta-llama/Llama-2-7b"
 model = AutoModelForCausalLM.from_pretrained(
     modelpath,    
     torch_dtype=torch.bfloat16,
     attn_implementation = "flash_attention_2",  
     device_map = "auto",
     use_cache = False,
 )
 tokenizer = AutoTokenizer.from_pretrained(modelpath, use_fast = False)

 # Setup for ChatML
 model, tokenizer = setup_chat_format(model, tokenizer)
 if tokenizer.pad_token in [None, tokenizer.eos_token]: 
     tokenizer.pad_token = tokenizer.unk_token

 # subset of the Open Assistant 2 dataset, 4000 of the top ranking conversations
 dataset = load_dataset("g-ronimo/oasst2_top4k_en")

 training_arguments = TrainingArguments(
     output_dir = f"out_{run_id}",
     evaluation_strategy = "steps",
     label_names = ["labels"],
     per_device_train_batch_size = 16,
     gradient_accumulation_steps = 1,
     save_steps = 250,
     eval_steps = 250,
     logging_steps = 1, 
     learning_rate = lr,
     num_train_epochs = 3,
     lr_scheduler_type = "constant",
     gradient_checkpointing = True,
     group_by_length = False,
 )

 optimizers = load_galore_optimizer(model, lr, galore_config)

 trainer = SFTTrainer(
     model = model,
     tokenizer = tokenizer,
     train_dataset = dataset["train"],
     eval_dataset = dataset['test'],
     data_collator = DataCollatorForCompletionOnlyLM(
         instruction_template = "<|im_start|>user", 
         response_template = "<|im_start|>assistant", 
         tokenizer = tokenizer, 
         mlm = False),
     max_seq_length = 256,
     dataset_kwargs = dict(add_special_tokens = False),
     optimizers = optimizers,
     args = training_arguments,
 )

 trainer.train()

GaLore优化器带有一些需要设置的超参数如下:

target_modules_list:指定GaLore针对的层

rank:投影矩阵的秩。与LoRA类似,秩越高,微调就越接近全参数微调。GaLore的作者建议7B使用1024

update_proj_gap:更新投影的步骤数。这是一个昂贵的步骤,对于7B来说大约需要15分钟。定义更新投影的间隔,建议范围在50到1000步之间。

scale:类似于LoRA的alpha的比例因子,用于调整更新强度。在尝试了几个值之后,我发现scale=2最接近于经典的全参数微调。

微调效果对比

给定超参数的训练损失与全参数调优的轨迹非常相似,表明GaLore分层方法确实是等效的。

用GaLore训练的模型得分与全参数微调非常相似。

GaLore可以节省大约15 GB的VRAM,但由于定期投影更新,它需要更长的训练时间。

上图为2个3090的内存占用对比

训练事件对比,微调:~58分钟。GaLore:约130分钟

最后我们再看看GaLore和LoRA的对比

上图为LoRA微调所有线性层,rank64,alpha 16的损失图

从数值上可以看到GaLore是一种近似全参数训练的新方法,性能与微调相当,比LoRA要好得多。

总结

GaLore可以节省VRAM,允许在消费级GPU上训练7B模型,但是速度较慢,比微调和LoRA的时间要长差不多两倍的时间。

GaLore: Memory-Efficient LLM Training by Gradient Low-Rank Projection.

https://avoid.overfit.cn/post/0b15de8db27040f0abcaa7e554b0b993

作者:Geronimo

相关实践学习
在云上部署ChatGLM2-6B大模型(GPU版)
ChatGLM2-6B是由智谱AI及清华KEG实验室于2023年6月发布的中英双语对话开源大模型。通过本实验,可以学习如何配置AIGC开发环境,如何部署ChatGLM2-6B大模型。
目录
相关文章
|
9月前
|
缓存 异构计算 Docker
构建高性能LLM推理服务的完整方案:单GPU处理172个查询/秒、10万并发仅需15美元/小时
本文将通过系统性实验不同的优化技术来构建自定义LLaMA模型服务,目标是高效处理约102,000个并行查询请求,并通过对比分析确定最优解决方案。
875 0
构建高性能LLM推理服务的完整方案:单GPU处理172个查询/秒、10万并发仅需15美元/小时
|
10月前
|
机器学习/深度学习 自然语言处理 算法
万字长文详解|DLRover LLM Agent:大模型驱动的高效集群资源调优
本文介绍了DLRover LLM Agent,展示了基于 LLM 上下文学习能力的优化算法设计理念以及在DLRover 资源调优上的应用方法和效果。
|
缓存 算法 关系型数据库
MIT韩松团队长上下文LLM推理高效框架DuoAttention:单GPU实现330万Token上下文推理
麻省理工学院韩松团队提出DuoAttention框架,旨在提高大型语言模型(LLM)处理长上下文的效率。该框架通过区分检索头和流式头,仅对检索头应用全键值缓存,减少内存消耗和计算时间,同时保持模型长上下文处理能力。实验结果显示,DuoAttention在多种模型架构上显著提升了推理效率,为LLM的实际应用提供了新可能。
479 14
|
自然语言处理 测试技术 异构计算
使用Accelerate库在多GPU上进行LLM推理
大型语言模型(llm)已经彻底改变了自然语言处理领域。随着这些模型在规模和复杂性上的增长,推理的计算需求也显著增加。为了应对这一挑战利用多个gpu变得至关重要。
2542 0
|
安全 异构计算
为大型语言模型 (LLM) 提供服务需要多少 GPU 内存?
为大型语言模型 (LLM) 提供服务需要多少 GPU 内存?
1368 0
为大型语言模型 (LLM) 提供服务需要多少 GPU 内存?
|
弹性计算 API 数据库
规模化落地AIGC应用,支持多个大语言模型(LLM)切换及GPU规划化管理(PAI-EAS + ADB-PG)
随着年初的ChatGPT引爆大语言模型市场, LLM的集中爆发,大部分企业已经完成了AIGC产品的调研,并进入第二阶段, 即寻求大规模落地的AIGC产品解决方案。本文介绍了如何企业规模化大语言模型落地,支持多个模型的快速使用,包括通义千问-7b,ChatGLM-6b,Llama2-7b 和 Llama2-13b。
2763 0
|
6月前
|
人工智能 算法 调度
阿里云ACK托管集群Pro版共享GPU调度操作指南
本文介绍在阿里云ACK托管集群Pro版中,如何通过共享GPU调度实现显存与算力的精细化分配,涵盖前提条件、使用限制、节点池配置及任务部署全流程,提升GPU资源利用率,适用于AI训练与推理场景。
542 1
|
6月前
|
人工智能 城市大脑 运维
喜讯!阿里云国产异构GPU云平台技术荣获“2025算力中国·年度重大成果”
2025年8月23日,在工业和信息化部新闻宣传中心、中国信息通信研究院主办的2025中国算力大会上,阿里云与浙江大学联合研发的“国产异构GPU云平台关键技术与系统”荣获「算力中国·年度重大成果」。该评选旨在选拔出算力产业具有全局性突破价值的重大成果,是业内公认的技术创新“风向标”。
655 0
|
11月前
|
存储 机器学习/深度学习 数据库
阿里云服务器X86/ARM/GPU/裸金属/超算五大架构技术特点、场景适配参考
在云计算技术飞速发展的当下,云计算已经渗透到各个行业,成为企业数字化转型的关键驱动力。选择合适的云服务器架构对于提升业务效率、降低成本至关重要。阿里云提供了多样化的云服务器架构选择,包括X86计算、ARM计算、GPU/FPGA/ASIC、弹性裸金属服务器以及高性能计算等。本文将深入解析这些架构的特点、优势及适用场景,以供大家了解和选择参考。
1422 61