数学表达式#
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 值。由于执行的操作是元素级的,因此所有操作数的形状必须兼容 - 要么完全匹配,要么是 可广播的。
有关详细信息和示例,请参阅 表达式教程。
注意
请记住将数学表达式中使用的张量常量(如 NumPy 数组)用 nvidia.dali.types.Constant()
包裹起来。如果直接使用,则可能会选取该张量库中的操作符实现,并且结果可能未定义。使用前面示例中的行,前两个变体是等效的,而第三个变体将是错误的
# 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
where T is not a float
floatX
floatY
floatZ
where Z = max(X, Y)
intX
intY
intZ
where Z = max(X, Y)
uintX
uintY
uintZ
where Z = max(X, Y)
intX
uintY
int2Y
if X <= Y
intX
uintY
intX
if 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。如果 input 是整数,结果将为浮点数,否则类型将保留。
- nvidia.dali.math.cos(input)#
计算
input
中值的余弦值。- 返回类型:
cos(input) 的 TensorList。如果 input 是整数,结果将为浮点数,否则类型将保留。
- nvidia.dali.math.tan(input)#
计算
input
中值的正切值。- 返回类型:
tan(input) 的 TensorList。如果 input 是整数,结果将为浮点数,否则类型将保留。
- nvidia.dali.math.asin(input)#
计算
input
中值的反正弦值。- 返回类型:
asin(input) 的 TensorList。如果 input 是整数,结果将为浮点数,否则类型将保留。
- nvidia.dali.math.acos(input)#
计算
input
中值的反余弦值。- 返回类型:
acos(input) 的 TensorList。如果 input 是整数,结果将为浮点数,否则类型将保留。
- nvidia.dali.math.atan(input)#
计算
input
中值的反正切值。- 返回类型:
atan(input) 的 TensorList。如果 input 是整数,结果将为浮点数,否则类型将保留。
- nvidia.dali.math.atan2(x, y)#
计算 x / y 中对应值的反正切值。
- 返回类型:
atan2(x, y) 的 TensorList。如果所有输入都是整数,结果将为浮点数,否则类型将保留。
双曲函数#
- nvidia.dali.math.sinh(input)#
计算
input
中值的双曲正弦值。- 返回类型:
sinh(input) 的 TensorList。如果 input 是整数,结果将为浮点数,否则类型将保留。
- nvidia.dali.math.cosh(input)#
计算
input
中值的双曲余弦值。- 返回类型:
cosh(input) 的 TensorList。如果 input 是整数,结果将为浮点数,否则类型将保留。
- nvidia.dali.math.tanh(input)#
计算
input
中值的双曲正切值。- 返回类型:
tanh(input) 的 TensorList。如果 input 是整数,结果将为浮点数,否则类型将保留。
- nvidia.dali.math.asinh(input)#
计算
input
中值的反双曲正弦值。- 返回类型:
asinh(input) 的 TensorList。如果 input 是整数,结果将为浮点数,否则类型将保留。