Paddle API贡献指南(二)API 设计和命名规范
本文最后更新于 2024-11-13,文章内容可能已经过时。
API 设计和命名规范-API文档-PaddlePaddle深度学习平台
API设计规范
总体原则
单一职责,每个 API 应只完成单一的任务
接口设计应考虑通用性,避免只适用于某些单一场景
符合行业标准,综合参考开源深度学习框架的接口设计,借鉴各框架的优点;除非飞桨 API 设计有明确优势的情况下可保留自有特色,否则需要符合行业标准
功能类似的接口,参数名和行为需要保持一致,比如,lstm 和 gru
优先保证清晰,然后考虑简洁,避免使用不容易理解的缩写
历史一致,如无必要原因,应避免接口修改
动静统一,如无特殊原因,动态图和静态图下的 API 输入、输出要求一致。开发者使用相同的代码,均可以在动态图和静态图模式下执行
动态图与静态图模式
关于飞桨框架支持的开发模式,为了便于用户理解,代码和 API 均采用“动态图”和“静态图”的说法;文档优先使用“动态图”和“静态图”的说法,不推荐使用“命令式编程”和“声明式编程”的说法。
API 目录结构规范
公开 API 代码应该放置到以下列出的对应位置目录/文件中,并添加到目录下__init__.py 的 all 列表中。非公开 API 不能添加到 all 列表中
API 行为定义规范
动静统一要求。除了 paddle.static 目录中的 API 外,其他目录的所有 API 原则上均需要支持动态图和静态图模式下的执行,且输入、输出要求一致。开发者使用相同的代码,可以在动态图和静态图模式下执行。
#静态图专用 paddle.fluid.gradients(targets, inputs, target_gradients=None, no_grad_set=None) #动态图专用 paddle.fluid.dygraph.grad(outputs, inputs, grad_outputs=None, retain_graph=None, create_graph=False, only_inputs=True, allow_unused=False, no_grad_vars=None, backward_strategy=None) #动、静态图通用 paddle.nn.functional.conv2d(x, weight, bias=None, padding=0, stride=1, dilation=1, groups=1, use_cudnn=True, act=None, data_format="NCHW", name=None) paddle.nn.Conv2D(num_channels, num_filters, filter_size, padding=0, stride=1, dilation=1, groups=1, param_attr=None, bias_attr=None, use_cudnn=True, act=None, data_format="NCHW", dtype='float32')
API 不需要用户指定执行硬件,框架可以自动根据当前配置,选择执行的库。
设置缺省参数类型 组网类 API 去除 dtype 参数,比如 Linear, Conv2d 等,通过使用 paddle.set_default_dtype 和 paddle.get_default_dtype 设置全局的数据类型。
数据类型转换规则
不支持 Tensor 和 Tensor 之间的隐式数据类型转换,隐藏类型转换虽然方便,但风险很高,很容易出现转换错误。如果发现类型不匹配,进行隐式类型转换,一旦转换造成精度损失,会导致模型的精度降低,由于没有任何提示,问题非常难以追查;而如果直接向用户报错或者警告,用户确认后,修改起来会很容易。避免了出错的风险。
import paddle a = paddle.randn([3, 1, 2, 2], dtype='float32') b = paddle.randint(0, 10, [3, 1, 2, 2], dtype='int32') c = a + b # 执行后会出现以下类型不匹配警告: # ......\paddle\fluid\dygraph\math_op_patch.py:239: UserWarning: The dtype of left and right variables are not the same, left dtype is paddle.float32, but right dtype is paddle.int32, the right dtype will convert to paddle.float32 format(lhs_dtype, rhs_dtype, lhs_dtype))
支持 Tensor 和 python Scalar 之间的隐式类型转换,当 Tensor 的数据类型和 python Scalar 是同一类的数据类型时(都是整型,或者都是浮点型),或者 Tensor 是浮点型而 python Scalar 是 整型的,默认会将 python Scalar 转换成 Tensor 的数据类型。而如果 Tensor 的数据类型是整型而 python Scalar 是浮点型时,计算结果会是 float32 类型的。
import paddle a = paddle.to_tensor([1.0], dtype='float32') b = a + 1 # 由于 python scalar 默认采用 int64, 转换后 b 的类型为'float32' c = a + 1.0 # 虽然 python scalar 是 float64, 但计算结果 c 的类型为'float32' a = paddle.to_tensor([1], dtype='int32') b = a + 1.0 # 虽然 python scalar 是 float64, 但计算结果 b 的类型为 'float32 c = a + 1 # 虽然 python scalar 是 int64, 但计算结果 c 的类型为'int32'
数据类型规范
参数数据类型
对于 loss 类 API,比如 cross_entropy, bce_loss 等,输入的 label 需要支持[int32, int64, float32, float64]数据类型。
返回值数据类型
实现需要返回下标 indices 的 API,比如 argmax、argmin、argsort、topk、unique 等接口时,需要提供 dtype 参数,用于控制返回值类型是 int32 或者 int64,默认使用 dtype=’int64’(与 numpy, tf, pytorch 保持一致),主要目的是当用户在明确输入数据不超过 int32 表示范围时,可以手动设置 dtype=’int32’来减少显存的占用;对于 dtype=’int32’设置,需要对输入数据的下标进行检查,如果超过 int32 表示范围,通过报错提示用户使用 int64 数据类型。
API 命名规范
API 的命名应使用准确的深度学习相关英文术语,具体参考附录的中英术语表。
类名与方法名的规范
类名的命名应采用驼峰命名法,通常采用名词形式
paddle.nn.Conv2D paddle.nn.BatchNorm paddle.nn.Embedding paddle.nn.LogSoftmax paddle.nn.SmoothL1Loss paddle.nn.LeakyReLU paddle.nn.Linear paddle.optimizer.lr.LambdaDecay
由多个单词组成的类名,最后一个单词应表示类型
# SimpleRNNCell 继承自 RNNCellBase paddle.nn.SimpleRNNCell # BrightnessTransform 继承 BaseTransform paddle.vision.BrightnessTransform
函数的名称应采用全小写,单词之间采用下划线分割
# 使用小写 paddle.nn.functional.conv2d paddle.nn.functional.embedding # 如果由多个单词构成应使用下划线连接 paddle.nn.functional.mse_loss paddle.nn.functional.batch_norm paddle.nn.functional.log_softmax
但一些约定俗成的例子可以保持不加下划线
paddle.isfinite paddle.isnan paddle.isinf paddle.argsort paddle.cumsum
API 命名时,缩写的使用不应引起歧义或误解;在容易引起歧义或误解的情况下,需要使用全称,比如
# pytorch 使用 ge,lt 之类的缩写,可读性较差,应保留全称,与 numpy 和 paddle 保持一致 paddle.tensor.greater_equal paddle.tensor.less_than # optimizer 不使用缩写 paddle.optimizer.SGD # parameter 不使用缩写 paddle.nn.create_parameter
在用于 API 命名时,常见的缩写列表如下:
conv、max、min、prod、norm、gru、lstm、add、func、op、num、cond
在用于 API 命名时,以下建议使用全称,不推荐使用缩写
API 命名不应包含版本号
# 不使用版本号 paddle.nn.multiclass_nms2
常见的数学计算 API 中的逐元素操作不需要加上 elementwise 前缀,按照某一轴操作不需要加上 reduce 前缀,一些例子如下
整数取模和取余
目前整除和取余取模运算机器运算符重载在不同的语言和库中对应关系比较复杂混乱(取余运算中余数和被除数同号,取模运算中模和除数同号。取余整除是对商向 0 取整,取模整除是对商向负取整)
常用组网 API 命名规范
# 卷积: paddle.nn.Conv2D #采用 2D 后缀,2D 表示维度时通常大写 paddle.nn.Conv2DTranspose paddle.nn.functional.conv2d paddle.nn.functional.conv2d_transpose # 池化: paddle.nn.MaxPool2D paddle.nn.AvgPool2D paddle.nn.MaxUnpool2D paddle.nn.functional.max_pool2d paddle.nn.functional.avg_pool2d paddle.nn.functional.max_unpool2d # 归一化: paddle.nn.BatchNorm2D paddle.nn.functional.batch_norm
参数命名规范
参数名称全部使用小写
paddle.nn.functional.mse_loss: def mse_loss(input, label, reduction='mean', name=None):
参数名可以区分单复数形态,单数表示输入参数是一个或多个变量,复数表示输入明确是含有多个变量的列表
paddle.nn.Softmax(axis=-1) # axis 明确为一个 int 数 paddle.squeeze(x, axis=None, dtype=None, keepdim=False, name=None): # axis 可以为一数也可以为多个 paddle.strided_slice(x, axes, starts, ends, strides, name=None) #axis 明确是多个数,则参数用复数形式 axes
函数操作只有一个待操作的张量参数时,用 x 命名;如果有 2 个待操作的张量参数时,且含义明确时,用 x, y 命名
paddle.sum(x, axis=None, dtype=None, keepdim=False, name=None) paddle.divide(x, y, name=None)
原则上所有的输入都用 x 表示,包括 functional 下的 linear, conv2d, lstm, batch_norm 等
原则上都要具备 name 参数,用于标记 layer,方便调试和可视化
loss 类的函数,使用
input
表示输入,使用label
表示真实预测值/类别,部分情况下,为了更好的便于用户理解,可以选用其他更恰当的参数名称。如softmax_with_logits
时,输入参数名可用logits
paddle.nn.functional.mse_loss(input, label, reduction='mean', name=None) paddle.nn.functional.cross_entropy(input, label, weight=None, ignore_index=-100, reduction='mean', soft_label=False, axis=-1, name=None):
Tensor 名称和操作
常用参数表
- 感谢你赐予我前进的力量