前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >深度学习框架OneFlow的并行特色(附框架源码和教程)

深度学习框架OneFlow的并行特色(附框架源码和教程)

作者头像
计算机视觉研究院
发布于 2020-08-12 07:53:20
发布于 2020-08-12 07:53:20
1K00
代码可运行
举报
运行总次数:0
代码可运行

作者:Edison_G

OneFlow 是什么? OneFlow是开源的、采用全新架构设计,世界领先的工业级通用深度学习框架

1、背景

在之前,“计算机视觉研究院”已经详细分享了OneFlow深度学习框架基础结构以及分析了分布式子训练的特点,今天我们就简单说说OneFlow的并行特色。

在Consistent 与 Mirrored 视角中,我们已经知道 OneFlow 提供了 mirrored 与 consistent 两种看待分布式系统的视角,并且提前了解了 OneFlow 的 consistent 视角颇具特色。

因为在 consistent_view 下,OneFlow 提供了逻辑上统一的视角,分布式训练时,用户可以自由选择数据并行、模型并行还是是混合并行。

在本文中,继续深入介绍 OneFlow 独具特色的 consistent 视角,包括:

  • OneFlow在consistent_view下纯数据并行流程示意
  • OneFlow在consistent_view下混合并行流程示意
  • 混合并行的优势及适用场景
  • OneFlow混合并行实例

2、网络模型训练的逻辑图

我们先设定一个简单的多层网络,作为我们我们讨论并行方式的载体,其结构如下图所示:

各层中,有 样本 (灰色矩形)、 模型 (蓝色矩形),以及作用在两者之上的 op (圆形),为了简化讨论,我们也可将样本与模型限定为 矩阵 ,作用在它们之上的op为 矩阵乘法 。

对照上图,我们很容易梳理出该网络模型的逻辑:

  • 第0层的输入为 Data 0 矩阵与 Model 0 矩阵,它们进行 op (矩阵乘法)运算后,输出 Data 1
  • 第1层的输入为 Data 1 矩阵与 Model 1 矩阵,它们进行 op 运算后,输出 output
  • 第2层为 output 层,Data 2 作为整个网络的输出;当然,在更深的网络中,它也可以作为下一层的输入继续参与训练

consistent 视角下支持数据并行、模型并行与混合并行,我们将依次进行介绍,其中混合并行是重点。

3、Consistent 视角下的并行特色

纯数据并行

我们已经知道,consistent 视角下,默认的并行方式是数据并行;而如果选择 mirrored 视角,则只能采用数据并行;若在调用作业函数时直接传递 numpy 数据(而不是使用 OneFlow 的 flow.data.xxx_reader 接口进行数据加载),两者的区别在于:

  • mirrored 视角下,采用纯数据并行,需要自己根据参与训练的卡数对数据进行切分、重组,使用 list 传递和接收数据;
  • 而 consistent 视角下提供了逻辑上的统一看待,数据的切分和重组交给了OneFlow 框架完成。

下图是 consistent 视角下,采用纯数据并行的方式,实现原逻辑网络模型的流程示意图:

在纯数据并行中,采用了2张显卡进行并行训练,因为采用了 纯数据并行 ,可以看到,对于原逻辑模型中的每一层,样本数据都被平均分配到了各个卡上,每张卡上都拥有 完整的模型,与切分的数据进行 op 运算,最后组合各个卡上的样本,得到完整的输出。

纯模型并行

在 consistent 视角下,也可以通过选择纯模型并行(设置方式在下文实例中会介绍),其流程示意图为:

在纯模型并行中,同样是2张显卡进行并行训练,原逻辑模型中的每一层中,都是 部分模型 与 完整的数据 进行 op 运算,最后组合得到完整的输出。

值得一提的是,从上图可以看出,各个卡上第0层的输出,并 不能 直接作为第1层的输入:因为模型并行中,为完成 op 操作,需要部分的模型与 完整的 数据;为了解决这个问题,OneFlow 中使用了 boxing 机制。

