Loop

Loop - 24

版本

  • 名称Loop (GitHub)

  • : main

  • 起始版本24

  • 函数: False

  • 支持级别: SupportType.COMMON

  • 形状推断: True

此版本的操作符已可用于版本 24 及以上

摘要

通用循环结构。此循环具有多个终止条件

  1. 循环次数。在运行时指定的迭代次数。通过指定输入 M 设置。可选。设置为空字符串表示省略。请注意,可以通过为输入 M 传入一个常量节点来指定静态循环次数(在图构建时指定)。

  2. 循环终止条件。这是操作符的输入,用于确定是否运行第一次迭代,也是主体图的循环依赖。无论是否提供此输入,主体图都必须为条件变量生成一个值。

此表总结了此操作符的操作模式,并附带等效的 C 风格代码

操作符输入定义为 (max_trip_count, condition_var)。

  • 输入 (“”, “”): for (int i=0; ; ++i) { cond = … // 注意此值被忽略,但在主体中是必需的 }

  • 输入 (“”, cond) // 注意这类似于 while 循环 bool cond = …; for (int i=0; cond; ++i) { cond = …; }

  • 输入 (“”, 1) // 注意这类似于 do-while 循环 bool cond = true for (int i=0; cond; ++i) { cond = …; }

  • 输入 (trip_count, “”) // 注意这类似于 for 循环 int trip_count = … for (int i=0; i < trip_count; ++i) { cond = …; // 忽略 }

  • 输入 (trip_count, cond) int trip_count = …; bool cond = …; for (int i=0; i < trip_count && cond; ++i) { cond = …; }

使用示例 - 条件和循环次数

graph predict-net {
  %a = Constant[value = <Scalar Tensor [3]>]()
  %b = Constant[value = <Scalar Tensor [6]>]()
  %keepgoing = Constant[value = <Scalar Tensor [1]>]()
  %max_trip_count = Constant[value = <Scalar Tensor [10]>]()
  %keepgoing_out, %b_out, %user_defined_vals = Loop[body = <graph body-net>](%max_trip_count, %keepgoing, %b)
  return
}

graph body-net (
  %i[INT32, scalar]           // iteration number
  %keepgoing_in[BOOL, scalar] // incoming loop-termination-condition; not used
  %b_in[INT32, scalar]        // incoming value of loop-carried-dependency b
) {
  %my_local = Add(%a, %b_in)
  %b_out = Sub(%a, %b_in) // outgoing value of loop-carried-dependency b
  %keepgoing_out = Greater(%my_local, %b_out) // outgoing loop-termination-condition
  %user_defined_val = Add(%b_in, %b_in) // scan-output value to be accumulated
  return %keepgoing_out, %b_out, %user_defined_val
}

等效 C 代码示例

{
  /* User-defined code (enclosing scope) */
  int a = 3, b = 6;
  bool keepgoing = true; // Analogous to input cond
  /* End user-defined code */

  /* Implicitly-defined code */
  const int max_trip_count = 10; // Analogous to input M
  int user_defined_vals[]; // Imagine this is resizable
  /* End implicitly-defined code */
  /* initialize loop-carried variables and scan-output variables */
  bool keepgoing_out = keepgoing
  int b_out = b

  for (int i=0; i < max_trip_count && keepgoing_out; ++i) {
    /* Implicitly-defined code: bind actual parameter values
       to formal parameter variables of loop-body */
    bool keepgoing_in = keepgoing_out;
    bool b_in = b_out;

    /* User-defined code (loop body) */
    int my_local = a + b_in; // Reading value "a" from the enclosing scope is fine
    b_out = a - b_in;
    keepgoing_out = my_local > b_out;
    user_defined_val = b_in + b_in; // b_in and b_out are different variables
    /* End user-defined code */

    /* Implicitly defined-code */
    user_defined_vals[i] = user_defined_val // accumulate scan-output values
  }
  // int t = my_local; // Can't do this. my_local is not accessible here.

  // The values below are bound to the output variables of the loop and therefore accessible
  // b_out; user_defined_vals; keepgoing_out;
}

此代码片段有几点值得注意

  1. 来自封闭作用域的值(即此处的变量“a”)在作用域内,可以在循环的输入中引用。

  2. 在循环体中计算的任何需要在后续迭代或循环后使用的值,通过循环体中的一对变量来建模,包括一个输入变量(例如 b_in)和一个输出变量(例如 b_out)。这些被称为循环依赖。循环操作节点为第一次迭代提供输入变量的输入值,并返回最终迭代生成的输出变量的输出值。

  3. Scan_output 变量用于隐式连接所有迭代中计算的值。在上述示例中,所有迭代中计算的 user_defined_val 的值被连接起来,并在循环后作为 user_defined_vals 的值返回。

  4. 在主体中创建的值不能在封闭作用域中访问,除非使用上述机制。

请注意,此操作符的语义支持“对角线”或“波前”执行。(有关示例,请参见此处第 3 步:https://devblogs.nvidia.com/optimizing-recurrent-neural-networks-cudnn-5/)。前端应将多层 RNN 发射为一系列 While 操作符(时间作为内部循环维度),每个后续层消耗前一层的 scan_outputs,可能通过几个逐点操作符(例如 dropout、残差连接、线性层)。

子图(由循环节点产生)的输入/输出匹配是基于顺序而不是名称。实现将根据此顺序确定名称。

属性

  • body - GRAPH (必需)

    每次迭代运行的图。它有 2+N 个输入:(迭代次数、条件、循环依赖…)。它有 1+N+K 个输出:(条件、循环依赖…、scan_outputs…)。每个 scan_output 是通过连接循环每次迭代结束时指定输出值的值而创建的。如果这些 scan_outputs 的维度或数据类型在循环迭代中发生变化,则会出错。

输入

2 到 2147483647 个输入之间。

  • M (可选,异构) - I

    在运行时指定的循环最大循环次数。可选。传入空字符串以跳过。

  • cond (可选,异构) - B

    布尔终止条件。可选。传入空字符串以跳过。

  • v_initial (可变参数) - V

    任何循环依赖(在循环迭代中更改的值)的初始值

输出

1 到 2147483647 个输出之间。

  • v_final_and_scan_outputs (可变参数) - V

    最终 N 个循环依赖值,然后是 K 个 scan_outputs。扫描输出必须是张量。

类型约束

  • V 在 ( optional(seq(tensor(bfloat16))), optional(seq(tensor(bool))), optional(seq(tensor(complex128))), optional(seq(tensor(complex64))), optional(seq(tensor(double))), optional(seq(tensor(float))), optional(seq(tensor(float16))), optional(seq(tensor(int16))), optional(seq(tensor(int32))), optional(seq(tensor(int64))), optional(seq(tensor(int8))), optional(seq(tensor(string))), optional(seq(tensor(uint16))), optional(seq(tensor(uint32))), optional(seq(tensor(uint64))), optional(seq(tensor(uint8))), optional(tensor(bfloat16)), optional(tensor(bool)), optional(tensor(complex128)), optional(tensor(complex64)), optional(tensor(double)), optional(tensor(float)), optional(tensor(float16)), optional(tensor(float4e2m1)), optional(tensor(float8e4m3fn)), optional(tensor(float8e4m3fnuz)), optional(tensor(float8e5m2)), optional(tensor(float8e5m2fnuz)), optional(tensor(float8e8m0)), optional(tensor(int16)), optional(tensor(int32)), optional(tensor(int4)), optional(tensor(int64)), optional(tensor(int8)), optional(tensor(string)), optional(tensor(uint16)), optional(tensor(uint32)), optional(tensor(uint4)), optional(tensor(uint64)), optional(tensor(uint8)), seq(tensor(bfloat16)), seq(tensor(bool)), seq(tensor(complex128)), seq(tensor(complex64)), seq(tensor(double)), seq(tensor(float)), seq(tensor(float16)), seq(tensor(float4e2m1)), seq(tensor(float8e4m3fn)), seq(tensor(float8e4m3fnuz)), seq(tensor(float8e5m2)), seq(tensor(float8e5m2fnuz)), seq(tensor(float8e8m0)), seq(tensor(int16)), seq(tensor(int32)), seq(tensor(int4)), seq(tensor(int64)), seq(tensor(int8)), seq(tensor(string)), seq(tensor(uint16)), seq(tensor(uint32)), seq(tensor(uint4)), seq(tensor(uint64)), seq(tensor(uint8)), tensor(bfloat16), tensor(bool), tensor(complex128), tensor(complex64), tensor(double), tensor(float), tensor(float16), tensor(float4e2m1), tensor(float8e4m3fn), tensor(float8e4m3fnuz), tensor(float8e5m2), tensor(float8e5m2fnuz), tensor(float8e8m0), tensor(int16), tensor(int32), tensor(int4), tensor(int64), tensor(int8), tensor(string), tensor(uint16), tensor(uint32), tensor(uint4), tensor(uint64), tensor(uint8) )

    所有张量、序列(张量)、可选(张量)和可选(序列(张量))类型,直到 IRv11。

  • I 在 ( tensor(int64) )

    int64 类型的张量,应为标量。

  • B 在 ( tensor(bool) )

    bool 类型的张量,应为标量。

Loop - 23

版本

  • 名称Loop (GitHub)

  • : main

  • 起始版本23

  • 函数: False

  • 支持级别: SupportType.COMMON

  • 形状推断: True

此版本的操作符已可用于版本 23 及以上

摘要

通用循环结构。此循环具有多个终止条件

  1. 循环次数。在运行时指定的迭代次数。通过指定输入 M 设置。可选。设置为空字符串表示省略。请注意,可以通过为输入 M 传入一个常量节点来指定静态循环次数(在图构建时指定)。

  2. 循环终止条件。这是操作符的输入,用于确定是否运行第一次迭代,也是主体图的循环依赖。无论是否提供此输入,主体图都必须为条件变量生成一个值。

此表总结了此操作符的操作模式,并附带等效的 C 风格代码

操作符输入定义为 (max_trip_count, condition_var)。

  • 输入 (“”, “”): for (int i=0; ; ++i) { cond = … // 注意此值被忽略,但在主体中是必需的 }

  • 输入 (“”, cond) // 注意这类似于 while 循环 bool cond = …; for (int i=0; cond; ++i) { cond = …; }

  • 输入 (“”, 1) // 注意这类似于 do-while 循环 bool cond = true for (int i=0; cond; ++i) { cond = …; }

  • 输入 (trip_count, “”) // 注意这类似于 for 循环 int trip_count = … for (int i=0; i < trip_count; ++i) { cond = …; // 忽略 }

  • 输入 (trip_count, cond) int trip_count = …; bool cond = …; for (int i=0; i < trip_count && cond; ++i) { cond = …; }

使用示例 - 条件和循环次数

graph predict-net {
  %a = Constant[value = <Scalar Tensor [3]>]()
  %b = Constant[value = <Scalar Tensor [6]>]()
  %keepgoing = Constant[value = <Scalar Tensor [1]>]()
  %max_trip_count = Constant[value = <Scalar Tensor [10]>]()
  %keepgoing_out, %b_out, %user_defined_vals = Loop[body = <graph body-net>](%max_trip_count, %keepgoing, %b)
  return
}

graph body-net (
  %i[INT32, scalar]           // iteration number
  %keepgoing_in[BOOL, scalar] // incoming loop-termination-condition; not used
  %b_in[INT32, scalar]        // incoming value of loop-carried-dependency b
) {
  %my_local = Add(%a, %b_in)
  %b_out = Sub(%a, %b_in) // outgoing value of loop-carried-dependency b
  %keepgoing_out = Greater(%my_local, %b_out) // outgoing loop-termination-condition
  %user_defined_val = Add(%b_in, %b_in) // scan-output value to be accumulated
  return %keepgoing_out, %b_out, %user_defined_val
}

等效 C 代码示例

{
  /* User-defined code (enclosing scope) */
  int a = 3, b = 6;
  bool keepgoing = true; // Analogous to input cond
  /* End user-defined code */

  /* Implicitly-defined code */
  const int max_trip_count = 10; // Analogous to input M
  int user_defined_vals[]; // Imagine this is resizable
  /* End implicitly-defined code */
  /* initialize loop-carried variables and scan-output variables */
  bool keepgoing_out = keepgoing
  int b_out = b

  for (int i=0; i < max_trip_count && keepgoing_out; ++i) {
    /* Implicitly-defined code: bind actual parameter values
       to formal parameter variables of loop-body */
    bool keepgoing_in = keepgoing_out;
    bool b_in = b_out;

    /* User-defined code (loop body) */
    int my_local = a + b_in; // Reading value "a" from the enclosing scope is fine
    b_out = a - b_in;
    keepgoing_out = my_local > b_out;
    user_defined_val = b_in + b_in; // b_in and b_out are different variables
    /* End user-defined code */

    /* Implicitly defined-code */
    user_defined_vals[i] = user_defined_val // accumulate scan-output values
  }
  // int t = my_local; // Can't do this. my_local is not accessible here.

  // The values below are bound to the output variables of the loop and therefore accessible
  // b_out; user_defined_vals; keepgoing_out;
}

此代码片段有几点值得注意

  1. 来自封闭作用域的值(即此处的变量“a”)在作用域内,可以在循环的输入中引用。

  2. 在循环体中计算的任何需要在后续迭代或循环后使用的值,通过循环体中的一对变量来建模,包括一个输入变量(例如 b_in)和一个输出变量(例如 b_out)。这些被称为循环依赖。循环操作节点为第一次迭代提供输入变量的输入值,并返回最终迭代生成的输出变量的输出值。

  3. Scan_output 变量用于隐式连接所有迭代中计算的值。在上述示例中,所有迭代中计算的 user_defined_val 的值被连接起来,并在循环后作为 user_defined_vals 的值返回。

  4. 在主体中创建的值不能在封闭作用域中访问,除非使用上述机制。

请注意,此操作符的语义支持“对角线”或“波前”执行。(有关示例,请参见此处第 3 步:https://devblogs.nvidia.com/optimizing-recurrent-neural-networks-cudnn-5/)。前端应将多层 RNN 发射为一系列 While 操作符(时间作为内部循环维度),每个后续层消耗前一层的 scan_outputs,可能通过几个逐点操作符(例如 dropout、残差连接、线性层)。

子图(由循环节点产生)的输入/输出匹配是基于顺序而不是名称。实现将根据此顺序确定名称。

属性

  • body - GRAPH (必需)

    每次迭代运行的图。它有 2+N 个输入:(迭代次数、条件、循环依赖…)。它有 1+N+K 个输出:(条件、循环依赖…、scan_outputs…)。每个 scan_output 是通过连接循环每次迭代结束时指定输出值的值而创建的。如果这些 scan_outputs 的维度或数据类型在循环迭代中发生变化,则会出错。

输入

2 到 2147483647 个输入之间。

  • M (可选,异构) - I

    在运行时指定的循环最大循环次数。可选。传入空字符串以跳过。

  • cond (可选,异构) - B

    布尔终止条件。可选。传入空字符串以跳过。

  • v_initial (可变参数) - V

    任何循环依赖(在循环迭代中更改的值)的初始值

输出

1 到 2147483647 个输出之间。

  • v_final_and_scan_outputs (可变参数) - V

    最终 N 个循环依赖值,然后是 K 个 scan_outputs。扫描输出必须是张量。

类型约束

  • V 在 ( optional(seq(tensor(bfloat16))), optional(seq(tensor(bool))), optional(seq(tensor(complex128))), optional(seq(tensor(complex64))), optional(seq(tensor(double))), optional(seq(tensor(float))), optional(seq(tensor(float16))), optional(seq(tensor(int16))), optional(seq(tensor(int32))), optional(seq(tensor(int64))), optional(seq(tensor(int8))), optional(seq(tensor(string))), optional(seq(tensor(uint16))), optional(seq(tensor(uint32))), optional(seq(tensor(uint64))), optional(seq(tensor(uint8))), optional(tensor(bfloat16)), optional(tensor(bool)), optional(tensor(complex128)), optional(tensor(complex64)), optional(tensor(double)), optional(tensor(float)), optional(tensor(float16)), optional(tensor(float4e2m1)), optional(tensor(float8e4m3fn)), optional(tensor(float8e4m3fnuz)), optional(tensor(float8e5m2)), optional(tensor(float8e5m2fnuz)), optional(tensor(int16)), optional(tensor(int32)), optional(tensor(int4)), optional(tensor(int64)), optional(tensor(int8)), optional(tensor(string)), optional(tensor(uint16)), optional(tensor(uint32)), optional(tensor(uint4)), optional(tensor(uint64)), optional(tensor(uint8)), seq(tensor(bfloat16)), seq(tensor(bool)), seq(tensor(complex128)), seq(tensor(complex64)), seq(tensor(double)), seq(tensor(float)), seq(tensor(float16)), seq(tensor(float4e2m1)), seq(tensor(float8e4m3fn)), seq(tensor(float8e4m3fnuz)), seq(tensor(float8e5m2)), seq(tensor(float8e5m2fnuz)), seq(tensor(int16)), seq(tensor(int32)), seq(tensor(int4)), seq(tensor(int64)), seq(tensor(int8)), seq(tensor(string)), seq(tensor(uint16)), seq(tensor(uint32)), seq(tensor(uint4)), seq(tensor(uint64)), seq(tensor(uint8)), tensor(bfloat16), tensor(bool), tensor(complex128), tensor(complex64), tensor(double), tensor(float), tensor(float16), tensor(float4e2m1)), tensor(float8e4m3fn)), tensor(float8e4m3fnuz)), tensor(float8e5m2)), tensor(float8e5m2fnuz)), tensor(int16), tensor(int32), tensor(int4), tensor(int64), tensor(int8), tensor(string), tensor(uint16), tensor(uint32), tensor(uint4), tensor(uint64), tensor(uint8) )

    所有张量、序列(张量)、可选(张量)和可选(序列(张量))类型,直到 IRv11。

  • I 在 ( tensor(int64) )

    int64 类型的张量,应为标量。

  • B 在 ( tensor(bool) )

    bool 类型的张量,应为标量。

