1. 计算核心
1.1 技术指南
主要使用C++ (C++11或更高特性), 大量使用宏和泛型的两者组合, 以减少重复代码
-
CPU计算加速优化:
- 优先使用Eigen(
third_party/eigen
), 其底层抽象了X86和ARM64指令集 - 对于X86, 然后考虑OpenMP,看情况可以手写SSE, AVX2, FMA, AVX512
- 对于ARM64, 优先适配NPU的SDK, 最后考虑手写NEON
- 根据时间节点,考虑 MKL / MKLDNN 的集成,CPU算子前期主要是配合单元测试
- 优先使用Eigen(
-
CUDA计算加速优化:
- 尽可能为每个算子实现Kernel, 对于复杂的并行算法(广播、规约、排序),
可以使用CUB(
third_party/cub
)和cuBLAS/Thrust(CUDA集成)- 尽可能利用每一个cuDNN接口, 编写cuDNN加速版可选算子
- 尽可能利用GPU的Cache/SharedMem,减少临时空间的使用
- 尽可能通过预定义使用新GPU架构的Intrinsic指令, 比如sm35以上的
__ldg
,
sm53 以上的
half
相关指令,以及安培架构新增的bfloat16
相关指令- 尽可能不要强制同步当前执行的CUDA Stream
-
分布式计算优化:
- 集群通信基础库由
third_party/mpi
负责, 我们默认用的是OpenMPI - 用NCCL实现支持的Collective MPI操作, 实现GPUDirect通过RDMA直接加速
- 由于pip预编译版本禁用了OpenMPI的RDMA特性, 暂不考虑MPI对Infiniband优化
- 集群通信基础库由
-
静态计算图
- 输入为满足SSA形式的proto结构, 我们称为GraphIR, 包含上下文的算子和一些执行信息
- 目前实现了三个级别的优化, 分别是:
- 图剪枝 (O1, 移除求解最终输出变量不需要的Op或者Op的部分输出)
- 追加: 自适应的In-place (O2, 输出直接覆盖只被引用一次的输入)
- 追加: 模拟垃圾回收(GC)机制 (O3, 用FIFO/LIFO的Buffer池改写全部中间输出)
默认优化级别为O3, 模拟GC在没有梯度计算时等价于PyTorch的
no_grad
执行时的内存优化,需要计算梯度时, 前向计算回滚到O2优化, 而反向计算的O3优化则实现了主流框架的梯度内存共享特性
-
动态计算图
- 前向计算输入为
Op
的proto结构, 反向计算输入为全部前向Op - 仅反向部分可用静态计算图形式构建, 由于O2优化此时由用户定义, 不满足SSA,
故O1的剪枝优化只能移除无关的叶子变量, 无法分析中间变量, O3优化同静态计算图
-
Tensor
垃圾回收目前利用PythonGC实现, 在计算核心中的管理方式同静态计算图
- 前向计算输入为
-
内存管理
-
UnifiedMemory
统一管理Host和Device内存, 并由状态机实现data间的同步 - 目前不支持
non-contigous
内存布局 - 一般由
Tensor
持有自己的UnifiedMemory
, 或映射到其它的Tensor
的UnifiedMemory
-
-
Workspace
- 维护
Tensor
,Graph
, 以及因动态图而cache参数的Op
- 等价于
tf.Graph
, Caffe2的Workspace
, 但我们沿用了Caffe2的命名 - 用于可命名资源的隔离管理及上下文视图, 实现DL框架的MVC模式
- 维护
-
算子
- 我们的
Op
实现为 抽象计算设备/数据类型 的计算 Dispatcher - 主要任务是处理静态/动态参数、形状推理,
最后根据输入
Tensor
设备/数据类型调用对应OpKernel
函数实现-
OpKernel
、MathKernel
与Op
独立实现,便于多个Op
调用相同目标的计算
- 我们的
-
C++代码规范
- Google C++规范模板
- 每个C++代码文件, 必须经过仓库内规定的
.clang-format
格式化,
推荐编辑器安装clang-format插件, 每次保存时自动格式化
1.2 开发路线图
- 高阶梯度 (PCL开源竞赛题)
- 对列出的全部算子,实现二阶梯度计算
- Div
- Sin, Cos, Tanh, Relu, Log, Square, Reciprocal, Abs, Clip
- Dropout, Sigmoid, Sqrt, Rsqrt, FullyConnected, Conv2d
- 对列出的部分算子,实现无限阶梯度计算
- Add, Sub, Mul
- 重构静态计算图的优化
- 参考ONNX和传统C/C++编译器, 细粒度化每一个PASS
- 重写亚线性内存优化, 引入代价函数实现局部计算图的不同变换
- 利用
cuDNN 7.5
引MultiHeadAttn
接口编写优化Transformer的Op
- 考虑设计更好的动态计算变量池方案
- 目前前向计算为FIFO, 反向为LIFO, 对于NAS任务完全失效
- 增加
TopKOp
, 需要对数学库增加cuda排序(Radix/Heap)的实现 - Mobile平台的模型推理
- 实现部分内置算子的INT8计算 (NEON)
2. Python接口
2.1 技术指南
-
Pybind
- 为
Tensor
、Workspace
等C++资源类绑定PyObject,
方便通过PythonGC为框架前端设计更灵活的接口
- 操纵NumPy或DLPack的Python对象,实现ZeroCopy的内存映射
- 在Python中使用C++实现的Protobuf Message, 以减少动态图传递、编辑IR的开销
- 为
-
独立的编译模块
- Pybind模块代码与框架主体分离在两个不同的动态库中,
否则在Windows下, Python解释器加载的扩展DLL, 不能共享整合DLL内Registry
-
静态计算 (
AutoGraph
)- 执行模式为
GRAPH_MODE
-
dragon.Tensor
中记录从叶子变量计算到本变量的全部OpDef
,
以及本变量对其它变量的偏导目标
- 根据前向计算的
OpDef
和偏导目标生成反向传播的OpDef
及
参数更新的
OpDef
, 加上执行信息一起注入进GraphDef
- 将
GraphDef
传递给计算核心在当前Workspace
构建优化的Graph
- 返回一个绑定
Graph
执行和Feed输入的回调函数给用户反复调用 - 装饰器模式: 通过inspect模块获取装饰器标记的函数的输入参数信息,
将输入替换为
dragon.Tensor
执行标记的函数, 取输出变量中的记录的OpDef
此过程等价tf 2.0引入的
tf.function
、pytorch 1.0引入的torch.jit.script
- 执行模式为
-
动态计算 (
EagerExecution
)- 执行模式为
EAGER_MODE
-
dragon.GradientTape
中记录上下文管理器进入至退出期间,
所有watched/trainable的
dragon.EagerTensor
, 执行所使用的OpDef
- 根据前向计算的
OpDef
和偏导目标生成反向传播的OpDef
,
并由当前
Workspace
逐个执行- 参数更新器对已计算出梯度的参数, 逐个执行Update算子
-
dragon.EagerTensor
参与PythonGC的引用计数,
引用归零且未被反向传播锁定则进入变量池
- 执行模式为
-
内置IO
- 层次化的设计
- HDD/SSD->Bytes (DataReader)
- Bytes->Image/Label (DataTransformer)
- Image/Label -> ImageBlob/LabelBlob (DataIterator)
- 三者位于不同进程中, 异步缓存数据, 通过同步队列传递数据
- DataReader
- 负责从硬盘进行分布式的非连续字节读取
- 需要预先序列化数据, 默认的Message结构为我们设计的KPLRecord
- 两种Shuffle策略: Example-wise和Chunk-wise
前者为每个epoch后逐样本打乱, 后者则是逐块打乱, 而块内顺序读取
Chunk-wise保证了HDD能够稳定支持单机8卡分布式ImageNet训练
- DataTransformer
- 数据解码、数据增强、标签处理
- 不同DL任务需要重写该类, 默认提供图像分类的Transformer
- DataIterator
- 从
DataTransformer
中取出数据组Batch
-
参数更新器
- 每一个slot控制一个param group, 组内学习率, clip norm, weight decay共享
-
apply_gradients
在静态计算下, 收集参数梯度二元组, 反之直接执行计算 - 分布式的
ProcessGroup
进入上下文管理器时, 增加AllReduceOp处理数据并行
-
虚拟框架: TensorFlow
- 不支持也无计划支持
tf.compat.v1
- tf 2.0大部分组件与dragon重合, 故仅仅是alias
-
tf.Graph
->dragon.Workspace
-
tf.GradientTape
->dragon.GradientTape
-
tf.Tensor
->dragon.Tensor
-
tf.EagerTensor
->dragon.EagerTensor
-
tf.function
->dragon.function
-
tf.gradients
->dragon.gradients
-
tf.ops
->dragon.ops
-
tf.Variable
目前确定为tf.ResourceVariable
,
在任何计算模式下都是
dragon.EagerTensor
的子类,可直接可用于静态计算
-
tf.keras
部分基本组件进行了重新设计 -
tf.keras.Network
和tf.keras.Model
对tf.keras.Layer
的堆叠功能下沉到
tf.keras.Layer
, 与tf.Module
设计理念一致- 以上三者的自动命名支持通过
__setattr__
时获取,
与
torch.nn.Module
设计理念一致, 简化name参数的传递-
tf.keras.optimizers.Optimizer
在dragon.updaters.Updater
基础上,
增加了对
Regularizer
的处理, slot的基准weight decay取所有regularizers的最小值, 非最小值则使用UpdateOp的
decay_mult
参数实现 - 不支持也无计划支持
-
虚拟框架: PyTorch
-
torch.Tensor
独立于dragon.EagerTensor
, 我们没有办法统一两者的接口,
受此影响,
torch.ops
不可对dragon.ops
做简单地alias, 需要重新封装一次- 动态计算接口针对PyTorch进行了部分微调
-
OpDef
默认通过torch.Tensor
存储和传递 (与静态计算类似)
GradientTape
仅仅在torch.jit.trace
接口中进行全局记录-
zero_grad
不是必须的, 计算核心并不会主动累积梯度, 也就不需要置零 - 由于Python不支持函数重载, 对PyTorch部分从C++导出接口解耦:
-
torch.max
->torch.max
,torch.argmax
,torch.maximum
-
torch.min
->torch.min
,torch.argmin
,torch.minimum
- 由于不支持
non-contigous
特性的, 与dim、stride相关的Op
存在计算/存储代价 -
view
,reshape
,squeeze
,unsqueeze
perimute
-
slice
,expand
-
-
算子插件
-
Op
可从外部动态库中加载和注册, 无须重新编译框架 - 通过C++/CUDA实现不支持的算子,提升特定算法平台的训练/推理性能
-
-
Python代码规范
- 遵守PEP8规范
- 每个Python代码文件, 必须经过仓库内规定的
.flake8
检查 - 避免使用
__all__
, 如需分隔用户/开发者的接口视角, 使用_api
和core
文件夹结构
-
Python注释规范
- 使用NumPy风格的编写docstring, 参数和返回值的数据类型必须注解精确
- 普通注释首字母大写, 包含主语的句子需要以句号结尾
- 语言表达需简洁扼要
2.2 开发路线图
- 与
PyTorch 1.5
对齐接口 - 与
TensorFlow 2.2
对齐接口 - 与
TensorLayer
对齐接口 - 完善
TensorRT
对INT8量化、动态形状接口 - 持续跟踪
DALI
新的数据处理算子
3. 文档
3.1 技术指南
- Sphinx-doc
- 通过Sphinx解析docstring生成Python API文档
- Sphinx主题具有高度可定制性, Tensorflow/PyTorch主页皆做了深度的设计
- 我们设计了自己的主题:
sphinx-seeta-theme
,借鉴了TensorFlow主题中一些交互元素
- reStructuredText
- 使用rst格式编写控制自动的文档生成源文件
- rst相比markdown,支持生成跨文件的目录结构树(TOC)
3.2 开发路线图
- 开发Sphinx主题: 增加二级导航栏, 一级导航栏的二级菜单, 增加左侧边栏的可定制性
- 补充Getting started 和 Tutorials
4. 测试
4.1 技术指南
- TBD
4.2 开发路线图
- 编写
Op
的单元测试, 考虑同时将所有的虚拟框架一起测试 - 编写核心功能的单元测试
5. 算法平台开发
5.1 图像分类
- 支持多种backbone和attention模块的组合
- 支持多种损失函数,如Focal Loss、Dice Loss等
- 优化数据/IO,支持分布式训练/分布式BatchNorm
- 支持ONNX模型导出与TensorRT推理优化
- 使用
PyTorch
或Tensorflow
虚拟接口开发
5.2 目标检测
- 复杂算子的实现:
Deformable Conv
- Backbone的补充:
HRNet
,ResNeSt
- 检测算法的补充:
Cascade R-CNN
,FCOS
,NAS-FPN
- 使用
PyTorch
或Tensorflow
虚拟接口开发
5.3 语义分割
- 支持多种backbone和attention模块的组合
- 支持多种损失函数,如Focal Loss、Dice Loss等
- 优化数据/IO,支持分布式训练/分布式BatchNorm
- 支持ONNX模型导出与TensorRT推理优化
- 使用
PyTorch
或Tensorflow
虚拟接口开发
5.4 GAN
- 实现DCGAN/ProgressiveGAN/StyleGAN/BigGAN
- 支持CIFAR10/ImageNet/CelebA/Celeb-HD等数据集
- 使用
PyTorch
或Tensorflow
虚拟接口开发
5.5 GCN
- 构建常用的GCN模块
- 处理Graph消息传递问题,并尝试优化执行效率
- 在常见数据上完成benchmark,和其他GCN框架比较精度和速度
- 使用
PyTorch
或Tensorflow
虚拟接口开发