boxing 机制会统筹分布式训练中各个节点的数据,并合理切分、合并到对应的卡上,除了模型并行过程中的数据重组问题外,数据并行中的反向梯度同步,也使用 boxing 机制解决。

boxing 的内部机制虽然复杂,但是对于用户而言是透明的,我们仅仅是防止读者产生迷惑才加入了 boxing 的图示,对于本文而言,我们只需要了解:OneFlow 会自动协调好分布式中数据的同步问题。

4、选择最优的并行方式

数据并行与模型并行的优劣并不是一成不变的,样本规模、模型规模及模型结构决定了分布式训练中的综合表现,需要具体情况具体分析。

概括而言:

  • 数据并行情况下,需要同步的信息是反向传播过程的 梯度,因此应该确保各个训练节点之间的信息同步速度要比节点内部的计算速度快,比如说 卷积层 的参数较少,但是计算量大,就比较适合使用数据并行;
  • 模型并行情况下,因为可以将逻辑上作为整体的模型 切分到各个物理卡 上,能够解决“模型太大,一张卡装不下”的问题,因此,对于参数量大的神经网络层(如最后的全连接层),可以考虑使用模型并行。

实际上,也可以使用 混合并行,在同一个分布式训练的不同部分,组合使用数据并行、模型并行。比如,对于神经网络中靠前的参数较少、计算量大的层,采用数据并行;在最终的参数众多的全连接层,则采用模型并行,以下是针对本文最开始的网络模型逻辑图的 混合并行 实现方案的示意图:

目前,其它的主流框架对于混合并行或者不支持,或者需要深度定制,而OneFlow 中可以通过简单的设置,配置混合并行的分布式训练,还可以用自由度超高的“网络接力”的并行模式,深度优化分布式系统。

5、混合并行实例

代码示例

以下,在 consistent 视角下,我们对 MLP 模型采用了混合并行方案:输入层与隐藏层采用(默认的)数据并行;输出层采用模型并行并进行列切分。

完整代码:mixed_parallel_mlp.py

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# mixed_parallel_mlp.py
import oneflow as flow
import oneflow.typing as tp

BATCH_SIZE = 100

def mlp(data):
    initializer = flow.truncated_normal(0.1)
    reshape = flow.reshape(data, [data.shape[0], -1])
    hidden = flow.layers.dense(
        reshape,
        512,
        activation=flow.nn.relu,
        kernel_initializer=initializer,
        name="dense1",
    )
    return flow.layers.dense(
        hidden,
        10,
        kernel_initializer=initializer,
        # dense涓哄垪瀛樺偍锛岃繘琛宻plit(0)鍒囧垎
        model_distribute=flow.distribute.split(axis=0),
        name="dense2",
    )


def get_train_config():
    config = flow.function_config()
    config.default_data_type(flow.float)
    return config


@flow.global_function(type="train", function_config=get_train_config())
def train_job(
    images: tp.Numpy.Placeholder((BATCH_SIZE, 1, 28, 28), dtype=flow.float),
    labels: tp.Numpy.Placeholder((BATCH_SIZE,), dtype=flow.int32),
) -> tp.Numpy:
    logits = mlp(images)
    loss = flow.nn.sparse_softmax_cross_entropy_with_logits(
        labels, logits, name="softmax_loss"
    )

    lr_scheduler = flow.optimizer.PiecewiseConstantScheduler([], [0.1])
    flow.optimizer.SGD(lr_scheduler, momentum=0).minimize(loss)
    return loss


if __name__ == "__main__":
    flow.config.gpu_device_num(2)
    check_point = flow.train.CheckPoint()
    check_point.init()

    (train_images, train_labels), (test_images, test_labels) = flow.data.load_mnist(
        BATCH_SIZE
    )

    for epoch in range(3):
        for i, (images, labels) in enumerate(zip(train_images, train_labels)):
            loss = train_job(images, labels)
            if i % 20 == 0:
                print(loss.mean())

代码解析

以上代码修改自3分钟快速上手中的示例代码,比较两份代码,也可以体会到在 OneFlow 的 consistent_view 下进行各种并行方案的配置是多么的简单,只需要在单机的程序上稍加修改即可。

