FairScale 库测试实验(一)-- 大模型训练基础之模型并行

news2024/9/23 19:23:07

DDP的分布式训练方法采用数据并行方式,相当于通过增大数据的batch来加快训练。但对于大模型(LLM)来说,DDP已经不适用了。因为LLMs的模型本身太大,一块GPU都放不下怎么可能去复制从而实现数据并行呢。所以LLM的训练采用模型并行的方式来训练。

FairScale 是一个用于高性能和大规模训练的 PyTorch 扩展库。该库扩展了基本的 PyTorch 功能,同时添加了新的 SOTA 扩展技术。FairScale 以可组合模块和易于使用的 API 的形式提供最新的分布式训练技术。这些 API 是研究人员工具箱的基本组成部分,因为他们试图用有限的资源扩展模型。(来源官网)

本次熟悉一下其常用的设置。

目录

一、预先准备

二、使用 PIPELINE PARALLEL 进行模型分片

1、官网的教程 

2、实际应用举例

3、模型分片后,数据前向传播流程分析

总结


一、预先准备

随便准备一个模型作为例子。以下面模型为例(可以运行),简单的分类任务。

import torch
import torch.nn as nn

import random
import torchvision.datasets as data
import torchvision.transforms as transforms
import torch.optim as optim


class Classifier(nn.Module):
    def __init__(self):
        super(Classifier, self).__init__()
        self.features = nn.Sequential(
            nn.Conv2d(in_channels=3,out_channels=32, kernel_size=4,stride=2, padding=1),
            nn.ReLU(),
            nn.MaxPool2d((2,2),1),
            nn.Conv2d(in_channels=32,out_channels=64, kernel_size=3, stride=2, padding=1),
            nn.ReLU(),
            nn.MaxPool2d((2,2),1),
            nn.Conv2d(64, 128, 2, 2,1),
            nn.ReLU(),
            nn.MaxPool2d((2,2),1)
        )
        #
        self.classifier = nn.Sequential(

            nn.Linear(3*3*128,4096),
            nn.ReLU(),

            nn.Dropout(p=0.5),
            nn.Linear(4096,2048),
            nn.ReLU(),

            nn.Linear(2048,1024),
            nn.ReLU()
        )
        self.last_layer_input = nn.Sequential(nn.Linear(1024,10),
            nn.Softmax())

    def forward(self, x):
        x = self.features(x)
        x = torch.flatten(x, 1)
        x = self.classifier(x)
        x = self.last_layer_input(x)

        return x

if __name__ == '__main__':

    batchSize = 50
    nepoch = 45

    print("Random Seed: 88")
    random.seed(88)
    torch.manual_seed(88)
    device = 'cuda' if torch.cuda.is_available() else 'cpu'

    dataset = data.CIFAR10(root='/root/data/zjx/Datasets/cifar10',  # 这个路径自己改
                         train=True,
                         transform=transforms.Compose([transforms.ToTensor()]),
                         download=True
                         )

    dataloader = torch.utils.data.DataLoader(dataset,
                                             batch_size=batchSize,
                                             shuffle=True)

    Model = Classifier().to(device)
    Cross_entropy = nn.BCELoss().to(device)
    Optimizer = optim.Adam(Model.parameters(), lr=0.00001)

    for epoch in range(nepoch):
        for i, (data, label) in enumerate(dataloader, 0):
            data = data.to(device)
            label_onehot = torch.zeros((data.shape[0], 10)).to(device)
            label_onehot[torch.arange(data.shape[0]), label] = 1
            output = Model(data)
            loss = Cross_entropy(output, label_onehot)
            print('{}/{}: Loss is {}'.format(i, epoch, loss.data))
            Model.zero_grad()
            loss.backward()
            Optimizer.step()

二、使用 PIPELINE PARALLEL 进行模型分片

1、官网的教程 

官网的示例看这里,主要关键点包括切片的语法设置,以及设备对齐。

模型切片的要求格式

import fairscale
import torch
import torch.nn as nn

model = nn.Sequential(
            torch.nn.Linear(10, 10),
            torch.nn.ReLU(),
            torch.nn.Linear(10, 5)
        )

model = fairscale.nn.Pipe(model, balance=[2, 1])

可以看到要求必须 torch.nn.Sequential 格式。上述前两层放到cuda:0, 后一层放到cuda:1上。但是这里有个问题。如果我们自定义的模型不全是nn.Sequential的格式,那么它还能这样实现吗?

