数学基础
- 线性代数
- 概率论与随机过程
- 数值计算
- 蒙特卡洛方法与 MCMC 采样
- 机器学习方法概论
统计学习
深度学习
- 深度学习简介
- 深度前馈网络
- 反向传播算法
- 正则化
- 深度学习中的最优化问题
- 卷积神经网络
- CNN:图像分类
- 循环神经网络 RNN
- Transformer
- 一、Transformer [2017]
- 二、Universal Transformer [2018]
- 三、Transformer-XL [2019]
- 四、GPT1 [2018]
- 五、GPT2 [2019]
- 六、GPT3 [2020]
- 七、OPT [2022]
- 八、BERT [2018]
- 九、XLNet [2019]
- 十、RoBERTa [2019]
- 十一、ERNIE 1.0 [2019]
- 十二、ERNIE 2.0 [2019]
- 十三、ERNIE 3.0 [2021]
- 十四、ERNIE-Huawei [2019]
- 十五、MT-DNN [2019]
- 十六、BART [2019]
- 十七、mBART [2020]
- 十八、SpanBERT [2019]
- 十九、ALBERT [2019]
- 二十、UniLM [2019]
- 二十一、MASS [2019]
- 二十二、MacBERT [2019]
- 二十三、Fine-Tuning Language Models from Human Preferences [2019]
- 二十四 Learning to summarize from human feedback [2020]
- 二十五、InstructGPT [2022]
- 二十六、T5 [2020]
- 二十七、mT5 [2020]
- 二十八、ExT5 [2021]
- 二十九、Muppet [2021]
- 三十、Self-Attention with Relative Position Representations [2018]
- 三十一、USE [2018]
- 三十二、Sentence-BERT [2019]
- 三十三、SimCSE [2021]
- 三十四、BERT-Flow [2020]
- 三十五、BERT-Whitening [2021]
- 三十六、Comparing the Geometry of BERT, ELMo, and GPT-2 Embeddings [2019]
- 三十七、CERT [2020]
- 三十八、DeCLUTR [2020]
- 三十九、CLEAR [2020]
- 四十、ConSERT [2021]
- 四十一、Sentence-T5 [2021]
- 四十二、ULMFiT [2018]
- 四十三、Scaling Laws for Neural Language Models [2020]
- 四十四、Chinchilla [2022]
- 四十七、GLM-130B [2022]
- 四十八、GPT-NeoX-20B [2022]
- 四十九、Bloom [2022]
- 五十、PaLM [2022] (粗读)
- 五十一、PaLM2 [2023](粗读)
- 五十二、Self-Instruct [2022]
- 句子向量
- 词向量
- 传统CTR 预估模型
- CTR 预估模型
- 一、DSSM [2013]
- 二、FNN [2016]
- 三、PNN [2016]
- 四、DeepCrossing [2016]
- 五、Wide 和 Deep [2016]
- 六、DCN [2017]
- 七、DeepFM [2017]
- 八、NFM [2017]
- 九、AFM [2017]
- 十、xDeepFM [2018]
- 十一、ESMM [2018]
- 十二、DIN [2017]
- 十三、DIEN [2019]
- 十四、DSIN [2019]
- 十五、DICM [2017]
- 十六、DeepMCP [2019]
- 十七、MIMN [2019]
- 十八、DMR [2020]
- 十九、MiNet [2020]
- 二十、DSTN [2019]
- 二十一、BST [2019]
- 二十二、SIM [2020]
- 二十三、ESM2 [2019]
- 二十四、MV-DNN [2015]
- 二十五、CAN [2020]
- 二十六、AutoInt [2018]
- 二十七、Fi-GNN [2019]
- 二十八、FwFM [2018]
- 二十九、FM2 [2021]
- 三十、FiBiNET [2019]
- 三十一、AutoFIS [2020]
- 三十三、AFN [2020]
- 三十四、FGCNN [2019]
- 三十五、AutoCross [2019]
- 三十六、InterHAt [2020]
- 三十七、xDeepInt [2023]
- 三十九、AutoDis [2021]
- 四十、MDE [2020]
- 四十一、NIS [2020]
- 四十二、AutoEmb [2020]
- 四十三、AutoDim [2021]
- 四十四、PEP [2021]
- 四十五、DeepLight [2021]
- 图的表达
- 一、DeepWalk [2014]
- 二、LINE [2015]
- 三、GraRep [2015]
- 四、TADW [2015]
- 五、DNGR [2016]
- 六、Node2Vec [2016]
- 七、WALKLETS [2016]
- 八、SDNE [2016]
- 九、CANE [2017]
- 十、EOE [2017]
- 十一、metapath2vec [2017]
- 十二、GraphGAN [2018]
- 十三、struc2vec [2017]
- 十四、GraphWave [2018]
- 十五、NetMF [2017]
- 十六、NetSMF [2019]
- 十七、PTE [2015]
- 十八、HNE [2015]
- 十九、AANE [2017]
- 二十、LANE [2017]
- 二十一、MVE [2017]
- 二十二、PMNE [2017]
- 二十三、ANRL [2018]
- 二十四、DANE [2018]
- 二十五、HERec [2018]
- 二十六、GATNE [2019]
- 二十七、MNE [2018]
- 二十八、MVN2VEC [2018]
- 二十九、SNE [2018]
- 三十、ProNE [2019]
- Graph Embedding 综述
- 图神经网络
- 一、GNN [2009]
- 二、Spectral Networks 和 Deep Locally Connected Networks [2013]
- 三、Fast Localized Spectral Filtering On Graph [2016]
- 四、GCN [2016]
- 五、神经图指纹 [2015]
- 六、GGS-NN [2016]
- 七、PATCHY-SAN [2016]
- 八、GraphSAGE [2017]
- 九、GAT [2017]
- 十、R-GCN [2017]
- 十一、 AGCN [2018]
- 十二、FastGCN [2018]
- 十三、PinSage [2018]
- 十四、GCMC [2017]
- 十五、JK-Net [2018]
- 十六、PPNP [2018]
- 十七、VRGCN [2017]
- 十八、ClusterGCN [2019]
- 十九、LDS-GNN [2019]
- 二十、DIAL-GNN [2019]
- 二十一、HAN [2019]
- 二十二、HetGNN [2019]
- 二十三、HGT [2020]
- 二十四、GPT-GNN [2020]
- 二十五、Geom-GCN [2020]
- 二十六、Graph Network [2018]
- 二十七、GIN [2019]
- 二十八、MPNN [2017]
- 二十九、UniMP [2020]
- 三十、Correct and Smooth [2020]
- 三十一、LGCN [2018]
- 三十二、DGCNN [2018]
- 三十三、AS-GCN
- 三十四、DGI [2018]
- 三十五、DIFFPOLL [2018]
- 三十六、DCNN [2016]
- 三十七、IN [2016]
- 图神经网络 2
- 图神经网络 3
- 推荐算法(传统方法)
- 一、Tapestry [1992]
- 二、GroupLens [1994]
- 三、ItemBased CF [2001]
- 四、Amazon I-2-I CF [2003]
- 五、Slope One Rating-Based CF [2005]
- 六、Bipartite Network Projection [2007]
- 七、Implicit Feedback CF [2008]
- 八、PMF [2008]
- 九、SVD++ [2008]
- 十、MMMF 扩展 [2008]
- 十一、OCCF [2008]
- 十二、BPR [2009]
- 十三、MF for RS [2009]
- 十四、 Netflix BellKor Solution [2009]
- 推荐算法(神经网络方法 1)
- 一、MIND [2019](用于召回)
- 二、DNN For YouTube [2016]
- 三、Recommending What Video to Watch Next [2019]
- 四、ESAM [2020]
- 五、Facebook Embedding Based Retrieval [2020](用于检索)
- 六、Airbnb Search Ranking [2018]
- 七、MOBIUS [2019](用于召回)
- 八、TDM [2018](用于检索)
- 九、DR [2020](用于检索)
- 十、JTM [2019](用于检索)
- 十一、Pinterest Recommender System [2017]
- 十二、DLRM [2019]
- 十三、Applying Deep Learning To Airbnb Search [2018]
- 十四、Improving Deep Learning For Airbnb Search [2020]
- 十五、HOP-Rec [2018]
- 十六、NCF [2017]
- 十七、NGCF [2019]
- 十八、LightGCN [2020]
- 十九、Sampling-Bias-Corrected Neural Modeling [2019](检索)
- 二十、EGES [2018](Matching 阶段)
- 二十一、SDM [2019](Matching 阶段)
- 二十二、COLD [2020 ] (Pre-Ranking 模型)
- 二十三、ComiRec [2020](https://www.wenjiangs.com/doc/0b4e1736-ac78)
- 二十四、EdgeRec [2020]
- 二十五、DPSR [2020](检索)
- 二十六、PDN [2021](mathcing)
- 二十七、时空周期兴趣学习网络ST-PIL [2021]
- 推荐算法之序列推荐
- 一、FPMC [2010]
- 二、GRU4Rec [2015]
- 三、HRM [2015]
- 四、DREAM [2016]
- 五、Improved GRU4Rec [2016]
- 六、NARM [2017]
- 七、HRNN [2017]
- 八、RRN [2017]
- 九、Caser [2018]
- 十、p-RNN [2016]
- 十一、GRU4Rec Top-k Gains [2018]
- 十二、SASRec [2018]
- 十三、RUM [2018]
- 十四、SHAN [2018]
- 十五、Phased LSTM [2016]
- 十六、Time-LSTM [2017]
- 十七、STAMP [2018]
- 十八、Latent Cross [2018]
- 十九、CSRM [2019]
- 二十、SR-GNN [2019]
- 二十一、GC-SAN [2019]
- 二十二、BERT4Rec [2019]
- 二十三、MCPRN [2019]
- 二十四、RepeatNet [2019]
- 二十五、LINet(2019)
- 二十六、NextItNet [2019]
- 二十七、GCE-GNN [2020]
- 二十八、LESSR [2020]
- 二十九、HyperRec [2020]
- 三十、DHCN [2021]
- 三十一、TiSASRec [2020]
- 推荐算法(综述)
- 多任务学习
- 系统架构
- 实践方法论
- 深度强化学习 1
- 自动代码生成
工具
- CRF
- lightgbm
- xgboost
- scikit-learn
- spark
- numpy
- matplotlib
- pandas
- huggingface_transformer
- 一、Tokenizer
- 二、Datasets
- 三、Model
- 四、Trainer
- 五、Evaluator
- 六、Pipeline
- 七、Accelerate
- 八、Autoclass
- 九、应用
- 十、Gradio
Scala
- 环境搭建
- 基础知识
- 函数
- 类
- 样例类和模式匹配
- 测试和注解
- 集合 collection(一)
- 集合collection(二)
- 集成 Java
- 并发
一、基础概念
Accelerate
是一个库,只需添加四行代码,就可以在任何分布式configuration
中运行相同的PyTorch
代码:x + from accelerate import Accelerator + accelerator = Accelerator() + model, optimizer, training_dataloader, scheduler = accelerator.prepare( + model, optimizer, training_dataloader, scheduler + ) for batch in training_dataloader: optimizer.zero_grad() inputs, targets = batch inputs = inputs.to(device) targets = targets.to(device) outputs = model(inputs) loss = loss_function(outputs, targets) + accelerator.backward(loss) optimizer.step() scheduler.step()
上述代码可以通过
Accelerate
的CLI
接口在任何系统上启动:xxxxxxxxxx
accelerate launch {my_script.py}安装:
xxxxxxxxxx
pip install accelerate conda install -c conda-forge accelerate pip install git+https://github.com/huggingface/accelerate配置:
xxxxxxxxxx
accelerate config然后
accelerate
会向你询问一些问题从而生成配置。检查配置:
xxxxxxxxxx
accelerate env为了使用
Accelerate
,你只需要修改四件事:首先,导入
Accelerator
并创建一个accelerator
对象:xxxxxxxxxx
from accelerate import Accelerator accelerator = Accelerator()然后,移除针对你的模型和输入数据的所有
.to(device)
或.cuda()
的调用。accelerator
将会为你正确处理这个问题,并为你把所有这些对象放在正确的设备上。如果你知道你在做什么,你可以保留那些
.to(device)
的调用,但你应该使用accelerator
对象提供的设备:accelerator.device
。要完全停用自动的
device placement
,在初始化Accelerator
时传递device_placement=False
。接着,将所有与训练有关的对象(
optimizer, model, training dataloader, learning rate scheduler
)传递给accelerator.prepare()
方法。这将确保一切都为训练做好准备。xxxxxxxxxx
model, optimizer, train_dataloader, lr_scheduler = accelerator.prepare( model, optimizer, train_dataloader, lr_scheduler )具体而言,
training dataloader
将被分片到所有可用的GPU/TPU
核心上,这样每个设备都能看到训练数据集的不同部分。此外,所有进程的随机数状态将在每次迭代开始时通过dataloader
进行同步,以确保数据以相同的方式被混洗(如果你决定使用shuffle=True
或任何类型的random sampler
)。训练的实际
batch size
将是使用的设备数量乘以你在脚本中设置的batch size
。另外,你可以在创建accelerator
对象时使用split_batches=True
参半,此时无论你在多少个GPU
上运行你的脚本,实际batch size
都会保持不变。你需要再开始实际的
training loop
之前执行accelerator.prepare()
。只有当
scheduler
需要再每个optimizer step
中被stepped
时,才需要把learning rate scheduler
传递给prepare()
。任何获取
training dataloader length
的方法(例如,你需要记录total training step
)都应该在accelerator.prepare()
之后进行。你可能想、也可能不想把你的
validation dataloader
发送到prepare()
,这取决于你是否想运行分布式评估。最后,用
accelerator.backward(loss)
替换loss.backward()
。
现在,你的脚本将在你的本地机器上运行,也可以在多个
GPU
或TPU
上运行。你可以使用你喜欢的工具来启动分布式训练,或者你可以使用Accelerate launcher
启动。分布式评估:
可以进行常规评估,此时你需要将
validation dataloader
保持在accelerator.prepare()
之外。并且,你需要手动将input
数据放在accelerator.device
上。也可以进行分布式评估,此时你需要将
validation dataloader
放置在accelerator.prepare()
之内:xxxxxxxxxx
validation_dataloader = accelerator.prepare(validation_dataloader)就像
training dataloader
,这意味着在分布式评估时,每个设备将仅看到部分evaluation
数据。这意味着你需要把predictions
进行group
。可以通过accelerator.gather_for_metrics()
方法来实现:xxxxxxxxxx
for inputs, targets in validation_dataloader: predictions = model(inputs) # Gather all predictions and targets all_predictions, all_targets = accelerator.gather_for_metrics((predictions, targets)) # Example of use with a Datasets.Metric metric.add_batch(all_predictions, all_targets)类似
training dataloader
,把validation dataloader
传入prepare()
可能会改变该dataloader
:如果你在 $ n $ 个GPU
上运行,则它的长度将被除以 $ n $ (因为你的实际batch size
将被乘以 $ n $ ),除非你设置split_batches=True
。任何获取
validation dataloader length
的方法都应该在accelerator.prepare()
之后进行。数据集末尾的一些数据可能是重复的,所以这个
batch
的数据可以平均分配给所有的工作者。因此,应该通过gather_for_metrics()
方法计算指标,以便在收集时自动删除重复的数据。如果出于某种原因,你不希望自动完成这项工作,可以用accelerator.gather()
来收集所有进程的数据,然后手动完成。gather()
和gather_for_metrics()
要求每个进程上的张量是相同尺寸的。如果你在每个进程上有不同尺寸的张量(例如,当动态填充到一个batch
的最大长度时),你应该使用accelerator.gather.pad_across_processes()
方法将张量填充到跨进程的最大尺寸。
启动分布式脚本:你可以使用常规命令来启动你的分布式训练(如
PyTorch
的torch.distributed.launch
),它们与Accelerate
完全兼容。这里唯一需要注意的是:Accelerate
使用environment
来确定所有有用的信息,所以torch.distributed.launch
应与标志--use_env
一起使用。Accelerate
还提供了一个CLI
工具,它统一了所有的launcher
,所以你只需要记住一个命令:xxxxxxxxxx
accelerate config你需要回答问题,然后
Accelerate
将在你的cache folder
创建一个default_config.yaml
文件。这个缓存目录是(根据优先级递减):- 环境变量
HF_HOME
的内容,以accelerate
为后缀。 - 如果不存在,则环境变量
XDG_CACHE_HOME
的内容,以huggingface/accelerate
为后缀。 - 如果也不存在,则为
~/.cache/huggingface/accelerate
。
你也可以通过标志
--config_file
来指定你要保存的文件的位置。然后,你可以通过运行来测试你的设置是否一切顺利:
xxxxxxxxxx
accelerate test这将启动一个简短的脚本,测试分布式环境。你也可以在测试期间指定配置文件的位置:
xxxxxxxxxx
accelerate test --config_file path_to_config.yaml如果测试通过,你可以通过如下的命令来执行你的脚本:
xxxxxxxxxx
accelerate launch path_to_script.py --args_for_the_script也可以指定配置文件的位置:
xxxxxxxxxx
accelerate launch --config_file path_to_config.yaml path_to_script.py --args_for_the_script- 环境变量
从
notebook
中启动:在Accelerate 0.3.0
中引入了一个notebook_launcher()
从而帮助你在notebook
上启动训练。只要在
notebook
的一个cell
中定义一个负责整个train and/or evaluation
的函数,然后用以下代码执行一个cell
:xxxxxxxxxx
from accelerate import notebook_launcher notebook_launcher(training_function)注意:你的
Accelerator
对象应该只在training_function
中定义,这是因为初始化应该只在launcher
内完成。在
TPU
上训练:如果你想在TPU
上启动你的脚本,有一些注意事项是你应该注意的。在幕后,TPU
将为你的training step
(前向传播、反向传播、以及optimizer step
)中发生的所有操作创建一个graph
。这就是为什么你的第一个训练步总是非常长,因为建立和编译这个graph
需要一些时间。好消息是,这个编译将被缓存,所以第二步和所有后续的
step
将更快。坏消息是,这只适用于你的所有step
做完全相同的操作,这意味着:- 所有
batch
必须有用相同的张量尺寸。 - 必须使用静态的代码(即,如果单个
step
中存在循环,那么循环次数在每个step
必须相同)。
如果上述任何一项在两个
step
之间发生变化,都会触发新的编译,这将再次花费大量时间。在实践中,这意味着:你必须特别注意让你的输入中的所有张量具有相同的形状(所以没有动态填充),并且不应该使用具有for
循环的层,其中for
循环的根据input
的不同而具有不同长度(如LSTM
)。否则,训练会慢得令人难受。可以针对
TPU
执行一些特殊的代码:xxxxxxxxxx
from accelerate import DistributedType if accelerator.distributed_type == DistributedType.TPU: # do something of static shape else: # go crazy and be dynamic最后要注意的是:如果你的模型有
tied weight
(比如语言模型将embedding matrix
的权重与decoder
的权重绑定),将这个模型移动到TPU
(无论是你自己移动、还是由prepare()
移动)会破坏绑定。你将需要在之后重新绑定权重。- 所有
在单个进程上执行的语句:有些语句只需要在特定的进程上执行而无需在所有进程上执行,如数据下载、记录日志、以及打印进度条。此时可以执行:
xxxxxxxxxx
if accelerator.is_local_main_process: # Is executed once per server from tqdm.auto import tqdm progress_bar = tqdm(range(args.max_train_steps), disable=not accelerator.is_local_main_process)local
意思是每台机器上运行:如果你在两台服务器上训练,其中每台服务器有几个GPU
,则代码将在每台服务器上执行一次。如果你希望对所有进程仅执行一次(如,上传模型到
model hub
),则可以执行:xxxxxxxxxx
if accelerator.is_main_process: # Is executed once only对于
print
语句,你希望在每台机器上执行一次,则可以用accelerator.print
代替print
函数。延迟执行:当你运行你的常规脚本时,指令是按顺序执行的。使用
Accelerate
在几个GPU
上同时部署你的脚本会带来一个复杂的问题:虽然每个进程都是按顺序执行所有指令,但有些可能比其他的快。你可能需要等待所有进程达到一定程度后再执行某条指令。例如,在确定每个进程都完成了训练之前,你不应该保存一个模型。要做到这一点,可以执行:
xxxxxxxxxx
accelerator.wait_for_everyone()这条指令将阻塞所有先到的进程,直到所有其他进程都到达该点(如果你只在一个
GPU
或CPU
上运行你的脚本,这不会有任何作用)。保存/加载模型:保存训练好的模型可能需要一些调整:
首先,你应该等待所有的进程到达脚本中的 “延迟执行” 所描述的那个点。
然后,你应该在保存模型之前
unwrap
你的模型。这是因为在通过prepare()
方法时,你的模型可能被wrap
从而用于分布式训练。如:xxxxxxxxxx
accelerator.wait_for_everyone() unwrapped_model = accelerator.unwrap_model(model) accelerator.save(unwrapped_model.state_dict(), filename)如果你的脚本包含加载
checkpoint
的逻辑,我们也建议你在unwrapped model
中加载你的权重(这只在prepare()
后使用加载函数时有用)。如:xxxxxxxxxx
unwrapped_model = accelerator.unwrap_model(model) unwrapped_model.load_state_dict(torch.load(filename))
保存/加载整个状态:当训练你的模型时,你可能想保存模型、优化器、随机数生成器、以及潜在的
LR scheduler
的当前状态,以便在同一个脚本中恢复训练。你可以分别使用save_state()
和load_state()
来做到这一点,只需简单地传入一个保存位置。如果你通过
register_for_checkpointing()
注册了任何其他需要存储的stateful item
,它们也会被保存和/或加载。示例:
xxxxxxxxxx
from accelerate import Accelerator import torch accelerator = Accelerator() my_scheduler = torch.optim.lr_scheduler.StepLR(my_optimizer, step_size=1, gamma=0.99) my_model, my_optimizer, my_training_dataloader = accelerate.prepare(my_model, my_optimizer, my_training_dataloader) # Register the LR scheduler accelerate.register_for_checkpointing(my_scheduler) # Save the starting state accelerate.save_state("my/save/path") device = accelerator.device my_model.to(device) # Perform training for epoch in range(num_epochs): for batch in my_training_dataloader: my_optimizer.zero_grad() inputs, targets = batch inputs = inputs.to(device) targets = targets.to(device) outputs = my_model(inputs) loss = my_loss_function(outputs, targets) accelerator.backward(loss) my_optimizer.step() my_scheduler.step() # Restore previous state accelerate.load_state("my/save/path")梯度裁剪:如果你在脚本中使用梯度剪裁,你应该把对
torch.nn.utils.clip_grad_norm_
或torch.nn.utils.clip_grad_value_
的调用分别替换为accelerator.clipgrad_norm()
和accelerator.clipgrad_value()
。混合精度训练:如果你用
Accelerate
在混合精度下训练,那么模型内的计算将以混合精度进行,而模型外的每一次计算都将以full precision
执行。例如,loss
的计算通常在模型外,且涉及softmax
。然而,你可能想把你的loss
计算放在accelerator.autocast
上下文管理器中:xxxxxxxxxx
with accelerator.autocast(): loss = complex_loss_function(outputs, target)混合精度训练的另一个注意事项是:梯度会在开始时跳过一些更新,有时在训练过程中也会跳过。这是因为动态损失缩放
dynamic loss scaling
策略,在训练过程中会有一些时刻,梯度已经溢出,loss scaling factor
会减少,从而避免在下一步再次发生这种情况。这意味着你可能会在没有梯度更新的时候就更新你的
learning rate scheduler
。这在一般情况下是没有问题的,但是当你的训练数据非常少,或者你的scheduler
的第一个学习率值非常重要时,可能会有影响。在这种情况下,你可以跳过learning rate scheduler
的更新:xxxxxxxxxx
if not accelerator.optimizer_step_was_skipped: lr_scheduler.step()梯度累积:要执行梯度累积,请使用
accumulate()
并指定gradient_accumulation_steps
。在多设备训练时,这也会自动确保梯度同步或不同步,检查是否真的应该执行该step
,并自动计算损失:xxxxxxxxxx
accelerator = Accelerator(gradient_accumulation_steps=2) model, optimizer, training_dataloader = accelerator.prepare(model, optimizer, training_dataloader) for input, label in training_dataloader: with accelerator.accumulate(model): predictions = model(input) loss = loss_function(predictions, label) accelerator.backward(loss) optimizer.step() scheduler.step() optimizer.zero_grad()相比之下,传统的梯度累加方法会用更冗长的代码:
xxxxxxxxxx
+ from accelerate import Accelerator + accelerator = Accelerator() + model, optimizer, training_dataloader, scheduler = accelerator.prepare( + model, optimizer, training_dataloader, scheduler + ) for index, batch in enumerate(training_dataloader): inputs, targets = batch - inputs = inputs.to(device) - targets = targets.to(device) outputs = model(inputs) loss = loss_function(outputs, targets) loss = loss / gradient_accumulation_steps + accelerator.backward(loss) if (index+1) % gradient_accumulation_steps == 0: optimizer.step() scheduler.step() optimizer.zero_grad()DeepSpeed
:DeepSpeed
支持是实验性的,所以底层API
将在不久的将来发展,可能会有一些轻微的破坏性变化。具体而言,Accelerate
还不支持你自己编写的DeepSpeed
配置,这将在下一个版本中添加。使用
accelerate launch
:xxxxxxxxxx
accelerate launch {script_name.py} --arg1 --arg2 ...指定单个
GPU
:xxxxxxxxxx
CUDA_VISIBLE_DEVICES="0" accelerate launch {script_name.py} --arg1 --arg2 ...在两个
GPU
上混合精度训练:xxxxxxxxxx
accelerate launch --multi_gpu --mixed_precision=fp16 --num_processes=2 {script_name.py} {--arg1} {--arg2} ...建议总是在
accelerate launch
之前执行accelerate config
,这样就无需再accelerate launch
中指定各种配置。在
notebook
中launch
:- 确保任何使用
CUDA
的代码在一个函数中,该函数被传递给notebook_launcher()
。 - 设置
num_processes
为训练的设备数量(如,GPU, CPU, TPU
数量)。 - 如果使用
TPU
,在training loop
函数之外声明你的模型。
如:
xxxxxxxxxx
from accelerate import notebook_launcher args = ("fp16", 42, 64) notebook_launcher(training_loop, args, num_processes=2)对于
TPU
:xxxxxxxxxx
model = create_model("resnet50d", pretrained=True, num_classes=len(label_to_id)) args = (model, "fp16", 42, 64) notebook_launcher(training_loop, args, num_processes=8)- 确保任何使用
启用
FSDP
:首先进行配置:
accelerate config
。FSDP
配置的一个例子:xxxxxxxxxx
compute_environment: LOCAL_MACHINE deepspeed_config: {} distributed_type: FSDP downcast_bf16: 'no' fsdp_config: fsdp_auto_wrap_policy: TRANSFORMER_BASED_WRAP fsdp_backward_prefetch_policy: BACKWARD_PRE fsdp_offload_params: false fsdp_sharding_strategy: 1 fsdp_state_dict_type: FULL_STATE_DICT fsdp_transformer_layer_cls_to_wrap: GPT2Block machine_rank: 0 main_process_ip: null main_process_port: null main_training_function: main mixed_precision: 'no' num_machines: 1 num_processes: 2 use_cpu: false然后开始训练:
xxxxxxxxxx
accelerate launch examples/nlp_example.py这些配置参数的含义为:
Sharding Strategy
:FULL_SHARD
:对optimizer states, gradients, parameters
都进行分片。SHARD_GRAD_OP
:仅对optimizer states, gradients
进行分片。NO_SHARD
:不进行分片。
Offload Params
:一个布尔值,指定是否将parameters
和gradients
卸载到CPU
。Auto Wrap Policy
:可以为TRANSFORMER_BASED_WRAP, SIZE_BASED_WRAP, NO_WRAP
。Transformer Layer Class to Wrap
:当使用TRANSFORMER_BASED_WRAP
时,指定特定的transformer layer class name
(大小写敏感)从而执行wrap
。如BertLayer, GPTJBlock, T5Block,...
。Min Num Params
:使用SIZE_BASED_WRAP
的最小参数数量。Backward Prefetch
:可以为BACKWARD_PRE, BACKWARD_POST, NO_PREFETCH
。State Dict Type
:可以为FULL_STATE_DICT, LOCAL_STATE_DICT, SHARDED_STATE_DICT
。
有几个需要注意的地方:
PyTorch FSDP
会自动wrap
子模块,对参数进行扁平化处理,并将参数分片。由于这个原因,任何在model wrapping
之前创建的optimizer
都会被破坏,并占用更多的内存。因此,强烈建议在创建optimizer
之前准备好模型,这也是很有效的。Accelerate
将自动wrap
模型,并在单个模型的情况下为你创建一个优化器,并发出警告信息:xxxxxxxxxx
FSDP Warning: When using FSDP, it is efficient and recommended to call prepare for the model before creating the optimizer.下面是使用
FSDP
时准备模型和优化器的推荐方法:xxxxxxxxxx
model = AutoModelForSequenceClassification.from_pretrained("bert-base-cased", return_dict=True) + model = accelerator.prepare(model) optimizer = torch.optim.AdamW(params=model.parameters(), lr=lr) - model, optimizer, train_dataloader, eval_dataloader, lr_scheduler = accelerator.prepare( - model, optimizer, train_dataloader, eval_dataloader, lr_scheduler - ) + optimizer, train_dataloader, eval_dataloader, lr_scheduler = accelerator.prepare( + optimizer, train_dataloader, eval_dataloader, lr_scheduler + )在单个模型的情况下,如果你用多个
parameter groups
创建了优化器,并且用它们一起调用prepare
,那么parameter groups
将被丢失,并显示以下警告:xxxxxxxxxx
FSDP Warning: When using FSDP, several parameter groups will be conflated into a single one due to nested module wrapping and parameter flattening.这是因为,由于嵌套的
FSDP
模块的参数扁平化为一维数组,在wrapping
前创建的parameter groups
在wrapping
后将没有意义。在有多个模型的情况下,有必要在创建优化器之前准备好模型,否则会抛出一个错误。然后将优化器以与相应模型相同的顺序传递给
prepare()
方法,否则accelerator.save_state()
和accelerator.load_state()
将导致错误/意外的行为。这个功能与
Transformers library
的run_translation.py
脚本中的--predict_with_generate
不兼容。
对于更多的控制,用户可以利用
FullyShardedDataParallelPlugin
。在创建这个类的实例后,用户可以把它传递给Accelerator
类的实例。
启用
DeepSpeed
:DeepSpeed
实现了ZeRO
论文中描述的一切。目前,它提供了如下的支持:Optimizer state partitioning
(ZeRO stage 1
)、Gradient partitioning
(ZeRO stage 2
)、Parameter partitioning
(ZeRO stage 3
)、Custom mixed precision training handling
、一系列基于CUDA
扩展的快速优化器、ZeRO-Offload
到CPU
和Disk/NVMe
。DeepSpeed ZeRO-2
主要只用于训练,因为它的功能对推理没有用处。DeepSpeed ZeRO-3
也可以用于推理,因为它允许在多个GPU
上加载巨大的模型。Accelerate
通过两种方式集成DeepSpeed
:- 通过
deepspeed
配置文件来集成。它支持DeepSpeed
的所有核心功能,并为用户提供了很大的灵活性。用户可能需要根据配置来改变几行代码。 - 通过
deepspeed_plugin
来集成。这支持DeepSpeed
功能的子集,并对其余的配置使用默认选项。用户不需要改变任何代码。
- 通过
什么被集成了?
训练:
DeepSpeed ZeRO
训练支持完整的ZeRO stages 1, 2 and 3
、以及optimizer states, gradients and parameters
的CPU/Disk offload
。Stage 1
:将optimizer states
分片到数据并行workers/GPUs
上。Stage 2
:将optimizer states + gradients
分片到数据并行workers/GPUs
上。Stage 3
:将optimizer states + gradients + model parameters
分片到数据并行workers/GPUs
上。Optimizer Offload
:将optimizer states + gradients
卸载到CPU/Disk
,建立在ZERO Stage 2
之上。Param Offload
:将model parameters
卸载到CPU/Disk
,建立在ZERO Stage 3
之上。
注意:关于
Disk Offload
,磁盘应该是NVME
的,以便有好的速度,但技术上可以在任何磁盘上工作。推断:
DeepSpeed ZeRO Inference
支持ZeRO Stage 3
与ZeRO-Infinity
。它使用与训练相同的ZeRO
协议,但它不使用优化器和lr scheduler
。
如何工作:
首先安装
DeepSpeed version >=0.6.5
。然后配置:
accelerate config
。一个配置的例子:xxxxxxxxxx
compute_environment: LOCAL_MACHINE deepspeed_config: gradient_accumulation_steps: 1 gradient_clipping: 1.0 offload_optimizer_device: none offload_param_device: none zero3_init_flag: true zero_stage: 2 distributed_type: DEEPSPEED fsdp_config: {} machine_rank: 0 main_process_ip: null main_process_port: null main_training_function: main mixed_precision: fp16 num_machines: 1 num_processes: 2 use_cpu: false最后执行训练:
accelerate launch examples/nlp_example.py
。
配置参数的含义:
zero_stage
:0
表示禁用,1
表示optimizer state partitioning
,2
表示optimizer+gradient state partitioning
,3
表示optimizer+gradient+parameter partitioning
。gradient_accumulation_steps
:一个整数,表示在averaging
和applying
这些梯度之前,积累梯度的training steps
数量。gradient_clipping
:一个浮点数,指定启用梯度剪裁的值。offload_optimizer_device
:none
表示禁用optimizer offloading
,cpu
表示offload optimizer
到CPU
,nvme
表示offload optimizer
到NVMe SSD
。仅适用于ZeRO >= Stage-2
。offload_param_device
:none
表示禁用parameter offloading
,cpu
表示offload parameter
到CPU
,nvme
表示offload parameter
到NVMe SSD
。仅适用于ZeRO Stage-3
。zero3_init_flag
:决定是否启用deepspeed.zero.Init
来构建大规模模型。只适用于ZeRO Stage-3
。zero3_save_16bit_model
:决定是否在使用ZeRO Stage-3
时保存16
位模型权重。mixed_precision
:no
用于FP32
训练,fp16
用于FP16
混合精度训练,bf16
用于BF16
混合精度训练。
当使用配置文件时,需要修改一些代码:
DeepSpeed Optimizers and Schedulers
:如果是
DeepSpeed Optim + DeepSpeed Scheduler
:用户必须使用enhance.utils.DummyOptim
和enhance.utils.DummyScheduler
来取代他们代码中的PyTorch/Custom
优化器和调度器:xxxxxxxxxx
# Creates Dummy Optimizer if `optimizer` was spcified in the config file else creates Adam Optimizer optimizer_cls = ( torch.optim.AdamW if accelerator.state.deepspeed_plugin is None or "optimizer" not in accelerator.state.deepspeed_plugin.deepspeed_config else DummyOptim ) optimizer = optimizer_cls(optimizer_grouped_parameters, lr=args.learning_rate) # Creates Dummy Scheduler if `scheduler` was spcified in the config file else creates `args.lr_scheduler_type` Scheduler if ( accelerator.state.deepspeed_plugin is None or "scheduler" not in accelerator.state.deepspeed_plugin.deepspeed_config ): lr_scheduler = get_scheduler( name=args.lr_scheduler_type, optimizer=optimizer, num_warmup_steps=args.num_warmup_steps, num_training_steps=args.max_train_steps, ) else: lr_scheduler = DummyScheduler( optimizer, total_num_steps=args.max_train_steps, warmup_num_steps=args.num_warmup_steps )Custom Optim + Custom Scheduler
:当DeepSpeed
配置文件中没有optimizer key
和scheduler key
的情况。在这种情况下,不需要用户修改代码,通过DeepSpeed Plugin
使用集成时就是这种情况。Custom Optim + DeepSpeed Scheduler
:这种情况下,用户必须使用accelerate.utils.DummyScheduler
来替换代码中的PyTorch/Custom scheduler
。DeepSpeed Optim + Custom Scheduler
:这将导致一个错误,因为当使用DeepSpeed Optim
时必须使用DeepSpeed Scheduler
。
DeepSpeed
配置文件中存在一些"auto"
值,这些值是由prepare
方法根据所提供的模型、dataloaders
、dummy optimizer
和dummy schedulers
自动处理的。那些不是"auto"
的字段必须由用户明确指定。如zero_stage2_config.json
文件:xxxxxxxxxx
{ "fp16": { "enabled": true, "loss_scale": 0, "loss_scale_window": 1000, "initial_scale_power": 16, "hysteresis": 2, "min_loss_scale": 1 }, "optimizer": { "type": "AdamW", "params": { "lr": "auto", "weight_decay": "auto", "torch_adam": true, "adam_w_mode": true } }, "scheduler": { "type": "WarmupDecayLR", "params": { "warmup_min_lr": "auto", "warmup_max_lr": "auto", "warmup_num_steps": "auto", "total_num_steps": "auto" } }, "zero_optimization": { "stage": 2, "allgather_partitions": true, "allgather_bucket_size": 2e8, "overlap_comm": true, "reduce_scatter": true, "reduce_bucket_size": "auto", "contiguous_gradients": true }, "gradient_accumulation_steps": 1, "gradient_clipping": "auto", "steps_per_print": 2000, "train_batch_size": "auto", "train_micro_batch_size_per_gpu": "auto", "wall_clock_breakdown": false }
保存和加载:
对于
ZeRO Stage-1
和ZeRO Stage-2
,模型的保存和加载不需要改动。对于
ZeRO Stage-3
,state_dict
仅只包含占位符,因为模型的权重被分片到多个GPU
。ZeRO Stage-3
有两个选项:保存整个
16
位的模型权重,然后使用model.load_state_dict(torch.load(pytorch_model.bin))
来直接加载。为此,要么在DeepSpeed
配置文件中把zero_optimization.stage3_gather_16bit_weights_on_model_save
设为True
,要么在DeepSpeed Plugin
中把zero3_save_16bit_model
设为True
。请注意,这个选项需要在一个
GPU
上整合权重,这可能会很慢,而且对内存要求很高,所以只有在需要时才使用这个功能。示例:
xxxxxxxxxx
unwrapped_model = accelerator.unwrap_model(model) # New Code # # Saves the whole/unpartitioned fp16 model when in ZeRO Stage-3 to the output directory if # `stage3_gather_16bit_weights_on_model_save` is True in DeepSpeed Config file or # `zero3_save_16bit_model` is True in DeepSpeed Plugin. # For Zero Stages 1 and 2, models are saved as usual in the output directory. # The model name saved is `pytorch_model.bin` unwrapped_model.save_pretrained( args.output_dir, is_main_process=accelerator.is_main_process, save_function=accelerator.save, state_dict=accelerator.get_state_dict(model), )为了获得
32
位的权重,首先使用model.save_checkpoint()
保存模型:xxxxxxxxxx
success = model.save_checkpoint(PATH, ckpt_id, checkpoint_state_dict) status_msg = "checkpointing: PATH={}, ckpt_id={}".format(PATH, ckpt_id) if success: logging.info(f"Success {status_msg}") else: logging.warning(f"Failure {status_msg}")这将在
checkpoint
目录下创建ZeRO model
和optimizer
的partitions
以及zero_to_fp32.py
脚本。你可以使用这个脚本来做离线整合,这不需要配置文件或GPU
。如:xxxxxxxxxx
cd /path/to/checkpoint_dir ./zero_to_fp32.py . pytorch_model.bin # Processing zero checkpoint at global_step1 # Detected checkpoint of type zero stage 3, world_size: 2 # Saving fp32 state dict to pytorch_model.bin (total_numel=60506624)要想加载
32
位的模型,做法如下:xxxxxxxxxx
from deepspeed.utils.zero_to_fp32 import load_state_dict_from_zero_checkpoint unwrapped_model = accelerator.unwrap_model(model) fp32_model = load_state_dict_from_zero_checkpoint(unwrapped_model, checkpoint_dir)如果你仅仅想得到
state_dict
,做法如下:xxxxxxxxxx
from deepspeed.utils.zero_to_fp32 import get_fp32_state_dict_from_zero_checkpoint state_dict = get_fp32_state_dict_from_zero_checkpoint(checkpoint_dir)注意,加载时需要大约
2
倍于final checkpoint
大小的内存。
ZeRO Inference
:DeepSpeed ZeRO Inference
支持ZeRO stage 3
。通过accelerate
的集成,你只需要prepare
模型和dataloader
,如下:xxxxxxxxxx
model, eval_dataloader = accelerator.prepare(model, eval_dataloader)注意事项:
- 目前的集成不支持
DeepSpeed
的Pipeline Parallelism
。 - 当前的集成不支持
mpu
,限制了Megatron-LM
中支持的张量并行。 - 目前的集成不支持多个模型。
- 目前的集成不支持
目前
Accelerate
支持如下的tracker
:TensorBoard, WandB, CometML, MLFlow
,如:xxxxxxxxxx
from accelerate import Accelerator from accelerate.utils import LoggerType accelerator = Accelerator(log_with="all") # For all available trackers in the environment accelerator = Accelerator(log_with="wandb") accelerator = Accelerator(log_with=["wandb", LoggerType.TENSORBOARD])然后需要初始化
tracker
:xxxxxxxxxx
hps = {"num_iterations": 5, "learning_rate": 1e-2} accelerator.init_trackers("my_project", config=hps)然后记录日志:
xxxxxxxxxx
accelerator.log({"train_loss": 1.12, "valid_loss": 0.8}, step=1)最后在训练结束时调用:
accelerator.end_training()
。你也可以通过
accelerator.get_tracker
来获取内置的tracker
对象:xxxxxxxxxx
wandb_tracker = accelerator.get_tracker("wandb") if accelerator.is_main_process: wandb_run.log_artifact(some_artifact_to_log)处理大模型:常规的加载预训练模型的方式:
xxxxxxxxxx
import torch my_model = ModelClass(...) # step 1 state_dict = torch.load(checkpoint_file) # step 2 my_model.load_state_dict(state_dict) # step 3这对于常规大小的模型而言很有效,但是无法处理大型模型:在
step 1
我们在RAM
中加载一个完整版本的模型,并花一些时间随机初始化权重(这将在step 3
被丢弃);在step 2
,我们在RAM
中加载另一个完整版本的模型,并使用预训练的权重。Accelerate
提供一些工具来帮助处理大模型(这些API
是实验性质的,未来可能会发生改变):init_empty_weights
上下文管理器:初始化一个模型而无需使用任何内存。这依赖于PyTorch 1.9
中引入的meta device
。xxxxxxxxxx
from accelerate import init_empty_weights with init_empty_weights(): my_model = ModelClass(...)在该上下文管理器中,每当有一个
parameter
被创建时,它就被立即移动到meta device
。sharded checkpoints
:有可能你的模型太大从而无法装入内存,这并不意味着它不能被加载:如果你有一个或几个GPU
,这就有更多的内存可用于存储你的模型。此时需要你的checkpoint
被拆分为几个小文件,即checkpoint shards
。Accelerate
将处理checkpoint shards
,但是要满足如下格式:你的checkpoint shards
应该放在一个文件夹中,并且有几个包含部分state dict
的文件、以及一个index.json
文件(将parameter name
映射到包含该parameter weights
的文件)。如:xxxxxxxxxx
first_state_dict.bin index.json second_state_dict.bin其中
index.json
内容为:xxxxxxxxxx
{ "linear1.weight": "first_state_dict.bin", "linear1.bias": "first_state_dict.bin", "linear2.weight": "second_state_dict.bin", "linear2.bias": "second_state_dict.bin" }load_checkpoint_and_dispatch
:在empty model
中加载一个checkpoint
。它支持full checkpoints
(包含整个state dict
的单一文件)以及sharded checkpoints
。它还会在你可用的设备(GPU
、CPU
)上自动分配这些权重,所以如果你正在加载一个sharded checkpoints
,最大的RAM
用量将是最大分片的大小。例如:
xxxxxxxxxx
git clone https://huggingface.co/sgugger/sharded-gpt-j-6B cd sharded-gpt-j-6B git-lfs install git pull初始化模型:
xxxxxxxxxx
from accelerate import init_empty_weights from transformers import AutoConfig, AutoModelForCausalLM checkpoint = "EleutherAI/gpt-j-6B" config = AutoConfig.from_pretrained(checkpoint) with init_empty_weights(): model = AutoModelForCausalLM.from_config(config)加载权重:
xxxxxxxxxx
from accelerate import load_checkpoint_and_dispatch model = load_checkpoint_and_dispatch( model, "sharded-gpt-j-6B", device_map="auto", no_split_module_classes=["GPTJBlock"] )通过
device_map="auto"
,Accelerate
根据可用资源自动决定将模型的每一层放在哪里:- 首先,我们使用
GPU
上的最大可用空间。 - 如果我们仍然需要空间,我们将剩余的权重存储在
CPU
上。 - 如果没有足够的
RAM
,我们将剩余的权重作为内存映射的张量存储在硬盘上。
no_split_module_classes=["GPTJBlock"]
表示属于GPTJBlock
的模块不应该在不同的设备上分割。你应该在这里设置所有包括某种残差连接的block
。可以通过
model.hf_device_map
查看模型的权重的设备。- 首先,我们使用
分布式训练的复现:
设置随机数种子:
xxxxxxxxxx
from accelerate import set_seed set_seed(42)它在内部设置了五种随机数种子:
xxxxxxxxxx
random.seed(seed) np.random.seed(seed) torch.manual_seed(seed) torch.cuda.manual_seed_all(seed) # ^^ safe to call this function even if cuda is not available if is_tpu_available(): xm.set_rng_state(seed)设置
batch size
:当使用Accelerate
训练时,传递给dataloader
的batch size
是batch size/GPU
,因此final batch size
是batch size * device num
。设置学习率:学习率应该和
device num
成正比,如:xxxxxxxxxx
learning_rate = 1e-3 accelerator = Accelerator() learning_rate *= accelerator.num_processes optimizer = AdamW(params=model.parameters(), lr=learning_rate)
梯度同步:在
DDP
中,PyTorch
在一些特定的点上进行进程间通信。然而在梯度累积时,你会累积n
个loss
并跳过.backward()
。这可能会导致明显的减速,因为所有的进程都需要与它们进行更多次的通信。可以通过
no_sync
上下文管理器来避免:xxxxxxxxxx
ddp_model, dataloader = accelerator.prepare(model, dataloader) for index, batch in enumerate(dataloader): inputs, targets = batch # Trigger gradient synchronization on the last batch if index != (len(dataloader)-1): - with ddp_model.no_sync(): + with accelerator.no_sync(model): # Gradients only accumulate outputs = ddp_model(inputs) loss = loss_func(outputs, targets) accelerator.backward(loss) else: # Gradients finally sync outputs = ddp_model(inputs) loss = loss_func(outputs) accelerator.backward(loss)或者直接使用
accelerator.accumulate
:xxxxxxxxxx
ddp_model, dataloader = accelerator.prepare(model, dataloader) for batch in dataloader: with accelerator.accumulate(model): optimizer.zero_grad() inputs, targets = batch outputs = model(inputs) loss = loss_function(outputs, targets) accelerator.backward(loss)进程间同步:
xxxxxxxxxx
accelerator.wait_for_everyone()这将阻塞所有进程直到所有进程都达到该点。
用途:
加载数据集:
xxxxxxxxxx
with accelerator.main_process_first(): datasets = load_dataset("glue", "mrpc")这等价于:
xxxxxxxxxx
# First do something on the main process if accelerator.is_main_process: datasets = load_dataset("glue", "mrpc") else: accelerator.wait_for_everyone() # And then send it to the rest of them if not accelerator.is_main_process: datasets = load_dataset("glue", "mrpc") else: accelerator.wait_for_everyone()存取
state_dict
:xxxxxxxxxx
if accelerator.is_main_process: model = accelerator.unwrap_model(model) torch.save(model.state_dict(), "weights.pth") with accelerator.main_process_first(): state = torch.load("weights.pth") model.load_state_dict(state)在
global main
进程上tokenizing
,然后传播到每个worker
:xxxxxxxxxx
datasets = load_dataset("glue", "mrpc") with accelerator.main_process_first(): tokenized_datasets = datasets.map( tokenize_function, batched=True, remove_columns=["idx", "sentence1", "sentence2"], )
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论