Loop - 21

版本

  • 名称Loop (GitHub)

  • : main

  • since_version: 21

  • 函数: False

  • 支持级别: SupportType.COMMON

  • 形状推断: True

此版本的操作符自 版本 21 起可用。

摘要

通用循环结构。此循环具有多个终止条件

  1. 循环次数。在运行时指定的迭代次数。通过指定输入 M 设置。可选。设置为空字符串表示省略。请注意,可以通过为输入 M 传入一个常量节点来指定静态循环次数(在图构建时指定)。

  2. 循环终止条件。这是操作符的输入,用于确定是否运行第一次迭代,也是主体图的循环依赖。无论是否提供此输入,主体图都必须为条件变量生成一个值。

此表总结了此操作符的操作模式,并附带等效的 C 风格代码

操作符输入定义为 (max_trip_count, condition_var)。

  • 输入 (“”, “”): for (int i=0; ; ++i) { cond = … // 注意此值被忽略,但在主体中是必需的 }

  • 输入 (“”, cond) // 注意这类似于 while 循环 bool cond = …; for (int i=0; cond; ++i) { cond = …; }

  • 输入 (“”, 1) // 注意这类似于 do-while 循环 bool cond = true for (int i=0; cond; ++i) { cond = …; }

  • 输入 (trip_count, “”) // 注意这类似于 for 循环 int trip_count = … for (int i=0; i < trip_count; ++i) { cond = …; // 忽略 }

  • 输入 (trip_count, cond) int trip_count = …; bool cond = …; for (int i=0; i < trip_count && cond; ++i) { cond = …; }

使用示例 - 条件和循环次数

graph predict-net {
  %a = Constant[value = <Scalar Tensor [3]>]()
  %b = Constant[value = <Scalar Tensor [6]>]()
  %keepgoing = Constant[value = <Scalar Tensor [1]>]()
  %max_trip_count = Constant[value = <Scalar Tensor [10]>]()
  %keepgoing_out, %b_out, %user_defined_vals = Loop[body = <graph body-net>](%max_trip_count, %keepgoing, %b)
  return
}

graph body-net (
  %i[INT32, scalar]           // iteration number
  %keepgoing_in[BOOL, scalar] // incoming loop-termination-condition; not used
  %b_in[INT32, scalar]        // incoming value of loop-carried-dependency b
) {
  %my_local = Add(%a, %b_in)
  %b_out = Sub(%a, %b_in) // outgoing value of loop-carried-dependency b
  %keepgoing_out = Greater(%my_local, %b_out) // outgoing loop-termination-condition
  %user_defined_val = Add(%b_in, %b_in) // scan-output value to be accumulated
  return %keepgoing_out, %b_out, %user_defined_val
}

等效 C 代码示例

{
  /* User-defined code (enclosing scope) */
  int a = 3, b = 6;
  bool keepgoing = true; // Analogous to input cond
  /* End user-defined code */

  /* Implicitly-defined code */
  const int max_trip_count = 10; // Analogous to input M
  int user_defined_vals[]; // Imagine this is resizable
  /* End implicitly-defined code */
  /* initialize loop-carried variables and scan-output variables */
  bool keepgoing_out = keepgoing
  int b_out = b

  for (int i=0; i < max_trip_count && keepgoing_out; ++i) {
    /* Implicitly-defined code: bind actual parameter values
       to formal parameter variables of loop-body */
    bool keepgoing_in = keepgoing_out;
    bool b_in = b_out;

    /* User-defined code (loop body) */
    int my_local = a + b_in; // Reading value "a" from the enclosing scope is fine
    b_out = a - b_in;
    keepgoing_out = my_local > b_out;
    user_defined_val = b_in + b_in; // b_in and b_out are different variables
    /* End user-defined code */

    /* Implicitly defined-code */
    user_defined_vals[i] = user_defined_val // accumulate scan-output values
  }
  // int t = my_local; // Can't do this. my_local is not accessible here.

  // The values below are bound to the output variables of the loop and therefore accessible
  // b_out; user_defined_vals; keepgoing_out;
}

此代码片段有几点值得注意

  1. 来自封闭作用域的值(即此处的变量“a”)在作用域内,可以在循环的输入中引用。

  2. 在循环体中计算的任何需要在后续迭代或循环后使用的值,通过循环体中的一对变量来建模,包括一个输入变量(例如 b_in)和一个输出变量(例如 b_out)。这些被称为循环依赖。循环操作节点为第一次迭代提供输入变量的输入值,并返回最终迭代生成的输出变量的输出值。

  3. Scan_output 变量用于隐式连接所有迭代中计算的值。在上述示例中,所有迭代中计算的 user_defined_val 的值被连接起来,并在循环后作为 user_defined_vals 的值返回。

  4. 在主体中创建的值不能在封闭作用域中访问,除非使用上述机制。

请注意,此操作符的语义支持“对角线”或“波前”执行。(有关示例,请参见此处第 3 步:https://devblogs.nvidia.com/optimizing-recurrent-neural-networks-cudnn-5/)。前端应将多层 RNN 发射为一系列 While 操作符(时间作为内部循环维度),每个后续层消耗前一层的 scan_outputs,可能通过几个逐点操作符(例如 dropout、残差连接、线性层)。

子图(由循环节点产生)的输入/输出匹配是基于顺序而不是名称。实现将根据此顺序确定名称。

属性

  • body - GRAPH (必需)

    每次迭代运行的图。它有 2+N 个输入:(迭代次数、条件、循环依赖…)。它有 1+N+K 个输出:(条件、循环依赖…、scan_outputs…)。每个 scan_output 是通过连接循环每次迭代结束时指定输出值的值而创建的。如果这些 scan_outputs 的维度或数据类型在循环迭代中发生变化,则会出错。

输入

2 到 2147483647 个输入之间。

  • M (可选,异构) - I

    在运行时指定的循环最大循环次数。可选。传入空字符串以跳过。

  • cond (可选,异构) - B

    布尔终止条件。可选。传入空字符串以跳过。

  • v_initial (可变参数) - V

    任何循环依赖(在循环迭代中更改的值)的初始值

输出

1 到 2147483647 个输出之间。

  • v_final_and_scan_outputs (可变参数) - V

    最终 N 个循环依赖值,然后是 K 个 scan_outputs。扫描输出必须是张量。

类型约束

  • V 在 ( optional(seq(tensor(bfloat16))), optional(seq(tensor(bool))), optional(seq(tensor(complex128))), optional(seq(tensor(complex64))), optional(seq(tensor(double))), optional(seq(tensor(float))), optional(seq(tensor(float16))), optional(seq(tensor(int16))), optional(seq(tensor(int32))), optional(seq(tensor(int64))), optional(seq(tensor(int8))), optional(seq(tensor(string))), optional(seq(tensor(uint16))), optional(seq(tensor(uint32))), optional(seq(tensor(uint64))), optional(seq(tensor(uint8))), optional(tensor(bfloat16)), optional(tensor(bool)), optional(tensor(complex128)), optional(tensor(complex64)), optional(tensor(double)), optional(tensor(float)), optional(tensor(float16)), optional(tensor(float8e4m3fn)), optional(tensor(float8e4m3fnuz)), optional(tensor(float8e5m2)), optional(tensor(float8e5m2fnuz)), optional(tensor(int16)), optional(tensor(int32)), optional(tensor(int4)), optional(tensor(int64)), optional(tensor(int8)), optional(tensor(string)), optional(tensor(uint16)), optional(tensor(uint32)), optional(tensor(uint4)), optional(tensor(uint64)), optional(tensor(uint8)), seq(tensor(bfloat16)), seq(tensor(bool)), seq(tensor(complex128)), seq(tensor(complex64)), seq(tensor(double)), seq(tensor(float)), seq(tensor(float16)), seq(tensor(float8e4m3fn)), seq(tensor(float8e4m3fnuz)), seq(tensor(float8e5m2)), seq(tensor(float8e5m2fnuz)), seq(tensor(int16)), seq(tensor(int32)), seq(tensor(int4)), seq(tensor(int64)), seq(tensor(int8)), seq(tensor(string)), seq(tensor(uint16)), seq(tensor(uint32)), seq(tensor(uint4)), seq(tensor(uint64)), seq(tensor(uint8)), tensor(bfloat16), tensor(bool), tensor(complex128), tensor(complex64), tensor(double), tensor(float), tensor(float16), tensor(float8e4m3fn)), tensor(float8e4m3fnuz)), tensor(float8e5m2)), tensor(float8e5m2fnuz)), tensor(int16), tensor(int32), tensor(int4), tensor(int64), tensor(int8), tensor(string), tensor(uint16), tensor(uint32), tensor(uint4), tensor(uint64), tensor(uint8) )

    所有张量、序列(张量)、可选(张量)和可选(序列(张量))类型,直到 IRv10。

  • I 在 ( tensor(int64) )

    int64 类型的张量,应为标量。

  • B 在 ( tensor(bool) )

    bool 类型的张量,应为标量。