以 一中预准备的模型为例,它并不全是nn.Sequential的格式,而是分成了三个部分,前向传播过程中有一步拉直操作。(当然,一中例子也可以转换成全是nn.Sequntial的格式,拉直可以用nn.Flatten()来实现)这样的话使用这个设置还可以吗?来试一下


Model = Classifier().to(device)
# 在上面语句的下面添加
Model = fairscale.nn.Pipe(Model, balance=[6, 6, 6])

# 运行报错
TypeError: module must be nn.Sequential to be partitioned

显然,这样不行。报出错误:必须是nn.Sequential类型的。这样行不通,必须另想办法。

2、实际应用举例

当整个模型不是连续的nn.Sequential类型时,而是分成几部分单独定义时,我们可以把每部分分别分片放到不同的GPU上。这个过程可以在模型定义的时候在其内部实现。

以一中模型为例,将 模型中的 self.features 分片,放到三块GPU上。


self.features = nn.Sequential(
            nn.Conv2d(in_channels=3,out_channels=32, kernel_size=4,stride=2, padding=1),
            nn.ReLU(),
            nn.MaxPool2d((2,2),1),
            nn.Conv2d(in_channels=32,out_channels=64, kernel_size=3, stride=2, padding=1),
            nn.ReLU(),
            nn.MaxPool2d((2,2),1),
            nn.Conv2d(64, 128, 2, 2,1),
            nn.ReLU(),
            nn.MaxPool2d((2,2),1)
        )
# 在上面语句的下面添加
self.features = fairscale.nn.Pipe(self.features, balance=[3, 3, 3])

注意 ,我这里是根据我实际情况划分的,我采用的是三块GPU,一共9层,三等分了,你们按实际自行改动。下面的实例也是都用的三块GPU的基础上进行的

这样简单的设置,来执行一下看看行不行得通。

# 运行报错

RuntimeError: Expected all tensors to be on the same device, but found at least two devices, cuda:1 and cuda:0! (when checking argument for argument weight in method wrapper__cudnn_convolution)

报错了。因为官网中还有另一个关键的设备对其没有设置。所以,必须在整个过程中进行一下设备对齐,才能顺利运行。

首先,在定义模型时先不把模型放到 cuda上, 而是在模型内部去实现这一步。

# 将
Model = Classifier().to(device)

# 改为
Model = Classifier()

然后


self.features = fairscale.nn.Pipe(self.features, balance=[3, 3, 3])
# 在上面语句的下面添加
self.device = self.features.devices[0]

self.classifier = nn.Sequential(

            nn.Linear(3*3*128,4096),
            nn.ReLU(),

            nn.Dropout(p=0.5),
            nn.Linear(4096,2048),
            nn.ReLU(),

            nn.Linear(2048,1024),
            nn.ReLU()
        )
# 在上面的语句下面添加
self.classifier.to(self.device)
self.last_layer_input = nn.Sequential(nn.Linear(1024, 10),
            nn.Softmax())
# 在上面的语句下面添加
self.last_layer_input.to(self.device)
x = torch.flatten(x, 1)
# 在上面语句的下面添加
x = x.to(self.device)

这样就可以运行了。我们来看一下不同GPU显存占用的变化

模型未分片,只用一个GPU时

(base) root@3eaab89e2baa:~/data# nvidia-smi
Sat Mar  9 04:15:26 2024       
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 510.47.03    Driver Version: 510.47.03    CUDA Version: 11.6     |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|                               |                      |               MIG M. |
|===============================+======================+======================|
|   0  NVIDIA GeForce ...  On   | 00000000:04:00.0 Off |                  N/A |
| 22%   33C    P2    71W / 250W |   1522MiB / 11264MiB |     31%      Default |
|                               |                      |                  N/A |
+-------------------------------+----------------------+----------------------+
|   1  NVIDIA GeForce ...  On   | 00000000:05:00.0 Off |                  N/A |
| 22%   27C    P8     3W / 250W |      3MiB / 11264MiB |      0%      Default |
|                               |                      |                  N/A |
+-------------------------------+----------------------+----------------------+
|   2  NVIDIA GeForce ...  On   | 00000000:09:00.0 Off |                  N/A |
| 22%   32C    P8     2W / 250W |      3MiB / 11264MiB |      0%      Default |
|                               |                      |                  N/A |
+-------------------------------+----------------------+----------------------+
                                                                               