以上程序的关键部分有:

  • 通过 oneflow.config.gpu_device_num 接口设置参与训练的GPU数目:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 flow.config.gpu_device_num(2)
  • reshape 及 hidden 采用默认的数据并行,不需要修改;输出层通过设置 model_distribute 为 flow.distribute.split(axis=0) 变为模型并行:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
def mlp(data):
    initializer = flow.truncated_normal(0.1)
    reshape = flow.reshape(data, [data.shape[0], -1])
    hidden = flow.layers.dense(
        reshape,
        512,
        activation=flow.nn.relu,
        kernel_initializer=initializer,
        name="dense1",
    )
    return flow.layers.dense(
        hidden,
        10,
        kernel_initializer=initializer,
        # dense为列存储,进行split(0)切分
        model_distribute=flow.distribute.split(axis=0),
        name="dense2",
    )

有读者可能好奇为什么split(axis=0)是列切分?需要说明的是,OneFlow 中的 dense 内部采用列存储,因此以上代码的flow.distribute.split(axis=0)确实是在做列切分。

此外,flow.layers.dense 使用 model_distribute 形参设置并行方式,其内部调用了底层更通用的 get_variable 接口创建 blob, get_variable 接口设置并行方式的形参名为 distribute。

可以看到,我们通过极少量的修改,就能将单机训练程序改为分布式、混合并行的程序,这是 OneFlow 区别于其它框架的一大特色。

6、流水并行实例

在模型并行之外,OneFlow 还提供了一种灵活度更高的“流水并行”的并行方式,可以让用户使用 scope.placement 接口显式指定用来运行逻辑 op的 物理硬件。

在流水并行中,整个神经网络有的层次在一组物理设备上,另外一些层次在另外一组物理设备上,它们以接力的方式协同工作,分多个阶段,在设备之间流水执行。

在以下示例中,我们对Consistent 与 Mirrored 视角中的"在 OneFlow 中使用 consistent 视角"代码进行简单修改,展示了流水并行模式。

代码示例

完整代码:mixed_parallel_lenet.py

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# mixed_parallel_lenet.py
import oneflow as flow
import oneflow.typing as tp

BATCH_SIZE = 100


def lenet(data, train=False):
    initializer = flow.truncated_normal(0.1)
    conv1 = flow.layers.conv2d(
        data,
        32,
        5,
        padding="SAME",
        activation=flow.nn.relu,
        kernel_initializer=initializer,
        name="conv1",
    )
    pool1 = flow.nn.max_pool2d(conv1, ksize=2, strides=2, padding="SAME", name="pool1")
    conv2 = flow.layers.conv2d(
        pool1,
        64,
        5,
        padding="SAME",
        activation=flow.nn.relu,
        kernel_initializer=initializer,
        name="conv2",
    )
    pool2 = flow.nn.max_pool2d(conv2, ksize=2, strides=2, padding="SAME", name="pool2")
    reshape = flow.reshape(pool2, [pool2.shape[0], -1])
    with flow.scope.placement("gpu", "0:0"):
        hidden = flow.layers.dense(
            reshape,
            512,
            activation=flow.nn.relu,
            kernel_initializer=initializer,
            name="hidden",
        )
    if train:
        hidden = flow.nn.dropout(hidden, rate=0.5)

    with flow.scope.placement("gpu", "0:1"):
        output = flow.layers.dense(
            hidden, 10, kernel_initializer=initializer, name="outlayer"
        )
    return output


def get_train_config():
    config = flow.function_config()
    config.default_data_type(flow.float)
    return config


@flow.global_function(type="train", function_config=get_train_config())
def train_job(
    images: tp.Numpy.Placeholder((BATCH_SIZE, 1, 28, 28), dtype=flow.float),
    labels: tp.Numpy.Placeholder((BATCH_SIZE,), dtype=flow.int32),
) -> tp.Numpy:
    logits = lenet(images, train=True)
    loss = flow.nn.sparse_softmax_cross_entropy_with_logits(
        labels, logits, name="softmax_loss"
    )

    lr_scheduler = flow.optimizer.PiecewiseConstantScheduler([], [0.1])
    flow.optimizer.SGD(lr_scheduler, momentum=0).minimize(loss)
    return loss


