-
Notifications
You must be signed in to change notification settings - Fork 270
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
【Hackathon No.25】为paddle新增 nanquantile #55
Conversation
|
||
## 1、相关背景 | ||
|
||
为了提升飞桨API丰富度,支持科学计算领域API,Paddle需要扩充API`paddle.nanquantile`以及`paddle.Tensor.nanquantile`.paddle.nanquantile 是 [paddle.quantile](https://www.paddlepaddle.org.cn/documentation/docs/zh/develop/api/paddle/quantile_cn.html) 的变体,即沿给定的轴计算非nan元素的分位数。 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
以及paddle.Tensor.nanquantile
.(英文句号得换成中文的),全文有好多处英文标点,都要换成中文的。
2. 使用`paddle.sort`得到排序后的tensor. | ||
3. 将`q`:[0, 1]映射到`indice`:[0, numel_of_dim-1];并对`indice`分别做`paddle.floor`和`paddle.ceil`求得需要计算的两端元素位置; | ||
4. `paddle.lerp`计算两端元素的加权插值,作为最终结果; | ||
5. 根据`keepdim`参数调整至对应的shape。 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
参考的实现逻辑里缺了对NaN的处理。
对NaN的处理,对原tensor采用paddle.isnan检查Nan值,包含NaN的,在步骤4所对应位置的元素置NaN。
可以引用下paddle.quantile的设计文档
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
感谢您的建议,稍后将会进行修改更新!
这里是使用了paddle.quantile的设计文档中的实现逻辑,但是在检查代码时并没有发现对NaN
的处理。经过测试发现实际上paddle.quantile
在输入含有NaN
值并不能与Numpy
和Pytorch
很好的对齐,对于指定维度上含有NaN
时,Numpy
和Pytorch
会返回NaN
,而paddle.quantile
会将NaN
值当做一个占位符,依旧返回数字,并且由于paddle.sort
的问题,其结果也是不正确的。
对于目前的情况要想保证结果的正确性,按照我的思路,其计算逻辑将会与nanquantile
更加靠近,代码复用性也会更好,如果流程和时间允许的话,我可以尝试一并修复。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
如果流程和时间允许的话,我可以尝试一并修复
我们内部讨论下关于paddle.quantile
和paddle.sort
处理的问题,稍后给您回复
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
简述一下我的思路吧
- 对于
quantile
和nanquantile
都会使用isnan
来找出NaN,并且替换为Inf。 - 对于
quantile
使用sum
、any
和logical_not
将存在NaN的位置置0,这样计算indices
的时候该位置就会变为-1,而Inf会被排到最后,后面取出的时候会就会取到Inf,输出时再替换为NaN。 nanquantile
也是同理,如设计文档中描述的,会将全是NaN的位置置0,indices
置为-1,后面取值同上。
另外一点就是原本的quantile
中indices
是一个数,后面会用expand_dim广播成对应的矩阵,其默认所有位置的indices都是同一个值。
而在nanquantitle
中计算indices
前的sum
的参数keepdim=True,本身就是形状正确的矩阵,修改后的quantile
也同样需要一个indices
矩阵,因为不同的位置indices不同。
这样一来二者之间唯一不同的地方就只有计算indices
了。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Asthestarsfalll 我和 @zoooo0820 @wawltor 讨论下:
- 通过上述思路来修改
quantile
和nanquantile
是可以的,辛苦更新下RFC文档,并同步修改下quantile
相关代码 paddle.sort
修改起来比较麻烦:1维是调用thrust库实现,因此修改的同时要保证性能。我们也给thrust库提了issue在跟进中:sort_by_key
returned bad result when the tensor hadNaN
value NVIDIA/thrust#1637
# 四、对比分析 | ||
|
||
- 使用场景与功能:在维度支持上,Pytorch只支持一维,而Numpy支持多维,这里对齐Numpy的实现逻辑,同时支持一维和多维场景。 | ||
- 实现对比:由于`pytorch.gather`和`paddle.gather`实际在秩大于1时的表现不一致;在出现多个`q`值时,pytorch可直接通过处理后的`indice`进行多维索引,paddle则需要分别索引再组合到一起。因此这里不再使用`paddle.gather`索引,改使用`paddle.take_along_axis`API进行索引。 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- 129行是paddle.quantile分析torch.quantile实现逻辑中下述代码,得到的对比:但本设计文档没有引用这段代码,因此129行可以去掉。
Tensor ranks_below = ranks.toType(kLong);
Tensor values_below = sorted.gather(-1, ranks_below);
// Actual interpolation is only needed for the liner and midpoint modes
if (interpolation == QUANTILE_INTERPOLATION_MODE::LINEAR ||
interpolation == QUANTILE_INTERPOLATION_MODE::MIDPOINT) {
// calculate weights for linear and midpoint
Tensor weights = interpolation == QUANTILE_INTERPOLATION_MODE::MIDPOINT
? at::full_like(ranks, 0.5)
: ranks - ranks_below;
// Interpolate to compute quantiles and store in values_below
Tensor ranks_above = ranks.ceil_().toType(kLong);
Tensor values_above = sorted.gather(-1, ranks_above);
values_below.lerp_(values_above, weights);
- 对比设计可以更注重在是否要最大化的共用已有的代码逻辑,如torch.quantile和torch.nanquantile共用了代码,torch.nanquantile只是新增了对NaN的处理
|
||
API设计为`paddle.unquantile(x, q, axis=None, keepdim=False, name=None)`及`paddle.Tensor.unquantile(q, axis=None, keepdim=False, name=None)` | ||
命名与参数顺序为:形参名`input`->`x`和`dim`->`axis`, 与paddle其他API保持一致性,不影响实际功能使用。 | ||
参数类型中,`axis`支持`int`与`1-D Tensor`输入,以同时支持一维和多维的场景。 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
输入,(英文逗号要改成中文),全文还有多处
5. 根据`keepdim`参数,确定是否需要对应调整结果的shape; | ||
5. 将结果中的`Inf`再替换回`NaN`,输出即可。 | ||
|
||
- 如果后续版本`paddle.sort`支持将NaN排序到最后,即可将两次`NaN`和`Inf`的转化取消。 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- 根据上面的对比分析,明确是否要和quantile最大化的共用代码逻辑
- 如果是的话,需要区分哪些是已有quantile的逻辑,哪些是新增的,这样更加清晰。即写明专门处理NaN的逻辑是哪些
- 可以对quantile的python端代码进行修改,更加模块化,便于nanquantile的复用。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
感谢对paddle.sort不能支持nan的发现和提议!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
即可将两次
NaN
和Inf
的转化取消。
即可将第一步和第十步的两次NaN
和Inf
的转化取消
|
||
## API实现方案 | ||
|
||
主要按下列步骤进行组合实现, 实现位置为`paddle/tensor/stat.py`与`mean`,`median`等方法放在一起: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
与quantile
放在一起更加合理
|
||
# 八、影响面 | ||
|
||
为独立新增API,对其他模块没有影响。 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
可以对quantile的python端代码进行修改,更加模块化,便于nanquantile的复用。
这样对quantile可能有影响。
你的PR有最新反馈,请及时修改。 |
@luotao1
|
可以将各种方案的考虑都写入RFC文档,然后选择第一种方案实现「将NaN替换为-Inf,排序时将会排在最前面」。 |
已修改,最终选择了方案二,后续可直接去除 |
# 四、对比分析 | ||
|
||
- 使用场景与功能:在维度支持上,Pytorch只支持一维,而Numpy支持多维,这里对齐Numpy的实现逻辑,同时支持一维和多维场景。 | ||
- 代码复用:Pytorch与Numpy都是针对输入 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
129行是没写完么?
|
||
1. 对`mask`使用`paddle.logical_not`取反,在指定维度上求和,得到每个位置上的有效数字的个数,这是一个矩阵; | ||
|
||
2. 对替换后的tensor使用`paddle.sort`,因为`sort`不能对含有`NaN`的输入进行正确排序; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
因为
sort
不能对含有NaN
的输入进行正确排序;
- 这句应该放在150行后面,用来解释为什么要替换成Inf。放在154行后面不太通顺
- 对替换后的tensor-》对第一步替换后的tensor,因为用的不是第二步的输出
|
||
2. 对替换后的tensor使用`paddle.sort`,因为`sort`不能对含有`NaN`的输入进行正确排序; | ||
|
||
2. 使用上述**有效数字矩阵**-1乘以`q`:[0, 1]得到`indices`:[-1, dim_wo_nan-1]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- 有效数字矩阵-》第二步的有效数字矩阵
-1
是指什么呢
5. 根据`keepdim`参数,确定是否需要对应调整结果的shape; | ||
5. 将结果中的`Inf`再替换回`NaN`,输出即可。 | ||
|
||
- 如果后续版本`paddle.sort`支持将NaN排序到最后,即可将两次`NaN`和`Inf`的转化取消。 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
即可将两次
NaN
和Inf
的转化取消。
即可将第一步和第十步的两次NaN
和Inf
的转化取消
已全部修改 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM,关于paddle.sort不能处理nan的问题,已经在修复中了。PaddlePaddle/Paddle#41070 可以等该PR merge后(预计这周内merge)再调整下实现方案。
@Asthestarsfalll PaddlePaddle/Paddle#41070 关于paddle.sort在CPU上不能支持NAN的问题,已经修复了。你可以拉一下develop验证下,然后修改下设计文档。有任何问题请随时联系我们 |
感谢如此及时的修复!晚点我会验证并修改。 |
已经看到修改后的RFC文档了,如果验证成功请在评论区告知 |
抱歉,刚刚看到,已经验证成功了! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
为paddle新增 nanquantile