+-----------------------------------------------------------------------------+
| Processes:                                                                  |
|  GPU   GI   CI        PID   Type   Process name                  GPU Memory |
|        ID   ID                                                   Usage      |
|=============================================================================|
|    0   N/A  N/A     28350      C                                    1519MiB |
+-----------------------------------------------------------------------------+

模型分片时的情况

(base) root@3eaab89e2baa:~/data# nvidia-smi
Sat Mar  9 04:17:00 2024       
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 510.47.03    Driver Version: 510.47.03    CUDA Version: 11.6     |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|                               |                      |               MIG M. |
|===============================+======================+======================|
|   0  NVIDIA GeForce ...  On   | 00000000:04:00.0 Off |                  N/A |
| 22%   34C    P2    66W / 250W |   1546MiB / 11264MiB |     22%      Default |
|                               |                      |                  N/A |
+-------------------------------+----------------------+----------------------+
|   1  NVIDIA GeForce ...  On   | 00000000:05:00.0 Off |                  N/A |
| 22%   30C    P2    52W / 250W |   1210MiB / 11264MiB |      3%      Default |
|                               |                      |                  N/A |
+-------------------------------+----------------------+----------------------+
|   2  NVIDIA GeForce ...  On   | 00000000:09:00.0 Off |                  N/A |
| 22%   35C    P2    47W / 250W |   1190MiB / 11264MiB |      2%      Default |
|                               |                      |                  N/A |
+-------------------------------+----------------------+----------------------+
                                                                               
+-----------------------------------------------------------------------------+
| Processes:                                                                  |
|  GPU   GI   CI        PID   Type   Process name                  GPU Memory |
|        ID   ID                                                   Usage      |
|=============================================================================|
|    0   N/A  N/A     29306      C                                    1543MiB |
|    1   N/A  N/A     29306      C                                    1207MiB |
|    2   N/A  N/A     29306      C                                    1187MiB |
+-----------------------------------------------------------------------------+

可以看到其中的区别。未分片时只有一个GPU内存被占用,分片时三个GPU显存被占用。至于占用的大小并不是1+1=2的关系,因为其中不仅仅只是模型的参数被划分,在训练过程中还有其它参数的内存占用,比如中间过程生成的特征参数,计算保留的梯度参数等等。这里自行体会。

3、模型分片后,数据前向传播流程分析

debug,发现

模型被分片后,其被分到了三个设备上,具体的体现就是图中的devices包含三个cuda:1,2,3。 

在对其设备时,数据被放到了 cuda:0 上。所以,在送入 self.features 这个被分片的模型之前,数据的状态如下

当数据在分片的模型 self.features 前向流程走完后,发现

其在 cuda:2 设备上进行了输出。!!所以整个流程如下图所示

因此,模型分片的时候必须要对齐设备,所以,2中的例子才会有那老些的对齐设备步骤。

至此,整个过程以及需要注意的事项已经有了大概的了解,有了一定的视野。接下来,我们将会把一中的例子中的 self.classifier在之前的基础上也进行模型分片。有了上面的视图,这实现起来经不会太难。

具体地,在之前地基础上进行修改

self.classifier = nn.Sequential(

            nn.Linear(3*3*128,4096),
            nn.ReLU(),

            nn.Dropout(p=0.5),
            nn.Linear(4096,2048),
            nn.ReLU(),

            nn.Linear(2048,1024),
            nn.ReLU()
        )
# 在上面的语句下面添加
self.classifier = fairscale.nn.Pipe(self.classifier, balance=[2, 3, 2])
# 注释掉下面语句

# self.classifier.to(self.device)

注释掉是为了对齐进行模型分片后 ,模型会放到不同的设备上,如果再放到cuda:0上造成矛盾,从而出错。记住,模型分片后的设备cuda是个list,被放到了好几个cuda上。

x = self.classifier(x)
# 在上面的语句下面添加
x = x.to(self.device)

对齐设备,从之前的图中看到,x回在cuda:2上输出,所以必须把它放到cuda:0上才能进行下一步 

查看GPU显存占用情况