if __name__ == "__main__":
    flow.config.gpu_device_num(2)
    check_point = flow.train.CheckPoint()
    check_point.init()
    (train_images, train_labels), (test_images, test_labels) = flow.data.load_mnist(
        BATCH_SIZE
    )

    for epoch in range(50):
        for i, (images, labels) in enumerate(zip(train_images, train_labels)):
            loss = train_job(images, labels)
            if i % 20 == 0:
                print(loss.mean())

代码解析

以上关键的代码只有2行,且他们的本质作用是类似的:

通过 oneflow.scope.placement ,指定 hidden 层的 op 计算运行在0号 GPU 上:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
with flow.scope.placement("gpu", "0:0"):
        hidden = flow.layers.dense(
            reshape,
            512,
            activation=flow.nn.relu,
            kernel_initializer=initializer,
            name="hidden",
        )

通过 oneflow.scope.placement ,指定 output 层的op计算运行在1号GPU上:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
with flow.scope.placement("gpu", "0:1"):
        output = flow.layers.dense(
            hidden, 10, kernel_initializer=initializer, name="outlayer"
        )

其中 scope.placement 的第一个参数指定 cpu 还是 gpu,第二个参数指定机器及运算设备编号,如,“使用第1号机器的第2个 GPU”,则应该写:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
with flow.scope.placement("gpu", "1:2"):
    # ...

流水并行,使得用户可以为每个 op 指定物理设备,非常适合对网络模型及分布式情况都很熟悉的用户进行深度优化 。

