数学表达式#

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()boolintfloat 类型的常规 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 代表任何一种支持的数值类型:boolint8int16int32int64uint8uint16uint32uint64float32float64

bool 类型被认为是最小的无符号整数类型,并且相对于上表被视为 uint1

注意

类型提升是可交换的。

对于两个以上的参数,结果类型计算为从左到右的归约 - 首先计算前两个参数运算的结果,然后在该中间结果和第三个参数之间进行运算,依此类推,直到只剩下结果类型。

支持的算术运算#

目前,DALI 支持以下运算

一元 算术 运算符: +, -

实现 __pos__(self)__neg__(self) 的一元运算符。一元算术运算的结果始终保留输入类型。一元运算符仅接受来自其他操作符的 TensorList 输入。

返回类型:

相同类型的 TensorList

二元 算术 运算: +, -, *, /, //, **

分别实现 __add____sub____mul____truediv____floordiv____pow__ 的二元运算符。

两个操作数之间的算术运算结果在 上面 进行了描述,但 /,即 __truediv__ 运算除外,它始终返回 float32float64 类型。

注意

两个 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.DataNodenvidia.dali.types.Constant()boolintfloat 类型的常规 Python 值作为参数。输入中至少有一个必须是其他 DALI 操作符的输出。

nvidia.dali.math.abs(input)#

计算 input 中值的绝对值。

返回类型:

abs(input) 的 TensorList。类型被保留。

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.min(left, right)#

计算 leftright 中对应值的最小值。

返回类型:

基于类型提升规则计算的类型的 TensorList。

nvidia.dali.math.max(left, right)#

计算 leftright 中对应值的最大值。

返回类型:

基于类型提升规则计算的类型的 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.log2(input)#

计算 input 中值的对数(底数为 2)。

返回类型:

log2(input) 的 TensorList。如果输入是整数,则结果将为浮点数,否则类型将被保留。

nvidia.dali.math.log10(input)#

计算 input 中值的对数(底数为 10)。

返回类型:

log10(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。如果输入是整数,结果将是浮点数,否则类型保持不变。

nvidia.dali.math.acosh(input)#

计算 input 中值的反双曲余弦。

返回类型:

acosh(input) 的 TensorList。如果输入是整数,结果将是浮点数,否则类型保持不变。

nvidia.dali.math.atanh(input)#

计算 input 中值的反双曲正切。

返回类型:

atanh(input) 的 TensorList。如果输入是整数,结果将是浮点数,否则类型保持不变。