(base) root@3eaab89e2baa:~/data# nvidia-smi
Sat Mar  9 04:49:19 2024       
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 510.47.03    Driver Version: 510.47.03    CUDA Version: 11.6     |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|                               |                      |               MIG M. |
|===============================+======================+======================|
|   0  NVIDIA GeForce ...  On   | 00000000:04:00.0 Off |                  N/A |
| 22%   34C    P2    57W / 250W |   1326MiB / 11264MiB |     11%      Default |
|                               |                      |                  N/A |
+-------------------------------+----------------------+----------------------+
|   1  NVIDIA GeForce ...  On   | 00000000:05:00.0 Off |                  N/A |
| 22%   31C    P2    58W / 250W |   1420MiB / 11264MiB |     13%      Default |
|                               |                      |                  N/A |
+-------------------------------+----------------------+----------------------+
|   2  NVIDIA GeForce ...  On   | 00000000:09:00.0 Off |                  N/A |
| 22%   36C    P2    49W / 250W |   1250MiB / 11264MiB |      5%      Default |
|                               |                      |                  N/A |
+-------------------------------+----------------------+----------------------+
                                                                               
+-----------------------------------------------------------------------------+
| Processes:                                                                  |
|  GPU   GI   CI        PID   Type   Process name                  GPU Memory |
|        ID   ID                                                   Usage      |
|=============================================================================|
|    0   N/A  N/A     13027      C                                    1323MiB |
|    1   N/A  N/A     13027      C                                    1417MiB |
|    2   N/A  N/A     13027      C                                    1247MiB |
+-----------------------------------------------------------------------------+

明显比之前的大了。

总结

到这里,通过一步步的简单的实践对模型的分片有了一定的了解。知道了怎么去实现模型分片。接下来会继续探索其中的奥秘, 望诸君共勉!嘿嘿嘿

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1502696.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Ansible常用模块详解

Ansible常用模块详解一、Ansible简介1、Ansible是什么?2、Ansible是怎么工作的?3、Ansible的特性 二、Ansible 环境安装部署三、Ansible 命令行模块1、command 模块2、shell 模块3、cron 模块4、user 模块5、group 模块6、copy 模块7、file 模块8、hostn…

阿里云服务器没有国外地域吗?

阿里云地域没有国外节点?有,阿里云服务器国外地域美国、日本、新加坡、韩国、英国及德国等,阿里云服务器地域遍布全球,共29个地域可选。如果您在购买阿里云服务器时,没有国外地域可选,那是因为活动上提供的…

基于SSM框架的婚庆平台设计与实现

目 录 摘 要 I Abstract II 引 言 1 1相关技术 3 1.1 SSM框架简介 3 1.2 MySQL数据库简介 3 1.3 MVC设计模式简介 3 1.4 本章小结 4 2系统分析 5 2.1功能需求 5 2.1.1 用户功能需求 5 2.1.2 管理员功能需求 6 2.2非功能需求 10 2.3本章小结 10 3系统设计 11 3.1总体设计 11 3.…

spark 实验二 RDD编程初级实践

目录 一. pyspark交互式编程示例(学生选课成绩统计) 该系总共有多少学生; 该系DataBase课程共有多少人选修; 各门课程的平均分是多少; 使用累加器计算共有多少人选了DataBase这门课。 二.编写独立应用程序实现数…

java Spring boot简述jetcache 并叙述后续文章安排

我们之前 讲了 Spring boot 整合 cache 使用 simple(默认) redis Ehcache memcached的几种方式 但是 始终有人觉得不够完善 提出了一些问题 例如 觉得 当前spring boot 对缓存过期的控制过于松散 不严谨 比较明显的体现就是 memcached过期时间在逻辑代码中控制 Ehcache的过期时…

spring boot 集成 mysql ,mybatisplus多数据源

1、需要的依赖&#xff0c;版本自行控制 <dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId> </dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java<…

神经网络 梯度与神经元参数w、b关系;梯度与导数关系

参考&#xff1a;https://blog.csdn.net/weixin_44259490/article/details/90295146 概念 梯度与w的关系可以用梯度下降公式来表示&#xff1a;ww−α ∂ c o s t ∂ w \frac{\partial cost}{\partial w} ∂w∂cost​&#xff0c;其中w表示网络的权重&#xff0c; ∂ c o s t…

练习3-softmax分类(李沐函数简要解析)与d2l.train_ch3缺失的简单解决方式

环境为:练习1的环境 网址为:https://www.bilibili.com/video/BV1K64y1Q7wu/?spm_id_from333.1007.top_right_bar_window_history.content.click 代码简要解析 导入模块 导入PyTorch 导入Torch中的nn模块 导入d2l中torch模块 并命名为d2l import torch from torch import nn…

实现鼠标移动el-select下拉框的label上面显示出table悬浮窗

