数学表达式#
DALI 允许您在 pipeline 定义中使用常规 Python 算术运算 和其他 数学函数 (通过 @pipeline_def
或在 define_graph()
中),对从调用其他操作符返回的值进行操作。
所使用的表达式将被整合到 pipeline 中,而无需显式实例化操作符,并将描述张量上的元素级运算
@pipeline_def
def my_pipeline():
"""Create a pipeline which reads and decodes the images, scales channels by
broadcasting and clamps the result to [128, 255) range."""
img_files, _ = fn.readers.file(file_root="image_dir")
images = fn.decoders.image(img_files, device="mixed")
red_highlight = images * nvidia.dali.types.Constant(np.float32([1.25, 0.75, 0.75]))
result = nvidia.dali.math.clamp(red_highlight, 128, 255)
return result
算术表达式的输入中,至少要有一个是由其他 DALI 操作符返回的 - 即表示一批张量的 nvidia.dali.pipeline.DataNode
类型的值。另一个输入可以是 nvidia.dali.types.Constant()
或 bool
、int
或 float
类型的常规 Python 值。由于执行的操作是元素级的,因此所有操作数的形状必须兼容 - 要么完全匹配,要么是 可广播的。
有关详细信息和示例,请参阅 表达式教程。
注意
请记住,用 nvidia.dali.types.Constant()
包装数学表达式中使用的张量常量(如 NumPy 数组)。如果直接使用,可能会选取该张量库中的操作符实现,并且结果可能未定义。使用前面示例中的行,前两个变体是等效的,而第三个是错误的
# Correct approach:
red_highlight_0 = images *
nvidia.dali.types.Constant(np.float32([1.25, 0.75, 0.75]))
red_highlight_1 = nvidia.dali.types.Constant(np.float32([1.25, 0.75, 0.75])) *
images
# Wrong approach:
# red_highlight_2 = np.float32([1.25, 0.75, 0.75]) * images
类型提升规则#
对于接受两个(或更多)参数的操作,适用类型提升。结果类型根据下表计算。
操作数类型
操作数类型
结果类型
附加条件
T
T
T
floatX
T
floatX
其中 T 不是浮点数
floatX
floatY
floatZ
其中 Z = max(X, Y)
intX
intY
intZ
其中 Z = max(X, Y)
uintX
uintY
uintZ
其中 Z = max(X, Y)
intX
uintY
int2Y
如果 X <= Y
intX
uintY
intX
如果 X > Y
T
代表任何一种支持的数值类型:bool
、int8
、int16
、int32
、int64
、uint8
、uint16
、uint32
、uint64
、float32
和 float64
。
bool
类型被认为是最小的无符号整数类型,并且相对于上表被视为 uint1
。
注意
类型提升是可交换的。
对于两个以上的参数,结果类型计算为从左到右的归约 - 首先计算前两个参数运算的结果,然后在该中间结果和第三个参数之间进行运算,依此类推,直到只剩下结果类型。
支持的算术运算#
目前,DALI 支持以下运算
- 一元 算术 运算符: +, -
实现
__pos__(self)
和__neg__(self)
的一元运算符。一元算术运算的结果始终保留输入类型。一元运算符仅接受来自其他操作符的 TensorList 输入。- 返回类型:
相同类型的 TensorList
- 二元 算术 运算: +, -, *, /, //, **
分别实现
__add__
、__sub__
、__mul__
、__truediv__
、__floordiv__
和__pow__
的二元运算符。两个操作数之间的算术运算结果在 上面 进行了描述,但
/
,即__truediv__
运算除外,它始终返回float32
或float64
类型。注意
两个
bool
值之间唯一允许的算术运算是乘法(*)
。- 返回类型:
基于类型提升规则计算的类型的 TensorList。
- 比较 运算: ==, !=, <, <=, >, >=
比较运算。
- 返回类型:
bool
类型的 TensorList。
- 按位 二元 运算: &, |, ^
按位二元运算遵循与算术二元运算相同的类型提升规则,但它们的输入仅限于整数类型(包括
bool
)。注意
按位运算可以应用于两个布尔输入。这些运算可以用于模拟张量上的元素级逻辑运算。
- 返回类型:
基于类型提升规则计算的类型的 TensorList。
广播#
术语“广播”指的是在数学表达式中如何处理不同形状的张量。来自较小张量的值被“广播”,因此它有助于多个输出值。最简单的情况是,标量值被广播到所有输出值。在更复杂的情况下,如果其中一个操作数的大小为 1,而另一个操作数较大,则值可以沿着某些维度广播
[[D, E], [[ A+D, B+E ],
[[A, B]] + [F, G], == [ A+F, B+G ],
[H, J]] [ A+H, B+J ]]
在上面的示例中,操作数的形状为 (1, 2) 和 (3, 2)。来自数组 [[A, B]] 的值沿着轴 0 广播。两个操作数都可能沿着不同的维度进行广播
[[D], [[ A+D, B+D ],
[[A, B ]] + [E], == [ A+E, B+E ],
[F]] [ A+F, B+F ]]
在此示例中,形状为 (1, 2) 和 (3, 1) - 第一个操作数沿轴 0 广播,第二个操作数沿轴 1 广播。
形状扩展#
为方便起见,如果数组具有不同数量的维度,则形状会用外部单位维度进行填充
shape of A == (480, 640, 3)
shape of B == (3)
shape of A + B == (480, 640, 3) # b is treated as if it was shaped (1, 1, 3)
局限性#
DALI 中的广播运算只能具有有限的复杂性。进行广播时,需要或不需要广播的相邻轴会分组。最多可以有六个交替的广播/非广播组。分组示例
shape of A == a, b, 1, c, d
shape of B == a, b, e, 1, 1
grouping dimensions (0..1) and (3..4)
grouped shapes:
a*b, 1, c*d
a*b, e, 1
数学函数#
与算术表达式类似,可以在 Pipeline 图定义中使用选定的数学函数。它们也接受 nvidia.dali.pipeline.DataNode
、nvidia.dali.types.Constant()
或 bool
、int
或 float
类型的常规 Python 值作为参数。输入中至少有一个必须是其他 DALI 操作符的输出。
- nvidia.dali.math.fabs(input)#
计算
input
中值的浮点绝对值。- 返回类型:
fabs(input) 的 TensorList。如果输入是整数,则结果将为浮点数,否则类型将被保留。
- nvidia.dali.math.floor(input)#
计算
input
中值的向下取整值。- 返回类型:
floor(input) 的 TensorList。如果输入是整数,则结果将为浮点数,否则类型将被保留。
- nvidia.dali.math.ceil(input)#
计算
input
中值的向上取整值。- 返回类型:
ceil(input) 的 TensorList。如果输入是整数,则结果将为浮点数,否则类型将被保留。
- nvidia.dali.math.pow(base, exponent)#
计算底数的指数幂,即 base ** exponent。
- 返回类型:
pow(base, exponent) 的 TensorList。类型根据类型提升规则计算。
- nvidia.dali.math.fpow(base, exponent)#
将底数计算为指数的浮点数幂。
- 返回类型:
pow(base, exponent) 的 TensorList。如果所有输入都是整数,则结果将为浮点数,否则类型将被保留。
- nvidia.dali.math.clamp(value, lo, hi)#
生成一个张量,其值来自
value
,并被限制在范围[lo, hi]
内。- 返回类型:
基于类型提升规则计算的类型的 TensorList。
指数和对数#
- nvidia.dali.math.sqrt(input)#
计算
input
中值的平方根。- 返回类型:
sqrt(input) 的 TensorList。如果输入是整数,则结果将为浮点数,否则类型将被保留。
- nvidia.dali.math.rsqrt(input)#
计算
input
中值的平方根的倒数。- 返回类型:
rsqrt(input) 的 TensorList。如果输入是整数,则结果将为浮点数,否则类型将被保留。
- nvidia.dali.math.cbrt(input)#
计算
input
中值的立方根。- 返回类型:
cbrt(input) 的 TensorList。如果输入是整数,则结果将为浮点数,否则类型将被保留。
- nvidia.dali.math.exp(input)#
计算
input
中值的指数。- 返回类型:
exp(input) 的 TensorList。如果输入是整数,则结果将为浮点数,否则类型将被保留。
- nvidia.dali.math.log(input)#
计算
input
中值的自然对数(底数为 e)。- 返回类型:
log(input) 的 TensorList。如果输入是整数,则结果将为浮点数,否则类型将被保留。
三角函数#
- nvidia.dali.math.sin(input)#
计算
input
中值的正弦值。- 返回类型:
sin(input) 的 TensorList。如果输入是整数,则结果将为浮点数,否则类型将被保留。
- nvidia.dali.math.cos(input)#
计算
input
中值的余弦值。- 返回类型:
cos(input) 的 TensorList。如果输入是整数,则结果将为浮点数,否则类型将被保留。
- nvidia.dali.math.tan(input)#
计算
input
中值的正切值。- 返回类型:
tan(input) 的 TensorList。如果输入是整数,则结果将为浮点数,否则类型将被保留。
- nvidia.dali.math.asin(input)#
计算
input
中值的反正弦值。- 返回类型:
asin(input) 的 TensorList。如果输入是整数,则结果将为浮点数,否则类型将被保留。
- nvidia.dali.math.acos(input)#
计算
input
中值的反余弦。- 返回类型:
acos(input) 的 TensorList。如果输入是整数,结果将是浮点数,否则类型保持不变。
- nvidia.dali.math.atan(input)#
计算
input
中值的反正切。- 返回类型:
atan(input) 的 TensorList。如果输入是整数,结果将是浮点数,否则类型保持不变。
- nvidia.dali.math.atan2(x, y)#
计算 x / y 中对应值的反正切。
- 返回类型:
atan2(x, y) 的 TensorList。如果所有输入都是整数,结果将是浮点数,否则类型保持不变。
双曲函数#
- nvidia.dali.math.sinh(input)#
计算
input
中值的双曲正弦。- 返回类型:
sinh(input) 的 TensorList。如果输入是整数,结果将是浮点数,否则类型保持不变。
- nvidia.dali.math.cosh(input)#
计算
input
中值的双曲余弦。- 返回类型:
cosh(input) 的 TensorList。如果输入是整数,结果将是浮点数,否则类型保持不变。
- nvidia.dali.math.tanh(input)#
计算
input
中值的双曲正切。- 返回类型:
tanh(input) 的 TensorList。如果输入是整数,结果将是浮点数,否则类型保持不变。
- nvidia.dali.math.asinh(input)#
计算
input
中值的反双曲正弦。- 返回类型:
asinh(input) 的 TensorList。如果输入是整数,结果将是浮点数,否则类型保持不变。