赞
踩
本篇文章介绍了深度学习训练中的三种优化方法:量化、3D并行和CPU卸载。
量化可以将模型压缩为更小的尺寸,从而减少计算和存储的开销;
3D并行可以将大型模型分成多个块,每个块分配到不同的GPU上进行计算,从而充分利用多个GPU的计算能力;
卸载可以让参数暂存于内存或硬盘中,从而使得有限资源训练更大的模型。
混合精度
混合精度训练(mixed precision training)是一种加速深度学习训练的技术。其主要思想是使用较低精度的浮点数(如FP16)来表示神经网络中的权重和激活值,从而减少内存使用和计算开销,进而加速训练过程。
混合精度训练的实现可以分为以下几个步骤:
将FP32的权重转换为FP16格式,然后进行前向计算,得到FP32的损失(loss)。
使用FP16计算梯度。
将梯度转换为FP32格式,并将其更新到权重上。
由于FP16精度较低,可能会导致精度损失,因此在混合精度训练中需要进行一些技巧来保持模型的准确性。例如,可以使用梯度缩放(GradScaler)来控制梯度的大小,以避免梯度下降过快而影响模型的准确性。
精度数值范围
FP16:半精度浮点数,使用16位二进制数表示,其中1位表示符号位,5位表示指数位,10位表示尾数位,能够表示的数值范围为±2^15。
FP32:单精度浮点数,使用32位二进制数表示,其中1位表示符号位,8位表示指数位,23位表示尾数位,能够表示的数值范围为±3.4×10^38。
FP64:双精度浮点数,使用64位二进制数表示,其中1位表示符号位,11位表示指数位,52位表示尾数位,能够表示的数值范围为±1.8×10^308。
INT8:8位整数,能够表示的数值范围为-128到127。
INT4:4位整数,能够表示的数值范围为-8到7。
流程
混合精度训练的流程如下:
将FP32的权重转换为FP16格式,然后进行前向计算,得到FP32的损失(loss)。
使用FP16计算梯度。
将梯度转换为FP32格式,并将其更新到权重上。
在训练过程中,使用autocast将输入和输出转换为FP16格式,使用GradScaler对损失值进行缩放,以避免梯度下降过快而影响模型的准确性。
FP32保存权重的原因
梯度的更新值太小,FP16直接变为了0
FP16表示权重,梯度的计算结果可能变成0
用FP16保存权重会造成80%的精度损失
使用apex
apex.parallel.DistributedDataParallel 与apex.amp 已被以下两个API取代
torch.nn.parallel.DistributedDataParallel和torch.amp
model = Net().cuda()
optimizer = optim.SGD(model.parameters(), ...)
# 创建scaler
scaler = GradScaler()
for epoch in epochs:
for inputs, target in data:
optimizer.zero_grad()
with autocast(device_type='cuda', dtype=torch.float16): # 自动进行转化
output = model(inputs)
loss = loss_fn(output, target)
scaler.scale(loss).backward() # 应用于损失函数
scaler.step(optimizer) # 应用于优化函数
scaler.update()
量化
量化是一种通过减少数字表示的位数来减小模型存储量和计算量的方法。在深度学习中,通常使用32位浮点数来表示权重和激活值。但是,这种精度可能会导致计算和存储的开销非常高。因此,量化使用更短的整数表示权重和激活值,从而减少内存和计算开销。
在量化过程中,可以使用两种方法:动态量化和静态量化。
动态量化在运行时收集数据,并根据数据动态地量化模型。
静态量化在训练过程中对模型进行量化,并在推理时应用量化。
量化会导致模型准确度下降,因为更低的精度可能会导致舍入误差。因此,在量化期间,需要进行一些技巧来保持模型的准确程度,例如:对权重进行缩放或使用动态范围量化。
总的来说,量化是一种非常有用的方法,可以减少模型的存储和计算开销,提高模型在设备上的执行效率。
量化推理
使用load_in_8bit方法可以实现模型的量化。该方法可以将模型权重和激活值量化为8位整数,从而减少内存和计算开销。具体实现方法如下:
import torch
from transformers import AutoModel
model = AutoModel.from_pretrained(‘bert-base-uncased’,load_in_8bit=True)
需要注意的是,使用load_in_8bit方法量化模型可能会导致模型准确度下降。因此,在量化模型之前,需要对模型进行测试,确保准确度可以接受。另外,不是所有的模型都可以被量化,只有支持动态量化的模型才可以使用该方法进行量化。
量化训练
在深度学习中,量化是一种通过减少数字表示的位数来减小模型存储量和计算量的方法。在使用混合精度训练时,可以将模型权重和梯度从FP32转换为FP16,以节省内存和加速训练。同样的思路,量化训练可以将激活值转换为更短的整数,从而减少内存和计算开销。
PyTorch中提供了一些量化训练的工具和API,例如QAT(量化感知训练),使用动态范围量化等。其中,使用Adam8bit进行量化训练是一种方法。
下面是使用Adam8bit、trainer进行量化训练的示例代码:
import torch from torch.optim import Adam from torch.optim.lr_scheduler import LambdaLR from torch.utils.data import DataLoader from torchvision.transforms import Compose, ToTensor, Normalize from torch.cuda.amp import GradScaler, autocast from torch.quantization import QuantWrapper, Adam8Bit # 初始化模型 model = Net().cuda() # 初始化Adam优化器 optimizer = Adam(model.parameters(), lr=0.001) # 初始化Adam8Bit optimizer = Adam8Bit(optimizer) # 初始化学习率调度器 lr_scheduler = LambdaLR(optimizer, lr_lambda=lambda epoch: 0.1 ** (epoch // 20)) # 初始化GradScaler scaler = GradScaler() # 开始训练 for epoch in range(10): for i, (inputs, labels) in enumerate(train_loader): optimizer.zero_grad() with autocast(): outputs = model(inputs.cuda()) loss = torch.nn.functional.cross_entropy(outputs, labels.cuda()) scaler.scale(loss).backward() scaler.step(optimizer) scaler.update() lr_scheduler.step() if i % 100 == 0: print('Epoch:{}, Iteration:{}, Loss:{:.4f}'.format(epoch, i, loss.item())) # 量化模型 quantized_model = QuantWrapper(model).to(torch.device('cuda')) 另外还可以通过trainer进行训练 import torch import transformers # 加载已经训练好的BERT模型 model = transformers.BertForSequenceClassification.from_pretrained('bert-base-uncased') # 定义训练参数 training_args = transformers.TrainingArguments( output_dir='./results', evaluation_strategy='steps', eval_steps=1000, save_total_limit=3, learning_rate=1e-5, num_train_epochs=3, per_device_train_batch_size=8, per_device_eval_batch_size=8, warmup_steps=100, weight_decay=0.01, logging_dir='./logs', logging_steps=1000, load_best_model_at_end=True, metric_for_best_model='eval_loss', greater_is_better=False, quantization_config={ 'activations': torch.quantization.default_qconfig, 'weights': torch.quantization.default_qconfig } ) # 定义Trainer并进行量化训练 trainer = transformers.Trainer( model=model, args=training_args, train_dataset=train_dataset, eval_dataset=val_dataset ) trainer.quantize() trainer.train()
其中torch.quantization.default_qconfig是PyTorch中提供的一个默认的量化配置,包含了一些默认的量化参数。在一些简单的量化任务中,可以使用这个默认配置,而不需要自己手动指定每个参数的值。其中:
activation_8bit: 激活值的8位量化配置。默认值为torch.quantization.QConfig(activation=torch.quantization.default_observer.with_args(dtype=torch.qint8), weight=torch.quantization.default_per_channel_qconfig)。
weight_8bit: 权重的8位量化配置。默认值为torch.quantization.default_per_channel_qconfig.with_args(dtype=torch.qint8)。
这些默认值可以在使用**quantize()**函数时进行自定义,以满足特定的量化需求。
3D并行
为了进一步提高GPU的利用率,可以使用3D并行优化来加速深度学习的训练。3D并行优化可以将大型模型分成多个块,每个块分别分配到不同的GPU上进行计算。这样可以充分利用多个GPU的计算能力,从而加速训练过程。
在3D并行优化中,可以使用不同的并行策略,包括模型并行、数据并行、流水线并行等。模型并行将模型分成多个部分,每个部分分配到不同的GPU上进行计算。数据并行将数据分成多个部分,每个部分分配到不同的GPU上进行计算。流水线并行将计算过程分成多个阶段,每个阶段分配到不同的GPU上进行计算。这些并行策略可以组合使用,以充分利用多个GPU的计算能力。
具体的,流水线并行是一种并行计算的方法。在流水线并行中,计算过程分成多个阶段,每个阶段分配到不同的GPU上进行计算。每个GPU只需要计算自己负责的阶段,这样可以充分利用多个GPU的计算能力,提高训练效率和速度。
举一个例子,假设有一个深度学习模型需要进行训练,训练过程包括数据预处理、前向传播、反向传播、参数更新等多个阶段。在流水线并行中,可以将这个训练过程分成多个阶段,每个阶段分配到不同的GPU上进行计算。例如,可以将数据预处理分配到GPU1,前向传播分配到GPU2,反向传播分配到GPU3,参数更新分配到GPU4。这样每个GPU只需要计算自己负责的阶段,可以充分利用多个GPU的计算能力,提高训练效率和速度。
在使用流水线并行时,需要进行复杂的调度和同步操作,以确保计算正确。例如,在上面的例子中,GPU2需要等待GPU1完成数据预处理后才能开始进行前向传播计算,GPU3需要等待GPU2完成前向传播后才能开始进行反向传播计算,GPU4需要等待GPU3完成反向传播后才能开始进行参数更新计算。这些同步操作需要精确地协调和调度,以确保计算的正确性和效率。
总的来说,流水线并行是一种有效的加速深度学习训练的方法,可以充分利用多个GPU的计算能力,提高训练效率和速度。但是,需要进行复杂的调度和同步操作,需要具备一定的计算机系统和并行计算的知识。
在使用3D并行优化时,还需要进行分块和线性规划。分块是将大型模型分成多个块的过程。线性规划是通过优化GPU之间的通信和计算负载,以最大化GPU的利用率,利用这种方法加之量化为4bit FMInference/FlexGen实现了单块T4推理175B 1 Token/s
总的来说,3D并行优化是一种有效的加速深度学习训练的方法,可以充分利用多个GPU的计算能力,提高训练效率和速度。
卸载
在深度学习训练过程中,GPU需要大量的数据进行计算,但是如果数据没有及时传输到GPU就会导致GPU处于等待状态,浪费GPU的计算能力。因此,CPU卸载技术就应运而生,通过让CPU负责将数据传输到GPU,可以让GPU专心计算,提高训练速度。
卸载分为多种类型,包括数据卸载、模型卸载、梯度卸载等。数据卸载是指将数据卸载到存储设备(例如硬盘)中,用的时候传输到GPU中,其他的类似。
CPU
深度学习的训练需要用到GPU,因为它的计算速度比较快,但是如果GPU没有及时得到数据,就会处于等待状态,浪费了它的计算能力。CPU卸载技术就是让CPU来负责把数据传输到GPU,这样GPU就可以专心计算,提高训练速度。CPU卸载还可以帮助减少GPU内存的使用,降低训练过程中的内存压力。
nvme
使用 NVMe 固态硬盘扩展 GPU 是一种有效的 CPU 卸载技术。NVMe 固态硬盘具有高速的数据传输速度和低延迟,可以大大提高数据传输效率。此外,NVMe 固态硬盘还支持多通道和多队列,可以实现并行传输和处理,进一步提高数据传输速度。在使用 NVMe 固态硬盘时,可以通过在 CPU 和 GPU 之间使用高带宽 PCIe 总线,进一步优化数据传输速度,提高训练效率和速度。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。