Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
MegEngine 天元
MegEngine
提交
08ac685e
MegEngine
项目概览
MegEngine 天元
/
MegEngine
大约 1 年 前同步成功
通知
399
Star
4705
Fork
582
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
MegEngine
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
提交
08ac685e
编写于
6月 10, 2020
作者:
M
Megvii Engine Team
提交者:
Xu Xinran
6月 19, 2020
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
feat(mge/functional): add logsumexp
GitOrigin-RevId: e7ef50e9ece3ba6f71f5fe23c9a81ce9ccd0dc60
上级
65ec4f7c
变更
4
显示空白变更内容
内联
并排
Showing
4 changed file
with
134 addition
and
9 deletion
+134
-9
python_module/megengine/functional/__init__.py
python_module/megengine/functional/__init__.py
+13
-1
python_module/megengine/functional/math.py
python_module/megengine/functional/math.py
+37
-2
python_module/megengine/test/__init__.py
python_module/megengine/test/__init__.py
+29
-5
python_module/test/unit/functional/test_math.py
python_module/test/unit/functional/test_math.py
+55
-1
未找到文件。
python_module/megengine/functional/__init__.py
浏览文件 @
08ac685e
...
...
@@ -50,7 +50,19 @@ from .loss import (
square_loss
,
triplet_margin_loss
,
)
from
.math
import
argmax
,
argmin
,
max
,
mean
,
min
,
norm
,
normalize
,
prod
,
sqrt
,
sum
from
.math
import
(
argmax
,
argmin
,
logsumexp
,
max
,
mean
,
min
,
norm
,
normalize
,
prod
,
sqrt
,
sum
,
)
from
.nn
import
(
assert_equal
,
avg_pool2d
,
...
...
python_module/megengine/functional/math.py
浏览文件 @
08ac685e
...
...
@@ -6,12 +6,15 @@
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT ARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
from
typing
import
Optional
import
math
import
numbers
from
typing
import
Optional
,
Sequence
,
Union
import
megengine._internal
as
mgb
from
..core
import
Tensor
,
wrap_io_tensor
from
.elemwise
import
clamp
from
.elemwise
import
clamp
,
exp
,
isinf
,
log
from
.tensor
import
remove_axis
,
where
,
zeros_like
@
wrap_io_tensor
...
...
@@ -296,3 +299,35 @@ def normalize(
return
inp
/
clamp
(
norm
(
inp
,
p
),
lower
=
eps
)
else
:
return
inp
/
clamp
(
norm
(
inp
,
p
,
axis
,
keepdims
=
True
),
lower
=
eps
)
def
logsumexp
(
inp
:
Tensor
,
axis
:
Union
[
int
,
Sequence
[
int
]],
keepdims
:
bool
=
False
):
r
"""
Compute the log of the sum of exponentials of inputs along the given :attr:`axis`. The computation is numerically stabilized.
.. math::
\mathsf{logsumexp}(x_1, \dots, x_n) = \log(\exp(x_1) + \cdots + \exp(x_n))
:param inp: The input tensor.
:param axis: Axis over which the sum is taken. It can be a single axis or a list of axes.
:param keepdims: whether to retain :attr:`axis` or not for the output tensor.
"""
if
isinstance
(
axis
,
numbers
.
Integral
):
axis
=
(
axis
,)
max_value
=
inp
for
dim
in
axis
:
max_value
=
max_value
.
max
(
axis
=
dim
,
keepdims
=
True
)
max_value
=
where
(
isinf
(
max_value
).
astype
(
"int32"
),
zeros_like
(
max_value
),
max_value
)
x
=
exp
(
inp
-
max_value
)
for
dim
in
axis
:
x
=
x
.
sum
(
axis
=
dim
,
keepdims
=
True
)
x
=
max_value
+
log
(
x
)
if
not
keepdims
:
axis
=
sorted
(
axis
,
reverse
=
True
)
for
i
in
axis
:
x
=
remove_axis
(
x
,
axis
=
i
)
return
x
python_module/megengine/test/__init__.py
浏览文件 @
08ac685e
...
...
@@ -9,9 +9,12 @@
import
numpy
as
np
def
assertTensorClose
(
v0
,
v1
,
*
,
max_err
=
1e-6
,
name
=
None
):
def
assertTensorClose
(
v0
,
v1
,
*
,
max_err
:
float
=
1e-6
,
allow_special_values
:
bool
=
False
,
name
=
None
):
"""
max_err: relative error
:param allow_special_values: whether to allow :attr:`v0` and :attr:`v1` to contain inf and nan values.
:param max_err: relative error
"""
__tracebackhide__
=
True
# pylint: disable=unused-variable
...
...
@@ -20,9 +23,30 @@ def assertTensorClose(v0, v1, *, max_err=1e-6, name=None):
),
"Two Tensor must have same dtype, but the inputs are {} and {}"
.
format
(
v0
.
dtype
,
v1
.
dtype
)
v0
=
np
.
ascontiguousarray
(
v0
,
dtype
=
np
.
float32
)
v1
=
np
.
ascontiguousarray
(
v1
,
dtype
=
np
.
float32
)
v0
=
np
.
ascontiguousarray
(
v0
,
dtype
=
np
.
float32
).
copy
()
v1
=
np
.
ascontiguousarray
(
v1
,
dtype
=
np
.
float32
).
copy
()
if
allow_special_values
:
# check nan and rm it
v0_nan_mask
=
np
.
isnan
(
v0
)
if
np
.
any
(
v0_nan_mask
):
assert
np
.
array_equiv
(
v0_nan_mask
,
np
.
isnan
(
v1
)),
(
v0
,
v1
)
v0
[
v0_nan_mask
]
=
0
v1
[
v0_nan_mask
]
=
0
# check inf and rm it
v0_inf_mask
=
v0
==
float
(
"inf"
)
if
np
.
any
(
v0_inf_mask
):
assert
np
.
array_equiv
(
v0_inf_mask
,
v1
==
float
(
"inf"
)),
(
v0
,
v1
)
v0
[
v0_inf_mask
]
=
0
v1
[
v0_inf_mask
]
=
0
# check -inf and rm it
v0_inf_mask
=
v0
==
float
(
"-inf"
)
if
np
.
any
(
v0_inf_mask
):
assert
np
.
array_equiv
(
v0_inf_mask
,
v1
==
float
(
"-inf"
)),
(
v0
,
v1
)
v0
[
v0_inf_mask
]
=
0
v1
[
v0_inf_mask
]
=
0
else
:
assert
np
.
isfinite
(
v0
.
sum
())
and
np
.
isfinite
(
v1
.
sum
()),
(
v0
,
v1
)
assert
v0
.
shape
==
v1
.
shape
,
"Two tensor must have same shape({} v.s. {})"
.
format
(
v0
.
shape
,
v1
.
shape
)
...
...
python_module/test/unit/functional/test_math.py
浏览文件 @
08ac685e
...
...
@@ -6,10 +6,14 @@
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT ARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
from
functools
import
partial
import
numpy
as
np
from
helpers
import
opr_test
import
megengine.functional
as
F
from
megengine.test
import
assertTensorClose
def
common_test_reduce
(
opr
,
ref_opr
):
...
...
@@ -86,7 +90,6 @@ def test_sqrt():
def
test_normalize
():
from
functools
import
partial
cases
=
[
{
"input"
:
np
.
random
.
random
((
2
,
3
,
12
,
12
)).
astype
(
np
.
float32
)}
for
i
in
range
(
2
)
...
...
@@ -112,3 +115,54 @@ def test_normalize():
cases
[
0
][
"input"
][
0
,
0
,
0
,
:]
=
0
cases
[
1
][
"input"
][
0
,
0
,
0
,
:]
=
0
opr_test
(
cases
,
partial
(
F
.
normalize
,
axis
=
3
),
ref_fn
=
partial
(
np_normalize
,
axis
=
3
))
def
test_logsumexp
():
x
=
np
.
arange
(
10
).
astype
(
np
.
float32
)
expected
=
np
.
log
(
np
.
sum
(
np
.
exp
(
x
)))
cases
=
[{
"input"
:
x
,
"output"
:
expected
}]
compare_fn
=
partial
(
assertTensorClose
,
allow_special_values
=
True
)
# large value check
n
=
100
x
=
np
.
full
(
n
,
10000
,
dtype
=
np
.
float32
)
expected
=
10000
+
np
.
log
(
n
)
cases
.
append
({
"input"
:
x
,
"output"
:
expected
.
astype
(
np
.
float32
)})
opr_test
(
cases
,
F
.
logsumexp
,
axis
=
0
,
compare_fn
=
compare_fn
)
# special value check
x
=
np
.
array
([
np
.
inf
],
dtype
=
np
.
float32
)
expected
=
x
cases
=
[{
"input"
:
x
,
"output"
:
expected
}]
x
=
np
.
array
([
-
np
.
inf
,
0.0
],
dtype
=
np
.
float32
)
expected
=
np
.
zeros
(
1
).
astype
(
np
.
float32
)
cases
.
append
({
"input"
:
x
,
"output"
:
expected
})
opr_test
(
cases
,
F
.
logsumexp
,
axis
=
0
,
compare_fn
=
compare_fn
)
x
=
np
.
array
([
np
.
nan
],
dtype
=
np
.
float32
)
expected
=
x
cases
=
[{
"input"
:
x
,
"output"
:
expected
}]
x
=
np
.
array
([
-
np
.
inf
,
1
],
dtype
=
np
.
float32
)
expected
=
np
.
array
([
1.0
],
dtype
=
np
.
float32
)
cases
.
append
({
"input"
:
x
,
"output"
:
expected
})
opr_test
(
cases
,
F
.
logsumexp
,
axis
=
0
,
compare_fn
=
compare_fn
)
# keepdims check
x
=
np
.
array
([[
1e10
,
1e-10
],
[
-
1e10
,
-
np
.
inf
]],
dtype
=
np
.
float32
)
expected
=
np
.
array
([[
1e10
],
[
-
1e10
]],
dtype
=
np
.
float32
)
cases
=
[{
"input"
:
x
,
"output"
:
expected
}]
x
=
np
.
array
([[
1e10
,
-
1e-10
,
1e-10
],
[
1e10
,
1e-10
,
np
.
inf
]],
dtype
=
np
.
float32
)
expected
=
np
.
array
([[
1e10
],
[
np
.
inf
]],
dtype
=
np
.
float32
)
cases
.
append
({
"input"
:
x
,
"output"
:
expected
})
opr_test
(
cases
,
F
.
logsumexp
,
axis
=
1
,
keepdims
=
True
,
compare_fn
=
compare_fn
)
# multiple axes check
x
=
np
.
array
([[
1e10
,
1e-10
],
[
-
1e10
,
-
np
.
inf
]],
dtype
=
np
.
float32
)
expected
=
np
.
array
([
1e10
],
dtype
=
np
.
float32
)
cases
=
[{
"input"
:
x
,
"output"
:
expected
}]
x
=
np
.
array
([[
1e10
,
-
1e-10
,
1e-10
],
[
1e10
,
1e-10
,
np
.
inf
]],
dtype
=
np
.
float32
)
expected
=
np
.
array
([
np
.
inf
],
dtype
=
np
.
float32
)
cases
.
append
({
"input"
:
x
,
"output"
:
expected
})
opr_test
(
cases
,
F
.
logsumexp
,
axis
=
(
0
,
1
),
keepdims
=
False
,
compare_fn
=
compare_fn
)
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录