【第二次正经 PR】左操作(`__lshift__`)和右操作(`__rlshift__`) -part2: AutoTensor 定义 kernel 实现 int -> Tensor 的类型转换。
虽然在 PR 中我想要定义 kernel 的想法被驳回了,但是不影响咱们自己玩。
Refrence:
如何在 Paddle 中定义一个 CPP kernel 并且把它映射到 Python 层
咱们就挨着bitwise_left_shift
来定义。先来一个标准输出流打印点东西试试。
找到映射 kernel 和 api 的 yaml 文件:
(base) xnne@xnne-PC:~/code/Paddle-Local$ find . -path ./build -prune -o -name "ops.yaml" -print
./paddle/phi/ops/yaml/ops.yaml
./paddle/cinn/hlir/dialect/operator/ir/ops.yaml
ops.yaml 似乎从 bitwise_left_shift 定义后换了一个位置,还好没改名。
位置目前位于./paddle/phi/ops/yaml/ops.yaml
- op: bitwise_left_shift
args: (Tensor x, Tensor y, bool is_arithmetic = true)
output: Tensor(out)
infer_meta:
func: BitwiseShiftInferMeta
kernel:
func: bitwise_left_shift
backend: x
inplace: (x -> out)
traits: paddle::dialect::ForwardOnlyTrait
interfaces: paddle::dialect::InferSymbolicShapeInterface
长这样,我到时候需要在这个文件里面定义一个新的 kernel,大概就叫 AutoTensor
。
一些名词解释:
traits: paddle::dialect::ForwardOnlyTrait # ForwardOnlyTrait 是一个特性(trait),表示该操作仅用于前向计算,不支持反向传播(即梯度计算)。应该是自动微分的超参数
interfaces: paddle::dialect::InferSymbolicShapeInterface # InferSymbolicShapeInterface 是一个接口(interface),表示该操作支持符号形状推断。什么是符号形状推断,说人话就是,支持shape里面包含变量,而不是具体的数值。 | 永远可以拿出来鞭策的CNN,CNN的模型,输入输出一般都是固定的,这时候不需要符号形状推断,而对于Seq2Seq,当Seq的长度不一样的时候,shape就会变化,也就是说包含变量,这个时候,就需要符号推断,如果不支持,该计算就会报错。先这样理解。
inplace: (x -> out) # 原地操作返回。 | 可选,不是必要的,不是所有函数都特地定义inplace。
backend: x # 表示 bitwise_left_shift 操作有一个针对 x 后端的计算实现。也许这个 x 是一个专门优化的后端,可以在特定硬件(比如某个加速器)上高效执行位运算。 | 不懂,先放着
backward: bmm_grad # 表示这个 bmm(批矩阵乘法)操作有一个与之相关的反向传播函数 bmm_grad,用来计算梯度。在训练时,框架会使用这个函数来计算与 x 和 y 的梯度。 | 暂时不用,先放着
我见到的比较短的定义是这样的:
- op: bmm
args: (Tensor x, Tensor y)
output: Tensor
infer_meta:
func: BmmInferMeta
kernel:
func: bmm
backward: bmm_grad
interfaces: paddle::dialect::InferSymbolicShapeInterface
这个没有backend
.
- op: calc_reduced_attn_scores
args: (Tensor q, Tensor k, Tensor softmax_lse)
output: Tensor(reduced_scores)
infer_meta:
func: CalcReducedAttnScoresInferMeta
param: [q, k, softmax_lse]
kernel:
func: calc_reduced_attn_scores
data_type: q
traits: paddle::dialect::ForwardOnlyTrait
这个没有符号推断。
AutoTensor
也应该尽量简单,不需要太多参数。
大概像这样:
# 将输入的int自动转换成Tensor.
- op: auto_tenosor
args: (int x)
output: Tensor(out)
infer_meta:
func: AutoTensorMeta
kernel:
func: auto_tensor
traits: paddle::dialect::ForwardOnlyTrait
丢弃了backend
和backward
和符号推断
,保留ForwardOnly
.因为这个没有反向传播的必要。
比较重要的是理清楚infer_meta
的func
和kernel
的func
以及op
是什么关系。
哪个是映射的 api 名称,哪个是具体定义的 kernel 名称。
未完待续。