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虚拟接口开发