Loop - 19

版本

  • 名称Loop (GitHub)

  • : main

  • since_version: 19

  • 函数: False

  • 支持级别: SupportType.COMMON

  • 形状推断: True

此版本的操作符自 版本 19 起可用。

摘要

通用循环结构。此循环具有多个终止条件

  1. 循环次数。在运行时指定的迭代次数。通过指定输入 M 设置。可选。设置为空字符串表示省略。请注意,可以通过为输入 M 传入一个常量节点来指定静态循环次数(在图构建时指定)。

  2. 循环终止条件。这是操作符的输入,用于确定是否运行第一次迭代,也是主体图的循环依赖。无论是否提供此输入,主体图都必须为条件变量生成一个值。

此表总结了此操作符的操作模式,并附带等效的 C 风格代码

操作符输入定义为 (max_trip_count, condition_var)。

  • 输入 (“”, “”): for (int i=0; ; ++i) { cond = … // 注意此值被忽略,但在主体中是必需的 }

  • 输入 (“”, cond) // 注意这类似于 while 循环 bool cond = …; for (int i=0; cond; ++i) { cond = …; }

  • 输入 (“”, 1) // 注意这类似于 do-while 循环 bool cond = true for (int i=0; cond; ++i) { cond = …; }

  • 输入 (trip_count, “”) // 注意这类似于 for 循环 int trip_count = … for (int i=0; i < trip_count; ++i) { cond = …; // 忽略 }

  • 输入 (trip_count, cond) int trip_count = …; bool cond = …; for (int i=0; i < trip_count && cond; ++i) { cond = …; }

使用示例 - 条件和循环次数

graph predict-net {
  %a = Constant[value = <Scalar Tensor [3]>]()
  %b = Constant[value = <Scalar Tensor [6]>]()
  %keepgoing = Constant[value = <Scalar Tensor [1]>]()
  %max_trip_count = Constant[value = <Scalar Tensor [10]>]()
  %keepgoing_out, %b_out, %user_defined_vals = Loop[body = <graph body-net>](%max_trip_count, %keepgoing, %b)
  return
}

graph body-net (
  %i[INT32, scalar]           // iteration number
  %keepgoing_in[BOOL, scalar] // incoming loop-termination-condition; not used
  %b_in[INT32, scalar]        // incoming value of loop-carried-dependency b
) {
  %my_local = Add(%a, %b_in)
  %b_out = Sub(%a, %b_in) // outgoing value of loop-carried-dependency b
  %keepgoing_out = Greater(%my_local, %b_out) // outgoing loop-termination-condition
  %user_defined_val = Add(%b_in, %b_in) // scan-output value to be accumulated
  return %keepgoing_out, %b_out, %user_defined_val
}

等效 C 代码示例

{
  /* User-defined code (enclosing scope) */
  int a = 3, b = 6;
  bool keepgoing = true; // Analogous to input cond
  /* End user-defined code */

  /* Implicitly-defined code */
  const int max_trip_count = 10; // Analogous to input M
  int user_defined_vals[]; // Imagine this is resizable
  /* End implicitly-defined code */
  /* initialize loop-carried variables and scan-output variables */
  bool keepgoing_out = keepgoing
  int b_out = b

  for (int i=0; i < max_trip_count && keepgoing_out; ++i) {
    /* Implicitly-defined code: bind actual parameter values
       to formal parameter variables of loop-body */
    bool keepgoing_in = keepgoing_out;
    bool b_in = b_out;

    /* User-defined code (loop body) */
    int my_local = a + b_in; // Reading value "a" from the enclosing scope is fine
    b_out = a - b_in;
    keepgoing_out = my_local > b_out;
    user_defined_val = b_in + b_in; // b_in and b_out are different variables
    /* End user-defined code */

    /* Implicitly defined-code */
    user_defined_vals[i] = user_defined_val // accumulate scan-output values
  }
  // int t = my_local; // Can't do this. my_local is not accessible here.

  // The values below are bound to the output variables of the loop and therefore accessible
  // b_out; user_defined_vals; keepgoing_out;
}

此代码片段有几点值得注意

  1. 来自封闭作用域的值(即此处的变量“a”)在作用域内,可以在循环的输入中引用。

  2. 在循环体中计算的任何需要在后续迭代或循环后使用的值,通过循环体中的一对变量来建模,包括一个输入变量(例如 b_in)和一个输出变量(例如 b_out)。这些被称为循环依赖。循环操作节点为第一次迭代提供输入变量的输入值,并返回最终迭代生成的输出变量的输出值。

  3. Scan_output 变量用于隐式连接所有迭代中计算的值。在上述示例中,所有迭代中计算的 user_defined_val 的值被连接起来,并在循环后作为 user_defined_vals 的值返回。

  4. 在主体中创建的值不能在封闭作用域中访问,除非使用上述机制。

请注意,此操作符的语义支持“对角线”或“波前”执行。(有关示例,请参见此处第 3 步:https://devblogs.nvidia.com/optimizing-recurrent-neural-networks-cudnn-5/)。前端应将多层 RNN 发射为一系列 While 操作符(时间作为内部循环维度),每个后续层消耗前一层的 scan_outputs,可能通过几个逐点操作符(例如 dropout、残差连接、线性层)。

子图(由循环节点产生)的输入/输出匹配是基于顺序而不是名称。实现将根据此顺序确定名称。

属性

  • body - GRAPH (必需)

    每次迭代运行的图。它有 2+N 个输入:(迭代次数、条件、循环依赖…)。它有 1+N+K 个输出:(条件、循环依赖…、scan_outputs…)。每个 scan_output 是通过连接循环每次迭代结束时指定输出值的值而创建的。如果这些 scan_outputs 的维度或数据类型在循环迭代中发生变化,则会出错。

输入

2 到 2147483647 个输入之间。

  • M (可选,异构) - I

    在运行时指定的循环最大循环次数。可选。传入空字符串以跳过。

  • cond (可选,异构) - B

    布尔终止条件。可选。传入空字符串以跳过。

  • v_initial (可变参数) - V

    任何循环依赖(在循环迭代中更改的值)的初始值

输出

1 到 2147483647 个输出之间。

  • v_final_and_scan_outputs (可变参数) - V

    最终 N 个循环依赖值,然后是 K 个 scan_outputs。扫描输出必须是张量。

类型约束

  • V 在 ( optional(seq(tensor(bfloat16))), optional(seq(tensor(bool))), optional(seq(tensor(complex128))), optional(seq(tensor(complex64))), optional(seq(tensor(double))), optional(seq(tensor(float))), optional(seq(tensor(float16))), optional(seq(tensor(int16))), optional(seq(tensor(int32))), optional(seq(tensor(int64))), optional(seq(tensor(int8))), optional(seq(tensor(string))), optional(seq(tensor(uint16))), optional(seq(tensor(uint32))), optional(seq(tensor(uint64))), optional(seq(tensor(uint8))), optional(tensor(bfloat16)), optional(tensor(bool)), optional(tensor(complex128)), optional(tensor(complex64)), optional(tensor(double)), optional(tensor(float)), optional(tensor(float16)), optional(tensor(float8e4m3fn)), optional(tensor(float8e4m3fnuz)), optional(tensor(float8e5m2)), optional(tensor(float8e5m2fnuz)), optional(tensor(int16)), optional(tensor(int32)), optional(tensor(int64)), optional(tensor(int8)), optional(tensor(string)), optional(tensor(uint16)), optional(tensor(uint32)), optional(tensor(uint64)), optional(tensor(uint8)), seq(tensor(bfloat16)), seq(tensor(bool)), seq(tensor(complex128)), seq(tensor(complex64)), seq(tensor(double)), seq(tensor(float)), seq(tensor(float16)), seq(tensor(float8e4m3fn)), seq(tensor(float8e4m3fnuz)), seq(tensor(float8e5m2)), seq(tensor(float8e5m2fnuz)), seq(tensor(int16)), seq(tensor(int32)), seq(tensor(int4)), seq(tensor(int64)), seq(tensor(int8)), seq(tensor(string)), seq(tensor(uint16)), seq(tensor(uint32)), seq(tensor(uint4)), seq(tensor(uint64)), seq(tensor(uint8)), tensor(bfloat16), tensor(bool), tensor(complex128), tensor(complex64), tensor(double), tensor(float), tensor(float16), tensor(float8e4m3fn)), tensor(float8e4m3fnuz)), tensor(float8e5m2)), tensor(float8e5m2fnuz)), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(string), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8) )

    所有张量、序列(张量)、可选(张量)和可选(序列(张量))类型,直到 IRv9。

  • I 在 ( tensor(int64) )

    int64 类型的张量,应为标量。

  • B 在 ( tensor(bool) )

    bool 类型的张量,应为标量。