首先是对vue代码 实现思路就是在el-option里面放一个span来包裹el-popover&#xff0c;里面在放tabe实现悬浮表格 <el-form-item label"原理图编号"><el-select v-model"data.number" placeholder"请选择" clearable multiple collaps…

C语言第三十七弹---文件操作(下)

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】 文件操作 1、文件的随机读写 1.1、fseek 1.2、ftell 1.3、rewind 2、文件读取结束的判定 2.1、被错误使用的 feof 3、文件缓冲区 总结 1、文件的随机读写…

阿里云主机地域怎么选择?哪个好?

阿里云服务器地域选择方法&#xff0c;如何选择速度更快、网络延迟更低的地域节点&#xff0c;地域指云服务器所在的地理位置区域&#xff0c;地域以城市划分&#xff0c;如北京、杭州、深圳及上海等&#xff0c;如何选择地域&#xff1f;建议根据用户所在地区就近选择地域&…

同等学力申硕专业介绍——管理学硕士

同等学力申硕的专业很多。 目前有十三大门类&#xff0c;分别是医学、法学、管理学、工学、教育学、经济学、艺术学、文学、历史学、理学、哲学、农学、军事学等&#xff0c;每个大门类中都有很多的细分专业。 今天为大家介绍同等学力申硕专业——管理学。 专业介绍 管理学是…

Java后端核心——Servlet

目录 一.概述 二.基础实现 1.导入坐标 2.定义实现类 3.注解 4.访问Servlet 三.执行流程 四.生命周期 1.加载和实例化 2.初始化 3.请求处理 4.服务终止 五.方法 1.init 2.service 3.destroy 4.getServletInfo 5.getServletConfig 六.体系结构 七.urlPatter…

Spring Boot中Excel数据导入导出的高效实现

&#x1f31f; 前言 欢迎来到我的技术小宇宙&#xff01;&#x1f30c; 这里不仅是我记录技术点滴的后花园&#xff0c;也是我分享学习心得和项目经验的乐园。&#x1f4da; 无论你是技术小白还是资深大牛&#xff0c;这里总有一些内容能触动你的好奇心。&#x1f50d; &#x…

能量不等式证明

波动方程初值问题能量不等式的证明 Gronwall 不等式 若非负函数 G ( τ ) G(\tau) G(τ) 在 [ 0 , T ] [0,T] [0,T] 上连续可微&#xff0c; G ( 0 ) 0 G(0)0 G(0)0&#xff0c;且对 τ ∈ [ 0 , T ] \tau\in[0,T] τ∈[0,T]满足 d G ( τ ) d τ ≤ C G ( τ ) F ( τ …

Using WebView from more than one process

关于作者&#xff1a;CSDN内容合伙人、技术专家&#xff0c; 从零开始做日活千万级APP。 专注于分享各领域原创系列文章 &#xff0c;擅长java后端、移动开发、商业变现、人工智能等&#xff0c;希望大家多多支持。 未经允许不得转载 目录 一、导读二、概览三、问题过程源码追踪…

Mamba-minimal Mamba的最小限度实现 (一)

文章目录 参数和数据尺寸约定class MambaBlockdef forwarddef __ int__def ssmdef selective_scan johnma2006/mamba-minimal: Simple, minimal implementation of the Mamba SSM in one file of PyTorch. (github.com) manba的简单最小限度实现&#xff0c;和原始论文实现stat…

深入了解Kafka中生产者的神奇力量

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 深入了解Kafka中生产者的神奇力量 前言生产者的基本概念Kafka 生产者的定义&#xff1a;Kafka 生产者的基本原理&#xff1a;为何生产者是 Kafka 消息传递的创造者&#xff1a; 生产者的创建于配置生产…

新版AndroidStudio的Gradle窗口显示task list not built 问题解决

在使用新版AndroidStudio时&#xff0c;会出现&#xff0c;Task List not built 的问题。如果你记得task的名字&#xff0c;当然可以 直接通过命令 gradle taskname 或者 ./gradlew taskName直接执行即可&#xff0c;但是若是记不住&#xff0c;还是把这个任务构建处理比较好用…

智慧文旅|AI数字人导览:让旅游体验不再局限于传统

AI数字人导览作为一种创新的展示方式&#xff0c;已经逐渐成为了VR全景领域的一大亮点&#xff0c;不仅可以很好的嵌入在VR全景中&#xff0c;更是能够随时随地为观众提供一种声情并茂的讲解介绍&#xff0c;结合VR场景的沉浸式体验&#xff0c;让观众仿佛置身于真实场景之中&a…