此外,OneFlow 提供的 API oneflow.unpack、oneflow.pack 等,结合了 OneFlow 自身任务调度的特点,使得流水并行更易用、高效。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-08-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 计算机视觉战队 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
OneFlow | 新深度学习框架后浪(附源代码)
随着深度学习的发展,用户越来越依赖 GPU 或者其他加速器进行大规模运算。人工智能(Artificial Intelligence)需要更优秀的软件来释放硬件的能量已成业界共识。一方面,各种框架需要进一步降低编写深度学习分布式训练程序的门槛;另一方面,用户期待系统可以支持不同的深度学习网络模型,并实现线性加速。各知名深度学习框架正在朝这方面努力,但用户在使用这些框架时仍会遇到横向扩展性的难题,或者是投入很多计算资源但没有看到效率收益,或者是问题规模超过 GPU 显存限制而无法求解。
计算机视觉研究院
2020/08/06
1K0
OneFlow | 新深度学习框架后浪(附源代码)
分布式深度学习最佳入门(踩坑)指南
本文主要介绍了分布式深度学习的各框架以及一些分布式深度学习训练中的常见问题,如:docker及ssh环境问题、nccl多机通信问题等。
计算机视觉
2021/01/14
3.5K0
分布式深度学习最佳入门(踩坑)指南
最新深度学习框架——OneFlow:新分布式训练(附源代码)
随着深度学习的发展,用户越来越依赖 GPU 或者其他加速器进行大规模运算。人工智能(Artificial Intelligence)需要更优秀的软件来释放硬件的能量已成业界共识。一方面,各种框架需要进一步降低编写深度学习分布式训练程序的门槛;另一方面,用户期待系统可以支持不同的深度学习网络模型,并实现线性加速。各知名深度学习框架正在朝这方面努力,但用户在使用这些框架时仍会遇到横向扩展性的难题,或者是投入很多计算资源但没有看到效率收益,或者是问题规模超过 GPU 显存限制而无法求解。
计算机视觉研究院
2020/08/11
2.5K0
最新深度学习框架——OneFlow:新分布式训练(附源代码)
【tensorflow速成】Tensorflow图像分类从模型自定义到测试
TensorFlow 是 Google brain 推出的开源机器学习库,与 Caffe 一样,主要用作深度学习相关的任务。
用户1508658
2019/07/25
7330
【tensorflow速成】Tensorflow图像分类从模型自定义到测试
教程 | 用AI生成猫的图片,撸猫人士必备
编译 | 小梁 【AI科技大本营导读】我们身边总是不乏各种各样的撸猫人士,面对朋友圈一波又一波晒猫的浪潮,作为学生狗和工作狗的我们只有羡慕的份,更流传有“吸猫穷三代,撸猫毁一生?”的名言,今天营长就为
AI科技大本营
2018/04/26
2.2K0
教程 | 用AI生成猫的图片,撸猫人士必备
一看就懂的Tensorflow实战(多层感知机)
这里定义含有两个隐含层的模型,隐含层输出均为256个节点,输入784(MNIST数据集图片大小28*28),输出10。
AI异构
2020/07/29
7300
一看就懂的Tensorflow实战(多层感知机)
tf46:再议tf.estimator之便利
版权声明:本文为博主原创文章,未经博主允许不得转载。有问题可以加微信:lp9628(注明CSDN)。 https://blog.csdn.net/u014365862/article/details/84381123
MachineLP
2019/05/26
1.1K0
批量归一化batch_normalization
(1)\(\mu_B = \frac{1}{m_B}\sum_{i=1}^{m_B}x^{(i)}\) #经验平均值,评估整个小批量B
全栈程序员站长
2022/07/18
2070
大模型训练之难,难于上青天?预训练易用、效率超群的「李白」模型库来了!
机器之心发布 机器之心编辑部 LiBai(李白)模型库覆盖了 Hugging Face、Megatron-LM、DeepSpeed、FairSeq 这些所有主流 Transformer 库的优点,让大模型训练飞入寻常百姓家。 大模型多了去了,告诉我怎么加速?自 2018 年 BERT 诞生,到 GPT-3、ViT 等拥有数以亿计的参数规模的模型不断涌现,AI 模型参数量的爆发式增长已不足为奇,让炼丹师无暇顾及甚至感到麻木。 与此同时,大模型对计算和内存资源提出了巨大的挑战。训练成本急剧上升,比如用一块非
机器之心
2022/07/07
1.2K0
大模型训练之难,难于上青天?预训练易用、效率超群的「李白」模型库来了!
GPT-3模型为何难以复现?这也许是分布式AI框架的最优设计
2020 年,最轰动的 AI 新闻莫过于 OpenAI 发布的 GPT-3 了。它的1750亿参数量及其在众多NLP任务上超过人类的出众表现让大家坚信:大模型才是未来。但与之带来的问题是,训练超大模型所需的算力、存储已不再是单机就能搞定的了(之前的 BERT 还是可以用 DGX-1/2 这样的超级服务器训练)。
AI科技大本营
2021/06/08
4.1K0
GPT-3模型为何难以复现?这也许是分布式AI框架的最优设计
深度学习工具和框架详细指南:PyTorch、TensorFlow、Keras
在深度学习的世界中,PyTorch、TensorFlow和Keras是最受欢迎的工具和框架,它们为研究者和开发者提供了强大且易于使用的接口。在本文中,我们将深入探索这三个框架,涵盖如何用它们实现经典深度学习模型,并通过代码实例详细讲解这些工具的使用方法。
平凡之路.
2024/11/21
1.2K0
CV新进展 | 迭代视觉推理框架 | 李飞飞团队 | Tensorflow的MNIST案例
陈鑫磊、李佳、李飞飞、Abhinav Gupta等人提出了一种新的迭代视觉推理框架
用户7623498
2020/08/04
4350
知乎问题代码
# -*- coding: utf-8 -*- """ Created on Sat May 19 18:44:40 2018 @author: John Kwok """ # import import numpy as np import tensorflow as tf import GetDataUtil # 数据读取及预处理 ''' 定义超参 ''' BATCH_SIZE = 128 # 批大小 EPOCH = 5 # 训练EPOCH次数 HIDDEN_UNIT = 512 KERNEL_S
10JQKA
2018/08/01
1.1K0
深度学习中的自动编码器:TensorFlow示例
  自动编码器是重建输入的绝佳工具。简单来说,机器就是一个图像,可以生成一个密切相关的图片。这种神经网络中的输入是未标记的,这意味着网络能够在没有监督的情况下进行学习。更准确地说,输入由网络编码,仅关注最关键的特征。这是自动编码器因降维而流行的原因之一。此外,自动编码器可用于生成生成学习模型。例如,神经网络可以用一组面部训练,然后可以产生新的面部。
