公司网站必须做可信认证吗旅行网站开发

当前位置: 首页 > news >正文

公司网站必须做可信认证吗,旅行网站开发,视觉差的网站,重庆做网站公司经典神经网络(13)GPT-1、GPT-2原理及nanoGPT源码分析(GPT-2) 2022 年 11 月#xff0c;ChatGPT 成功面世#xff0c;成为历史上用户增长最快的消费者应用。与 Google、FaceBook等公司不同#xff0c;OpenAI 从初代模型 GPT-1 开始#xff0c;始终贯彻只有解码器#xff0…经典神经网络(13)GPT-1、GPT-2原理及nanoGPT源码分析(GPT-2) 2022 年 11 月ChatGPT 成功面世成为历史上用户增长最快的消费者应用。与 Google、FaceBook等公司不同OpenAI 从初代模型 GPT-1 开始始终贯彻只有解码器Decoder-only的技术路径不断迭代升级。 模型发布日期GPT2018-11-14GPT-22019-11-27GPT-32020-6-11InstructGPT2022-3-4ChatGPT2022-11-30GPT-42023-3-14ChatGPT Plugin2023-5-12 可以看到2022 年是 GPT 系列模型围绕 GPT-3、GPT-3.5 加速版本迭代的年份 2022 年 3 月基于 GPT-3 微调的 InstructGPT 发布验证了人类反馈强化学习RLHF对模型输出对齐alignment的重要作用2022年4-6月基于Codex、InstructGPTOpenAI 加速迭代形成 GPT-3.5 模型2022 年 11 月基于 GPT-3.5 微调的 ChatGPT 发布成为 Instruction-tuning、RLHF、思维链等 LLM 相关技术的集大成者。 ChatGPT与InstructGPT的训练方法基本一致区别在于InstructGPT、ChatGPT分别基于GPT-3、GPT-3.5进行模型微调。InstructGPT具体可分为有监督微调、奖励模型训练、PPO 强化学习三个步骤。ChatGPT技术原理解析可参考https://blog.csdn.net/v_JULY_v/article/details/128579457 2023年3月中旬OpenAI正式对外发布GPT-4增加了多模态(支持图片的输入形式)且ChatGPT底层的语言模型直接从GPT3.5升级到了GPT4。 ChatGPT 的发展不仅得益于 GPT 模型参数、训练数据的持续优化也得益于各类 LLM 新技术的融会贯通OpenAI 博采众长加速 Instruction-tuning、RLHF、思维链等新技术在 GPT 系列模型中的深度应用ChatGPT 是现有技术的集大成者。 我们今天主要了解下GPT-2。
1 GPT-1简介 2017年Google推出了Transformer模型这一架构因其在性能上的显著优势迅速吸引了OpenAI团队的注意。OpenAI随后将研发重点转移到Transformer架构并在2018年发布了GPT-1模型。 OpenAI在2018年提出了GPTGenerative Pre-training生成式预训练模型采用了仅有解码器的Transformer模型专注于预测下一个词元。 GPT采用了transformer的Decoder作为框架并采用了两阶段的训练方式。首先在大量的无标记数据集中进行生成式训练Generative Pre-training然后在在特定任务进行微调fine-tuning。 论文language_understanding_paper (openai.com)
1.1 GPT-1网络结构 下图左半部分是transformer架构图右半部分是GPT的架构图。与GPT相比transformer的Decoder除了中间被隐去的cross-attention其余部分结构相同GPT由12个Decoder串联而成。 GPT的输入部分与transformer的Encoder的输入部分相同与transformer不同的是位置向量采用随机初始化并在训练中进行更新GPT的Decoder可以看做是 transformer 的 Decoder 去掉中间Cross-Attention后的结构。Decoder主要有三个子模块组成Masked Multi-Head Attention、残差网络LayerNorm 以及 Feed Forward。 GPT的输出部分对应于下游任务不同的任务使用不同的全连接层作为输出。 1.2 两阶段训练 GPT的训练过程分为两个阶段第一阶段是采用大量文本预料进行无监督训练第二个阶段是采用少量有标注的数据进行有监督的微调。 1.2.1 无监督预训练 GPT采用标准的语言模型进行无监督训练即通过上文前 k k k个词来预测当前词预训练时只有Text Prediction没有Task Classifier 预训练模型的参数设置 GPT-1使用BooksCorpus数据集(约5GB)来训练语言模型。BooksCorpus有大约7000本未出版的书籍这些书籍帮助在不可见的数据上训练语言模型。 采用L12层decoder每个自注意层有A12个注意头使用了带有40,000个合并的字节对编码(BPE)词汇表分词嵌入维度H为768位置编码嵌入维度为768通过模型学习获得位置编码位置前馈层采用3072维dropout为0.1GELU函数作为激活函数batch_size为64序列长度为512epoch为100 参数共117M即1.17 亿的参数量。 1.2.2 有监督微调 无监督训练完毕后并不能直接用于下游任务需要在具体任务的标注数据集上进行微调(如下图右半部分)。对于大多数下游任务监督的微调只需要3个epoch。对比预训练阶段只是多增加了“Task Classifier”模块。 当得到无监督的预训练模型后可以将该模型直接应用到有监督任务中。每个实例有m个输入 x 1 , x 2 , . . , x m x^1,x^2,..,x^m x1,x2,..,xm 以及标签y组成。首先将这些token输入到预训练的GPT1中得到最终的特征向量 h l m h_l^m hlm​ ,然后再通过一个全连接层得到预测结果y P ( y ∣ x 1 , … , x m ) s o f t m a x ( h l m W y ) P(y|x^1,…,x^m)softmax(h_l^mW_y) P(y∣x1,…,xm)softmax(hlm​Wy​) 有监督的目标是最大化以下损失 L 2 ( C ) ∑ l o g P ( y ∣ x 1 , … , x m ) L_2©∑logP(y|x^1,…,x^m) L2​©∑logP(y∣x1,…,xm) GPT的实验中发现加入语言模型学习目标作为辅助任务也就是损失函数中加入 L 1 ( u ) L_1(u) L1​(u)能带来两点好处不仅能提升监督模型的泛化能力还能加快收敛 因此作者并没有直接使用L2而是使用联合损失函数来进行微调(Text Prediction【L1】 Task Classifier【L2】)并使用 λ λ λ 进行两个任务权值的调整 λ λ λ 的值一般为0.5 L 3 ( C ) L 2 ( C ) λ ∗ L 1 ( C ) L_3©L_2©λ*L_1© L3​©L2​©λ∗L1​© 文本分类可以看到有两个特殊符号Start和Extract通过Transformer后添加了一个线性层。 蕴含理解给一段话提出一个假设看看假设是否成立。 将前提premise和假设hypothesis通过分隔符Delimiter隔开两端加上起始和终止token再依次通过Transformer和全连接得到预测结果 文本相似断两段文字是不是相似。相似是一个对称关系A和B相似那么B和A也是相似的 所以先有Text1分隔符Text2再有Text2分隔符Text1两个序列分别经过Transformer后各自得到输出的向量我们把它按元素加到一起然后送给一个线性层。这也是一个二分类问题。 多项选择多个序列每个序列都由相同的问题Context和不同的Answer构成。 如果有N个答案就构造N个序列每个QA序列都各自经过Transformers和线性层对每个答案都计算出一个标量最后经过softmax生成一个各个答案的概率密度分布。这是一个N分类问题。
2 GPT-2简介 Bert论文https://arxiv.org/pdf/1810.04805 GPT-2论文Language Models are Unsupervised Multitask Learners (openai.com) 同年10月谷歌发布了BERT模型。BERT用了Transformer中的Encoder部分更类似完形填空根据上下文来确定中间词 和GPT相比BERT所使用的掩码语言模型任务Masked Language Model虽然让它失去了直接生成文本的能力但换来的是双向编码的能力这让模型拥有了更强的文本编码性能直接的体现则是下游任务效果的大幅提升。而GPT为了保留生成文本的能力只能采用单向编码。 如下图所示为了和GPT进行对比Bert论文作者设计了Base模型模型参数大小和GPT大致相等。但是BERT数据集的数据量大概是GPT的四倍。 对比结果如下图所示BERT-Large模型在多个NLU任务上取得了显著的性能提升成为当时自然语言处理领域的明星模型引领了一波研究热潮。 以当年的眼光来看BERT绝对是一个更加优秀的模型。因为既然BERT和GPT两者都是采用「预训练微调」的范式并且下游任务依然是分类、匹配、序列标注等等「经典」的NLP任务形式那么像BERT模型这种更注重特征编码的质量下游任务选一个合适的损失函数去配合任务做微调显然比GPT这种以文本生成的方式去「迂回地」完成这些任务更加直接。如果当时OpenAI放弃生成式预训练这条路也许我们要等更长的时间才能见到ChatGPT这样的模型。 2.1 GPT-2核心思想 Q当模型被别人用更大的数据集、参数量(Bert)打败时应该怎么做 A自己也增大数据集和模型参数量。 Q但是当文本数据集增大模型参数量增大的基础上模型的优势没有那么高的情况下应该怎么办 A找到另一个卖点另辟蹊径——zero shot 如果这篇文章单纯讲结果比Bert好一些其实大家一看没啥意思太工程化了但是换一个角度做一个更难的问题但是得到一个好一点的结果文章新颖性一下子有了。做工程和做研究的区别就是做工程可以一直死盯着精度但是做研究需要另辟蹊径找到一个创新点。 来自《李沐GPT、GPT-2、GPT-3论文精读》 GPT-2的核心思想就是当模型的容量非常大且数据量足够丰富时仅仅靠语言模型的学习便可以完成其他有监督学习的任务不需要在下游任务微调。 GPT-2和GPT的区别在于GPT-2使用了更多的网络参数和更大的数据集以此来训练一个泛化能力更强的词向量模型。GPT-2相比于GPT有如下几点区别 主推zero-shot而GPT-1为pre-trainfine-tuning模型更大参数量达到了15亿个而GPT-1只有1.17亿个数据集更大WebText数据集包含了40GB的文本数据而GPT-1只有5GB 没有选择Common Crawl这种具有很多冗余无用信息的项目选用的是reddit里面已经被人工筛选出的有意义的并且具有至少3karma值的网页进行数据处理大概有800万个文本40GB的文字。 训练参数变化batch_size从64增加到 512上文窗口大小从512增加到1024 2.2 GPT-2模型结构 GPT-2 提供了四种规模的模型 在模型结构方面整个GPT-2的模型框架与GPT相同调整更多的是被当作训练时的trick而不作为GPT-2的创新具体为以下几点 后置层归一化(post-norm)改为前置层归一化(pre-norm)在模型最后一个自注意力层之后额外增加一个层归一化调整参数的初始化方式按残差层个数进行缩放缩放比例为 1 : sqrt(n)输入序列的最大长度从512扩充到1024 2.3 GPT-2的贡献 2.3.1 预训练和zero-shot GPT-2的预训练和GPT基本没什么区别但是对下游任务用了zero-shot。 GPT-2可以在zero-shot设定下实现下游任务即不需要用有标签的数据进行微调。 为了实现zero-shot下游任务的输入就不能像GPT那样在构造输入时加入开始、中间和结束的特殊字符这些是模型在预训练时没有见过的而是应该和预训练模型看到的文本一样更像一个自然语言。可以通过做prompt的方式来zero-shot。 例如在做句子翻译任务时训练的句子可以被写为 (translate to french, english text, french text). 其中translate to french在后文叫做prompt也叫做提示相当于做了一个特殊的提示词。如果要做阅读理解任务时可以写作(answer the question, document阅读的文本, question, answer)answer the question相当于任务提示 为何zero-shot这种方式是有效的呢?从一个尽可能大且多样化的数据集中一定能收集到不同领域不同任务相关的自然语言描述示例数据集里就存在展示了这些prompt示例所以训练出来就自然而然有一定zero-shot的能力了。
2.3.2 总结 GPT-2的最大贡献是验证了通过海量数据和大量参数训练出来的词向量模型有迁移到其它类别任务中而不需要额外的训练即zero-shot learning的能力。但是效果其实很一般。 GPT-2表明随着模型容量和数据量的增大其潜能还有进一步开发的空间基于这个思想促使了GPT3的出现。 GPT-2虽然提出zero-shot比Bert有新意但是有效性方面不佳。GPT-3考虑few-shot用少量文本提升有效性。
3 nanoGPT源码分析(GPT-2) nanoGPT是李飞飞教授的学生前特斯拉AI总监Andrej Karpathy基于OpenWebText重现 GPT-2 (124M)的开源项目。nanoGPT删繁就简代码非常简单cpu也可以跑。无论是从头开始训练新模型或者微调都能很容易满足需求。 GPT-2原理解释可参考https://jalammar.github.io/illustrated-gpt2/ nanoGPT源码仓库https://github.com/karpathy/nanoGPT 首先我们clone下整个仓库并按照仓库的Install的部分安装需要的package即可 如果我们想使用torch.compile的技术则需要安装2.x版本的PyTorch【torch.compile是PyTorch 2.x版本提出的一个新的技术可以有效降低我们训练模型的时间】
pip install torch numpy transformers datasets tiktoken wandb tqdmnanoGPT提供了两个案例 第一个案例是在shakespeare上的构建的字符级别character-level的GPT2。这个数据很小并且训练很快很适合理解原理。第二个就是根据原始论文在OpenWebText数据上重现GPT2但是这个需要在8块A100 40GB机器上训练4天。
3.1 GPT-2模型 3.1.1 LayerNorm import math import inspect from dataclasses import dataclassimport torch import torch.nn as nn from torch.nn import functional as Fclass LayerNorm(nn.Module): LayerNorm but with an optional bias. PyTorch doesnt support simply biasFalse def init(self, ndim, bias):super().init()self.weight nn.Parameter(torch.ones(ndim))self.bias nn.Parameter(torch.zeros(ndim)) if bias else Nonedef forward(self, input):return F.layer_norm(input, self.weight.shape, self.weight, self.bias, 1e-5)3.1.2 CausalSelfAttention class CausalSelfAttention(nn.Module):def init(self, config):super().init()assert config.n_embd % config.n_head 0# key, query, value projections for all heads, but in a batchself.c_attn nn.Linear(config.n_embd, 3 * config.n_embd, biasconfig.bias)# output projectionself.c_proj nn.Linear(config.n_embd, config.n_embd, biasconfig.bias)# regularizationself.attn_dropout nn.Dropout(config.dropout)self.resid_dropout nn.Dropout(config.dropout)self.n_head config.n_headself.n_embd config.n_embdself.dropout config.dropout# flash attention make GPU go brrrrr but support is only in PyTorch 2.0self.flash hasattr(torch.nn.functional, scaled_dot_product_attention)if not self.flash:print(WARNING: using slow attention. Flash Attention requires PyTorch 2.0)# causal mask to ensure that attention is only applied to the left in the input sequence# 目的使用下三角矩阵屏蔽未来词汇# torch.ones(config.block_size, config.block_size) 创建一个 block_size * block_size的矩阵# torch.tril() 将上三角元素设置为0下三角仍为1self.register_buffer(bias, torch.tril(torch.ones(config.block_size, config.block_size)).view(1, 1, config.block_size, config.block_size))def forward(self, x):B, T, C x.size() # batch size, sequence length, embedding dimensionality (n_embd)# calculate query, key, values for all heads in batch and move head forward to be the batch dimq, k, v self.c_attn(x).split(self.n_embd, dim2)# 多头注意力机制需要拆头k k.view(B, T, self.n_head, C // self.n_head).transpose(1, 2) # (B, nh, T, hs)q q.view(B, T, self.n_head, C // self.n_head).transpose(1, 2) # (B, nh, T, hs)v v.view(B, T, self.n_head, C // self.n_head).transpose(1, 2) # (B, nh, T, hs)# causal self-attention; Self-attend: (B, nh, T, hs) x (B, nh, hs, T) - (B, nh, T, T)if self.flash:# efficient attention using Flash Attention CUDA kernelsy torch.nn.functional.scaled_dot_product_attention(q, k, v, attn_maskNone, dropout_pself.dropout if self.training else 0, is_causalTrue)else:# manual implementation of attention# QK^T / sqrt(d_k)att (q k.transpose(-2, -1)) * (1.0 / math.sqrt(k.size(-1)))# 将矩阵的为0的地方填为-inf即上三角填充为-inf、屏蔽未来词汇att att.masked_fill(self.bias[:, :, :T, :T] 0, float(-inf))# 得到的softmax以后矩阵上三角部分的注意力权重 - 0att F.softmax(att, dim-1)# 如果提供了dropout对注意力权重att进行dropout操作att self.attn_dropout(att)# 对value进行加权求和y att v # (B, nh, T, T) x (B, nh, T, hs) - (B, nh, T, hs)# 维度转换y y.transpose(1, 2).contiguous().view(B, T, C) # re-assemble all head outputs side by side# output projectiony self.resid_dropout(self.c_proj(y))return y3.1.3 FFN class MLP(nn.Module):前馈神经网络FFNdef init(self, config):super().init()# 注意输出维度为n_embd的4倍self.c_fc nn.Linear(config.n_embd, 4 * config.n_embd, biasconfig.bias)self.gelu nn.GELU()self.c_proj nn.Linear(4 * config.n_embd, config.n_embd, biasconfig.bias)self.dropout nn.Dropout(config.dropout)def forward(self, x):x self.c_fc(x)x self.gelu(x)x self.c_proj(x)x self.dropout(x)return x3.1.4 组装Block 包含两个子层一个为Masked Multi-Head Attention一个为FFN后置层归一化(post-norm)改为前置层归一化(pre-norm) class Block(nn.Module):def init(self, config):super().init()self.ln_1 LayerNorm(config.n_embd, biasconfig.bias)self.attn CausalSelfAttention(config)self.ln_2 LayerNorm(config.n_embd, biasconfig.bias)self.mlp MLP(config)def forward(self, x):# 1、第一个子层# Sublayer(LayerNorm(x)) x其中Sublayer Masked Multi-Head Attentionx x self.attn(self.ln_1(x))# 2、第二个子层# Sublayer(LayerNorm(x)) x其中Sublayer FFNx x self.mlp(self.ln_2(x))return x3.1.5 封装GPT-2模型 这里主要看下初始化、forward函数、以及generate函数。当然作者还提供了从transformers库加载GPT2模型、配置优化器等函数可以自己看下。 这里作者把word embedding和lm_head权重进行共享减少了模型参数 c_proj的权重初始化按n_layer层数进行缩放
class GPT(nn.Module):def init(self, config):super().init()assert config.vocab_size is not Noneassert config.block_size is not Noneself.config configself.transformer nn.ModuleDict(dict(wte nn.Embedding(config.vocab_size, config.n_embd), # word table embeddingwpe nn.Embedding(config.block_size, config.n_embd), # word position embeddingdrop nn.Dropout(config.dropout),h nn.ModuleList([Block(config) for _ in range(config.n_layer)]),ln_f LayerNorm(config.n_embd, biasconfig.bias),))# 定义一个线性层将模型的输出维度映射到词汇表大小self.lm_head nn.Linear(config.n_embd, config.vocab_size, biasFalse)# with weight tying when using torch.compile() some warnings get generated:# UserWarning: functional_call was passed multiple values for tied weights.# This behavior is deprecated and will be an error in future versions# not 100% sure what this is, so far seems to be harmless. TODO investigate# word embedding和lm_head权重共享self.transformer.wte.weight self.lm_head.weight # https://paperswithcode.com/method/weight-tying# init all weightsself.apply(self._init_weights)# apply special scaled init to the residual projections, per GPT-2 paperfor pn, p in self.named_parameters():if pn.endswith(c_proj.weight):# 初始化方式按nlayer层数进行缩放torch.nn.init.normal(p, mean0.0, std0.02/math.sqrt(2 * config.n_layer))# report number of parameters(参数共享后的参数量)print(number of parameters: %.2fM % (self.get_num_params()/1e6,))在模型最后一个自注意力层之后额外增加一个层归一化推理时只用最后一个时刻的hidden state去预测logits ……def forward(self, idx, targetsNone):device idx.deviceb, t idx.size()assert t self.config.block_size, fCannot forward sequence of length {t}, block size is only {self.config.block_size}pos torch.arange(0, t, dtypetorch.long, devicedevice) # shape (t)# forward the GPT model itselftok_emb self.transformer.wte(idx) # token embeddings of shape (b, t, n_embd)pos_emb self.transformer.wpe(pos) # position embeddings of shape (t, n_embd)x self.transformer.drop(tok_emb pos_emb)for block in self.transformer.h:x block(x)# 在模型最后一个自注意力层之后额外增加一个层归一化x self.transformer.ln_f(x)if targets is not None:# if we are given some desired targets also calculate the losslogits self.lm_head(x)loss F.cross_entropy(logits.view(-1, logits.size(-1)), targets.view(-1), ignore_index-1)else:# inference-time mini-optimization: only forward the lm_head on the very last position# 小优化: 只用最后一个时刻的hidden state去预测logitslogits self.lm_head(x[:, [-1], :]) # note: using list [-1] to preserve the time dimloss Nonereturn logits, loss推理过程中如果上下文长度大于block_size(1024)就裁剪到block_size长度再输入到模型中推理temperature的是作用在logits上通过temperature的大小来调整模型输出概率分布的尖锐程度。 当temperature值较高大于1时将使得概率分布变得更加均匀模型的预测结果将更加多样化但可能不太准确。换句话说模型会有更大的概率去尝试预测不太可能的结果。相反当temperature值较低小于1时将使得概率分布变得更加尖锐模型的预测结果将更加聚焦于最有可能的结果但可能牺牲多样性。换句话说模型会更倾向于预测最可能的结果。 top_k在这段代码中的作用就是在生成预测结果后只保留得分最高的前k个选项以减少计算量并且可能提高模型的生成质量。 ……torch.no_grad()def generate(self, idx, max_new_tokens, temperature1.0, top_kNone):Take a conditioning sequence of indices idx (LongTensor of shape (b,t)) and completethe sequence max_new_tokens times, feeding the predictions back into the model each time.Most likely youll want to make sure to be in model.eval() mode of operation for this.for _ in range(max_new_tokens):# if the sequence context is growing too long we must crop it at block_size# 如果上下文长度大于block_size就裁剪到block_size长度再输入到模型中推理idx_cond idx if idx.size(1) self.config.block_size else idx[:, -self.config.block_size:]# forward the model to get the logits for the index in the sequencelogits, _ self(idx_cond)# pluck the logits at the final step and scale by desired temperaturetemperature的是作用在logits上通过temperature的大小来调整模型输出概率分布的尖锐程度。当temperature值较高大于1时将使得概率分布变得更加均匀模型的预测结果将更加多样化但可能不太准确。换句话说模型会有更大的概率去尝试预测不太可能的结果。相反当temperature值较低小于1时将使得概率分布变得更加尖锐模型的预测结果将更加聚焦于最有可能的结果但可能牺牲多样性。换句话说模型会更倾向于预测最可能的结果。logits logits[:, -1, :] / temperature# optionally crop the logits to only the top k optionstop_k在这段代码中的作用就是在生成预测结果后只保留得分最高的前k个选项以减少计算量并且可能提高模型的生成质量。if top_k is not None:# 取概率最大的topk个v, _ torch.topk(logits, min(top_k, logits.size(-1)))# 取topk个概率中最小的值如果小于此值就将概率置为负无穷这样softmax后就趋近于0logits[logits v[:, [-1]]] -float(Inf)# apply softmax to convert logits to (normalized) probabilitiesprobs F.softmax(logits, dim-1)# sample from the distribution# 函数作用是从模型输出的概率中采样num_samples是采样次数idx_next torch.multinomial(probs, num_samples1)# append sampled index to the running sequence and continue# 在得到idx_next后我们会将它和idx合在一起去预测新的下一个idxidx torch.cat((idx, idx_next), dim1)return idx3.2 数据集的准备 我们运行下面的代码就可以下载Shakespeare数据集并且将数据分为训练集和验证集。 python data/shakespeare_char/prepare.py执行这个命令后命令行会输出下面的内容 length of dataset in characters: 1115394 # 统计所有数据有多少个字母 all the unique characters: !$,-.3:;?ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz # 统计有哪些字母和符号 vocab size: 65 # 构建vocabulary即就是上面的这些符号 train has 1003854 tokens val has 111540 tokens运行完后我们也会得到train.bin和val.bin。这两个.bin文件其实就是将对应字母/符号映射到vocabulary后的序号存储而形成的。train.bin包含了100w个tokenval.bin包括10w个token。 因为我们训练的是character-level的GPT所以我们的vocabulary就是26个英文字母的大小写和一些特殊符号组成vocabulary的大小是65。运行完后会将vocabulary信息vocab_size、itos(id2token)、stoi(token2id)封装为dict保存到meta.pkl文件中。 具体可以看data/shakespeare_char/prepare.py源码。
3.3 模型训练过程 其中如果pytorch版本2.0在训练时需要指定compile为False 如果没有GPU但是又想训练尝试下的话需要设置device为cpu train.py一共只有300多行代码写的通俗易懂支持多卡训练混合精度训练断点训练梯度积累动态学习率变化wandb记录log具体可以看源码。
这里主要介绍下DDP分布式训练的相关概念 rank 进程号在多进程上下文中我们通常假定rank 0是第一个进程或者主进程其它进程分别具有123不同rank号这样总共具有4个进程 node 物理节点可以是一个容器也可以是一台机器节点内部可以有多个GPUnnodes指物理节点数量nproc_per_node指每个物理节点上面进程的数量 local_rank 指在一个node上进程的相对序号local_rank在node之间相互独立这里需要注意的是在torch.distributed.launch中local_rank是隐式参数即torch自动分配的。local_rank可以通过自动注入命令行参数来获得 。torch1.10开始官方建议使用环境变量的方式来获取local_rank。用终端命令torchrun来代替torch.distributed.launchlocal_rank不再支持用命令行隐式传递的方式完全使用环境变量配置各类参数。 world_size 全局进程总个数即在一个分布式任务中rank的数量 group 进程组一个分布式任务对应了一个进程组。只有用户需要创立多个进程组时才会用到group来管理默认情况下只有一个group
如下图所示共有3个节点(node)每个节点上有4个GPU每台机器上起4个进程每个进程占一块GPU那么图中一共有12个rank(world_size)nproc_per_node4nnodes3每个节点都一个对应的node_rank。 backend 通信后端可选的包括ncclNVIDIA推出、glooFacebook推出、mpiOpenMPI。一般建议GPU训练选择ncclCPU训练选择gloo master_addr与master_port 主节点的地址以及端口供init_method 的tcp方式使用。因为pytorch中网络通信建立是从机去连接主机运行ddp只需要指定主节点的IP与端口其它节点的IP不需要填写。这个两个参数可以通过环境变量或者init_method传入

方式1

os.environ[MASTER_ADDR] localhost os.environ[MASTER_PORT] 12345 dist.init_process_group(“nccl”, rankrank, world_sizeworld_size)# 方式2 dist.init_process_group(“nccl”,init_method“tcp://localhost:12345”,rankrank,world_sizeworld_size)使用DDP分布式训练的话主要包含下面步骤 初始化进程组 dist.init_process_group设置分布式采样器 DistributedSampler使用DistributedDataParallel封装模型使用torchrun 或者 mp.spawn 启动分布式训练 需要注意的点 模型保存的时候注意调用model.module.state_dict()加载模型的时候需要利用map_location参数指定加载的设备。有了sampler在DataLoader中不需要shuffle在每个训练周期开始处调用sampler.set_epoch(epoch)使得数据充分打乱 DDP代码实战可以参考 Pytorch DDP分布式训练介绍