Loop - 16

版本

  • 名称Loop (GitHub)

  • : main

  • since_version: 16

  • 函数: False

  • 支持级别: SupportType.COMMON

  • 形状推断: True

此版本的运算符自 版本 16 起可用。

摘要

通用循环结构。此循环具有多个终止条件

  1. 循环次数。在运行时指定的迭代次数。通过指定输入 M 设置。可选。设置为空字符串表示省略。请注意,可以通过为输入 M 传入一个常量节点来指定静态循环次数(在图构建时指定)。

  2. 循环终止条件。这是操作符的输入,用于确定是否运行第一次迭代,也是主体图的循环依赖。无论是否提供此输入,主体图都必须为条件变量生成一个值。

此表总结了此操作符的操作模式,并附带等效的 C 风格代码

操作符输入定义为 (max_trip_count, condition_var)。

  • 输入 (“”, “”): for (int i=0; ; ++i) { cond = … // 注意此值被忽略,但在主体中是必需的 }

  • 输入 (“”, cond) // 注意这类似于 while 循环 bool cond = …; for (int i=0; cond; ++i) { cond = …; }

  • 输入 (“”, 1) // 注意这类似于 do-while 循环 bool cond = true for (int i=0; cond; ++i) { cond = …; }

  • 输入 (trip_count, “”) // 注意这类似于 for 循环 int trip_count = … for (int i=0; i < trip_count; ++i) { cond = …; // 忽略 }

  • 输入 (trip_count, cond) int trip_count = …; bool cond = …; for (int i=0; i < trip_count && cond; ++i) { cond = …; }

使用示例 - 条件和循环次数

graph predict-net {
  %a = Constant[value = <Scalar Tensor [3]>]()
  %b = Constant[value = <Scalar Tensor [6]>]()
  %keepgoing = Constant[value = <Scalar Tensor [1]>]()
  %max_trip_count = Constant[value = <Scalar Tensor [10]>]()
  %keepgoing_out, %b_out, %user_defined_vals = Loop[body = <graph body-net>](%max_trip_count, %keepgoing, %b)
  return
}

graph body-net (
  %i[INT32, scalar]           // iteration number
  %keepgoing_in[BOOL, scalar] // incoming loop-termination-condition; not used
  %b_in[INT32, scalar]        // incoming value of loop-carried-dependency b
) {
  %my_local = Add(%a, %b_in)
  %b_out = Sub(%a, %b_in) // outgoing value of loop-carried-dependency b
  %keepgoing_out = Greater(%my_local, %b_out) // outgoing loop-termination-condition
  %user_defined_val = Add(%b_in, %b_in) // scan-output value to be accumulated
  return %keepgoing_out, %b_out, %user_defined_val
}

等效 C 代码示例

{
  /* User-defined code (enclosing scope) */
  int a = 3, b = 6;
  bool keepgoing = true; // Analogous to input cond
  /* End user-defined code */

  /* Implicitly-defined code */
  const int max_trip_count = 10; // Analogous to input M
  int user_defined_vals[]; // Imagine this is resizable
  /* End implicitly-defined code */
  /* initialize loop-carried variables and scan-output variables */
  bool keepgoing_out = keepgoing
  int b_out = b

  for (int i=0; i < max_trip_count && keepgoing_out; ++i) {
    /* Implicitly-defined code: bind actual parameter values
       to formal parameter variables of loop-body */
    bool keepgoing_in = keepgoing_out;
    bool b_in = b_out;

    /* User-defined code (loop body) */
    int my_local = a + b_in; // Reading value "a" from the enclosing scope is fine
    b_out = a - b_in;
    keepgoing_out = my_local > b_out;
    user_defined_val = b_in + b_in; // b_in and b_out are different variables
    /* End user-defined code */

    /* Implicitly defined-code */
    user_defined_vals[i] = user_defined_val // accumulate scan-output values
  }
  // int t = my_local; // Can't do this. my_local is not accessible here.

  // The values below are bound to the output variables of the loop and therefore accessible
  // b_out; user_defined_vals; keepgoing_out;
}

此代码片段有几点值得注意

  1. 来自封闭作用域的值(即此处的变量“a”)在作用域内,可以在循环的输入中引用。

  2. 在循环体中计算的任何需要在后续迭代或循环后使用的值,通过循环体中的一对变量来建模,包括一个输入变量(例如 b_in)和一个输出变量(例如 b_out)。这些被称为循环依赖。循环操作节点为第一次迭代提供输入变量的输入值,并返回最终迭代生成的输出变量的输出值。

  3. Scan_output 变量用于隐式连接所有迭代中计算的值。在上述示例中,所有迭代中计算的 user_defined_val 的值被连接起来,并在循环后作为 user_defined_vals 的值返回。

  4. 在主体中创建的值不能在封闭作用域中访问,除非使用上述机制。

请注意,此操作符的语义支持“对角线”或“波前”执行。(有关示例,请参见此处第 3 步:https://devblogs.nvidia.com/optimizing-recurrent-neural-networks-cudnn-5/)。前端应将多层 RNN 发射为一系列 While 操作符(时间作为内部循环维度),每个后续层消耗前一层的 scan_outputs,可能通过几个逐点操作符(例如 dropout、残差连接、线性层)。

子图(由循环节点产生)的输入/输出匹配是基于顺序而不是名称。实现将根据此顺序确定名称。

属性

  • body - GRAPH (必需)

    每次迭代运行的图。它有 2+N 个输入:(迭代次数、条件、循环依赖…)。它有 1+N+K 个输出:(条件、循环依赖…、scan_outputs…)。每个 scan_output 是通过连接循环每次迭代结束时指定输出值的值而创建的。如果这些 scan_outputs 的维度或数据类型在循环迭代中发生变化,则会出错。

输入

2 到 2147483647 个输入之间。

  • M (可选,异构) - I

    在运行时指定的循环最大循环次数。可选。传入空字符串以跳过。

  • cond (可选,异构) - B

    布尔终止条件。可选。传入空字符串以跳过。

  • v_initial (可变参数) - V

    任何循环依赖(在循环迭代中更改的值)的初始值

输出

1 到 2147483647 个输出之间。

  • v_final_and_scan_outputs (可变参数) - V

    最终 N 个循环依赖值,然后是 K 个 scan_outputs。扫描输出必须是张量。

类型约束

  • V 在 ( optional(seq(tensor(bfloat16))), optional(seq(tensor(bool))), optional(seq(tensor(complex128))), optional(seq(tensor(complex64))), optional(seq(tensor(double))), optional(seq(tensor(float))), optional(seq(tensor(float16))), optional(seq(tensor(int16))), optional(seq(tensor(int32))), optional(seq(tensor(int64))), optional(seq(tensor(int8))), optional(seq(tensor(string))), optional(seq(tensor(uint16))), optional(seq(tensor(uint32))), optional(seq(tensor(uint64))), optional(seq(tensor(uint8))), optional(tensor(bfloat16)), optional(tensor(bool)), optional(tensor(complex128)), optional(tensor(complex64)), optional(tensor(double)), optional(tensor(float)), optional(tensor(float16)), optional(tensor(int16)), optional(tensor(int32)), optional(tensor(int64)), optional(tensor(int8)), optional(tensor(string)), optional(tensor(uint16)), optional(tensor(uint32)), optional(tensor(uint64)), optional(tensor(uint8)), seq(tensor(bfloat16)), seq(tensor(bool)), seq(tensor(complex128)), seq(tensor(complex64)), seq(tensor(double)), seq(tensor(float)), seq(tensor(float16)), seq(tensor(int16)), seq(tensor(int32)), seq(tensor(int64)), seq(tensor(int8)), seq(tensor(string)), seq(tensor(uint16)), seq(tensor(uint32)), seq(tensor(uint64)), seq(tensor(uint8)), tensor(bfloat16), tensor(bool), tensor(complex128), tensor(complex64), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(string), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8) )

    所有张量、序列(张量)、可选(张量)和可选(序列(张量))类型,直到 IRv4。

  • I 在 ( tensor(int64) )

    int64 类型的张量,应为标量。

  • B 在 ( tensor(bool) )

    bool 类型的张量,应为标量。

Loop - 13

版本

  • 名称Loop (GitHub)

  • : main

  • 起始版本: 13

  • 函数: False

  • 支持级别: SupportType.COMMON

  • 形状推断: True

此版本的运算符自 版本 13 起可用。

摘要

通用循环结构。此循环具有多个终止条件

  1. 循环次数。在运行时指定的迭代次数。通过指定输入 M 设置。可选。设置为空字符串表示省略。请注意,可以通过为输入 M 传入一个常量节点来指定静态循环次数(在图构建时指定)。

  2. 循环终止条件。这是操作符的输入,用于确定是否运行第一次迭代,也是主体图的循环依赖。无论是否提供此输入,主体图都必须为条件变量生成一个值。

此表总结了此操作符的操作模式,并附带等效的 C 风格代码

操作符输入定义为 (max_trip_count, condition_var)。

input ("", ""):
    for (int i=0; ; ++i) {
      cond = ... // Note this value is ignored, but is required in the body
    }

input ("", cond) // Note this is analogous to a while loop
    bool cond = ...;
    for (int i=0; cond; ++i) {
      cond = ...;
    }

input ("", 1) // Note this is analogous to a do-while loop
    bool cond = true
    for (int i=0; cond; ++i) {
      cond = ...;
    }

input (trip_count, "") // Note this is analogous to a for loop
    int trip_count = ...
    for (int i=0; i < trip_count; ++i) {
      cond = ...; // ignored
    }

input (trip_count, cond)
    int trip_count = ...;
    bool cond = ...;
    for (int i=0; i < trip_count && cond; ++i) {
      cond = ...;
    }

使用示例 - 条件和循环次数

graph predict-net {
  %a = Constant[value = <Scalar Tensor [3]>]()
  %b = Constant[value = <Scalar Tensor [6]>]()
  %keepgoing = Constant[value = <Scalar Tensor [1]>]()
  %max_trip_count = Constant[value = <Scalar Tensor [10]>]()
  %keepgoing_out, %b_out, %user_defined_vals = Loop[body = <graph body-net>](%max_trip_count, %keepgoing, %b)
  return
}

graph body-net (
  %i[INT32, scalar]           // iteration number
  %keepgoing_in[BOOL, scalar] // incoming loop-termination-condition; not used
  %b_in[INT32, scalar]        // incoming value of loop-carried-dependency b
) {
  %my_local = Add(%a, %b_in)
  %b_out = Sub(%a, %b_in) // outgoing value of loop-carried-dependency b
  %keepgoing_out = Greater(%my_local, %b_out) // outgoing loop-termination-condition
  %user_defined_val = Add(%b_in, %b_in) // scan-output value to be accumulated
  return %keepgoing_out, %b_out, %user_defined_val
}

等效 C 代码示例

{
  /* User-defined code (enclosing scope) */
  int a = 3, b = 6;
  bool keepgoing = true; // Analogous to input cond
  /* End user-defined code */

  /* Implicitly-defined code */
  const int max_trip_count = 10; // Analogous to input M
  int user_defined_vals[]; // Imagine this is resizable
  /* End implicitly-defined code */
  /* initialize loop-carried variables and scan-output variables */
  bool keepgoing_out = keepgoing
  int b_out = b

  for (int i=0; i < max_trip_count && keepgoing_out; ++i) {
    /* Implicitly-defined code: bind actual parameter values
       to formal parameter variables of loop-body */
    bool keepgoing_in = keepgoing_out;
    bool b_in = b_out;

    /* User-defined code (loop body) */
    int my_local = a + b_in; // Reading value "a" from the enclosing scope is fine
    b_out = a - b_in;
    keepgoing_out = my_local > b_out;
    user_defined_val = b_in + b_in; // b_in and b_out are different variables
    /* End user-defined code */

    /* Implicitly defined-code */
    user_defined_vals[i] = user_defined_val // accumulate scan-output values
  }
  // int t = my_local; // Can't do this. my_local is not accessible here.

  // The values below are bound to the output variables of the loop and therefore accessible
  // b_out; user_defined_vals; keepgoing_out;
}

此代码片段有几点值得注意

  1. 来自封闭作用域的值(即此处的变量“a”)在作用域内,可以在循环的输入中引用。

  2. 在循环体中计算的任何需要在后续迭代或循环后使用的值,通过循环体中的一对变量来建模,包括一个输入变量(例如 b_in)和一个输出变量(例如 b_out)。这些被称为循环依赖。循环操作节点为第一次迭代提供输入变量的输入值,并返回最终迭代生成的输出变量的输出值。

  3. Scan_output 变量用于隐式连接所有迭代中计算的值。在上述示例中,所有迭代中计算的 user_defined_val 的值被连接起来,并在循环后作为 user_defined_vals 的值返回。

  4. 在主体中创建的值不能在封闭作用域中访问,除非使用上述机制。

请注意,此操作符的语义支持“对角线”或“波前”执行。(有关示例,请参见此处第 3 步:https://devblogs.nvidia.com/optimizing-recurrent-neural-networks-cudnn-5/)。前端应将多层 RNN 发射为一系列 While 操作符(时间作为内部循环维度),每个后续层消耗前一层的 scan_outputs,可能通过几个逐点操作符(例如 dropout、残差连接、线性层)。

子图(由循环节点产生)的输入/输出匹配是基于顺序而不是名称。实现将根据此顺序确定名称。

属性

  • body - GRAPH (必需)

    每次迭代运行的图。它有 2+N 个输入:(迭代次数、条件、循环依赖…)。它有 1+N+K 个输出:(条件、循环依赖…、scan_outputs…)。每个 scan_output 是通过连接循环每次迭代结束时指定输出值的值而创建的。如果这些 scan_outputs 的维度或数据类型在循环迭代中发生变化,则会出错。

输入

2 到 2147483647 个输入之间。

  • M (可选,异构) - I

    在运行时指定的循环最大循环次数。可选。传入空字符串以跳过。

  • cond (可选,异构) - B

    布尔终止条件。可选。传入空字符串以跳过。

  • v_initial (可变参数) - V

    任何循环依赖(在循环迭代中更改的值)的初始值

输出

1 到 2147483647 个输出之间。

  • v_final_and_scan_outputs (可变参数) - V

    最终 N 个循环依赖值,然后是 K 个 scan_outputs。扫描输出必须是张量。

类型约束

  • V 在 ( seq(tensor(bool)), seq(tensor(complex128)), seq(tensor(complex64)), seq(tensor(double)), seq(tensor(float)), seq(tensor(float16)), seq(tensor(int16)), seq(tensor(int32)), seq(tensor(int64)), seq(tensor(int8)), seq(tensor(string)), seq(tensor(uint16)), seq(tensor(uint32)), seq(tensor(uint64)), seq(tensor(uint8)), tensor(bool), tensor(complex128), tensor(complex64), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(string), tensor(uint16), tensor(uint32), tensor(uint4), tensor(uint64), tensor(uint8) )

    所有张量和序列类型

  • I 在 ( tensor(int64) )

    int64 类型的张量,应为标量。

  • B 在 ( tensor(bool) )

    bool 类型的张量,应为标量。

Loop - 11

版本

  • 名称Loop (GitHub)

  • : main

  • 起始版本: 11

  • 函数: False

  • 支持级别: SupportType.COMMON

  • 形状推断: True

此版本的运算符自 版本 11 起可用。

摘要

通用循环结构。此循环具有多个终止条件

  1. 循环次数。在运行时指定的迭代次数。通过指定输入 M 设置。可选。设置为空字符串表示省略。请注意,可以通过为输入 M 传入一个常量节点来指定静态循环次数(在图构建时指定)。

  2. 循环终止条件。这是操作符的输入,用于确定是否运行第一次迭代,也是主体图的循环依赖。无论是否提供此输入,主体图都必须为条件变量生成一个值。

此表总结了此操作符的操作模式,并附带等效的 C 风格代码

操作符输入定义为 (max_trip_count, condition_var)。

input ("", ""):
    for (int i=0; ; ++i) {
      cond = ... // Note this value is ignored, but is required in the body
    }

input ("", cond) // Note this is analogous to a while loop
    bool cond = ...;
    for (int i=0; cond; ++i) {
      cond = ...;
    }

input ("", 1) // Note this is analogous to a do-while loop
    bool cond = true
    for (int i=0; cond; ++i) {
      cond = ...;
    }

input (trip_count, "") // Note this is analogous to a for loop
    int trip_count = ...
    for (int i=0; i < trip_count; ++i) {
      cond = ...; // ignored
    }

input (trip_count, cond)
    int trip_count = ...;
    bool cond = ...;
    for (int i=0; i < trip_count && cond; ++i) {
      cond = ...;
    }

使用示例 - 条件和循环次数

graph predict-net {
  %a = Constant[value = <Scalar Tensor [3]>]()
  %b = Constant[value = <Scalar Tensor [6]>]()
  %keepgoing = Constant[value = <Scalar Tensor [1]>]()
  %max_trip_count = Constant[value = <Scalar Tensor [10]>]()
  %keepgoing_out, %b_out, %user_defined_vals = Loop[body = <graph body-net>](%max_trip_count, %keepgoing, %b)
  return
}

graph body-net (
  %i[INT32, scalar]           // iteration number
  %keepgoing_in[BOOL, scalar] // incoming loop-termination-condition; not used
  %b_in[INT32, scalar]        // incoming value of loop-carried-dependency b
) {
  %my_local = Add(%a, %b_in)
  %b_out = Sub(%a, %b_in) // outgoing value of loop-carried-dependency b
  %keepgoing_out = Greater(%my_local, %b_out) // outgoing loop-termination-condition
  %user_defined_val = Add(%b_in, %b_in) // scan-output value to be accumulated
  return %keepgoing_out, %b_out, %user_defined_val
}

等效 C 代码示例

{
  /* User-defined code (enclosing scope) */
  int a = 3, b = 6;
  bool keepgoing = true; // Analogous to input cond
  /* End user-defined code */

  /* Implicitly-defined code */
  const int max_trip_count = 10; // Analogous to input M
  int user_defined_vals[]; // Imagine this is resizable
  /* End implicitly-defined code */
  /* initialize loop-carried variables and scan-output variables */
  bool keepgoing_out = keepgoing
  int b_out = b

  for (int i=0; i < max_trip_count && keepgoing_out; ++i) {
    /* Implicitly-defined code: bind actual parameter values
       to formal parameter variables of loop-body */
    bool keepgoing_in = keepgoing_out;
    bool b_in = b_out;

    /* User-defined code (loop body) */
    int my_local = a + b_in; // Reading value "a" from the enclosing scope is fine
    b_out = a - b_in;
    keepgoing_out = my_local > b_out;
    user_defined_val = b_in + b_in; // b_in and b_out are different variables
    /* End user-defined code */

    /* Implicitly defined-code */
    user_defined_vals[i] = user_defined_val // accumulate scan-output values
  }
  // int t = my_local; // Can't do this. my_local is not accessible here.

  // The values below are bound to the output variables of the loop and therefore accessible
  // b_out; user_defined_vals; keepgoing_out;
}

此代码片段有几点值得注意

  1. 来自封闭作用域的值(即此处的变量“a”)在作用域内,可以在循环的输入中引用。

  2. 在循环体中计算的任何需要在后续迭代或循环后使用的值,通过循环体中的一对变量来建模,包括一个输入变量(例如 b_in)和一个输出变量(例如 b_out)。这些被称为循环依赖。循环操作节点为第一次迭代提供输入变量的输入值,并返回最终迭代生成的输出变量的输出值。

  3. Scan_output 变量用于隐式连接所有迭代中计算的值。在上述示例中,所有迭代中计算的 user_defined_val 的值被连接起来,并在循环后作为 user_defined_vals 的值返回。

  4. 在主体中创建的值不能在封闭作用域中访问,除非使用上述机制。

请注意,此操作符的语义支持“对角线”或“波前”执行。(有关示例,请参见此处第 3 步:https://devblogs.nvidia.com/optimizing-recurrent-neural-networks-cudnn-5/)。前端应将多层 RNN 发射为一系列 While 操作符(时间作为内部循环维度),每个后续层消耗前一层的 scan_outputs,可能通过几个逐点操作符(例如 dropout、残差连接、线性层)。

属性

  • body - GRAPH (必需)

    每次迭代运行的图。它有 2+N 个输入:(迭代次数、条件、循环依赖…)。它有 1+N+K 个输出:(条件、循环依赖…、scan_outputs…)。每个 scan_output 是通过连接循环每次迭代结束时指定输出值的值而创建的。如果这些 scan_outputs 的维度或数据类型在循环迭代中发生变化,则会出错。

输入

2 到 2147483647 个输入之间。

  • M (可选,异构) - I

    在运行时指定的循环最大循环次数。可选。传入空字符串以跳过。

  • cond (可选,异构) - B

    布尔终止条件。可选。传入空字符串以跳过。

  • v_initial (可变参数) - V

    任何循环依赖(在循环迭代中更改的值)的初始值

输出

1 到 2147483647 个输出之间。

  • v_final_and_scan_outputs (可变参数) - V

    最终 N 个循环依赖值,然后是 K 个扫描输出

类型约束

  • V 在 ( tensor(bool), tensor(complex128), tensor(complex64), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(string), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8) )

    所有张量类型

  • I 在 ( tensor(int64) )

    int64 类型的张量,应为标量。

  • B 在 ( tensor(bool) )

    bool 类型的张量,应为标量。

Loop - 1

版本

  • 名称Loop (GitHub)

  • : main

  • 起始版本: 1

  • 函数: False

  • 支持级别: SupportType.COMMON

  • 形状推断: True

此版本的运算符自 版本 1 起可用。

摘要

通用循环结构。此循环具有多个终止条件

  1. 循环次数。在运行时指定的迭代次数。通过指定输入 M 设置。可选。设置为空字符串表示省略。请注意,可以通过为输入 M 传入一个常量节点来指定静态循环次数(在图构建时指定)。

  2. 循环终止条件。这是操作符的输入,用于确定是否运行第一次迭代,也是主体图的循环依赖。无论是否提供此输入,主体图都必须为条件变量生成一个值。

此表总结了此操作符的操作模式,并附带等效的 C 风格代码

操作符输入定义为 (max_trip_count, condition_var)。

input ("", ""):
    for (int i=0; ; ++i) {
      cond = ... // Note this value is ignored, but is required in the body
    }

input ("", cond) // Note this is analogous to a while loop
    bool cond = ...;
    for (int i=0; cond; ++i) {
      cond = ...;
    }

input ("", 1) // Note this is analogous to a do-while loop
    bool cond = true
    for (int i=0; cond; ++i) {
      cond = ...;
    }

input (trip_count, "") // Note this is analogous to a for loop
    int trip_count = ...
    for (int i=0; i < trip_count; ++i) {
      cond = ...; // ignored
    }

input (trip_count, cond)
    int trip_count = ...;
    bool cond = ...;
    for (int i=0; i < trip_count && cond; ++i) {
      cond = ...;
    }

使用示例 - 条件和循环次数

graph predict-net {
  %a = Constant[value = <Scalar Tensor [3]>]()
  %b = Constant[value = <Scalar Tensor [6]>]()
  %keepgoing = Constant[value = <Scalar Tensor [1]>]()
  %max_trip_count = Constant[value = <Scalar Tensor [10]>]()
  %keepgoing_out, %b_out, %user_defined_vals = Loop[body = <graph body-net>](%max_trip_count, %keepgoing, %b)
  return
}

graph body-net (
  %i[INT32, scalar]
  %keepgoing[BOOL, scalar]
  %b[INT32, scalar]
) {
  %my_local = Add(%a, %b)
  %b_out = Sub(%a, %b)
  %keepgoing_out = Greater(%my_local, %b_out)
  %user_defined_vals = Add(%b, %b)
  return %keepgoing_out, %b_out, %user_defined_vals
}

等效 C 代码示例

{
  /* User-defined code (enclosing scope) */
  int a = 3, b = 6;
  bool keepgoing = true; // Analogous to input cond
  /* End user-defined code */

  /* Implicitly-defined code */
  const int max_trip_count = 10; // Analogous to input M
  int user_defined_vals[]; // Imagine this is resizable
  /* End implicitly-defined code */
  for (int i=0; i < max_trip_count && keepgoing; ++i) {
    /* User-defined code (loop body) */
    int my_local = a + b; // Reading values in the enclosing scope is fine
    b = a - b; // writes fine if we specify b as a loop-carried dependency
    keepgoing = my_local > b; // keepgoing is a loop-carried dependency
    user_defined_vals[i] = b + b;
    /* End user-defined code */
  }
  // my_local = 123; // Can't do this. my_local was defined in the body

  // These below values are live-out from the loop and therefore accessible
  b_out; user_defined_vals; keepgoing_out;
}

此代码片段有几点值得注意

  1. 来自封闭作用域的值(即此处的变量 a)在作用域内,可以在循环的输入中引用。

  2. 您希望在封闭作用域中可用的任何变量(即变量 b 和 keepgoing)必须声明为循环依赖(同时在操作符输入和输出以及主体网络输入和输出处)或扫描输出。

  3. 在主体中创建的值不能在封闭作用域中访问。

请注意,此操作符的语义支持“对角线”或“波前”执行。(有关示例,请参见此处第 3 步:https://devblogs.nvidia.com/optimizing-recurrent-neural-networks-cudnn-5/)。前端应将多层 RNN 发射为一系列 While 操作符(时间作为内部循环维度),每个后续层消耗前一层的 scan_outputs,可能通过几个逐点操作符(例如 dropout、残差连接、线性层)。

属性

  • body - GRAPH (必需)

    每次迭代运行的图。它有 2+N 个输入:(迭代次数、条件、循环依赖…)。它有 1+N+K 个输出:(条件、循环依赖…、scan_outputs…)。每个 scan_output 是通过连接循环每次迭代结束时指定输出值的值而创建的。如果这些 scan_outputs 的维度或数据类型在循环迭代中发生变化,则会出错。

输入

3 到 2147483647 个输入之间。

  • M (可选,异构) - I

    在运行时指定的循环最大循环次数。可选。传入空字符串以跳过。

  • cond (可选,异构) - B

    布尔终止条件。可选。传入空字符串以跳过。

  • v_initial (可变参数) - V

    任何循环依赖(在循环迭代中更改的值)的初始值

输出

1 到 2147483647 个输出之间。

  • v_final_and_scan_outputs (可变参数) - V

    最终 N 个循环依赖值,然后是 K 个扫描输出

类型约束

  • V 在 ( tensor(bool), tensor(complex128), tensor(complex64), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(string), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8) )

    所有张量类型

  • I 在 ( tensor(int64) )

    int64 类型的张量,应为标量。

  • B 在 ( tensor(bool) )

    bool 类型的张量,应为标量。