全栈程序员站长
2022/09/05
7560
深度学习中的自动编码器:TensorFlow示例
一看就懂的Tensorflow实战(卷积神经网络)
注意,这里只需要给出输入数据,输出通道数,卷积核大小即可。 Pooling layers 模块提供了多个池化方法,这几个池化方法都是类似的,包括 max_pooling1d()、max_pooling2d()、max_pooling3d()、average_pooling1d()、average_pooling2d()、average_pooling3d(),分别代表一维二维三维最大和平均池化方法,它们都定义在 tensorflow/python/layers/pooling.py 中,这里以 > max_pooling2d() 方法为例进行介绍。 max_pooling2d( inputs, pool_size, strides, padding='valid', data_format='channels_last', name=None ) 参数说明如下:
AI异构
2020/07/29
5460
一看就懂的Tensorflow实战(卷积神经网络)
YJango:TensorFlow高层API Custom Estimator建立CNN+RNN的演示
该文是YJango:TensorFlow中层API Datasets+TFRecord的数据导入的后续。
YJango
2018/04/03
2.6K3
YJango:TensorFlow高层API Custom Estimator建立CNN+RNN的演示
OneFlow深度学习框架介绍:新手快速上手指南
深度学习已成为现代人工智能领域的核心技术,而选择一款合适的深度学习框架对于科研人员与开发者而言至关重要。OneFlow作为近年来崭露头角的一款高性能深度学习框架,以其独特的设计理念、卓越的性能表现和友好的社区生态吸引了大量关注。本篇博客将以新手视角出发,深入浅出地介绍OneFlow的主要特点、核心优势以及如何快速上手,帮助您开启OneFlow深度学习之旅。
Jimaks
2024/04/13
4370
《Scikit-Learn与TensorFlow机器学习实用指南》 第11章 训练深度神经网络(上)
第 10 章介绍了人工神经网络,并训练了我们的第一个深度神经网络。 但它是一个非常浅的 DNN,只有两个隐藏层。 如果你需要解决非常复杂的问题,例如检测高分辨率图像中的数百种类型的对象,该怎么办? 你可能需要训练更深的 DNN,也许有 10 层,每层包含数百个神经元,通过数十万个连接相连。 这可不像公园散步那么简单:
SeanCheney
2020/10/27
5760
《Scikit-Learn与TensorFlow机器学习实用指南》 第11章 训练深度神经网络(上)
【深度】监督&强化学习算法在A股中的应用
Github项目:https://github.com/Ceruleanacg/Personae 前八期传送门: 【系列58】强化学习在Market Making上的应用 【系列57】为什么机器学习在投资领域并不是那么好用 【系列56】特征重要性在量化投资中的深度应用 【系列55】机器学习应用量化投资必须要踩的那些坑 【系列54】因子的有效性分析基于7种机器学习算法 【系列53】基于XGBoost的量化金融实战 【系列52】基于Python预测股价的那些人那些坑 【系列51】通过ML、Time Series
量化投资与机器学习微信公众号
2018/05/28
2.3K0
深度学习中的正则化策略综述(附Python代码)
本文翻译自《An Overview of Regularization Techniques in Deep Learning (with Python code)》(https://www.analyticsvidhya.com/blog/2018/04/fundamentals-deep-learning-regularization-techniques/),原作者保留版权。
机器学习算法工程师
2018/07/27
7850
深度学习中的正则化策略综述(附Python代码)
推荐阅读
相关推荐
OneFlow | 新深度学习框架后浪(附源代码)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验